Add indentation to partials
This commit is contained in:
@@ -84,7 +84,11 @@ public class Mustache {
|
|||||||
|
|
||||||
/** Compiles the supplied template into a repeatedly executable intermediate form. */
|
/** Compiles the supplied template into a repeatedly executable intermediate form. */
|
||||||
public Template compile (Reader source) {
|
public Template compile (Reader source) {
|
||||||
return Mustache.compile(source, this);
|
return compile(source, "");
|
||||||
|
}
|
||||||
|
/** Compiles the supplied template into a repeatedly executable intermediate form. */
|
||||||
|
public Template compile (Reader source, String indent) {
|
||||||
|
return Mustache.compile(source, this, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a compiler that either does or does not escape HTML by default. Note: this
|
/** Returns a compiler that either does or does not escape HTML by default. Note: this
|
||||||
@@ -214,11 +218,11 @@ public class Mustache {
|
|||||||
* @throw MustacheException if the template could not be loaded (due to I/O exception) or
|
* @throw MustacheException if the template could not be loaded (due to I/O exception) or
|
||||||
* compiled (due to syntax error, etc.).
|
* compiled (due to syntax error, etc.).
|
||||||
*/
|
*/
|
||||||
public Template loadTemplate (String name) throws MustacheException {
|
public Template loadTemplate (String name, String indent) throws MustacheException {
|
||||||
Reader tin = null;
|
Reader tin = null;
|
||||||
try {
|
try {
|
||||||
tin = loader.getTemplate(name);
|
tin = loader.getTemplate(name);
|
||||||
return compile(tin);
|
return compile(tin, indent);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof RuntimeException) {
|
if (e instanceof RuntimeException) {
|
||||||
throw (RuntimeException)e;
|
throw (RuntimeException)e;
|
||||||
@@ -385,13 +389,55 @@ public class Mustache {
|
|||||||
/**
|
/**
|
||||||
* Compiles the supplied template into a repeatedly executable intermediate form.
|
* Compiles the supplied template into a repeatedly executable intermediate form.
|
||||||
*/
|
*/
|
||||||
protected static Template compile (Reader source, Compiler compiler) {
|
protected static Template compile (Reader source, Compiler compiler, String indent) {
|
||||||
Accumulator accum = new Parser(compiler).parse(source);
|
Accumulator accum = new Parser(compiler).parse(source);
|
||||||
return new Template(trim(accum.finish(), true), compiler);
|
return new Template(trim(indent(accum.finish(), indent, false), true), compiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mustache () {} // no instantiateski
|
private Mustache () {} // no instantiateski
|
||||||
|
|
||||||
|
protected static Template.Segment[] indent(Template.Segment[] segs, String indent, boolean inline) {
|
||||||
|
for (int ii = 0, ll = segs.length; ii < ll ; ii++) {
|
||||||
|
Template.Segment seg = segs[ii];
|
||||||
|
Template.Segment pseg = (ii > 0) ? segs[ii - 1] : null;
|
||||||
|
Template.Segment nseg = (ii < ll - 1) ? segs[ii + 1] : null;
|
||||||
|
StringSegment prev = (pseg instanceof StringSegment) ? (StringSegment)pseg : null;
|
||||||
|
boolean prevBlank = prev != null && prev.trailsBlank();
|
||||||
|
// add indent after each new line when the next line is not empty
|
||||||
|
if (seg instanceof StringSegment && !indent.isEmpty()) {
|
||||||
|
final StringSegment segment = ((StringSegment) seg);
|
||||||
|
// add indent to every line that is not blank
|
||||||
|
String indentedText = segment._text.replaceAll("\n(?!\r?\n)", "\n" + indent);
|
||||||
|
// if the last line ist just the indent, remove it
|
||||||
|
if (nseg == null && indentedText.endsWith("\n" + indent)) {
|
||||||
|
indentedText = indentedText.substring(0, indentedText.length() - indent.length());
|
||||||
|
}
|
||||||
|
// if this is the first segement in a block, add indent at the beginning
|
||||||
|
if (pseg == null && !inline) {
|
||||||
|
indentedText = indent + indentedText;
|
||||||
|
}
|
||||||
|
segs[ii] = new StringSegment(indentedText, false);
|
||||||
|
} else if (seg instanceof BlockSegment) {
|
||||||
|
BlockSegment block = (BlockSegment)seg;
|
||||||
|
final boolean inlineBlock = !block.firstLeadsBlank() || !prevBlank;
|
||||||
|
block._segs = indent(block._segs, indent, inlineBlock);
|
||||||
|
} else if (seg instanceof IncludedTemplateSegment) {
|
||||||
|
final IncludedTemplateSegment segment = (IncludedTemplateSegment) seg;
|
||||||
|
if (prev != null && prev.trailsBlank()) {
|
||||||
|
segment._indent = prev.getTrailBlank();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add indent to the first line if it starts with a variable
|
||||||
|
if (!indent.isEmpty() && segs.length > 0 && !inline && (segs[0] instanceof VariableSegment)) {
|
||||||
|
Template.Segment[] oldSegs = segs;
|
||||||
|
segs = new Template.Segment[segs.length + 1];
|
||||||
|
segs[0] = new StringSegment(indent, false);
|
||||||
|
System.arraycopy(oldSegs, 0, segs, 1, oldSegs.length);
|
||||||
|
}
|
||||||
|
return segs;
|
||||||
|
}
|
||||||
|
|
||||||
protected static Template.Segment[] trim (Template.Segment[] segs, boolean top) {
|
protected static Template.Segment[] trim (Template.Segment[] segs, boolean top) {
|
||||||
// now that we have all of our segments, we make a pass through them to trim whitespace
|
// now that we have all of our segments, we make a pass through them to trim whitespace
|
||||||
// from section tags which stand alone on their lines
|
// from section tags which stand alone on their lines
|
||||||
@@ -415,9 +461,10 @@ public class Mustache {
|
|||||||
block.trimLastBlank();
|
block.trimLastBlank();
|
||||||
if (nseg != null) segs[ii+1] = next.trimLeadBlank();
|
if (nseg != null) segs[ii+1] = next.trimLeadBlank();
|
||||||
}
|
}
|
||||||
|
trim(block._segs, false);
|
||||||
}
|
}
|
||||||
// potentially trim around non-printing (comments/delims) segments
|
// potentially trim around non-printing (comments/delims) segments
|
||||||
else if (seg instanceof FauxSegment) {
|
else if (seg instanceof FauxSegment || seg instanceof IncludedTemplateSegment) {
|
||||||
if (prevBlank && nextBlank) {
|
if (prevBlank && nextBlank) {
|
||||||
if (pseg != null) segs[ii-1] = prev.trimTrailBlank();
|
if (pseg != null) segs[ii-1] = prev.trimTrailBlank();
|
||||||
if (nseg != null) segs[ii+1] = next.trimLeadBlank();
|
if (nseg != null) segs[ii+1] = next.trimLeadBlank();
|
||||||
@@ -775,6 +822,13 @@ public class Mustache {
|
|||||||
_trailBlank = trailBlank;
|
_trailBlank = trailBlank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTrailBlank() {
|
||||||
|
if (!trailsBlank()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return _text.substring(_trailBlank);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean leadsBlank () { return _leadBlank != -1; }
|
public boolean leadsBlank () { return _leadBlank != -1; }
|
||||||
public boolean trailsBlank () { return _trailBlank != -1; }
|
public boolean trailsBlank () { return _trailBlank != -1; }
|
||||||
|
|
||||||
@@ -821,6 +875,7 @@ public class Mustache {
|
|||||||
|
|
||||||
/** A segment that loads and executes a sub-template. */
|
/** A segment that loads and executes a sub-template. */
|
||||||
protected static class IncludedTemplateSegment extends Template.Segment {
|
protected static class IncludedTemplateSegment extends Template.Segment {
|
||||||
|
private String _indent = "";
|
||||||
public IncludedTemplateSegment (Compiler compiler, String name) {
|
public IncludedTemplateSegment (Compiler compiler, String name) {
|
||||||
_comp = compiler;
|
_comp = compiler;
|
||||||
_name = name;
|
_name = name;
|
||||||
@@ -842,7 +897,7 @@ public class Mustache {
|
|||||||
// we compile our template lazily to avoid infinie recursion if a template includes
|
// we compile our template lazily to avoid infinie recursion if a template includes
|
||||||
// itself (see issue #13)
|
// itself (see issue #13)
|
||||||
if (_template == null) {
|
if (_template == null) {
|
||||||
_template = _comp.loadTemplate(_name);
|
_template = _comp.loadTemplate(_name, _indent);
|
||||||
}
|
}
|
||||||
return _template;
|
return _template;
|
||||||
}
|
}
|
||||||
@@ -913,7 +968,7 @@ public class Mustache {
|
|||||||
|
|
||||||
protected BlockSegment (String name, Template.Segment[] segs, int line) {
|
protected BlockSegment (String name, Template.Segment[] segs, int line) {
|
||||||
super(name, line);
|
super(name, line);
|
||||||
_segs = trim(segs, false);
|
_segs = segs;
|
||||||
}
|
}
|
||||||
protected void executeSegs (Template tmpl, Template.Context ctx, Writer out) {
|
protected void executeSegs (Template tmpl, Template.Context ctx, Writer out) {
|
||||||
for (Template.Segment seg : _segs) {
|
for (Template.Segment seg : _segs) {
|
||||||
@@ -921,7 +976,7 @@ public class Mustache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final Template.Segment[] _segs;
|
protected Template.Segment[] _segs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A segment that represents a section. */
|
/** A segment that represents a section. */
|
||||||
|
|||||||
@@ -228,6 +228,97 @@ public abstract class SharedTests extends GWTTestCase
|
|||||||
}), "foo inside:foo nonfoo foo", "{{bar}} {{>foo}} {{>baz}} {{bar}}", context("bar", "foo"));
|
}), "foo inside:foo nonfoo foo", "{{bar}} {{>foo}} {{>baz}} {{bar}}", context("bar", "foo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test public void testPartialIndent () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
return new StringReader("|\n{{{content}}}\n|\n");
|
||||||
|
}
|
||||||
|
}), "\\\n |\n <\n->\n |\n/\n", "\\\n {{>partial}}\n/\n", context("content", "<\n->"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testPartialBlankLines () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
return new StringReader("|\na\n\nb\n|\n");
|
||||||
|
}
|
||||||
|
}), "\\\n\t|\n\ta\n\n\tb\n\t|\n/\n", "\\\n\t{{>partial}}\n/\n", context());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testNestedPartialBlankLines () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
if (name.equals("partial")) {
|
||||||
|
return new StringReader("1\n\t{{>nest}}\n1\n");
|
||||||
|
} else {
|
||||||
|
return new StringReader("2\na\n\nb\n2\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), "\\\n\t1\n\t\t2\n\t\ta\n\n\t\tb\n\t\t2\n\t1\n/\n", "\\\n\t{{>partial}}\n/\n", context());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testNestedPartialBlankLinesCRLF () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
if (name.equals("partial")) {
|
||||||
|
return new StringReader("1\r\n\t{{>nest}}\r\n1\r\n");
|
||||||
|
} else {
|
||||||
|
return new StringReader("2\r\na\r\n\r\nb\r\n2\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), "\\\r\n\t1\r\n\t\t2\r\n\t\ta\r\n\r\n\t\tb\r\n\t\t2\r\n\t1\r\n/\r\n", "\\\r\n\t{{>partial}}\r\n/\r\n", context());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testNestedPartialIndent () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
if (name.equals("partial")) {
|
||||||
|
return new StringReader("1\n {{>nest}}\n1\n");
|
||||||
|
} else {
|
||||||
|
return new StringReader("2\n{{{content}}}\n2\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), "|\n 1\n 2\n <\n->\n 2\n 1\n|\n", "|\n {{>partial}}\n|\n", context("content", "<\n->"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testPartialIndentWithVariableAtTheStart () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
return new StringReader("{{{content}}}\n|\n");
|
||||||
|
}
|
||||||
|
}), "\\\n <\n->\n |\n/\n", "\\\n {{>partial}}\n/\n", context("content", "<\n->"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testPartialIndentWithBlock () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
return new StringReader("|\n{{#show}}\n{{{content}}}{{/show}}\n|\n");
|
||||||
|
}
|
||||||
|
}), "\\\n |\n <\n->\n |\n/\n", "\\\n {{>partial}}\n/\n", context("show", true, "content", "<\n->"));
|
||||||
|
}
|
||||||
|
@Test public void testPartialIndentInBlock () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
return new StringReader("content");
|
||||||
|
}
|
||||||
|
}), " content", "{{#show}}\n {{>partial}}\n{{/show}}\n", context("show", true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testPartialIndentWithBlockAtStart () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
return new StringReader("{{#show}}\n{{{content}}}{{/show}}\n|\n");
|
||||||
|
}
|
||||||
|
}), "\\\n <\n->\n |\n/\n", "\\\n {{>partial}}\n/\n", context("show", true, "content", "<\n->"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void testPartialIndentWithInlineBlock () {
|
||||||
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate (String name) {
|
||||||
|
return new StringReader("line {{#show}}content{{/show}}\n");
|
||||||
|
}
|
||||||
|
}), "\\\n line content\n/\n", "\\\n {{>partial}}\n/\n", context("show", true));
|
||||||
|
}
|
||||||
|
|
||||||
@Test public void testPartialPlusNestedContext () {
|
@Test public void testPartialPlusNestedContext () {
|
||||||
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
test(Mustache.compiler().withLoader(new Mustache.TemplateLoader() {
|
||||||
public Reader getTemplate (String name) {
|
public Reader getTemplate (String name) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public class SpecRunner extends BlockJUnit4ClassRunner
|
|||||||
"interpolation",
|
"interpolation",
|
||||||
"inverted",
|
"inverted",
|
||||||
"sections",
|
"sections",
|
||||||
// "partials"
|
"partials"
|
||||||
};
|
};
|
||||||
Method m = getTestClassMethod("test", Spec.class);
|
Method m = getTestClassMethod("test", Spec.class);
|
||||||
List<FrameworkMethod> tests = new ArrayList<FrameworkMethod>();
|
List<FrameworkMethod> tests = new ArrayList<FrameworkMethod>();
|
||||||
|
|||||||
Reference in New Issue
Block a user