Optional allow only one $ around the latex

This commit is contained in:
zhangyu.0602 2023-06-14 20:26:50 +08:00
parent 2ea148c30a
commit f711d6d702
3 changed files with 146 additions and 6 deletions

View File

@ -1,11 +1,11 @@
package io.noties.markwon.ext.latex;
import androidx.annotation.Nullable;
import org.commonmark.node.Node;
import java.util.regex.Pattern;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import io.noties.markwon.inlineparser.InlineProcessor;
/**
@ -13,7 +13,24 @@ import io.noties.markwon.inlineparser.InlineProcessor;
*/
class JLatexMathInlineProcessor extends InlineProcessor {
private static final Pattern RE = Pattern.compile("(\\${2})([\\s\\S]+?)\\1");
private static final Pattern singleOrDoubleDollar =
Pattern.compile("(\\${2})([\\s\\S]+?)(\\${2})|(\\$)([\\s\\S]+?)(\\$)");
private static final Pattern doubleDollar =
Pattern.compile("(\\${2})([\\s\\S]+?)\\1");
private final boolean allowSingle$;
@VisibleForTesting
final Pattern pattern;
JLatexMathInlineProcessor() {
this(false);
}
JLatexMathInlineProcessor(boolean allowSingle$) {
this.allowSingle$ = allowSingle$;
this.pattern = allowSingle$ ? singleOrDoubleDollar : doubleDollar;
}
@Override
public char specialCharacter() {
@ -24,13 +41,25 @@ class JLatexMathInlineProcessor extends InlineProcessor {
@Override
protected Node parse() {
final String latex = match(RE);
final String latex = match(pattern);
if (latex == null) {
return null;
}
final JLatexMathNode node = new JLatexMathNode();
node.latex(latex.substring(2, latex.length() - 2));
node.latex(trimDollar(latex));
return node;
}
@SuppressWarnings("DuplicateExpressions")
@VisibleForTesting
String trimDollar(String latex) {
if (allowSingle$) {
return latex.startsWith("$$") && latex.endsWith("$$")
? latex.substring(2, latex.length() - 2)
: latex.substring(1, latex.length() - 1);
} else {
return latex.substring(2, latex.length() - 2);
}
}
}

View File

@ -119,6 +119,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
final boolean blocksEnabled;
final boolean blocksLegacy;
final boolean inlinesEnabled;
final boolean allowInlineSingle$;
// @since 4.3.0
final ErrorHandler errorHandler;
@ -130,6 +131,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
this.blocksEnabled = builder.blocksEnabled;
this.blocksLegacy = builder.blocksLegacy;
this.inlinesEnabled = builder.inlinesEnabled;
this.allowInlineSingle$ = builder.allowInlineSingle$;
this.errorHandler = builder.errorHandler;
// @since 4.0.0
ExecutorService executorService = builder.executorService;
@ -160,7 +162,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
if (config.inlinesEnabled) {
registry.require(MarkwonInlineParserPlugin.class)
.factoryBuilder()
.addInlineProcessor(new JLatexMathInlineProcessor());
.addInlineProcessor(new JLatexMathInlineProcessor(config.allowInlineSingle$));
}
}
@ -285,6 +287,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
private boolean blocksEnabled = true;
private boolean blocksLegacy;
private boolean inlinesEnabled;
private boolean allowInlineSingle$;
// @since 4.3.0
private ErrorHandler errorHandler;
@ -331,6 +334,16 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
return this;
}
/**
* @param inlineSingleDollar indicates if $xxx$ is valid.
* @since 4.7.0
*/
@NonNull
public Builder allowInlinesSingleDollar(boolean inlineSingleDollar){
this.allowInlineSingle$ = inlineSingleDollar;
return this;
}
@NonNull
public Builder errorHandler(@Nullable ErrorHandler errorHandler) {
this.errorHandler = errorHandler;

View File

@ -0,0 +1,98 @@
package io.noties.markwon.ext.latex;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.regex.Matcher;
/**
* @author YvesCheung
* 2023/6/14
*/
@RunWith(Parameterized.class)
public class JLatexMathInlineParserTest {
@Parameterized.Parameters
public static Object[][] data() {
return new Object[][]{
{true, "$ a $", "$ a $", " a "},
{false, "$ a $", "", ""},
{true, "ashdksa $ a $sfalhs", "$ a $", " a "},
{false, "ashdksa $ a $sfalhs", "", ""},
{true, "c sajdl asjkdhk $abc$\n sahdila", "$abc$", "abc"},
{false, "c sajdl asjkdhk $abc$\n sahdila", "", ""},
{true, "c sajdl asjkdhk \n$abcd $ sahdila", "$abcd $", "abcd "},
{false, "c sajdl asjkdhk \n$abcd $ sahdila", "", ""},
{true, "$$abc$$", "$$abc$$", "abc"},
{false, "$$abc$$", "$$abc$$", "abc"},
{true, "$$abc$", "$$abc$", "$abc"},
{false, "$$abc$", "", ""},
{true, "lllll bbb xxx $dhaksdhk\n asd ${b}", "$dhaksdhk\n asd $", "dhaksdhk\n asd "},
{false, "lllll bbb xxx $dhaksdhk\n asd ${b}", "", ""},
{true, "aaa yyy $$bb $ dddd$", "$$bb $", "$bb "},
{false, "aaa yyy $$bb $ dddd$", "", ""},
{true, "aaa $sagdkg$$ Hello", "$sagdkg$", "sagdkg"},
{false, "aaa $sagdkg$$ Hello", "", ""},
{true, "lllll bbb xxx dhaksdhk\n asd ${b}", "", ""},
{false, "lllll bbb xxx dhaksdhk\n asd ${b}", "", ""},
{true, "asdhfalkhasl suaflhslia lasdjikaih sahk", "", ""},
{false, "asdhfalkhasl suaflhslia lasdjikaih sahk", "", ""},
{true, "lllll bbb $xxx dhaksdhk\n asd", "", ""},
{false, "lllll bbb $xxx dhaksdhk\n asd", "", ""}
};
}
@Parameterized.Parameter(0)
public boolean allowSingle$;
@Parameterized.Parameter(1)
public String input;
@Parameterized.Parameter(2)
public String output;
@Parameterized.Parameter(3)
public String trimOutput;
@Test
public void match() {
JLatexMathInlineProcessor processor = new JLatexMathInlineProcessor(allowSingle$);
Matcher matcher = processor.pattern.matcher(input);
if (output == null || "".equals(output)) {
Assert.assertFalse(matcher.find());
} else {
Assert.assertTrue(matcher.find());
String actual = matcher.group();
Assert.assertEquals(output, actual);
Assert.assertEquals(trimOutput, processor.trimDollar(actual));
}
}
@Test
public void not_match() {
String[][] testCase = new String[][]{
new String[]{"lllll bbb xxx dhaksdhk\n asd ${b}"},
new String[]{"asdhfalkhasl suaflhslia lasdjikaih sahk"},
new String[]{"lllll bbb $xxx dhaksdhk\n asd"},
};
for (String[] c : testCase) {
String input = c[0];
JLatexMathInlineProcessor processor = new JLatexMathInlineProcessor(true);
Matcher matcher = processor.pattern.matcher(input);
Assert.assertFalse(matcher.find());
}
}
}