-
-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for Pandoc-style inline/display math
Fixes valentjn/vscode-ltex#210.
- Loading branch information
Showing
10 changed files
with
515 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
ltexls-core/src/main/java/org/bsplines/ltexls/parsing/markdown/LtexMarkdownDisplayMath.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* Copyright (C) 2020 Julian Valentin, LTeX Development Community | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
*/ | ||
|
||
package org.bsplines.ltexls.parsing.markdown; | ||
|
||
import com.vladsch.flexmark.ast.Paragraph; | ||
import com.vladsch.flexmark.ast.ParagraphContainer; | ||
import com.vladsch.flexmark.util.ast.Block; | ||
import com.vladsch.flexmark.util.ast.BlockContent; | ||
import com.vladsch.flexmark.util.sequence.BasedSequence; | ||
import java.util.List; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public class LtexMarkdownDisplayMath extends Block implements ParagraphContainer { | ||
private BasedSequence openingMarker = BasedSequence.NULL; | ||
private BasedSequence openingTrailing = BasedSequence.NULL; | ||
private BasedSequence closingMarker = BasedSequence.NULL; | ||
private BasedSequence closingTrailing = BasedSequence.NULL; | ||
|
||
@Override | ||
public void getAstExtra(@NotNull StringBuilder out) { | ||
segmentSpanChars(out, this.openingMarker, "open"); | ||
segmentSpanChars(out, this.openingTrailing, "openTrail"); | ||
segmentSpanChars(out, this.closingMarker, "close"); | ||
segmentSpanChars(out, this.closingTrailing, "closeTrail"); | ||
} | ||
|
||
@Override | ||
public @NotNull BasedSequence[] getSegments() { | ||
return new BasedSequence[] { | ||
this.openingMarker, | ||
this.openingTrailing, | ||
this.closingMarker, | ||
this.closingTrailing | ||
}; | ||
} | ||
|
||
@Override | ||
public boolean isParagraphEndWrappingDisabled(Paragraph node) { | ||
return ((node == getLastChild()) || (node.getNext() instanceof LtexMarkdownDisplayMath)); | ||
} | ||
|
||
@Override | ||
public boolean isParagraphStartWrappingDisabled(Paragraph node) { | ||
return ((node == getFirstChild()) || (node.getPrevious() instanceof LtexMarkdownDisplayMath)); | ||
} | ||
|
||
public LtexMarkdownDisplayMath() { | ||
} | ||
|
||
public LtexMarkdownDisplayMath(BasedSequence chars) { | ||
super(chars); | ||
} | ||
|
||
public LtexMarkdownDisplayMath(BasedSequence chars, List<BasedSequence> segments) { | ||
super(chars, segments); | ||
} | ||
|
||
public LtexMarkdownDisplayMath(BlockContent blockContent) { | ||
super(blockContent); | ||
} | ||
|
||
public BasedSequence getOpeningMarker() { | ||
return this.openingMarker; | ||
} | ||
|
||
public void setOpeningMarker(BasedSequence openingMarker) { | ||
this.openingMarker = openingMarker; | ||
} | ||
|
||
public BasedSequence getClosingMarker() { | ||
return this.closingMarker; | ||
} | ||
|
||
public void setClosingMarker(BasedSequence closingMarker) { | ||
this.closingMarker = closingMarker; | ||
} | ||
|
||
public BasedSequence getOpeningTrailing() { | ||
return this.openingTrailing; | ||
} | ||
|
||
public void setOpeningTrailing(BasedSequence openingTrailing) { | ||
this.openingTrailing = openingTrailing; | ||
} | ||
|
||
public BasedSequence getClosingTrailing() { | ||
return this.closingTrailing; | ||
} | ||
|
||
public void setClosingTrailing(BasedSequence closingTrailing) { | ||
this.closingTrailing = closingTrailing; | ||
} | ||
} |
165 changes: 165 additions & 0 deletions
165
...ore/src/main/java/org/bsplines/ltexls/parsing/markdown/LtexMarkdownDisplayMathParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
/* Copyright (C) 2020 Julian Valentin, LTeX Development Community | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
*/ | ||
|
||
package org.bsplines.ltexls.parsing.markdown; | ||
|
||
import com.vladsch.flexmark.parser.InlineParser; | ||
import com.vladsch.flexmark.parser.block.AbstractBlockParser; | ||
import com.vladsch.flexmark.parser.block.AbstractBlockParserFactory; | ||
import com.vladsch.flexmark.parser.block.BlockContinue; | ||
import com.vladsch.flexmark.parser.block.BlockParser; | ||
import com.vladsch.flexmark.parser.block.BlockParserFactory; | ||
import com.vladsch.flexmark.parser.block.BlockStart; | ||
import com.vladsch.flexmark.parser.block.CustomBlockParserFactory; | ||
import com.vladsch.flexmark.parser.block.MatchedBlockParser; | ||
import com.vladsch.flexmark.parser.block.ParserState; | ||
import com.vladsch.flexmark.util.ast.Block; | ||
import com.vladsch.flexmark.util.ast.BlockContent; | ||
import com.vladsch.flexmark.util.ast.Node; | ||
import com.vladsch.flexmark.util.data.DataHolder; | ||
import com.vladsch.flexmark.util.sequence.BasedSequence; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
public class LtexMarkdownDisplayMathParser extends AbstractBlockParser { | ||
private static final Pattern DISPLAY_MATH_START_PATTERN = Pattern.compile("\\$\\$(\\s*$)"); | ||
private static final Pattern DISPLAY_MATH_END_PATTERN = Pattern.compile("\\$\\$(\\s*$)"); | ||
|
||
private LtexMarkdownDisplayMath block = new LtexMarkdownDisplayMath(); | ||
private @Nullable BlockContent content = new BlockContent(); | ||
private boolean hadClose = false; | ||
|
||
LtexMarkdownDisplayMathParser(DataHolder options, BasedSequence openMarker, | ||
BasedSequence openTrailing) { | ||
this.block.setOpeningMarker(openMarker); | ||
this.block.setOpeningTrailing(openTrailing); | ||
} | ||
|
||
@Override | ||
public Block getBlock() { | ||
return this.block; | ||
} | ||
|
||
@Override | ||
public BlockContinue tryContinue(ParserState state) { | ||
if (this.hadClose) return BlockContinue.none(); | ||
|
||
int index = state.getIndex(); | ||
BasedSequence line = state.getLineWithEOL(); | ||
Matcher matcher = DISPLAY_MATH_END_PATTERN.matcher(line.subSequence(index)); | ||
|
||
if (!matcher.matches()) { | ||
return BlockContinue.atIndex(index); | ||
} else { | ||
@Nullable Node lastChild = this.block.getLastChild(); | ||
|
||
if ((lastChild != null) && (lastChild instanceof LtexMarkdownDisplayMath)) { | ||
BlockParser parser = state.getActiveBlockParser((Block)lastChild); | ||
|
||
if ((parser instanceof LtexMarkdownDisplayMathParser) | ||
&& !((LtexMarkdownDisplayMathParser)parser).hadClose) { | ||
return BlockContinue.atIndex(index); | ||
} | ||
} | ||
|
||
this.hadClose = true; | ||
this.block.setClosingMarker(state.getLine().subSequence(index, index + 2)); | ||
this.block.setClosingTrailing( | ||
state.getLineWithEOL().subSequence(matcher.start(1), matcher.end(1))); | ||
|
||
return BlockContinue.atIndex(state.getLineEndIndex()); | ||
} | ||
} | ||
|
||
@Override | ||
public void addLine(ParserState state, BasedSequence line) { | ||
if (this.content == null) return; | ||
this.content.add(line, state.getIndent()); | ||
} | ||
|
||
@Override | ||
public void closeBlock(ParserState state) { | ||
if (this.content == null) return; | ||
this.block.setContent(this.content); | ||
this.block.setCharsFromContent(); | ||
this.content = null; | ||
} | ||
|
||
@Override | ||
public boolean isContainer() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public boolean canContain(ParserState state, BlockParser blockParser, Block block) { | ||
return false; | ||
} | ||
|
||
@Override | ||
public void parseInlines(InlineParser inlineParser) { | ||
} | ||
|
||
public static class Factory implements CustomBlockParserFactory { | ||
@Override | ||
public @Nullable Set<Class<?>> getAfterDependents() { | ||
return null; | ||
} | ||
|
||
@Override | ||
public @Nullable Set<Class<?>> getBeforeDependents() { | ||
return null; | ||
} | ||
|
||
@Override | ||
public boolean affectsGlobalScope() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public @NotNull BlockParserFactory apply(@NotNull DataHolder options) { | ||
return new BlockFactory(options); | ||
} | ||
} | ||
|
||
private static class BlockFactory extends AbstractBlockParserFactory { | ||
BlockFactory(DataHolder options) { | ||
super(options); | ||
} | ||
|
||
private static boolean haveDisplayMathParser(ParserState state) { | ||
List<BlockParser> parsers = state.getActiveBlockParsers(); | ||
|
||
for (int i = parsers.size() - 1; i >= 0; i--) { | ||
if (parsers.get(i) instanceof LtexMarkdownDisplayMathParser) return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
@Override | ||
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) { | ||
if (!haveDisplayMathParser(state)) { | ||
BasedSequence line = state.getLineWithEOL(); | ||
Matcher matcher = DISPLAY_MATH_START_PATTERN.matcher(line); | ||
|
||
if (matcher.matches()) { | ||
LtexMarkdownDisplayMathParser parser = new LtexMarkdownDisplayMathParser( | ||
state.getProperties(), | ||
line.subSequence(0, 2), | ||
line.subSequence(matcher.start(1), matcher.end(1))); | ||
return BlockStart.of(parser).atIndex(state.getLineEndIndex()); | ||
} | ||
} | ||
|
||
return BlockStart.none(); | ||
} | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
ltexls-core/src/main/java/org/bsplines/ltexls/parsing/markdown/LtexMarkdownExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* Copyright (C) 2020 Julian Valentin, LTeX Development Community | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
*/ | ||
|
||
package org.bsplines.ltexls.parsing.markdown; | ||
|
||
import com.vladsch.flexmark.parser.Parser; | ||
import com.vladsch.flexmark.util.data.DataKey; | ||
import com.vladsch.flexmark.util.data.MutableDataHolder; | ||
|
||
public class LtexMarkdownExtension implements Parser.ParserExtension { | ||
public static final DataKey<Boolean> DISPLAY_MATH_PARSER = | ||
new DataKey<>("DISPLAY_MATH_PARSER", true); | ||
public static final DataKey<Boolean> INLINE_MATH_PARSER = | ||
new DataKey<>("INLINE_MATH_PARSER", true); | ||
|
||
private LtexMarkdownExtension() { | ||
} | ||
|
||
public static LtexMarkdownExtension create() { | ||
return new LtexMarkdownExtension(); | ||
} | ||
|
||
@Override | ||
public void parserOptions(MutableDataHolder options) { | ||
} | ||
|
||
@Override | ||
public void extend(Parser.Builder parserBuilder) { | ||
LtexMarkdownOptions options = new LtexMarkdownOptions(parserBuilder); | ||
|
||
if (options.displayMathParser) { | ||
parserBuilder.customBlockParserFactory(new LtexMarkdownDisplayMathParser.Factory()); | ||
} | ||
|
||
if (options.inlineMathParser) { | ||
parserBuilder.customInlineParserExtensionFactory(new LtexMarkdownInlineMathParser.Factory()); | ||
} | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
ltexls-core/src/main/java/org/bsplines/ltexls/parsing/markdown/LtexMarkdownInlineMath.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* Copyright (C) 2020 Julian Valentin, LTeX Development Community | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
*/ | ||
|
||
package org.bsplines.ltexls.parsing.markdown; | ||
|
||
import com.vladsch.flexmark.util.ast.DelimitedNode; | ||
import com.vladsch.flexmark.util.ast.Node; | ||
import com.vladsch.flexmark.util.sequence.BasedSequence; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public class LtexMarkdownInlineMath extends Node implements DelimitedNode { | ||
protected BasedSequence openingMarker = BasedSequence.NULL; | ||
protected BasedSequence text = BasedSequence.NULL; | ||
protected BasedSequence closingMarker = BasedSequence.NULL; | ||
|
||
@Override | ||
public @NotNull BasedSequence[] getSegments() { | ||
return new BasedSequence[] { this.openingMarker, this.text, this.closingMarker }; | ||
} | ||
|
||
@Override | ||
public void getAstExtra(@NotNull StringBuilder out) { | ||
delimitedSegmentSpanChars(out, this.openingMarker, this.text, this.closingMarker, "text"); | ||
} | ||
|
||
public LtexMarkdownInlineMath() { | ||
} | ||
|
||
public LtexMarkdownInlineMath(BasedSequence chars) { | ||
super(chars); | ||
} | ||
|
||
public LtexMarkdownInlineMath(BasedSequence openingMarker, BasedSequence text, | ||
BasedSequence closingMarker) { | ||
super(openingMarker.baseSubSequence( | ||
openingMarker.getStartOffset(), closingMarker.getEndOffset())); | ||
this.openingMarker = openingMarker; | ||
this.text = text; | ||
this.closingMarker = closingMarker; | ||
} | ||
|
||
public BasedSequence getOpeningMarker() { | ||
return this.openingMarker; | ||
} | ||
|
||
public void setOpeningMarker(BasedSequence openingMarker) { | ||
this.openingMarker = openingMarker; | ||
} | ||
|
||
public BasedSequence getText() { | ||
return this.text; | ||
} | ||
|
||
public void setText(BasedSequence text) { | ||
this.text = text; | ||
} | ||
|
||
public BasedSequence getClosingMarker() { | ||
return this.closingMarker; | ||
} | ||
|
||
public void setClosingMarker(BasedSequence closingMarker) { | ||
this.closingMarker = closingMarker; | ||
} | ||
} |
Oops, something went wrong.