/**
* Copyright (c) 2012-2015 Edgar Espina
*
* This file is part of Handlebars.java.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.jknack.handlebars.internal;
import java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.Token;
import com.github.jknack.handlebars.internal.HbsParser.AmpvarContext;
import com.github.jknack.handlebars.internal.HbsParser.BlockContext;
import com.github.jknack.handlebars.internal.HbsParser.CommentContext;
import com.github.jknack.handlebars.internal.HbsParser.DelimitersContext;
import com.github.jknack.handlebars.internal.HbsParser.NewlineContext;
import com.github.jknack.handlebars.internal.HbsParser.PartialContext;
import com.github.jknack.handlebars.internal.HbsParser.SpacesContext;
import com.github.jknack.handlebars.internal.HbsParser.TemplateContext;
import com.github.jknack.handlebars.internal.HbsParser.TextContext;
import com.github.jknack.handlebars.internal.HbsParser.TvarContext;
import com.github.jknack.handlebars.internal.HbsParser.UnlessContext;
import com.github.jknack.handlebars.internal.HbsParser.VarContext;
/**
* Remove space and lines according to the Mustache Spec.
*
* @author edgar.espina
* @since 0.10.0
*/
public class MustacheSpec extends HbsParserBaseListener {
/**
* Track if the current line has real text (not spaces).
*/
private boolean nonSpace = false;
/**
* Track if the current line has mustache instruction.
*/
private Boolean hasTag;
/**
* Track the current line.
*/
protected StringBuilder line = new StringBuilder();
/**
* Track the spaces/lines that need to be excluded.
*/
private List<CommonToken> spaces = new ArrayList<CommonToken>();
@Override
public void enterSpaces(final SpacesContext ctx) {
CommonToken space = (CommonToken) ctx.SPACE().getSymbol();
line.append(space.getText());
spaces.add(space);
}
@Override
public void enterNewline(final NewlineContext ctx) {
CommonToken newline = (CommonToken) ctx.NL().getSymbol();
spaces.add(newline);
stripSpaces();
}
@Override
public void exitTemplate(final TemplateContext ctx) {
stripSpaces();
}
/**
* Move tokens to the hidden channel if necessary.
*/
private void stripSpaces() {
boolean hasTag = this.hasTag == null ? false : this.hasTag.booleanValue();
if (hasTag && !nonSpace) {
for (CommonToken space : spaces) {
space.setChannel(Token.HIDDEN_CHANNEL);
}
} else {
spaces.clear();
}
this.hasTag = null;
nonSpace = false;
line.setLength(0);
}
@Override
public void enterText(final TextContext ctx) {
nonSpace = true;
}
@Override
public void enterBlock(final BlockContext ctx) {
hasTag(true);
}
@Override
public void exitBlock(final BlockContext ctx) {
hasTag(true);
}
@Override
public void enterComment(final CommentContext ctx) {
hasTag(true);
}
@Override
public void exitPartial(final PartialContext ctx) {
hasTag(true);
}
@Override
public void enterDelimiters(final DelimitersContext ctx) {
hasTag(true);
}
@Override
public void enterUnless(final UnlessContext ctx) {
hasTag(true);
}
@Override
public void exitUnless(final UnlessContext ctx) {
hasTag(true);
}
@Override
public void enterAmpvar(final AmpvarContext ctx) {
hasTag(false);
}
@Override
public void enterTvar(final TvarContext ctx) {
hasTag(false);
}
@Override
public void enterVar(final VarContext ctx) {
hasTag(false);
}
/**
* Mark the current line with a mustache instruction.
*
* @param hasTag True, to indicate there is a mustache instruction.
*/
private void hasTag(final boolean hasTag) {
if (this.hasTag != Boolean.FALSE) {
this.hasTag = hasTag;
}
}
}