mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
feat: annotation based TSLanguage registry
This commit is contained in:
+4
-4
@@ -15,19 +15,19 @@
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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)
|
||||
+1
-1
@@ -15,4 +15,4 @@
|
||||
# along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
com.itsaky.androidide.annotations.ksp.IDESymbolProcessorProvider
|
||||
com.itsaky.androidide.annotations.ksp.inflater.ViewAdapterSymbolProcessorProvider
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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? {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@JvmField val FACTORY = Factory { JsonLanguage(it) }
|
||||
}
|
||||
|
||||
override fun getInterruptionLevel(): Int {
|
||||
return INTERRUPTION_LEVEL_STRONG
|
||||
}
|
||||
}
|
||||
|
||||
+67
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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 <T : TreeSitterLanguage> register(fileType: String, factory: TreeSitterLanguage.Factory<T>)
|
||||
|
||||
/**
|
||||
* 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 <T : TreeSitterLanguage> getFactory(fileType: String): TreeSitterLanguage.Factory<T>
|
||||
|
||||
/**
|
||||
* 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'")
|
||||
}
|
||||
+12
-1
@@ -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<T : TreeSitterLanguage> {
|
||||
|
||||
/**
|
||||
* Create the instance of the [TreeSitterLanguage] implementation.
|
||||
*
|
||||
* @param context The current context.
|
||||
*/
|
||||
fun create(context: Context): T
|
||||
}
|
||||
}
|
||||
|
||||
+6
-10
@@ -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<TreeSitterLanguage>(type).create(context)
|
||||
} catch (e: TSLanguageRegistry.NotRegisteredException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+56
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<String, TreeSitterLanguage.Factory<out TreeSitterLanguage>>()
|
||||
|
||||
override fun <T : TreeSitterLanguage> register(
|
||||
fileType: String,
|
||||
factory: TreeSitterLanguage.Factory<T>
|
||||
) {
|
||||
val older = registry.put(fileType, factory)
|
||||
if (older != null) {
|
||||
registry[fileType] = older
|
||||
throw TSLanguageRegistry.AlreadyRegisteredException(fileType)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : TreeSitterLanguage> getFactory(
|
||||
fileType: String
|
||||
): TreeSitterLanguage.Factory<T> {
|
||||
return (registry[fileType] ?: throw TSLanguageRegistry.NotRegisteredException(fileType))
|
||||
as TreeSitterLanguage.Factory<T>
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
registry.clear()
|
||||
}
|
||||
}
|
||||
@@ -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? {
|
||||
|
||||
Reference in New Issue
Block a user