@@ -178,15 +178,19 @@ string(String) ->
178178-spec concat (doc (), doc ()) -> doc ().
179179concat (Left , Right ) when is_binary (Left ), is_binary (Right ) ->
180180 # doc_string {string = [Left | Right ], length = byte_size (Left ) + byte_size (Right )};
181+
181182concat (# doc_string {string = String , length = Length }, Right ) when is_binary (Right ) ->
182183 # doc_string {string = [String | Right ], length = Length + byte_size (Right )};
184+
183185concat (Left , # doc_string {string = String , length = Length }) when is_binary (Left ) ->
184186 # doc_string {string = [Left | String ], length = Length + byte_size (Left )};
187+
185188concat (# doc_string {} = Left , # doc_string {} = Right ) ->
186189 # doc_string {
187190 string = [Left # doc_string .string | Right # doc_string .string ],
188191 length = Left # doc_string .length + Right # doc_string .length
189192 };
193+
190194concat (Left , Right ) when ? is_doc (Left ), ? is_doc (Right ) ->
191195 # doc_cons {left = Left , right = Right }.
192196
@@ -208,8 +212,10 @@ nest(Doc, Level) ->
208212-spec nest (doc (), non_neg_integer (), always | break ) -> doc ().
209213nest (Doc , 0 , _Mode ) when ? is_doc (Doc ) ->
210214 Doc ;
215+
211216nest (Doc , Indent , always ) when ? is_doc (Doc ), is_integer (Indent ) andalso Indent >= 0 ->
212217 # doc_nest {doc = Doc , indent = Indent , always_or_break = always };
218+
213219nest (Doc , Indent , break ) when ? is_doc (Doc ), is_integer (Indent ) andalso Indent >= 0 ->
214220 # doc_nest {doc = Doc , indent = Indent , always_or_break = break }.
215221
@@ -414,8 +420,10 @@ line(Doc1, Doc2) -> concat(Doc1, line(), Doc2).
414420-spec fold_doc (fun ((doc (), doc ()) -> doc ()), [doc ()]) -> doc ().
415421fold_doc (_Fun , []) ->
416422 empty ();
423+
417424fold_doc (_Fun , [Doc ]) ->
418425 Doc ;
426+
419427fold_doc (Fun , [Doc | Docs ]) ->
420428 Fun (Doc , fold_doc (Fun , Docs )).
421429
@@ -455,134 +463,178 @@ when
455463
456464fits (Width , Column , HasBreaks , _ ) when Column > Width andalso HasBreaks ->
457465 false ;
466+
458467fits (_ , _ , _ , []) ->
459468 true ;
469+
460470fits (Width , Column , _ , {tail , HasBreaks , Entries }) ->
461471 fits (Width , Column , HasBreaks , Entries );
472+
462473% ## Flat no break
463474
464475fits (Width , Column , HasBreaks , [
465476 {Indent , _ , # doc_fits {group = X , enabled_or_disabled = disabled }}
466477 | T
467478]) ->
468479 fits (Width , Column , HasBreaks , [{Indent , flat_no_break , X } | T ]);
480+
469481fits (Width , Column , HasBreaks , [{Indent , flat_no_break , # doc_fits {group = X }} | T ]) ->
470482 fits (Width , Column , HasBreaks , [{Indent , flat_no_break , X } | T ]);
483+
471484% ## Breaks no flat
472485
473486fits (Width , Column , HasBreaks , [
474487 {Indent , _ , # doc_fits {group = X , enabled_or_disabled = enabled }}
475488 | T
476489]) ->
477490 fits (Width , Column , HasBreaks , [{Indent , break_no_flat , X } | T ]);
491+
478492fits (Width , Column , HasBreaks , [{_Indent , break_no_flat , doc_force_breaks } | T ]) ->
479493 fits (Width , Column , HasBreaks , T );
494+
480495fits (_ , _ , _ , [{_ , break_no_flat , # doc_break {}} | _ ]) ->
481496 true ;
497+
482498fits (_ , _ , _ , [{_ , break_no_flat , # doc_line {}} | _ ]) ->
483499 true ;
500+
484501% ## Breaks
485502
486503fits (_ , _ , _ , [{_ , break , # doc_break {}} | _ ]) ->
487504 true ;
505+
488506fits (_ , _ , _ , [{_ , break , # doc_line {}} | _ ]) ->
489507 true ;
508+
490509fits (Width , Column , HasBreaks , [{Indent , break , # doc_group {group = X }} | T ]) ->
491510 fits (Width , Column , HasBreaks , [{Indent , flat , X } | {tail , HasBreaks , T }]);
511+
492512% ## Catch all
493513
494514fits (Width , _ , _ , [{Indent , _ , # doc_line {}} | T ]) ->
495515 fits (Width , Indent , false , T );
516+
496517fits (Width , Column , HasBreaks , [{_ , _ , doc_nil } | T ]) ->
497518 fits (Width , Column , HasBreaks , T );
519+
498520fits (Width , Column , HasBreaks , [{_ , _ , # doc_string {length = L }} | T ]) ->
499521 fits (Width , Column + L , HasBreaks , T );
522+
500523fits (Width , Column , HasBreaks , [{_ , _ , S } | T ]) when is_binary (S ) ->
501524 fits (Width , Column + byte_size (S ), HasBreaks , T );
525+
502526fits (_ , _ , _ , [{_ , _ , doc_force_breaks } | _ ]) ->
503527 false ;
528+
504529fits (Width , Column , _ , [{_ , _ , # doc_break {break = S }} | T ]) ->
505530 fits (Width , Column + byte_size (S ), true , T );
531+
506532fits (Width , Column , HasBreaks , [{Indent , M , # doc_nest {doc = X , always_or_break = break }} | T ]) ->
507533 fits (Width , Column , HasBreaks , [{Indent , M , X } | T ]);
534+
508535fits (Width , Column , HasBreaks , [{Indent , M , # doc_nest {doc = X , indent = J }} | T ]) ->
509536 fits (Width , Column , HasBreaks , [{Indent + J , M , X } | T ]);
537+
510538fits (Width , Column , HasBreaks , [{Indent , M , # doc_cons {left = X , right = Y }} | T ]) ->
511539 fits (Width , Column , HasBreaks , [{Indent , M , X }, {Indent , M , Y } | T ]);
540+
512541fits (Width , Column , HasBreaks , [{Indent , M , # doc_group {group = X }} | T ]) ->
513542 fits (Width , Column , HasBreaks , [{Indent , M , X } | {tail , HasBreaks , T }]).
514543
515544-spec format (integer () | infinity , integer (), [{integer (), mode (), doc ()}]) -> [binary ()].
516545format (_ , _ , []) ->
517546 [];
547+
518548format (Width , Column , [{_ , _ , doc_nil } | T ]) ->
519549 format (Width , Column , T );
550+
520551format (Width , _ , [{Indent , _ , # doc_line {count = Count }} | T ]) ->
521552 NewLines = binary :copy (<<" \n " >>, Count - 1 ),
522553 [NewLines , indent (Indent ) | format (Width , Indent , T )];
554+
523555format (Width , Column , [{Indent , M , # doc_cons {left = X , right = Y }} | T ]) ->
524556 format (Width , Column , [{Indent , M , X }, {Indent , M , Y } | T ]);
557+
525558format (Width , Column , [{_ , _ , # doc_string {string = S , length = L }} | T ]) ->
526559 [S | format (Width , Column + L , T )];
560+
527561format (Width , Column , [{_ , _ , S } | T ]) when is_binary (S ) ->
528562 [S | format (Width , Column + byte_size (S ), T )];
563+
529564format (Width , Column , [{_Indent , _M , doc_force_breaks } | T ]) ->
530565 format (Width , Column , T );
566+
531567format (Width , Column , [{Indent , M , # doc_fits {group = X }} | T ]) ->
532568 format (Width , Column , [{Indent , M , X } | T ]);
569+
533570% # Flex breaks are not conditional to the mode
534571format (Width , K0 , [{Indent , M , # doc_break {break = S , flex_or_strict = flex }} | T ]) ->
535572 Column = K0 + byte_size (S ),
536573 case Width == infinity orelse M == flat orelse fits (Width , Column , true , T ) of
537574 true -> [S | format (Width , Column , T )];
575+
538576 false -> [indent (Indent ) | format (Width , Indent , T )]
539577 end ;
578+
540579% # Strict breaks are conditional to the mode
541580format (Width , Column , [{Indent , M , # doc_break {break = S , flex_or_strict = strict }} | T ]) ->
542581 case M of
543582 break -> [indent (Indent ) | format (Width , Indent , T )];
583+
544584 _ -> [S | format (Width , Column + byte_size (S ), T )]
545585 end ;
586+
546587% # Nesting is conditional to the mode.
547588format (Width , Column , [{Indent , M , # doc_nest {doc = X , indent = J , always_or_break = Nest }} | T ]) ->
548589 case Nest == always orelse (Nest == break andalso M == break ) of
549590 true -> format (Width , Column , [{Indent + J , M , X } | T ]);
591+
550592 false -> format (Width , Column , [{Indent , M , X } | T ])
551593 end ;
594+
552595% # Groups must do the fitting decision.
553596format (Width , Column , [{Indent , _ , # doc_group {group = X }} | T0 ]) ->
554597 {StringLength , T1 } = peek_next_string_length (T0 ),
555598 case Width == infinity orelse fits (Width - StringLength , Column , false , [{Indent , flat , X }]) of
556599 true ->
557600 format (Width , Column , [{Indent , flat , X } | T1 ]);
601+
558602 false ->
559603 T = force_next_flex_break (T1 ),
560604 format (Width , Column , [{Indent , break , X } | T ])
561605 end .
562606
563607peek_next_string_length ([{Indent , M , # doc_cons {left = Left , right = Right }} | T ]) ->
564608 peek_next_string_length ([{Indent , M , Left }, {Indent , M , Right } | T ]);
609+
565610peek_next_string_length ([{_ , _ , # doc_string {length = Length }} | _ ] = Stack ) ->
566611 {Length , Stack };
612+
567613peek_next_string_length ([{_ , _ , Binary } | _ ] = Stack ) when is_binary (Binary ) ->
568614 {byte_size (Binary ), Stack };
615+
569616peek_next_string_length (Stack ) ->
570617 {0 , Stack }.
571618
572619% % after a group breaks, we force next flex break to also break
573620force_next_flex_break ([{Indent , M , # doc_break {flex_or_strict = flex } = Break } | T ]) ->
574621 [{Indent , M , Break # doc_break {flex_or_strict = strict }} | T ];
622+
575623force_next_flex_break ([{_ , _ , # doc_break {flex_or_strict = strict }} | _ ] = Stack ) ->
576624 Stack ;
625+
577626force_next_flex_break ([{Indent , M , # doc_cons {left = Left , right = Right }} | T ]) ->
578627 force_next_flex_break ([{Indent , M , Left }, {Indent , M , Right } | T ]);
628+
579629force_next_flex_break ([Other | T ]) ->
580630 [Other | force_next_flex_break (T )];
631+
581632force_next_flex_break ([]) ->
582633 [].
583634
584635indent (0 ) ->
585636 ? newline ;
637+
586638indent (Indent ) when is_integer (Indent ) ->
587639 Spaces = binary :copy (<<" " >>, Indent ),
588640 <<? newline /binary , Spaces /binary >>.
0 commit comments