public StrongEmphSuperNode(StrongEmphSuperNode node) { super(node.getChildren()); this.isClosed = node.isClosed; this.chars = node.chars; }
/** * Mark the current StrongEmphSuperNode as closed sequence */ protected boolean setClosed(){ StrongEmphSuperNode node = (StrongEmphSuperNode) peek(); node.setClosed(true); return true; }
/** * This method checks if current parent is a strong parent based on param `chars`. If so, it checks if the * latest inline node to be added as child does not end with a closing character of the parent. When this * is true, a next test should check if the closing character(s) of the child should become (part of) the * closing character(s) of the parent. */ protected boolean isStrongCloseCharStolen( String chars ){ if(chars.length() < 2 ) return false; Object childClass = peek().getClass(); //checks if last `inline` to be added as child is not a StrongEmphSuperNode //that eats up a closing character for the parent StrongEmphSuperNode if( StrongEmphSuperNode.class.equals( childClass ) ){ StrongEmphSuperNode child = (StrongEmphSuperNode) peek(); if (!child.isClosed()) return false; if( child.getChars().endsWith( chars.substring(0, 1) ) ){ //The nested child ends with closing char for the parent, allow stealing it back return true; } } return false; }
/** * This method checks if the parser can enter an emph or strong sequence * Emph only allows Strong as direct child, Strong only allows Emph as * direct child. */ protected boolean mayEnterEmphOrStrong(String chars){ if( !isLegalEmphOrStrongStartPos() ){ return false; } Object parent = peek(2); boolean isStrong = ( chars.length()==2 ); if( StrongEmphSuperNode.class.equals( parent.getClass() ) ){ if( ((StrongEmphSuperNode) parent).isStrong() == isStrong ) return false; } return true; }
@Cached public Rule EmphOrStrong(String chars) { return Sequence( Test(mayEnterEmphOrStrong(chars)), EmphOrStrongOpen(chars), push(new StrongEmphSuperNode(chars)), OneOrMore( TestNot(EmphOrStrongClose(chars)), Inline(), FirstOf( Sequence( //if current inline ends with a closing char for a current strong node: Test(isStrongCloseCharStolen(chars)), //and composes a valid strong close: chars.substring(0, 1), //which is not followed by another closing char (e.g. in __strong _nestedemph___): TestNot(chars.substring(0, 1)), //degrade current inline emph to unclosed and mark current strong node for closing stealBackStrongCloseChar() ), addAsChild() ) ), Optional(Sequence(EmphOrStrongClose(chars), setClosed())) ); }
@Override public boolean f(StrongEmphSuperNode p, final Node parent, final int index) { if( index!=0 || !p.isStrong() ) return false; boolean found = findByClass(p, TextNode.class, isSpecialPanelText ); if( found ) { // GET ELEMENT TITLE final StringBuilder _sb = bufferVisit(new F<Void,Void>() { @Override public Void f(Void p) { parent.getChildren().remove(0); visitChildren(parent); return null; } }); title = _sb.toString().trim(); } return found; }
@Override public boolean f(StrongEmphSuperNode p, final Node parent, final int index) { if( index!=0 || !p.isStrong() ) return false; boolean found = findByClass(p, TextNode.class, isSpecialPanelText ); if( found ) { // GET ELEMENT TITLE final StringBuilder _sb = bufferVisit( (param) -> { parent.getChildren().remove(0); visitChildren(parent); } ); title = _sb.toString().trim(); } return found; }
/** * This method checks if the last parsed character or sequence is a valid prefix for a closing char for * an emph or strong sequence. */ protected boolean isLegalEmphOrStrongClosePos(){ Object lastItem = peek(); if ( StrongEmphSuperNode.class.equals( lastItem.getClass() ) ){ List<Node> children = ((StrongEmphSuperNode) lastItem).getChildren(); if(children.size() < 1) return true; lastItem = children.get( children.size()-1 ); Class<?> lastClass = lastItem.getClass(); if( TextNode.class.equals(lastClass) ) return !((TextNode) lastItem).getText().endsWith(" "); if( SimpleNode.class.equals(lastClass) ) return !((SimpleNode) lastItem).getType().equals(SimpleNode.Type.Linebreak); } return true; }
/** * Steals the last close char by marking a previously closed emph/strong node as unclosed. */ protected boolean stealBackStrongCloseChar(){ StrongEmphSuperNode child = (StrongEmphSuperNode) peek(); child.setClosed(false); addAsChild(); //signal parser to close StrongEmphSuperNode in next check for close char push(new ValidEmphOrStrongCloseNode()); return true; }
@Override public boolean f(StrongEmphSuperNode p, final Node parent, final int index) { if( index!=0 || !p.isStrong() ) return false; boolean found = findByClass(p, TextNode.class, isSpecialPanelText ); if( found ) { // GET ELEMENT TITLE final StringBuilder _sb = bufferVisit( (param) -> { parent.getChildren().remove(0); visitChildren(parent); } ); title = _sb.toString().trim(); } return found; }
@Override public void process(int level, Node node, InvocationContext context) { StrongEmphSuperNode emNode = (StrongEmphSuperNode) node; Font font = context.peekFont(); int style = emNode.isStrong() ? Font.BOLD : Font.ITALIC; context.pushFont(new Font(font.getBaseFont(), font.getSize(), font.getStyle() | style)); context.processChildren(level, node); context.popFont(); } }