diff options
-rw-r--r-- | app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java | 118 |
1 files changed, 39 insertions, 79 deletions
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java index 1cca0cfe..3a05b71c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java @@ -3,6 +3,7 @@ package ml.docilealligator.infinityforreddit.markdown; import android.graphics.Color; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.util.Pair; import android.widget.TextView; import androidx.annotation.NonNull; @@ -13,8 +14,7 @@ import org.commonmark.node.HtmlBlock; import org.commonmark.node.HtmlInline; import org.commonmark.parser.Parser; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.ArrayList; import java.util.Set; import java.util.Stack; @@ -52,21 +52,21 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { public void afterSetText(@NonNull TextView textView) { textView.setHighlightColor(Color.TRANSPARENT); - if(textView.getText().length() < 5) { + if (textView.getText().length() < 5) { return; } SpannableStringBuilder markdownStringBuilder = new SpannableStringBuilder(textView.getText()); - LinkedHashMap<Integer, Integer> spoilers = parse(markdownStringBuilder); - if(spoilers.size() == 0) { + ArrayList<Pair<Integer, Integer>> spoilers = parse(markdownStringBuilder); + if (spoilers.size() == 0) { return; } - int offset = 2; - for (Map.Entry<Integer, Integer> entry : spoilers.entrySet()) { - int spoilerStart = entry.getKey() - offset; - int spoilerEnd = entry.getValue() - offset; + int offset = 2; + for (Pair<Integer, Integer> spoiler : spoilers) { + int spoilerStart = spoiler.first - offset; + int spoilerEnd = spoiler.second - offset; // Try not to set a spoiler span if it's inside a CodeSpan CodeSpan[] codeSpans = markdownStringBuilder.getSpans(spoilerStart, spoilerEnd, CodeSpan.class); @@ -78,6 +78,7 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { SpoilerSpan spoilerSpan = new SpoilerSpan(textColor, backgroundColor); markdownStringBuilder.setSpan(spoilerSpan, spoilerStart, spoilerEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); offset += 4; + continue; } for (CodeSpan codeSpan : codeSpans) { @@ -108,7 +109,7 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { } } } - if(offset > 2) { + if (offset > 2) { textView.setText(markdownStringBuilder); } } @@ -117,86 +118,45 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { // Don't allow more than one new line after every non-blank line // Try not to care about recursing spoilers, we just want the outermost spoiler because // spoiler revealing-hiding breaks with recursing spoilers - private LinkedHashMap<Integer, Integer> parse(SpannableStringBuilder markdown) { + private ArrayList<Pair<Integer, Integer>> parse(SpannableStringBuilder markdown) { final int MAX_NEW_LINE = 1; - var openSpoilerStack = new Stack<Integer>(); - var closedSpoilerMap = new LinkedHashMap<Integer, Integer>(); - int variable_max_depth = calculateBalance(0, markdown) + 1; + int length = markdown.length(); + Stack<Integer> openSpoilerStack = new Stack<>(); + ArrayList<Pair<Integer, Integer>> closedSpoilers = new ArrayList<>(); int new_lines = 0; - int depth = 0; - for (int i = 0; i < markdown.length(); i++) { - if (markdown.charAt(i) == '\u2000' || markdown.charAt(i) == '\t') { - continue; - } else if (markdown.charAt(i) == '>' && (i + 1) < markdown.length() && markdown.charAt(i + 1) == '!') { - openSpoilerStack.push(i + 1); - depth++; - } else if (openSpoilerStack.size() > 0 - && markdown.charAt(i) == '!' && (i + 1) < markdown.length() - && markdown.charAt(i + 1) == '<') { - var pos = i + 1; - for (int j = 0; j < depth; j++) { - if (!openSpoilerStack.isEmpty()) pos = openSpoilerStack.peek(); - if (pos + 1 <= i) { - if (!openSpoilerStack.isEmpty()) pos = openSpoilerStack.peek(); - break; - } else { - if (!openSpoilerStack.isEmpty()) pos = openSpoilerStack.pop(); - } - } - if (depth <= variable_max_depth && pos + 1 <= i) //Spoiler content cannot be zero or less length - { - openSpoilerStack.clear(); - closedSpoilerMap.put(pos + 1, i); - } - depth--; - } else if (markdown.charAt(i) == '\n') { + for (int i = 0; i < length; i++) { + if (markdown.charAt(i) == '\n') { new_lines++; - if (openSpoilerStack.size() >= 1 && new_lines > MAX_NEW_LINE) { + if (new_lines > MAX_NEW_LINE) { openSpoilerStack.clear(); new_lines = 0; - depth = 0; - variable_max_depth = calculateBalance(i, markdown) + 1; } - } else { + } else if ((markdown.charAt(i) != '>') + && (markdown.charAt(i) != '<') + && (markdown.charAt(i) != '!')) { new_lines = 0; - } - - if (openSpoilerStack.size() >= 32) // No - { - openSpoilerStack.clear(); - closedSpoilerMap.clear(); - continue; - } - } - return closedSpoilerMap; - } - - private int calculateBalance(int index, SpannableStringBuilder line) { - final int MAX_NEW_LINE = 1; - int new_lines = 0; - int opening = 0; - int closing = 0; - for (int i = index; i < line.length(); i++) { - if (line.charAt(i) == '\u0020' || line.charAt(i) == '\t') { - continue; - } else if (line.charAt(i) == '>' - && (i + 1) < line.length() - && line.charAt(i + 1) == '!') { - opening++; - } else if (line.charAt(i) == '!' && (i + 1) < line.length() - && line.charAt(i + 1) == '<') { - closing++; - } else if (line.charAt(i) == '\n') { - new_lines++; - if (new_lines > MAX_NEW_LINE) { - break; + } else if ((i + 1 < length) + && markdown.charAt(i) == '>' + && markdown.charAt(i + 1) == '!') { + openSpoilerStack.push(i + 2); + } else if ((i + 1 < length) && (i - 1 >= 0) + && openSpoilerStack.size() > 0 + && markdown.charAt(i - 1) != '>' + && markdown.charAt(i) == '!' + && markdown.charAt(i + 1) == '<') { + var pos = openSpoilerStack.pop(); + if (!closedSpoilers.isEmpty() + && closedSpoilers.get(closedSpoilers.size() - 1).first > pos + && closedSpoilers.get(closedSpoilers.size() - 1).second < i) { + closedSpoilers.remove(closedSpoilers.size() - 1); + } + if (pos != i) { + closedSpoilers.add(Pair.create(pos, i)); } } else { new_lines = 0; - continue; } } - return Math.abs(opening - closing); + return closedSpoilers; } - } |