From 78b870c5580aa483f98f84c70ecb0753a1d1d941 Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Fri, 18 Sep 2020 15:22:10 +0100 Subject: [PATCH 01/13] Downgrade markwon version and enable LaTeX rendering for messages --- dependencies.gradle | 4 +++- vector/build.gradle | 2 ++ .../detail/timeline/factory/MessageItemFactory.kt | 1 + .../home/room/detail/timeline/item/MessageTextItem.kt | 7 +++++++ .../im/vector/app/features/html/EventHtmlRenderer.kt | 11 +++++++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index a4e2c60387..58133c3eef 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -14,7 +14,7 @@ def kotlinCoroutines = "1.5.1" def dagger = "2.38.1" def retrofit = "2.9.0" def arrow = "0.8.2" -def markwon = "4.6.2" +def markwon = "4.3.1" def moshi = "1.12.0" def lifecycle = "2.2.0" def rxBinding = "3.1.0" @@ -90,6 +90,8 @@ ext.libs = [ ], markwon : [ 'core' : "io.noties.markwon:core:$markwon", + 'extLatex' : "io.noties.markwon:ext-latex:$markwon", + 'inlineParser' : "io.noties.markwon:inline-parser:$markwon", 'html' : "io.noties.markwon:html:$markwon" ], airbnb : [ diff --git a/vector/build.gradle b/vector/build.gradle index d60f928f2c..9d25914e8e 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -390,6 +390,8 @@ dependencies { implementation libs.google.material implementation 'me.gujun.android:span:1.7' implementation libs.markwon.core + implementation libs.markwon.extLatex + implementation libs.markwon.inlineParser implementation libs.markwon.html implementation 'com.googlecode.htmlcompressor:htmlcompressor:1.5.2' implementation 'me.saket:better-link-movement-method:2.2.0' diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 287cd014e9..fd675d90fa 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -484,6 +484,7 @@ class MessageItemFactory @Inject constructor( } .useBigFont(linkifiedBody.length <= MAX_NUMBER_OF_EMOJI_FOR_BIG_FONT * 2 && containsOnlyEmojis(linkifiedBody.toString())) .canUseTextFuture(canUseTextFuture) + .markwonPlugins(htmlRenderer.get().plugins) .searchForPills(isFormatted) .previewUrlRetriever(callback?.getPreviewUrlRetriever()) .imageContentRenderer(imageContentRenderer) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt index c6dce5a9ce..a53e80362d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt @@ -16,6 +16,7 @@ package im.vector.app.features.home.room.detail.timeline.item +import android.text.Spanned import android.text.method.MovementMethod import androidx.appcompat.widget.AppCompatTextView import androidx.core.text.PrecomputedTextCompat @@ -31,6 +32,7 @@ import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlRetriever import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlUiState import im.vector.app.features.home.room.detail.timeline.url.PreviewUrlView import im.vector.app.features.media.ImageContentRenderer +import io.noties.markwon.MarkwonPlugin @EpoxyModelClass(layout = R.layout.item_timeline_event_base) abstract class MessageTextItem : AbsMessageItem() { @@ -59,6 +61,9 @@ abstract class MessageTextItem : AbsMessageItem() { @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var movementMethod: MovementMethod? = null + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) + var markwonPlugins: (List)? = null + private val previewUrlViewUpdater = PreviewUrlViewUpdater() override fun bind(holder: Holder) { @@ -92,6 +97,7 @@ abstract class MessageTextItem : AbsMessageItem() { } else { null } + markwonPlugins?.forEach { plugin -> plugin.beforeSetText(holder.messageView, message as Spanned) } super.bind(holder) holder.messageView.movementMethod = movementMethod @@ -104,6 +110,7 @@ abstract class MessageTextItem : AbsMessageItem() { } else { holder.messageView.text = message } + markwonPlugins?.forEach { plugin -> plugin.afterSetText(holder.messageView) } } override fun unbind(holder: Holder) { diff --git a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt index d3b3be6a3e..cc7c999067 100644 --- a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt @@ -21,7 +21,11 @@ import android.text.Spannable import androidx.core.text.toSpannable import im.vector.app.core.resources.ColorProvider import io.noties.markwon.Markwon +import io.noties.markwon.MarkwonPlugin +import io.noties.markwon.ext.latex.JLatexMathPlugin +import io.noties.markwon.ext.latex.JLatexMathTheme import io.noties.markwon.html.HtmlPlugin +import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin import org.commonmark.node.Node import timber.log.Timber import javax.inject.Inject @@ -37,8 +41,15 @@ class EventHtmlRenderer @Inject constructor(htmlConfigure: MatrixHtmlPluginConfi private val markwon = Markwon.builder(context) .usePlugin(HtmlPlugin.create(htmlConfigure)) + .usePlugin(MarkwonInlineParserPlugin.create()) + .usePlugin(JLatexMathPlugin.create(44F) { builder -> + builder.inlinesEnabled(true) + builder.theme().inlinePadding(JLatexMathTheme.Padding.symmetric(24, 8)) + }) .build() + val plugins: List = markwon.plugins + fun parse(text: String): Node { return markwon.parse(text) } From 20821fbe802a527c950fe333d649894820a395f7 Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Fri, 18 Sep 2020 15:23:21 +0100 Subject: [PATCH 02/13] Render maths with respect to `data-mx-maths` (https://github.com/matrix-org/matrix-doc/pull/2191) Firstly, this implements a commonmark-java plugin which is solely used to parse LaTeX input in the composer box, so that they can be rendered into `fallback` and `
fallback
` for inline and display maths respectively in the sent message. Secondly, received messages of this form are pre-processed by a simple regex into a form which markwon (which performs the rendering) expects. --- .../commonmark/ext/maths/DisplayMaths.java | 32 +++++++++ .../org/commonmark/ext/maths/InlineMaths.java | 55 ++++++++++++++++ .../commonmark/ext/maths/MathsExtension.java | 51 ++++++++++++++ .../DollarMathsDelimiterProcessor.java | 66 +++++++++++++++++++ .../maths/internal/MathsHtmlNodeRenderer.java | 50 ++++++++++++++ .../ext/maths/internal/MathsNodeRenderer.java | 35 ++++++++++ .../sdk/internal/session/room/RoomModule.kt | 6 +- .../session/room/send/MarkdownParser.kt | 2 +- .../app/features/html/EventHtmlRenderer.kt | 8 +++ 9 files changed, 303 insertions(+), 2 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.java create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.java create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.java create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.java create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.java create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.java diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.java new file mode 100644 index 0000000000..3cf574b824 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.commonmark.ext.maths; + +import org.commonmark.node.CustomBlock; + +public class DisplayMaths extends CustomBlock { + public enum DisplayDelimiter { + DOUBLE_DOLLAR, + SQUARE_BRACKET_ESCAPED + }; + + private DisplayDelimiter delimiter; + + public DisplayMaths(DisplayDelimiter delimiter) { + this.delimiter = delimiter; + } +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.java new file mode 100644 index 0000000000..982570a58d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.commonmark.ext.maths; + +import org.commonmark.node.CustomNode; +import org.commonmark.node.Delimited; + +public class InlineMaths extends CustomNode implements Delimited { + public enum InlineDelimiter { + SINGLE_DOLLAR, + ROUND_BRACKET_ESCAPED + }; + + private InlineDelimiter delimiter; + + public InlineMaths(InlineDelimiter delimiter) { + this.delimiter = delimiter; + } + + @Override + public String getOpeningDelimiter() { + switch (delimiter) { + case SINGLE_DOLLAR: + return "$"; + case ROUND_BRACKET_ESCAPED: + return "\\("; + } + return null; + } + + @Override + public String getClosingDelimiter() { + switch (delimiter) { + case SINGLE_DOLLAR: + return "$"; + case ROUND_BRACKET_ESCAPED: + return "\\)"; + } + return null; + } +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.java new file mode 100644 index 0000000000..31706b3f2d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.commonmark.ext.maths; + +import org.commonmark.Extension; +import org.commonmark.ext.maths.internal.DollarMathsDelimiterProcessor; +import org.commonmark.ext.maths.internal.MathsHtmlNodeRenderer; +import org.commonmark.parser.Parser; +import org.commonmark.renderer.NodeRenderer; +import org.commonmark.renderer.html.HtmlNodeRendererContext; +import org.commonmark.renderer.html.HtmlNodeRendererFactory; +import org.commonmark.renderer.html.HtmlRenderer; + +public class MathsExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension { + + private MathsExtension() { + } + + public static Extension create() { + return new MathsExtension(); + } + + @Override + public void extend(Parser.Builder parserBuilder) { + parserBuilder.customDelimiterProcessor(new DollarMathsDelimiterProcessor()); + } + + @Override + public void extend(HtmlRenderer.Builder rendererBuilder) { + rendererBuilder.nodeRendererFactory(new HtmlNodeRendererFactory() { + @Override + public NodeRenderer create(HtmlNodeRendererContext context) { + return new MathsHtmlNodeRenderer(context); + } + }); + } +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.java new file mode 100644 index 0000000000..809c070f29 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.commonmark.ext.maths.internal; + +import org.commonmark.ext.maths.DisplayMaths; +import org.commonmark.ext.maths.InlineMaths; +import org.commonmark.node.Node; +import org.commonmark.node.Text; +import org.commonmark.parser.delimiter.DelimiterProcessor; +import org.commonmark.parser.delimiter.DelimiterRun; + +public class DollarMathsDelimiterProcessor implements DelimiterProcessor { + @Override + public char getOpeningCharacter() { + return '$'; + } + + @Override + public char getClosingCharacter() { + return '$'; + } + + @Override + public int getMinLength() { + return 1; + } + + @Override + public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) { + if (opener.length() == 1 && closer.length() == 1) + return 1; // inline + else if (opener.length() == 2 && closer.length() == 2) + return 2; // display + else + return 0; + } + + @Override + public void process(Text opener, Text closer, int delimiterUse) { + Node maths = delimiterUse == 1 ? new InlineMaths(InlineMaths.InlineDelimiter.SINGLE_DOLLAR) : + new DisplayMaths(DisplayMaths.DisplayDelimiter.DOUBLE_DOLLAR); + + Node tmp = opener.getNext(); + while (tmp != null && tmp != closer) { + Node next = tmp.getNext(); + maths.appendChild(tmp); + tmp = next; + } + + opener.insertAfter(maths); + } +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.java new file mode 100644 index 0000000000..a84129cd28 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.commonmark.ext.maths.internal; + +import org.commonmark.ext.maths.DisplayMaths; +import org.commonmark.node.Node; +import org.commonmark.node.Text; +import org.commonmark.renderer.html.HtmlNodeRendererContext; +import org.commonmark.renderer.html.HtmlWriter; + +import java.util.Collections; +import java.util.Map; + +public class MathsHtmlNodeRenderer extends MathsNodeRenderer { + private final HtmlNodeRendererContext context; + private final HtmlWriter html; + + public MathsHtmlNodeRenderer(HtmlNodeRendererContext context) { + this.context = context; + this.html = context.getWriter(); + } + + @Override + public void render(Node node) { + boolean display = node.getClass() == DisplayMaths.class; + Node contents = node.getFirstChild(); // should be the only child + String latex = ((Text) contents).getLiteral(); + Map attributes = context.extendAttributes(node, display ? "div" : "span", Collections.singletonMap("data-mx-maths", + latex)); + html.tag(display ? "div" : "span", attributes); + html.tag("code"); + context.render(contents); + html.tag("/code"); + html.tag(display ? "/div" : "/span"); + } +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.java new file mode 100644 index 0000000000..4d2a35f33d --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.commonmark.ext.maths.internal; + +import org.commonmark.ext.maths.DisplayMaths; +import org.commonmark.ext.maths.InlineMaths; +import org.commonmark.node.Node; +import org.commonmark.renderer.NodeRenderer; + +import java.util.HashSet; +import java.util.Set; + +abstract class MathsNodeRenderer implements NodeRenderer { + @Override + public Set> getNodeTypes() { + final Set> types = new HashSet>(); + types.add(InlineMaths.class); + types.add(DisplayMaths.class); + return types; + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index dbd0ae6f06..105c8ad03e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -19,6 +19,8 @@ package org.matrix.android.sdk.internal.session.room import dagger.Binds import dagger.Module import dagger.Provides +import org.commonmark.Extension +import org.commonmark.ext.maths.MathsExtension import org.commonmark.parser.Parser import org.commonmark.renderer.html.HtmlRenderer import org.matrix.android.sdk.api.session.file.FileService @@ -104,6 +106,7 @@ internal abstract class RoomModule { @Module companion object { + private val extensions : List = listOf(MathsExtension.create()) @Provides @JvmStatic @SessionScope @@ -121,7 +124,7 @@ internal abstract class RoomModule { @Provides @JvmStatic fun providesParser(): Parser { - return Parser.builder().build() + return Parser.builder().extensions(extensions).build() } @Provides @@ -129,6 +132,7 @@ internal abstract class RoomModule { fun providesHtmlRenderer(): HtmlRenderer { return HtmlRenderer .builder() + .extensions(extensions) .softbreak("
") .build() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt index c99d482300..1ac95154f8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt @@ -32,7 +32,7 @@ internal class MarkdownParser @Inject constructor( private val textPillsUtils: TextPillsUtils ) { - private val mdSpecialChars = "[`_\\-*>.\\[\\]#~]".toRegex() + private val mdSpecialChars = "[`_\\-*>.\\[\\]#~$]".toRegex() fun parse(text: CharSequence): TextContent { val source = textPillsUtils.processSpecialSpansToMarkdown(text) ?: text.toString() diff --git a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt index cc7c999067..e2fb385ae5 100644 --- a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt @@ -20,6 +20,7 @@ import android.content.Context import android.text.Spannable import androidx.core.text.toSpannable import im.vector.app.core.resources.ColorProvider +import io.noties.markwon.AbstractMarkwonPlugin import io.noties.markwon.Markwon import io.noties.markwon.MarkwonPlugin import io.noties.markwon.ext.latex.JLatexMathPlugin @@ -41,6 +42,13 @@ class EventHtmlRenderer @Inject constructor(htmlConfigure: MatrixHtmlPluginConfi private val markwon = Markwon.builder(context) .usePlugin(HtmlPlugin.create(htmlConfigure)) + .usePlugin(object : AbstractMarkwonPlugin() { // Markwon expects maths to be in a specific format: https://noties.io/Markwon/docs/v4/ext-latex + override fun processMarkdown(markdown: String): String { + return markdown + .replace(Regex(""".*?""")) { matchResult -> "$$" + matchResult.groupValues[1] + "$$" } + .replace(Regex(""".*?""")) { matchResult -> "\n$$\n" + matchResult.groupValues[1] + "\n$$\n" } + } + }) .usePlugin(MarkwonInlineParserPlugin.create()) .usePlugin(JLatexMathPlugin.create(44F) { builder -> builder.inlinesEnabled(true) From 4c45a69129dcd523d441d4b04ca46847b1a8f946 Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Wed, 8 Sep 2021 16:06:31 +0100 Subject: [PATCH 03/13] Migrate commonmark extension to kotlin --- .../{DisplayMaths.java => DisplayMaths.kt} | 20 ++---- .../org/commonmark/ext/maths/InlineMaths.java | 55 ---------------- .../org/commonmark/ext/maths/InlineMaths.kt | 39 +++++++++++ .../commonmark/ext/maths/MathsExtension.java | 51 -------------- .../commonmark/ext/maths/MathsExtension.kt | 38 +++++++++++ .../DollarMathsDelimiterProcessor.java | 66 ------------------- .../internal/DollarMathsDelimiterProcessor.kt | 53 +++++++++++++++ .../maths/internal/MathsHtmlNodeRenderer.java | 50 -------------- .../maths/internal/MathsHtmlNodeRenderer.kt | 39 +++++++++++ ...NodeRenderer.java => MathsNodeRenderer.kt} | 31 ++++----- 10 files changed, 189 insertions(+), 253 deletions(-) rename matrix-sdk-android/src/main/java/org/commonmark/ext/maths/{DisplayMaths.java => DisplayMaths.kt} (63%) delete mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.java create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt delete mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.java create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.kt delete mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.java create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt delete mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.java create mode 100644 matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt rename matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/{MathsNodeRenderer.java => MathsNodeRenderer.kt} (51%) diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt similarity index 63% rename from matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.java rename to matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt index 3cf574b824..bf6a89a26a 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.java +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt @@ -13,20 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.commonmark.ext.maths -package org.commonmark.ext.maths; +import org.commonmark.node.CustomBlock -import org.commonmark.node.CustomBlock; - -public class DisplayMaths extends CustomBlock { - public enum DisplayDelimiter { - DOUBLE_DOLLAR, - SQUARE_BRACKET_ESCAPED - }; - - private DisplayDelimiter delimiter; - - public DisplayMaths(DisplayDelimiter delimiter) { - this.delimiter = delimiter; +class DisplayMaths(private val delimiter: DisplayDelimiter) : CustomBlock() { + enum class DisplayDelimiter { + DOUBLE_DOLLAR, SQUARE_BRACKET_ESCAPED } -} +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.java deleted file mode 100644 index 982570a58d..0000000000 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2020 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.commonmark.ext.maths; - -import org.commonmark.node.CustomNode; -import org.commonmark.node.Delimited; - -public class InlineMaths extends CustomNode implements Delimited { - public enum InlineDelimiter { - SINGLE_DOLLAR, - ROUND_BRACKET_ESCAPED - }; - - private InlineDelimiter delimiter; - - public InlineMaths(InlineDelimiter delimiter) { - this.delimiter = delimiter; - } - - @Override - public String getOpeningDelimiter() { - switch (delimiter) { - case SINGLE_DOLLAR: - return "$"; - case ROUND_BRACKET_ESCAPED: - return "\\("; - } - return null; - } - - @Override - public String getClosingDelimiter() { - switch (delimiter) { - case SINGLE_DOLLAR: - return "$"; - case ROUND_BRACKET_ESCAPED: - return "\\)"; - } - return null; - } -} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt new file mode 100644 index 0000000000..cb24949317 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.commonmark.ext.maths + +import org.commonmark.node.CustomNode +import org.commonmark.node.Delimited + +class InlineMaths(private val delimiter: InlineDelimiter) : CustomNode(), Delimited { + enum class InlineDelimiter { + SINGLE_DOLLAR, ROUND_BRACKET_ESCAPED + } + + override fun getOpeningDelimiter(): String { + return when (delimiter) { + InlineDelimiter.SINGLE_DOLLAR -> "$" + InlineDelimiter.ROUND_BRACKET_ESCAPED -> "\\(" + } + } + + override fun getClosingDelimiter(): String { + return when (delimiter) { + InlineDelimiter.SINGLE_DOLLAR -> "$" + InlineDelimiter.ROUND_BRACKET_ESCAPED -> "\\)" + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.java deleted file mode 100644 index 31706b3f2d..0000000000 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2020 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.commonmark.ext.maths; - -import org.commonmark.Extension; -import org.commonmark.ext.maths.internal.DollarMathsDelimiterProcessor; -import org.commonmark.ext.maths.internal.MathsHtmlNodeRenderer; -import org.commonmark.parser.Parser; -import org.commonmark.renderer.NodeRenderer; -import org.commonmark.renderer.html.HtmlNodeRendererContext; -import org.commonmark.renderer.html.HtmlNodeRendererFactory; -import org.commonmark.renderer.html.HtmlRenderer; - -public class MathsExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension { - - private MathsExtension() { - } - - public static Extension create() { - return new MathsExtension(); - } - - @Override - public void extend(Parser.Builder parserBuilder) { - parserBuilder.customDelimiterProcessor(new DollarMathsDelimiterProcessor()); - } - - @Override - public void extend(HtmlRenderer.Builder rendererBuilder) { - rendererBuilder.nodeRendererFactory(new HtmlNodeRendererFactory() { - @Override - public NodeRenderer create(HtmlNodeRendererContext context) { - return new MathsHtmlNodeRenderer(context); - } - }); - } -} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.kt new file mode 100644 index 0000000000..4a5d4e440e --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.commonmark.ext.maths + +import org.commonmark.Extension +import org.commonmark.ext.maths.internal.DollarMathsDelimiterProcessor +import org.commonmark.ext.maths.internal.MathsHtmlNodeRenderer +import org.commonmark.parser.Parser +import org.commonmark.renderer.html.HtmlRenderer + +class MathsExtension private constructor() : Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension { + override fun extend(parserBuilder: Parser.Builder) { + parserBuilder.customDelimiterProcessor(DollarMathsDelimiterProcessor()) + } + + override fun extend(rendererBuilder: HtmlRenderer.Builder) { + rendererBuilder.nodeRendererFactory { context -> MathsHtmlNodeRenderer(context) } + } + + companion object { + fun create(): Extension { + return MathsExtension() + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.java deleted file mode 100644 index 809c070f29..0000000000 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2020 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.commonmark.ext.maths.internal; - -import org.commonmark.ext.maths.DisplayMaths; -import org.commonmark.ext.maths.InlineMaths; -import org.commonmark.node.Node; -import org.commonmark.node.Text; -import org.commonmark.parser.delimiter.DelimiterProcessor; -import org.commonmark.parser.delimiter.DelimiterRun; - -public class DollarMathsDelimiterProcessor implements DelimiterProcessor { - @Override - public char getOpeningCharacter() { - return '$'; - } - - @Override - public char getClosingCharacter() { - return '$'; - } - - @Override - public int getMinLength() { - return 1; - } - - @Override - public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) { - if (opener.length() == 1 && closer.length() == 1) - return 1; // inline - else if (opener.length() == 2 && closer.length() == 2) - return 2; // display - else - return 0; - } - - @Override - public void process(Text opener, Text closer, int delimiterUse) { - Node maths = delimiterUse == 1 ? new InlineMaths(InlineMaths.InlineDelimiter.SINGLE_DOLLAR) : - new DisplayMaths(DisplayMaths.DisplayDelimiter.DOUBLE_DOLLAR); - - Node tmp = opener.getNext(); - while (tmp != null && tmp != closer) { - Node next = tmp.getNext(); - maths.appendChild(tmp); - tmp = next; - } - - opener.insertAfter(maths); - } -} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt new file mode 100644 index 0000000000..a3daa26361 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.commonmark.ext.maths.internal + +import org.commonmark.ext.maths.DisplayMaths +import org.commonmark.ext.maths.InlineMaths +import org.commonmark.node.Text +import org.commonmark.parser.delimiter.DelimiterProcessor +import org.commonmark.parser.delimiter.DelimiterRun + +class DollarMathsDelimiterProcessor : DelimiterProcessor { + override fun getOpeningCharacter(): Char { + return '$' + } + + override fun getClosingCharacter(): Char { + return '$' + } + + override fun getMinLength(): Int { + return 1 + } + + override fun getDelimiterUse(opener: DelimiterRun, closer: DelimiterRun): Int { + return if (opener.length() == 1 && closer.length() == 1) 1 // inline + else if (opener.length() == 2 && closer.length() == 2) 2 // display + else 0 + } + + override fun process(opener: Text, closer: Text, delimiterUse: Int) { + val maths = if (delimiterUse == 1) InlineMaths(InlineMaths.InlineDelimiter.SINGLE_DOLLAR) else DisplayMaths(DisplayMaths.DisplayDelimiter.DOUBLE_DOLLAR) + var tmp = opener.next + while (tmp != null && tmp !== closer) { + val next = tmp.next + maths.appendChild(tmp) + tmp = next + } + opener.insertAfter(maths) + } +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.java deleted file mode 100644 index a84129cd28..0000000000 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2020 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.commonmark.ext.maths.internal; - -import org.commonmark.ext.maths.DisplayMaths; -import org.commonmark.node.Node; -import org.commonmark.node.Text; -import org.commonmark.renderer.html.HtmlNodeRendererContext; -import org.commonmark.renderer.html.HtmlWriter; - -import java.util.Collections; -import java.util.Map; - -public class MathsHtmlNodeRenderer extends MathsNodeRenderer { - private final HtmlNodeRendererContext context; - private final HtmlWriter html; - - public MathsHtmlNodeRenderer(HtmlNodeRendererContext context) { - this.context = context; - this.html = context.getWriter(); - } - - @Override - public void render(Node node) { - boolean display = node.getClass() == DisplayMaths.class; - Node contents = node.getFirstChild(); // should be the only child - String latex = ((Text) contents).getLiteral(); - Map attributes = context.extendAttributes(node, display ? "div" : "span", Collections.singletonMap("data-mx-maths", - latex)); - html.tag(display ? "div" : "span", attributes); - html.tag("code"); - context.render(contents); - html.tag("/code"); - html.tag(display ? "/div" : "/span"); - } -} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt new file mode 100644 index 0000000000..f46a21afd8 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.commonmark.ext.maths.internal + +import org.commonmark.ext.maths.DisplayMaths +import org.commonmark.node.Node +import org.commonmark.node.Text +import org.commonmark.renderer.html.HtmlNodeRendererContext +import org.commonmark.renderer.html.HtmlWriter +import java.util.Collections + +class MathsHtmlNodeRenderer(private val context: HtmlNodeRendererContext) : MathsNodeRenderer() { + private val html: HtmlWriter = context.writer + override fun render(node: Node) { + val display = node.javaClass == DisplayMaths::class.java + val contents = node.firstChild // should be the only child + val latex = (contents as Text).literal + val attributes = context.extendAttributes(node, if (display) "div" else "span", Collections.singletonMap("data-mx-maths", + latex)) + html.tag(if (display) "div" else "span", attributes) + html.tag("code") + context.render(contents) + html.tag("/code") + html.tag(if (display) "/div" else "/span") + } +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.java b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.kt similarity index 51% rename from matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.java rename to matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.kt index 4d2a35f33d..f6edd5385a 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.java +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.kt @@ -13,23 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.commonmark.ext.maths.internal -package org.commonmark.ext.maths.internal; +import org.commonmark.ext.maths.InlineMaths +import org.commonmark.ext.maths.DisplayMaths +import org.commonmark.ext.maths.internal.MathsNodeRenderer +import org.commonmark.node.Node +import org.commonmark.renderer.NodeRenderer +import java.util.HashSet -import org.commonmark.ext.maths.DisplayMaths; -import org.commonmark.ext.maths.InlineMaths; -import org.commonmark.node.Node; -import org.commonmark.renderer.NodeRenderer; - -import java.util.HashSet; -import java.util.Set; - -abstract class MathsNodeRenderer implements NodeRenderer { - @Override - public Set> getNodeTypes() { - final Set> types = new HashSet>(); - types.add(InlineMaths.class); - types.add(DisplayMaths.class); - return types; +abstract class MathsNodeRenderer : NodeRenderer { + override fun getNodeTypes(): Set> { + val types: MutableSet> = HashSet() + types.add(InlineMaths::class.java) + types.add(DisplayMaths::class.java) + return types } -} +} \ No newline at end of file From 2262cd4b6d08bc5644a45e557b00fb51caf717f5 Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Wed, 8 Sep 2021 17:01:12 +0100 Subject: [PATCH 04/13] Gate LaTeX maths behind labs flag --- .../app/features/html/EventHtmlRenderer.kt | 37 +++++++++++-------- .../features/settings/VectorPreferences.kt | 5 +++ vector/src/main/res/values/strings.xml | 1 + .../src/main/res/xml/vector_settings_labs.xml | 5 +++ 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt index e2fb385ae5..5c950b43e9 100644 --- a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt @@ -20,6 +20,7 @@ import android.content.Context import android.text.Spannable import androidx.core.text.toSpannable import im.vector.app.core.resources.ColorProvider +import im.vector.app.features.settings.VectorPreferences import io.noties.markwon.AbstractMarkwonPlugin import io.noties.markwon.Markwon import io.noties.markwon.MarkwonPlugin @@ -34,27 +35,33 @@ import javax.inject.Singleton @Singleton class EventHtmlRenderer @Inject constructor(htmlConfigure: MatrixHtmlPluginConfigure, - context: Context) { + context: Context, + private val vectorPreferences: VectorPreferences) { interface PostProcessor { fun afterRender(renderedText: Spannable) } - private val markwon = Markwon.builder(context) + private val builder = Markwon.builder(context) .usePlugin(HtmlPlugin.create(htmlConfigure)) - .usePlugin(object : AbstractMarkwonPlugin() { // Markwon expects maths to be in a specific format: https://noties.io/Markwon/docs/v4/ext-latex - override fun processMarkdown(markdown: String): String { - return markdown - .replace(Regex(""".*?""")) { matchResult -> "$$" + matchResult.groupValues[1] + "$$" } - .replace(Regex(""".*?""")) { matchResult -> "\n$$\n" + matchResult.groupValues[1] + "\n$$\n" } - } - }) - .usePlugin(MarkwonInlineParserPlugin.create()) - .usePlugin(JLatexMathPlugin.create(44F) { builder -> - builder.inlinesEnabled(true) - builder.theme().inlinePadding(JLatexMathTheme.Padding.symmetric(24, 8)) - }) - .build() + + private val markwon = if (vectorPreferences.latexMathsIsEnabled()) { + builder + .usePlugin(object : AbstractMarkwonPlugin() { // Markwon expects maths to be in a specific format: https://noties.io/Markwon/docs/v4/ext-latex + override fun processMarkdown(markdown: String): String { + return markdown + .replace(Regex(""".*?""")) { matchResult -> "$$" + matchResult.groupValues[1] + "$$" } + .replace(Regex(""".*?""")) { matchResult -> "\n$$\n" + matchResult.groupValues[1] + "\n$$\n" } + } + }) + .usePlugin(MarkwonInlineParserPlugin.create()) + .usePlugin(JLatexMathPlugin.create(44F) { builder -> + builder.inlinesEnabled(true) + builder.theme().inlinePadding(JLatexMathTheme.Padding.symmetric(24, 8)) + }) + } else { + builder + }.build() val plugins: List = markwon.plugins diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 0b7b495f48..1e673e7b4f 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -100,6 +100,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { private const val SETTINGS_SEND_MESSAGE_WITH_ENTER = "SETTINGS_SEND_MESSAGE_WITH_ENTER" private const val SETTINGS_ENABLE_CHAT_EFFECTS = "SETTINGS_ENABLE_CHAT_EFFECTS" private const val SETTINGS_SHOW_EMOJI_KEYBOARD = "SETTINGS_SHOW_EMOJI_KEYBOARD" + private const val SETTINGS_LABS_ENABLE_LATEX_MATHS = "SETTINGS_LABS_ENABLE_LATEX_MATHS" // Room directory private const val SETTINGS_ROOM_DIRECTORY_SHOW_ALL_PUBLIC_ROOMS = "SETTINGS_ROOM_DIRECTORY_SHOW_ALL_PUBLIC_ROOMS" @@ -337,6 +338,10 @@ class VectorPreferences @Inject constructor(private val context: Context) { return defaultPrefs.getBoolean(SETTINGS_LABS_UNREAD_NOTIFICATIONS_AS_TAB, false) } + fun latexMathsIsEnabled(): Boolean { + return defaultPrefs.getBoolean(SETTINGS_LABS_ENABLE_LATEX_MATHS, false) + } + fun failFast(): Boolean { return BuildConfig.DEBUG || (developerMode() && defaultPrefs.getBoolean(SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY, false)) } diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 453b5ba432..f96320175a 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -3595,4 +3595,5 @@ Link this email with your account %s in Settings to receive invites directly in Element. + Enable LaTeX mathematics diff --git a/vector/src/main/res/xml/vector_settings_labs.xml b/vector/src/main/res/xml/vector_settings_labs.xml index 6260f65fd9..e7f06bc3b3 100644 --- a/vector/src/main/res/xml/vector_settings_labs.xml +++ b/vector/src/main/res/xml/vector_settings_labs.xml @@ -50,6 +50,11 @@ android:key="SETTINGS_LABS_USE_RESTRICTED_JOIN_RULE" android:title="@string/labs_use_restricted_join_rule" android:summary="@string/labs_use_restricted_join_rule_desc"/> + + From cf1a93839f6fc1554d91b2a6d4098459c1e6b623 Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Wed, 8 Sep 2021 23:13:53 +0100 Subject: [PATCH 05/13] Use PrecomputedFutureTextSetterCompat --- .../main/java/im/vector/app/features/html/EventHtmlRenderer.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt index 5c950b43e9..35da5ca4d1 100644 --- a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt @@ -24,6 +24,7 @@ import im.vector.app.features.settings.VectorPreferences import io.noties.markwon.AbstractMarkwonPlugin import io.noties.markwon.Markwon import io.noties.markwon.MarkwonPlugin +import io.noties.markwon.PrecomputedFutureTextSetterCompat import io.noties.markwon.ext.latex.JLatexMathPlugin import io.noties.markwon.ext.latex.JLatexMathTheme import io.noties.markwon.html.HtmlPlugin @@ -61,7 +62,7 @@ class EventHtmlRenderer @Inject constructor(htmlConfigure: MatrixHtmlPluginConfi }) } else { builder - }.build() + }.textSetter(PrecomputedFutureTextSetterCompat.create()).build() val plugins: List = markwon.plugins From 0a498bee38bc60c3344077ecab8247cbfb531431 Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Fri, 24 Sep 2021 12:43:41 +0100 Subject: [PATCH 06/13] Fix lints and add changelog.d entry --- changelog.d/2133.feature | 1 + .../main/java/org/commonmark/ext/maths/DisplayMaths.kt | 4 ++-- .../src/main/java/org/commonmark/ext/maths/InlineMaths.kt | 2 +- .../main/java/org/commonmark/ext/maths/MathsExtension.kt | 2 +- .../ext/maths/internal/DollarMathsDelimiterProcessor.kt | 2 +- .../ext/maths/internal/MathsHtmlNodeRenderer.kt | 2 +- .../commonmark/ext/maths/internal/MathsNodeRenderer.kt | 4 ++-- .../java/im/vector/app/features/html/EventHtmlRenderer.kt | 8 ++++++-- 8 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 changelog.d/2133.feature diff --git a/changelog.d/2133.feature b/changelog.d/2133.feature new file mode 100644 index 0000000000..5649ca4cc6 --- /dev/null +++ b/changelog.d/2133.feature @@ -0,0 +1 @@ +Add labs support for rendering LaTeX maths (MSC2191) diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt index bf6a89a26a..a69649640f 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 New Vector Ltd + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,4 +21,4 @@ class DisplayMaths(private val delimiter: DisplayDelimiter) : CustomBlock() { enum class DisplayDelimiter { DOUBLE_DOLLAR, SQUARE_BRACKET_ESCAPED } -} \ No newline at end of file +} diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt index cb24949317..799626045d 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 New Vector Ltd + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.kt index 4a5d4e440e..18c0fc4284 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/MathsExtension.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 New Vector Ltd + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt index a3daa26361..55b27a21bc 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 New Vector Ltd + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt index f46a21afd8..94652ed7ad 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsHtmlNodeRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 New Vector Ltd + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.kt index f6edd5385a..d5ce47abeb 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/MathsNodeRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 New Vector Ltd + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,4 +29,4 @@ abstract class MathsNodeRenderer : NodeRenderer { types.add(DisplayMaths::class.java) return types } -} \ No newline at end of file +} diff --git a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt index 35da5ca4d1..2d832b60cc 100644 --- a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt @@ -51,8 +51,12 @@ class EventHtmlRenderer @Inject constructor(htmlConfigure: MatrixHtmlPluginConfi .usePlugin(object : AbstractMarkwonPlugin() { // Markwon expects maths to be in a specific format: https://noties.io/Markwon/docs/v4/ext-latex override fun processMarkdown(markdown: String): String { return markdown - .replace(Regex(""".*?""")) { matchResult -> "$$" + matchResult.groupValues[1] + "$$" } - .replace(Regex(""".*?""")) { matchResult -> "\n$$\n" + matchResult.groupValues[1] + "\n$$\n" } + .replace(Regex(""".*?""")) { + matchResult -> "$$" + matchResult.groupValues[1] + "$$" + } + .replace(Regex(""".*?""")) { + matchResult -> "\n$$\n" + matchResult.groupValues[1] + "\n$$\n" + } } }) .usePlugin(MarkwonInlineParserPlugin.create()) From c3480bfd1672805b60beead0d85fd962cc6f70b7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Dec 2021 16:47:46 +0100 Subject: [PATCH 07/13] Add summary to the setting --- vector/src/main/res/values/strings.xml | 1 + vector/src/main/res/xml/vector_settings_labs.xml | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 7580c1da63..40f561234c 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -3662,6 +3662,7 @@ %s in Settings to receive invites directly in Element. Enable LaTeX mathematics + Restart the application for the change to take effect. Create Poll diff --git a/vector/src/main/res/xml/vector_settings_labs.xml b/vector/src/main/res/xml/vector_settings_labs.xml index 2e8ed08bf4..f394d1923e 100644 --- a/vector/src/main/res/xml/vector_settings_labs.xml +++ b/vector/src/main/res/xml/vector_settings_labs.xml @@ -47,13 +47,14 @@ + android:summary="@string/labs_use_restricted_join_rule_desc" + android:title="@string/labs_use_restricted_join_rule" /> + android:summary="@string/restart_the_application_to_apply_changes" + android:title="@string/labs_enable_latex_maths" /> Date: Fri, 31 Dec 2021 17:01:11 +0100 Subject: [PATCH 08/13] Add group for dependency, and use latest markwon version --- dependencies.gradle | 2 +- dependencies_groups.gradle | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index b975abba0b..6cb5fac64c 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -14,7 +14,7 @@ def kotlinCoroutines = "1.5.2" def dagger = "2.40.5" def retrofit = "2.9.0" def arrow = "0.8.2" -def markwon = "4.3.1" +def markwon = "4.6.2" def moshi = "1.12.0" def lifecycle = "2.4.0" def flowBinding = "1.2.0" diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index 25a78bc0c3..7edf54fb50 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -179,6 +179,7 @@ ext.groups = [ 'org.sonatype.oss', 'org.testng', 'org.threeten', + 'ru.noties', 'xerces', 'xml-apis', ] From a80f8b96c151e30ba792a7c2710987a7ffe18f88 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 31 Dec 2021 17:35:53 +0100 Subject: [PATCH 09/13] Format --- .../java/im/vector/app/features/html/EventHtmlRenderer.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt index 2d832b60cc..36acad8854 100644 --- a/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/app/features/html/EventHtmlRenderer.kt @@ -35,9 +35,11 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class EventHtmlRenderer @Inject constructor(htmlConfigure: MatrixHtmlPluginConfigure, - context: Context, - private val vectorPreferences: VectorPreferences) { +class EventHtmlRenderer @Inject constructor( + htmlConfigure: MatrixHtmlPluginConfigure, + context: Context, + vectorPreferences: VectorPreferences +) { interface PostProcessor { fun afterRender(renderedText: Spannable) From 98df73325770cab1de34f44205262c40983806d0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Jan 2022 15:25:21 +0100 Subject: [PATCH 10/13] Split long line and use Kotlin style --- .../internal/DollarMathsDelimiterProcessor.kt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt index 55b27a21bc..cfd03fa8f1 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/internal/DollarMathsDelimiterProcessor.kt @@ -22,17 +22,11 @@ import org.commonmark.parser.delimiter.DelimiterProcessor import org.commonmark.parser.delimiter.DelimiterRun class DollarMathsDelimiterProcessor : DelimiterProcessor { - override fun getOpeningCharacter(): Char { - return '$' - } + override fun getOpeningCharacter() = '$' - override fun getClosingCharacter(): Char { - return '$' - } + override fun getClosingCharacter() = '$' - override fun getMinLength(): Int { - return 1 - } + override fun getMinLength() = 1 override fun getDelimiterUse(opener: DelimiterRun, closer: DelimiterRun): Int { return if (opener.length() == 1 && closer.length() == 1) 1 // inline @@ -41,7 +35,11 @@ class DollarMathsDelimiterProcessor : DelimiterProcessor { } override fun process(opener: Text, closer: Text, delimiterUse: Int) { - val maths = if (delimiterUse == 1) InlineMaths(InlineMaths.InlineDelimiter.SINGLE_DOLLAR) else DisplayMaths(DisplayMaths.DisplayDelimiter.DOUBLE_DOLLAR) + val maths = if (delimiterUse == 1) { + InlineMaths(InlineMaths.InlineDelimiter.SINGLE_DOLLAR) + } else { + DisplayMaths(DisplayMaths.DisplayDelimiter.DOUBLE_DOLLAR) + } var tmp = opener.next while (tmp != null && tmp !== closer) { val next = tmp.next From b39caeb04df454d07acc673ae6aea73f43aecb66 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 3 Jan 2022 15:27:59 +0100 Subject: [PATCH 11/13] 2 new enums --- .../src/main/java/org/commonmark/ext/maths/DisplayMaths.kt | 3 ++- .../src/main/java/org/commonmark/ext/maths/InlineMaths.kt | 3 ++- tools/check/forbidden_strings_in_code.txt | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt index a69649640f..b8ee36e724 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/DisplayMaths.kt @@ -19,6 +19,7 @@ import org.commonmark.node.CustomBlock class DisplayMaths(private val delimiter: DisplayDelimiter) : CustomBlock() { enum class DisplayDelimiter { - DOUBLE_DOLLAR, SQUARE_BRACKET_ESCAPED + DOUBLE_DOLLAR, + SQUARE_BRACKET_ESCAPED } } diff --git a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt index 799626045d..962b1b8cbf 100644 --- a/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt +++ b/matrix-sdk-android/src/main/java/org/commonmark/ext/maths/InlineMaths.kt @@ -20,7 +20,8 @@ import org.commonmark.node.Delimited class InlineMaths(private val delimiter: InlineDelimiter) : CustomNode(), Delimited { enum class InlineDelimiter { - SINGLE_DOLLAR, ROUND_BRACKET_ESCAPED + SINGLE_DOLLAR, + ROUND_BRACKET_ESCAPED } override fun getOpeningDelimiter(): String { diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index 6ca86be095..cbfaf20247 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -160,7 +160,7 @@ Formatter\.formatShortFileSize===1 # android\.text\.TextUtils ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt -enum class===114 +enum class===116 ### Do not import temporary legacy classes import org.matrix.android.sdk.internal.legacy.riot===3 From 48e15b1c36a25a3a00ab3d1b7338fe3e40b5ce3b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Jan 2022 16:15:25 +0100 Subject: [PATCH 12/13] Restore line deleted during GitHub conflict fixing by mistake --- tools/check/forbidden_strings_in_code.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index 2698429b13..7b869e8cd2 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -32,6 +32,8 @@ import static ### Rubbish from merge. Please delete those lines (sometimes in comment) +<<<<<<< +>>>>>>> ### carry return before "}". Please remove empty lines. \n\s*\n\s*\} From 10a63f8949758cdd490e19a156f3e641abd2e996 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 4 Jan 2022 16:16:13 +0100 Subject: [PATCH 13/13] Fix code after #4837 has been merged --- .../features/home/room/detail/timeline/item/MessageTextItem.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt index 2f7631006a..e9563aa69c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageTextItem.kt @@ -100,7 +100,7 @@ abstract class MessageTextItem : AbsMessageItem() { } else { null } - markwonPlugins?.forEach { plugin -> plugin.beforeSetText(holder.messageView, message as Spanned) } + markwonPlugins?.forEach { plugin -> plugin.beforeSetText(holder.messageView, message?.charSequence as Spanned) } super.bind(holder) holder.messageView.movementMethod = movementMethod renderSendState(holder.messageView, holder.messageView)