@@ -15,6 +15,7 @@ const kinds = Element.elements;
1515const Attribute = @import ("Attribute.zig" );
1616
1717const log = std .log .scoped (.@"html/ast" );
18+ const fmtlog = std .log .scoped (.@"html/ast/fmt" );
1819
1920has_syntax_errors : bool ,
2021language : Language ,
@@ -949,34 +950,40 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
949950 var current = ast .nodes [1 ];
950951 var direction : enum { enter , exit } = .enter ;
951952 var last_rbracket : u32 = 0 ;
953+ var last_was_text = false ;
952954 var pre : u32 = 0 ;
953955 while (true ) {
954956 const zone_outer = tracy .trace (@src ());
955957 defer zone_outer .end ();
956- log .debug ("looping, ind: {}, dir: {s}" , .{
958+ fmtlog .debug ("looping, ind: {}, dir: {s}" , .{
957959 indentation ,
958960 @tagName (direction ),
959961 });
962+
963+ const crt = current ;
964+ defer last_was_text = crt .kind == .text ;
960965 switch (direction ) {
961966 .enter = > {
962967 const zone = tracy .trace (@src ());
963968 defer zone .end ();
964- log .debug ("rendering enter ({}): {s} {any }" , .{
969+ fmtlog .debug ("rendering enter ({}): {t} lwt: { }" , .{
965970 indentation ,
966- "" ,
967- // current.open.slice(src),
968- current ,
971+ current .kind ,
972+ last_was_text ,
969973 });
970974
971975 const maybe_ws = src [last_rbracket .. current .open .start ];
972- log .debug ("maybe_ws = '{s}'" , .{maybe_ws });
976+ fmtlog .debug ("maybe_ws = '{s}'" , .{maybe_ws });
973977 if (pre > 0 ) {
974978 try w .writeAll (maybe_ws );
975979 } else {
976- const vertical = maybe_ws .len > 0 ;
980+ const vertical = if (last_was_text and current .kind != .text )
981+ std .mem .indexOfScalar (u8 , maybe_ws , '\n ' ) != null
982+ else
983+ maybe_ws .len > 0 ;
977984
978985 if (vertical ) {
979- log .debug ("adding a newline" , .{});
986+ fmtlog .debug ("adding a newline" , .{});
980987 const lines = std .mem .count (u8 , maybe_ws , "\n " );
981988 if (last_rbracket > 0 ) {
982989 if (lines >= 2 ) {
@@ -989,6 +996,8 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
989996 for (0.. indentation ) | _ | {
990997 try w .writeAll ("\t " );
991998 }
999+ } else if ((last_was_text or current .kind == .text ) and maybe_ws .len > 0 ) {
1000+ try w .writeAll (" " );
9921001 }
9931002 }
9941003
@@ -1016,7 +1025,7 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
10161025 return ;
10171026 }
10181027
1019- log .debug ("rendering exit ({}): {s} {any}" , .{
1028+ fmtlog .debug ("rendering exit ({}): {s} {any}" , .{
10201029 indentation ,
10211030 current .open .slice (src ),
10221031 current ,
@@ -1034,12 +1043,24 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
10341043 indentation -= 1 ;
10351044 }
10361045
1037- const open_was_vertical = std .ascii .isWhitespace (src [current .open .end ]);
1038-
10391046 if (pre > 0 ) {
10401047 const maybe_ws = src [last_rbracket .. current .close .start ];
10411048 try w .writeAll (maybe_ws );
10421049 } else {
1050+ // const first_child_is_text = if (ast.child(current)) |ch|
1051+ // ch.kind == .text
1052+ // else
1053+ // false;
1054+ // const open_was_vertical = if (first_child_is_text)
1055+ // std.mem.indexOfScalar(
1056+ // u8,
1057+ // src[current.open.end..ast.nodes[current.first_child_idx].open.start],
1058+ // '\n',
1059+ // ) != null
1060+ // else
1061+ // std.ascii.isWhitespace(src[current.open.end]);
1062+
1063+ const open_was_vertical = std .ascii .isWhitespace (src [current .open .end ]);
10431064 if (open_was_vertical ) {
10441065 try w .writeAll ("\n " );
10451066 for (0.. indentation ) | _ | {
@@ -1069,7 +1090,29 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
10691090 const txt = current .open .slice (src );
10701091 const parent_kind = ast .nodes [current .parent_idx ].kind ;
10711092 switch (parent_kind ) {
1072- else = > try w .writeAll (txt ),
1093+ else = > {
1094+ var it = std .mem .splitScalar (u8 , txt , '\n ' );
1095+ var first = true ;
1096+ var empty_line = false ;
1097+ while (it .next ()) | raw_line | {
1098+ const line = std .mem .trim (
1099+ u8 ,
1100+ raw_line ,
1101+ & std .ascii .whitespace ,
1102+ );
1103+ if (line .len == 0 ) {
1104+ if (empty_line ) continue ;
1105+ empty_line = true ;
1106+ if (! first ) for (0.. indentation ) | _ | try w .print ("\t " , .{});
1107+ try w .print ("\n " , .{});
1108+ continue ;
1109+ } else empty_line = false ;
1110+ if (! first ) for (0.. indentation ) | _ | try w .print ("\t " , .{});
1111+ try w .print ("{s}" , .{line });
1112+ if (it .peek () != null ) try w .print ("\n " , .{});
1113+ first = false ;
1114+ }
1115+ },
10731116 .style , .script = > {
10741117 var css_indent = indentation ;
10751118 var it = std .mem .splitScalar (u8 , txt , '\n ' );
@@ -1110,7 +1153,7 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
11101153 last_rbracket = current .open .end ;
11111154
11121155 if (current .next_idx != 0 ) {
1113- log .debug ("text next: {}" , .{current .next_idx });
1156+ fmtlog .debug ("text next: {}" , .{current .next_idx });
11141157 current = ast .nodes [current .next_idx ];
11151158 } else {
11161159 current = ast .nodes [current .parent_idx ];
@@ -1141,7 +1184,7 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
11411184 const maybe_name , const maybe_extra = blk : {
11421185 var tt : Tokenizer = .{ .language = ast .language };
11431186 const tag = current .open .slice (src );
1144- log .debug ("doctype tag: {s} {any}" , .{ tag , current });
1187+ fmtlog .debug ("doctype tag: {s} {any}" , .{ tag , current });
11451188 const dt = tt .next (tag ).? .doctype ;
11461189 const maybe_name : ? []const u8 = if (dt .name ) | name |
11471190 name .slice (tag )
@@ -1203,7 +1246,7 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
12031246 break :blk true ;
12041247 };
12051248
1206- log .debug ("element <{s}> vertical = {}" , .{ name , vertical });
1249+ fmtlog .debug ("element <{s}> vertical = {}" , .{ name , vertical });
12071250
12081251 // if (std.mem.eql(u8, name, "path")) @breakpoint();
12091252
@@ -1294,7 +1337,7 @@ pub fn render(ast: Ast, src: []const u8, w: *Writer) !void {
12941337 .return_attrs = true ,
12951338 };
12961339 const tag = current .open .slice (src );
1297- log .debug ("retokenize {s}\n " , .{tag });
1340+ fmtlog .debug ("retokenize {s}\n " , .{tag });
12981341 break :blk tt .getName (tag ).? .slice (tag );
12991342 };
13001343
@@ -1870,17 +1913,13 @@ test "spans" {
18701913test "arrow span" {
18711914 const case =
18721915 \\<a href="$if.permalink()">← <span var="$if.title"></span></a>
1873- ;
1874- const expected = comptime std .fmt .comptimePrint (
1875- \\<a href="$if.permalink()">←
1876- \\{c}<span var="$if.title"></span></a>
18771916 \\
1878- , .{ ' \t ' }) ;
1917+ ;
18791918
18801919 const ast = try Ast .init (std .testing .allocator , case , .html , true );
18811920 defer ast .deinit (std .testing .allocator );
18821921
1883- try std .testing .expectFmt (expected , "{f}" , .{ast .formatter (case )});
1922+ try std .testing .expectFmt (case , "{f}" , .{ast .formatter (case )});
18841923}
18851924
18861925test "self-closing tag complex example" {
0 commit comments