diff --git a/annotation-ksp/src/main/kotlin/com/itsaky/androidide/annotations/ksp/IDESymbolProcessorProvider.kt b/annotation-ksp/src/main/kotlin/com/itsaky/androidide/annotations/ksp/inflater/ViewAdapterSymbolProcessorProvider.kt
similarity index 81%
rename from annotation-ksp/src/main/kotlin/com/itsaky/androidide/annotations/ksp/IDESymbolProcessorProvider.kt
rename to annotation-ksp/src/main/kotlin/com/itsaky/androidide/annotations/ksp/inflater/ViewAdapterSymbolProcessorProvider.kt
index 9a8e3cbcb..c29c00c05 100644
--- a/annotation-ksp/src/main/kotlin/com/itsaky/androidide/annotations/ksp/IDESymbolProcessorProvider.kt
+++ b/annotation-ksp/src/main/kotlin/com/itsaky/androidide/annotations/ksp/inflater/ViewAdapterSymbolProcessorProvider.kt
@@ -15,19 +15,19 @@
* along with AndroidIDE. If not, see .
*/
-package com.itsaky.androidide.annotations.ksp
+package com.itsaky.androidide.annotations.ksp.inflater
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
-import com.itsaky.androidide.annotations.ksp.inflater.ViewAdapterSymbolProcessor
/**
- * AndroidIDE [SymbolProcessorProvider] implementation.
+ * [SymbolProcessorProvider] implementation for
+ * [ViewAdapter][com.itsaky.androidide.annotations.inflater.ViewAdapter] annotation.
*
* @author Akash Yadav
*/
-class IDESymbolProcessorProvider : SymbolProcessorProvider {
+class ViewAdapterSymbolProcessorProvider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return ViewAdapterSymbolProcessor(environment.codeGenerator, environment.logger)
diff --git a/annotation-ksp/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/annotation-ksp/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
index 5e65fdc80..004759fc8 100644
--- a/annotation-ksp/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
+++ b/annotation-ksp/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
@@ -15,4 +15,4 @@
# along with AndroidIDE. If not, see .
#
-com.itsaky.androidide.annotations.ksp.IDESymbolProcessorProvider
\ No newline at end of file
+com.itsaky.androidide.annotations.ksp.inflater.ViewAdapterSymbolProcessorProvider
\ No newline at end of file
diff --git a/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt b/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt
index ede934963..88e1e6449 100644
--- a/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt
+++ b/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt
@@ -31,6 +31,10 @@ import com.itsaky.androidide.R.string
import com.itsaky.androidide.actions.ActionData
import com.itsaky.androidide.actions.ActionItem.Location.EDITOR_TOOLBAR
import com.itsaky.androidide.actions.ActionsRegistry.Companion.getInstance
+import com.itsaky.androidide.editor.language.java.JavaLanguage
+import com.itsaky.androidide.editor.language.json.JsonLanguage
+import com.itsaky.androidide.editor.language.treesitter.TSLanguageRegistry
+import com.itsaky.androidide.editor.language.xml.XMLLanguage
import com.itsaky.androidide.editor.schemes.IDEColorSchemeProvider
import com.itsaky.androidide.editor.ui.IDEEditor
import com.itsaky.androidide.interfaces.IEditorHandler
@@ -76,6 +80,7 @@ open class EditorHandlerActivity : ProjectHandlerActivity(), IEditorHandler {
override fun preDestroy() {
super.preDestroy()
+ TSLanguageRegistry.instance.destroy()
viewModel.removeAllFiles()
}
@@ -106,7 +111,12 @@ open class EditorHandlerActivity : ProjectHandlerActivity(), IEditorHandler {
}
}
- executeAsync { IDEColorSchemeProvider.initIfNeeded() }
+ executeAsync {
+ TSLanguageRegistry.instance.register(JavaLanguage.TS_TYPE, JavaLanguage.FACTORY)
+ TSLanguageRegistry.instance.register(JsonLanguage.TS_TYPE, JsonLanguage.FACTORY)
+ TSLanguageRegistry.instance.register(XMLLanguage.TS_TYPE, XMLLanguage.FACTORY)
+ IDEColorSchemeProvider.initIfNeeded()
+ }
}
@SuppressLint("RestrictedApi")
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 ae0aa40e0..d6b88891b 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
@@ -53,6 +53,7 @@ import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.SizeUtils;
import com.itsaky.androidide.app.BaseApplication;
import com.itsaky.androidide.editor.databinding.LayoutCodeEditorBinding;
+import com.itsaky.androidide.editor.language.treesitter.TSLanguageRegistry;
import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguage;
import com.itsaky.androidide.editor.language.cpp.CppLanguage;
import com.itsaky.androidide.editor.language.groovy.GroovyLanguage;
diff --git a/editor/build.gradle.kts b/editor/build.gradle.kts
index 851a348cc..6f2ccfde4 100644
--- a/editor/build.gradle.kts
+++ b/editor/build.gradle.kts
@@ -1,6 +1,7 @@
plugins {
id("com.android.library")
id("kotlin-android")
+ id("com.google.devtools.ksp") version libs.versions.ksp
}
android {
@@ -8,6 +9,7 @@ android {
}
dependencies {
+ ksp(projects.annotationKsp)
api(libs.androidide.ts)
api(libs.androidide.ts.java)
@@ -28,6 +30,7 @@ dependencies {
implementation(libs.google.material)
implementation(projects.actions)
+ implementation(projects.annotations)
implementation(projects.common)
implementation(projects.lexers)
implementation(projects.shared)
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/java/JavaLanguage.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/java/JavaLanguage.kt
index a7ab0da5a..7314e1d3f 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/language/java/JavaLanguage.kt
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/java/JavaLanguage.kt
@@ -18,6 +18,7 @@
package com.itsaky.androidide.editor.language.java
import android.content.Context
+import com.itsaky.androidide.editor.language.json.JsonLanguage
import com.itsaky.androidide.editor.language.utils.CommonSymbolPairs
import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguage
import com.itsaky.androidide.editor.language.newline.TSBracketsHandler
@@ -39,6 +40,8 @@ class JavaLanguage(context: Context) :
companion object {
const val TS_TYPE = "java"
+
+ @JvmField val FACTORY = Factory { JavaLanguage(it) }
}
override fun getLanguageServer(): ILanguageServer? {
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/json/JsonLanguage.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/json/JsonLanguage.kt
index e313fcf97..b2b69ce54 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/language/json/JsonLanguage.kt
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/json/JsonLanguage.kt
@@ -19,6 +19,7 @@ package com.itsaky.androidide.editor.language.json
import android.content.Context
import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguage
+import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguage.Factory
import com.itsaky.androidide.treesitter.json.TSLanguageJson
/**
@@ -26,12 +27,15 @@ import com.itsaky.androidide.treesitter.json.TSLanguageJson
*
* @author Akash Yadav
*/
-class JsonLanguage(context: Context) : TreeSitterLanguage(context, TSLanguageJson.newInstance(), EXT_JSON) {
- companion object {
- const val EXT_JSON = "json"
- }
+class JsonLanguage(context: Context) :
+ TreeSitterLanguage(context, TSLanguageJson.newInstance(), TS_TYPE) {
+ companion object {
+ const val TS_TYPE = "json"
- override fun getInterruptionLevel(): Int {
- return INTERRUPTION_LEVEL_STRONG
- }
-}
\ No newline at end of file
+ @JvmField val FACTORY = Factory { JsonLanguage(it) }
+ }
+
+ override fun getInterruptionLevel(): Int {
+ return INTERRUPTION_LEVEL_STRONG
+ }
+}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TSLanguageRegistry.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TSLanguageRegistry.kt
new file mode 100644
index 000000000..9d556d16d
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TSLanguageRegistry.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.treesitter
+
+import com.itsaky.androidide.editor.language.treesitter.internal.TSLanguageRegistryImpl
+
+/**
+ * Registry for managing [TreeSitterLanguage factories][TreeSitterLanguage.Factory].
+ *
+ * @author Akash Yadav
+ */
+interface TSLanguageRegistry {
+
+ companion object {
+ @JvmStatic
+ val instance by lazy { TSLanguageRegistryImpl() }
+ }
+
+ /**
+ * Registers the given [factory] for the given file types.
+ *
+ * @param fileType The file extension for which the given factory should be used.
+ * @param factory The factory which will create the [TreeSitterLanguage] instance.
+ * @throws AlreadyRegisteredException If an instance of [TreeSitterLanguage.Factory] is already
+ * registered for the given file type.
+ */
+ fun register(fileType: String, factory: TreeSitterLanguage.Factory)
+
+ /**
+ * Returns the instance of the [TreeSitterLanguage.Factory] for the given file type.
+ *
+ * @param fileType The file type (extension) to create the language factory instance for.
+ * @return The [TreeSitterLanguage.Factory] implmementation.
+ * @throws NotRegisteredException If no [TreeSitterLanguage.Factory] is registered for the given
+ * file type.
+ */
+ fun getFactory(fileType: String): TreeSitterLanguage.Factory
+
+ /**
+ * Destroys the language registry, removing all the registered language factory. This must be
+ * called only when the application is exiting.
+ */
+ fun destroy()
+
+ class AlreadyRegisteredException(type: String) :
+ IllegalStateException(
+ "An instance of TreeSitterLanguage.Factory is already registered for file type '$type'"
+ )
+
+ class NotRegisteredException(type: String) :
+ RuntimeException("No TreeSitterLanguage.Factory registered for file type '$type'")
+}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterLanguage.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterLanguage.kt
index bd8af3f13..cca1c3c38 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterLanguage.kt
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterLanguage.kt
@@ -67,7 +67,7 @@ abstract class TreeSitterLanguage(context: Context, lang: TSLanguage, type: Stri
log.error("Invalid color scheme returned by color scheme provider", scheme)
return@readScheme
}
-
+
val langScheme = scheme.languages[type] ?: return@readScheme
langScheme.styles.forEach { tsTheme.putStyleRule(it.key, it.value.makeStyle()) }
}
@@ -149,4 +149,15 @@ abstract class TreeSitterLanguage(context: Context, lang: TSLanguage, type: Stri
override fun destroy() {
languageSpec.close()
}
+
+ /** A [Factory] creates instance of a specific [TreeSitterLanguage] implementation. */
+ fun interface Factory {
+
+ /**
+ * Create the instance of the [TreeSitterLanguage] implementation.
+ *
+ * @param context The current context.
+ */
+ fun create(context: Context): T
+ }
}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterLanguageProvider.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterLanguageProvider.kt
index e9bbf4fc6..5bbe7eb7c 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterLanguageProvider.kt
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterLanguageProvider.kt
@@ -18,9 +18,6 @@
package com.itsaky.androidide.editor.language.treesitter
import android.content.Context
-import com.itsaky.androidide.editor.language.java.JavaLanguage
-import com.itsaky.androidide.editor.language.json.JsonLanguage
-import com.itsaky.androidide.editor.language.xml.XMLLanguage
import com.itsaky.androidide.editor.schemes.LanguageSpecProvider.BASE_SPEC_PATH
import java.io.File
import java.io.IOException
@@ -34,19 +31,18 @@ object TreeSitterLanguageProvider {
fun forFile(file: File, context: Context): TreeSitterLanguage? {
val type = file.extension
-
+
try {
// check if there is at least highlights.scm file for this file type
context.assets.open("${BASE_SPEC_PATH}/${type}/highlights.scm").close()
} catch (e: IOException) {
return null
}
-
- return when (type) {
- "java" -> JavaLanguage(context)
- "json" -> JsonLanguage(context)
- "xml" -> XMLLanguage(context)
- else -> return null
+
+ return try {
+ TSLanguageRegistry.instance.getFactory(type).create(context)
+ } catch (e: TSLanguageRegistry.NotRegisteredException) {
+ null
}
}
}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/internal/TSLanguageRegistryImpl.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/internal/TSLanguageRegistryImpl.kt
new file mode 100644
index 000000000..842c73986
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/internal/TSLanguageRegistryImpl.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.treesitter.internal
+
+import com.itsaky.androidide.editor.language.treesitter.TSLanguageRegistry
+import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguage
+import java.util.concurrent.ConcurrentHashMap
+
+/**
+ * Default implementation of [TSLanguageRegistry].
+ *
+ * @author Akash Yadav
+ */
+class TSLanguageRegistryImpl : TSLanguageRegistry {
+
+ private val registry =
+ ConcurrentHashMap>()
+
+ override fun register(
+ fileType: String,
+ factory: TreeSitterLanguage.Factory
+ ) {
+ val older = registry.put(fileType, factory)
+ if (older != null) {
+ registry[fileType] = older
+ throw TSLanguageRegistry.AlreadyRegisteredException(fileType)
+ }
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ override fun getFactory(
+ fileType: String
+ ): TreeSitterLanguage.Factory {
+ return (registry[fileType] ?: throw TSLanguageRegistry.NotRegisteredException(fileType))
+ as TreeSitterLanguage.Factory
+ }
+
+ override fun destroy() {
+ registry.clear()
+ }
+}
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
index 7834a7a4c..7a9f82e93 100644
--- 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
@@ -19,13 +19,11 @@ package com.itsaky.androidide.editor.language.xml
import android.content.Context
import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguage
+import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguage.Factory
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.text.TextUtils.countLeadingSpaceCount
import io.github.rosemoe.sora.util.MyCharacter
/**
@@ -38,6 +36,8 @@ class XMLLanguage(context: Context) :
companion object {
const val TS_TYPE = "xml"
+
+ @JvmField val FACTORY = Factory { XMLLanguage(it) }
}
override fun getLanguageServer(): ILanguageServer? {