/*=============================================================================#
# Copyright (c) 2015-2016 Stephan Wahlbrink (WalWare.de) 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:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.docmlet.wikitext.internal.commonmark.core.source;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import de.walware.ecommons.text.IndentUtil;
import de.walware.docmlet.wikitext.core.ast.Block;
import de.walware.docmlet.wikitext.core.ast.WikitextAstNode;
import de.walware.docmlet.wikitext.core.source.IMarkupSourceFormatAdapter;
import de.walware.docmlet.wikitext.internal.commonmark.core.Line;
import de.walware.docmlet.wikitext.internal.commonmark.core.blocks.BlockQuoteBlock;
import de.walware.docmlet.wikitext.internal.commonmark.core.blocks.ListBlock;
public class CommonmarkSourceFormatAdapter implements IMarkupSourceFormatAdapter {
private final Matcher quoteMatcher= BlockQuoteBlock.PATTERN.matcher(""); //$NON-NLS-1$
private final Matcher listItemMatcher= ListBlock.PATTERN.matcher(""); //$NON-NLS-1$
private final StringBuilder indentBuilder= new StringBuilder();
public CommonmarkSourceFormatAdapter() {
}
@Override
public String getPrefixCont(WikitextAstNode node,
final IndentUtil indentUtil) throws Exception {
if (indentUtil.getTabWidth() != 4) {
return null;
}
final List<Block> blocks= new ArrayList<>(8);
ITER_NODE: for (; node != null; node= node.getWikitextParent()) {
switch (node.getNodeType()) {
case SOURCELINES:
if (node.getParent() == null) {
break ITER_NODE;
}
return null;
case BLOCK:
switch (((Block) node).getBlockType()) {
case BULLETED_LIST:
case NUMERIC_LIST:
continue ITER_NODE;
case PARAGRAPH:
case QUOTE:
case LIST_ITEM:
blocks.add((Block) node);
continue ITER_NODE;
default:
break;
}
return null;
default:
return null;
}
}
switch (blocks.size()) {
case 0:
return null;
case 1:
break;
default:
Collections.reverse(blocks);
break;
}
return createIndent(blocks, indentUtil);
}
private String createIndent(final List<Block> blocks,
final IndentUtil indentUtil) throws Exception {
this.indentBuilder.setLength(0);
int column= 0;
for (final Block block : blocks) {
final Line nodeLine;
final Matcher matcher;
switch (block.getBlockType()) {
case PARAGRAPH:
break;
case QUOTE:
nodeLine= createLine(indentUtil, block.getOffset());
matcher= nodeLine.setupIndent(this.quoteMatcher);
if (!matcher.matches()) {
return null;
}
indentUtil.appendIndent(this.indentBuilder, column,
column= nodeLine.getIndent() );
this.indentBuilder.append("> "); //$NON-NLS-1$
break;
case LIST_ITEM:
nodeLine= createLine(indentUtil, block.getOffset());
matcher= nodeLine.setupIndent(this.listItemMatcher);
if (!matcher.matches()) {
return null;
}
indentUtil.appendIndent(this.indentBuilder, column,
column= ListBlock.computeItemLineIndent(nodeLine, matcher) );
break;
default:
assert (false);
}
}
return this.indentBuilder.toString();
}
private Line createLine(final IndentUtil indentUtil, final int offset)
throws BadLocationException {
final IDocument doc= indentUtil.getDocument();
final int lineNum= doc.getLineOfOffset(offset);
final IRegion lineInfo= doc.getLineInformation(lineNum);
return new Line(lineNum, offset, indentUtil.getColumn(lineNum, offset),
doc.get(offset, lineInfo.getOffset() + lineInfo.getLength() - offset), "\n"); //$NON-NLS-1$
}
}