package gutenberg.pegdown.plugin;
import org.parboiled.Rule;
import org.parboiled.common.Reference;
import org.parboiled.support.StringBuilderVar;
import org.pegdown.Parser;
import org.pegdown.ast.AbstractNode;
import org.pegdown.ast.Node;
import org.pegdown.plugins.BlockPluginParser;
/**
* @author <a href="http://twitter.com/aloyer">@aloyer</a>
*/
public class GenericBoxPlugin extends Parser implements BlockPluginParser {
public final Reference<Parser> delegate;
public GenericBoxPlugin(Reference<Parser> delegate) {
super(ALL, 1000l, DefaultParseRunnerProvider);
this.delegate = delegate;
}
@Override
public Rule[] blockPluginRules() {
return new Rule[]{Box()};
}
public Rule Box() {
StringBuilderVar inner = new StringBuilderVar();
return NodeSequence(
OneOrMore(
xcrossedOut(Sequence('G', '>', Optional(' ')), inner),
Line(inner)
),
// trigger a recursive parsing run on the inner source we just built
// and attach the root of the inner parses AST
push(new GenericBoxNode(
xwithIndicesShifted(
delegate.get().parseInternal(inner),
(Integer) peek()
).getChildren()))
);
}
Rule xcrossedOut(Rule rule, StringBuilderVar block) {
return Sequence(rule, xappendCrossed(block));
}
boolean xappendCrossed(StringBuilderVar block) {
for (int i = 0; i < matchLength(); i++) {
block.append(CROSSED_OUT);
}
return true;
}
Node xwithIndicesShifted(Node node, int delta) {
((AbstractNode) node).shiftIndices(delta);
for (Node subNode : node.getChildren()) {
xwithIndicesShifted(subNode, delta);
}
return node;
}
}