/*=============================================================================# # 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.commonmark.core; import java.io.StringWriter; import java.util.List; import java.util.Objects; import org.eclipse.core.runtime.Platform; import org.eclipse.mylyn.wikitext.core.parser.DocumentBuilder; import org.eclipse.mylyn.wikitext.core.parser.IdGenerator; import org.eclipse.mylyn.wikitext.core.parser.MarkupParser; import org.eclipse.mylyn.wikitext.core.parser.builder.MultiplexingDocumentBuilder; import org.eclipse.mylyn.wikitext.core.parser.markup.IdGenerationStrategy; import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage; import de.walware.ecommons.ltk.core.SourceContent; import de.walware.docmlet.wikitext.core.WikitextProblemReporter; import de.walware.docmlet.wikitext.core.markup.IMarkupConfig; import de.walware.docmlet.wikitext.core.markup.IMarkupLanguage; import de.walware.docmlet.wikitext.core.markup.IMarkupLanguageExtension2; import de.walware.docmlet.wikitext.core.markup.MarkupParser2; import de.walware.docmlet.wikitext.core.source.IMarkupSourceFormatAdapter; import de.walware.docmlet.wikitext.core.source.MarkupEventPrinter; import de.walware.docmlet.wikitext.core.source.extdoc.IExtdocMarkupLanguage; import de.walware.docmlet.wikitext.internal.commonmark.core.Commonmark; import de.walware.docmlet.wikitext.internal.commonmark.core.CommonmarkIdGenerationStrategy; import de.walware.docmlet.wikitext.internal.commonmark.core.ContentLineSequence; import de.walware.docmlet.wikitext.internal.commonmark.core.LineSequence; import de.walware.docmlet.wikitext.internal.commonmark.core.NullIdGenerator; import de.walware.docmlet.wikitext.internal.commonmark.core.ProcessingContext; import de.walware.docmlet.wikitext.internal.commonmark.core.SourceBlockItem; import de.walware.docmlet.wikitext.internal.commonmark.core.SourceBlocks; import de.walware.docmlet.wikitext.internal.commonmark.core.inlines.InlineParser; import de.walware.docmlet.wikitext.internal.commonmark.core.source.CommonmarkSourceFormatAdapter; public class CommonmarkLanguage extends MarkupLanguage implements IMarkupLanguage, IMarkupLanguageExtension2, IExtdocMarkupLanguage { protected static final String COMMONMARK_LANGUAGE_NAME= "CommonMark\u2002[StatET]"; //$NON-NLS-1$ public static final int MARKDOWN_COMPAT_MODE= 1 << 16; private static final boolean DEBUG_LOG_EVENTS= Boolean.parseBoolean( Platform.getDebugOption("de.walware.docmlet.wikitext.commonmark/debug/Parser/logEvents") ); //$NON-NLS-1$ private /*final*/ String scope; private /*final*/ int mode; private ICommonmarkConfig config; private SourceBlocks sourceBlocks; private InlineParser inlineParser; public CommonmarkLanguage() { this(null, 0, null); } public CommonmarkLanguage(final String scope, final int mode, final IMarkupConfig config) { this.scope= scope; this.mode= mode; setName(COMMONMARK_LANGUAGE_NAME); setMarkupConfig(config); } @Override public CommonmarkLanguage clone() { final CommonmarkLanguage clone= (CommonmarkLanguage) super.clone(); clone.mode = this.mode; clone.config= this.config; return clone; } @Override public CommonmarkLanguage clone(final String scope, final int mode) { final CommonmarkLanguage clone= (CommonmarkLanguage) super.clone(); clone.scope= scope; clone.mode= mode; clone.config= this.config; return clone; } @Override public String getScope() { return this.scope; } @Override public int getMode() { return this.mode; } @Override public boolean isModeEnabled(final int modeMask) { return ((this.mode & modeMask) != 0); } @Override public void setMarkupConfig(final IMarkupConfig config) { if (config != null) { config.seal(); } if (this.config != config) { this.config= (ICommonmarkConfig) config; this.sourceBlocks= null; this.inlineParser= null; } } @Override public ICommonmarkConfig getMarkupConfig() { return this.config; } @Override public void processContent(final MarkupParser2 parser, final SourceContent content, final boolean asDocument) { if (parser == null) { throw new NullPointerException("parser"); //$NON-NLS-1$ } if (content == null) { throw new NullPointerException("content"); //$NON-NLS-1$ } if (parser.getBuilder() == null) { throw new NullPointerException("parser.builder"); //$NON-NLS-1$ } if (DEBUG_LOG_EVENTS) { final StringWriter out= new StringWriter(); try { final MarkupEventPrinter printer= new MarkupEventPrinter(content.getText(), this, out); final MarkupParser2 debugParser= new MarkupParser2(this, new MultiplexingDocumentBuilder(printer, parser.getBuilder()), parser.getFlags() ); doProcessContent(debugParser, content, asDocument); System.out.println(out.toString()); } catch (final Exception e) { System.out.println(out.toString()); e.printStackTrace(); } } else { doProcessContent(parser, content, asDocument); } } protected void doProcessContent(final MarkupParser2 parser, final SourceContent content, final boolean asDocument) { final DocumentBuilder builder= parser.getBuilder(); final LineSequence lineSequence= new ContentLineSequence(content.getText(), content.getLines()); final ProcessingContext context= createContext(); if (asDocument) { builder.beginDocument(); } if (parser.isEnabled(MarkupParser2.SOURCE_STRUCT)) { context.getSourceBlocks().parseSourceStruct(context, lineSequence, builder); } else { final List<SourceBlockItem<?>> items= context.getSourceBlocks().createItems(lineSequence); context.getSourceBlocks().initializeContext(context, items); context.getSourceBlocks().emit(context, items, builder); } if (asDocument) { builder.endDocument(); } } @Override public void processContent(final MarkupParser parser, final String markupContent, final boolean asDocument) { processContent(new MarkupParser2(parser), new SourceContent(0, markupContent), asDocument); } private WikitextProblemReporter validator; @Override public WikitextProblemReporter getProblemReporter() { if (this.validator == null) { this.validator= new WikitextProblemReporter(); } return this.validator; } private CommonmarkSourceFormatAdapter sourceAdapter; @Override public IMarkupSourceFormatAdapter getSourceFormatAdapter() { if (this.sourceAdapter == null) { this.sourceAdapter= new CommonmarkSourceFormatAdapter(); } return this.sourceAdapter; } @Override public IdGenerationStrategy getIdGenerationStrategy() { return ((this.mode & MYLYN_COMPAT_MODE) != 0) ? new CommonmarkIdGenerationStrategy() : null; } private IdGenerator createIdGenerator() { final IdGenerationStrategy idGenerationStrategy= getIdGenerationStrategy(); if (idGenerationStrategy != null) { final IdGenerator generator= new IdGenerator(); generator.setGenerationStrategy(idGenerationStrategy); return generator; } return new NullIdGenerator(); } private ProcessingContext createContext() { SourceBlocks sourceBlocks= this.sourceBlocks; if (sourceBlocks == null) { sourceBlocks= Commonmark.newSourceBlocks(this.config); this.sourceBlocks= sourceBlocks; } InlineParser inlineParser= this.inlineParser; if (inlineParser == null) { inlineParser= ((this.mode & MARKDOWN_COMPAT_MODE) != 0) ? Commonmark.newInlineParserMarkdown() : Commonmark.newInlineParserCommonMark(this.config); this.inlineParser= inlineParser; } final ProcessingContext context= new ProcessingContext(sourceBlocks, inlineParser, createIdGenerator(), ProcessingContext.INITIALIZE_CONTEXT ); return context; } @Override public int hashCode() { return getName().hashCode() + this.mode; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null || obj.getClass() != getClass()) { return false; } final CommonmarkLanguage other= (CommonmarkLanguage) obj; return (getName().equals(other.getName()) && this.mode == other.mode && Objects.equals(this.config, other.getMarkupConfig()) ); } }