blob: 56248d0a0e78836b0577e6bde0f31577f0624918 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 David Green.
* 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
*******************************************************************************/
package org.eclipse.mylyn.internal.wikitext.commonmark.inlines;
import java.util.List;
import org.eclipse.mylyn.internal.wikitext.commonmark.Line;
import org.eclipse.mylyn.wikitext.core.parser.DocumentBuilder;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
class PotentialEmphasisDelimiter extends InlineWithText {
private final boolean canOpen;
private final boolean canClose;
public PotentialEmphasisDelimiter(Line line, int offset, int length, String text, boolean canOpen, boolean canClose) {
super(line, offset, length, text);
this.canOpen = canOpen;
this.canClose = canClose;
}
@Override
public void emit(DocumentBuilder builder) {
builder.characters(text);
}
@Override
Optional<InlinesSubstitution> secondPass(List<Inline> inlines) {
if (!canClose) {
return Optional.absent();
}
int indexOfThis = inlines.indexOf(this);
Optional<PotentialEmphasisDelimiter> opener = previousOpener(inlines, indexOfThis);
if (opener.isPresent()) {
PotentialEmphasisDelimiter openingDelimiter = opener.get();
int delimiterSize = delimiterSize(openingDelimiter);
int indexOfOpeningDelimiter = inlines.indexOf(openingDelimiter);
List<Inline> contents = InlineParser.secondPass(inlines.subList(indexOfOpeningDelimiter + 1, indexOfThis));
int spanOffset = openingDelimiter.getOffset();
int spanLength = getOffset() + getLength() - openingDelimiter.getOffset();
Inline emphasis = createEmphasis(openingDelimiter.getLine(), spanOffset, spanLength, delimiterSize,
contents);
ImmutableList.Builder<Inline> substitutionInlines = ImmutableList.builder();
if (delimiterSize < openingDelimiter.getLength()) {
substitutionInlines.add(createPotentialOpeningDelimiter(openingDelimiter, delimiterSize));
}
substitutionInlines.add(emphasis);
if (delimiterSize < getLength()) {
substitutionInlines.add(createPotentialClosingDelimiter(delimiterSize));
}
return Optional.of(new InlinesSubstitution(openingDelimiter, this, substitutionInlines.build()));
}
return Optional.absent();
}
private Inline createPotentialClosingDelimiter(int delimiterSize) {
return new PotentialEmphasisDelimiter(getLine(), getOffset() + delimiterSize, getLength() - delimiterSize,
getText().substring(0 + delimiterSize, getText().length()), canOpen, canClose);
}
private Inline createEmphasis(Line line, int offset, int length, int delimiterSize, List<Inline> contents) {
if (delimiterSize == 1) {
return new Emphasis(line, offset, length, contents);
}
return new Strong(line, offset, length, contents);
}
private PotentialEmphasisDelimiter createPotentialOpeningDelimiter(PotentialEmphasisDelimiter openingDelimiter,
int consumedSize) {
return new PotentialEmphasisDelimiter(openingDelimiter.getLine(), openingDelimiter.getOffset(),
openingDelimiter.getLength() - consumedSize, openingDelimiter.getText().substring(0,
openingDelimiter.getText().length() - consumedSize), openingDelimiter.canOpen,
openingDelimiter.canClose);
}
private int delimiterSize(PotentialEmphasisDelimiter openingDelimiter) {
int openingLength = openingDelimiter.getLength();
if (openingLength < 3 || getLength() < 3) {
return openingLength > getLength() ? getLength() : openingLength;
}
return getLength() % 2 == 0 ? 2 : 1;
}
private Optional<PotentialEmphasisDelimiter> previousOpener(List<Inline> inlines, int indexOfThis) {
char c = getText().charAt(0);
for (int index = indexOfThis - 1; index >= 0; --index) {
Inline inline = inlines.get(index);
if (inline instanceof PotentialEmphasisDelimiter) {
PotentialEmphasisDelimiter previousDelimiter = (PotentialEmphasisDelimiter) inline;
if (previousDelimiter.canOpen && previousDelimiter.getText().charAt(0) == c) {
return Optional.of(previousDelimiter);
}
}
}
return Optional.absent();
}
}