blob: a8fd24204dd32a72bba48865da0b45c9a01d071a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 Max Rydahl and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Stefan Seelmann - initial API and implementation
* Max Rydahl Andersen - copied from markdown to get base for asciidoc
*******************************************************************************/
package org.eclipse.mylyn.wikitext.asciidoc.internal.block;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.mylyn.wikitext.asciidoc.internal.AsciiDocContentState;
import org.eclipse.mylyn.wikitext.asciidoc.internal.util.LanguageSupport;
import org.eclipse.mylyn.wikitext.asciidoc.internal.util.LookAheadReader;
import org.eclipse.mylyn.wikitext.asciidoc.internal.util.ReadAheadBlock;
import org.eclipse.mylyn.wikitext.parser.HeadingAttributes;
import org.eclipse.mylyn.wikitext.parser.markup.Block;
/**
* AsciiDoc setext underlined headings.
*
* @author Stefan Seelmann
* @author Max Rydahl Andersen
*/
public class UnderlinedHeadingBlock extends Block implements ReadAheadBlock {
private static final Pattern h1pattern = Pattern.compile("(=+)\\s*"); //$NON-NLS-1$
private static final Pattern h2pattern = Pattern.compile("(-+)\\s*"); //$NON-NLS-1$
private static final Pattern h3pattern = Pattern.compile("(~+)\\s*"); //$NON-NLS-1$
private static final Pattern h4pattern = Pattern.compile("(\\^+)\\s*"); //$NON-NLS-1$
private static final Pattern h5pattern = Pattern.compile("(\\++)\\s*"); //$NON-NLS-1$
private int blockLineCount;
private int lineLevel;
public boolean canStart(String line, int lineOffset, LookAheadReader lookAheadReader) {
blockLineCount = 0;
lineLevel = 0;
String nextLine = lookAheadReader.lookAhead();
if (nextLine == null) {
return false;
} else {
int expectedLength = line.trim().length() - lineOffset;
if (checkNextLine(expectedLength, nextLine, h1pattern, 1)) {
return true;
} else if (checkNextLine(expectedLength, nextLine, h2pattern, 2)) {
return true;
} else if (checkNextLine(expectedLength, nextLine, h3pattern, 3)) {
return true;
} else if (checkNextLine(expectedLength, nextLine, h4pattern, 4)) {
return true;
} else if (checkNextLine(expectedLength, nextLine, h5pattern, 5)) {
return true;
}
return false;
}
}
/**
* The next line should be a sequence of same chars. The nextLine length (nextineLength) should: nextlineLength - 1
* <= titleLength <= nextlineLength + 1
*
* @param length
* length of the current line (title)
* @param nextLine
* next line in the document
* @param pattern
* regular expression in a Pattern to match a line of chars in the next line
* @param level
* level that is set if the next line matches
* @return
*/
private boolean checkNextLine(int length, String nextLine, Pattern pattern, int level) {
Matcher matcher = pattern.matcher(nextLine);
if (matcher.matches()) {
int lineLength = matcher.group(1).length();
if ((lineLength > length - 2) && (lineLength < length + 2)) {
lineLevel = level;
return true;
}
}
return false;
}
@Override
public boolean canStart(String line, int lineOffset) {
String message = "Read-ahead required, call canStart(String, int, LookAheadReader) instead."; //$NON-NLS-1$
throw new UnsupportedOperationException(message);
}
@Override
public int processLineContent(String line, int offset) {
if (blockLineCount == 0) {
HeadingAttributes attributes = new HeadingAttributes();
attributes.setId(state.getIdGenerator().newId(null, line));
int level = LanguageSupport.computeHeadingLevel(lineLevel, getAsciiDocState());
builder.beginHeading(level, attributes);
builder.characters(line.trim());
} else {
builder.endHeading();
setClosed(true);
}
blockLineCount++;
return -1;
}
protected AsciiDocContentState getAsciiDocState() {
return (AsciiDocContentState) state;
}
}