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) {
|
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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user