1package eu.siacs.conversations.ui.util;
2
3import eu.siacs.conversations.Config;
4import eu.siacs.conversations.utils.UIHelper;
5
6public class QuoteHelper {
7
8
9 public static final char QUOTE_CHAR = '>';
10 public static final char QUOTE_END_CHAR = '<'; // used for one check, not for actual quoting
11 public static final char QUOTE_ALT_CHAR = '»';
12 public static final char QUOTE_ALT_END_CHAR = '«';
13
14 public static boolean isPositionQuoteCharacter(CharSequence body, int pos) {
15 // second part of logical check actually goes against the logic indicated in the method name, since it also checks for context
16 // but it's very useful
17 return body.charAt(pos) == QUOTE_CHAR || isPositionAltQuoteStart(body, pos);
18 }
19
20 public static boolean isPositionQuoteEndCharacter(CharSequence body, int pos) {
21 return body.charAt(pos) == QUOTE_END_CHAR;
22 }
23
24 public static boolean isPositionAltQuoteCharacter(CharSequence body, int pos) {
25 return body.charAt(pos) == QUOTE_ALT_CHAR;
26 }
27
28 public static boolean isPositionAltQuoteEndCharacter(CharSequence body, int pos) {
29 return body.charAt(pos) == QUOTE_ALT_END_CHAR;
30 }
31
32 public static boolean isPositionAltQuoteStart(CharSequence body, int pos) {
33 return isPositionAltQuoteCharacter(body, pos) && !isPositionFollowedByAltQuoteEnd(body, pos);
34 }
35
36 public static boolean isPositionFollowedByQuoteChar(CharSequence body, int pos) {
37 return body.length() > pos + 1 && isPositionQuoteCharacter(body, pos + 1);
38 }
39
40 // 'Prequote' means anything we require or can accept in front of a QuoteChar
41 public static boolean isPositionPrecededByPreQuote(CharSequence body, int pos) {
42 return UIHelper.isPositionPrecededByLineStart(body, pos);
43 }
44
45 public static boolean isPositionQuoteStart(CharSequence body, int pos) {
46 return (isPositionQuoteCharacter(body, pos)
47 && isPositionPrecededByPreQuote(body, pos)
48 && (UIHelper.isPositionFollowedByQuoteableCharacter(body, pos)
49 || isPositionFollowedByQuoteChar(body, pos)));
50 }
51
52 public static boolean bodyContainsQuoteStart(CharSequence body) {
53 for (int i = 0; i < body.length(); i++) {
54 if (isPositionQuoteStart(body, i)) {
55 return true;
56 }
57 }
58 return false;
59 }
60
61 public static boolean isPositionFollowedByAltQuoteEnd(CharSequence body, int pos) {
62 if (body.length() <= pos + 1 || Character.isWhitespace(body.charAt(pos + 1))) {
63 return false;
64 }
65 boolean previousWasWhitespace = false;
66 for (int i = pos + 1; i < body.length(); i++) {
67 char c = body.charAt(i);
68 if (c == '\n' || isPositionAltQuoteCharacter(body, i)) {
69 return false;
70 } else if (isPositionAltQuoteEndCharacter(body, i) && !previousWasWhitespace) {
71 return true;
72 } else {
73 previousWasWhitespace = Character.isWhitespace(c);
74 }
75 }
76 return false;
77 }
78
79 public static boolean isNestedTooDeeply(CharSequence line) {
80 if (isPositionQuoteStart(line, 0)) {
81 int nestingDepth = 1;
82 for (int i = 1; i < line.length(); i++) {
83 if (isPositionQuoteStart(line, i)) {
84 nestingDepth++;
85 }
86 if (nestingDepth > (Config.QUOTING_MAX_DEPTH - 1)) {
87 return true;
88 }
89 }
90 }
91 return false;
92 }
93
94 public static String replaceAltQuoteCharsInText(String text) {
95 for (int i = 0; i < text.length(); i++) {
96 if (isPositionAltQuoteStart(text, i)) {
97 text = text.substring(0, i) + QUOTE_CHAR + text.substring(i + 1);
98 }
99 }
100 return text;
101 }
102}