Rewrite QuoteHelper to integrate French quotes logics. Also reallow QuoteChars not followed by whitespace as indicated in XEP-0393.

This commit is contained in:
Millesimus 2021-08-22 08:53:47 +02:00 committed by Daniel Gultsch
parent 748443cd4e
commit a0bca08997
2 changed files with 59 additions and 37 deletions

View File

@ -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;
}
}

View File

@ -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) {