Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion dune-project
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
(lang dune 1.0)
(lang dune 3.0)
(name patch)
(executables_implicit_empty_intf true)
(formatting disabled)
2 changes: 1 addition & 1 deletion patch.opam
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license: "ISC"

depends: [
"ocaml" {>= "4.04.2"}
"dune"
"dune" {>= "3.0"}
"alcotest" {with-test & >= "0.7.0"}
"crowbar" {with-test}
]
Expand Down
62 changes: 62 additions & 0 deletions src/patch.ml
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,65 @@ let patch filedata diff =
| true, true -> lines
in
Some (String.concat "\n" lines)

let diff_op operation a b =
let rec aux ~mine_start ~mine_len ~mine ~their_start ~their_len ~their l1 l2 =
let create_diff ~mine_no_nl ~their_no_nl =
let hunks =
if mine = [] && their = [] then
assert false
else
let mine = List.rev mine in
let their = List.rev their in
[{mine_start; mine_len; mine; their_start; their_len; their}]
in
{operation; hunks; mine_no_nl; their_no_nl}
in
match l1, l2 with
| [], [] | [""], [""] when mine = [] && their = [] -> assert false
| [], [] -> Some (create_diff ~mine_no_nl:true ~their_no_nl:true)
| [""], [] -> Some (create_diff ~mine_no_nl:false ~their_no_nl:true)
| [], [""] -> Some (create_diff ~mine_no_nl:true ~their_no_nl:false)
| [""], [""] -> Some (create_diff ~mine_no_nl:false ~their_no_nl:false)
| [a; ""], [b] when b <> "" ->
aux
~mine_start ~mine_len:(mine_len + 1) ~mine:(a :: mine)
~their_start ~their_len:(their_len + 1) ~their:(b :: their)
[""] []
| [a], [b; ""] when a <> "" ->
aux
~mine_start ~mine_len:(mine_len + 1) ~mine:(a :: mine)
~their_start ~their_len:(their_len + 1) ~their:(b :: their)
[] [""]
| a::l1, ([] | [""]) ->
aux
~mine_start ~mine_len:(mine_len + 1) ~mine:(a :: mine)
~their_start ~their_len ~their
l1 l2
| ([] | [""]), b::l2 ->
aux
~mine_start ~mine_len ~mine
~their_start ~their_len:(their_len + 1) ~their:(b :: their)
l1 l2
| a::l1, b::l2 when mine = [] && their = [] && String.equal a b ->
aux
~mine_start:(mine_start + 1) ~mine_len ~mine
~their_start:(their_start + 1) ~their_len ~their
l1 l2
| a::l1, b::l2 ->
aux
~mine_start ~mine_len:(mine_len + 1) ~mine:(a :: mine)
~their_start ~their_len:(their_len + 1) ~their:(b :: their)
l1 l2
in
aux
~mine_start:0 ~mine_len:0 ~mine:[]
~their_start:0 ~their_len:0 ~their:[]
(to_lines a) (to_lines b)

let diff operation a b = match a, b with
| None, None -> invalid_arg "no input given"
| None, Some b -> diff_op operation "" b
| Some a, None -> diff_op operation a ""
| Some a, Some b when String.equal a b -> None (* NOTE: Optimization *)
| Some a, Some b -> diff_op operation a b
6 changes: 6 additions & 0 deletions src/patch.mli
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,9 @@ val to_diffs : string -> t list
val patch : string option -> t -> string option
(** [patch file_contents diff] applies [diff] on [file_contents], resulting in
the new file contents (or None if deleted). *)

val diff : operation -> string option -> string option -> t option
(** [diff operation content_a content_b] creates a diff between
[content_a] and [content_b]. Returns [None] if no changes could be detected.

@raise Invalid_argument if both [content_a] and [content_b] are [None]. *)
4 changes: 2 additions & 2 deletions test/dune
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
(modules test)
(libraries patch alcotest))

(alias
(name runtest)
(rule
(alias runtest)
(deps (source_tree data) (:< test.exe))
(action (run %{<})))

Expand Down
Loading