aboutsummaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
authorscria1000 <91804886+scria1000@users.noreply.github.com>2022-11-03 10:07:25 +0000
committerGitHub <noreply@github.com>2022-11-03 10:07:25 +0000
commit20214ce32302b48e83404f66ba9ccb79c64830d0 (patch)
treef6d7917a6027764098d422c32d2d1d7e2c73cf96 /app/src
parente362f2ecf06f12be4ff511cb0f489abc880e7bc7 (diff)
downloadinfinity-for-reddit-20214ce32302b48e83404f66ba9ccb79c64830d0.tar
infinity-for-reddit-20214ce32302b48e83404f66ba9ccb79c64830d0.tar.gz
infinity-for-reddit-20214ce32302b48e83404f66ba9ccb79c64830d0.tar.bz2
infinity-for-reddit-20214ce32302b48e83404f66ba9ccb79c64830d0.tar.lz
infinity-for-reddit-20214ce32302b48e83404f66ba9ccb79c64830d0.tar.xz
infinity-for-reddit-20214ce32302b48e83404f66ba9ccb79c64830d0.tar.zst
infinity-for-reddit-20214ce32302b48e83404f66ba9ccb79c64830d0.zip
Superscript parser overhaul (#1162)
* Superscript parser overhaul * Make superscript work with tables * Fix some issues with Table compatibility * Some bug fixes * Re-enable Autolink
Diffstat (limited to '')
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java17
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java16
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java9
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/Superscript.java21
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptClosingInlineProcessor.java51
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptInlineProcessor.java32
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpening.java17
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningBracket.java31
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningInlineProcessor.java50
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningStorage.java38
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptPlugin.java206
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptSpan.java34
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java60
21 files changed, 453 insertions, 177 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java
index c9474bb2..bb2e43de 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java
@@ -178,12 +178,6 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA
binding.commentContentMarkdownView.setNestedScrollingEnabled(false);
int linkColor = mCustomThemeWrapper.getLinkColor();
MarkwonPlugin miscPlugin = new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
if (contentTypeface != null) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java
index 2ded838c..81276e23 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/FullMarkdownActivity.java
@@ -117,12 +117,6 @@ public class FullMarkdownActivity extends BaseActivity {
int spoilerBackgroundColor = markdownColor | 0xFF000000;
int linkColor = mCustomThemeWrapper.getLinkColor();
MarkwonPlugin miscPlugin = new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
if (typeface != null) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java
index 6cb65b28..00576c85 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/WikiActivity.java
@@ -149,12 +149,6 @@ public class WikiActivity extends BaseActivity {
int spoilerBackgroundColor = markdownColor | 0xFF000000;
int linkColor = mCustomThemeWrapper.getLinkColor();
MarkwonPlugin miscPlugin = new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
textView.setTextColor(markdownColor);
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java
index 1503a469..d7432db6 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsListingRecyclerViewAdapter.java
@@ -138,12 +138,6 @@ public class CommentsListingRecyclerViewAdapter extends PagedListAdapter<Comment
mCommentIconAndInfoColor = customThemeWrapper.getCommentIconAndInfoColor();
int linkColor = customThemeWrapper.getLinkColor();
MarkwonPlugin miscPlugin = new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
if (mActivity.contentTypeface != null) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java
index 34996b15..e28a579a 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/CommentsRecyclerViewAdapter.java
@@ -169,12 +169,6 @@ public class CommentsRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerVi
int commentSpoilerBackgroundColor = mCommentTextColor | 0xFF000000;
int linkColor = customThemeWrapper.getLinkColor();
MarkwonPlugin miscPlugin = new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
if (mActivity.contentTypeface != null) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java
index 12c24df8..915cc292 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/MessageRecyclerViewAdapter.java
@@ -28,8 +28,6 @@ import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
-import io.noties.markwon.html.HtmlPlugin;
-import io.noties.markwon.html.tag.SuperScriptHandler;
import io.noties.markwon.inlineparser.AutolinkInlineProcessor;
import io.noties.markwon.inlineparser.BangInlineProcessor;
import io.noties.markwon.inlineparser.HtmlInlineProcessor;
@@ -47,11 +45,10 @@ import ml.docilealligator.infinityforreddit.events.ChangeInboxCountEvent;
import ml.docilealligator.infinityforreddit.markdown.RedditHeadingPlugin;
import ml.docilealligator.infinityforreddit.markdown.SpoilerAwareMovementMethod;
import ml.docilealligator.infinityforreddit.markdown.SpoilerParserPlugin;
-import ml.docilealligator.infinityforreddit.markdown.SuperscriptInlineProcessor;
+import ml.docilealligator.infinityforreddit.markdown.SuperscriptPlugin;
import ml.docilealligator.infinityforreddit.message.FetchMessage;
import ml.docilealligator.infinityforreddit.message.Message;
import ml.docilealligator.infinityforreddit.message.ReadMessage;
-import ml.docilealligator.infinityforreddit.utils.Utils;
import retrofit2.Retrofit;
public class MessageRecyclerViewAdapter extends PagedListAdapter<Message, RecyclerView.ViewHolder> {
@@ -109,21 +106,10 @@ public class MessageRecyclerViewAdapter extends PagedListAdapter<Message, Recycl
// add tables support and replace with MarkdownUtils#commonPostMarkwonBuilder
mMarkwon = Markwon.builder(mActivity)
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
- plugin.excludeInlineProcessor(AutolinkInlineProcessor.class);
plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
plugin.excludeInlineProcessor(BangInlineProcessor.class);
- plugin.addInlineProcessor(new SuperscriptInlineProcessor());
- }))
- .usePlugin(HtmlPlugin.create(plugin -> {
- plugin.excludeDefaults(true).addHandler(new SuperScriptHandler());
}))
.usePlugin(new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
builder.linkResolver((view, link) -> {
@@ -139,6 +125,7 @@ public class MessageRecyclerViewAdapter extends PagedListAdapter<Message, Recycl
builder.linkColor(customThemeWrapper.getLinkColor());
}
})
+ .usePlugin(SuperscriptPlugin.create())
.usePlugin(SpoilerParserPlugin.create(mSecondaryTextColor, spoilerBackgroundColor))
.usePlugin(RedditHeadingPlugin.create())
.usePlugin(StrikethroughPlugin.create())
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java
index 1ad0ba21..de5468cf 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java
@@ -232,12 +232,6 @@ public class PostDetailRecyclerViewAdapter extends RecyclerView.Adapter<Recycler
int postSpoilerBackgroundColor = markdownColor | 0xFF000000;
int linkColor = customThemeWrapper.getLinkColor();
MarkwonPlugin miscPlugin = new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
if (mActivity.contentTypeface != null) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java
index de0898ae..2dc24c71 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PrivateMessagesDetailRecyclerViewAdapter.java
@@ -32,8 +32,6 @@ import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.core.MarkwonTheme;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
-import io.noties.markwon.html.HtmlPlugin;
-import io.noties.markwon.html.tag.SuperScriptHandler;
import io.noties.markwon.inlineparser.AutolinkInlineProcessor;
import io.noties.markwon.inlineparser.BangInlineProcessor;
import io.noties.markwon.inlineparser.HtmlInlineProcessor;
@@ -49,7 +47,7 @@ import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
import ml.docilealligator.infinityforreddit.markdown.RedditHeadingPlugin;
import ml.docilealligator.infinityforreddit.markdown.SpoilerAwareMovementMethod;
import ml.docilealligator.infinityforreddit.markdown.SpoilerParserPlugin;
-import ml.docilealligator.infinityforreddit.markdown.SuperscriptInlineProcessor;
+import ml.docilealligator.infinityforreddit.markdown.SuperscriptPlugin;
import ml.docilealligator.infinityforreddit.message.Message;
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
import ml.docilealligator.infinityforreddit.utils.Utils;
@@ -85,21 +83,10 @@ public class PrivateMessagesDetailRecyclerViewAdapter extends RecyclerView.Adapt
// add tables support and replace with MarkdownUtils#commonPostMarkwonBuilder
mMarkwon = Markwon.builder(viewPrivateMessagesActivity)
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
- plugin.excludeInlineProcessor(AutolinkInlineProcessor.class);
plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
plugin.excludeInlineProcessor(BangInlineProcessor.class);
- plugin.addInlineProcessor(new SuperscriptInlineProcessor());
- }))
- .usePlugin(HtmlPlugin.create(plugin -> {
- plugin.excludeDefaults(true).addHandler(new SuperScriptHandler());
}))
.usePlugin(new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
if (mViewPrivateMessagesActivity.contentTypeface != null) {
@@ -122,6 +109,7 @@ public class PrivateMessagesDetailRecyclerViewAdapter extends RecyclerView.Adapt
builder.linkColor(customThemeWrapper.getLinkColor());
}
})
+ .usePlugin(SuperscriptPlugin.create())
.usePlugin(StrikethroughPlugin.create())
.usePlugin(SpoilerParserPlugin.create(commentColor, commentColor | 0xFF000000))
.usePlugin(RedditHeadingPlugin.create())
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java
index c7d32b93..1fa0a8a5 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RulesRecyclerViewAdapter.java
@@ -53,12 +53,6 @@ public class RulesRecyclerViewAdapter extends RecyclerView.Adapter<RulesRecycler
mPrimaryTextColor = customThemeWrapper.getPrimaryTextColor();
int spoilerBackgroundColor = mPrimaryTextColor | 0xFF000000;
MarkwonPlugin miscPlugin = new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
if (activity.typeface != null) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java
index bc1a0ddd..475c7053 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/SidebarFragment.java
@@ -104,12 +104,6 @@ public class SidebarFragment extends Fragment {
int spoilerBackgroundColor = markdownColor | 0xFF000000;
MarkwonPlugin miscPlugin = new AbstractMarkwonPlugin() {
- @NonNull
- @Override
- public String processMarkdown(@NonNull String markdown) {
- return Utils.fixSuperScript(markdown);
- }
-
@Override
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
if (activity.contentTypeface != null) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java
index 68640220..ac432943 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/MarkdownUtils.java
@@ -11,8 +11,6 @@ import org.commonmark.ext.gfm.tables.TableBlock;
import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonPlugin;
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
-import io.noties.markwon.html.HtmlPlugin;
-import io.noties.markwon.html.tag.SuperScriptHandler;
import io.noties.markwon.inlineparser.AutolinkInlineProcessor;
import io.noties.markwon.inlineparser.BangInlineProcessor;
import io.noties.markwon.inlineparser.HtmlInlineProcessor;
@@ -39,15 +37,11 @@ public class MarkdownUtils {
@Nullable BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) {
return Markwon.builder(context)
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
- plugin.excludeInlineProcessor(AutolinkInlineProcessor.class);
plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
plugin.excludeInlineProcessor(BangInlineProcessor.class);
- plugin.addInlineProcessor(new SuperscriptInlineProcessor());
- }))
- .usePlugin(HtmlPlugin.create(plugin -> {
- plugin.excludeDefaults(true).addHandler(new SuperScriptHandler());
}))
.usePlugin(miscPlugin)
+ .usePlugin(SuperscriptPlugin.create())
.usePlugin(SpoilerParserPlugin.create(markdownColor, spoilerBackgroundColor))
.usePlugin(RedditHeadingPlugin.create())
.usePlugin(StrikethroughPlugin.create())
@@ -68,7 +62,6 @@ public class MarkdownUtils {
@Nullable BetterLinkMovementMethod.OnLinkLongClickListener onLinkLongClickListener) {
return Markwon.builder(context)
.usePlugin(MarkwonInlineParserPlugin.create(plugin -> {
- plugin.excludeInlineProcessor(AutolinkInlineProcessor.class);
plugin.excludeInlineProcessor(HtmlInlineProcessor.class);
plugin.excludeInlineProcessor(BangInlineProcessor.class);
}))
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/Superscript.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/Superscript.java
new file mode 100644
index 00000000..a2cb7b74
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/Superscript.java
@@ -0,0 +1,21 @@
+package ml.docilealligator.infinityforreddit.markdown;
+
+import org.commonmark.node.CustomNode;
+import org.commonmark.node.Visitor;
+
+public class Superscript extends CustomNode {
+ private boolean isBracketed;
+
+ @Override
+ public void accept(Visitor visitor) {
+ visitor.visit(this);
+ }
+
+ public boolean isBracketed() {
+ return isBracketed;
+ }
+
+ public void setBracketed(boolean bracketed) {
+ isBracketed = bracketed;
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptClosingInlineProcessor.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptClosingInlineProcessor.java
new file mode 100644
index 00000000..8bdf9c44
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptClosingInlineProcessor.java
@@ -0,0 +1,51 @@
+package ml.docilealligator.infinityforreddit.markdown;
+
+import static io.noties.markwon.inlineparser.InlineParserUtils.mergeChildTextNodes;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.commonmark.node.Node;
+
+import io.noties.markwon.inlineparser.InlineProcessor;
+
+public class SuperscriptClosingInlineProcessor extends InlineProcessor {
+ @NonNull
+ private final SuperscriptOpeningStorage superscriptOpeningStorage;
+
+ public SuperscriptClosingInlineProcessor(@NonNull SuperscriptOpeningStorage superscriptOpeningStorage) {
+ this.superscriptOpeningStorage = superscriptOpeningStorage;
+ }
+
+ @Override
+ public char specialCharacter() {
+ return ')';
+ }
+
+ @Nullable
+ @Override
+ protected Node parse() {
+ SuperscriptOpeningBracket superscriptOpening = superscriptOpeningStorage.pop(block);
+ if (superscriptOpening == null) {
+ return null;
+ }
+ index++;
+
+ Superscript superscript = new Superscript();
+ superscript.setBracketed(true);
+ Node node = superscriptOpening.node.getNext();
+ while (node != null) {
+ Node next = node.getNext();
+ superscript.appendChild(node);
+ node = next;
+ }
+
+ // Process delimiters such as emphasis inside spoiler
+ processDelimiters(superscriptOpening.previousDelimiter);
+ mergeChildTextNodes(superscript);
+ // We don't need the corresponding text node anymore, we turned it into a spoiler node
+ superscriptOpening.node.unlink();
+
+ return superscript;
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptInlineProcessor.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptInlineProcessor.java
deleted file mode 100644
index 93c9ab10..00000000
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptInlineProcessor.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package ml.docilealligator.infinityforreddit.markdown;
-
-import androidx.annotation.Nullable;
-
-import org.commonmark.node.HtmlInline;
-import org.commonmark.node.Node;
-
-import java.util.regex.Pattern;
-
-import io.noties.markwon.inlineparser.InlineProcessor;
-
-public class SuperscriptInlineProcessor extends InlineProcessor {
- private static final Pattern HTML_TAG = Pattern.compile("^</?sup>", Pattern.CASE_INSENSITIVE);
-
- @Override
- public char specialCharacter() {
- return '<';
- }
-
- @Nullable
- @Override
- protected Node parse() {
- String m = match(HTML_TAG);
- if (m != null) {
- HtmlInline node = new HtmlInline();
- node.setLiteral(m);
- return node;
- } else {
- return null;
- }
- }
-}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpening.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpening.java
new file mode 100644
index 00000000..9b8107cb
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpening.java
@@ -0,0 +1,17 @@
+package ml.docilealligator.infinityforreddit.markdown;
+
+import org.commonmark.node.Node;
+
+public class SuperscriptOpening {
+ /**
+ * Node that contains non-bracketed superscript opening markdown ({@code ^}).
+ */
+ public final Node node;
+
+ public final Integer start;
+
+ public SuperscriptOpening(Node node, int start) {
+ this.node = node;
+ this.start = start;
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningBracket.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningBracket.java
new file mode 100644
index 00000000..e47d43b0
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningBracket.java
@@ -0,0 +1,31 @@
+package ml.docilealligator.infinityforreddit.markdown;
+
+import org.commonmark.internal.Delimiter;
+import org.commonmark.node.Node;
+
+public class SuperscriptOpeningBracket {
+ /**
+ * Node that contains superscript opening bracket markdown ({@code ^(}).
+ */
+ public final Node node;
+
+ /**
+ * Previous superscript opening bracket.
+ */
+ public final SuperscriptOpeningBracket previous;
+
+ /**
+ * Previous delimiter (emphasis, etc) before this bracket.
+ */
+ public final Delimiter previousDelimiter;
+
+ public final Integer start;
+
+ public SuperscriptOpeningBracket(Node node, SuperscriptOpeningBracket previous, Delimiter previousDelimiter) {
+ this.node = node;
+ this.previous = previous;
+ this.previousDelimiter = previousDelimiter;
+ this.start = null;
+ }
+}
+
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningInlineProcessor.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningInlineProcessor.java
new file mode 100644
index 00000000..1224df85
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningInlineProcessor.java
@@ -0,0 +1,50 @@
+package ml.docilealligator.infinityforreddit.markdown;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.commonmark.node.Node;
+import org.commonmark.node.Text;
+
+import io.noties.markwon.inlineparser.InlineProcessor;
+
+public class SuperscriptOpeningInlineProcessor extends InlineProcessor {
+ @NonNull
+ private final SuperscriptOpeningStorage superscriptOpeningStorage;
+
+ public SuperscriptOpeningInlineProcessor(@NonNull SuperscriptOpeningStorage superscriptOpeningStorage) {
+ this.superscriptOpeningStorage = superscriptOpeningStorage;
+ }
+
+ @Override
+ public char specialCharacter() {
+ return '^';
+ }
+
+ @Nullable
+ @Override
+ protected Node parse() {
+ index++;
+ char c = peek();
+ if (c != '\0' && !Character.isWhitespace(c)) {
+ if (c == '(') {
+ index++;
+ Text node = text("^(");
+ superscriptOpeningStorage.add(block, node, lastDelimiter());
+ return node;
+ }
+
+ if (lastDelimiter() != null && lastDelimiter().canOpen && block.getLastChild() != null) {
+ if (lastDelimiter().node == this.block.getLastChild()) {
+ if (lastDelimiter().delimiterChar == peek()) {
+ index--;
+ return null;
+ }
+ }
+ }
+
+ return new Superscript();
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningStorage.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningStorage.java
new file mode 100644
index 00000000..ce0db58c
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptOpeningStorage.java
@@ -0,0 +1,38 @@
+package ml.docilealligator.infinityforreddit.markdown;
+
+import androidx.annotation.Nullable;
+
+import org.commonmark.internal.Delimiter;
+import org.commonmark.node.Node;
+
+public class SuperscriptOpeningStorage {
+ @Nullable
+ private SuperscriptOpeningBracket lastBracket;
+ private Node currentBlock;
+
+ public void clear() {
+ lastBracket = null;
+ }
+
+ public void add(Node block, Node node, Delimiter lastDelimiter) {
+ updateBlock(block);
+ lastBracket = new SuperscriptOpeningBracket(node, lastBracket, lastDelimiter);
+ }
+
+ @Nullable
+ public SuperscriptOpeningBracket pop(Node block) {
+ updateBlock(block);
+ SuperscriptOpeningBracket opening = lastBracket;
+ if (opening != null) {
+ lastBracket = opening.previous;
+ }
+ return opening;
+ }
+
+ private void updateBlock(Node block) {
+ if (block != currentBlock) {
+ clear();
+ }
+ currentBlock = block;
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptPlugin.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptPlugin.java
new file mode 100644
index 00000000..1a5f3526
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptPlugin.java
@@ -0,0 +1,206 @@
+package ml.docilealligator.infinityforreddit.markdown;
+
+import android.text.Spannable;
+import android.text.Spanned;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import org.commonmark.ext.gfm.tables.TableCell;
+import org.commonmark.node.Node;
+import org.commonmark.node.Paragraph;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.noties.markwon.AbstractMarkwonPlugin;
+import io.noties.markwon.MarkwonSpansFactory;
+import io.noties.markwon.MarkwonVisitor;
+import io.noties.markwon.core.spans.CodeSpan;
+import io.noties.markwon.core.spans.TextViewSpan;
+import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
+
+public class SuperscriptPlugin extends AbstractMarkwonPlugin {
+ private final SuperscriptOpeningStorage superscriptOpeningBracketStorage;
+ private final List<SuperscriptOpening> superscriptOpeningList;
+
+ SuperscriptPlugin() {
+ this.superscriptOpeningBracketStorage = new SuperscriptOpeningStorage();
+ this.superscriptOpeningList = new ArrayList<>();
+ }
+
+ @NonNull
+ public static SuperscriptPlugin create() {
+ return new SuperscriptPlugin();
+ }
+
+ private static char peek(int index, CharSequence input) {
+ return index >= 0 && index < input.length() ? input.charAt(index) : '\0';
+ }
+
+ private static List<SpanInfo> getSpans(Spannable spannable, int start, int end) {
+ var spanArray = spannable.getSpans(start, end, Object.class);
+ List<SpanInfo> spanList = new ArrayList<>();
+ for (int i = spanArray.length - 1; i >= 0; i--) {
+ Object span = spanArray[i];
+ int spanStart = spannable.getSpanStart(span);
+ int spanEnd = spannable.getSpanEnd(span);
+ int spanFlags = spannable.getSpanFlags(span);
+ spanList.add(new SpanInfo(span, spanStart, spanEnd, spanFlags));
+ }
+ return spanList;
+ }
+
+ private static SpanInfo matchSuperscriptAtPosition(List<SpanInfo> spans, int value) {
+ for (var span : spans)
+ if (span.what.getClass() == SuperscriptSpan.class && !((SuperscriptSpan) span.what).isBracketed && span.start <= value && value <= span.end)
+ return span;
+ return null;
+ }
+
+ private static SpanInfo matchSpanAtPosition(List<SpanInfo> spans, int value, Object spanClass) {
+ for (var span : spans)
+ if (span.what.getClass() == spanClass && span.start <= value && value <= span.end)
+ return span;
+ return null;
+ }
+
+ private static SpanInfo matchNonTextSpanAtBoundary(List<SpanInfo> spans, int value) {
+ for (var span : spans)
+ if ((span.end == value || span.start == value) && span.what.getClass() != CodeSpan.class && span.what.getClass() != SuperscriptSpan.class && span.what.getClass() != TextViewSpan.class)
+ return span;
+ return null;
+ }
+
+ @Override
+ public void configure(@NonNull Registry registry) {
+ registry.require(MarkwonInlineParserPlugin.class, plugin -> {
+ plugin.factoryBuilder().addInlineProcessor(new SuperscriptOpeningInlineProcessor(superscriptOpeningBracketStorage));
+ plugin.factoryBuilder().addInlineProcessor(new SuperscriptClosingInlineProcessor(superscriptOpeningBracketStorage));
+ }
+ );
+ }
+
+ @Override
+ public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
+ builder.setFactory(Superscript.class, (config, renderProps) -> new SuperscriptSpan(true));
+ }
+
+ @Override
+ public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
+ builder.on(Superscript.class, new MarkwonVisitor.NodeVisitor<>() {
+ int depth = 0;
+
+ @Override
+ public void visit(@NonNull MarkwonVisitor visitor, @NonNull Superscript superscript) {
+ int start = visitor.length();
+
+ if (!superscript.isBracketed()) {
+ visitor.builder().setSpan(new SuperscriptSpan(false), start, start + 1); // Workaround for Table Plugin
+ superscriptOpeningList.add(new SuperscriptOpening(superscript, start));
+ return;
+ }
+
+ depth++;
+ visitor.visitChildren(superscript);
+ depth--;
+ if (depth == 0) {
+ int end = visitor.builder().length();
+ var spans = visitor.builder().getSpans(start, end);
+ for (var span : spans) {
+ if (span.what instanceof CodeSpan) {
+ if (span.end <= end) {
+ visitor.builder().setSpan(new SuperscriptSpan(true), start, span.start);
+ }
+ start = span.end;
+ }
+ }
+ if (start < end) {
+ visitor.setSpansForNode(superscript, start);
+ }
+ }
+ }
+ });
+ }
+
+ @Override
+ public void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor) {
+ superscriptOpeningBracketStorage.clear();
+ }
+
+ @Override
+ public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
+ if (superscriptOpeningList.size() == 0 || !(markdown instanceof Spannable)) {
+ return;
+ }
+
+ var spannable = (Spannable) markdown;
+ var spans = getSpans(spannable, 0, spannable.length());
+ final String text = spannable.toString();
+
+ outerLoop:
+ for (int i = 0; i < superscriptOpeningList.size(); i++) {
+ SuperscriptOpening opening = superscriptOpeningList.get(i);
+ SuperscriptOpening nextOpening = i + 1 < superscriptOpeningList.size() ? superscriptOpeningList.get(i + 1) : null;
+
+ // Workaround for Table Plugin
+ var superscriptMarker = matchSuperscriptAtPosition(spans, opening.start);
+ if (superscriptMarker == null)
+ return;
+ spannable.removeSpan(superscriptMarker.what);
+ spans.remove(superscriptMarker);
+
+ boolean isNextOpeningOfLocalNode = nextOpening != null && opening.node.getParent().equals(nextOpening.node.getParent());
+ if (opening.start >= text.length() || (matchSpanAtPosition(spans, opening.start, CodeSpan.class) == null && Character.isWhitespace(text.charAt(opening.start))) || (isNextOpeningOfLocalNode && opening.start.equals(nextOpening.start))) {
+ superscriptOpeningList.remove(i);
+ i--;
+ continue;
+ }
+
+ boolean isChildOfDelimited = !(opening.node.getParent() == null || opening.node.getParent() instanceof Paragraph || opening.node.getParent() instanceof TableCell);
+ int openingStart = opening.start;
+ for (int j = opening.start; j <= text.length(); j++) {
+ char currentChar = peek(j, text);
+ SpanInfo codeSpanAtPosition = matchSpanAtPosition(spans, j, CodeSpan.class);
+ SpanInfo nonTextSpanAtBoundary = matchNonTextSpanAtBoundary(spans, j);
+ // When we reach the end position of, for example, an Emphasis
+ // Check whether the superscript originated from inside this Emphasis
+ // If so, stop further spanning of the current Superscript
+ boolean isInsideDelimited = nonTextSpanAtBoundary != null && openingStart != j && j == nonTextSpanAtBoundary.end && (openingStart > nonTextSpanAtBoundary.start || isChildOfDelimited);
+ if (codeSpanAtPosition != null) {
+ if (openingStart < j) {
+ spannable.setSpan(new SuperscriptSpan(false), openingStart, j, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ //Skip to end of CodeSpan
+ j = codeSpanAtPosition.end;
+ currentChar = peek(j, text);
+ if (currentChar == '\0' || Character.isWhitespace(currentChar) || (isNextOpeningOfLocalNode && j == nextOpening.start) || isInsideDelimited) {
+ superscriptOpeningList.remove(i);
+ i--;
+ continue outerLoop;
+ }
+ openingStart = j;
+ } else if (currentChar == '\0' || Character.isWhitespace(currentChar) || isInsideDelimited) {
+ spannable.setSpan(new SuperscriptSpan(false), openingStart, j, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ superscriptOpeningList.remove(i);
+ i--;
+ continue outerLoop;
+ }
+ }
+ }
+ }
+
+ private static class SpanInfo {
+ public final Object what;
+ public final int start;
+ public final int end;
+ public final int flags;
+
+ private SpanInfo(Object what, int start, int end, int flags) {
+ this.what = what;
+ this.start = start;
+ this.end = end;
+ this.flags = flags;
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptSpan.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptSpan.java
new file mode 100644
index 00000000..8ea30317
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SuperscriptSpan.java
@@ -0,0 +1,34 @@
+package ml.docilealligator.infinityforreddit.markdown;
+
+import android.text.TextPaint;
+import android.text.style.MetricAffectingSpan;
+
+import androidx.annotation.NonNull;
+
+public class SuperscriptSpan extends MetricAffectingSpan {
+ private static final float SCRIPT_DEF_TEXT_SIZE_RATIO = .75F;
+ public final boolean isBracketed;
+
+ public SuperscriptSpan() {
+ this.isBracketed = false;
+ }
+
+ public SuperscriptSpan(boolean isBracketed) {
+ this.isBracketed = isBracketed;
+ }
+
+ @Override
+ public void updateDrawState(TextPaint tp) {
+ apply(tp);
+ }
+
+ @Override
+ public void updateMeasureState(@NonNull TextPaint tp) {
+ apply(tp);
+ }
+
+ private void apply(TextPaint paint) {
+ paint.setTextSize(paint.getTextSize() * SCRIPT_DEF_TEXT_SIZE_RATIO);
+ paint.baselineShift += (int) (paint.ascent() / 2);
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java
index a663cfb4..39aadc17 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/Utils.java
@@ -83,69 +83,9 @@ public final class Utils {
regexed = REGEX_PATTERNS[1].matcher(regexed).replaceAll("[$0](https://www.reddit.com/$0)");
regexed = REGEX_PATTERNS[2].matcher(regexed).replaceAll("^");
- //return fixSuperScript(regexed);
- // We don't want to fix super scripts here because we need the original markdown later for editing posts
return regexed;
}
- public static String fixSuperScript(String regexedMarkdown) {
- StringBuilder regexed = new StringBuilder(regexedMarkdown);
- boolean hasBracket = false;
- int nCarets = 0;
- int newLines = 0;
- for (int i = 0; i < regexed.length(); i++) {
- char currentChar = regexed.charAt(i);
- if (hasBracket && currentChar == '\n') {
- newLines++;
- if (newLines > 1) {
- hasBracket = false;
- nCarets = 0;
- newLines = 0;
- }
- } else if (currentChar == '^') {
- if (!(i > 0 && regexed.charAt(i - 1) == '\\')) {
- if (nCarets == 0 && i < regexed.length() - 1 && regexed.charAt(i + 1) == '(') {
- regexed.replace(i, i + 2, "<sup>");
- hasBracket = true;
- } else {
- regexed.replace(i, i + 1, "<sup>");
- }
- nCarets++;
- }
- } else if (hasBracket && currentChar == ')') {
- if (i > 0 && regexed.charAt(i - 1) == '\\') {
- hasBracket = false;
- nCarets--;
- continue;
- }
- hasBracket = false;
- regexed.replace(i, i + 1, "</sup>");
- nCarets--;
- } else if (!hasBracket && currentChar == '\n') {
- for (int j = 0; j < nCarets; j++) {
- regexed.insert(i, "</sup>");
- i += 6;
- }
- nCarets = 0;
- } else if (!hasBracket && Character.isWhitespace(currentChar)) {
- for (int j = 0; j < nCarets; j++) {
- regexed.insert(i, "</sup>");
- i += 6;
- }
- nCarets = 0;
- } else {
- newLines = 0;
- }
- }
- if (!hasBracket) {
- for (int j = 0; j < nCarets; j++) {
- regexed.append("</sup>");
- }
- }
-
- return regexed.toString();
- }
-
public static String parseInlineGifInComments(String markdown) {
StringBuilder markdownStringBuilder = new StringBuilder(markdown);
Pattern inlineGifPattern = REGEX_PATTERNS[3];