blob: 32924eb881d16ad590aaeeb190a92a04af1be461 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2014, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.redocs.wikitext.r.textile.core;
import java.io.StringWriter;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.Platform;
import org.eclipse.mylyn.wikitext.parser.MarkupParser;
import org.eclipse.mylyn.wikitext.parser.builder.MultiplexingDocumentBuilder;
import org.eclipse.mylyn.wikitext.parser.markup.Block;
import org.eclipse.mylyn.wikitext.textile.TextileLanguage;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.docmlet.wikitext.core.WikitextProblemReporter;
import org.eclipse.statet.docmlet.wikitext.core.markup.MarkupConfig;
import org.eclipse.statet.docmlet.wikitext.core.markup.MarkupParser2;
import org.eclipse.statet.docmlet.wikitext.core.source.MarkupEventPrinter;
import org.eclipse.statet.docmlet.wikitext.core.source.MarkupSourceFormatAdapter;
import org.eclipse.statet.docmlet.wikitext.core.source.RegexBlockWeaveParticipant;
import org.eclipse.statet.docmlet.wikitext.core.source.RegexInlineWeaveParticipant;
import org.eclipse.statet.docmlet.wikitext.core.source.WeaveLanguageProcessor;
import org.eclipse.statet.docmlet.wikitext.core.source.extdoc.ExtdocMarkupLanguage;
import org.eclipse.statet.docmlet.wikitext.core.source.extdoc.TexMathDollarsDisplayWeaveParticipant;
import org.eclipse.statet.docmlet.wikitext.core.source.extdoc.TexMathDollarsInlineWeaveParticipant;
import org.eclipse.statet.docmlet.wikitext.core.source.extdoc.TexMathSBackslashDisplayWeaveParticipant;
import org.eclipse.statet.docmlet.wikitext.core.source.extdoc.TexMathSBackslashInlineWeaveParticipant;
import org.eclipse.statet.docmlet.wikitext.core.source.extdoc.YamlBlockWeaveParticipant;
import org.eclipse.statet.ltk.core.SourceContent;
import org.eclipse.statet.redocs.r.core.source.AbstractRChunkPartitionNodeScanner;
import org.eclipse.statet.redocs.wikitext.r.core.source.RweaveMarkupLanguage;
import org.eclipse.statet.redocs.wikitext.r.textile.core.RTextileConfig;
public class RTextileLanguage extends TextileLanguage
implements ExtdocMarkupLanguage, RweaveMarkupLanguage {
public static final String TEXTILE_LANGUAGE_NAME= "Textile"; //$NON-NLS-1$
public static final String TEXTILE_RWEAVE_LANGUAGE_NAME= "Textile+R"; //$NON-NLS-1$
private static final boolean DEBUG_LOG_BASE_EVENTS= Boolean.parseBoolean(
Platform.getDebugOption("org.eclipse.statet.redocs.wikitext.r.textile/debug/Parser/logBaseEvents") ); //$NON-NLS-1$
private static final ImList<String> INDENT_PREFIXES= ImCollections.emptyList();
private static final Pattern CHUNK_START_LINE_PATTERN= Pattern.compile("\\A###\\.[ \\t]++(?:begin\\.rcode)(.*+)\\p{all}*\\z"); //$NON-NLS-1$
private static final Pattern CHUNK_REF_LINE_PATTERN= Pattern.compile("\\A[ \\t]*<<(.*?)(?:>>)?+\\p{all}*\\z"); //$NON-NLS-1$
private static final Pattern CHUNK_END_LINE_PATTERN= Pattern.compile("\\A###\\.[ \\t]++(?:end\\.rcode)\\p{all}*\\z"); //$NON-NLS-1$
private static final Pattern INLINE_PATTERN= Pattern.compile("@r ([^@]+)@"); //$NON-NLS-1$
private /*final*/ String scope;
private /*final*/ int mode;
private RTextileConfig config;
private RTextileConfig configuredConfig;
private WeaveLanguageProcessor weaveProcessor;
public RTextileLanguage() {
this(null, 0, null);
}
public RTextileLanguage(final String scope, final int mode, final RTextileConfig config) {
super();
assert (TEXTILE_LANGUAGE_NAME.equals(getName()));
setName(TEXTILE_RWEAVE_LANGUAGE_NAME);
setExtendsLanguage(TEXTILE_LANGUAGE_NAME);
this.scope= scope;
this.mode= mode;
setMarkupConfig(config);
}
@Override
public RTextileLanguage clone() {
final RTextileLanguage clone= (RTextileLanguage) super.clone();
clone.mode= this.mode;
clone.config= this.config;
return clone;
}
@Override
public RTextileLanguage clone(final String scope, final int mode) {
final RTextileLanguage clone= (RTextileLanguage) 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 MarkupConfig config) {
if (config != null) {
config.seal();
}
this.config= (RTextileConfig) config;
}
@Override
public RTextileConfig getMarkupConfig() {
return this.config;
}
@Override
protected void addPhraseModifierExtensions(final PatternBasedSyntax phraseModifierSyntax) {
super.addPhraseModifierExtensions(phraseModifierSyntax);
}
@Override
protected void addBlockExtensions(final List<Block> blocks, final List<Block> paragraphBreakingBlocks) {
super.addBlockExtensions(blocks, paragraphBreakingBlocks);
}
protected void configure(final WeaveLanguageProcessor weaveProcessor,
final RTextileConfig config) {
weaveProcessor.addChunkParticipant(new RegexBlockWeaveParticipant(
EMBEDDED_R, EMBEDDED_R_CHUNK_DESCR,
CHUNK_START_LINE_PATTERN, CHUNK_END_LINE_PATTERN ));
weaveProcessor.addInlineParticipants(new RegexInlineWeaveParticipant(
EMBEDDED_R, EMBEDDED_R_INLINE_DESCR,
INLINE_PATTERN ));
if (config != null) {
if (config.isYamlMetadataEnabled()) {
weaveProcessor.addChunkParticipant(new YamlBlockWeaveParticipant());
}
if (config.isTexMathDollarsEnabled()) {
weaveProcessor.addInlineParticipants(new TexMathDollarsDisplayWeaveParticipant(
isModeEnabled(TEMPLATE_MODE) ));
weaveProcessor.addInlineParticipants(new TexMathDollarsInlineWeaveParticipant(
isModeEnabled(TEMPLATE_MODE) ));
}
if (config.isTexMathSBackslashEnabled()) {
weaveProcessor.addInlineParticipants(new TexMathSBackslashDisplayWeaveParticipant());
weaveProcessor.addInlineParticipants(new TexMathSBackslashInlineWeaveParticipant());
}
}
}
@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 (this.weaveProcessor == null) {
this.weaveProcessor= new WeaveLanguageProcessor();
}
final RTextileConfig config= getMarkupConfig();
if (config != this.configuredConfig) {
this.weaveProcessor.clearConfig();
configure(this.weaveProcessor, config);
this.configuredConfig= config;
}
setFilterGenerativeContents(parser.isDisabled(MarkupParser2.GENERATIVE_CONTENT));
setBlocksOnly(parser.isDisabled(MarkupParser2.INLINE_MARKUP));
final String markupContent= this.weaveProcessor.preprocess(content, parser.getBuilder(),
parser.getFlags() );
if (DEBUG_LOG_BASE_EVENTS) {
final StringWriter out= new StringWriter();
try {
final MarkupEventPrinter printer= new MarkupEventPrinter(markupContent, this, out);
final MarkupParser baseParser= new MarkupParser(this,
new MultiplexingDocumentBuilder(printer, this.weaveProcessor) );
super.processContent(baseParser, markupContent, asDocument);
this.weaveProcessor.finish();
System.out.println(out.toString());
}
catch (final Exception e) {
System.out.println(out.toString());
e.printStackTrace();
}
}
else {
final MarkupParser baseParser= new MarkupParser(this, this.weaveProcessor);
super.processContent(baseParser, markupContent, asDocument);
this.weaveProcessor.finish();
}
}
@Override
public void processContent(final MarkupParser parser, final String markupContent, final boolean asDocument) {
processContent(new MarkupParser2(parser), new SourceContent(0, markupContent), asDocument);
}
@Override
public List<String> getIndentPrefixes() {
return INDENT_PREFIXES;
}
@Override
public Pattern getRChunkStartLinePattern() {
return CHUNK_START_LINE_PATTERN;
}
@Override
public Pattern getRChunkRefLinePattern() {
return CHUNK_REF_LINE_PATTERN;
}
@Override
public Pattern getRChunkEndLinePattern() {
return CHUNK_END_LINE_PATTERN;
}
@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 RTextileLanguage other= (RTextileLanguage) obj;
return (getName().equals(other.getName())
&& this.mode == other.mode
&& Objects.equals(this.config, other.getMarkupConfig()) );
}
private WikitextProblemReporter validator;
@Override
public WikitextProblemReporter getProblemReporter() {
if (this.validator == null) {
this.validator= new TextileValidator();
}
return this.validator;
}
@Override
public MarkupSourceFormatAdapter getSourceFormatAdapter() {
return null;
}
private RChunkPartitionNodeScanner rPartitionScanner;
@Override
public AbstractRChunkPartitionNodeScanner getRChunkPartitionScanner() {
if (this.rPartitionScanner == null) {
this.rPartitionScanner= new RChunkPartitionNodeScanner();
}
return this.rPartitionScanner;
}
}