feat: add tree-sitter language for XML

This commit is contained in:
Akash Yadav
2022-12-27 20:11:03 +05:30
parent ef5098575a
commit 4e621f7150
15 changed files with 185 additions and 162 deletions
@@ -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
View File
@@ -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 = [
+1
View File
@@ -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)