Skip to content

Commit

Permalink
Merge pull request #97 from ahmetsait/master
Browse files Browse the repository at this point in the history
Make empty text nodes generate newline
  • Loading branch information
s-ludwig authored Jan 8, 2025
2 parents 9e24640 + 2bf9c17 commit 3cea222
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 24 deletions.
4 changes: 2 additions & 2 deletions source/diet/dom.d
Original file line number Diff line number Diff line change
Expand Up @@ -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
}


Expand Down
89 changes: 84 additions & 5 deletions source/diet/html.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -1209,3 +1215,76 @@ unittest { // output empty tags as singular for XML output
assert(utCompile!("doctype html\nfoo") == `<!DOCTYPE html><foo></foo>`);
assert(utCompile!("doctype xml\nfoo") == `<?xml version="1.0" encoding="utf-8" ?><foo/>`);
}

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) == `<!DOCTYPE html>
<html>
<body>
<div>
<a>
1
</a>
<a>
2
</a><a>
3
</a><a>
4
</a><a>
5
</a>
</div>
<div>
<a>
1
</a>
<a>2</a><a>
3
</a><a>4</a><a>
5
</a>
</div>
</body>
</html>`);
}
39 changes: 22 additions & 17 deletions source/diet/parser.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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] == '&') {
Expand Down

0 comments on commit 3cea222

Please sign in to comment.