diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index f1320a117..9a5e20415 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -549,6 +549,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index 6b3caea9d..544f69660 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,6 +1,5 @@
-
\ No newline at end of file
diff --git a/editor/src/main/assets/editor/treesitter/kotlin/highlights.scm b/editor/src/main/assets/editor/treesitter/kotlin/highlights.scm
new file mode 100644
index 000000000..32a04f0f9
--- /dev/null
+++ b/editor/src/main/assets/editor/treesitter/kotlin/highlights.scm
@@ -0,0 +1,412 @@
+;;; Identifiers
+
+(simple_identifier) @variable
+
+; `this` this keyword inside classes
+(this_expression) @variable.builtin
+
+; `super` keyword inside classes
+(super_expression) @variable.builtin
+
+(class_parameter
+ (simple_identifier) @property)
+
+(class_body
+ (property_declaration
+ (variable_declaration
+ (simple_identifier) @property)))
+
+; id_1.id_2.id_3: `id_2` and `id_3` are assumed as object properties
+(_
+ (navigation_suffix
+ (simple_identifier) @property))
+
+; SCREAMING CASE identifiers are assumed to be constants
+((simple_identifier) @constant
+(#match? @constant "^[A-Z][A-Z0-9_]*$"))
+
+(_
+ (navigation_suffix
+ (simple_identifier) @constant
+ (#lua-match? @constant "^[A-Z][A-Z0-9_]*$")))
+
+(enum_entry
+ (simple_identifier) @constant)
+
+(type_identifier) @type
+
+; '?' operator, replacement for Java @Nullable
+(nullable_type) @punctuation.special
+
+(type_alias
+ (type_identifier) @type.definition)
+
+((type_identifier) @type.builtin
+ (#any-of? @type.builtin
+ "Byte"
+ "Short"
+ "Int"
+ "Long"
+ "UByte"
+ "UShort"
+ "UInt"
+ "ULong"
+ "Float"
+ "Double"
+ "Boolean"
+ "Char"
+ "String"
+ "Array"
+ "ByteArray"
+ "ShortArray"
+ "IntArray"
+ "LongArray"
+ "UByteArray"
+ "UShortArray"
+ "UIntArray"
+ "ULongArray"
+ "FloatArray"
+ "DoubleArray"
+ "BooleanArray"
+ "CharArray"
+ "Map"
+ "Set"
+ "List"
+ "EmptyMap"
+ "EmptySet"
+ "EmptyList"
+ "MutableMap"
+ "MutableSet"
+ "MutableList"
+))
+
+(package_header "package" @keyword
+ . (identifier (simple_identifier) @namespace))
+
+(import_header
+ "import" @include)
+
+; The last `simple_identifier` in a `import_header` will always either be a function
+; or a type. Classes can appear anywhere in the import path, unlike functions
+(import_header
+ (identifier
+ (simple_identifier) @type @_import)
+ (import_alias
+ (type_identifier) @type.definition)?
+ (#match? @_import "^[A-Z]"))
+
+(import_header
+ (identifier
+ (simple_identifier) @function @_import .)
+ (import_alias
+ (type_identifier) @function)?
+ (#match? @_import "^[a-z]"))
+
+; TODO: Separate labeled returns/breaks/continue/super/this
+; Must be implemented in the parser first
+(label) @label
+
+;;; Function definitions
+
+(function_declaration
+ (simple_identifier) @function)
+
+(getter
+ ("get") @function.builtin)
+(setter
+ ("set") @function.builtin)
+
+(primary_constructor) @constructor
+(secondary_constructor
+ ("constructor") @constructor)
+
+(constructor_invocation
+ (user_type
+ (type_identifier) @constructor))
+
+(anonymous_initializer
+ ("init") @constructor)
+
+(parameter
+ (simple_identifier) @parameter)
+
+(parameter_with_optional_type
+ (simple_identifier) @parameter)
+
+; lambda parameters
+(lambda_literal
+ (lambda_parameters
+ (variable_declaration
+ (simple_identifier) @parameter)))
+
+;;; Function calls
+
+; function()
+(call_expression
+ . (simple_identifier) @function.call)
+
+; ::function
+(callable_reference
+ . (simple_identifier) @function.call)
+
+; object.function() or object.property.function()
+(call_expression
+ (navigation_expression
+ (navigation_suffix
+ (simple_identifier) @function.call) . ))
+
+(call_expression
+ . (simple_identifier) @function.builtin
+ (#any-of? @function.builtin
+ "arrayOf"
+ "arrayOfNulls"
+ "byteArrayOf"
+ "shortArrayOf"
+ "intArrayOf"
+ "longArrayOf"
+ "ubyteArrayOf"
+ "ushortArrayOf"
+ "uintArrayOf"
+ "ulongArrayOf"
+ "floatArrayOf"
+ "doubleArrayOf"
+ "booleanArrayOf"
+ "charArrayOf"
+ "emptyArray"
+ "mapOf"
+ "setOf"
+ "listOf"
+ "emptyMap"
+ "emptySet"
+ "emptyList"
+ "mutableMapOf"
+ "mutableSetOf"
+ "mutableListOf"
+ "print"
+ "println"
+ "error"
+ "TODO"
+ "run"
+ "runCatching"
+ "repeat"
+ "lazy"
+ "lazyOf"
+ "enumValues"
+ "enumValueOf"
+ "assert"
+ "check"
+ "checkNotNull"
+ "require"
+ "requireNotNull"
+ "with"
+ "suspend"
+ "synchronized"
+))
+
+;;; Literals
+
+(comment) @comment
+
+(shebang_line) @preproc
+
+(comment) @spell
+
+(real_literal) @float
+[
+ (integer_literal)
+ (long_literal)
+ (hex_literal)
+ (bin_literal)
+ (unsigned_literal)
+] @number
+
+[
+ "null" ; should be highlighted the same as booleans
+ (boolean_literal)
+] @boolean
+
+(character_literal) @character
+
+[
+ (line_string_literal)
+ (multi_line_string_literal)
+] @string
+
+; NOTE: Escapes not allowed in multi-line strings
+(line_string_literal (character_escape_seq) @string.escape)
+
+; There are 3 ways to define a regex
+; - "[abc]?".toRegex()
+(call_expression
+ (navigation_expression
+ ([(line_string_literal) (multi_line_string_literal)] @string.regex)
+ (navigation_suffix
+ ((simple_identifier) @_function
+ (#eq? @_function "toRegex")))))
+
+; - Regex("[abc]?")
+(call_expression
+ ((simple_identifier) @_function
+ (#eq? @_function "Regex"))
+ (call_suffix
+ (value_arguments
+ (value_argument
+ [ (line_string_literal) (multi_line_string_literal) ] @string.regex))))
+
+; - Regex.fromLiteral("[abc]?")
+(call_expression
+ (navigation_expression
+ ((simple_identifier) @_class
+ (#eq? @_class "Regex"))
+ (navigation_suffix
+ ((simple_identifier) @_function
+ (#eq? @_function "fromLiteral"))))
+ (call_suffix
+ (value_arguments
+ (value_argument
+ [ (line_string_literal) (multi_line_string_literal) ] @string.regex))))
+
+;;; Keywords
+
+(type_alias "typealias" @keyword)
+
+(companion_object "companion" @keyword)
+
+[
+ (class_modifier)
+ (member_modifier)
+ (function_modifier)
+ (property_modifier)
+ (platform_modifier)
+ (variance_modifier)
+ (parameter_modifier)
+ (visibility_modifier)
+ (reification_modifier)
+ (inheritance_modifier)
+] @type.qualifier
+
+[
+ "val"
+ "var"
+ "enum"
+ "class"
+ "object"
+ "interface"
+ "fun"
+; "typeof" ; NOTE: It is reserved for future use
+] @keyword
+
+("fun") @keyword.function
+
+(jump_expression) @keyword.return
+
+[
+ "if"
+ "else"
+ "when"
+] @conditional
+
+[
+ "for"
+ "do"
+ "while"
+] @repeat
+
+[
+ "try"
+ "catch"
+ "throw"
+ "finally"
+] @exception
+
+
+(annotation
+ "@" @attribute (use_site_target)? @attribute)
+(annotation
+ (user_type
+ (type_identifier) @attribute))
+(annotation
+ (constructor_invocation
+ (user_type
+ (type_identifier) @attribute)))
+
+(file_annotation
+ "@" @attribute "file" @attribute ":" @attribute)
+(file_annotation
+ (user_type
+ (type_identifier) @attribute))
+(file_annotation
+ (constructor_invocation
+ (user_type
+ (type_identifier) @attribute)))
+
+;;; Operators & Punctuation
+
+[
+ "!"
+ "!="
+ "!=="
+ "="
+ "=="
+ "==="
+ ">"
+ ">="
+ "<"
+ "<="
+ "||"
+ "&&"
+ "+"
+ "++"
+ "+="
+ "-"
+ "--"
+ "-="
+ "*"
+ "*="
+ "/"
+ "/="
+ "%"
+ "%="
+ "?."
+ "?:"
+ "!!"
+ "is"
+ "!is"
+ "in"
+ "!in"
+ "as"
+ "as?"
+ ".."
+ "->"
+] @operator
+
+[
+ "(" ")"
+ "[" "]"
+ "{" "}"
+] @punctuation.bracket
+
+[
+ "."
+ ","
+ ";"
+ ":"
+ "::"
+] @punctuation.delimiter
+
+; NOTE: `interpolated_identifier`s can be highlighted in any way
+(line_string_literal
+ "$" @punctuation.special
+ (interpolated_identifier) @none @variable)
+(line_string_literal
+ "${" @punctuation.special
+ (interpolated_expression) @none
+ "}" @punctuation.special)
+
+(multi_line_string_literal
+ "$" @punctuation.special
+ (interpolated_identifier) @none @variable)
+(multi_line_string_literal
+ "${" @punctuation.special
+ (interpolated_expression) @none
+ "}" @punctuation.special)
\ No newline at end of file
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/AnyOfPredicate.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/AnyOfPredicate.kt
new file mode 100644
index 000000000..2467072b8
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/AnyOfPredicate.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.predicates
+
+import com.itsaky.androidide.treesitter.TSQuery
+import com.itsaky.androidide.treesitter.TSQueryMatch
+import com.itsaky.androidide.treesitter.TSQueryPredicateStep
+import io.github.rosemoe.sora.editor.ts.predicate.PredicateResult
+import io.github.rosemoe.sora.editor.ts.predicate.TsClientPredicateStep
+import io.github.rosemoe.sora.editor.ts.predicate.TsPredicate
+import io.github.rosemoe.sora.editor.ts.predicate.builtin.getCaptureContent
+
+/**
+ * [TsPredicate] implementation for '#any-of?' query predicates.
+ *
+ * Syntax : `"#any-of?" @capture "string" ["string", ... ] Done`
+ *
+ * Checks if the text of `@capture` matches (literally) any of the `"string"` defined.
+ *
+ * @author Akash Yadav
+ */
+object AnyOfPredicate : TreeSitterPredicate() {
+
+ override val name: String
+ get() = "any-of"
+
+ override fun canHandle(steps: List): Boolean {
+ return steps.size > 4 &&
+ steps.let {
+ it[0].predicateType == TSQueryPredicateStep.Type.String &&
+ it[1].predicateType == TSQueryPredicateStep.Type.Capture &&
+ it[it.lastIndex].predicateType == TSQueryPredicateStep.Type.Done &&
+ it.subList(2, it.lastIndex - 1).all { step ->
+ step.predicateType == TSQueryPredicateStep.Type.String
+ }
+ }
+ }
+
+ override fun doPredicateInternal(
+ tsQuery: TSQuery,
+ text: CharSequence,
+ match: TSQueryMatch,
+ predicate: List
+ ): PredicateResult {
+ val captured = getCaptureContent(tsQuery, match, predicate[1].content, text)
+ val toMatch = predicate.subList(2, predicate.lastIndex - 1).map { it.content }
+ for (capture in captured) {
+ if (capture !in toMatch) {
+ return PredicateResult.REJECT
+ }
+ }
+ return PredicateResult.ACCEPT
+ }
+}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/MatchPredicate.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/MatchPredicate.kt
new file mode 100644
index 000000000..4b5ccfef7
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/MatchPredicate.kt
@@ -0,0 +1,86 @@
+/*
+ * 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.predicates
+
+import com.itsaky.androidide.treesitter.TSQuery
+import com.itsaky.androidide.treesitter.TSQueryMatch
+import com.itsaky.androidide.treesitter.TSQueryPredicateStep
+import io.github.rosemoe.sora.editor.ts.predicate.PredicateResult
+import io.github.rosemoe.sora.editor.ts.predicate.TsClientPredicateStep
+import io.github.rosemoe.sora.editor.ts.predicate.TsPredicate
+import io.github.rosemoe.sora.editor.ts.predicate.builtin.getCaptureContent
+import io.github.rosemoe.sora.editor.ts.predicate.builtin.parametersMatch
+import java.util.concurrent.ConcurrentHashMap
+import java.util.regex.PatternSyntaxException
+
+/**
+ * [TsPredicate] implementation for '#match?' query predicates.
+ *
+ * @author Akash Yadav
+ */
+open class MatchPredicate protected constructor() : TreeSitterPredicate() {
+
+ override val name: String
+ get() = "match"
+
+ companion object {
+
+ @JvmField
+ val INSTANCE = MatchPredicate()
+
+ @JvmField
+ val PARAMETERS =
+ arrayOf(
+ TSQueryPredicateStep.Type.String,
+ TSQueryPredicateStep.Type.Capture,
+ TSQueryPredicateStep.Type.String,
+ TSQueryPredicateStep.Type.Done
+ )
+ }
+
+ private val cache = ConcurrentHashMap()
+
+ override fun doPredicateInternal(
+ tsQuery: TSQuery,
+ text: CharSequence,
+ match: TSQueryMatch,
+ predicate: List
+ ): PredicateResult {
+ val captured = getCaptureContent(tsQuery, match, predicate[1].content, text)
+ try {
+ var regex = cache[predicate[2].content]
+ if (regex == null) {
+ regex = Regex(predicate[2].content)
+ cache[predicate[2].content] = regex
+ }
+ for (str in captured) {
+ if (regex.find(str) == null) {
+ return PredicateResult.REJECT
+ }
+ }
+ return PredicateResult.ACCEPT
+ } catch (e: PatternSyntaxException) {
+ e.printStackTrace()
+ return PredicateResult.UNHANDLED
+ }
+ }
+
+ override fun canHandle(steps: List): Boolean {
+ return parametersMatch(steps, PARAMETERS)
+ }
+}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/NotMatchPredicate.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/NotMatchPredicate.kt
new file mode 100644
index 000000000..d4b7a3e9a
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/NotMatchPredicate.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.predicates
+
+import com.itsaky.androidide.treesitter.TSQuery
+import com.itsaky.androidide.treesitter.TSQueryMatch
+import io.github.rosemoe.sora.editor.ts.predicate.PredicateResult
+import io.github.rosemoe.sora.editor.ts.predicate.TsClientPredicateStep
+import io.github.rosemoe.sora.editor.ts.predicate.TsPredicate
+
+/**
+ * [TsPredicate] implementation for '#not-match?' query predicates.
+ *
+ * @author Akash Yadav
+ */
+object NotMatchPredicate : MatchPredicate() {
+
+ override val name: String
+ get() = "not-match"
+
+ override fun doPredicateInternal(
+ tsQuery: TSQuery,
+ text: CharSequence,
+ match: TSQueryMatch,
+ predicate: List
+ ): PredicateResult {
+
+ // Invert the result of the match predicate
+ return when (val result = super.doPredicateInternal(tsQuery, text, match, predicate)) {
+ PredicateResult.ACCEPT -> PredicateResult.REJECT
+ PredicateResult.REJECT -> PredicateResult.ACCEPT
+ else -> result
+ }
+ }
+}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/TreeSitterPredicate.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/TreeSitterPredicate.kt
new file mode 100644
index 000000000..0fbe0b9c2
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/predicates/TreeSitterPredicate.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.predicates
+
+import com.itsaky.androidide.treesitter.TSQuery
+import com.itsaky.androidide.treesitter.TSQueryMatch
+import io.github.rosemoe.sora.editor.ts.predicate.PredicateResult
+import io.github.rosemoe.sora.editor.ts.predicate.TsClientPredicateStep
+import io.github.rosemoe.sora.editor.ts.predicate.TsPredicate
+
+/**
+ * Base class for tree-sitter predicate implementations.
+ *
+ * @author Akash Yadav
+ */
+abstract class TreeSitterPredicate : TsPredicate {
+
+ /** The name of the predicate that will be used to match. */
+ abstract val name: String
+
+ /**
+ * Whether the implmentation can handle the given predicate steps.
+ *
+ * @param steps The predicate steps.
+ * @return `true` if and only if the implementatin can handle the given predicate steps, `false`
+ * otherwise.
+ */
+ abstract fun canHandle(steps: List): Boolean
+
+ /**
+ * Performs the predicate check.
+ *
+ * @param tsQuery The [TSQuery] for the predicate.
+ * @param text The editor text.
+ * @param match The [TSQueryMatch] object.
+ * @param predicate The predicate steps.
+ * @return The result of the predicate check.
+ */
+ abstract fun doPredicateInternal(
+ tsQuery: TSQuery,
+ text: CharSequence,
+ match: TSQueryMatch,
+ predicate: List
+ ): PredicateResult
+
+ override fun doPredicate(
+ tsQuery: TSQuery,
+ text: CharSequence,
+ match: TSQueryMatch,
+ predicate: List
+ ): PredicateResult {
+
+ if (predicate.isEmpty() || predicate[0].content != "${name}?" || !canHandle(predicate)) {
+ return PredicateResult.UNHANDLED
+ }
+
+ return doPredicateInternal(tsQuery, text, match, predicate)
+ }
+}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/schemes/LanguageSpecProvider.kt b/editor/src/main/java/com/itsaky/androidide/editor/schemes/LanguageSpecProvider.kt
index a7a950723..cb078fc78 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/schemes/LanguageSpecProvider.kt
+++ b/editor/src/main/java/com/itsaky/androidide/editor/schemes/LanguageSpecProvider.kt
@@ -19,6 +19,9 @@ package com.itsaky.androidide.editor.schemes
import android.content.Context
import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguageSpec
+import com.itsaky.androidide.editor.language.treesitter.predicates.AnyOfPredicate
+import com.itsaky.androidide.editor.language.treesitter.predicates.MatchPredicate
+import com.itsaky.androidide.editor.language.treesitter.predicates.NotMatchPredicate
import com.itsaky.androidide.treesitter.TSLanguage
import com.itsaky.androidide.utils.ILogger
import io.github.rosemoe.sora.editor.ts.LocalsCaptureSpec
@@ -33,7 +36,7 @@ object LanguageSpecProvider {
const val BASE_SPEC_PATH = "editor/treesitter"
private val log = ILogger.newInstance("LanguageSpecProvider")
-
+
@JvmStatic
@JvmOverloads
fun getLanguageSpec(
@@ -42,15 +45,20 @@ object LanguageSpecProvider {
lang: TSLanguage,
localsCaptureSpec: LocalsCaptureSpec = LocalsCaptureSpec.DEFAULT
): TreeSitterLanguageSpec {
- val editorLangSpec = TsLanguageSpec(
- language = lang,
- highlightScmSource = readScheme(context, type, "highlights"),
- localsScmSource = readScheme(context, type, "locals"),
- codeBlocksScmSource = readScheme(context, type, "blocks"),
- bracketsScmSource = readScheme(context, type, "brackets"),
- localsCaptureSpec = localsCaptureSpec
+ val editorLangSpec =
+ TsLanguageSpec(
+ language = lang,
+ highlightScmSource = readScheme(context, type, "highlights"),
+ localsScmSource = readScheme(context, type, "locals"),
+ codeBlocksScmSource = readScheme(context, type, "blocks"),
+ bracketsScmSource = readScheme(context, type, "brackets"),
+ localsCaptureSpec = localsCaptureSpec,
+ predicates = listOf(MatchPredicate.INSTANCE, NotMatchPredicate, AnyOfPredicate)
+ )
+ return TreeSitterLanguageSpec(
+ spec = editorLangSpec,
+ indentsQueryScm = readScheme(context, type, "indents")
)
- return TreeSitterLanguageSpec(spec = editorLangSpec, indentsQueryScm = readScheme(context, type, "indents"))
}
private fun readScheme(context: Context, type: String, name: String): String {