Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Towards word diffing #75

Merged
merged 32 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
feaac1a
Polymorphize Patch.t
panglesd Jul 22, 2024
8ef9470
Apply ocamlformat on docstrings
panglesd Jul 22, 2024
b303194
Add an unimplemented `Block` module
panglesd Jul 22, 2024
f44d1ac
Add an unimplemented WordDiff module
panglesd Jul 22, 2024
3ff6c9f
initial commit
yokurang Jul 25, 2024
4adc84e
initial commit
yokurang Jul 25, 2024
d756e85
clean up
yokurang Jul 25, 2024
18b0fe1
Word Diff Implementation for Normal View (#74)
yokurang Jul 25, 2024
e32a03a
added comments
yokurang Jul 25, 2024
014e3bb
Polymorphize Patch.t
panglesd Jul 22, 2024
9d9a9ba
Apply ocamlformat on docstrings
panglesd Jul 22, 2024
f93adad
Add an unimplemented `Block` module
panglesd Jul 22, 2024
6777728
Add an unimplemented WordDiff module
panglesd Jul 22, 2024
929db0c
initial commit
yokurang Jul 25, 2024
a9bb086
initial commit
yokurang Jul 25, 2024
21d90b6
clean up
yokurang Jul 25, 2024
aff37fd
added comments
yokurang Jul 25, 2024
9652119
rebased
yokurang Jul 25, 2024
03b5fc9
rebased
yokurang Jul 25, 2024
3e79f14
rebased
yokurang Jul 25, 2024
0e5ddc8
attmpting of_hunk in test block
yokurang Jul 26, 2024
b92a496
working mvp
yokurang Jul 29, 2024
35c3a0f
blocks
yokurang Jul 29, 2024
77efe74
fixed of_hunk function
yokurang Jul 30, 2024
7fb1da8
formatted
yokurang Jul 30, 2024
60f70a4
trying to optimise
yokurang Jul 30, 2024
e0e43ba
addressed jule's comments
yokurang Jul 30, 2024
96f395b
added Newline type
yokurang Aug 2, 2024
18599e7
test word diff modularly
yokurang Aug 2, 2024
63e70c8
first version of word diff with blocks
yokurang Aug 2, 2024
280cb82
add tests
yokurang Aug 2, 2024
4f37860
add tests
yokurang Aug 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .ocamlformat
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
version = 0.26.1
version = 0.26.1
parse-docstrings=true
50 changes: 50 additions & 0 deletions lib/Block.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
type 'a t = Common of 'a | Changed of { mine : 'a list; their : 'a list }

(* Helper function implementations *)
let rec group_lines acc current_mine current_their = function
| [] ->
if current_mine <> [] || current_their <> [] then
Changed { mine = current_mine; their = current_their } :: acc
else acc
| `Common line :: rest ->
let acc' =
if current_mine <> [] || current_their <> [] then
Changed { mine = current_mine; their = current_their } :: acc
else acc
in
group_lines (Common line :: acc') [] [] rest
| `Mine line :: rest ->
group_lines acc (line :: current_mine) current_their rest
| `Their line :: rest ->
group_lines acc current_mine (line :: current_their) rest

let rec process_blocks lines mine_len their_len = function
| [] -> (lines, mine_len, their_len)
| Common line :: rest ->
process_blocks (`Common line :: lines) (mine_len + 1) (their_len + 1) rest
| Changed { mine; their } :: rest ->
let mine_lines = List.rev_map (fun line -> `Mine line) mine in
let their_lines = List.rev_map (fun line -> `Their line) their in
process_blocks
(List.rev_append mine_lines (List.rev_append their_lines lines))
(mine_len + List.length mine)
(their_len + List.length their)
rest

(* End of helper function implementations *)

