blob: b158b101e8ce02d07abfc6f20e4ae321b89ef393 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2014, 2018 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.docmlet.wikitext.core.source;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.mylyn.wikitext.parser.Attributes;
import org.eclipse.mylyn.wikitext.parser.DocumentBuilder;
import org.eclipse.mylyn.wikitext.parser.Locator;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.text.core.BasicTextRegion;
import org.eclipse.statet.jcommons.text.core.TextRegion;
import org.eclipse.statet.ecommons.text.core.ILineInformation;
import org.eclipse.statet.docmlet.wikitext.core.markup.IWikitextLocator;
import org.eclipse.statet.docmlet.wikitext.core.markup.MarkupParser2;
import org.eclipse.statet.ltk.core.SourceContent;
public class WeaveLanguageProcessor extends DocumentBuilder {
private static final boolean DEBUGGING= false;
private static abstract class Embedded {
/** begin startOffset in checked content */
private final int startOffset;
/** end startOffset in checked content */
private final int endOffset;
private final int embedDescr;
public Embedded(final int startOffset, final int endOffset, final int embedDescr) {
this.startOffset= startOffset;
this.endOffset= endOffset;
this.embedDescr= embedDescr;
}
public abstract WeaveParticipant getParticipant();
public final int getEmbedDescr() {
return this.embedDescr;
}
public final int getBeginOffset() {
return this.startOffset;
}
public final int getEndOffset() {
return this.endOffset;
}
public final int getLength() {
return this.endOffset - this.startOffset;
}
public abstract int getOrgLength();
public abstract int getTextLength();
}
private static final class EmbeddedChunk extends Embedded {
private final BlockWeaveParticipant participant;
private final int orgStartOffset;
private final int orgEndOffset;
public EmbeddedChunk(final BlockWeaveParticipant participant,
final int beginOffset, final int endOffset,
final int orgBeginOffset, final int orgEndOffset) {
super(beginOffset, endOffset, participant.getEmbedDescr());
this.participant= participant;
this.orgStartOffset= orgBeginOffset;
this.orgEndOffset= orgEndOffset;
}
@Override
public BlockWeaveParticipant getParticipant() {
return this.participant;
}
public int getShift() {
return this.orgEndOffset - getEndOffset();
}
public int getOrgBeginOffset() {
return this.orgStartOffset;
}
public int getOrgEndOffset() {
return this.orgEndOffset;
}
@Override
public int getOrgLength() {
return this.orgEndOffset - this.orgStartOffset;
}
@Override
public int getTextLength() {
return getParticipant().getTextLength();
}
}
private static final class EmbeddedInline extends Embedded {
private final RegexInlineWeaveParticipant participant;
private final int contentStartOffset;
private final int contentEndOffset;
public EmbeddedInline(final RegexInlineWeaveParticipant participant,
final int beginOffset, final int endOffset,
final int contentStartOffset, final int contentEndOffset) {
super(beginOffset, endOffset, participant.getEmbedDescr());
this.participant= participant;
this.contentStartOffset= contentStartOffset;
this.contentEndOffset= contentEndOffset;
}
@Override
public RegexInlineWeaveParticipant getParticipant() {
return this.participant;
}
public int getContentBeginOffset() {
return this.contentStartOffset;
}
public int getContentEndOffset() {
return this.contentEndOffset;
}
@Override
public int getOrgLength() {
return getLength();
}
@Override
public int getTextLength() {
return getLength();
}
}
private class EmbeddedIterator {
private int nextIdx;
private Embedded nextObject;
private int nextOffset;
public EmbeddedIterator() {
reset();
}
public EmbeddedIterator(final EmbeddedIterator iter0) {
updateNext(iter0.nextIdx);
}
public void reset() {
updateNext(0);
}
private void updateNext(final int idx) {
final int total= WeaveLanguageProcessor.this.embeddedList.size();
if (idx < total) {
this.nextIdx= idx;
this.nextObject= WeaveLanguageProcessor.this.embeddedList.get(idx);
this.nextOffset= this.nextObject.getBeginOffset();
}
else {
this.nextIdx= total;
this.nextObject= null;
this.nextOffset= Integer.MAX_VALUE;
}
}
public final int getNextOffset() {
return this.nextOffset;
}
public @Nullable Embedded getNext() {
return this.nextObject;
}
public final boolean hasNext(final int offset) {
return (offset > this.nextOffset);
}
public void consume() {
updateNext(this.nextIdx + 1);
}
public void consumeTo(final int offset) {
while (offset > this.nextOffset && offset > this.nextObject.getEndOffset()) {
updateNext(this.nextIdx + 1);
}
}
public void consumeToChunk() {
while (this.nextObject != null && !(this.nextObject instanceof EmbeddedChunk)) {
updateNext(this.nextIdx + 1);
}
}
}
private class EmbeddedChunkIterator extends EmbeddedIterator {
public EmbeddedChunkIterator(final EmbeddedIterator iter0) {
super(iter0);
consumeToChunk();
}
@Override
public EmbeddedChunk getNext() {
return (EmbeddedChunk) super.getNext();
}
@Override
public void consume() {
super.consume();
consumeToChunk();
}
@Override
public void consumeTo(final int offset) {
super.consumeTo(offset);
consumeToChunk();
}
}
private final class ExplLocator implements Locator, IWikitextLocator {
private int lineNumber;
private int shift;
private int beginOffset;
private int endOffset;
public ExplLocator() {
}
public void setShift(final int offset) {
this.shift= offset;
}
private void setOffset(final int offset) {
if (this.beginOffset != offset) {
this.beginOffset= offset;
this.lineNumber= -1;
}
this.endOffset= offset;
}
public int computeOffset(final int offset) {
return this.shift + offset;
}
public void setTo(final int beginOffset) {
setOffset(computeOffset(beginOffset));
}
public void setTo(final int beginOffset, final int endOffset) {
setOffset(computeOffset(beginOffset));
if (endOffset > beginOffset) {
this.endOffset= computeOffset(endOffset);
}
}
public void reset() {
this.shift= 0;
this.beginOffset= 0;
this.endOffset= 0;
this.lineNumber= -1;
}
@Override
public int getLineNumber() {
try {
if (this.lineNumber < 0) {
final ILineInformation lines= WeaveLanguageProcessor.this.orgContent.getLines();
this.lineNumber= lines.getLineOfOffset(this.beginOffset);
}
return this.lineNumber;
}
catch (final BadLocationException e) {
throw new RuntimeException(e);
}
}
private ILineInformation getLines() throws BadLocationException {
final ILineInformation lines= WeaveLanguageProcessor.this.orgContent.getLines();
if (this.lineNumber < 0) {
this.lineNumber= lines.getLineOfOffset(this.beginOffset);
}
return lines;
}
@Override
public int getLineOffset() {
try {
return getLines().getLineOffset(this.lineNumber);
}
catch (final BadLocationException e) {
throw new RuntimeException(e);
}
}
@Override
public int getLineDocumentOffset() {
return getLineOffset();
}
@Override
public int getLineLength() {
try {
return getLines().getLineLength(this.lineNumber);
}
catch (final BadLocationException e) {
throw new RuntimeException(e);
}
}
public int getLineEndOffset() {
try {
final ILineInformation lines= getLines();
return lines.getLineEndOffset(this.lineNumber);
}
catch (final BadLocationException e) {
throw new RuntimeException(e);
}
}
@Override
public int getDocumentOffset() {
return this.beginOffset;
}
@Override
public int getBeginOffset() {
return this.beginOffset;
}
@Override
public int getLineCharacterOffset() {
return this.beginOffset - getLineOffset();
}
@Override
public int getEndOffset() {
return this.endOffset;
}
@Override
public int getLineSegmentEndOffset() {
return this.endOffset - getLineOffset();
}
}
private SourceContent orgContent;
private final List<BlockWeaveParticipant> chunkParticipants= new ArrayList<>();
private final List<RegexInlineWeaveParticipant> inlineParticipants= new ArrayList<>();
private Matcher inlineMatcher;
private final List<Embedded> embeddedList= new ArrayList<>();
private final EmbeddedIterator embeddedIterator= new EmbeddedIterator();
private int maxOffset;
private int lastOffset;
// private final Matcher chunkStartMatcher;
// private final Matcher chunkEndMatcher;
private int[] endSpanFix= new int[16];
private int endSpanFixIdx;
private int ignoreCounter;
private final ExplLocator orgLocator= new ExplLocator();
private int flags;
private DocumentBuilder builder;
private boolean finished;
private final StringBuilder sBuilder= new StringBuilder();
public WeaveLanguageProcessor() {
}
public void clearConfig() {
this.chunkParticipants.clear();
this.inlineParticipants.clear();
this.inlineMatcher= null;
}
public void addChunkParticipant(final BlockWeaveParticipant participant) {
if (participant == null) {
throw new NullPointerException("participant"); //$NON-NLS-1$
}
this.chunkParticipants.add(participant);
}
public void addInlineParticipants(final RegexInlineWeaveParticipant participant) {
if (participant == null) {
throw new NullPointerException("participant"); //$NON-NLS-1$
}
this.inlineParticipants.add(participant);
this.inlineMatcher= null;
}
private Pattern combineInlineParticipants() {
final int n= this.inlineParticipants.size();
if (n == 0) {
return null;
}
else if (n == 1) {
return this.inlineParticipants.get(0).getPattern();
}
else {
this.sBuilder.setLength(0);
for (int i= 0; i < n; i++) {
this.sBuilder.append("|(?:"); //$NON-NLS-1$
this.sBuilder.append(this.inlineParticipants.get(i).getPattern().pattern());
this.sBuilder.append(')');
}
return Pattern.compile(this.sBuilder.substring(1));
}
}
public String preprocess(final SourceContent content, final DocumentBuilder builder,
final int flags) {
this.orgContent= content;
this.builder= builder;
this.builder.setLocator(this.orgLocator);
this.flags= flags;
this.orgLocator.reset();
this.finished= false;
this.lastOffset= 0;
this.endSpanFixIdx= -1;
String checkedContent;
final String source= content.getText();
try {
this.embeddedList.clear();
for (int iPart= 0; iPart < this.chunkParticipants.size(); iPart++) {
this.chunkParticipants.get(iPart).reset(content);
}
for (int iPart= 0; iPart < this.inlineParticipants.size(); iPart++) {
this.inlineParticipants.get(iPart).reset(content);
}
if (this.inlineMatcher == null) {
final Pattern pattern= combineInlineParticipants();
if (pattern != null) {
this.inlineMatcher= pattern.matcher(source);
if (DEBUGGING && this.inlineMatcher.groupCount() != this.inlineParticipants.size()) {
System.out.println(this.inlineMatcher.pattern());
}
}
}
else {
this.inlineMatcher.reset(source);
}
this.sBuilder.setLength(0);
this.sBuilder.ensureCapacity(source.length() + 40);
int endOffset= 0;
final ILineInformation lines= content.getLines();
int lineEndOffset= lines.getLineOffset(0);
final int numLines= lines.getNumberOfLines();
for (int line= 0; line < numLines; line++) {
int lineOffset= lineEndOffset;
lineEndOffset= lines.getLineEndOffset(line);
final int nPart= this.chunkParticipants.size();
for (int iPart= 0; iPart < nPart; iPart++) {
final BlockWeaveParticipant part= this.chunkParticipants.get(iPart);
if (part.checkStartLine(lineOffset, lineEndOffset)) {
append(source, endOffset, part.getStartOffset());
final int checkedBeginOffset= this.sBuilder.length();
part.appendReplacement(this.sBuilder, source, part.getStartOffset(), lineEndOffset);
final int checkedEndOffset= this.sBuilder.length();
endOffset= source.length();
while (++line < numLines) {
lineOffset= lineEndOffset;
lineEndOffset= lines.getLineEndOffset(line);
if (part.checkEndLine(lineOffset, lineEndOffset)) {
endOffset= lineEndOffset;
break;
}
}
this.embeddedList.add(new EmbeddedChunk(part,
checkedBeginOffset, checkedEndOffset,
part.getStartOffset(), endOffset ));
}
}
}
if (this.sBuilder.length() > 0 || (this.inlineMatcher != null && this.inlineMatcher.find())) {
append(source, endOffset, source.length());
checkedContent= this.sBuilder.toString();
}
else {
checkedContent= source;
}
this.embeddedIterator.reset();
}
catch (final BadLocationException e) {
throw new RuntimeException(e);
}
this.ignoreCounter= 0;
this.maxOffset= checkedContent.length();
return checkedContent;
}
private void append(final String source, final int begin, final int end) {
if (begin < end) {
final int shift= begin - this.sBuilder.length();
int offset= begin;
final Matcher matcher= this.inlineMatcher;
if (matcher != null) {
matcher.region(begin, end);
final int nPart= this.inlineParticipants.size();
while (matcher.find()) {
final int matchStart= matcher.start();
if (offset < matchStart) {
this.sBuilder.append(source.substring(offset, matchStart));
}
offset= matcher.end();
int length= offset - matchStart;
if (length > 0) {
this.sBuilder.append(WeaveParticipant.REPLACEMENT_CHAR);
length--;
while (length > 0) {
final int l= Math.min(length, 40);
this.sBuilder.append(WeaveParticipant.REPLACEMENT_STRING, 0, l);
// sb.append("Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 0, l);
length-= l;
}
}
for (int iPart= 0; iPart < nPart; iPart++) {
final int groupNum= iPart + 1;
if (matcher.start(groupNum) >= 0) {
this.embeddedList.add(new EmbeddedInline(this.inlineParticipants.get(iPart),
matchStart - shift, offset - shift,
matcher.start(groupNum), matcher.end(groupNum) ));
break;
}
}
}
}
this.sBuilder.append(source.substring(offset, end));
}
}
public void clear() {
this.orgContent= null;
for (int iPart= 0; iPart < this.chunkParticipants.size(); iPart++) {
this.chunkParticipants.get(iPart).reset(null);
}
for (int iPart= 0; iPart < this.inlineParticipants.size(); iPart++) {
this.inlineParticipants.get(iPart).reset(null);
}
this.builder= null;
}
private void processEmbedded(final int toOffset) {
if (toOffset < this.lastOffset) {
return;
}
while (this.embeddedIterator.hasNext(toOffset)) {
final Embedded embedded= this.embeddedIterator.getNext();
if (embedded instanceof EmbeddedChunk) {
sendChunk((EmbeddedChunk) embedded);
}
else {
sendInline((EmbeddedInline) embedded);
}
this.lastOffset= embedded.getEndOffset();
this.embeddedIterator.consume();
}
}
private void sendChunk(final EmbeddedChunk chunk) {
final WeaveParticipant part= chunk.getParticipant();
this.orgLocator.setTo(chunk.getBeginOffset());
this.builder.beginBlock(BlockType.CODE, new EmbeddingAttributes(
part.getForeignTypeId(), chunk.getEmbedDescr(),
new BasicTextRegion(chunk.getOrgBeginOffset(), chunk.getOrgEndOffset()) ));
this.orgLocator.setShift(chunk.getShift());
this.orgLocator.setTo(chunk.getEndOffset());
this.builder.endBlock();
}
private void sendInline(final EmbeddedInline inline) {
if ((this.flags & MarkupParser2.INLINE_EMBEDDED) != 0) {
final WeaveParticipant part= inline.getParticipant();
this.orgLocator.setTo(inline.getBeginOffset(), inline.getEndOffset());
this.builder.beginSpan(SpanType.CODE, new EmbeddingAttributes(
part.getForeignTypeId(), inline.getEmbedDescr(),
new BasicTextRegion(inline.getContentBeginOffset(), inline.getContentEndOffset()) ));
this.orgLocator.setTo(inline.getEndOffset());
this.builder.endSpan();
}
}
private int getSegmentBeginOffset() {
return Math.min(
this.locator.getLineDocumentOffset() + this.locator.getLineCharacterOffset(),
this.maxOffset );
}
private int getSegmentEndOffset() {
return Math.min(
this.locator.getLineDocumentOffset() + this.locator.getLineSegmentEndOffset(),
this.maxOffset );
}
private LabelInfo updateOffsets(final LabelInfo labelInfo) {
if (labelInfo == null) {
return null;
}
return new LabelInfo(labelInfo.getLabel(),
this.orgLocator.computeOffset(labelInfo.getStartOffset()),
this.orgLocator.computeOffset(labelInfo.getEndOffset()) );
}
private ImList<TextRegion> updateOffsets(final List<? extends TextRegion> regions) {
if (regions == null) {
return null;
}
final EmbeddedChunkIterator embeddedIter= new EmbeddedChunkIterator(this.embeddedIterator);
int shift= this.orgLocator.shift;
int last= this.lastOffset;
final TextRegion[] updated= new TextRegion[regions.size()];
int i= 0;
ITER_REGIONS: for (final TextRegion region : regions) {
final int beginOffset;
final int endOffset;
{ int offset= region.getStartOffset();
while (embeddedIter.hasNext(offset)) {
shift= embeddedIter.getNext().getShift();
last= embeddedIter.getNext().getEndOffset();
embeddedIter.consume();
}
if (offset < last) {
offset= last;
}
beginOffset= shift + offset;
}
{ final int offset= region.getEndOffset();
if (embeddedIter.hasNext(offset)) {
continue ITER_REGIONS;
}
endOffset= shift + offset;
}
final int l= endOffset - beginOffset;
if (l > 0 || (l == 0 && region.getLength() == 0)) {
updated[i++]= new BasicTextRegion(beginOffset, endOffset);
}
}
return ImCollections.newList(updated, 0, i);
}
@Override
public void beginDocument() {
this.orgLocator.setTo(0);
this.builder.beginDocument();
}
@Override
public void endDocument() {
this.finished= true;
processEmbedded(Integer.MAX_VALUE);
final int endOffset= this.locator.getDocumentOffset();
this.lastOffset= endOffset;
this.orgLocator.setTo(endOffset);
this.builder.endDocument();
}
public void finish() {
if (!this.finished) {
this.finished= true;
processEmbedded(Integer.MAX_VALUE);
}
}
@Override
public void beginBlock(final BlockType type, final Attributes attributes) {
final int beginOffset= this.locator.getDocumentOffset();
processEmbedded(beginOffset);
if (beginOffset < this.lastOffset) {
this.ignoreCounter++;
return;
}
this.lastOffset= beginOffset;
this.orgLocator.setTo(beginOffset);
if (attributes instanceof SourceTextBlockAttributes) {
final SourceTextBlockAttributes textBlockAttributes= (SourceTextBlockAttributes) attributes;
textBlockAttributes.setTextRegions(updateOffsets(textBlockAttributes.getTextRegions()));
}
this.builder.beginBlock(type, attributes);
}
@Override
public void endBlock() {
if (this.ignoreCounter > 0) {
this.ignoreCounter--;
return;
}
final int endOffset= this.locator.getLineDocumentOffset();
if (DEBUGGING) {
if (endOffset > this.maxOffset) {
System.out.println("endOffset > source.length: " + endOffset);
}
if (endOffset < this.lastOffset) {
System.out.println("endOffset < lastOffset: " + endOffset);
}
}
processEmbedded(endOffset);
if (endOffset > this.lastOffset) {
this.lastOffset= endOffset;
}
this.orgLocator.setTo(this.lastOffset);
this.builder.endBlock();
}
@Override
public void beginSpan(final SpanType type, final Attributes attributes) {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
final int beginOffset= getSegmentBeginOffset();
final int endOffset= getSegmentEndOffset();
processEmbedded(beginOffset);
if (beginOffset < this.lastOffset) {
this.ignoreCounter++;
return;
}
if (++this.endSpanFixIdx >= this.endSpanFix.length) {
this.endSpanFix= Arrays.copyOf(this.endSpanFix, this.endSpanFix.length + 16);
}
this.endSpanFix[this.endSpanFixIdx]= endOffset;
this.lastOffset= beginOffset;
this.orgLocator.setTo(beginOffset, endOffset);
this.builder.beginSpan(type, attributes);
}
@Override
public void endSpan() {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
if (this.ignoreCounter > 0) {
this.ignoreCounter--;
return;
}
final int endOffset= Math.max(
getSegmentEndOffset(),
this.endSpanFix[this.endSpanFixIdx--] );
if (DEBUGGING) {
if (endOffset > this.maxOffset) {
System.out.println("endOffset > source.length: " + endOffset);
}
if (endOffset < this.lastOffset) {
System.out.println("endOffset < lastOffset: " + endOffset);
}
}
processEmbedded(endOffset);
if (endOffset > this.lastOffset) {
this.lastOffset= endOffset;
}
this.orgLocator.setTo(this.lastOffset);
this.builder.endSpan();
}
@Override
public void beginHeading(final int level, final Attributes attributes) {
final int beginOffset= this.locator.getDocumentOffset();
processEmbedded(beginOffset);
if (beginOffset < this.lastOffset) {
this.ignoreCounter++;
return;
}
this.lastOffset= beginOffset;
this.orgLocator.setTo(beginOffset);
this.builder.beginHeading(level, attributes);
}
@Override
public void endHeading() {
if (this.ignoreCounter > 0) {
this.ignoreCounter--;
return;
}
final int endOffset= this.locator.getLineDocumentOffset();
if (DEBUGGING) {
if (endOffset > this.maxOffset) {
System.out.println("endOffset > source.length: " + endOffset);
}
if (endOffset < this.lastOffset) {
System.out.println("endOffset < lastOffset: " + endOffset);
}
}
processEmbedded(endOffset);
if (endOffset > this.lastOffset) {
this.lastOffset= endOffset;
}
this.orgLocator.setTo(this.lastOffset);
this.builder.endHeading();
}
@Override
public void characters(final String text) {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
int offset= this.locator.getDocumentOffset();
int endOffset= getSegmentEndOffset();
int lastIdx= 0;
while (this.embeddedIterator.hasNext(endOffset)) {
final Embedded embedded= this.embeddedIterator.getNext();
final int textIdx= (lastIdx < text.length()) ? text.indexOf(WeaveParticipant.REPLACEMENT_CHAR, lastIdx) : -1;
if (textIdx < 0 || embedded.getTextLength() <= 0) {
endOffset= this.embeddedIterator.getNextOffset();
lastIdx= text.length();
break;
}
this.orgLocator.setTo(offset, embedded.getBeginOffset());
this.builder.characters(text.substring(lastIdx, textIdx));
lastIdx= textIdx + embedded.getTextLength();
if (embedded instanceof EmbeddedChunk) {
sendChunk((EmbeddedChunk) embedded);
}
else {
sendInline((EmbeddedInline) embedded);
}
this.lastOffset= offset= embedded.getEndOffset();
this.embeddedIterator.consume();
}
if (offset < endOffset && lastIdx < text.length()) {
this.lastOffset= endOffset;
this.orgLocator.setTo(offset, endOffset);
this.builder.characters(text.substring(lastIdx, text.length()));
}
}
@Override
public void entityReference(final String entity) {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
final int beginOffset= getSegmentBeginOffset();
final int endOffset= getSegmentEndOffset();
if (beginOffset >= endOffset) {
return;
}
processEmbedded(endOffset);
if (beginOffset > this.lastOffset) {
return;
}
this.orgLocator.setTo(beginOffset, endOffset);
this.builder.entityReference(entity);
}
@Override
public void image(final Attributes attributes, final String url) {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
final int beginOffset= getSegmentBeginOffset();
final int endOffset= getSegmentEndOffset();
if (beginOffset >= endOffset) {
return;
}
processEmbedded(endOffset);
if (beginOffset > this.lastOffset) {
return;
}
if (attributes instanceof ImageByRefAttributes) {
final ImageByRefAttributes refAttributes= (ImageByRefAttributes) attributes;
refAttributes.setReferenceLabel(updateOffsets((refAttributes).getReferenceLabel()));
}
this.orgLocator.setTo(beginOffset, endOffset);
this.builder.image(attributes, url);
}
@Override
public void link(final Attributes attributes, final String hrefOrHashName, final String text) {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
final int beginOffset= getSegmentBeginOffset();
final int endOffset= getSegmentEndOffset();
if (beginOffset >= endOffset) {
return;
}
processEmbedded(endOffset);
if (beginOffset < this.lastOffset) {
return;
// if (text.indexOf(REPLACEMENT_CHAR) >= 0) {
// text= replaceText(text, locator.getLineDocumentOffset() + locator.getLineCharacterOffset());
// }
}
if (attributes instanceof LinkRefDefinitionAttributes) {
final LinkRefDefinitionAttributes refAttributes= (LinkRefDefinitionAttributes) attributes;
refAttributes.setReferenceLabel(updateOffsets((refAttributes).getReferenceLabel()));
}
else if (attributes instanceof LinkByRefAttributes) {
final LinkByRefAttributes refAttributes= (LinkByRefAttributes) attributes;
refAttributes.setReferenceLabel(updateOffsets((refAttributes).getReferenceLabel()));
}
this.lastOffset= endOffset;
this.orgLocator.setTo(beginOffset, endOffset);
this.builder.link(attributes, hrefOrHashName, text);
}
@Override
public void imageLink(final Attributes linkAttributes, final Attributes imageAttributes,
final String href, final String imageUrl) {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
final int beginOffset= getSegmentBeginOffset();
final int endOffset= getSegmentEndOffset();
if (beginOffset >= endOffset) {
return;
}
processEmbedded(endOffset);
if (beginOffset < this.lastOffset) {
return;
}
this.lastOffset= endOffset;
this.orgLocator.setTo(beginOffset, endOffset);
this.builder.imageLink(linkAttributes, imageAttributes, href, imageUrl);
}
@Override
public void acronym(final String text, final String definition) {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
final int beginOffset= getSegmentBeginOffset();
final int endOffset= getSegmentEndOffset();
if (beginOffset >= endOffset) {
return;
}
processEmbedded(endOffset);
if (beginOffset < this.lastOffset) {
return;
}
this.lastOffset= endOffset;
this.orgLocator.setTo(beginOffset, endOffset);
this.builder.acronym(text, definition);
}
@Override
public void lineBreak() {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
final int beginOffset= this.locator.getDocumentOffset();
this.orgLocator.setTo(beginOffset);
this.builder.lineBreak();
}
@Override
public void charactersUnescaped(final String literal) {
if ((this.flags & MarkupParser2.INLINE_MARKUP) == 0) {
return;
}
final int beginOffset= getSegmentBeginOffset();
final int endOffset= getSegmentEndOffset();
if (beginOffset >= endOffset) {
return;
}
processEmbedded(endOffset);
if (beginOffset < this.lastOffset) {
return;
}
this.lastOffset= endOffset;
this.orgLocator.setTo(beginOffset, endOffset);
this.builder.charactersUnescaped(literal);
}
}