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
56 changes: 48 additions & 8 deletions src/patch.ml
Original file line number Diff line number Diff line change
Expand Up @@ -161,20 +161,60 @@ let operation_eq a b = match a, b with

let no_file = "/dev/null"

let pp_filename ppf fn =
(* NOTE: filename quote format from GNU diffutils *)
let rec aux ~to_quote buf fn ~len i =
if i < len then
let c = fn.[i] in
let to_quote =
if c = '\007' then
(Buffer.add_string buf "\\a"; true)
else if c = '\b' then
(Buffer.add_string buf "\\b"; true)
else if c = '\t' then
(Buffer.add_string buf "\\t"; true)
else if c = '\n' then
(Buffer.add_string buf "\\n"; true)
else if c = '\011' then
(Buffer.add_string buf "\\v"; true)
else if c = '\012' then
(Buffer.add_string buf "\\f"; true)
else if c = '\r' then
(Buffer.add_string buf "\\r"; true)
else if c < ' ' || c > '~' then
(Printf.bprintf buf "\\%03o" (Char.code c); true)
else if c = ' ' then
(Buffer.add_char buf ' '; true)
else if c = '"' || c = '\\' then
(Buffer.add_char buf '\\'; Buffer.add_char buf c; true)
else
(Buffer.add_char buf c; to_quote)
in
aux ~to_quote buf fn ~len (i + 1)
else
to_quote
in
let len = String.length fn in
let buf = Buffer.create (len * 2) in
if aux ~to_quote:false buf fn ~len 0 then
Format.fprintf ppf "\"%s\"" (Buffer.contents buf)
else
Format.pp_print_text ppf fn

let pp_operation ppf op =
match op with
| Edit (old_name, new_name) ->
Format.fprintf ppf "--- %s\n" old_name ;
Format.fprintf ppf "+++ %s\n" new_name
Format.fprintf ppf "--- %a\n" pp_filename old_name ;
Format.fprintf ppf "+++ %a\n" pp_filename new_name
| Delete name ->
Format.fprintf ppf "--- %s\n" name ;
Format.fprintf ppf "+++ %s\n" no_file
Format.fprintf ppf "--- %a\n" pp_filename name ;
Format.fprintf ppf "+++ %a\n" pp_filename no_file
| Create name ->
Format.fprintf ppf "--- %s\n" no_file ;
Format.fprintf ppf "+++ %s\n" name
Format.fprintf ppf "--- %a\n" pp_filename no_file ;
Format.fprintf ppf "+++ %a\n" pp_filename name
| Rename_only (old_name, new_name) ->
Format.fprintf ppf "rename from %s\n" old_name;
Format.fprintf ppf "rename to %s\n" new_name
Format.fprintf ppf "rename from %a\n" pp_filename old_name;
Format.fprintf ppf "rename to %a\n" pp_filename new_name

type t = {
operation : operation ;
Expand Down
33 changes: 33 additions & 0 deletions test/test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,38 @@ let patch_p = [
"-p1 with root files", `Quick, p1_root;
]

let pp_output_test = Alcotest.testable Format.pp_print_string String.equal
let operations exp str () =
let exp = Format.asprintf "%a" Patch.pp_operation exp in
Alcotest.(check pp_output_test) __LOC__ str exp

let plain_filename =
{|--- a/test
+++ b/test
|}

let plain_filename = operations (Patch.Edit ("a/test", "b/test")) plain_filename

let filename_with_spaces =
{|--- "a/one space"
+++ "b/with two spaces"
|}

let filename_with_spaces = operations (Patch.Edit ("a/one space", "b/with two spaces")) filename_with_spaces

let filename_with_special_chars =
{|--- "\a\b\f\n\r\t\v some name \\\"\001\177&"
+++ /dev/null
|}

let filename_with_special_chars = operations (Patch.Delete "\007\b\012\n\r\t\011 some name \\\"\001\127&") filename_with_special_chars

let pp_filenames = [
"plain", `Quick, plain_filename;
"with spaces", `Quick, filename_with_spaces;
"with special characters", `Quick, filename_with_special_chars;
]

let tests = [
"parse", parse_diffs ;
"apply", apply_diffs ;
Expand All @@ -1021,6 +1053,7 @@ let tests = [
"regression", regression_diffs ;
"diff", unified_diff_creation ;
"patch -p", patch_p;
"pretty-print filenames", pp_filenames;
]

let () =
Expand Down