feat: brackets matching

This commit is contained in:
hyb1996 2018-02-26 13:12:36 +08:00
parent 445bcfa462
commit 3b2aac78fd
8 changed files with 160 additions and 17 deletions

View File

@ -11,7 +11,18 @@
},
"tokenColors": [
{
"scope": [
"scope": "bracket.matched",
"settings": {
"foreground": "#76ff03"
}
},
{
"scope": "error",
"settings": {
"foreground": "#f44336"
}
},
{ "scope": [
"meta.embedded",
"source.groovy.embedded"
],

View File

@ -7,6 +7,18 @@
"foreground": "#333333"
}
},
{
"scope": "bracket.matched",
"settings": {
"foreground": "#76ff03"
}
},
{
"scope": "error",
"settings": {
"foreground": "#f44336"
}
},
{
"scope": [
"meta.embedded",
@ -487,7 +499,6 @@
"editor.background": "#F5F5F5",
"editor.foreground": "#000000",
"editor.lineHighlightBackground": "#E4F6D4",
"focusBorder": "#A6B39B",
"pickerGroup.foreground": "#A6B39B",
"pickerGroup.border": "#749351",

View File

@ -46,4 +46,12 @@ public class TokenColor {
public void setSettings(TokenColorSettings settings) {
mSettings = settings;
}
@Override
public String toString() {
return "TokenColor{" +
"scope=" + mScope +
", settings=" + mSettings.getForeground() +
'}';
}
}

View File

@ -32,4 +32,6 @@ public class TokenColorSettings {
public void setFontStyle(String fontStyle) {
mFontStyle = fontStyle;
}
}

View File

@ -0,0 +1,63 @@
package com.stardust.scriptdroid.ui.edit.editor;
/**
* Created by Stardust on 2018/2/25.
*/
public class BracketMatching {
public static int UNMATCHED_BRACKET = -2;
public static int BRACKET_NOT_FOUND = -1;
private static final char[] PAIR_LEFT = {'(', '{', '['};
private static final char[] PAIR_RIGHT = {')', '}', ')'};
public static int bracketMatching(CharSequence text, int index) {
char ch = text.charAt(index);
for (int i = 0; i < PAIR_LEFT.length; i++) {
if (PAIR_LEFT[i] == ch) {
return findRightBracket(text, index + 1, PAIR_LEFT[i], PAIR_RIGHT[i]);
}
}
for (int i = 0; i < PAIR_RIGHT.length; i++) {
if (PAIR_RIGHT[i] == ch) {
return findLeftBracket(text, index - 1, PAIR_LEFT[i], PAIR_RIGHT[i]);
}
}
return BRACKET_NOT_FOUND;
}
public static int findLeftBracket(CharSequence text, int index, char left, char right) {
int rightBracketCount = 0;
for (int i = index; i >= 0; i--) {
char ch = text.charAt(i);
if (ch == left) {
if (rightBracketCount == 0) {
return i;
}
rightBracketCount--;
} else if (ch == right) {
rightBracketCount++;
}
}
return UNMATCHED_BRACKET;
}
public static int findRightBracket(CharSequence text, int index, char left, char right) {
int leftBracketCount = 0;
for (int i = index; i < text.length(); i++) {
char ch = text.charAt(i);
if (ch == left) {
leftBracketCount++;
} else if (ch == right) {
if (leftBracketCount == 0) {
return i;
}
leftBracketCount--;
}
}
return BRACKET_NOT_FOUND;
}
}

View File

@ -22,7 +22,6 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.speech.tts.TextToSpeech;
import android.support.v7.widget.AppCompatEditText;
import android.text.Layout;
import android.util.AttributeSet;
@ -32,10 +31,12 @@ import android.view.Gravity;
import com.stardust.scriptdroid.BuildConfig;
import com.stardust.scriptdroid.ui.edit.theme.Theme;
import com.stardust.scriptdroid.ui.edit.theme.TokenMapping;
import com.stardust.util.TextUtils;
import java.lang.reflect.Array;
import java.util.Arrays;
import org.mozilla.javascript.Token;
import static com.stardust.scriptdroid.ui.edit.editor.BracketMatching.UNMATCHED_BRACKET;
/**
* Created by Administrator on 2018/2/11.
@ -56,6 +57,8 @@ public class CodeEditText extends AppCompatEditText {
private TimingLogger mLogger = new TimingLogger(LOG_TAG, "draw");
private Paint mLineHighlightPaint = new Paint();
private int mFirstLineForDraw = -1, mLastLineForDraw;
private int[] mMatchingBrackets = {-1, -1};
private int mUnmatchedBracket = -1;
public CodeEditText(Context context) {
super(context);
@ -181,23 +184,31 @@ public class CodeEditText extends AppCompatEditText {
int visibleCharStart = getVisibleCharIndex(paint, scrollX, lineStart, lineEnd);
int visibleCharEnd = getVisibleCharIndex(paint, scrollX + mParentScrollView.getWidth(), lineStart, lineEnd) + 1;
int previousColorPos = visibleCharStart;
int previousColor = mHighlightTokens.getCharColor(previousColorPos);
int previousColor = getCharColor(previousColorPos);
if (DEBUG)
Log.d(LOG_TAG, "draw line " + line + ": " + (visibleCharEnd - visibleCharStart));
for (int i = visibleCharStart; i < visibleCharEnd && i < lineEnd; i++) {
int i;
for (i = visibleCharStart; i < visibleCharEnd; i++) {
fontCount++;
int color = mHighlightTokens.getCharColor(i);
int color = getCharColor(i);
if (previousColor != color) {
drawText(canvas, paint, paddingLeft, lineBaseline, lineStart, previousColorPos, previousColorPos + fontCount, previousColor);
drawText(canvas, paint, paddingLeft, lineBaseline, lineStart, previousColorPos, i, previousColor);
previousColor = color;
previousColorPos = i;
fontCount = 1;
}
if (i == visibleCharEnd - 1) {
drawText(canvas, paint, paddingLeft, lineBaseline, lineStart, previousColorPos, previousColorPos + fontCount, previousColor);
}
}
drawText(canvas, paint, paddingLeft, lineBaseline, lineStart, previousColorPos, visibleCharEnd, previousColor);
}
private int getCharColor(int i) {
if (i == mUnmatchedBracket) {
return mTheme.getColorForToken(Token.ERROR);
}
if (i == mMatchingBrackets[0] || i == mMatchingBrackets[1]) {
return mTheme.getColorForToken(TokenMapping.TOKEN_MATCHED_BRACKET);
}
return mHighlightTokens.getCharColor(i);
}
@ -264,11 +275,39 @@ public class CodeEditText extends AppCompatEditText {
return;
}
callCursorChangeCallback(getText(), selStart);
checkParenthesesPairs(getText(), selStart);
matchesBracket(getText(), selStart);
}
private void checkParenthesesPairs(CharSequence text, int sel) {
// TODO: 2018/2/24
private void matchesBracket(CharSequence text, int cursor) {
if (checkBracketMatchingAt(text, cursor)) {
return;
}
if (checkBracketMatchingAt(text, cursor - 1)) {
return;
}
mMatchingBrackets[0] = -1;
mMatchingBrackets[1] = -1;
mUnmatchedBracket = -1;
}
private boolean checkBracketMatchingAt(CharSequence text, int cursor) {
if (cursor < 0 || cursor >= text.length()) {
return false;
}
int i = BracketMatching.bracketMatching(text, cursor);
if (i >= 0) {
mMatchingBrackets[0] = cursor;
mMatchingBrackets[1] = i;
mUnmatchedBracket = -1;
return true;
} else if (i == UNMATCHED_BRACKET) {
mUnmatchedBracket = cursor;
mMatchingBrackets[0] = -1;
mMatchingBrackets[1] = -1;
return true;
}
return false;
}
private void callCursorChangeCallback(CharSequence text, int sel) {

View File

@ -75,7 +75,7 @@ public class Theme {
}
public static Theme getDefault(android.content.Context context) {
return fromAssetsJson(context, "editor/theme/dark_plus.json");
return fromAssetsJson(context, "editor/theme/light_plus.json");
}
public static Theme fromJson(String json) {
@ -140,4 +140,5 @@ public class Theme {
return getName();
}
}

View File

@ -15,6 +15,8 @@ import java.util.List;
public class TokenMapping {
public static final int TOKEN_MATCHED_BRACKET = Token.LAST_TOKEN + 1;
private static final List<Integer> KEYWORD = tokenNamesToTypes(Arrays.asList("return", "new", "delete", "typeof", "null", "this", "false", "true", "throw", "in", "instanceof", "yield", "try", "function", "if", "else", "switch", "case", "default", "while", "do", "for", "break", "continue", "var", "with", "catch", "finally", "void", "let", "const", "debugger"));
private static final List<Integer> KEYWORD_CONTROL = tokenNamesToTypes(Arrays.asList("if", "else", "switch", "case", "break", "continue", "goto", "return", "try", "catch", "throw", "finally"));
private static final List<Integer> KEYWORD_OPERATOR = Collections.emptyList();
@ -29,13 +31,17 @@ public class TokenMapping {
return KEYWORD_CONTROL;
default:
int token = tokenNameToType(scope);
if (Token.isValidToken(token)) {
if (isValidToken(token)) {
return Collections.singletonList(token);
}
}
return Collections.emptyList();
}
public static boolean isValidToken(int token) {
return token >= -1;
}
public static int tokenNameToType(String name) {
switch (name) {
case "this.self":
@ -46,6 +52,8 @@ public class TokenMapping {
return Token.NAME;
case "constant.numeric":
return Token.NUMBER;
case "bracket.matched":
return TOKEN_MATCHED_BRACKET;
}
for (int token = Token.ERROR; token < Token.LAST_TOKEN; token++) {