blob: 3d4bff28907f70f9ad1d57b30bcd5861a7036227 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 David Green 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:
* David Green - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.wikitext.textile.internal.block;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.mylyn.wikitext.parser.Attributes;
import org.eclipse.mylyn.wikitext.parser.DocumentBuilder.BlockType;
import org.eclipse.mylyn.wikitext.parser.ListAttributes;
import org.eclipse.mylyn.wikitext.parser.markup.Block;
public class DefinitionListBlock extends Block {
private static final Pattern START_PATTERN = Pattern.compile("(?:(;\\s+(.+))|(-\\s+(.+?)\\s*(:=)\\s*((.+?)\\s*(=:)?)?))"); //$NON-NLS-1$
private static final Pattern END_ITEM_PATTERN = Pattern.compile("(.*?)\\s*(=:)\\s*"); //$NON-NLS-1$
private static final Pattern COLON_START_PATTERN = Pattern.compile(":\\s+(.+)"); //$NON-NLS-1$
private Matcher matcher;
private int blockLineCount;
private int levelsOpen = 0;
private int linesThisItem = 0;
@Override
protected int processLineContent(String line, int offset) {
++blockLineCount;
if (blockLineCount == 1) {
beginBlock(BlockType.DEFINITION_LIST, new ListAttributes());
handleStartTerm();
return -1;
} else {
matcher = START_PATTERN.matcher(line);
if (matcher.matches()) {
closeItems();
handleStartTerm();
return -1;
} else {
String content = line;
int contentOffset = 0;
boolean closeThisLine = false;
if (levelsOpen < 2) {
Matcher ddMatcher = COLON_START_PATTERN.matcher(line);
if (ddMatcher.matches()) {
content = ddMatcher.group(1);
contentOffset = ddMatcher.start(1);
closeItems();
beginBlock(BlockType.DEFINITION_ITEM, new Attributes());
linesThisItem = 0;
closeThisLine = true;
} else {
setClosed(true);
return 0;
}
} else {
// continuation of list item. blank line is termination
if (markupLanguage.isEmptyLine(line)) {
setClosed(true);
return 0;
}
Matcher endMatcher = END_ITEM_PATTERN.matcher(line);
if (endMatcher.matches()) {
content = endMatcher.group(1);
}
}
if (markupLanguage.isEmptyLine(content)) {
closeItems();
return -1;
}
if (++linesThisItem > 1) {
builder.lineBreak();
}
markupLanguage.emitMarkupLine(getParser(), state, contentOffset, content, offset);
if (closeThisLine) {
endBlock();
}
}
}
return -1;
}
protected void handleStartTerm() {
linesThisItem = 0;
int textLineOffset;
String term = matcher.group(2);
String definition = null;
int definitionOffset = 0;
int definitionSegmentOffset = 0;
boolean definitionEnd = false;
if (term == null) {
term = matcher.group(4);
textLineOffset = matcher.start(4);
definition = matcher.group(7);
definitionOffset = matcher.start(7);
definitionEnd = matcher.group(8) != null;
definitionSegmentOffset = matcher.start(5);
state.setLineSegmentEndOffset(definitionSegmentOffset);
} else {
textLineOffset = matcher.start(2);
}
beginBlock(BlockType.DEFINITION_TERM, new Attributes());
markupLanguage.emitMarkupLine(getParser(), state, textLineOffset, term, 0);
endBlock();
if (definition != null) {
// since it's a mid-line block, we must set the offsets here
state.setLineCharacterOffset(definitionSegmentOffset);
beginBlock(BlockType.DEFINITION_ITEM, new Attributes());
markupLanguage.emitMarkupLine(getParser(), state, definitionOffset, definition, 0);
if (definitionEnd) {
endBlock();
} else {
linesThisItem = 1;
}
}
}
private void closeItems() {
while (levelsOpen > 1) {
endBlock();
}
}
public void beginBlock(BlockType type, Attributes attributes) {
++levelsOpen;
builder.beginBlock(type, attributes);
}
public void endBlock() {
--levelsOpen;
builder.endBlock();
}
@Override
public void setClosed(boolean closed) {
if (closed && !isClosed()) {
while (levelsOpen > 0) {
endBlock();
}
}
super.setClosed(closed);
}
@Override
public boolean canStart(String line, int lineOffset) {
blockLineCount = 0;
matcher = START_PATTERN.matcher(line);
if (lineOffset > 0) {
matcher.region(lineOffset, line.length());
}
if (matcher.matches()) {
return true;
}
matcher = null;
return false;
}
}