styling: introduce support for code blocks

This commit is contained in:
Daniel Gultsch 2017-11-07 23:28:14 +01:00
parent 2e3b5de6b6
commit e9587f73ce
2 changed files with 47 additions and 17 deletions

View File

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

View File

@ -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");