(* Main block function implementations *)
let of_hunk (_hunk : 'a Patch.hunk) : 'a t list =
List.rev (group_lines [] [] [] _hunk.lines)

let to_hunk (_blocks : 'a t list) : 'a Patch.hunk =
let lines, mine_len, their_len = process_blocks [] 0 0 _blocks in
{
mine_start = 0;
mine_len;
their_start = 0;
their_len;
lines = List.rev lines;
}

(* End of main block function implementations *)
9 changes: 9 additions & 0 deletions lib/Block.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
type 'a t = Common of 'a | Changed of { mine : 'a list; their : 'a list }

val of_hunk : 'a Patch.hunk -> 'a t list
(** Turns a hunk into a list of blocks by grouping consecutive changed lines. *)

val to_hunk : 'a t list -> 'a Patch.hunk
(** Turns back a list of blocks into a hunk.

[x |> of_hunk |> to_hunk] should yield [x] back. *)
11 changes: 6 additions & 5 deletions lib/HunkView.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module W = Nottui_widgets

(* Implementation of Single View Mode *)

let ui_hunk_summary (hunk : Patch.hunk) : Nottui.ui =
let ui_hunk_summary (hunk : string Patch.hunk) : Nottui.ui =
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
Expand Down Expand Up @@ -61,7 +61,7 @@ let rec process_lines (mine_num : int) (their_num : int) (acc : Nottui.ui list)
in
process_lines new_mine new_their (ui_element :: acc) rest

let ui_unified_diff (hunk : Patch.hunk) : Nottui.ui =
let ui_unified_diff (hunk : string Patch.hunk) : Nottui.ui =
let lines_ui =
process_lines hunk.Patch.mine_start hunk.Patch.their_start []
hunk.Patch.lines
Expand All @@ -70,7 +70,7 @@ let ui_unified_diff (hunk : Patch.hunk) : Nottui.ui =

Ui.vcat [ ui_hunk_summary hunk; lines_ui_vcat ]

let current_hunks (z_patches : Patch.t Zipper.t) : Nottui.ui =
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
Expand Down Expand Up @@ -151,7 +151,7 @@ let create_summary (start_line_num : int) (hunk_length : int)
(Printf.sprintf "@@ %s%d,%d @@" sign start_line_num hunk_length)
else W.string ~attr (Printf.sprintf "@@ %s0,0 @@" sign)

let ui_of_hunk_side_by_side (hunk : Patch.hunk) : Nottui.ui =
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

Expand All @@ -177,7 +177,8 @@ let ui_of_hunk_side_by_side (hunk : Patch.hunk) : Nottui.ui =
Ui.resize ~w:0 ~sw:2 (Ui.vcat (summary_their :: content_their));
]

let current_hunks_side_by_side (z_patches : Patch.t Zipper.t) : Nottui.ui =
let current_hunks_side_by_side (z_patches : string Patch.t Zipper.t) : Nottui.ui
=
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
10 changes: 6 additions & 4 deletions lib/HunkView.mli
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
val current_hunks : Patch.t Zipper.t -> Nottui.ui
(** [current_hunks zipper] returns the current hunks in a patch zipper for normal view. *)
val current_hunks : string Patch.t Zipper.t -> Nottui.ui
(** [current_hunks zipper] returns the current hunks in a patch zipper for
normal view. *)

val current_hunks_side_by_side : Patch.t Zipper.t -> Nottui.ui
(** [current_hunks_side_by_side zipper] returns the current hunks in a patch zipper for side-by-side view. *)
val current_hunks_side_by_side : string Patch.t Zipper.t -> Nottui.ui
(** [current_hunks_side_by_side zipper] returns the current hunks in a patch
zipper for side-by-side view. *)
4 changes: 2 additions & 2 deletions lib/InteractiveViewer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ let quit = Lwd.var false
let toggle_help_visibility () =
Lwd.set help_visible (not (Lwd.peek help_visible))

let view (patches : Patch.t list) =
let z_patches_var : Patch.t Zipper.t Lwd.var =
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
| Some z -> Lwd.var z
| None -> failwith "zipper_of_list: empty list"
Expand Down
7 changes: 4 additions & 3 deletions lib/InteractiveViewer.mli
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
val start : ?term:Notty_unix.Term.t -> Patch.t list -> unit
val start : ?term:Notty_unix.Term.t -> string Patch.t list -> unit
(** [start patches] starts diffcessible with the given patches *)

val start_test : Patch.t list -> char list -> int -> int -> unit
(** [start_test patches input start_line start_col] starts diffcessible with the given patches and input *)
val start_test : string Patch.t list -> char list -> int -> int -> unit
(** [start_test patches input start_line start_col] starts diffcessible with the
given patches and input *)
8 changes: 4 additions & 4 deletions lib/OperationView.ml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
open Nottui
module W = Nottui_widgets

let operation_info (z_patches : Patch.t Zipper.t) : Nottui.ui =
let operation_info (z_patches : string Patch.t Zipper.t) : Nottui.ui =
let p = Zipper.get_focus z_patches in
let num_hunks = List.length p.Patch.hunks in
let hunk_text =
Expand Down Expand Up @@ -45,7 +45,7 @@ let ui_of_operation (operation : Patch.operation) : Nottui.ui =
Ui.hcat
[ W.string "Modification of "; W.string ~attr:blue_bold_attr path ]

let current_operation (z_patches : Patch.t Zipper.t) : Nottui.ui =
let current_operation (z_patches : string Patch.t Zipper.t) : Nottui.ui =
let p = Zipper.get_focus z_patches in
ui_of_operation p.Patch.operation

Expand All @@ -58,7 +58,7 @@ let additions_and_removals lines : int * int =
in
List.fold_left add_line (0, 0) lines

let accumulate_count (hunks : Patch.hunk list) : int * int =
let accumulate_count (hunks : string Patch.hunk list) : int * int =
List.fold_left
(fun (add_acc, remove_acc) hunk ->
let add_in_hunk, remove_in_hunk =
Expand All @@ -67,7 +67,7 @@ let accumulate_count (hunks : Patch.hunk list) : int * int =
(add_acc + add_in_hunk, remove_acc + remove_in_hunk))
(0, 0) hunks

let change_summary (z_patches : Patch.t Zipper.t) : Nottui.ui =
let change_summary (z_patches : string Patch.t Zipper.t) : Nottui.ui =
let p = Zipper.get_focus z_patches in
let total_additions, total_removals = accumulate_count p.Patch.hunks in
let format_plural n singular plural =
Expand Down
18 changes: 9 additions & 9 deletions lib/OperationView.mli
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
val operation_info : Patch.t Zipper.t -> Nottui.ui
(** [operation_info zipper] returns a UI element that displays information about the
current operation in the zipper. *)
val operation_info : string Patch.t Zipper.t -> Nottui.ui
(** [operation_info zipper] returns a UI element that displays information about
the current operation in the zipper. *)

val change_summary : Patch.t Zipper.t -> Nottui.ui
(** [change_summary zipper] returns a UI element that displays a summary of the changes
that will be made by the current operation in the zipper. *)
val change_summary : string Patch.t Zipper.t -> Nottui.ui
(** [change_summary zipper] returns a UI element that displays a summary of the
changes that will be made by the current operation in the zipper. *)

val current_operation : Patch.t Zipper.t -> Nottui.ui
(** [current_operation zipper] returns a UI element that displays the current operation
in the zipper. *)
val current_operation : string Patch.t Zipper.t -> Nottui.ui
(** [current_operation zipper] returns a UI element that displays the current
operation in the zipper. *)
2 changes: 1 addition & 1 deletion lib/PatchNavigation.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ module W = Nottui_widgets

type direction = Prev | Next

let navigate (dir : direction) : Patch.t Zipper.t -> Patch.t Zipper.t =
let navigate (dir : direction) =
match dir with Prev -> Zipper.prev | Next -> Zipper.next
2 changes: 1 addition & 1 deletion lib/PatchNavigation.mli
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ type direction =
| Prev
| Next (** [direction] represents the direction of navigation. *)

val navigate : direction -> Patch.t Zipper.t -> Patch.t Zipper.t
val navigate : direction -> 'a Patch.t Zipper.t -> 'a Patch.t Zipper.t
(** [navigate direction zipper] returns the zipper that is the result of
navigating in the given direction. *)
4 changes: 4 additions & 0 deletions lib/WordDiff.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type word = Unchanged of string | Changed of string
type line_content = word list

let compute _block = failwith "TODO"
4 changes: 4 additions & 0 deletions lib/WordDiff.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type word = Unchanged of string | Changed of string
type line_content = word list

val compute : string Block.t -> line_content Block.t
23 changes: 14 additions & 9 deletions lib/zipper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ type 'a t = {
current_index : int; (* 0-based index *)
}

