Properly trim whitespace around delims tag.

This includes consolidation of other whitespace trimming to avoid duplication
with the delims trimming code.
This commit is contained in:
Michael Bayne
2014-12-16 11:07:24 -08:00
parent 4b3f677fbf
commit 0e2a7d13d5
@@ -299,21 +299,33 @@ public class Mustache
protected static Template.Segment[] trim (Template.Segment[] segs) { protected static Template.Segment[] trim (Template.Segment[] segs) {
// 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
for (int ii = 0, ll = segs.length-1; ii < ll; ii++) { for (int ii = 0, ll = segs.length; ii < ll; ii++) {
Template.Segment seg0 = segs[ii], seg1 = segs[ii+1]; Template.Segment seg = segs[ii];
// check whether we're looking at <sttart>/block (trim open) or block/<end> (trim close) Template.Segment pseg = (ii > 0) ? segs[ii-1] : null;
if (ii == 0 && seg0 instanceof BlockSegment) { Template.Segment nseg = (ii < ll-1) ? segs[ii+1] : null;
((BlockSegment)seg0).trimOpen(); StringSegment prev = (pseg instanceof StringSegment) ? (StringSegment)pseg : null;
} else if (ii == ll-1 && seg1 instanceof BlockSegment) { StringSegment next = (nseg instanceof StringSegment) ? (StringSegment)nseg : null;
((BlockSegment)seg1).trimClose(); boolean prevTrailsBlank = (pseg == null || (prev != null && prev.trailsBlank()));
boolean nextLeadsBlank = (nseg == null || (next != null && next.leadsBlank()));
boolean trimPrev = false, trimNext = false;
// potentially trim the open and close tags of a block segment
if (seg instanceof BlockSegment) {
BlockSegment block = (BlockSegment)seg;
if (prevTrailsBlank && block.firstLeadsBlank()) {
if (pseg != null) segs[ii-1] = prev.trimTrailBlank();
block.trimFirstBlank();
}
if (nextLeadsBlank && block.lastTrailsBlank()) {
block.trimLastBlank();
if (nseg != null) segs[ii+1] = next.trimLeadBlank();
}
} }
// check whether we're looking at a block/text sequence (trim close) // potentially trim around a delims segment
if (seg0 instanceof BlockSegment && seg1 instanceof StringSegment) { else if (seg instanceof DelimsSegment) {
segs[ii+1] = ((BlockSegment)seg0).trimClose((StringSegment)seg1); if (prevTrailsBlank && nextLeadsBlank) {
} if (pseg != null) segs[ii-1] = prev.trimTrailBlank();
// check whether we're looking at a text/block sequence (trim open) if (nseg != null) segs[ii+1] = next.trimLeadBlank();
else if (seg0 instanceof StringSegment && seg1 instanceof BlockSegment) { }
segs[ii] = ((BlockSegment)seg1).trimOpen((StringSegment)seg0);
} }
} }
return segs; return segs;
@@ -446,6 +458,7 @@ public class Mustache
if (text.charAt(0) == '=') { if (text.charAt(0) == '=') {
delims.updateDelims(text.substring(1, text.length()-1)); delims.updateDelims(text.substring(1, text.length()-1));
text.setLength(0); text.setLength(0);
accum.addDelimsSegment(); // for newline trimming
} else { } else {
// if the delimiters are {{ and }}, and the tag starts with {{{ then // if the delimiters are {{ and }}, and the tag starts with {{{ then
// require that it end with }}} and disable escaping // require that it end with }}} and disable escaping
@@ -610,6 +623,10 @@ public class Mustache
} }
} }
public void addDelimsSegment () {
_segs.add(new DelimsSegment());
}
public Template.Segment[] finish () { public Template.Segment[] finish () {
return _segs.toArray(new Template.Segment[_segs.size()]); return _segs.toArray(new Template.Segment[_segs.size()]);
} }
@@ -752,21 +769,22 @@ public class Mustache
/** A helper class for block segments. */ /** A helper class for block segments. */
protected static abstract class BlockSegment extends NamedSegment { protected static abstract class BlockSegment extends NamedSegment {
public void trimOpen () { public boolean firstLeadsBlank () {
if (firstLeadsBlank()) trimFirstBlank(); if (_segs.length == 0 || !(_segs[0] instanceof StringSegment)) return false;
return ((StringSegment)_segs[0]).leadsBlank();
} }
public void trimClose () { public void trimFirstBlank () {
if (lastTrailsBlank()) trimLastBlank(); _segs[0] = ((StringSegment)_segs[0]).trimLeadBlank();
} }
public StringSegment trimOpen (StringSegment prev) {
if (!firstLeadsBlank() || !prev.trailsBlank()) return prev; public boolean lastTrailsBlank () {
trimFirstBlank(); int lastIdx = _segs.length-1;
return prev.trimTrailBlank(); if (_segs.length == 0 || !(_segs[lastIdx] instanceof StringSegment)) return false;
return ((StringSegment)_segs[lastIdx]).trailsBlank();
} }
public StringSegment trimClose (StringSegment next) { public void trimLastBlank () {
if (!lastTrailsBlank() || !next.leadsBlank()) return next; int idx = _segs.length-1;
trimLastBlank(); _segs[idx] = ((StringSegment)_segs[idx]).trimTrailBlank();
return next.trimLeadBlank();
} }
protected BlockSegment (String name, Template.Segment[] segs, int line) { protected BlockSegment (String name, Template.Segment[] segs, int line) {
@@ -779,24 +797,6 @@ public class Mustache
} }
} }
private boolean firstLeadsBlank () {
if (_segs.length == 0 || !(_segs[0] instanceof StringSegment)) return false;
return ((StringSegment)_segs[0]).leadsBlank();
}
private void trimFirstBlank () {
_segs[0] = ((StringSegment)_segs[0]).trimLeadBlank();
}
private boolean lastTrailsBlank () {
int lastIdx = _segs.length-1;
if (_segs.length == 0 || !(_segs[lastIdx] instanceof StringSegment)) return false;
return ((StringSegment)_segs[lastIdx]).trailsBlank();
}
private void trimLastBlank () {
int idx = _segs.length-1;
_segs[idx] = ((StringSegment)_segs[idx]).trimTrailBlank();
}
protected final Template.Segment[] _segs; protected final Template.Segment[] _segs;
} }
@@ -871,6 +871,10 @@ public class Mustache
protected final Compiler _comp; protected final Compiler _comp;
} }
protected static class DelimsSegment extends Template.Segment {
@Override public void execute (Template tmpl, Template.Context ctx, Writer out) {} // nada
}
/** Used when we have only a single character delimiter. */ /** Used when we have only a single character delimiter. */
protected static final char NO_CHAR = Character.MIN_VALUE; protected static final char NO_CHAR = Character.MIN_VALUE;