Skip to content

Commit 68e3256

Browse files
nojbhhugo
andauthored
Do not normalize newlines inside quoted strings (#1754)
Co-authored-by: Hugo Heuzard <[email protected]>
1 parent 422e348 commit 68e3256

File tree

3 files changed

+53
-27
lines changed

3 files changed

+53
-27
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
+ Honour .ocamlformat-ignore on Windows (#1752, @nojb)
1818

19+
+ Avoid normalizing newlines inside quoted strings `{|...|}` (#1754, @nojb, @hhugo)
20+
1921
#### Changes
2022

2123
#### New features

lib/Translation_unit.ml

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,24 @@ let recover (type a) : a Ast_passes.Ast0.t -> _ -> a = function
258258
| Module_type -> failwith "no recovery for module_type"
259259
| Expression -> failwith "no recovery for expression"
260260

261+
let strconst_mapper locs =
262+
let constant self c =
263+
match c with
264+
| Parsetree.Pconst_string (_, {Location.loc_start; loc_end; _}, Some _)
265+
->
266+
locs := (loc_start.Lexing.pos_cnum, loc_end.Lexing.pos_cnum) :: !locs ;
267+
c
268+
| _ -> Ast_mapper.default_mapper.constant self c
269+
in
270+
{Ast_mapper.default_mapper with constant}
271+
272+
let collect_strlocs (type a) (fgN : a Ast_passes.Ast_final.t) (ast : a) :
273+
(int * int) list =
274+
let locs = ref [] in
275+
let _ = Ast_passes.Ast_final.map fgN (strconst_mapper locs) ast in
276+
let compare (c1, _) (c2, _) = Stdlib.compare c1 c2 in
277+
List.sort ~compare !locs
278+
261279
let format (type a b) (fg0 : a Ast_passes.Ast0.t)
262280
(fgN : b Ast_passes.Ast_final.t) ?output_file ~input_name ~prev_source
263281
~parsed conf opts =
@@ -307,7 +325,8 @@ let format (type a b) (fg0 : a Ast_passes.Ast0.t)
307325
if opts.Conf.margin_check then
308326
check_margin conf ~fmted
309327
~filename:(Option.value output_file ~default:input_name) ;
310-
Ok fmted )
328+
let strlocs = collect_strlocs fgN t.ast in
329+
Ok (strlocs, fmted) )
311330
else
312331
let exn_args () =
313332
[("output file", dump_formatted ~suffix:".invalid-ast" fmted)]
@@ -412,29 +431,34 @@ let parse_result ?(f = Ast_passes.Ast0.Parse.ast) fragment conf ~source
412431
| exception exn -> Error (Error.Invalid_source {exn; input_name})
413432
| parsed -> Ok parsed
414433

415-
let normalize_eol ~line_endings s =
434+
let normalize_eol ~strlocs ~line_endings s =
416435
let buf = Buffer.create (String.length s) in
417-
let rec loop seen_cr i =
418-
if i = String.length s then (
419-
if seen_cr then Buffer.add_char buf '\r' ;
420-
Buffer.contents buf )
436+
let add_cr n = Buffer.add_string buf (String.init n ~f:(fun _ -> '\r')) in
437+
let rec normalize_segment ~seen_cr i stop =
438+
if i = stop then add_cr seen_cr
421439
else
422-
match (s.[i], line_endings) with
423-
| '\r', _ ->
424-
if seen_cr then Buffer.add_char buf '\r' ;
425-
loop true (i + 1)
426-
| '\n', `Crlf ->
427-
Buffer.add_string buf "\r\n" ;
428-
loop false (i + 1)
429-
| '\n', `Lf ->
430-
Buffer.add_char buf '\n' ;
431-
loop false (i + 1)
432-
| c, _ ->
433-
if seen_cr then Buffer.add_char buf '\r' ;
440+
match s.[i] with
441+
| '\r' -> normalize_segment ~seen_cr:(seen_cr + 1) (i + 1) stop
442+
| '\n' ->
443+
Buffer.add_string buf
444+
(match line_endings with `Crlf -> "\r\n" | `Lf -> "\n") ;
445+
normalize_segment ~seen_cr:0 (i + 1) stop
446+
| c ->
447+
add_cr seen_cr ;
434448
Buffer.add_char buf c ;
435-
loop false (i + 1)
449+
normalize_segment ~seen_cr:0 (i + 1) stop
450+
in
451+
let rec loop locs i =
452+
match locs with
453+
| [] ->
454+
normalize_segment ~seen_cr:0 i (String.length s) ;
455+
Buffer.contents buf
456+
| (start, stop) :: xs ->
457+
normalize_segment ~seen_cr:0 i start ;
458+
Buffer.add_substring buf s ~pos:start ~len:(stop - start) ;
459+
loop xs stop
436460
in
437-
loop false 0
461+
loop strlocs 0
438462

439463
let parse_and_format (type a b) (fg0 : a Ast_passes.Ast0.t)
440464
(fgN : b Ast_passes.Ast_final.t) ?output_file ~input_name ~source conf
@@ -445,8 +469,8 @@ let parse_and_format (type a b) (fg0 : a Ast_passes.Ast0.t)
445469
let parsed = {parsed with ast= Ast_passes.run fg0 fgN parsed.ast} in
446470
format fg0 fgN ?output_file ~input_name ~prev_source:source ~parsed conf
447471
opts
448-
>>= fun formatted ->
449-
Ok (normalize_eol ~line_endings:conf.Conf.line_endings formatted)
472+
>>= fun (strlocs, formatted) ->
473+
Ok (normalize_eol ~strlocs ~line_endings:conf.Conf.line_endings formatted)
450474

451475
let parse_and_format = function
452476
| Syntax.Structure -> parse_and_format Structure Structure
@@ -483,7 +507,7 @@ let numeric (type a b) (fg0 : a list Ast_passes.Ast0.t)
483507
let parsed = {parsed with ast= Ast_passes.run fg0 fgN parsed.ast} in
484508
let {ast= parsed_ast; source= parsed_src; _} = parsed in
485509
match format fg0 fgN ~input_name ~prev_source:src ~parsed conf opts with
486-
| Ok fmted_src -> (
510+
| Ok (_, fmted_src) -> (
487511
match parse_result fg0 ~source:fmted_src conf ~input_name with
488512
| Ok {ast= fmted_ast; source= fmted_src; _} ->
489513
let fmted_ast = Ast_passes.run fg0 fgN fmted_ast in

test/passing/tests/crlf_to_lf.ml.ref

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
let _ = {|
2-
foo
3-
4-
bar
1+
let _ = {|
2+
foo
3+
4+
bar
55
|}
66

77
(** This is verbatim:

0 commit comments

Comments
 (0)