mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
feat: add tree-sitter language for XML
This commit is contained in:
@@ -42,6 +42,7 @@ class IDEApplication : BaseApplication() {
|
||||
init {
|
||||
System.loadLibrary("android-tree-sitter")
|
||||
System.loadLibrary("tree-sitter-java")
|
||||
System.loadLibrary("tree-sitter-xml")
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
|
||||
@@ -234,7 +234,7 @@ public class CodeEditorView extends LinearLayout {
|
||||
case "java":
|
||||
return new JavaLanguage(getContext());
|
||||
case "xml":
|
||||
return new XMLLanguage();
|
||||
return new XMLLanguage(getContext());
|
||||
case "gradle":
|
||||
return new GroovyLanguage();
|
||||
case "kt":
|
||||
|
||||
+3
-2
@@ -5,7 +5,7 @@ ext {
|
||||
oss_licenses_version = '0.10.6'
|
||||
nav_safeargs_version = '2.5.3'
|
||||
|
||||
ats_version = '1.0.9'
|
||||
ats_version = '1.0.10'
|
||||
editor_version = '0.20.1'
|
||||
|
||||
classpaths = [
|
||||
@@ -19,7 +19,8 @@ ext {
|
||||
androidide = [
|
||||
javac : 'io.github.itsaky:nb-javac-android:17.0.0.4-SNAPSHOT',
|
||||
ats : "io.github.itsaky:android-tree-sitter:$ats_version",
|
||||
ts_java: "io.github.itsaky:tree-sitter-java:$ats_version"
|
||||
ts_java: "io.github.itsaky:tree-sitter-java:$ats_version",
|
||||
ts_xml: "io.github.itsaky:tree-sitter-xml:$ats_version"
|
||||
]
|
||||
|
||||
common = [
|
||||
|
||||
@@ -41,6 +41,7 @@ dependencies {
|
||||
|
||||
api androidide.ats
|
||||
api androidide.ts_java
|
||||
api androidide.ts_xml
|
||||
api common.editor
|
||||
api common.editor_ts
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
"onSurfaceVariant": "#4a4644",
|
||||
"outline": "#7a7572",
|
||||
"text.selected": "#ff5252",
|
||||
"black": "#000000",
|
||||
"white": "#ffffff",
|
||||
|
||||
"type": "#2196f3",
|
||||
"keyword": "#1e88e5",
|
||||
"operator": "#2196f3",
|
||||
@@ -24,12 +27,14 @@
|
||||
"comment": "#a8a8a8",
|
||||
"func.decl": "#2962ff",
|
||||
"func.call": "#2962ff",
|
||||
"black": "#000000",
|
||||
"white": "#ffffff"
|
||||
|
||||
"xml.tag": "#1e88e5",
|
||||
"xml.ref": "#2196f3",
|
||||
"ns_prefix": "#9c27b0"
|
||||
},
|
||||
"editor": "@editor.json",
|
||||
"languages": [
|
||||
"@log.json",
|
||||
"@java.json"
|
||||
"@java.json",
|
||||
"@xml.json"
|
||||
]
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"types": [
|
||||
"@log"
|
||||
],
|
||||
"styles": {
|
||||
"text.error": "#f44336",
|
||||
"text.warning": "#ffeb3b",
|
||||
"text.info": "#4caf50",
|
||||
"text.debug": "#f5f5f5",
|
||||
"text.verbose": "#4fc3f7",
|
||||
"priority.error": {
|
||||
"fg": "@black",
|
||||
"bg": "#f44336",
|
||||
"completion": false
|
||||
},
|
||||
"priority.warning": {
|
||||
"fg": "@black",
|
||||
"bg": "#ffeb3b"
|
||||
},
|
||||
"priority.info": {
|
||||
"fg": "@white",
|
||||
"bg": "#1f65c0"
|
||||
},
|
||||
"priority.debug": {
|
||||
"fg": "@white",
|
||||
"bg": "#9e9d24"
|
||||
},
|
||||
"priority.verbose": {
|
||||
"fg": "@black",
|
||||
"bg": "@white"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,13 @@
|
||||
scheme.name=AndroidIDE Default
|
||||
|
||||
# The version code of the color scheme
|
||||
scheme.version=1
|
||||
scheme.version=2
|
||||
|
||||
# Whether the scheme is dark or light
|
||||
scheme.isDark=false
|
||||
|
||||
# Languages that scheme supports
|
||||
scheme.langs=java,@log
|
||||
scheme.langs=java,xml
|
||||
|
||||
# The JSON color scheme definition file
|
||||
scheme.file=default.json
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"types": ["xml"],
|
||||
"styles": {
|
||||
"xml_decl": {
|
||||
"fg": "@operator",
|
||||
"bold": true
|
||||
},
|
||||
"element.tag": {
|
||||
"fg": "@xml.tag",
|
||||
"bold": true
|
||||
},
|
||||
"ns_declarator": {
|
||||
"fg": "@keyword",
|
||||
"bold": true
|
||||
},
|
||||
"xml.ref": {
|
||||
"fg": "@xml.ref",
|
||||
"italic": true
|
||||
},
|
||||
"comment": {
|
||||
"fg": "@comment",
|
||||
"italic": true
|
||||
},
|
||||
"operator": "@operator",
|
||||
"cdata.start": "@xml.tag",
|
||||
"cdata.end": "@xml.tag",
|
||||
"cdata": "@onSurface",
|
||||
"xmlns.prefix": "@ns_prefix",
|
||||
"attr.prefix" : "@ns_prefix",
|
||||
"attr.name": "@onSurface",
|
||||
"attr.value": "@string"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
; bracket pair highlights query for sora-editor
|
||||
|
||||
; for xml declaration, mark the opening '<?' as brackets open and closing '?>' as brackets close
|
||||
(xml_decl
|
||||
"<?" @editor.brackets.open
|
||||
"?>" @editor.brackets.close)
|
||||
|
||||
; for empty element tag, mark opening '<' and closing '/>' as brackets open and close
|
||||
(empty_element
|
||||
"<" @editor.brackets.open
|
||||
"/>" @editor.brackets.close)
|
||||
|
||||
; in case of an element which has an end tag
|
||||
; mark the tag name in tag_start as bracket open
|
||||
; and the tag name in tag_end as bracket close
|
||||
(tag_start
|
||||
tag_name: (name) @editor.brackets.open)
|
||||
(tag_end
|
||||
tag_name: (name) @editor.brackets.close)
|
||||
|
||||
; bracket pairs for CDATA sections
|
||||
(cdata_start) @editor.brackets.open
|
||||
(cdata_end) @editor.brackets.close
|
||||
@@ -0,0 +1,45 @@
|
||||
(xml_decl
|
||||
decl: "xml" @xml_decl)
|
||||
|
||||
(xml_version
|
||||
version_attr: "version" @attr.name)
|
||||
|
||||
(xml_encoding
|
||||
encoding_attr: "encoding" @attr.name)
|
||||
|
||||
(xml_version_value) @attr.value
|
||||
(xml_encoding_value) @attr.value
|
||||
|
||||
(empty_element
|
||||
tag_name: (name) @element.tag)
|
||||
|
||||
(tag_start
|
||||
tag_name: (name) @element.tag)
|
||||
|
||||
(tag_end
|
||||
tag_name: (name) @element.tag)
|
||||
|
||||
"xmlns" @ns_declarator
|
||||
(ns_decl
|
||||
xmlns_prefix: (name) @xmlns.prefix)
|
||||
|
||||
(xml_attr
|
||||
ns_prefix: (name) @attr.prefix
|
||||
attr_name: (name) @attr.name)
|
||||
|
||||
(attr_value) @attr.value
|
||||
|
||||
(comment) @comment
|
||||
|
||||
(entity_ref) @xml.ref
|
||||
(char_ref) @xml.ref
|
||||
|
||||
(comment) @comment
|
||||
|
||||
(cdata_start) @cdata.start
|
||||
(cdata_end) @cdata.end
|
||||
(cdata) @cdata.data
|
||||
|
||||
(eq) @operator
|
||||
|
||||
["<" "</" ">" "<?" "?>" "/>"] @operator
|
||||
@@ -28,6 +28,7 @@ import io.github.rosemoe.sora.editor.ts.TsAnalyzeManager
|
||||
import io.github.rosemoe.sora.editor.ts.TsLanguageSpec
|
||||
import io.github.rosemoe.sora.editor.ts.TsTheme
|
||||
import io.github.rosemoe.sora.lang.analysis.AnalyzeManager
|
||||
import io.github.rosemoe.sora.widget.SymbolPairMatch
|
||||
|
||||
/**
|
||||
* Tree Sitter language implementation.
|
||||
@@ -66,6 +67,10 @@ abstract class TreeSitterLanguage(context: Context, lang: TSLanguage, type: Stri
|
||||
override fun getAnalyzeManager(): AnalyzeManager {
|
||||
return this.analyzer
|
||||
}
|
||||
|
||||
override fun getSymbolPairs(): SymbolPairMatch {
|
||||
return CommonSymbolPairs()
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
languageSpec.close()
|
||||
|
||||
@@ -1,119 +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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.itsaky.androidide.editor.language.xml;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.itsaky.androidide.editor.language.CommonSymbolPairs;
|
||||
import com.itsaky.androidide.editor.language.IDELanguage;
|
||||
import com.itsaky.androidide.lexers.xml.XMLLexer;
|
||||
import com.itsaky.androidide.lsp.api.ILanguageServer;
|
||||
import com.itsaky.androidide.lsp.api.ILanguageServerRegistry;
|
||||
import com.itsaky.androidide.lsp.xml.XMLLanguageServer;
|
||||
import com.itsaky.androidide.utils.ILogger;
|
||||
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import io.github.rosemoe.sora.lang.analysis.AnalyzeManager;
|
||||
import io.github.rosemoe.sora.lang.smartEnter.NewlineHandler;
|
||||
import io.github.rosemoe.sora.text.ContentReference;
|
||||
import io.github.rosemoe.sora.util.MyCharacter;
|
||||
import io.github.rosemoe.sora.widget.SymbolPairMatch;
|
||||
|
||||
public class XMLLanguage extends IDELanguage {
|
||||
|
||||
private static final ILogger LOG = ILogger.newInstance("XMLLanguage");
|
||||
private final NewlineHandler[] newlineHandlers;
|
||||
private XMLAnalyzer analyzer;
|
||||
|
||||
public XMLLanguage() {
|
||||
this.analyzer = new XMLAnalyzer();
|
||||
this.newlineHandlers = new NewlineHandler[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ILanguageServer getLanguageServer() {
|
||||
return ILanguageServerRegistry.getDefault().getServer(XMLLanguageServer.SERVER_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkIsCompletionChar(final char c) {
|
||||
return MyCharacter.isJavaIdentifierPart(c) || c == '<' || c == '/';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndentAdvance(@NonNull String content) {
|
||||
try {
|
||||
XMLLexer lexer = new XMLLexer(CharStreams.fromReader(new StringReader(content)));
|
||||
Token token;
|
||||
int advance = 0;
|
||||
while (((token = lexer.nextToken()) != null && token.getType() != token.EOF)) {
|
||||
switch (token.getType()) {
|
||||
case XMLLexer.OPEN:
|
||||
advance++;
|
||||
break;
|
||||
case XMLLexer.CLOSE:
|
||||
case XMLLexer.SLASH_CLOSE:
|
||||
advance--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
advance = Math.max(0, advance);
|
||||
return advance * getTabSize();
|
||||
} catch (Throwable e) {
|
||||
LOG.error("Failed to compute indent advance", e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AnalyzeManager getAnalyzeManager() {
|
||||
return analyzer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInterruptionLevel() {
|
||||
return INTERRUPTION_LEVEL_STRONG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndentAdvance(@NonNull ContentReference content, int line, int column) {
|
||||
final var text = content.getLine(line).substring(0, column);
|
||||
return getIndentAdvance(text.trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SymbolPairMatch getSymbolPairs() {
|
||||
return new CommonSymbolPairs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NewlineHandler[] getNewlineHandlers() {
|
||||
return newlineHandlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
analyzer = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.editor.language.xml
|
||||
|
||||
import android.content.Context
|
||||
import com.itsaky.androidide.editor.language.TreeSitterLanguage
|
||||
import com.itsaky.androidide.lsp.api.ILanguageServer
|
||||
import com.itsaky.androidide.lsp.api.ILanguageServerRegistry
|
||||
import com.itsaky.androidide.lsp.xml.XMLLanguageServer
|
||||
import com.itsaky.androidide.treesitter.xml.TSLanguageXml
|
||||
import io.github.rosemoe.sora.lang.smartEnter.NewlineHandler
|
||||
import io.github.rosemoe.sora.text.ContentReference
|
||||
import io.github.rosemoe.sora.util.MyCharacter
|
||||
|
||||
/**
|
||||
* Tree Sitter language XML language.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class XMLLanguage(context: Context) :
|
||||
TreeSitterLanguage(context, lang = TSLanguageXml.newInstance(), type = TS_TYPE) {
|
||||
|
||||
companion object {
|
||||
const val TS_TYPE = "xml"
|
||||
}
|
||||
|
||||
override fun getLanguageServer(): ILanguageServer? {
|
||||
return ILanguageServerRegistry.getDefault().getServer(XMLLanguageServer.SERVER_ID)
|
||||
}
|
||||
|
||||
override fun checkIsCompletionChar(c: Char): Boolean {
|
||||
return MyCharacter.isJavaIdentifierPart(c) || c == '<' || c == '/'
|
||||
}
|
||||
|
||||
override fun getInterruptionLevel(): Int {
|
||||
return INTERRUPTION_LEVEL_STRONG
|
||||
}
|
||||
|
||||
override fun getIndentAdvance(content: ContentReference, line: Int, column: Int): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun getNewlineHandlers(): Array<NewlineHandler> {
|
||||
return emptyArray()
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -61,7 +61,7 @@ class ShowXmlActivity : BaseIDEActivity() {
|
||||
editor.editable = false
|
||||
editor.typefaceText = jetbrainsMono()
|
||||
editor.typefaceLineNumber = jetbrainsMono()
|
||||
editor.setEditorLanguage(XMLLanguage())
|
||||
editor.setEditorLanguage(XMLLanguage(this))
|
||||
editor.setText(intent?.getStringExtra(KEY_XML) ?: "")
|
||||
editor.setTextSize(fontSize)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user