/*=============================================================================# # Copyright (c) 2015-2016 David Green and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v1.0 # which accompanies this distribution, and is available at # http://www.eclipse.org/legal/epl-v10.html # # Contributors: # David Green - initial API and implementation in Mylyn # Stephan Wahlbrink (WalWare.de) - revised API and implementation #=============================================================================*/ package de.walware.docmlet.wikitext.internal.commonmark.core.inlines; import java.util.ArrayList; import java.util.List; import org.eclipse.mylyn.wikitext.core.parser.DocumentBuilder; import de.walware.docmlet.wikitext.internal.commonmark.core.CommonmarkLocator; import de.walware.docmlet.wikitext.internal.commonmark.core.Line; import de.walware.docmlet.wikitext.internal.commonmark.core.ProcessingContext; class PotentialStyleDelimiter extends InlineWithText { private final PotentialStyleDelimiterInfo info; private final boolean canOpen; private final boolean canClose; public PotentialStyleDelimiter(final PotentialStyleDelimiterInfo info, final Line line, final int offset, final int length, final String text, final boolean canOpen, final boolean canClose) { super(line, offset, length, length, text); this.info= info; this.canOpen= canOpen; this.canClose= canClose; } @Override public void emit(final ProcessingContext context, final CommonmarkLocator locator, final DocumentBuilder builder) { builder.characters(this.text); } @Override InlinesSubstitution secondPass(final List<Inline> inlines) { if (!this.canClose) { return null; } final int indexOfThis= inlines.indexOf(this); final char c= getText().charAt(0); final int openingDelimiterIndex= findLastOpeningDelimiter(inlines, indexOfThis, c); if (openingDelimiterIndex >= 0) { final PotentialStyleDelimiter openingDelimiter= (PotentialStyleDelimiter) inlines.get(openingDelimiterIndex); final int delimiterSize= this.info.getSize(openingDelimiter.getLength(), getLength()); if ((this.info.getRequirements(delimiterSize) & PotentialStyleDelimiterInfo.NO_SPACE) != 0) { for (int index= openingDelimiterIndex + 1; index < indexOfThis; index++) { final Inline inline= inlines.get(index); if (inline instanceof Characters) { if (((Characters) inline).getText().indexOf(' ') >= 0) { return null; } } if (inline instanceof HardLineBreak) { if (((HardLineBreak) inline).getType() == ' ') { return null; } } } } final List<Inline> contents= InlineParser.secondPass(inlines.subList(openingDelimiterIndex + 1, indexOfThis)); final int startOffset= openingDelimiter.getOffset(); final int endOffset= getOffset() + getLength(); final Inline styleInline= this.info.createStyleInline(delimiterSize, openingDelimiter.getLine(), startOffset, endOffset - startOffset, contents ); final List<Inline> substitutionInlines= new ArrayList<>(); if (delimiterSize < openingDelimiter.getLength()) { substitutionInlines.add(createRemainingOpeningDelimiter(openingDelimiter, delimiterSize)); } substitutionInlines.add(styleInline); if (delimiterSize < getLength()) { substitutionInlines.add(createRemainingClosingDelimiter(delimiterSize)); } return new InlinesSubstitution(openingDelimiter, this, substitutionInlines); } return null; } private int findLastOpeningDelimiter(final List<Inline> inlines, final int indexOfThis, final char c) { for (int index= indexOfThis - 1; index >= 0; --index) { final Inline inline= inlines.get(index); if (inline instanceof PotentialStyleDelimiter) { final PotentialStyleDelimiter previousDelimiter= (PotentialStyleDelimiter) inline; if (previousDelimiter.info == this.info && previousDelimiter.canOpen && ((!this.canOpen && !previousDelimiter.canClose) || (previousDelimiter.getLength() + getLength()) % 3 != 0) ) { return index; } } } return -1; } private Inline createRemainingOpeningDelimiter(final PotentialStyleDelimiter openingDelimiter, final int delimiterSize) { final int newLength= openingDelimiter.getLength() - delimiterSize; if (this.info.isPotentialSequence(newLength)) { return new PotentialStyleDelimiter(this.info, openingDelimiter.getLine(), openingDelimiter.getOffset(), newLength, openingDelimiter.getText().substring(0, newLength), openingDelimiter.canOpen, openingDelimiter.canClose ); } else { return new Characters(openingDelimiter.getLine(), openingDelimiter.getOffset(), newLength, newLength, openingDelimiter.getText().substring(0, newLength) ); } } private Inline createRemainingClosingDelimiter(final int delimiterSize) { final int newLength= getLength() - delimiterSize; if (this.info.isPotentialSequence(newLength)) { return new PotentialStyleDelimiter(this.info, getLine(), getOffset() + delimiterSize, newLength, getText().substring(0, newLength), this.canOpen, this.canClose ); } else { return new Characters(getLine(), getOffset() + delimiterSize, newLength, newLength, getText().substring(0, newLength) ); } } }