diff --git a/source/diet/dom.d b/source/diet/dom.d index 4dcb3ee..de5a03c 100644 --- a/source/diet/dom.d +++ b/source/diet/dom.d @@ -271,8 +271,8 @@ enum NodeAttribs { translated = 1<<0, /// Translate node contents textNode = 1<<1, /// All nested lines are treated as text rawTextNode = 1<<2, /// All nested lines are treated as raw text (no interpolations or inline tags) - fitOutside = 1<<3, /// Don't insert white space outside of the node when generating output (currently ignored by the HTML generator) - fitInside = 1<<4, /// Don't insert white space around the node contents when generating output (currently ignored by the HTML generator) + fitOutside = 1<<3, /// Don't insert white space outside of the node when generating output + fitInside = 1<<4, /// Don't insert white space around the node contents when generating output } diff --git a/source/diet/html.d b/source/diet/html.d index f4b1f41..16232e4 100644 --- a/source/diet/html.d +++ b/source/diet/html.d @@ -520,10 +520,16 @@ private string getHTMLMixin(ref CTX ctx, in Node node, bool in_pre) @safe case Node.SpecialName.hidden: return null; case Node.SpecialName.text: string ret; - foreach (i, c; node.contents) - ret ~= ctx.getNodeContentsMixin(c, in_pre); - if (in_pre) ctx.plainNewLine(); - else ctx.prettyNewLine(); + if (node.contents.length == 0) { + ret ~= ctx.outputPendingNewline(); + if (in_pre) ctx.plainNewLine(); + else ctx.prettyNewLine(); + ret ~= ctx.outputPendingNewline(); + } else { + foreach (i, c; node.contents) + ret ~= ctx.getNodeContentsMixin(c, in_pre); + if (in_pre) ctx.plainNewLine(); + } return ret; } } @@ -544,7 +550,7 @@ private string getElementMixin(ref CTX ctx, in Node node, bool in_pre) @safe case "area", "base", "basefont", "br", "col", "embed", "frame", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr": is_singular_tag = true; - need_newline = true; + need_newline = ctx.pretty; break; } } else if (!node.hasNonWhitespaceContent) is_singular_tag = true; @@ -1209,3 +1215,76 @@ unittest { // output empty tags as singular for XML output assert(utCompile!("doctype html\nfoo") == ``); assert(utCompile!("doctype xml\nfoo") == ``); } + +unittest { // generate newlines on empty text nodes + @dietTraits struct T { enum HTMLOutputStyle htmlOutputStyle = HTMLOutputStyle.pretty; } + assert(utCompile!(`doctype html +html + body + div + a + | + | 1 + | + a< + | + | 2 + | + a> + | + | 3 + | + a<> + | + | 4 + | + a + | + | 5 + | + div + a + | 1 + a< + | 2 + a> + | 3 + a<> + | 4 + a + | 5`, T) == ` + + +
+ + + 1 + + + + 2 + + + 3 + + + 4 + + + 5 + + +
+
+ + 1 + + 2 + 3 + 4 + 5 + +
+ +`); +} diff --git a/source/diet/parser.d b/source/diet/parser.d index 4bdfe2a..6ec0346 100644 --- a/source/diet/parser.d +++ b/source/diet/parser.d @@ -1121,6 +1121,27 @@ private Node parseTagLine(alias TR)(ref string input, ref Location loc, out bool return ret; } +private void parseWhitespaceControl(ref string input, ref size_t idx, ref Node dst) +@safe { + // avoid whitespace inside of tag + if (idx < input.length && input[idx] == '<') { + idx++; + dst.attribs |= NodeAttribs.fitInside; + } + + // avoid whitespace outside of tag + if (idx < input.length && input[idx] == '>') { + idx++; + dst.attribs |= NodeAttribs.fitOutside; + } + + // avoid whitespace inside of tag (also allowed after >) + if (!(dst.attribs & NodeAttribs.fitInside) && idx < input.length && input[idx] == '<') { + idx++; + dst.attribs |= NodeAttribs.fitInside; + } +} + private bool parseTag(ref string input, ref size_t idx, ref Node dst, ref bool has_nested, ref Location loc) @safe { import std.ascii : isWhite; @@ -1158,23 +1179,7 @@ private bool parseTag(ref string input, ref size_t idx, ref Node dst, ref bool h if (idx < input.length && input[idx] == '(') parseAttributes(input, idx, dst, loc); - // avoid whitespace inside of tag - if (idx < input.length && input[idx] == '<') { - idx++; - dst.attribs |= NodeAttribs.fitInside; - } - - // avoid whitespace outside of tag - if (idx < input.length && input[idx] == '>') { - idx++; - dst.attribs |= NodeAttribs.fitOutside; - } - - // avoid whitespace inside of tag (also allowed after >) - if (!(dst.attribs & NodeAttribs.fitInside) && idx < input.length && input[idx] == '<') { - idx++; - dst.attribs |= NodeAttribs.fitInside; - } + parseWhitespaceControl(input, idx, dst); // translate text contents if (idx < input.length && input[idx] == '&') {