styling: introduce support for code blocks
This commit is contained in:
parent
2e3b5de6b6
commit
e9587f73ce
|
@ -35,19 +35,29 @@ import java.util.List;
|
|||
|
||||
public class ImStyleParser {
|
||||
|
||||
final static List<Character> KEYWORDS = Arrays.asList('*', '_', '~', '`');
|
||||
final static List<Character> NO_SUB_PARSING_KEYWORDS = Arrays.asList('`');
|
||||
final static boolean ALLOW_EMPTY = false;
|
||||
private final static List<Character> KEYWORDS = Arrays.asList('*', '_', '~', '`');
|
||||
private final static List<Character> NO_SUB_PARSING_KEYWORDS = Arrays.asList('`');
|
||||
private final static List<Character> BLOCK_KEYWORDS = Arrays.asList('`');
|
||||
private final static boolean ALLOW_EMPTY = false;
|
||||
|
||||
public static List<Style> parse(CharSequence text) {
|
||||
return parse(text, 0, text.length() - 1);
|
||||
}
|
||||
|
||||
public static List<Style> parse(CharSequence text, int start, int end) {
|
||||
private static List<Style> parse(CharSequence text, int start, int end) {
|
||||
List<Style> styles = new ArrayList<>();
|
||||
for (int i = start; i <= end; ++i) {
|
||||
char c = text.charAt(i);
|
||||
if (KEYWORDS.contains(c) && precededByWhiteSpace(text, i, start) && !followedByWhitespace(text, i, end)) {
|
||||
if (BLOCK_KEYWORDS.contains(c) && isCharRepeatedTwoTimes(text, c, i + 1, end)) {
|
||||
int to = seekEndBlock(text, c, i + 3, end);
|
||||
if (to != -1 && (to != i + 5 || ALLOW_EMPTY)) {
|
||||
String keyword = String.valueOf(c) + String.valueOf(c) + String.valueOf(c);
|
||||
styles.add(new Style(keyword, i, to));
|
||||
i = to;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int to = seekEnd(text, c, i + 1, end);
|
||||
if (to != -1 && (to != i + 1 || ALLOW_EMPTY)) {
|
||||
styles.add(new Style(c, i, to));
|
||||
|
@ -61,6 +71,10 @@ public class ImStyleParser {
|
|||
return styles;
|
||||
}
|
||||
|
||||
private static boolean isCharRepeatedTwoTimes(CharSequence text, char c, int index, int end) {
|
||||
return index + 1 <= end && text.charAt(index) == c && text.charAt(index) == c;
|
||||
}
|
||||
|
||||
private static boolean precededByWhiteSpace(CharSequence text, int index, int start) {
|
||||
return index == start || Character.isWhitespace(text.charAt(index - 1));
|
||||
}
|
||||
|
@ -81,20 +95,34 @@ public class ImStyleParser {
|
|||
return -1;
|
||||
}
|
||||
|
||||
private static int seekEndBlock(CharSequence text, char needle, int start, int end) {
|
||||
for (int i = start; i <= end; ++i) {
|
||||
char c = text.charAt(i);
|
||||
if (c == needle && isCharRepeatedTwoTimes(text, needle, i + 1, end)) {
|
||||
return i + 2;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static class Style {
|
||||
|
||||
private final char c;
|
||||
private final String keyword;
|
||||
private final int start;
|
||||
private final int end;
|
||||
|
||||
public Style(char c, int start, int end) {
|
||||
this.c = c;
|
||||
public Style(char character, int start, int end) {
|
||||
this(String.valueOf(character), start, end);
|
||||
}
|
||||
|
||||
public Style(String keyword, int start, int end) {
|
||||
this.keyword = keyword;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public char getCharacter() {
|
||||
return c;
|
||||
public String getKeyword() {
|
||||
return keyword;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
|
|
|
@ -67,21 +67,23 @@ public class StylingHelper {
|
|||
|
||||
public static void format(final Editable editable, @ColorInt int textColor) {
|
||||
for (ImStyleParser.Style style : ImStyleParser.parse(editable)) {
|
||||
editable.setSpan(createSpanForStyle(style), style.getStart() + 1, style.getEnd(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
makeKeywordOpaque(editable, style.getStart(), style.getStart() + 1, textColor);
|
||||
makeKeywordOpaque(editable, style.getEnd(), style.getEnd() + 1, textColor);
|
||||
final int keywordLength = style.getKeyword().length();
|
||||
editable.setSpan(createSpanForStyle(style), style.getStart() + keywordLength, style.getEnd() - keywordLength + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
makeKeywordOpaque(editable, style.getStart(), style.getStart() + keywordLength, textColor);
|
||||
makeKeywordOpaque(editable, style.getEnd() - keywordLength + 1, style.getEnd() + 1, textColor);
|
||||
}
|
||||
}
|
||||
|
||||
private static ParcelableSpan createSpanForStyle(ImStyleParser.Style style) {
|
||||
switch (style.getCharacter()) {
|
||||
case '*':
|
||||
switch (style.getKeyword()) {
|
||||
case "*":
|
||||
return new StyleSpan(Typeface.BOLD);
|
||||
case '_':
|
||||
case "_":
|
||||
return new StyleSpan(Typeface.ITALIC);
|
||||
case '~':
|
||||
case "~":
|
||||
return new StrikethroughSpan();
|
||||
case '`':
|
||||
case "`":
|
||||
case "```":
|
||||
return new TypefaceSpan("monospace");
|
||||
default:
|
||||
throw new AssertionError("Unknown Style");
|
||||
|
|
Loading…
Reference in New Issue