diff --git a/lib/HunkView.ml b/lib/HunkView.ml index b2fd616..413c1cf 100644 --- a/lib/HunkView.ml +++ b/lib/HunkView.ml @@ -2,11 +2,14 @@ open Nottui module W = Nottui_widgets (* Types *) - type line = Change of string | Common of string | Empty +type rendering_mode = Color | TextMarkers (* Utility Functions *) +let added_marker (content : Ui.t) : Ui.t = Ui.hcat [ W.string "+"; content ] +let removed_marker (content : Ui.t) : Ui.t = Ui.hcat [ W.string "-"; content ] + let split_and_align_hunk hunks : line list * line list = let rec process_hunk mine_acc their_acc = function | [] -> (List.rev mine_acc, List.rev their_acc) @@ -37,25 +40,43 @@ let split_and_align_hunk hunks : line list * line list = in process_hunk [] [] hunks -(* Normal Mode *) +(* Styling Functions *) + +let style_text (text : string) (attr : Notty.attr) (mode : rendering_mode) : + Ui.t = + match mode with Color -> W.string ~attr text | TextMarkers -> W.string text + +let style_word (word : string) + (change_type : [ `Added | `Removed | `Unchanged ]) (mode : rendering_mode) : + Ui.t = + let styled_word = + match (mode, change_type) with + | Color, `Added -> W.string ~attr:Notty.A.(fg green) word + | Color, `Removed -> W.string ~attr:Notty.A.(fg red) word + | Color, `Unchanged -> W.string word + | TextMarkers, `Added -> added_marker (W.string word) + | TextMarkers, `Removed -> removed_marker (W.string word) + | TextMarkers, `Unchanged -> W.string word + in + Ui.hcat [ styled_word; W.string " " ] + +(* Rendering Functions *) -let ui_hunk_summary (hunk : string Patch.hunk) : Nottui.ui = +let render_hunk_summary (hunk : string Patch.hunk) (mode : rendering_mode) : + Ui.t = let mine_info = - if hunk.Patch.mine_len = 0 then "0,0" - else Printf.sprintf "%d,%d" (hunk.Patch.mine_start + 1) hunk.Patch.mine_len + Printf.sprintf "%d,%d" (hunk.Patch.mine_start + 1) hunk.Patch.mine_len in let their_info = - if hunk.Patch.their_len = 0 then "0,0" - else - Printf.sprintf "%d,%d" (hunk.Patch.their_start + 1) hunk.Patch.their_len + Printf.sprintf "%d,%d" (hunk.Patch.their_start + 1) hunk.Patch.their_len in let mine_summary = - W.string ~attr:Notty.A.(fg red) (Printf.sprintf "-%s" mine_info) + style_text (Printf.sprintf "-%s" mine_info) Notty.A.(fg red) mode in let their_summary = - W.string ~attr:Notty.A.(fg green) (Printf.sprintf "+%s" their_info) + style_text (Printf.sprintf "+%s" their_info) Notty.A.(fg green) mode in - let at_symbols = W.string ~attr:Notty.A.(fg lightblue) "@@" in + let at_symbols = style_text "@@" Notty.A.(fg lightblue) mode in Ui.hcat [ at_symbols; @@ -67,91 +88,214 @@ let ui_hunk_summary (hunk : string Patch.hunk) : Nottui.ui = at_symbols; ] -let ui_unified_diff (hunk : string Patch.hunk) : Nottui.ui = - let hunk_summary = ui_hunk_summary hunk in - let hunk_content = - let blocks = Block.of_hunk hunk.Patch.lines in - let single_line_changes = - List.for_all - (function - | Block.Changed { mine; their; _ } -> - List.length mine = 1 && List.length their = 1 - | _ -> true) - blocks - in - if single_line_changes then - let word_diff_blocks = List.map WordDiff.compute blocks in - let word_diff_lines = Block.to_hunk word_diff_blocks in - WordDiff.render_hunk_lines word_diff_lines - else WordDiff.render_hunk hunk +let render_line_number (mine_num : int) (their_num : int) + (diff_type : [ `Added | `Removed | `Unchanged ]) (mode : rendering_mode) : + Ui.t = + let attr = + match mode with + | TextMarkers -> None + | Color -> ( + match diff_type with + | `Added -> Some Notty.A.(fg green) + | `Removed -> Some Notty.A.(fg red) + | `Unchanged -> None) in - Ui.vcat [ hunk_summary; hunk_content ] + match diff_type with + | `Added -> W.string ?attr (Printf.sprintf " %2d + " (their_num + 1)) + | `Removed -> W.string ?attr (Printf.sprintf "%2d - " (mine_num + 1)) + | `Unchanged -> + W.string ?attr + (Printf.sprintf "%2d %2d " (mine_num + 1) (their_num + 1)) -let current_hunks (z_patches : string Patch.t Zipper.t) : Nottui.ui = - let p = Zipper.get_focus z_patches in - let hunks = List.map ui_unified_diff p.Patch.hunks in - Ui.vcat hunks +let render_word_diff (words : WordDiff.word list) + (diff_type : [ `Added | `Removed | `Unchanged ]) (mode : rendering_mode) : + Ui.t = + let render_word = function + | WordDiff.Changed word -> style_word word diff_type mode + | WordDiff.Unchanged word -> style_word word `Unchanged mode + in + Ui.hcat (List.map render_word words) -(** Side by side diff view implementation **) +let render_diff_line (mine_num : int) (their_num : int) + (diff_type : [ `Added | `Removed | `Unchanged ]) + (content : WordDiff.word list) (mode : rendering_mode) : Ui.t = + let line_number = render_line_number mine_num their_num diff_type mode in + let content_ui = render_word_diff content diff_type mode in + Ui.hcat [ line_number; content_ui ] -let lines_with_numbers (lines : line list) (attr_change : Notty.attr) - (prefix : string) : Nottui.ui list = +let render_hunk_lines (hunk_lines : WordDiff.line_content Patch.line list) + (mode : rendering_mode) : Ui.t = + let rec process_lines mine_num their_num acc = function + | [] -> List.rev acc + | line :: rest -> + let new_mine, new_their, ui = + match line with + | `Common words -> + ( mine_num + 1, + their_num + 1, + render_diff_line mine_num their_num `Unchanged words mode ) + | `Mine words -> + ( mine_num + 1, + their_num, + render_diff_line mine_num their_num `Removed words mode ) + | `Their words -> + ( mine_num, + their_num + 1, + render_diff_line mine_num their_num `Added words mode ) + in + process_lines new_mine new_their (ui :: acc) rest + in + Ui.vcat (process_lines 0 0 [] hunk_lines) + +let render_hunk_without_word_diff (hunk : string Patch.hunk) + (mode : rendering_mode) : Ui.t = + let render_line mine_num their_num diff_type content = + let line_number = render_line_number mine_num their_num diff_type mode in + let content_ui = + style_text content + (match diff_type with + | `Added -> Notty.A.(fg green) + | `Removed -> Notty.A.(fg red) + | `Unchanged -> Notty.A.empty) + mode + in + Ui.hcat [ line_number; content_ui ] + in + let rec process_lines mine_num their_num acc = function + | [] -> List.rev acc + | line :: rest -> + let new_mine, new_their, ui = + match line with + | `Common content -> + ( mine_num + 1, + their_num + 1, + render_line mine_num their_num `Unchanged content ) + | `Mine content -> + ( mine_num + 1, + their_num, + render_line mine_num their_num `Removed content ) + | `Their content -> + ( mine_num, + their_num + 1, + render_line mine_num their_num `Added content ) + in + process_lines new_mine new_their (ui :: acc) rest + in + Ui.vcat + (process_lines hunk.Patch.mine_start hunk.Patch.their_start [] + hunk.Patch.lines) + +(* Helper functions for side-by-side view *) + +let lines_with_numbers (lines : line list) (attr_change : Notty.attr option) + (change_type : [ `Add | `Remove | `Unchanged ]) (mode : rendering_mode) : + Ui.t list = let rec process_lines line_num acc = function | [] -> List.rev acc | line :: rest -> - let content, attr, next_num = + let line_ui, next_num = match line with | Common s -> let content = Printf.sprintf "%3d %s" line_num s in - (content, Notty.A.empty, line_num + 1) + (W.string content, line_num + 1) | Change s -> - let content = Printf.sprintf "%3d %s %s" line_num prefix s in - (content, attr_change, line_num + 1) - | Empty -> - let content = Printf.sprintf " " in - (content, Notty.A.empty, line_num) + let marker = + match change_type with + | `Add -> "+" + | `Remove -> "-" + | `Unchanged -> " " + in + let line_number = Printf.sprintf "%3d" line_num in + let content = s in + ( (match mode with + | Color -> + W.string ?attr:attr_change + (Printf.sprintf "%s %s %s" line_number marker content) + | TextMarkers -> + Ui.hcat + [ + W.string (line_number ^ " "); + (match change_type with + | `Add -> added_marker (W.string (" " ^ content)) + | `Remove -> removed_marker (W.string (" " ^ content)) + | `Unchanged -> W.string (" " ^ content)); + ]), + line_num + 1 ) + | Empty -> (W.string " ", line_num) in - let new_acc = W.string ~attr content :: acc in - process_lines next_num new_acc rest + process_lines next_num (line_ui :: acc) rest in process_lines 1 [] lines let create_summary (start_line_num : int) (hunk_length : int) - (attr : Notty.attr) (change_type : [ `Add | `Remove ]) : Nottui.ui = + (attr : Notty.attr option) (change_type : [ `Add | `Remove ]) : Ui.t = let sign = match change_type with `Add -> "+" | `Remove -> "-" in - if hunk_length > 0 then - W.string ~attr - (Printf.sprintf "@@ %s%d,%d @@" sign start_line_num hunk_length) - else W.string ~attr (Printf.sprintf "@@ %s0,0 @@" sign) + let summary = + Printf.sprintf "@@ %s%d,%d @@" sign start_line_num hunk_length + in + W.string ?attr summary -let ui_of_hunk_side_by_side (hunk : string Patch.hunk) : Nottui.ui = - let attr_mine = Notty.A.(fg red ++ st bold) in - let attr_their = Notty.A.(fg green ++ st bold) in +(* Main View Functions *) - let mine_lines, their_lines = split_and_align_hunk hunk.Patch.lines in +let ui_unified_diff (hunk : string Patch.hunk) (mode : rendering_mode) : Ui.t = + let hunk_summary = render_hunk_summary hunk mode in + let hunk_content = + let blocks = Block.of_hunk hunk.Patch.lines in + let single_line_changes = + List.for_all + (function + | Block.Changed { mine; their; _ } -> + List.length mine = 1 && List.length their = 1 + | _ -> true) + blocks + in + if single_line_changes then + let word_diff_blocks = List.map WordDiff.compute blocks in + let word_diff_lines = Block.to_hunk word_diff_blocks in + render_hunk_lines word_diff_lines mode + else render_hunk_without_word_diff hunk mode + in + Ui.vcat [ hunk_summary; hunk_content ] + +let current_hunks (z_patches : string Patch.t Zipper.t) (mode : rendering_mode) + : Ui.t = + let p = Zipper.get_focus z_patches in + let hunks = List.map (fun hunk -> ui_unified_diff hunk mode) p.Patch.hunks in + Ui.vcat hunks - let content_mine = lines_with_numbers mine_lines attr_mine "-" in - let content_their = lines_with_numbers their_lines attr_their "+" in +let render_side_by_side (hunk : string Patch.hunk) (mode : rendering_mode) : + Ui.t = + let mine_lines, their_lines = split_and_align_hunk hunk.Patch.lines in + let render_lines lines change_type attr = + let attr_option = + match mode with Color -> Some attr | TextMarkers -> None + in + lines_with_numbers lines attr_option change_type mode + in + let content_mine = render_lines mine_lines `Remove Notty.A.(fg red) in + let content_their = render_lines their_lines `Add Notty.A.(fg green) in let summary_mine = create_summary (hunk.Patch.mine_start + 1) - hunk.Patch.mine_len attr_mine `Remove + hunk.Patch.mine_len + (match mode with Color -> Some Notty.A.(fg red) | TextMarkers -> None) + `Remove in let summary_their = create_summary (hunk.Patch.their_start + 1) - hunk.Patch.their_len attr_their `Add + hunk.Patch.their_len + (match mode with Color -> Some Notty.A.(fg green) | TextMarkers -> None) + `Add in - let space = Ui.space 1 0 in Ui.hcat [ Ui.resize ~w:0 ~sw:2 (Ui.vcat (summary_mine :: content_mine)); - space; + Ui.space 1 0; Ui.resize ~w:0 ~sw:2 (Ui.vcat (summary_their :: content_their)); ] -let current_hunks_side_by_side (z_patches : string Patch.t Zipper.t) : Nottui.ui - = +let current_hunks_side_by_side (z_patches : string Patch.t Zipper.t) + (mode : rendering_mode) : Ui.t = let p = Zipper.get_focus z_patches in - let hunks_ui = List.map ui_of_hunk_side_by_side p.Patch.hunks in - Ui.vcat hunks_ui + Ui.vcat (List.map (fun hunk -> render_side_by_side hunk mode) p.Patch.hunks) diff --git a/lib/HunkView.mli b/lib/HunkView.mli index 4e408cb..e0b129b 100644 --- a/lib/HunkView.mli +++ b/lib/HunkView.mli @@ -1,7 +1,10 @@ -val current_hunks : string Patch.t Zipper.t -> Nottui.ui +type rendering_mode = Color | TextMarkers + +val current_hunks : string Patch.t Zipper.t -> rendering_mode -> Nottui.ui (** [current_hunks zipper] returns the current hunks in a patch zipper for normal view. *) -val current_hunks_side_by_side : string Patch.t Zipper.t -> Nottui.ui +val current_hunks_side_by_side : + string Patch.t Zipper.t -> rendering_mode -> Nottui.ui (** [current_hunks_side_by_side zipper] returns the current hunks in a patch zipper for side-by-side view. *) diff --git a/lib/InteractiveViewer.ml b/lib/InteractiveViewer.ml index cab3902..fa67c08 100644 --- a/lib/InteractiveViewer.ml +++ b/lib/InteractiveViewer.ml @@ -5,18 +5,26 @@ open Lwd_infix type view_mode = SideBySide | Normal let view_mode : view_mode Lwd.var = Lwd.var Normal +let render_mode : HunkView.rendering_mode Lwd.var = Lwd.var HunkView.Color let toggle_view_mode () : unit = match Lwd.peek view_mode with | Normal -> Lwd.set view_mode SideBySide | SideBySide -> Lwd.set view_mode Normal +let toggle_render_mode () : unit = + match Lwd.peek render_mode with + | HunkView.Color -> Lwd.set render_mode HunkView.TextMarkers + | HunkView.TextMarkers -> Lwd.set render_mode HunkView.Color + let help_visible = Lwd.var false let quit = Lwd.var false let toggle_help_visibility () = Lwd.set help_visible (not (Lwd.peek help_visible)) +let help_string = "[h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode" + let view (patches : string Patch.t list) = let z_patches_var : string Patch.t Zipper.t Lwd.var = match Zipper.zipper_of_list patches with @@ -24,10 +32,12 @@ let view (patches : string Patch.t list) = | None -> failwith "zipper_of_list: empty list" in let hunks_ui = - let$ mode = Lwd.get view_mode and$ z_patches = Lwd.get z_patches_var in + let$ mode = Lwd.get view_mode + and$ z_patches = Lwd.get z_patches_var + and$ render_mode = Lwd.get render_mode in match mode with - | Normal -> HunkView.current_hunks z_patches - | SideBySide -> HunkView.current_hunks_side_by_side z_patches + | Normal -> HunkView.current_hunks z_patches render_mode + | SideBySide -> HunkView.current_hunks_side_by_side z_patches render_mode in let curr_scroll_state = Lwd.var W.default_scroll_state in let change_scroll_state _action state = @@ -83,11 +93,11 @@ let view (patches : string Patch.t list) = | `ASCII 't', [] -> toggle_view_mode (); `Handled + | `ASCII 'r', [] -> + toggle_render_mode (); + `Handled | _ -> `Unhandled) - (W.string - "Type 'h' to go to the help panel, 'q' to quit, 'n' to go to \ - the next operation, 'p' to go to the previous operation. \ - Press 't' to toggle view mode."); + (W.string help_string); ] in Lwd.return ui diff --git a/lib/WordDiff.ml b/lib/WordDiff.ml index aaf94ce..6faac06 100644 --- a/lib/WordDiff.ml +++ b/lib/WordDiff.ml @@ -1,6 +1,3 @@ -open Nottui -module W = Nottui_widgets - type word = Unchanged of string | Changed of string type line_content = word list @@ -62,100 +59,3 @@ let compute (block : string Block.t) : line_content Block.t = let their_str = String.concat " " their in let mine_words, their_words = diff_words mine_str their_str in Block.Changed { mine = [ mine_words ]; their = [ their_words ]; order } - -let word_to_ui word attr = W.string ~attr (word ^ " ") - -let render_diff_line mine_num their_num attr diff_type words = - let format_line_number = - match diff_type with - | `Added -> W.string ~attr (Printf.sprintf " %2d + " (their_num + 1)) - | `Deleted -> W.string ~attr (Printf.sprintf "%2d - " (mine_num + 1)) - | `Equal -> - W.string ~attr:Notty.A.empty - (Printf.sprintf "%2d %2d " (mine_num + 1) (their_num + 1)) - in - Ui.hcat - [ - format_line_number; - Ui.hcat - (List.map - (function - | Changed word when diff_type = `Deleted || diff_type = `Added -> - word_to_ui word attr - | Unchanged word -> word_to_ui word Notty.A.empty - | _ -> Ui.empty) - words); - ] - -let render_hunk_lines (hunk_lines : line_content Patch.line list) : Nottui.ui = - let rec process_lines mine_num their_num acc = function - | [] -> List.rev acc - | line :: rest -> - let new_mine, new_their, ui = - match line with - | `Common words -> - ( mine_num + 1, - their_num + 1, - render_diff_line mine_num their_num Notty.A.empty `Equal words - ) - | `Mine words -> - ( mine_num + 1, - their_num, - render_diff_line mine_num their_num - Notty.A.(fg red) - `Deleted words ) - | `Their words -> - ( mine_num, - their_num + 1, - render_diff_line mine_num their_num - Notty.A.(fg green) - `Added words ) - in - process_lines new_mine new_their (ui :: acc) rest - in - let lines_ui = process_lines 0 0 [] hunk_lines in - Ui.vcat lines_ui - -let render_diff_line_str (mine_num : int) (their_num : int) (attr : Notty.attr) - (diff_type : [ `Equal | `Deleted | `Added ]) (content : string) : Ui.t = - let format_line_number = - match diff_type with - | `Added -> W.string ~attr (Printf.sprintf " %2d + " (their_num + 1)) - | `Deleted -> W.string ~attr (Printf.sprintf "%2d - " (mine_num + 1)) - | `Equal -> - W.string ~attr:Notty.A.empty - (Printf.sprintf "%2d %2d " (mine_num + 1) (their_num + 1)) - in - let content_ui = W.string ~attr content in - Ui.hcat [ format_line_number; content_ui ] - -let render_line_diff (mine_num : int) (their_num : int) - (line : string Patch.line) : int * int * Ui.t = - match line with - | `Common s -> - ( mine_num + 1, - their_num + 1, - render_diff_line_str mine_num their_num Notty.A.empty `Equal s ) - | `Mine s -> - ( mine_num + 1, - their_num, - render_diff_line_str mine_num their_num Notty.A.(fg red) `Deleted s ) - | `Their s -> - ( mine_num, - their_num + 1, - render_diff_line_str mine_num their_num Notty.A.(fg green) `Added s ) - -let render_hunk (hunk : string Patch.hunk) : Nottui.ui = - let lines_ui = - let rec process_lines mine_num their_num acc = function - | [] -> List.rev acc - | line :: rest -> - let new_mine, new_their, ui = - render_line_diff mine_num their_num line - in - process_lines new_mine new_their (ui :: acc) rest - in - process_lines hunk.Patch.mine_start hunk.Patch.their_start [] - hunk.Patch.lines - in - Ui.vcat lines_ui diff --git a/lib/WordDiff.mli b/lib/WordDiff.mli index 0dae84a..f9a5cda 100644 --- a/lib/WordDiff.mli +++ b/lib/WordDiff.mli @@ -2,8 +2,6 @@ type word = Unchanged of string | Changed of string type line_content = word list val compute : string Block.t -> line_content Block.t -val render_hunk_lines : line_content Patch.line list -> Nottui.ui -val render_hunk : string Patch.hunk -> Nottui.Ui.t (* for tests *) val lcs : 'a list -> 'a list -> 'a list diff --git a/test/cram/test.t b/test/cram/test.t index e96fbb8..3b780e1 100644 --- a/test/cram/test.t +++ b/test/cram/test.t @@ -21,7 +21,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n Operation 2 of 14, 1 hunk 3 additions, 1 removal @@ -42,7 +42,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n Operation 3 of 14, 1 hunk 1 addition, 1 removal @@ -63,7 +63,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff h Help Panel: @@ -105,7 +105,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal more-examples.diff n Operation 2 of 2, 1 hunk 2 additions, 1 removal @@ -126,7 +126,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode @@ -154,7 +154,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal more-examples.diff n t Operation 2 of 2, 1 hunk @@ -176,7 +176,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n t Operation 3 of 14, 1 hunk @@ -198,7 +198,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n n t Operation 4 of 14, 1 hunk @@ -220,7 +220,7 @@ This is a cram test for the new executable. 13 let quit = Lwd.var false 6 let quit = Lwd.var false 14 - let counter = Lwd.var 0 7 + let string_of_operation = Format.asprintf "%a" (Patch.pp_operation ~ 15 - let counter_d = Lwd.get counter - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n n n t @@ -243,7 +243,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n n n n t @@ -266,7 +266,7 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n n n n n n t Operation 8 of 14, 1 hunk @@ -288,13 +288,13 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n n n n n n n n t Operation 10 of 14, 1 hunk 0 additions, 1 removal Deletion of dir1/file.txt - @@ -1,1 @@ @@ +0,0 @@ + @@ -1,1 @@ @@ +1,0 @@ 1 - some text @@ -310,13 +310,13 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n n n n n n n n n n n t Operation 13 of 14, 1 hunk 2 additions, 0 removals Creation of dir2/sample.txt - @@ -0,0 @@ @@ +1,2 @@ + @@ -1,0 @@ @@ +1,2 @@ 1 + some text 2 + lorem ipsum @@ -332,13 +332,13 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n n n n n n n n n n n n n n t Operation 14 of 14, 1 hunk 1 addition, 0 removals Rename with modifications dir1/file.txt to dir2/file.txt - @@ -0,0 @@ @@ +1,1 @@ + @@ -1,0 @@ @@ +1,1 @@ 1 + new text @@ -354,14 +354,14 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal example.diff n n n n n n n n n n n n n n n n t Operation 14 of 14, 1 hunk 1 addition, 0 removals Rename with modifications dir1/file.txt to dir2/file.txt - @@ -0,0 @@ @@ +1,1 @@ + @@ -1,0 @@ @@ +1,1 @@ 1 + new text @@ -377,9 +377,139 @@ This is a cram test for the new executable. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode +# Test unified view with text markers (colorless) + $ dummy_terminal example.diff r + Operation 1 of 14, 1 hunk + 1 addition, 1 removal + Modification of bin/dune + @@ -1,4 +1,4 @@ + 1 1 (executable + 2 2 (public_name diffcessible) + 3 3 (name main) + 4 - (libraries diffcessible -cmdliner)) + 4 + (libraries diffcessible +cmdliner +patch)) + + + + + + + + + + + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode +# Test side-by-side view with text markers (colorless) + $ dummy_terminal example.diff t r + Operation 1 of 14, 1 hunk + 1 addition, 1 removal + Modification of bin/dune + @@ -1,4 @@ @@ +1,4 @@ + 1 (executable 1 (executable + 2 (public_name diffcessible) 2 (public_name diffcessible) + 3 (name main) 3 (name main) + 4 - (libraries diffcessible cmdliner)) 4 + (libraries diffcessible cmdliner patch)) + + + + + + + + + + + + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode + $ dummy_terminal example.diff n n r + Operation 3 of 14, 1 hunk + 1 addition, 1 removal + Modification of lib/dune + @@ -1,3 +1,3 @@ + 1 1 (library + 2 2 (name diffcessible) + 3 - (libraries notty nottui -lwd)) + 3 + (libraries notty nottui +lwd +patch)) + + + + + + + + + + + + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode + + $ dummy_terminal example.diff n n n r + Operation 4 of 14, 1 hunk + 6 additions, 20 removals + Modification of lib/interactive_viewer.ml + @@ -1,39 +1,25 @@ + 1 1 open Nottui + 2 2 module W = Nottui_widgets + 3 - open Lwd_infix + 4 - + 5 - type patch = unit + 3 + (* open Lwd_infix *) + 6 4 + 7 5 let pure_str s = Lwd.pure (W.string s) + 8 - + 9 - let string_of_counter c = + 10 - let$ c = c in + 11 - W.string (string_of_int c) + 12 - + 13 6 let quit = Lwd.var false + 14 - let counter = Lwd.var 0 + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode + $ dummy_terminal example.diff n n r t + Operation 3 of 14, 1 hunk + 1 addition, 1 removal + Modification of lib/dune + @@ -1,3 @@ @@ +1,3 @@ + 1 (library 1 (library + 2 (name diffcessible) 2 (name diffcessible) + 3 - (libraries notty nottui lwd)) 3 + (libraries notty nottui lwd patch)) + + + + + + + + + + + + + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode + + $ dummy_terminal example.diff n n n r t + Operation 4 of 14, 1 hunk + 6 additions, 20 removals + Modification of lib/interactive_viewer.ml + @@ -1,39 @@ @@ +1,25 @@ + 1 open Nottui 1 open Nottui + 2 module W = Nottui_widgets 2 module W = Nottui_widgets + 3 - open Lwd_infix 3 + (* open Lwd_infix *) + 4 - + 5 - type patch = unit + 6 4 + 7 let pure_str s = Lwd.pure (W.string s) 5 let pure_str s = Lwd.pure (W.string s) + 8 - + 9 - let string_of_counter c = + 10 - let$ c = c in + 11 - W.string (string_of_int c) + 12 - + 13 let quit = Lwd.var false 6 let quit = Lwd.var false + 14 - let counter = Lwd.var 0 7 + let string_of_operation = Format.asprintf "%a" (Patch.pp_operation ~ + 15 - let counter_d = Lwd.get counter + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode diff --git a/test/cram/word-diff.t/run.t b/test/cram/word-diff.t/run.t index 873b0b9..d0acd96 100644 --- a/test/cram/word-diff.t/run.t +++ b/test/cram/word-diff.t/run.t @@ -19,7 +19,7 @@ 3 3 Actions speak louder than words. @@ -11,2 +11,2 @@ 1 - The early bird catches the worm. - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode $ dummy_terminal examples.diff n Operation 2 of 2, 3 hunks 3 additions, 3 removals @@ -40,6 +40,6 @@ - Type 'h' to go to the help panel, 'q' to quit, 'n' to go to the next operation, 'p' to go to the previous operation. Press 't' to toggle view mode. + [h]elp [q]uit [n/p]avigate [t]oggle view [r]ender mode diff --git a/test/unit/TestBlock.ml b/test/unit/TestBlock.ml index 01668c7..d6612b2 100644 --- a/test/unit/TestBlock.ml +++ b/test/unit/TestBlock.ml @@ -5,8 +5,8 @@ let example_hunk1 : string Patch.line list = let example_blocks1 : string Block.t list = [ - Block.Changed { mine = [ "A" ]; their = [ "B" ]; order = Block.Mine }; - Block.Changed { mine = [ "C" ]; their = [ "D" ]; order = Block.Mine }; + Block.Changed { mine = [ "A" ]; their = [ "B" ]; order = Mine }; + Block.Changed { mine = [ "C" ]; their = [ "D" ]; order = Mine }; ] let empty_hunk : string Patch.line list = [] @@ -22,15 +22,13 @@ let mine_only_hunk : string Patch.line list = [ `Mine "A"; `Mine "B"; `Mine "C" ] let mine_only_blocks : string Block.t list = - [ Block.Changed { mine = [ "A"; "B"; "C" ]; their = []; order = Block.Mine } ] + [ Block.Changed { mine = [ "A"; "B"; "C" ]; their = []; order = Mine } ] let their_only_hunk : string Patch.line list = [ `Their "X"; `Their "Y"; `Their "Z" ] let their_only_blocks : string Block.t list = - [ - Block.Changed { mine = []; their = [ "X"; "Y"; "Z" ]; order = Block.Their }; - ] + [ Block.Changed { mine = []; their = [ "X"; "Y"; "Z" ]; order = Their } ] let complex_hunk : string Patch.line list = [ @@ -48,10 +46,10 @@ let complex_hunk : string Patch.line list = let complex_blocks : string Block.t list = [ Block.Common "A"; - Block.Changed { mine = [ "B" ]; their = [ "C" ]; order = Block.Mine }; - Block.Changed { mine = [ "D" ]; their = [ "E" ]; order = Block.Mine }; + Block.Changed { mine = [ "B" ]; their = [ "C" ]; order = Mine }; + Block.Changed { mine = [ "D" ]; their = [ "E" ]; order = Mine }; Block.Common "F"; - Block.Changed { mine = [ "G" ]; their = [ "H"; "I" ]; order = Block.Mine }; + Block.Changed { mine = [ "G" ]; their = [ "H"; "I" ]; order = Mine }; ] let alternating_add_remove_hunk1 : string Patch.line list = @@ -59,8 +57,8 @@ let alternating_add_remove_hunk1 : string Patch.line list = let alternating_add_remove_blocks1 : string Block.t list = [ - Block.Changed { mine = [ "A" ]; their = [ "B" ]; order = Block.Mine }; - Block.Changed { mine = [ "C" ]; their = []; order = Block.Mine }; + Block.Changed { mine = [ "A" ]; their = [ "B" ]; order = Mine }; + Block.Changed { mine = [ "C" ]; their = []; order = Mine }; ] let alternating_remove_add_hunk1 : string Patch.line list = @@ -68,8 +66,8 @@ let alternating_remove_add_hunk1 : string Patch.line list = let alternating_remove_add_blocks1 : string Block.t list = [ - Block.Changed { mine = [ "Y" ]; their = [ "X" ]; order = Block.Their }; - Block.Changed { mine = []; their = [ "Z" ]; order = Block.Their }; + Block.Changed { mine = [ "Y" ]; their = [ "X" ]; order = Their }; + Block.Changed { mine = []; their = [ "Z" ]; order = Their }; ] let complex_alternating_hunk : string Patch.line list = @@ -91,13 +89,13 @@ let complex_alternating_hunk : string Patch.line list = let complex_alternating_blocks : string Block.t list = [ - Block.Changed { mine = [ "A" ]; their = [ "B" ]; order = Block.Mine }; - Block.Changed { mine = [ "C" ]; their = [ "D" ]; order = Block.Mine }; - Block.Changed { mine = [ "E" ]; their = [ "F" ]; order = Block.Mine }; - Block.Changed { mine = [ "G" ]; their = [ "H" ]; order = Block.Mine }; + Block.Changed { mine = [ "A" ]; their = [ "B" ]; order = Mine }; + Block.Changed { mine = [ "C" ]; their = [ "D" ]; order = Mine }; + Block.Changed { mine = [ "E" ]; their = [ "F" ]; order = Mine }; + Block.Changed { mine = [ "G" ]; their = [ "H" ]; order = Mine }; Block.Common "I"; - Block.Changed { mine = [ "K" ]; their = [ "J" ]; order = Block.Their }; - Block.Changed { mine = [ "M" ]; their = [ "L" ]; order = Block.Their }; + Block.Changed { mine = [ "K" ]; their = [ "J" ]; order = Their }; + Block.Changed { mine = [ "M" ]; their = [ "L" ]; order = Their }; ] let multiple_consecutive_changes_hunk : string Patch.line list = @@ -119,13 +117,10 @@ let multiple_consecutive_changes_hunk : string Patch.line list = let multiple_consecutive_changes_blocks : string Block.t list = [ - Block.Changed - { mine = [ "A"; "B" ]; their = [ "C"; "D" ]; order = Block.Mine }; - Block.Changed - { mine = [ "E"; "F" ]; their = [ "G"; "H" ]; order = Block.Mine }; + Block.Changed { mine = [ "A"; "B" ]; their = [ "C"; "D" ]; order = Mine }; + Block.Changed { mine = [ "E"; "F" ]; their = [ "G"; "H" ]; order = Mine }; Block.Common "I"; - Block.Changed - { mine = [ "L"; "M" ]; their = [ "J"; "K" ]; order = Block.Their }; + Block.Changed { mine = [ "L"; "M" ]; their = [ "J"; "K" ]; order = Their }; ] let string_of_block = function @@ -134,10 +129,7 @@ let string_of_block = function Printf.sprintf "Changed { mine = [%s]; their = [%s]; order = %s }" (String.concat "; " (List.map (Printf.sprintf "%S") mine)) (String.concat "; " (List.map (Printf.sprintf "%S") their)) - (match order with - | Block.Mine -> "Mine" - | Block.Their -> "Their" - | Block.None -> "None") + (match order with Mine -> "Mine" | Their -> "Their" | None -> "None") let string_of_blocks blocks = "[" ^ String.concat "; " (List.map string_of_block blocks) ^ "]" diff --git a/test/unit/TestWordDiff.ml b/test/unit/TestWordDiff.ml index 8a325b5..18aae91 100644 --- a/test/unit/TestWordDiff.ml +++ b/test/unit/TestWordDiff.ml @@ -12,8 +12,8 @@ let test_lcs_4 = ([], [], []) (* Empty lists *) let test_lcs_5 = ([ "a"; "a"; "b"; "b"; "c" ], [ "a"; "b"; "c"; "c" ], [ "a"; "b"; "c" ]) -(* Repeating elements *) +(* Repeating elements *) let test_lcs_6 = ([ "a"; "b"; "c" ], [ "d"; "e"; "f" ], []) (* All different, same length *) @@ -121,6 +121,7 @@ let test_diff_words () = List.iter test_case [ test_diff_1; test_diff_2; test_diff_3; test_diff_4; test_diff_5 ] +(* Updated run_tests function *) let run_tests () = let run_test name f = try