Fix identation with section segments
This commit is contained in:
@@ -470,7 +470,15 @@ public class Mustache {
|
|||||||
return segs;
|
return segs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Template.Segment[] indentSegs(Template.Segment[] _segs, String indent) {
|
/**
|
||||||
|
* Indents segments by indent.
|
||||||
|
* @param _segs segments to be cloned if indentation is needed
|
||||||
|
* @param indent the space to use for indent.
|
||||||
|
* @param _first whether to append an indent on the first segment
|
||||||
|
* @param _last whether to append an indent on the last segment last empty newline (no character after \n).
|
||||||
|
* @return cloned segments if changed
|
||||||
|
*/
|
||||||
|
static Template.Segment[] indentSegs(Template.Segment[] _segs, String indent, boolean _first, boolean _last) {
|
||||||
// unlike trim this method clones the segments if they have changed
|
// unlike trim this method clones the segments if they have changed
|
||||||
// so the return value must be handled
|
// so the return value must be handled
|
||||||
// a simple identity check on the return can be used to determine
|
// a simple identity check on the return can be used to determine
|
||||||
@@ -486,38 +494,104 @@ public class Mustache {
|
|||||||
Template.Segment seg = _segs[i];
|
Template.Segment seg = _segs[i];
|
||||||
Template.Segment pseg = (i > 0) ? _segs[i-1] : null;
|
Template.Segment pseg = (i > 0) ? _segs[i-1] : null;
|
||||||
Template.Segment nseg = (i < length - 1) ? _segs[i+1] : null;
|
Template.Segment nseg = (i < length - 1) ? _segs[i+1] : null;
|
||||||
/*
|
|
||||||
* If we are the first segment then we rely on the indentation
|
Template.Segment copy;
|
||||||
* already present before the partial tag.
|
if (seg instanceof BlockSegment) {
|
||||||
* [ WS ]{{> partial }}
|
BlockSegment bs = (BlockSegment) seg;
|
||||||
*
|
boolean first;
|
||||||
* That is partial tags do not have the trailing blank
|
boolean last;
|
||||||
* removed.
|
if (pseg == null) {
|
||||||
*
|
// We are the first segment so we inherit
|
||||||
* This avoids needlessley creating StringSegment tags.
|
// outer first
|
||||||
*/
|
first = _first;
|
||||||
boolean first = pseg == null ? false : seg.isStandalone() || pseg.isStandalone();
|
}
|
||||||
boolean last;
|
else if (bs.isStandaloneStart()) {
|
||||||
if (nseg instanceof BlockSegment){
|
first = true;
|
||||||
BlockSegment bs = (BlockSegment) nseg;
|
}
|
||||||
last = bs.isStandaloneStart();
|
else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
if (bs.isStandalone()) {
|
||||||
|
// the closing tag owns the last new line
|
||||||
|
// in the section so we do not indent
|
||||||
|
last = false;
|
||||||
|
}
|
||||||
|
else if (nseg == null) {
|
||||||
|
// We are the last segment so we inherit the
|
||||||
|
// outer last
|
||||||
|
last = _last;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
last = true;
|
||||||
|
}
|
||||||
|
copy = bs.indent(indent, first, last);
|
||||||
}
|
}
|
||||||
else if (nseg == null || nseg.isStandalone()) {
|
else if (seg instanceof StringSegment) {
|
||||||
last = false;
|
boolean first;
|
||||||
|
boolean last;
|
||||||
|
if (pseg == null) {
|
||||||
|
first = _first;
|
||||||
|
}
|
||||||
|
else if (pseg.isStandalone()) {
|
||||||
|
first = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
if (nseg == null) {
|
||||||
|
last = _last;
|
||||||
|
}
|
||||||
|
else if (nseg instanceof BlockSegment) {
|
||||||
|
BlockSegment bs = (BlockSegment) nseg;
|
||||||
|
last = ! bs.isStandaloneStart();
|
||||||
|
}
|
||||||
|
else if (nseg.isStandalone()) {
|
||||||
|
last = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
last = true;
|
||||||
|
}
|
||||||
|
copy = seg.indent(indent, first, last);
|
||||||
|
}
|
||||||
|
else if (seg instanceof IncludedTemplateSegment) {
|
||||||
|
/*
|
||||||
|
* If we are standalone then we rely on the indentation
|
||||||
|
* already present before the partial tag.
|
||||||
|
* [ WS ]{{> partial }}[\n]
|
||||||
|
*
|
||||||
|
* That is partial tags do not have the trailing blank
|
||||||
|
* removed during the trim process.
|
||||||
|
*
|
||||||
|
* This avoids needlessley creating StringSegment tags.
|
||||||
|
*/
|
||||||
|
if (seg.isStandalone()) {
|
||||||
|
boolean last;
|
||||||
|
if (nseg == null) {
|
||||||
|
last = _last;
|
||||||
|
}
|
||||||
|
else if (nseg.isStandalone()) {
|
||||||
|
last = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
last = true;
|
||||||
|
}
|
||||||
|
// Again first = false here because we
|
||||||
|
//already have the indentation set on a previous segment
|
||||||
|
copy = seg.indent(indent, false, last);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
copy = seg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
last = true;
|
copy = seg.indent(indent, _first, _last);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Recursively indent
|
|
||||||
*/
|
|
||||||
Template.Segment copy = seg.indent(indent, first, last);
|
|
||||||
if (copy != seg) {
|
if (copy != seg) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
copySegs[i] = copy;
|
copySegs[i] = copy;
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
return copySegs;
|
return copySegs;
|
||||||
}
|
}
|
||||||
return _segs;
|
return _segs;
|
||||||
@@ -1162,10 +1236,12 @@ public class Mustache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override protected SectionSegment indent (String indent, boolean first, boolean last) {
|
@Override protected SectionSegment indent (String indent, boolean first, boolean last) {
|
||||||
if (indent.equals("")) {
|
// If the end tag is standalone we do NOT add the indent on the end
|
||||||
return this;
|
// (e.g. the newline following the end tag).
|
||||||
}
|
// This is because the block always owns the newlines within the block but
|
||||||
Template.Segment[] segs = indentSegs(_segs, indent);
|
// it only owns the last newline following the end tag if and only if
|
||||||
|
// the closing tag is standalone.
|
||||||
|
Template.Segment[] segs = indentSegs(_segs, indent, first, last);
|
||||||
if (segs == _segs) {
|
if (segs == _segs) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -1222,10 +1298,7 @@ public class Mustache {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected InvertedSegment indent (String indent, boolean first, boolean last) {
|
protected InvertedSegment indent (String indent, boolean first, boolean last) {
|
||||||
if (indent.equals("")) {
|
Template.Segment[] segs = indentSegs(_segs, indent, first, last);
|
||||||
return this;
|
|
||||||
}
|
|
||||||
Template.Segment[] segs = indentSegs(_segs, indent);
|
|
||||||
if (segs == _segs) {
|
if (segs == _segs) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ public class Template {
|
|||||||
if (indent.equals("")) {
|
if (indent.equals("")) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
Segment[] copySegs = Mustache.indentSegs(_segs, indent);
|
Segment[] copySegs = Mustache.indentSegs(_segs, indent, false,false);
|
||||||
if (copySegs == _segs) {
|
if (copySegs == _segs) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public abstract class SpecTest {
|
|||||||
public void test () throws Exception {
|
public void test () throws Exception {
|
||||||
//System.out.println("Testing: " + name);
|
//System.out.println("Testing: " + name);
|
||||||
SpecAwareTemplateLoader loader = new SpecAwareTemplateLoader(spec);
|
SpecAwareTemplateLoader loader = new SpecAwareTemplateLoader(spec);
|
||||||
Mustache.Compiler compiler = Mustache.compiler().defaultValue("").withLoader(loader);
|
Mustache.Compiler compiler = Mustache.compiler().emptyStringIsFalse(true).defaultValue("").withLoader(loader);
|
||||||
String tmpl = spec.getTemplate();
|
String tmpl = spec.getTemplate();
|
||||||
String desc = String.format("Template: '''%s'''\nData: '%s'\n",
|
String desc = String.format("Template: '''%s'''\nData: '%s'\n",
|
||||||
uncrlf(tmpl), uncrlf(spec.getData().toString()));
|
uncrlf(tmpl), uncrlf(spec.getData().toString()));
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ tests:
|
|||||||
nest: "2\n{{{content}}}\n2\n"
|
nest: "2\n{{{content}}}\n2\n"
|
||||||
expected: "|\n 1\n 2\n <\n->\n 2\n 1\n|\n"
|
expected: "|\n 1\n 2\n <\n->\n 2\n 1\n|\n"
|
||||||
|
|
||||||
- name: Standalone Indentation
|
- name: Partial Section Indentation End Content
|
||||||
desc: Each line of the partial should be indented before rendering.
|
desc: Closing end sections that have content on same line should be indented
|
||||||
data: { content: "<\n->" }
|
data: { content: "<\n->" }
|
||||||
template: |
|
template: |
|
||||||
\
|
\
|
||||||
@@ -34,12 +34,83 @@ tests:
|
|||||||
partials:
|
partials:
|
||||||
partial: |
|
partial: |
|
||||||
|
|
|
|
||||||
{{{content}}}
|
{{#content}}
|
||||||
|
{{{.}}}
|
||||||
|
{{/content}}-
|
||||||
|
|
|
|
||||||
expected: |
|
expected: |
|
||||||
\
|
\
|
||||||
|
|
|
|
||||||
<
|
<
|
||||||
->
|
->
|
||||||
|
-
|
||||||
|
|
|
|
||||||
/
|
/
|
||||||
|
|
||||||
|
- name: Partial Section Indentation Inside Start Content
|
||||||
|
desc: Content that is not white space on same line as section start tag inside should be indented
|
||||||
|
data: { content: "<\n->" }
|
||||||
|
template: |
|
||||||
|
\
|
||||||
|
{{>partial}}
|
||||||
|
/
|
||||||
|
partials:
|
||||||
|
partial: |
|
||||||
|
|
|
||||||
|
{{#content}}-
|
||||||
|
{{{.}}}
|
||||||
|
{{/content}}
|
||||||
|
|
|
||||||
|
expected: |
|
||||||
|
\
|
||||||
|
|
|
||||||
|
-
|
||||||
|
<
|
||||||
|
->
|
||||||
|
|
|
||||||
|
/
|
||||||
|
|
||||||
|
- name: Partial Section Indentation Start Content
|
||||||
|
desc: Content that is not white space on same line as section start tags should be indented
|
||||||
|
data: { content: "<\n->" }
|
||||||
|
template: |
|
||||||
|
\
|
||||||
|
{{>partial}}
|
||||||
|
/
|
||||||
|
partials:
|
||||||
|
partial: |
|
||||||
|
|
|
||||||
|
-{{#content}}
|
||||||
|
{{{.}}}
|
||||||
|
{{/content}}
|
||||||
|
|
|
||||||
|
expected: |
|
||||||
|
\
|
||||||
|
|
|
||||||
|
-
|
||||||
|
<
|
||||||
|
->
|
||||||
|
|
|
||||||
|
/
|
||||||
|
|
||||||
|
- name: Partial Indentation With Empty Sections
|
||||||
|
desc: Empty standlone sections should not have indentation before or after
|
||||||
|
data: { content: "" }
|
||||||
|
template: |
|
||||||
|
\
|
||||||
|
{{>partial}}
|
||||||
|
/
|
||||||
|
partials:
|
||||||
|
partial: |
|
||||||
|
|
|
||||||
|
{{#content}}
|
||||||
|
{{{.}}}
|
||||||
|
{{/content}}
|
||||||
|
|
|
||||||
|
expected: |
|
||||||
|
\
|
||||||
|
|
|
||||||
|
|
|
||||||
|
/
|
||||||
|
|
||||||
|
# The extra newline on the end is required
|
||||||
Reference in New Issue
Block a user