(** [zipper_of_list lst] converts a list into a zipper. If the list is empty, it returns [None].
Otherwise, it returns [Some zipper] with the first element of the list as the focus. *)
(** [zipper_of_list lst] converts a list into a zipper. If the list is empty, it
returns [None]. Otherwise, it returns [Some zipper] with the first element
of the list as the focus. *)
let zipper_of_list lst : 'a t option =
match lst with
| [] -> None
Expand All @@ -28,8 +29,8 @@ let zipper_of_list lst : 'a t option =
current_index = 0;
}

(** [next z] moves the focus of the zipper [z] to the next element, if any.
If the focus is on the last element, the zipper remains unchanged. *)
(** [next z] moves the focus of the zipper [z] to the next element, if any. If
the focus is on the last element, the zipper remains unchanged. *)
let next z =
match z.after with
| [] -> z
Expand All @@ -43,7 +44,7 @@ let next z =
}

(** [prev z] moves the focus of the zipper [z] to the previous element, if any.
If the focus is on the first element, the zipper remains unchanged. *)
If the focus is on the first element, the zipper remains unchanged. *)
let prev z =
match z.before with
| [] -> z
Expand All @@ -59,14 +60,18 @@ let prev z =
(** [get_focus z] returns the current focus of the zipper [z]. *)
let get_focus z = z.focus

(** [get_before z] returns the list of elements before the focus in the zipper [z]. *)
(** [get_before z] returns the list of elements before the focus in the zipper
[z]. *)
let get_before z = z.before

