diff --git a/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt b/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt
index 2a345a775..b30aed5a5 100755
--- a/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt
+++ b/app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt
@@ -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() {
diff --git a/app/src/main/java/com/itsaky/androidide/ui/editor/CodeEditorView.java b/app/src/main/java/com/itsaky/androidide/ui/editor/CodeEditorView.java
index e7d0e27a2..671140af2 100644
--- a/app/src/main/java/com/itsaky/androidide/ui/editor/CodeEditorView.java
+++ b/app/src/main/java/com/itsaky/androidide/ui/editor/CodeEditorView.java
@@ -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":
diff --git a/dependencies.gradle b/dependencies.gradle
index 547854b90..a5aa282e7 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -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 = [
diff --git a/editor/build.gradle b/editor/build.gradle
index f45f3e033..b4fb5f13d 100644
--- a/editor/build.gradle
+++ b/editor/build.gradle
@@ -41,6 +41,7 @@ dependencies {
api androidide.ats
api androidide.ts_java
+ api androidide.ts_xml
api common.editor
api common.editor_ts
diff --git a/editor/src/main/assets/editor/schemes/default/default.json b/editor/src/main/assets/editor/schemes/default/default.json
index 408cd4cb2..a8a7e82b0 100644
--- a/editor/src/main/assets/editor/schemes/default/default.json
+++ b/editor/src/main/assets/editor/schemes/default/default.json
@@ -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"
]
}
\ No newline at end of file
diff --git a/editor/src/main/assets/editor/schemes/default/log.json b/editor/src/main/assets/editor/schemes/default/log.json
deleted file mode 100644
index 576ff7e10..000000000
--- a/editor/src/main/assets/editor/schemes/default/log.json
+++ /dev/null
@@ -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"
- }
- }
-}
\ No newline at end of file
diff --git a/editor/src/main/assets/editor/schemes/default/scheme.prop b/editor/src/main/assets/editor/schemes/default/scheme.prop
index 2ac0edde1..64364fbfe 100644
--- a/editor/src/main/assets/editor/schemes/default/scheme.prop
+++ b/editor/src/main/assets/editor/schemes/default/scheme.prop
@@ -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
\ No newline at end of file
diff --git a/editor/src/main/assets/editor/schemes/default/xml.json b/editor/src/main/assets/editor/schemes/default/xml.json
new file mode 100644
index 000000000..f9bc4aef3
--- /dev/null
+++ b/editor/src/main/assets/editor/schemes/default/xml.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"
+ }
+}
\ No newline at end of file
diff --git a/editor/src/main/assets/editor/treesitter/xml/brackets.scm b/editor/src/main/assets/editor/treesitter/xml/brackets.scm
new file mode 100644
index 000000000..b97564d1d
--- /dev/null
+++ b/editor/src/main/assets/editor/treesitter/xml/brackets.scm
@@ -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
\ No newline at end of file
diff --git a/editor/src/main/assets/editor/treesitter/xml/highlights.scm b/editor/src/main/assets/editor/treesitter/xml/highlights.scm
new file mode 100644
index 000000000..034793219
--- /dev/null
+++ b/editor/src/main/assets/editor/treesitter/xml/highlights.scm
@@ -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
\ No newline at end of file
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/TreeSitterLanguage.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/TreeSitterLanguage.kt
index 1da63ffeb..d6d62a7dc 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/language/TreeSitterLanguage.kt
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/TreeSitterLanguage.kt
@@ -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()
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/xml/XMLLanguage.java b/editor/src/main/java/com/itsaky/androidide/editor/language/xml/XMLLanguage.java
deleted file mode 100755
index a4e49749d..000000000
--- a/editor/src/main/java/com/itsaky/androidide/editor/language/xml/XMLLanguage.java
+++ /dev/null
@@ -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 .
- */
-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;
- }
-}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/xml/XMLLanguage.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/xml/XMLLanguage.kt
new file mode 100644
index 000000000..a965177d4
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/xml/XMLLanguage.kt
@@ -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 .
+ */
+
+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 {
+ return emptyArray()
+ }
+}
diff --git a/tests/test-home/.androidide/init/model.jar b/tests/test-home/.androidide/init/model.jar
index 2ee5a1531..fb153043c 100644
Binary files a/tests/test-home/.androidide/init/model.jar and b/tests/test-home/.androidide/init/model.jar differ
diff --git a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/ShowXmlActivity.kt b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/ShowXmlActivity.kt
index ff698e49a..40c487adc 100644
--- a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/ShowXmlActivity.kt
+++ b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/ShowXmlActivity.kt
@@ -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)