build: reorganize and reconfigure modules to resolve dependency resolution errors

Gradle, for some reason, does not the path of modules to identify them uniquely. Instead, the 'build id' is used to do so, which consists of the maven group and artifact ID. So, even if two modules are located in separate directories, but have the name group and artifact ID, including both of them in other modules may result in dependency resolution errors.
This commit is contained in:
Akash Yadav
2024-05-29 13:11:44 +05:30
parent c0c185cfb7
commit 1efd6a04d5
2457 changed files with 1069 additions and 709 deletions
+41
View File
@@ -0,0 +1,41 @@
/*
* 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/>.
*/
import com.itsaky.androidide.build.config.BuildConfig
plugins {
id("com.android.library")
id("kotlin-android")
}
groupConfig {
groupIdSuffix.set("core")
}
android {
namespace = "${BuildConfig.packageName}.editor.api"
}
dependencies {
api(libs.androidide.ts)
api(projects.core.lspApi)
api(projects.core.lspModels)
implementation(projects.core.common)
implementation(projects.logging.logger)
}
+21
View File
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
@@ -0,0 +1,204 @@
/*
* 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.api;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.itsaky.androidide.models.Position;
import com.itsaky.androidide.models.Range;
import io.github.rosemoe.sora.text.CharPosition;
import java.io.File;
/**
* Interface for other modules to access the editor.
*
* @author Akash Yadav
*/
public interface IEditor {
String KEY_FILE = "ide.editor.file";
/**
* Get the file that this editor is currently editing.
*
* @return The file instance.
*/
@Nullable
File getFile();
/**
* Whether the content of this editor differs from the content of the file on disk.
*
* @return <code>true</code> if the content has been modified, <code>false</code> otherwise.
*/
boolean isModified();
/**
* Set the selection of this editor to the given position.
*
* @param position The position to select.
*/
void setSelection(@NonNull Position position);
/**
* Set selection to the given range.
*
* @param range The range to select.
*/
default void setSelection(@NonNull Range range) {
setSelection(range.getStart(), range.getEnd());
}
void setSelection(@NonNull Position start, @NonNull Position end);
/**
* Set selection around the given position.
* @param position The position to set selection around.
*/
default void setSelectionAround(CharPosition position) {
setSelectionAround(position.getLine(), position.getColumn());
}
/**
* Set selection around the given position.
* @param position The position to set selection around.
*/
default void setSelectionAround(Position position) {
setSelectionAround(position.getLine(), position.getColumn());
}
/**
* Set selection around the given position.
* @param line The line index.
* @param column The column index.
*/
void setSelectionAround(int line, int column);
/**
* Get the cursor's selection range in the form of {@link Range}.
*
* @return The {@link Range} of the cursor.
*/
Range getCursorLSPRange();
/**
* Get the cursor's position in the form of {@link Position}.
*
* @return The {@link Position} of the cursor.
*/
Position getCursorLSPPosition();
/**
* Validates the range if it is invalid and returns a valid range.
*
* @param range Th range to validate.
* @return A new, validated range.
*/
void validateRange(@NonNull Range range);
/**
* Checks if the given range is valid for this editor's text.
*
* @param range The range to check.
* @return <code>true</code> if valid, <code>false</code> otherwise.
*/
default boolean isValidRange(Range range) {
return isValidRange(range, false);
}
/**
* Checks if the given range is valid for this editor's text.
*
* @param range The range to check.
* @param allowColumnEqual Whether to allow <code>column</code> to be equal to column count of *
* <code>line</code>.
* @return <code>true</code> if valid, <code>false</code> otherwise.
*/
boolean isValidRange(Range range, boolean allowColumnEqual);
/**
* Checks if the given position is valid for this editor's text.
*
* @param position The position to check.
* @return <code>true</code> if valid, <code>false</code> otherwise.
*/
default boolean isValidPosition(Position position) {
return isValidPosition(position, false);
}
/**
* Checks if the given position is valid for this editor's text.
*
* @param position The position to check.
* @param allowColumnEqual Whether to allow <code>column</code> to be equal to column count of *
* <code>line</code>.
* @return <code>true</code> if valid, <code>false</code> otherwise.
*/
boolean isValidPosition(Position position, boolean allowColumnEqual);
/**
* Checks if the given line is valid for this editor's text.
*
* @param line The line to check.
* @return <code>true</code> if valid, <code>false</code> otherwise.
*/
boolean isValidLine(int line);
/**
* Checks if the given column is valid for this editor's text.
*
* @param line The line of the column to check.
* @param column The column to check.
* @return <code>true</code> if valid, <code>false</code> otherwise.
* @see #isValidColumn(int, int, boolean)
*/
default boolean isValidColumn(int line, int column) {
return isValidColumn(line, column, false);
}
/**
* Checks if the given column is valid for this editor's text.
*
* @param line The line of the column to check.
* @param column The column to check.
* @param allowColumnEqual Whether to allow <code>column</code> to be equal to column count of
* <code>line</code>.
* @return <code>true</code> if valid, <code>false</code> otherwise.
*/
boolean isValidColumn(int line, int column, boolean allowColumnEqual);
/**
* Append the given text at the end of the editor's content.
*
* @param text The text to append.
* @return The line at which the text was appended.
*/
int append(CharSequence text);
/**
* Replaces the editor's existing content with the given content.
*
* @param newContent The new content to set to the editor.
*/
void replaceContent(CharSequence newContent);
/** Set the selection of the editor's cursor to the last line of the it's content. */
void goToEnd();
}
@@ -0,0 +1,91 @@
/*
* 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.api
import com.itsaky.androidide.lsp.api.ILanguageClient
import com.itsaky.androidide.lsp.api.ILanguageServer
import com.itsaky.androidide.lsp.models.Command
import com.itsaky.androidide.lsp.models.SignatureHelp
/**
* LSP functions for the editor.
*
* @author Akash Yadav
*/
interface ILspEditor {
/**
* Set the language server that this editor will connect with. If the language client is not set,
* it'll be set to [ILanguageClient] from the language server.
*
* @param server The server to set. Provide `null` to disable all the language server features.
*/
fun setLanguageServer(server: ILanguageServer?)
/**
* Set the language client to this editor.
*
* @param client The client to set.
*/
fun setLanguageClient(client: ILanguageClient?)
/**
* Execute the given LSP command in the editor.
*
* @param command The command to execute.
*/
fun executeCommand(command: Command?)
/**
* If any language server is set, requests signature help at the cursor's position. On a valid
* response, shows the signature help in a popup window.
*/
fun signatureHelp()
/**
* Shows the given signature help in the editor.
*
* @param help The signature help data to show.
*/
fun showSignatureHelp(help: SignatureHelp?)
/**
* If any language server is set, asks the language server to find the definition of token at the
* cursor position.
*
* If the server returns a valid response, and the file specified in the response is same the file
* in this editor, the range specified in the response will be selected.
*/
fun findDefinition()
/**
* If any language server instance is set, finds the references to of the token at the current
* cursor position.
*
* If the server returns a valid response, that response is forwarded to the [ ].
*/
fun findReferences()
/**
* Requests the language server to provided a semantically larger selection than the current
* selection. If a valid response is received, that range will be selected.
*/
fun expandSelection()
/** Ensures that all the windows are dismissed. */
fun ensureWindowsDismissed()
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSInputEdit
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
class TreeSitterInputEdit @JvmOverloads internal constructor(
startByte: Int = 0,
oldEndByte: Int = 0,
newEndByte: Int = 0,
startPoint: TSPoint? = null,
oldEndPoint: TSPoint? = null,
newEndPoint: TSPoint? = null
) : TSInputEdit(startByte, oldEndByte, newEndByte, startPoint, oldEndPoint, newEndPoint),
RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
/**
* Obtain an instance of [TreeSitterInputEdit].
*/
@JvmStatic
fun obtain(startByte: Int,
oldEndByte: Int,
newEndByte: Int,
startPoint: TSPoint,
oldEndPoint: TSPoint,
newEndPoint: TSPoint): TreeSitterInputEdit {
return obtainFromPool<TreeSitterInputEdit>().apply {
this.startByte = startByte
this.oldEndByte = oldEndByte
this.newEndByte = newEndByte
this.startPoint = startPoint
this.oldEndPoint = oldEndPoint
this.newEndPoint = newEndPoint
}
}
}
override fun recycle() {
this.startByte = 0
this.oldEndByte = 0
this.newEndByte = 0
this.startPoint = null
this.oldEndPoint = null
this.newEndPoint = null
returnToPool()
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSLookaheadIterator
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterLookaheadIterator @JvmOverloads internal constructor(pointer: Long = 0) :
TSLookaheadIterator(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterLookaheadIterator {
return obtainFromPool<TreeSitterLookaheadIterator>().apply {
nativeObject = pointer
}
}
}
override fun close() {
super.close()
recycle()
}
override fun recycle() {
this.nativeObject = 0
this.langName = null
returnToPool()
}
}
@@ -0,0 +1,55 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSLanguage
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterNativeLanguage @JvmOverloads internal constructor(
name: String? = null,
pointers: LongArray? = longArrayOf(0, 0)
) : TSLanguage(name, pointers), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(name: String?, pointers: LongArray?): TreeSitterNativeLanguage {
return obtainFromPool<TreeSitterNativeLanguage>().apply {
this.name = name
this.nativeObject = pointers?.get(0) ?: 0
this.libHandle = pointers?.get(1) ?: 0
}
}
}
override fun close() {
super.close()
recycle()
}
override fun recycle() {
this.nativeObject = 0
this.name = null
this.libHandle = 0
returnToPool()
}
}
@@ -0,0 +1,64 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterNode @JvmOverloads internal constructor(
context0: Int = 0,
context1: Int = 0,
context2: Int = 0,
context3: Int = 0,
id: Long = 0,
tree: Long = 0
) : TSNode(context0, context1, context2, context3, id, tree),
RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(
context0: Int, context1: Int, context2: Int, context3: Int, id: Long, tree: Long
): TreeSitterNode {
return obtainFromPool<TreeSitterNode>().apply {
this.context0 = context0
this.context1 = context1
this.context2 = context2
this.context3 = context3
this.id = id
this.tree = tree
}
}
}
override fun recycle() {
this.context0 = 0
this.context1 = 0
this.context2 = 0
this.context3 = 0
this.id = 0
this.tree = 0
this.mTree = null
returnToPool()
}
}
@@ -0,0 +1,133 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSInputEdit
import com.itsaky.androidide.treesitter.TSLanguage
import com.itsaky.androidide.treesitter.TSLookaheadIterator
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.treesitter.TSParser
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.treesitter.TSQuery
import com.itsaky.androidide.treesitter.TSQueryCapture
import com.itsaky.androidide.treesitter.TSQueryCursor
import com.itsaky.androidide.treesitter.TSQueryMatch
import com.itsaky.androidide.treesitter.TSQueryPredicateStep
import com.itsaky.androidide.treesitter.TSRange
import com.itsaky.androidide.treesitter.TSTree
import com.itsaky.androidide.treesitter.TSTreeCursor
import com.itsaky.androidide.treesitter.TSTreeCursorNode
import com.itsaky.androidide.treesitter.string.SynchronizedUTF16String
import com.itsaky.androidide.treesitter.string.UTF16String
import com.itsaky.androidide.treesitter.util.TSObjectFactory
/**
* [TSObjectFactory] implementation for AndroidIDE.
*
* @author Akash Yadav
*/
class TreeSitterObjectFactory : TSObjectFactory {
override fun createInputEdit(startByte: Int, oldEndByte: Int, newEndByte: Int,
startPoint: TSPoint, oldEndPoint: TSPoint, newEndPoint: TSPoint): TSInputEdit {
return TreeSitterInputEdit.obtain(
startByte,
oldEndByte,
newEndByte,
startPoint,
oldEndPoint,
newEndPoint
)
}
override fun createParser(parserPointer: Long): TSParser {
return TreeSitterParser.obtain(parserPointer)
}
override fun createQuery(queryPointer: Long): TSQuery {
return TreeSitterQuery.obtain(queryPointer)
}
override fun createQueryCursor(pointer: Long): TSQueryCursor {
return TreeSitterQueryCursor.obtain(pointer)
}
override fun createPoint(row: Int, column: Int): TSPoint {
return TreeSitterPoint.obtain(row, column)
}
override fun createRange(startByte: Int, endByte: Int, startPoint: TSPoint,
endPoint: TSPoint?): TSRange {
return TreeSitterRange.obtain(startByte, endByte, startPoint, endPoint)
}
override fun createRangeArr(size: Int): Array<TSRange?> {
return arrayOfNulls(size)
}
override fun createTree(pointer: Long): TSTree {
return TreeSitterTree.obtain(pointer)
}
override fun createTreeCursor(pointer: Long): TSTreeCursor {
return TreeSitterTreeCursor.obtain(pointer)
}
override fun createNode(context0: Int, context1: Int, context2: Int, context3: Int, id: Long,
treePointer: Long): TSNode {
return TreeSitterNode.obtain(context0, context1, context2, context3, id, treePointer)
}
override fun createQueryCapture(node: TSNode?, index: Int): TSQueryCapture {
return TreeSitterQueryCapture.obtain(node, index)
}
override fun createQueryMatch(id: Int, patternIndex: Int,
captures: Array<TSQueryCapture?>?): TSQueryMatch {
return TreeSitterQueryMatch.obtain(id, patternIndex, captures)
}
override fun createQueryPredicateStep(type: Int, valueId: Int): TSQueryPredicateStep {
return TreeSitterQueryPredicateStep.obtain(type, valueId)
}
override fun createQueryPredicateStepArr(size: Int): Array<TSQueryPredicateStep?> {
return arrayOfNulls(size)
}
override fun createTreeCursorNode(
type: String?,
name: String?,
startByte: Int,
endByte: Int
): TSTreeCursorNode {
return TreeSitterTreeCursorNode.obtain(type, name, startByte, endByte)
}
override fun createLookaheadIterator(pointer: Long): TSLookaheadIterator {
return TreeSitterLookaheadIterator.obtain(pointer)
}
override fun createLanguage(name: String?, pointers: LongArray?): TSLanguage {
return TreeSitterNativeLanguage.obtain(name, pointers)
}
override fun createString(pointer: Long, isSynchronized: Boolean): UTF16String {
return if (isSynchronized) SynchronizedUTF16String(pointer) else UTF16String(pointer)
}
}
@@ -0,0 +1,90 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.utils.RecyclableObjectPool
import com.itsaky.androidide.utils.RecyclableObjectPool.Companion.CAPACITY_DEFAULT
import com.itsaky.androidide.utils.RecyclableObjectPool.Companion.CAPACITY_MINI
import com.itsaky.androidide.utils.newRecyclableObjectPool
import com.itsaky.androidide.utils.uncheckedCast
import java.util.concurrent.ConcurrentHashMap
/**
* Provides instances of [RecyclableObjectPool] for tree sitter objects.
*
* @author Akash Yadav
*/
internal object TreeSitterObjectPoolProvider {
private val caches = ConcurrentHashMap<Class<out RecyclableObjectPool.Recyclable>, RecyclableObjectPool<*>>()
init {
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterInputEdit)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterLookaheadIterator)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterNativeLanguage)
putPool(capacity = 1_00_000, fillFirst = 1000, factory = ::TreeSitterNode)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterParser)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterPoint)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterQuery)
putPool(capacity = 1_00_000, fillFirst = 1000, factory = ::TreeSitterQueryCapture)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterQueryCursor)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterQueryMatch)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterQueryPredicateStep)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterRange)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterTree)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterTreeCursor)
putPool(capacity = CAPACITY_MINI, factory = ::TreeSitterTreeCursorNode)
}
fun logMetrics() {
caches.forEach { (_, pool) ->
pool.logMetrics()
}
}
inline fun <reified T : RecyclableObjectPool.Recyclable> getPool(): RecyclableObjectPool<T>? {
return getPool(T::class.java)
}
inline fun <reified T : RecyclableObjectPool.Recyclable> requirePool(): RecyclableObjectPool<T> {
return requireNotNull(getPool())
}
fun <T : RecyclableObjectPool.Recyclable> getPool(klass: Class<T>): RecyclableObjectPool<T>? {
return caches[klass]?.let { uncheckedCast(it) }
}
fun <T : RecyclableObjectPool.Recyclable> requirePool(klass: Class<T>): RecyclableObjectPool<T> {
return requireNotNull(getPool(klass))
}
private inline fun <reified T : RecyclableObjectPool.Recyclable> putPool(
capacity: Int = CAPACITY_DEFAULT,
fillFirst: Int = 0,
factory: RecyclableObjectPool.Factory<T>
) {
if (caches[T::class.java] != null) {
throw IllegalArgumentException("Attempt to replace object pool for ${T::class.java}")
}
// disable metrics logging for tree sitter objects
// this is required because the log views also use tree sitter to highlight the lines
// if we enable metrics, it would result in an infite loop and 'analyze and log' in some cases
caches[T::class.java] = newRecyclableObjectPool(capacity, fillFirst, false, factory)
}
}
@@ -0,0 +1,52 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSParser
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterParser @JvmOverloads internal constructor(
pointer: Long = 0
) : TSParser(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(
pointer: Long
): TreeSitterParser {
return obtainFromPool<TreeSitterParser>().apply {
this.nativeObject = pointer
}
}
}
override fun close() {
super.close()
recycle()
}
override fun recycle() {
this.nativeObject = 0
returnToPool()
}
}
@@ -0,0 +1,48 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterPoint @JvmOverloads internal constructor(
row: Int = 0,
column: Int = 0
) : TSPoint(row, column), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(row: Int, column: Int): TreeSitterPoint {
return obtainFromPool<TreeSitterPoint>().apply {
this.row = row
this.column = column
}
}
}
override fun recycle() {
this.row = 0
this.column = 0
returnToPool()
}
}
@@ -0,0 +1,53 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSQuery
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQuery @JvmOverloads internal constructor(
pointer: Long = 0
) : TSQuery(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterQuery {
return obtainFromPool<TreeSitterQuery>().apply {
this.nativeObject = pointer
}
}
}
override fun close() {
super.close()
recycle()
}
override fun recycle() {
this.nativeObject = 0
this.captureNames = null
this.errorOffset = 0
this.errorType = 0
returnToPool()
}
}
@@ -0,0 +1,54 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.treesitter.TSQueryCapture
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQueryCapture @JvmOverloads internal constructor(
node: TSNode? = null,
index: Int = 0
) : TSQueryCapture(node, index), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(node: TSNode?, index: Int): TreeSitterQueryCapture {
return obtainFromPool<TreeSitterQueryCapture>().apply {
this.node = node
this.index = index
}
}
}
override fun recycle() {
(this.node as? TreeSitterNode?)?.apply {
if (!isRecycled) {
recycle()
}
}
this.index = 0
this.node = null
returnToPool()
}
}
@@ -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 <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.treesitter.api
import com.itsaky.androidide.treesitter.TSQueryCursor
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQueryCursor(
pointer: Long = 0
) : TSQueryCursor(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterQueryCursor {
return obtainFromPool<TreeSitterQueryCursor>().apply {
this.nativeObject = pointer
}
}
}
override fun close() {
super.close()
recycle()
}
override fun recycle() {
this.nativeObject = 0
returnToPool()
}
}
@@ -0,0 +1,54 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSQueryCapture
import com.itsaky.androidide.treesitter.TSQueryMatch
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQueryMatch @JvmOverloads internal constructor(
id: Int = 0,
patternIndex: Int = 0,
captures: Array<out TSQueryCapture?>? = null
) : TSQueryMatch(id, patternIndex, captures, null),
RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(id: Int, patternIndex: Int,
captures: Array<out TSQueryCapture?>?): TreeSitterQueryMatch {
return obtainFromPool<TreeSitterQueryMatch>().apply {
this.id = id
this.patternIndex = patternIndex
this.captures = captures
}
}
}
override fun recycle() {
this.id = 0
this.patternIndex = 0
this.captures = null
returnToPool()
}
}
@@ -0,0 +1,49 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSQueryPredicateStep
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterQueryPredicateStep @JvmOverloads internal constructor(
type: Int = 0,
valueId: Int = 0
) : TSQueryPredicateStep(type, valueId), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(type: Int, valueId: Int): TreeSitterQueryPredicateStep {
return obtainFromPool<TreeSitterQueryPredicateStep>().apply {
this.type = type
this.valueId = valueId
}
}
}
override fun recycle() {
this.type = 0
this.valueId = 0
this.cachedType = null
returnToPool()
}
}
@@ -0,0 +1,60 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSPoint
import com.itsaky.androidide.treesitter.TSRange
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterRange @JvmOverloads internal constructor(
startByte: Int = 0,
endByte: Int = 0,
startPoint: TSPoint? = null,
endPoint: TSPoint? = null
) : TSRange(startByte, endByte, startPoint, endPoint),
RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(startByte: Int, endByte: Int, startPoint: TSPoint?,
endPoint: TSPoint?): TreeSitterRange {
return obtainFromPool<TreeSitterRange>().apply {
this.startByte = startByte
this.endByte = endByte
this.startPoint = startPoint
this.endPoint = endPoint
}
}
}
override fun recycle() {
(this.startPoint as? TreeSitterPoint?)?.recycle()
(this.endPoint as? TreeSitterPoint?)?.recycle()
this.startByte = 0
this.endByte = 0
this.startPoint = null
this.endPoint = null
returnToPool()
}
}
@@ -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.treesitter.api
import com.itsaky.androidide.treesitter.TSTree
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterTree @JvmOverloads internal constructor(
pointer: Long = 0
) : TSTree(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
private var ownerThread: Thread? = null
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterTree {
return obtainFromPool<TreeSitterTree>().apply {
this.nativeObject = pointer
this.ownerThread = Thread.currentThread()
}
}
}
override fun close() {
super.close()
this.nativeObject = 0
recycle()
}
override fun recycle() {
this.ownerThread = null
if (!canAccess()) {
returnToPool()
}
}
}
@@ -0,0 +1,54 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSTreeCursor
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterTreeCursor @JvmOverloads internal constructor(
pointer: Long = 0
) : TSTreeCursor(pointer), RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(pointer: Long): TreeSitterTreeCursor {
return obtainFromPool<TreeSitterTreeCursor>().apply {
this.nativeObject = pointer
}
}
}
override fun close() {
super.close()
recycle()
}
override fun recycle() {
this.nativeObject = 0
this.context0 = 0
this.context1 = 0
this.id = 0
this.tree = 0
returnToPool()
}
}
@@ -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.treesitter.api
import com.itsaky.androidide.treesitter.TSTreeCursorNode
import com.itsaky.androidide.utils.DefaultRecyclable
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* @author Akash Yadav
*/
class TreeSitterTreeCursorNode @JvmOverloads internal constructor(
type: String? = null,
name: String? = null,
startByte: Int = 0,
endByte: Int = 0
) : TSTreeCursorNode(type, name, startByte, endByte),
RecyclableObjectPool.Recyclable by DefaultRecyclable() {
companion object {
@JvmStatic
fun obtain(type: String?, name: String?, startByte: Int,
endByte: Int): TreeSitterTreeCursorNode {
return obtainFromPool<TreeSitterTreeCursorNode>().apply {
this.type = type
this.name = name
this.startByte = startByte
this.endByte = endByte
}
}
}
override fun recycle() {
this.type = null
this.name = null
this.startByte = 0
this.endByte = 0
returnToPool()
}
}
@@ -0,0 +1,38 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.utils.RecyclableObjectPool
/**
* Returns this [RecyclableObjectPool.Recyclable] object to the pool from the [TreeSitterObjectPoolProvider].
*
* @see TreeSitterObjectPoolProvider.requirePool
*/
internal inline fun <reified T : RecyclableObjectPool.Recyclable> T.returnToPool() {
TreeSitterObjectPoolProvider.requirePool<T>().recycle(this)
}
/**
* Get an instance of [T] from the [RecyclableObjectPool] using [TreeSitterObjectPoolProvider].
*
* @see TreeSitterObjectPoolProvider.requirePool
*/
internal inline fun <reified T : RecyclableObjectPool.Recyclable> obtainFromPool(): T {
return TreeSitterObjectPoolProvider.requirePool<T>().obtain()
}
@@ -0,0 +1,186 @@
/*
* 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.treesitter.api
import com.itsaky.androidide.treesitter.TSNode
import com.itsaky.androidide.treesitter.TSQuery
import com.itsaky.androidide.treesitter.TSQueryCursor
import com.itsaky.androidide.treesitter.TSQueryMatch
import com.itsaky.androidide.treesitter.TSTree
import org.slf4j.LoggerFactory
@PublishedApi
internal val log = LoggerFactory.getLogger("TsUtilsKt")
/**
* Safely create a query cursor and execute the given [TSQuery]. The given [action] will be called for
* every [TSQueryMatch]. If the tree, cursor, tree or the tree's node is closed or edited while the cursor is
* querying the node, the [onClosedOrEdited] will be called.
*
* This method does not close the [TSQueryCursor] instance.
*/
inline fun <ResultT> TSQueryCursor.safeExecQueryCursor(
query: TSQuery,
tree: TSTree?,
recycleNodeAfterUse: Boolean = true,
crossinline matchCondition: (TSQueryMatch?) -> Boolean = { true },
crossinline whileTrue: (TSQueryMatch?) -> Boolean = { true },
crossinline onClosedOrEdited: () -> Unit = {},
debugName: String = "",
debugLogging: Boolean = false,
crossinline action: (TSQueryMatch) -> ResultT
): ResultT? {
if (tree == null || !tree.canAccess()) {
if (debugLogging) {
log.debug("$debugName: Cannot execute query, tree is null or not accessible", "tree=$tree",
"tree.canAccess=${tree?.canAccess()}")
}
return null
}
val rootNode = tree.rootNode
if (!rootNode.canAccess() || rootNode.hasChanges()) {
if (debugLogging) {
log.debug(
"$debugName, Cannot execute query, tree's root node is not accessible or has been edited",
"rootNode=$rootNode", "rootNode.canAccess=${rootNode.canAccess()}",
"rootNode.hasChanges=${rootNode.canAccess() && rootNode.hasChanges()}")
}
return null
}
return safeExecQueryCursor(
query = query,
node = rootNode,
recycleNodeAfterUse = recycleNodeAfterUse,
matchCondition = {
val result = tree.canAccess() && matchCondition(it)
if (!result && debugLogging) {
log.debug("$debugName: tree.canAccess=${tree.canAccess()}")
}
result
},
whileTrue = whileTrue,
onClosedOrEdited = onClosedOrEdited,
debugName = debugName,
debugLogging = debugLogging,
action = action
)
}
/**
* Safely create a query cursor and execute the given [TSQuery]. The given [action] will be called for
* every [TSQueryMatch]. If the tree, cursor or the node is closed or edited while the cursor is
* querying the node, the [onClosedOrEdited] will be called.
*
* This method does not close the [TSQueryCursor] instance.
*/
inline fun <ResultT> TSQueryCursor.safeExecQueryCursor(
query: TSQuery,
node: TSNode,
recycleNodeAfterUse: Boolean = true,
crossinline matchCondition: (TSQueryMatch?) -> Boolean = { true },
crossinline whileTrue: (TSQueryMatch?) -> Boolean = { true },
crossinline onClosedOrEdited: () -> Unit = {},
debugName: String = "",
debugLogging: Boolean = false,
crossinline action: (TSQueryMatch) -> ResultT
): ResultT? {
return doSafeExecQueryCursor(
query = query,
node = node,
recycleNodeAfterUse = recycleNodeAfterUse,
matchCondition = { match ->
match != null && canAccess() && node.canAccess() && !node.hasChanges() && matchCondition(
match)
},
whileTrue = whileTrue,
onClosedOrEdited = onClosedOrEdited,
debugName = debugName,
debugLogging = debugLogging,
action = action)
}
@PublishedApi
internal inline fun <ResultT> TSQueryCursor.doSafeExecQueryCursor(
query: TSQuery,
node: TSNode,
recycleNodeAfterUse: Boolean = true,
crossinline matchCondition: (TSQueryMatch?) -> Boolean,
crossinline whileTrue: (TSQueryMatch?) -> Boolean,
crossinline onClosedOrEdited: () -> Unit,
debugName: String = "",
debugLogging: Boolean = false,
crossinline action: (TSQueryMatch) -> ResultT
): ResultT? {
if (!query.canAccess()) {
if (debugLogging) {
log.debug("$debugName: Cannot execute query, query is not accessible")
}
return null
}
if (!node.canAccess() || node.hasChanges()) {
if (debugLogging) {
log.debug("$debugName: Cannot execute query, node is not accessible or has been edited",
"node.canAccess=${node.canAccess()}",
"node.hasChanges=${node.canAccess() && node.hasChanges()}")
}
return null
}
exec(query, node)
var match = nextMatch()
while (matchCondition(match) && whileTrue(match)) {
val result = action(match)
if (!matchCondition(match)) {
if (debugLogging) {
log.debug(
"$debugName: Cannot proceed with query operation.",
"cursor.canAccess=${canAccess()}",
"query.canAccess=${query.canAccess()}",
"node.canAccess=${node.canAccess()}",
"node.hasChanges=${node.canAccess() && node.hasErrors()}"
)
}
onClosedOrEdited()
break
}
(match as? TreeSitterQueryMatch?)?.recycle()
// if the action does not produce any output and simply returns Unit (void)
// then ignore the result and continue with the capture
if (result != Unit && result != null) {
return result
}
match = nextMatch()
}
if (recycleNodeAfterUse && node is TreeSitterNode && !node.isRecycled) {
node.recycle()
}
return null
}
+1
View File
@@ -0,0 +1 @@
/build
@@ -7,6 +7,10 @@ plugins {
id("com.google.devtools.ksp") version libs.versions.ksp
}
groupConfig {
groupIdSuffix.set("core")
}
android {
namespace = "${BuildConfig.packageName}.editor"
}
@@ -18,8 +22,8 @@ kapt {
}
dependencies {
ksp(projects.annotationProcessorsKsp)
kapt(projects.annotationProcessors)
ksp(projects.annotation.processorsKsp)
kapt(projects.annotation.processors)
api(libs.androidide.ts)
api(libs.androidide.ts.java)
@@ -30,8 +34,8 @@ dependencies {
api(libs.androidx.collection)
api(libs.common.editor)
api(projects.editorApi)
api(projects.editorTreesitter)
api(projects.editor.api)
api(projects.editor.treesitter)
implementation(libs.androidx.annotation)
implementation(libs.androidx.appcompat)
@@ -42,20 +46,19 @@ dependencies {
implementation(libs.common.utilcode)
implementation(libs.google.material)
implementation(projects.actions)
implementation(projects.annotations)
implementation(projects.common)
implementation(projects.eventbusAndroid)
implementation(projects.eventbusEvents)
implementation(projects.lexers)
implementation(projects.shared)
implementation(projects.resources)
implementation(projects.lsp.api)
implementation(projects.lsp.java)
implementation(projects.lsp.xml)
implementation(projects.annotation.annotations)
implementation(projects.core.actions)
implementation(projects.core.common)
implementation(projects.core.lspApi)
implementation(projects.core.resources)
implementation(projects.editor.lexers)
implementation(projects.event.eventbusAndroid)
implementation(projects.event.eventbusEvents)
implementation(projects.java.lsp)
implementation(projects.utilities.shared)
implementation(projects.xml.lsp)
testImplementation(libs.tests.junit)
testImplementation(libs.tests.google.truth)
testImplementation(libs.tests.robolectric)
View File

Some files were not shown because too many files have changed in this diff Show More