| /*=============================================================================# |
| # 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.commonmark.core; |
| |
| import java.util.List; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.collections.ImList; |
| |
| import org.eclipse.statet.docmlet.wikitext.commonmark.core.CommonmarkLanguage; |
| import org.eclipse.statet.docmlet.wikitext.core.markup.IMarkupConfig; |
| import org.eclipse.statet.docmlet.wikitext.core.markup.MarkupParser2; |
| 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.IExtdocMarkupLanguage; |
| 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.commonmark.core.IRCommonmarkConfig; |
| import org.eclipse.statet.redocs.wikitext.r.core.source.IRweaveMarkupLanguage; |
| |
| |
| public class RCommonmarkLanguage extends CommonmarkLanguage |
| implements IExtdocMarkupLanguage, IRweaveMarkupLanguage { |
| |
| |
| public static final String COMMONMARK_RWEAVE_LANGUAGE_NAME= "CommonMark+R"; //$NON-NLS-1$ |
| |
| |
| private static final ImList<String> INDENT_PREFIXES= ImCollections.newList(" ", "\t"); //$NON-NLS-1$ |
| /** |
| * <code>```{r args}</code> or <code>```{.r args}</code>, identation allowed |
| * <p> |
| * Regex: <code>\A[ \t]*+```[ \t]*+(?:\{\.?r)(.*?)}?\s*\z</code> |
| */ |
| private static final Pattern CHUNK_START_LINE_PATTERN= Pattern.compile("\\A[ \\t]*+```[ \\t]*+(?:\\{\\.?r)(.*?)}?\\s*\\z"); //$NON-NLS-1$ |
| private static final Pattern CHUNK_REF_LINE_PATTERN= Pattern.compile("\\A[ \\t]*+<<(.*?)(?:>>)?+\\p{all}*\\z"); //$NON-NLS-1$ |
| /** |
| * <code>```</code>, but not start pattern, identation allowed |
| * <p> |
| * Regex: <code>\A[ \t]*+```[ \t]*+(?!\{\.?r)\p{all}*\z</code> |
| */ |
| private static final Pattern CHUNK_END_LINE_PATTERN= Pattern.compile("\\A[ \\t]*+```[ \\t]*+(?!\\{\\.?r)\\p{all}*\\z"); //$NON-NLS-1$ |
| |
| private static final Pattern INLINE_PATTERN= Pattern.compile("`r ([^`]+)`"); //$NON-NLS-1$ |
| |
| |
| private IRCommonmarkConfig configuredConfig; |
| |
| private WeaveLanguageProcessor weaveProcessor; |
| |
| |
| public RCommonmarkLanguage() { |
| this(null, 0, null); |
| } |
| |
| public RCommonmarkLanguage(final String scope, final int mode, final IRCommonmarkConfig config) { |
| super(scope, mode, config); |
| |
| assert (COMMONMARK_LANGUAGE_NAME.equals(getName())); |
| setName(COMMONMARK_RWEAVE_LANGUAGE_NAME); |
| setExtendsLanguage(COMMONMARK_LANGUAGE_NAME); |
| |
| setMarkupConfig(config); |
| } |
| |
| |
| @Override |
| public RCommonmarkLanguage clone() { |
| return (RCommonmarkLanguage) super.clone(); |
| } |
| |
| @Override |
| public RCommonmarkLanguage clone(final String scope, final int mode) { |
| return (RCommonmarkLanguage) super.clone(scope, mode); |
| } |
| |
| |
| @Override |
| public void setMarkupConfig(final IMarkupConfig config) { |
| super.setMarkupConfig(config); |
| } |
| |
| @Override |
| public IRCommonmarkConfig getMarkupConfig() { |
| return (IRCommonmarkConfig) super.getMarkupConfig(); |
| } |
| |
| |
| // @Override |
| // protected void modeChanged(int oldMode, int newMode) { |
| // if (this.weaveProcessor != null) { |
| // this.configuredConfig= null; |
| // } |
| // } |
| // |
| protected void configure(final WeaveLanguageProcessor weaveProcessor, |
| final IRCommonmarkConfig config) { |
| weaveProcessor.addChunkParticipant(new RegexBlockWeaveParticipant( |
| EMBEDDED_R, EMBEDDED_R_CHUNK_DESCR, |
| CHUNK_START_LINE_PATTERN, CHUNK_END_LINE_PATTERN ) { |
| @Override |
| protected void appendReplacement(final StringBuilder sb, |
| final String source, final int startOffset, final int endOffset) { |
| { // Add indent |
| int offset= startOffset; |
| for (; offset < endOffset; offset++) { |
| final char c= source.charAt(offset); |
| if (c != ' ' && c != '\t') { |
| break; |
| } |
| } |
| if (startOffset < offset) { |
| sb.append(source.substring(startOffset, offset)); |
| } |
| } |
| super.appendReplacement(sb, source, startOffset, endOffset); |
| } |
| }); |
| 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 IRCommonmarkConfig config= getMarkupConfig(); |
| if (config != this.configuredConfig) { |
| this.weaveProcessor.clearConfig(); |
| configure(this.weaveProcessor, config); |
| this.configuredConfig= config; |
| } |
| |
| final String markupContent= this.weaveProcessor.preprocess(content, parser.getBuilder(), |
| parser.getFlags() ); |
| |
| final MarkupParser2 baseParser= new MarkupParser2(this, this.weaveProcessor, parser.getFlags()); |
| doProcessContent(baseParser, new SourceContent(content.getStamp(), markupContent), asDocument); |
| this.weaveProcessor.finish(); |
| } |
| |
| |
| @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; |
| } |
| |
| |
| private RChunkPartitionNodeScanner rPartitionScanner; |
| |
| @Override |
| public AbstractRChunkPartitionNodeScanner getRChunkPartitionScanner() { |
| if (this.rPartitionScanner == null) { |
| this.rPartitionScanner= new RChunkPartitionNodeScanner(); |
| } |
| return this.rPartitionScanner; |
| } |
| |
| } |