From c8e9929c39a758785ea42be5f5eb1abda90449d9 Mon Sep 17 00:00:00 2001 From: Bruno Dias Date: Wed, 16 Nov 2022 20:42:02 -0300 Subject: [PATCH 1/2] feature: accept hunks and stage selected changes on git... using the -review we can interactively select which changes we will accept. a new option is added to allow users to accept the patch and also automatically stage the changes (currently only git is supported). --- lib/app/interactive/interactive.ml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/app/interactive/interactive.ml b/lib/app/interactive/interactive.ml index 38f46410..218988fb 100644 --- a/lib/app/interactive/interactive.ml +++ b/lib/app/interactive/interactive.ml @@ -144,8 +144,8 @@ let handle_patch_errors = function Lwt_io.print message >>= fun _input -> Lwt_io.read_line Lwt_io.stdin >>= fun _input -> return `Ok -let apply_patch hunk_patch = - let cmd = Lwt_process.shell "patch -p 0" in +let apply_patch_with_cmd cmd hunk_patch = + let cmd = Lwt_process.shell cmd in return (Lwt_process.open_process_full cmd) >>= fun process -> Lwt_io.write_line process#stdin hunk_patch @@ -159,6 +159,12 @@ let apply_patch hunk_patch = (if debug then Lwt_io.printf "[debug] %s,%s\n" stdout stderr else return ()) >>= fun () -> process#close +let apply_patch_with_git hunk_patch = + apply_patch_with_cmd "git apply --index" hunk_patch + +let apply_patch hunk_patch = + apply_patch_with_cmd "patch -p 0" hunk_patch + let drop_into_editor editor path ~at_line = let command = Format.sprintf "%s +%d %s" editor at_line path in Lwt_unix.system command @@ -173,6 +179,10 @@ let process_input default_is_accept hunk_patch prev_start next_start editor path ; "\x1b[1m" ; " [default], " ; "\x1b[0m" + ; "\x1b[32m" + ; "g = accept as git patch" + ; "\x1b[0m" + ; ", " ; "\x1b[31m" ; "n = no" ; "\x1b[0m" @@ -193,6 +203,10 @@ let process_input default_is_accept hunk_patch prev_start next_start editor path ; "y = yes" ; "\x1b[0m" ; ", " + ; "\x1b[32m" + ; "g = accept as git patch" + ; "\x1b[0m" + ; ", " ; "\x1b[31m" ; "n = no" ; "\x1b[0m" @@ -220,6 +234,7 @@ let process_input default_is_accept hunk_patch prev_start next_start editor path | "y" -> apply_patch hunk_patch >>= handle_patch_errors >>= fun _ -> continue () | "" when default_is_accept -> apply_patch hunk_patch >>= handle_patch_errors >>= fun _ -> continue () + | "g" -> apply_patch_with_git hunk_patch >>= handle_patch_errors >>= fun _ -> continue () | "n" -> continue () | "" when not default_is_accept -> continue () | "e" -> From 28e0a695a7a027de1cd8a285fa4f63c07c3b92e5 Mon Sep 17 00:00:00 2001 From: Bruno Dias Date: Thu, 17 Nov 2022 22:24:05 -0300 Subject: [PATCH 2/2] feature: check if file is already on git repository... when applying to the stage area, if the file is not already commited on the repository the patch will fail. we show the option only if the file is already commited. --- lib/app/interactive/interactive.ml | 39 ++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/lib/app/interactive/interactive.ml b/lib/app/interactive/interactive.ml index 218988fb..aa3a8caf 100644 --- a/lib/app/interactive/interactive.ml +++ b/lib/app/interactive/interactive.ml @@ -160,7 +160,7 @@ let apply_patch_with_cmd cmd hunk_patch = >>= fun () -> process#close let apply_patch_with_git hunk_patch = - apply_patch_with_cmd "git apply --index" hunk_patch + apply_patch_with_cmd "git apply --index --intent-to-add" hunk_patch let apply_patch hunk_patch = apply_patch_with_cmd "patch -p 0" hunk_patch @@ -169,7 +169,24 @@ let drop_into_editor editor path ~at_line = let command = Format.sprintf "%s +%d %s" editor at_line path in Lwt_unix.system command +let file_in_git_repo path = + let command = Format.sprintf "test ! -z \"$(git ls-files -- %s)\"" path in + Lwt_unix.system command + >>= fun status -> + match status with + | Lwt_unix.WEXITED x -> return (x == 0) + | _ -> return false + let process_input default_is_accept hunk_patch prev_start next_start editor path ~continue = + file_in_git_repo path + >>= fun file_gited -> + let git_option = + if file_gited then + [ "\x1b[32m" + ; "g = accept as git patch" + ; "\x1b[0m" + ; ", " + ] else [] in let prompt = if default_is_accept then [ "Accept change (" @@ -179,11 +196,8 @@ let process_input default_is_accept hunk_patch prev_start next_start editor path ; "\x1b[1m" ; " [default], " ; "\x1b[0m" - ; "\x1b[32m" - ; "g = accept as git patch" - ; "\x1b[0m" - ; ", " - ; "\x1b[31m" + ] @ git_option @ [ + "\x1b[31m" ; "n = no" ; "\x1b[0m" ; ", " @@ -203,11 +217,8 @@ let process_input default_is_accept hunk_patch prev_start next_start editor path ; "y = yes" ; "\x1b[0m" ; ", " - ; "\x1b[32m" - ; "g = accept as git patch" - ; "\x1b[0m" - ; ", " - ; "\x1b[31m" + ] @ git_option @ [ + "\x1b[31m" ; "n = no" ; "\x1b[0m" ; "\x1b[1m" @@ -224,6 +235,7 @@ let process_input default_is_accept hunk_patch prev_start next_start editor path ; "q = quit)?" ] in + let no_command = fun () -> Lwt_io.printl "Uh, I don't know that one. Try again." in let prompt = String.concat prompt in Lwt_io.printl prompt >>= fun () -> @@ -234,7 +246,8 @@ let process_input default_is_accept hunk_patch prev_start next_start editor path | "y" -> apply_patch hunk_patch >>= handle_patch_errors >>= fun _ -> continue () | "" when default_is_accept -> apply_patch hunk_patch >>= handle_patch_errors >>= fun _ -> continue () - | "g" -> apply_patch_with_git hunk_patch >>= handle_patch_errors >>= fun _ -> continue () + | "g" when file_gited -> apply_patch_with_git hunk_patch >>= handle_patch_errors >>= fun _ -> continue () + | "g" when not file_gited -> no_command () >>= try_again | "n" -> continue () | "" when not default_is_accept -> continue () | "e" -> @@ -249,7 +262,7 @@ let process_input default_is_accept hunk_patch prev_start next_start editor path >>= handle_editor_errors >>= fun _ -> continue () | "q" -> raise Sys.Break - | _ -> Lwt_io.printl "Uh, I don't know that one. Try again." >>= try_again + | _ -> no_command () >>= try_again in try_again ()