/*=============================================================================#
# 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;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.mylyn.wikitext.core.parser.DocumentBuilder;
import de.walware.jcommons.collections.ImCollections;
import de.walware.jcommons.collections.ImList;
public class SourceBlocks {
private static interface ItemRunnable {
void run(SourceBlockItem<?> blockItem);
}
public class SourceBlockBuilder {
private SourceBlockItem<?> currentItem;
private SourceBlockBuilder() {
}
void setCurrentItem(final SourceBlockItem<?> blockItem) {
this.currentItem= blockItem;
}
public SourceBlockItem<?> getCurrentItem() {
return this.currentItem;
}
public SourceBlocks getSourceBlocks() {
return SourceBlocks.this;
}
public void createNestedItems(final LineSequence lineSequence,
final ImList<? extends SourceBlock> supportedBlocks) {
processItems(lineSequence, this,
(supportedBlocks != null) ? supportedBlocks : getSourceBlocks().supportedBlocks,
new ItemRunnable() {
@Override
public void run(final SourceBlockItem<?> blockItem) {
}
} );
}
}
private static class CollectLineSequence extends LineSequence {
private final LineSequence delegate;
private Line currentLine;
private final List<Line> lines= new ArrayList<>();
public CollectLineSequence(final LineSequence delegate) {
this.delegate= delegate;
}
@Override
public LineSequence lookAhead() {
return this.delegate.lookAhead();
}
@Override
public LineSequence lookAhead(final int lineNumber) {
return this.delegate.lookAhead(lineNumber);
}
@Override
public Line getCurrentLine() {
return this.currentLine= this.delegate.getCurrentLine();
}
@Override
public Line getNextLine() {
return this.delegate.getNextLine();
}
@Override
public void advance() {
Line line= this.currentLine;
if (line == null) {
line= this.delegate.getCurrentLine();
}
else {
this.currentLine= null;
}
this.delegate.advance();
this.lines.add(line);
}
public ImList<Line> getLines() {
return ImCollections.toList(this.lines);
}
public void initLines() {
this.lines.clear();
}
}
private final ImList<SourceBlock> supportedBlocks;
public SourceBlocks(final SourceBlock... blocks) {
this(ImCollections.newList(blocks));
}
public SourceBlocks(final List<SourceBlock> supportedBlocks) {
this.supportedBlocks= ImCollections.toList(supportedBlocks);
}
public List<SourceBlockItem<?>> createItems(final LineSequence lineSequence) {
final List<SourceBlockItem<?>> items= new ArrayList<>();
final SourceBlockBuilder sourceBlockBuilder= new SourceBlockBuilder();
processItems(lineSequence, sourceBlockBuilder, this.supportedBlocks,
new ItemRunnable() {
@Override
public void run(final SourceBlockItem<?> blockItem) {
items.add(blockItem);
}
} );
return items;
}
public void parseSourceStruct(final ProcessingContext context, final LineSequence lineSequence,
final DocumentBuilder builder) {
context.setMode(ProcessingContext.PARSE_SOURCE_STRUCT);
final SourceBlockBuilder sourceBlockBuilder= new SourceBlockBuilder();
final CommonmarkLocator locator= new CommonmarkLocator();
builder.setLocator(locator);
processItems(lineSequence, sourceBlockBuilder, this.supportedBlocks,
new ItemRunnable() {
@Override
public void run(final SourceBlockItem<?> blockItem) {
blockItem.getType().emit(context, blockItem, locator, builder);
}
} );
}
private void processItems(final LineSequence lineSequence, final SourceBlockBuilder builder,
final ImList<? extends SourceBlock> supportedBlocks,
final ItemRunnable runnable) {
final CollectLineSequence collectLineSequence= new CollectLineSequence(lineSequence);
final SourceBlockItem<?> parentItem= builder.getCurrentItem();
while (collectLineSequence.getCurrentLine() != null) {
final SourceBlock block= selectBlock(collectLineSequence, supportedBlocks, null);
if (block != null) {
collectLineSequence.initLines();
block.createItem(builder, collectLineSequence);
final SourceBlockItem<?> blockItem= builder.getCurrentItem();
blockItem.setLines(collectLineSequence.getLines());
builder.setCurrentItem(parentItem);
runnable.run(blockItem);
}
else {
return;
}
}
}
public void initializeContext(final ProcessingContext context, final List<SourceBlockItem<?>> items) {
context.setMode(ProcessingContext.INITIALIZE_CONTEXT);
for (final SourceBlockItem<?> item : items) {
item.getType().initializeContext(context, item);
}
}
public void emit(final ProcessingContext context, final List<SourceBlockItem<?>> items,
final DocumentBuilder builder) {
context.setMode(ProcessingContext.EMIT_DOCUMENT);
final CommonmarkLocator locator= new CommonmarkLocator();
builder.setLocator(locator);
for (final SourceBlockItem<?> item : items) {
item.getType().emit(context, item, locator, builder);
}
}
public SourceBlock selectBlock(final LineSequence lineSequence,
final SourceBlockItem<?> currentBlockItem) {
return selectBlock(lineSequence, this.supportedBlocks, currentBlockItem);
}
public SourceBlock selectBlock(final LineSequence lineSequence) {
return selectBlock(lineSequence, this.supportedBlocks, null);
}
public SourceBlock selectBlock(final LineSequence lineSequence,
final ImList<? extends SourceBlock> supportedBlocks,
final SourceBlockItem<?> currentBlockItem) {
for (final SourceBlock candidate : supportedBlocks) {
if (candidate.canStart(lineSequence, currentBlockItem)) {
return candidate;
}
}
return null;
}
}