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:
@@ -299,21 +299,33 @@ public class Mustache
|
||||
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
|
||||
// from section tags which stand alone on their lines
|
||||
for (int ii = 0, ll = segs.length-1; ii < ll; ii++) {
|
||||
Template.Segment seg0 = segs[ii], seg1 = segs[ii+1];
|
||||
// check whether we're looking at <sttart>/block (trim open) or block/<end> (trim close)
|
||||
if (ii == 0 && seg0 instanceof BlockSegment) {
|
||||
((BlockSegment)seg0).trimOpen();
|
||||
} else if (ii == ll-1 && seg1 instanceof BlockSegment) {
|
||||
((BlockSegment)seg1).trimClose();
|
||||
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;
|
||||
StringSegment next = (nseg instanceof StringSegment) ? (StringSegment)nseg : null;
|
||||
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)
|
||||
if (seg0 instanceof BlockSegment && seg1 instanceof StringSegment) {
|
||||
segs[ii+1] = ((BlockSegment)seg0).trimClose((StringSegment)seg1);
|
||||
}
|
||||
// check whether we're looking at a text/block sequence (trim open)
|
||||
else if (seg0 instanceof StringSegment && seg1 instanceof BlockSegment) {
|
||||
segs[ii] = ((BlockSegment)seg1).trimOpen((StringSegment)seg0);
|
||||
// potentially trim around a delims segment
|
||||
else if (seg instanceof DelimsSegment) {
|
||||
if (prevTrailsBlank && nextLeadsBlank) {
|
||||
if (pseg != null) segs[ii-1] = prev.trimTrailBlank();
|
||||
if (nseg != null) segs[ii+1] = next.trimLeadBlank();
|
||||
}
|
||||
}
|
||||
}
|
||||
return segs;
|
||||
@@ -446,6 +458,7 @@ public class Mustache
|
||||
if (text.charAt(0) == '=') {
|
||||
delims.updateDelims(text.substring(1, text.length()-1));
|
||||
text.setLength(0);
|
||||
accum.addDelimsSegment(); // for newline trimming
|
||||
} else {
|
||||
// if the delimiters are {{ and }}, and the tag starts with {{{ then
|
||||
// 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 () {
|
||||
return _segs.toArray(new Template.Segment[_segs.size()]);
|
||||
}
|
||||
@@ -752,21 +769,22 @@ public class Mustache
|
||||
|
||||
/** A helper class for block segments. */
|
||||
protected static abstract class BlockSegment extends NamedSegment {
|
||||
public void trimOpen () {
|
||||
if (firstLeadsBlank()) trimFirstBlank();
|
||||
public boolean firstLeadsBlank () {
|
||||
if (_segs.length == 0 || !(_segs[0] instanceof StringSegment)) return false;
|
||||
return ((StringSegment)_segs[0]).leadsBlank();
|
||||
}
|
||||
public void trimClose () {
|
||||
if (lastTrailsBlank()) trimLastBlank();
|
||||
public void trimFirstBlank () {
|
||||
_segs[0] = ((StringSegment)_segs[0]).trimLeadBlank();
|
||||
}
|
||||
public StringSegment trimOpen (StringSegment prev) {
|
||||
if (!firstLeadsBlank() || !prev.trailsBlank()) return prev;
|
||||
trimFirstBlank();
|
||||
return prev.trimTrailBlank();
|
||||
|
||||
public boolean lastTrailsBlank () {
|
||||
int lastIdx = _segs.length-1;
|
||||
if (_segs.length == 0 || !(_segs[lastIdx] instanceof StringSegment)) return false;
|
||||
return ((StringSegment)_segs[lastIdx]).trailsBlank();
|
||||
}
|
||||
public StringSegment trimClose (StringSegment next) {
|
||||
if (!lastTrailsBlank() || !next.leadsBlank()) return next;
|
||||
trimLastBlank();
|
||||
return next.trimLeadBlank();
|
||||
public void trimLastBlank () {
|
||||
int idx = _segs.length-1;
|
||||
_segs[idx] = ((StringSegment)_segs[idx]).trimTrailBlank();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -871,6 +871,10 @@ public class Mustache
|
||||
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. */
|
||||
protected static final char NO_CHAR = Character.MIN_VALUE;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user