(** [get_after z] returns the list of elements after the focus in the zipper [z]. *)
(** [get_after z] returns the list of elements after the focus in the zipper
[z]. *)
let get_after z = z.after

(** [get_total_length z] returns the total length of the list represented by the zipper [z]. *)
(** [get_total_length z] returns the total length of the list represented by the
zipper [z]. *)
let get_total_length z = z.total_length

(** [get_current_index z] returns the current index of the focus in the zipper [z]. *)
(** [get_current_index z] returns the current index of the focus in the zipper
[z]. *)
let get_current_index z = z.current_index
24 changes: 15 additions & 9 deletions lib/zipper.mli
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
type 'a t
(** Abstract type for a zipper for elements of type ['a] that allows for efficient traversal of a list. *)
(** Abstract type for a zipper for elements of type ['a] that allows for
efficient traversal of a list. *)

val zipper_of_list : 'a list -> 'a t option
(** [zipper_of_list lst] converts a list into a zipper. If the list is empty, it returns [None].
Otherwise, it returns [Some zipper] with the first element of the list as the focus. *)
(** [zipper_of_list lst] converts a list into a zipper. If the list is empty, it
returns [None]. Otherwise, it returns [Some zipper] with the first element
of the list as the focus. *)

val next : 'a t -> 'a t
(** [next z] moves the focus of the zipper [z] to the next element, if any.
If the focus is on the last element, the zipper remains unchanged. *)
(** [next z] moves the focus of the zipper [z] to the next element, if any. If
the focus is on the last element, the zipper remains unchanged. *)

val prev : 'a t -> 'a t
(** [prev z] moves the focus of the zipper [z] to the previous element, if any.
Expand All @@ -17,13 +19,17 @@ val get_focus : 'a t -> 'a
(** [get_focus z] returns the current focus of the zipper [z]. *)

val get_before : 'a t -> 'a list
(** [get_before z] returns the list of elements before the focus in the zipper [z]. *)
(** [get_before z] returns the list of elements before the focus in the zipper
[z]. *)

val get_after : 'a t -> 'a list
(** [get_after z] returns the list of elements after the focus in the zipper [z]. *)
(** [get_after z] returns the list of elements after the focus in the zipper
[z]. *)

val get_total_length : 'a t -> int
(** [get_total_length z] returns the total length of the list represented by the zipper [z]. *)
(** [get_total_length z] returns the total length of the list represented by the
zipper [z]. *)

val get_current_index : 'a t -> int
(** [get_current_index z] returns the current index (0-based) of the focus in the list. *)
(** [get_current_index z] returns the current index (0-based) of the focus in
the list. *)
10 changes: 6 additions & 4 deletions vendor/patch/src/patch.ml
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ module String = struct
let equal = String.equal
end

type hunk = {
type 'a line = [`Common of 'a | `Mine of 'a | `Their of 'a ]

type 'a hunk = {
mine_start : int ;
mine_len : int ;
their_start : int ;
their_len : int ;
lines : [ `Common of string | `Mine of string | `Their of string ] list ;
lines : 'a line list ;
}

let unified_diff hunk =
Expand Down Expand Up @@ -239,9 +241,9 @@ let pp_operation ~git ppf op =
Format.fprintf ppf "rename from %s\n" old_name;
Format.fprintf ppf "rename to %s\n" new_name

type t = {
type 'a t = {
operation : operation ;
hunks : hunk list ;
hunks : 'a hunk list ;
mine_no_nl : bool ;
their_no_nl : bool ;
}
Expand Down
22 changes: 12 additions & 10 deletions vendor/patch/src/patch.mli
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
type hunk = {
type 'a line = [`Common of 'a | `Mine of 'a | `Their of 'a ]

type 'a hunk = {
mine_start : int ;
mine_len : int ;
their_start : int ;
their_len : int ;
lines : [ `Common of string | `Mine of string | `Their of string ] list ;
lines : 'a line list ;
}

val mine : hunk -> string list
val their : hunk -> string list
val pp_hunk : Format.formatter -> hunk -> unit
val mine : 'a hunk -> 'a list
val their : 'a hunk -> 'a list
val pp_hunk : Format.formatter -> string hunk -> unit

type operation =
| Edit of string
Expand All @@ -21,15 +23,15 @@ val pp_operation : git:bool -> Format.formatter -> operation -> unit

val operation_eq : operation -> operation -> bool

type t = {
type 'a t = {
operation : operation ;
hunks : hunk list ;
hunks : 'a hunk list ;
mine_no_nl : bool ;
their_no_nl : bool ;
}

val pp : git:bool -> Format.formatter -> t -> unit
val pp : git:bool -> Format.formatter -> string t -> unit

val to_diffs : string -> t list
val to_diffs : string -> string t list

val patch : string option -> t -> string option
val patch : string option -> string t -> string option