diff --git a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAnalyzer.java b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAnalyzer.java deleted file mode 100755 index 054189269..000000000 --- a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAnalyzer.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * This file is part of AndroidIDE. - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * - */ - -package com.itsaky.androidide.language.groovy; - -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.ANNOTATION; -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.LITERAL; -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.OPERATOR; -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.TEXT_NORMAL; -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.TYPE_NAME; -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.forComment; -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.forKeyword; -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.forString; -import static com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.get; - -import com.itsaky.androidide.lexers.groovy.GroovyLexer; -import com.itsaky.androidide.utils.CharSequenceReader; -import com.itsaky.androidide.utils.ILogger; - -import org.antlr.v4.runtime.CharStreams; -import org.antlr.v4.runtime.CodePointCharStream; -import org.antlr.v4.runtime.Token; - -import java.io.IOException; -import java.util.Stack; - -import io.github.rosemoe.sora.lang.analysis.SimpleAnalyzeManager; -import io.github.rosemoe.sora.lang.styling.CodeBlock; -import io.github.rosemoe.sora.lang.styling.MappedSpans; -import io.github.rosemoe.sora.lang.styling.Styles; - -public class GroovyAnalyzer extends SimpleAnalyzeManager { - - private static final ILogger LOG = ILogger.newInstance("GroovyAnalyzer"); - - @Override - protected Styles analyze(StringBuilder text, Delegate delegate) { - final var styles = new Styles(); - final var colors = new MappedSpans.Builder(); - final CodePointCharStream stream; - try { - stream = CharStreams.fromReader(new CharSequenceReader(text)); - } catch (IOException e) { - LOG.error("Unable to read text to analyze", e); - return styles; - } - - final var lexer = new GroovyLexer(stream); - final var stack = new Stack(); - - Token token; - int line, column, lastLine = 1, currSwitch = 0, maxSwitch = 0, type, previous = 0; - boolean isFirst = true; - - while (!delegate.isCancelled()) { - token = lexer.nextToken(); - - if (token == null) { - break; - } - - line = token.getLine() - 1; - column = token.getCharPositionInLine(); - type = token.getType(); - - if (type == GroovyLexer.EOF) { - lastLine = line; - break; - } - - switch (type) { - case GroovyLexer.WS: - if (isFirst) { - colors.addNormalIfNull(); - } - break; - case GroovyLexer.ABSTRACT: - case GroovyLexer.ASSERT: - case GroovyLexer.BREAK: - case GroovyLexer.CASE: - case GroovyLexer.CATCH: - case GroovyLexer.CLASS: - case GroovyLexer.CONST: - case GroovyLexer.CONTINUE: - case GroovyLexer.DEFAULT: - case GroovyLexer.DO: - case GroovyLexer.ELSE: - case GroovyLexer.EXTENDS: - case GroovyLexer.FINAL: - case GroovyLexer.FINALLY: - case GroovyLexer.FOR: - case GroovyLexer.IF: - case GroovyLexer.GOTO: - case GroovyLexer.IMPLEMENTS: - case GroovyLexer.IMPORT: - case GroovyLexer.INSTANCEOF: - case GroovyLexer.INTERFACE: - case GroovyLexer.NATIVE: - case GroovyLexer.NEW: - case GroovyLexer.PACKAGE: - case GroovyLexer.PRIVATE: - case GroovyLexer.PROTECTED: - case GroovyLexer.PUBLIC: - case GroovyLexer.RETURN: - case GroovyLexer.STATIC: - case GroovyLexer.STRICTFP: - case GroovyLexer.SUPER: - case GroovyLexer.SWITCH: - case GroovyLexer.SYNCHRONIZED: - case GroovyLexer.THIS: - case GroovyLexer.THROW: - case GroovyLexer.THROWS: - case GroovyLexer.TRANSIENT: - case GroovyLexer.TRY: - case GroovyLexer.VOID: - case GroovyLexer.VOLATILE: - case GroovyLexer.WHILE: - colors.addIfNeeded(line, column, forKeyword()); - break; - case GroovyLexer.DECIMAL_LITERAL: - case GroovyLexer.HEX_LITERAL: - case GroovyLexer.OCT_LITERAL: - case GroovyLexer.BINARY_LITERAL: - case GroovyLexer.FLOAT_LITERAL: - case GroovyLexer.HEX_FLOAT_LITERAL: - case GroovyLexer.BOOL_LITERAL: - case GroovyLexer.CHAR_LITERAL: - case GroovyLexer.NULL_LITERAL: - colors.addIfNeeded(line, column, get(LITERAL)); - break; - case GroovyLexer.STRING_LITERAL: - case GroovyLexer.SINGLE_QUOTE_STRING: - colors.addIfNeeded(line, column, forString()); - break; - case GroovyLexer.LPAREN: - case GroovyLexer.RPAREN: - case GroovyLexer.LBRACK: - case GroovyLexer.RBRACK: - case GroovyLexer.SEMI: - case GroovyLexer.COMMA: - case GroovyLexer.ASSIGN: - case GroovyLexer.GT: - case GroovyLexer.LT: - case GroovyLexer.BANG: - case GroovyLexer.TILDE: - case GroovyLexer.QUESTION: - case GroovyLexer.COLON: - case GroovyLexer.EQUAL: - case GroovyLexer.GE: - case GroovyLexer.LE: - case GroovyLexer.NOTEQUAL: - case GroovyLexer.AND: - case GroovyLexer.OR: - case GroovyLexer.INC: - case GroovyLexer.DEC: - case GroovyLexer.ADD: - case GroovyLexer.SUB: - case GroovyLexer.MUL: - case GroovyLexer.DIV: - case GroovyLexer.BITAND: - case GroovyLexer.BITOR: - case GroovyLexer.CARET: - case GroovyLexer.MOD: - case GroovyLexer.ADD_ASSIGN: - case GroovyLexer.SUB_ASSIGN: - case GroovyLexer.MUL_ASSIGN: - case GroovyLexer.DIV_ASSIGN: - case GroovyLexer.AND_ASSIGN: - case GroovyLexer.OR_ASSIGN: - case GroovyLexer.XOR_ASSIGN: - case GroovyLexer.MOD_ASSIGN: - case GroovyLexer.LSHIFT_ASSIGN: - case GroovyLexer.RSHIFT_ASSIGN: - case GroovyLexer.URSHIFT_ASSIGN: - case GroovyLexer.ARROW: - case GroovyLexer.COLONCOLON: - case GroovyLexer.ELLIPSIS: - case GroovyLexer.DOT: - colors.addIfNeeded(line, column, get(OPERATOR)); - break; - case GroovyLexer.BOOLEAN: - case GroovyLexer.BYTE: - case GroovyLexer.CHAR: - case GroovyLexer.DOUBLE: - case GroovyLexer.ENUM: - case GroovyLexer.FLOAT: - case GroovyLexer.INT: - case GroovyLexer.LONG: - case GroovyLexer.SHORT: - colors.addIfNeeded(line, column, get(TYPE_NAME)); - break; - case GroovyLexer.COMMENT: - case GroovyLexer.LINE_COMMENT: - colors.addIfNeeded(line, column, forComment()); - break; - case GroovyLexer.AT: - colors.addIfNeeded(line, column, get(ANNOTATION)); - break; - case GroovyLexer.IDENTIFIER: - if (previous == GroovyLexer.AT) { - colors.addIfNeeded(line, column, get(ANNOTATION)); - break; - } - - colors.addIfNeeded(line, column, get(TEXT_NORMAL)); - break; - case GroovyLexer.LBRACE: - colors.addIfNeeded(line, column, get(OPERATOR)); - if (stack.isEmpty()) { - if (currSwitch > maxSwitch) maxSwitch = currSwitch; - currSwitch = 0; - } - currSwitch++; - var block = styles.obtainNewBlock(); - block.startLine = line; - block.startColumn = column; - stack.push(block); - break; - case GroovyLexer.RBRACE: - colors.addIfNeeded(line, column, get(OPERATOR)); - if (!stack.isEmpty()) { - var block2 = stack.pop(); - block2.endLine = line; - block2.endColumn = column; - if (block2.startLine != block2.endLine) styles.addCodeBlock(block2); - } - break; - default: - colors.addIfNeeded(line, column, get(TEXT_NORMAL)); - break; - } - - isFirst = false; - if (type != GroovyLexer.WS) { - previous = type; - } - } - - if (stack.isEmpty() && currSwitch > maxSwitch) { - maxSwitch = currSwitch; - } - - colors.determine(lastLine); - styles.setSuppressSwitch(maxSwitch + 10); - styles.spans = colors.build(); - - return styles; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAnalyzer.kt b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAnalyzer.kt new file mode 100644 index 000000000..1fb89053a --- /dev/null +++ b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAnalyzer.kt @@ -0,0 +1,192 @@ +/* + * This file is part of AndroidIDE. + * + * AndroidIDE is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * AndroidIDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with AndroidIDE. If not, see . + */ + +package com.itsaky.androidide.language.groovy + +import com.itsaky.androidide.language.incremental.BaseIncrementalAnalyzeManager +import com.itsaky.androidide.language.incremental.IncrementalToken +import com.itsaky.androidide.language.incremental.LineState +import com.itsaky.androidide.lexers.groovy.GroovyLexer +import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE +import io.github.rosemoe.sora.lang.analysis.IncrementalAnalyzeManager.LineTokenizeResult +import io.github.rosemoe.sora.lang.styling.CodeBlock +import io.github.rosemoe.sora.lang.styling.Span +import io.github.rosemoe.sora.lang.styling.TextStyle +import io.github.rosemoe.sora.text.Content + +/** @author Akash Yadav */ +class GroovyAnalyzer : BaseIncrementalAnalyzeManager(GroovyLexer::class.java) { + + override fun computeBlocks(text: Content, delegate: CodeBlockAnalyzeDelegate): List { + return emptyList() + } + + override fun generateSpans( + tokens: LineTokenizeResult, + ): List { + val spans = mutableListOf() + var previous = GroovyLexer.WS + var first = true + for (token in tokens.tokens) { + val type = token.type + val offset = token.startIndex + when (type) { + GroovyLexer.WS -> { + if (first) { + spans.add(Span.obtain(offset, TextStyle.makeStyle(SchemeAndroidIDE.TEXT_NORMAL))) + first = false + } + } + GroovyLexer.ABSTRACT, + GroovyLexer.ASSERT, + GroovyLexer.BREAK, + GroovyLexer.CASE, + GroovyLexer.CATCH, + GroovyLexer.CLASS, + GroovyLexer.CONST, + GroovyLexer.CONTINUE, + GroovyLexer.DEFAULT, + GroovyLexer.DO, + GroovyLexer.ELSE, + GroovyLexer.EXTENDS, + GroovyLexer.FINAL, + GroovyLexer.FINALLY, + GroovyLexer.FOR, + GroovyLexer.IF, + GroovyLexer.GOTO, + GroovyLexer.IMPLEMENTS, + GroovyLexer.IMPORT, + GroovyLexer.INSTANCEOF, + GroovyLexer.INTERFACE, + GroovyLexer.NATIVE, + GroovyLexer.NEW, + GroovyLexer.PACKAGE, + GroovyLexer.PRIVATE, + GroovyLexer.PROTECTED, + GroovyLexer.PUBLIC, + GroovyLexer.RETURN, + GroovyLexer.STATIC, + GroovyLexer.STRICTFP, + GroovyLexer.SUPER, + GroovyLexer.SWITCH, + GroovyLexer.SYNCHRONIZED, + GroovyLexer.THIS, + GroovyLexer.THROW, + GroovyLexer.THROWS, + GroovyLexer.TRANSIENT, + GroovyLexer.TRY, + GroovyLexer.VOID, + GroovyLexer.VOLATILE, + GroovyLexer.WHILE -> spans.add(Span.obtain(offset, SchemeAndroidIDE.forKeyword())) + GroovyLexer.DECIMAL_LITERAL, + GroovyLexer.HEX_LITERAL, + GroovyLexer.OCT_LITERAL, + GroovyLexer.BINARY_LITERAL, + GroovyLexer.FLOAT_LITERAL, + GroovyLexer.HEX_FLOAT_LITERAL, + GroovyLexer.BOOL_LITERAL, + GroovyLexer.CHAR_LITERAL, + GroovyLexer.NULL_LITERAL, -> + spans.add(Span.obtain(offset, TextStyle.makeStyle(SchemeAndroidIDE.LITERAL))) + GroovyLexer.SINGLE_QUOTE_STRING, + GroovyLexer.STRING_LITERAL -> spans.add(Span.obtain(offset, SchemeAndroidIDE.forString())) + GroovyLexer.LPAREN, + GroovyLexer.RPAREN, + GroovyLexer.LBRACK, + GroovyLexer.RBRACK, + GroovyLexer.SEMI, + GroovyLexer.COMMA, + GroovyLexer.ASSIGN, + GroovyLexer.GT, + GroovyLexer.LT, + GroovyLexer.BANG, + GroovyLexer.TILDE, + GroovyLexer.QUESTION, + GroovyLexer.COLON, + GroovyLexer.EQUAL, + GroovyLexer.GE, + GroovyLexer.LE, + GroovyLexer.NOTEQUAL, + GroovyLexer.AND, + GroovyLexer.OR, + GroovyLexer.INC, + GroovyLexer.DEC, + GroovyLexer.ADD, + GroovyLexer.SUB, + GroovyLexer.MUL, + GroovyLexer.DIV, + GroovyLexer.BITAND, + GroovyLexer.BITOR, + GroovyLexer.CARET, + GroovyLexer.MOD, + GroovyLexer.ADD_ASSIGN, + GroovyLexer.SUB_ASSIGN, + GroovyLexer.MUL_ASSIGN, + GroovyLexer.DIV_ASSIGN, + GroovyLexer.AND_ASSIGN, + GroovyLexer.OR_ASSIGN, + GroovyLexer.XOR_ASSIGN, + GroovyLexer.MOD_ASSIGN, + GroovyLexer.LSHIFT_ASSIGN, + GroovyLexer.RSHIFT_ASSIGN, + GroovyLexer.URSHIFT_ASSIGN, + GroovyLexer.ARROW, + GroovyLexer.COLONCOLON, + GroovyLexer.ELLIPSIS, + GroovyLexer.LBRACE, + GroovyLexer.RBRACE, + GroovyLexer.DOT, -> + spans.add(Span.obtain(offset, TextStyle.makeStyle(SchemeAndroidIDE.OPERATOR))) + GroovyLexer.BOOLEAN, + GroovyLexer.BYTE, + GroovyLexer.CHAR, + GroovyLexer.DOUBLE, + GroovyLexer.ENUM, + GroovyLexer.FLOAT, + GroovyLexer.INT, + GroovyLexer.LONG, + GroovyLexer.SHORT, -> + spans.add(Span.obtain(offset, TextStyle.makeStyle(SchemeAndroidIDE.TYPE_NAME))) + GroovyLexer.COMMENT -> spans.add(Span.obtain(offset, SchemeAndroidIDE.forComment())) + GroovyLexer.LINE_COMMENT -> handleLineCommentSpan(token, spans, offset) + GroovyLexer.AT -> + spans.add(Span.obtain(offset, TextStyle.makeStyle(SchemeAndroidIDE.ANNOTATION))) + GroovyLexer.IDENTIFIER -> { + var colorId = SchemeAndroidIDE.TEXT_NORMAL + if (previous == GroovyLexer.AT) { + colorId = SchemeAndroidIDE.ANNOTATION + } + spans.add(Span.obtain(offset, TextStyle.makeStyle(colorId))) + } + else -> spans.add(Span.obtain(offset, TextStyle.makeStyle(SchemeAndroidIDE.TEXT_NORMAL))) + } + previous = type + } + + return spans + } + + override fun getMultilineTokenStartEndTypes(): Array { + val start = intArrayOf(GroovyLexer.DIV, GroovyLexer.MUL) + val end = intArrayOf(GroovyLexer.MUL, GroovyLexer.DIV) + return arrayOf(start, end) + } + + override fun handleIncompleteToken(token: IncrementalToken) { + token.type = GroovyLexer.COMMENT + } +}