From a0bca08997cba7952cba49328ba09d71a6e8a1ba Mon Sep 17 00:00:00 2001 From: Millesimus Date: Sun, 22 Aug 2021 08:53:47 +0200 Subject: [PATCH] Rewrite QuoteHelper to integrate French quotes logics. Also reallow QuoteChars not followed by whitespace as indicated in XEP-0393. --- .../conversations/ui/util/QuoteHelper.java | 61 +++++++++++++++++-- .../siacs/conversations/utils/UIHelper.java | 35 +---------- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/util/QuoteHelper.java b/src/main/java/eu/siacs/conversations/ui/util/QuoteHelper.java index 2502f3682..4e4617cab 100644 --- a/src/main/java/eu/siacs/conversations/ui/util/QuoteHelper.java +++ b/src/main/java/eu/siacs/conversations/ui/util/QuoteHelper.java @@ -5,8 +5,32 @@ import eu.siacs.conversations.utils.UIHelper; public class QuoteHelper { + + public static final char QUOTE_CHAR = '>'; + public static final char QUOTE_END_CHAR = '<'; // used for one check, not for actual quoting + public static final char QUOTE_ALT_CHAR = '»'; + public static final char QUOTE_ALT_END_CHAR = '«'; + public static boolean isPositionQuoteCharacter(CharSequence body, int pos){ - return body.charAt(pos) == '>'; + // second part of logical check actually goes against the logic indicated in the method name, since it also checks for context + // but it's very useful + return body.charAt(pos) == QUOTE_CHAR || isPositionAltQuoteStart(body, pos); + } + + public static boolean isPositionQuoteEndCharacter(CharSequence body, int pos){ + return body.charAt(pos) == QUOTE_END_CHAR; + } + + public static boolean isPositionAltQuoteCharacter (CharSequence body, int pos){ + return body.charAt(pos) == QUOTE_ALT_CHAR; + } + + public static boolean isPositionAltQuoteEndCharacter(CharSequence body, int pos){ + return body.charAt(pos) == QUOTE_ALT_END_CHAR; + } + + public static boolean isPositionAltQuoteStart(CharSequence body, int pos){ + return isPositionAltQuoteCharacter(body, pos) && !isPositionFollowedByAltQuoteEnd(body, pos); } public static boolean isPositionFollowedByQuoteChar(CharSequence body, int pos) { @@ -19,10 +43,10 @@ public class QuoteHelper { } public static boolean isPositionQuoteStart (CharSequence body, int pos){ - return isPositionQuoteCharacter(body, pos) + return (isPositionQuoteCharacter(body, pos) && isPositionPrecededByPrequote(body, pos) - && (UIHelper.isPositionFollowedByWhitespace(body, pos) - || isPositionFollowedByQuoteChar(body, pos)); + && (UIHelper.isPositionFollowedByQuoteableCharacter(body, pos) + || isPositionFollowedByQuoteChar(body, pos))); } public static boolean bodyContainsQuoteStart (CharSequence body){ @@ -34,6 +58,24 @@ public class QuoteHelper { return false; } + public static boolean isPositionFollowedByAltQuoteEnd(CharSequence body, int pos) { + if (body.length() <= pos + 1 || Character.isWhitespace(body.charAt(pos + 1))) { + return false; + } + boolean previousWasWhitespace = false; + for (int i = pos + 1; i < body.length(); i++) { + char c = body.charAt(i); + if (c == '\n' || isPositionAltQuoteCharacter(body, i)) { + return false; + } else if (isPositionAltQuoteEndCharacter(body, i) && !previousWasWhitespace) { + return true; + } else { + previousWasWhitespace = Character.isWhitespace(c); + } + } + return false; + } + public static boolean isNestedTooDeeply (CharSequence line){ if (isPositionQuoteCharacter(line, 0)) { int nestingDepth = 1; @@ -48,4 +90,13 @@ public class QuoteHelper { } return false; } -} + + public static String replaceAltQuoteCharsInText(String text){ + for (int i = 0; i < text.length(); i++){ + if (isPositionAltQuoteStart(text, i)){ + text = text.substring(0, i) + QUOTE_CHAR + text.substring(i + 1); + } + } + return text; + } +} \ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index c293bcd12..4c2c0b585 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -329,7 +329,7 @@ public class UIHelper { continue; } char first = l.charAt(0); - if ((!QuoteHelper.isPositionQuoteStart(l, 0)) && first != '\u00bb') { + if ((!QuoteHelper.isPositionQuoteStart(l, 0))) { CharSequence line = CharSequenceUtils.trim(l); if (line.length() == 0) { continue; @@ -373,14 +373,6 @@ public class UIHelper { return input.length() > 256 ? StylingHelper.subSequence(input, 0, 256) : input; } - public static boolean isPositionFollowedByWhitespace(CharSequence body, int pos){ - return Character.isWhitespace(body.charAt(pos + 1)); - } - - public static boolean isPositionPrecededByWhitespace(CharSequence body, int pos){ - return Character.isWhitespace(body.charAt(pos -1 )); - } - public static boolean isPositionPrecededByBodyStart(CharSequence body, int pos){ // true if not a single linebreak before current position for (int i = pos - 1; i >= 0; i--){ @@ -395,10 +387,7 @@ public class UIHelper { if (isPositionPrecededByBodyStart(body, pos)){ return true; } - if (body.charAt(pos - 1) == '\n'){ - return true; - } - return false; + return body.charAt(pos - 1) == '\n'; } public static boolean isPositionFollowedByQuoteableCharacter(CharSequence body, int pos) { @@ -442,31 +431,13 @@ public class UIHelper { final char c = body.charAt(i); if (Character.isWhitespace(c)) { return false; - } else if (c == '<' || c == '>') { + } else if (QuoteHelper.isPositionQuoteCharacter(body, pos) || QuoteHelper.isPositionQuoteEndCharacter(body, pos)) { return body.length() == i + 1 || Character.isWhitespace(body.charAt(i + 1)); } } return false; } - public static boolean isPositionFollowedByQuote(CharSequence body, int pos) { - if (body.length() <= pos + 1 || Character.isWhitespace(body.charAt(pos + 1))) { - return false; - } - boolean previousWasWhitespace = false; - for (int i = pos + 1; i < body.length(); i++) { - char c = body.charAt(i); - if (c == '\n' || c == '»') { - return false; - } else if (c == '«' && !previousWasWhitespace) { - return true; - } else { - previousWasWhitespace = Character.isWhitespace(c); - } - } - return false; - } - public static String getDisplayName(MucOptions.User user) { Contact contact = user.getContact(); if (contact != null) {