Skip to content

Commit ed42c1c

Browse files
Start quotes at the beginning of the file name
1 parent 222a7d7 commit ed42c1c

File tree

4 files changed

+128
-46
lines changed

4 files changed

+128
-46
lines changed

src/fname.mli

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1 @@
1-
type t =
2-
| DevNull
3-
| Filename of string
4-
5-
val filename : string -> t
1+
val filename : string -> string

src/fname.mll

Lines changed: 107 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,119 @@
11
{
2-
type t =
3-
| DevNull
4-
| Filename of string
2+
type token =
3+
| Quote
4+
| Text of string
5+
| Tab
56
}
67

7-
rule quoted_fn acc = parse
8-
| '"' { Buffer.contents acc }
9-
| [^ '"']+ as s {
10-
Buffer.add_string acc s;
11-
quoted_fn acc lexbuf
8+
rule quoted_fn tokens = parse
9+
| '"' {
10+
(* after a quoted filename it might continue unquoted *)
11+
let tokens = fn tokens lexbuf in
12+
Quote :: tokens
1213
}
13-
| _ { quoted_fn acc lexbuf }
14+
| '\\' {
15+
let token = escape lexbuf in
16+
let tokens = quoted_fn tokens lexbuf in
17+
token :: tokens
18+
}
19+
| [^ '"' '\\']+ as s {
20+
let token = Text s in
21+
(* consume the end quote or the escape *)
22+
let tokens = quoted_fn tokens lexbuf in
23+
token :: tokens
24+
}
25+
| eof { tokens }
1426

15-
and unquoted_fn acc = parse
16-
| [^ '\t']+ as s {
17-
Buffer.add_string acc s;
18-
unquoted_fn acc lexbuf
27+
and escape = parse
28+
| '"' { Quote }
29+
| _ as c {
30+
(* ignore all other escapes, reconstruct the escape as text *)
31+
Text (Printf.sprintf {|\%c|} c)
1932
}
20-
| '\t' { Buffer.contents acc }
21-
| eof { Buffer.contents acc }
2233

23-
and fn acc = parse
24-
| "/dev/null" { DevNull }
25-
| '"' { Filename (quoted_fn acc lexbuf) }
26-
| _ as c {
27-
Buffer.add_char acc c;
28-
Filename (unquoted_fn acc lexbuf) }
34+
and unquoted_fn tokens = parse
35+
| [^ '\t']+ as s {
36+
let token = Text s in
37+
token :: tokens
38+
}
39+
| '\t' { (Tab :: tokens) }
40+
| eof { tokens }
2941

42+
and fn tokens = parse
43+
| '"' {
44+
let tokens = quoted_fn tokens lexbuf in
45+
Quote :: tokens
46+
}
47+
| '\t' {
48+
let tokens = fn tokens lexbuf in
49+
Tab :: tokens
50+
}
51+
| _ as c {
52+
let token = Text (String.make 1 c) in
53+
let tokens = unquoted_fn tokens lexbuf in
54+
token :: tokens
55+
}
56+
| eof { tokens }
3057
{
58+
59+
let lsplit2 ~f xs =
60+
let rec loop acc = function
61+
| [] -> List.rev acc, []
62+
| x::xs when f x -> (List.rev acc), xs
63+
| x::xs -> loop (x::acc) xs
64+
in
65+
loop [] xs
66+
67+
let rec ends_with e = function
68+
| [] -> false
69+
| [x] -> e = x
70+
| _::xs -> ends_with e xs
71+
72+
let starts_with e = function
73+
| [] -> false
74+
| x::_ -> e = x
75+
76+
let remove_start_end = function
77+
| [] -> []
78+
| _::_::[] -> []
79+
| _::xs -> (
80+
let rec remove_last acc = function
81+
| []
82+
| [_] -> List.rev acc
83+
| x::xs -> remove_last (x::acc) xs
84+
in
85+
remove_last [] xs)
86+
87+
let rec lstrip = function
88+
| [] -> []
89+
| (Text s)::xs when String.equal String.empty (String.trim s) -> lstrip xs
90+
| otherwise -> otherwise
91+
92+
let rstrip xs = xs |> List.rev |> lstrip |> List.rev
93+
94+
let strip xs = xs |> lstrip |> rstrip
95+
96+
let is_quoted_filename tokens =
97+
starts_with Quote tokens && ends_with Quote tokens
98+
99+
let unquote_filename tokens =
100+
match is_quoted_filename tokens with
101+
| true -> remove_start_end tokens
102+
| false -> tokens
103+
31104
let filename s =
32105
let lexbuf = Lexing.from_string s in
33-
fn (Buffer.create 16) lexbuf
106+
let tokens = fn [] lexbuf in
107+
(* read the first bit until a tab, if available *)
108+
let is_tab = function | Tab -> true | _ -> false in
109+
let (tokens, _) = lsplit2 ~f:is_tab tokens in
110+
let chunks = tokens
111+
|> strip
112+
|> unquote_filename
113+
|> List.map (function
114+
| Text s -> s
115+
| Quote -> {|"|}
116+
| Tab -> "\t")
117+
in
118+
String.concat "" chunks
34119
}

src/patch.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ let pp ~git ppf {operation; hunks; mine_no_nl; their_no_nl} =
247247
let pp_list ~git ppf diffs =
248248
List.iter (Format.fprintf ppf "%a" (pp ~git)) diffs
249249

250+
(* TODO: remove this and let users decide the prefix level they want *)
250251
let process_git_prefix ~git ~prefix s =
251252
if git && String.is_prefix ~prefix s then
252253
String.slice ~start:(String.length prefix) s
@@ -256,8 +257,8 @@ let process_git_prefix ~git ~prefix s =
256257
let operation_of_strings git mine their =
257258
let get_filename_opt s =
258259
match Fname.filename s with
259-
| DevNull -> None
260-
| Filename fn -> Some fn
260+
| "/dev/null" -> None
261+
| fn -> Some fn
261262
in
262263
match get_filename_opt mine, get_filename_opt their with
263264
| None, Some b ->

test/test.ml

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -846,39 +846,39 @@ let busybox_diff_spaces =
846846
operations [Patch.Edit ("a/foo bar", "b/foo bar")] busybox_diff_spaces
847847

848848
let unified_diff_quotes = {|\
849-
--- "foo \"bar\" baz" 2024-09-27 11:06:42.612922437 +0200
850-
+++ "foo bar \"baz\"" 2024-09-27 11:09:48.325541553 +0200
849+
--- "foo bar \"baz\"" 2024-09-27 11:09:48.325541553 +0200
850+
+++ "\"foo\" bar baz" 2024-09-27 11:06:42.612922437 +0200
851851
@@ -1 +1 @@
852-
-This is wrong.
853-
+This is right.
852+
-This is right.
853+
+This is wrong.
854854
|}
855855

856856
let unified_diff_quotes =
857-
operations [Patch.Edit ({|foo "bar" baz|}, {|foo bar "baz"|})] unified_diff_quotes
857+
operations [Patch.Edit ({|foo bar "baz"|}, {|"foo" bar baz|})] unified_diff_quotes
858858

859859
let git_diff_quotes = {|\
860-
diff --git "a/foo \"bar\" baz" "b/foo bar \"baz\""
861-
index ef00db3..88adca3 100644
862-
--- "a/foo \"bar\" baz"
863-
+++ "b/foo bar \"baz\""
860+
diff --git "a/foo bar \"baz\"" "b/\"foo\" bar baz"
861+
index 88adca3..ef00db3 100644
862+
--- "a/foo bar \"baz\""
863+
+++ "b/\"foo\" bar baz"
864864
@@ -1 +1 @@
865-
-This is wrong.
866-
+This is right.
865+
-This is right.
866+
+This is wrong.
867867
|}
868868

869869
let git_diff_quotes =
870-
operations [Patch.Edit ({|foo "bar" baz|}, {|foo bar "baz"|})] git_diff_quotes
870+
operations [Patch.Edit ({|foo bar "baz"|}, {|"foo" bar baz|})] git_diff_quotes
871871

872872
let busybox_diff_quotes = {|\
873-
--- foo "bar" baz
874-
+++ foo bar "baz"
873+
--- foo bar "baz"
874+
+++ "foo" bar baz
875875
@@ -1 +1 @@
876-
-This is wrong.
877-
+This is right.
876+
-This is right.
877+
+This is wrong.
878878
|}
879879

880880
let busybox_diff_quotes =
881-
operations [Patch.Edit ({|foo "bar" baz|}, {|foo bar "baz"|})] busybox_diff_quotes
881+
operations [Patch.Edit ({|foo bar "baz"|}, {|"foo" bar baz|})] busybox_diff_quotes
882882

883883
let dev_null_like = {|\
884884
--- /dev/null_but_actually_not

0 commit comments

Comments
 (0)