@@ -84,6 +84,7 @@ and erase_locs_partial (p : Locs.partial) : No_locs.partial = {
8484 contents = lazy (Option. map erase_locs (Lazy. force p.contents))
8585}
8686and erase_locs_param (pa : Locs.param ) : No_locs.param = {
87+ indent = pa.indent;
8788 name = pa.name;
8889 contents = erase_locs pa.contents;
8990}
@@ -113,6 +114,7 @@ and add_dummy_locs_partial (p : No_locs.partial) : Locs.partial = {
113114 contents = lazy (Option. map add_dummy_locs (Lazy. force p.contents));
114115}
115116and add_dummy_locs_param (pa : No_locs.param ) : Locs.param = {
117+ indent = pa.indent;
116118 name = pa.name;
117119 contents = add_dummy_locs pa.contents;
118120}
@@ -315,15 +317,15 @@ module Contexts : sig
315317 val add : t -> Json .value -> t
316318 val find_name : t -> string -> Json .value option
317319 val add_param : t -> Locs .param -> t
318- val find_param : t -> string -> Locs .t option
320+ val find_param : t -> string -> Locs .param option
319321end = struct
320322 type t = {
321323 (* nonempty stack of contexts, most recent first *)
322324 stack : Json .value * Json .value list ;
323325
324326 (* an associative list of partial parameters
325327 that have been defined *)
326- params : ( string * Locs .t ) list ;
328+ params : Locs .param list ;
327329 }
328330
329331 let start js = {
@@ -357,6 +359,9 @@ end = struct
357359 | [] -> None
358360 | top :: rest -> find_name { ctxs with stack = (top, rest) } name
359361
362+
363+ let param_has_name name (p : Locs.param ) = String. equal p.name name
364+
360365 (* Note: the template-inheritance specification for Mustache
361366 (https://github.com/mustache/spec/pull/75) mandates that in case
362367 of multi-level inclusion, the "topmost" definition of the
@@ -374,15 +379,15 @@ end = struct
374379 a grandparent), and then late-binding mandates that the
375380 definition "last" in the inheritance chain (so closest to the
376381 start of the rendering) wins.*)
377- let add_param ctxs { Locs. name; contents } =
378- if List. mem_assoc name ctxs.params then
382+ let add_param ctxs ( param : Locs.param ) =
383+ if List. exists (param_has_name param. name) ctxs.params then
379384 (* if the parameter is already bound, the existing binding has precedence *)
380385 ctxs
381386 else
382- {ctxs with params = (name, contents) :: ctxs.params}
387+ {ctxs with params = param :: ctxs .params}
383388
384389 let find_param ctxs name =
385- List. assoc_opt name ctxs.params
390+ List. find_opt (param_has_name name) ctxs.params
386391end
387392
388393let raise_err loc kind =
@@ -474,34 +479,64 @@ module Render = struct
474479 ?(strict = true )
475480 (buf : Buffer.t ) (m : Locs.t ) (js : Json.t )
476481 =
477- let print_indent indent =
478- for _ = 0 to indent - 1 do
479- Buffer. add_char buf ' '
480- done
482+ let beginning_of_line = ref true in
483+
484+ let print_indented buf indent line =
485+ assert (indent > = 0 );
486+ if String. equal line " "
487+ then ()
488+ else begin
489+ for _i = 1 to indent do Buffer. add_char buf ' ' done ;
490+ Buffer. add_string buf line;
491+ beginning_of_line := false ;
492+ end
481493 in
482494
483- let beginning_of_line = ref true in
495+ let print_dedented buf dedent line =
496+ assert (dedent > = 0 );
497+ let rec print_from i =
498+ if i = String. length line then ()
499+ else if i < dedent && (match line.[i] with ' ' | '\t' -> true | _ -> false )
500+ then print_from (i + 1 )
501+ else begin
502+ Buffer. add_substring buf line i (String. length line - i);
503+ beginning_of_line := false ;
504+ end
505+ in
506+ print_from 0
507+ in
484508
485- let align indent =
486- if ! beginning_of_line then (
487- print_indent indent;
488- beginning_of_line := false
489- )
509+ let print_line indent line =
510+ if not ! beginning_of_line then
511+ Buffer. add_string buf line
512+ else begin
513+ if indent > = 0
514+ then print_indented buf indent line
515+ else print_dedented buf (- indent) line;
516+ end
517+ in
518+
519+ let print_newline buf =
520+ Buffer. add_char buf '\n' ;
521+ beginning_of_line := true
490522 in
491523
492524 let print_indented_string indent s =
493525 let lines = String. split_on_char '\n' s in
494- align indent; Buffer. add_string buf (List. hd lines);
526+ print_line indent (List. hd lines);
495527 List. iter (fun line ->
496- Buffer. add_char buf '\n' ;
497- beginning_of_line := true ;
498- if line <> " " then (
499- align indent;
500- Buffer. add_string buf line;
501- )
528+ print_newline buf;
529+ print_line indent line
502530 ) (List. tl lines)
503531 in
504532
533+ let print_interpolated indent data =
534+ (* per the specification, interpolated data should be spliced into the
535+ document, with further lines *not* indented specifically; this effect
536+ is obtained by calling print_line on the (possibly multiline) data. *)
537+ print_line indent data
538+ in
539+
505540 let rec render indent m (ctxs : Contexts.t ) =
506541 let loc = m.loc in
507542 match m.desc with
@@ -510,12 +545,12 @@ module Render = struct
510545 print_indented_string indent s
511546
512547 | Escaped name ->
513- align indent;
514- Buffer. add_string buf (escape_html (Lookup. str ~strict ~loc ~key: name ctxs))
548+ print_interpolated indent
549+ (escape_html (Lookup. str ~strict ~loc ~key: name ctxs))
515550
516551 | Unescaped name ->
517- align indent;
518- Buffer. add_string buf (Lookup. str ~strict ~loc ~key: name ctxs)
552+ print_interpolated indent
553+ (Lookup. str ~strict ~loc ~key: name ctxs)
519554
520555 | Inverted_section s ->
521556 if Lookup. inverted ctxs ~loc ~key: s.name
@@ -545,18 +580,13 @@ module Render = struct
545580 render (indent + partial_indent) partial ctxs
546581 end
547582
548- | Param { name; contents } ->
583+ | Param default_param ->
549584 let param =
550- match Lookup. param ctxs ~loc ~key: name with
551- | None ->
552- (* The "contents" of the partial parameter is to be used as
553- default content, if the parameter was not explicitly passed
554- by one of the partials in scope. *)
555- contents
556- | Some param ->
557- param
585+ match Lookup. param ctxs ~loc ~key: default_param.name with
586+ | Some passed_param -> passed_param
587+ | None -> default_param
558588 in
559- render indent param ctxs
589+ render ( indent + default_param.indent - param.indent) param.contents ctxs
560590
561591 | Comment _c -> ()
562592
@@ -598,11 +628,11 @@ module Without_locations = struct
598628 concat (List. map ms ~f: go)
599629 | Partial {indent; name; params; contents} ->
600630 let params =
601- Option. map (List. map ~f: (fun {name; contents} -> (name, go contents))) params
631+ Option. map (List. map ~f: (fun {indent; name; contents} -> (indent, name, go contents))) params
602632 in
603- partial indent name ?params contents
604- | Param { name; contents } ->
605- param name (go contents)
633+ partial ? indent:( Some indent) name ?params contents
634+ | Param { indent; name; contents } ->
635+ param ?indent:( Some indent) name (go contents)
606636
607637 module Infix = struct
608638 let (^) y x = Concat [x; y]
@@ -615,24 +645,24 @@ module Without_locations = struct
615645 let inverted_section n c = Inverted_section { name = n ; contents = c }
616646 let partial ?(indent = 0 ) n ?params c =
617647 let params =
618- Option. map (List. map ~f: (fun (name , contents ) -> {name; contents})) params in
648+ Option. map (List. map ~f: (fun (indent , name , contents ) -> {indent; name; contents})) params in
619649 Partial { indent ; name = n ; params; contents = c }
620- let param n c = Param { name = n; contents = c }
650+ let param ?( indent = 0 ) n c = Param { indent; name = n; contents = c }
621651 let concat t = Concat t
622652 let comment s = Comment s
623653
624654 let rec expand_partials (partials : name -> t option ) : t -> t =
625655 let section ~inverted =
626656 if inverted then inverted_section else section
627657 in
628- let partial indent name ?params contents =
658+ let partial ? indent name ?params contents =
629659 let contents' = lazy (
630660 match Lazy. force contents with
631661 | None -> Option. map (expand_partials partials) (partials name)
632662 | Some t_opt -> Some t_opt
633663 )
634664 in
635- partial ~ indent name ?params contents'
665+ partial ? indent name ?params contents'
636666 in
637667 fold ~string: raw ~section ~escaped ~unescaped ~partial ~param ~comment ~concat
638668
@@ -683,10 +713,10 @@ module With_locations = struct
683713 concat ~loc (List. map ms ~f: go)
684714 | Partial p ->
685715 let params =
686- Option. map (List. map ~f: (fun {name; contents} -> (name, go contents))) p.params in
687- partial ~loc p.indent p.name ?params p.contents
688- | Param { name; contents } ->
689- param ~loc name (go contents)
716+ Option. map (List. map ~f: (fun {indent; name; contents} -> (indent, name, go contents))) p.params in
717+ partial ~loc ?indent:( Some p.indent) p.name ?params p.contents
718+ | Param { indent; name; contents } ->
719+ param ~loc ?indent:( Some indent) name (go contents)
690720
691721 module Infix = struct
692722 let (^) t1 t2 = { desc = Concat [t1; t2]; loc = dummy_loc }
@@ -703,27 +733,27 @@ module With_locations = struct
703733 loc }
704734 let partial ~loc ?(indent = 0 ) n ?params c =
705735 let params =
706- Option. map (List. map ~f: (fun (name , contents ) -> {name; contents})) params in
736+ Option. map (List. map ~f: (fun (indent , name , contents ) -> {indent; name; contents})) params in
707737 { desc = Partial { indent; name = n; params; contents = c };
708738 loc }
709739 let concat ~loc t = { desc = Concat t; loc }
710740 let comment ~loc s = { desc = Comment s; loc }
711- let param ~loc n c =
712- { desc = Param { name = n; contents = c };
741+ let param ~loc ?( indent = 0 ) n c =
742+ { desc = Param { indent; name = n; contents = c };
713743 loc }
714744
715745 let rec expand_partials (partials : name -> t option ) : t -> t =
716746 let section ~loc ~inverted =
717747 if inverted then inverted_section ~loc else section ~loc
718748 in
719- let partial ~loc indent name ?params contents =
749+ let partial ~loc ? indent name ?params contents =
720750 let contents' = lazy (
721751 match Lazy. force contents with
722752 | None -> Option. map (expand_partials partials) (partials name)
723753 | Some t_opt -> Some t_opt
724754 )
725755 in
726- partial ~loc ~ indent name ?params contents'
756+ partial ~loc ? indent name ?params contents'
727757 in
728758 fold ~string: raw ~section ~escaped ~unescaped ~partial ~param ~comment ~concat
729759
0 commit comments