diff --git a/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TSAnalyzeManager.kt b/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TSAnalyzeManager.kt
deleted file mode 100644
index 7583798878..0000000000
--- a/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TSAnalyzeManager.kt
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * This file is part of AndroidIDE.
- *
- * AndroidIDE is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * AndroidIDE is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with AndroidIDE. If not, see .
- */
-
-package io.github.rosemoe.sora.editor.ts
-
-import android.os.Bundle
-import com.itsaky.androidide.treesitter.TSInputEdit
-import io.github.rosemoe.sora.editor.ts.spans.DefaultSpanFactory
-import io.github.rosemoe.sora.editor.ts.spans.TsSpanFactory
-import io.github.rosemoe.sora.lang.analysis.AnalyzeManager
-import io.github.rosemoe.sora.lang.analysis.StyleReceiver
-import io.github.rosemoe.sora.lang.styling.Styles
-import io.github.rosemoe.sora.text.CharPosition
-import io.github.rosemoe.sora.text.ContentReference
-import kotlinx.coroutines.CoroutineName
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-
-/**
- * @author Akash Yadav
- */
-open class TSAnalyzeManager(val languageSpec: TsLanguageSpec, var theme: TsTheme) : AnalyzeManager {
-
- var stylesReceiver: StyleReceiver? = null
- var reference: ContentReference? = null
- var spanFactory: TsSpanFactory = DefaultSpanFactory()
-
- open var styles = Styles()
-
- private var analyzeWorker: TsAnalyzeWorker? = null
- protected val analyzerScope = CoroutineScope(
- Dispatchers.Default + CoroutineName("TSAnalyzeManager"))
-
- open fun updateTheme(theme: TsTheme) {
- this.theme = theme
- (styles.spans as LineSpansGenerator?)?.also {
- it.theme = theme
- }
- }
-
- override fun setReceiver(receiver: StyleReceiver?) {
- stylesReceiver = receiver
- analyzeWorker?.stylesReceiver = receiver
- }
-
- override fun reset(content: ContentReference, extraArguments: Bundle) {
- reference = content
- rerun()
- }
-
- override fun insert(start: CharPosition, end: CharPosition, insertedContent: CharSequence) {
- val edit = TSInputEdit.create(start.index shl 1, start.index shl 1, end.index shl 1,
- start.toTSPoint(), start.toTSPoint(), end.toTSPoint())
- (styles.spans as LineSpansGenerator?)?.apply {
- lineCount = reference!!.lineCount
- edit(edit)
- }
- analyzeWorker?.onMod(Mod(TextMod(start.index, end.index, edit, insertedContent.toString())))
- }
-
- override fun delete(start: CharPosition, end: CharPosition, deletedContent: CharSequence) {
- val edit = TSInputEdit.create(start.index shl 1, start.index shl 1, end.index shl 1,
- start.toTSPoint(), start.toTSPoint(), end.toTSPoint())
- (styles.spans as LineSpansGenerator?)?.apply {
- lineCount = reference!!.lineCount
- edit(edit)
- }
- analyzeWorker?.onMod(Mod(TextMod(start.index, end.index, edit, null)))
- }
-
- override fun rerun() {
- analyzeWorker?.stop()
- analyzeWorker = null
-
- (styles.spans as LineSpansGenerator?)?.tree?.close()
- styles.spans = null
- styles = Styles()
-
- val initText = reference?.reference?.toString() ?: ""
-
- analyzeWorker = TsAnalyzeWorker(this, languageSpec, theme, styles, reference!!, spanFactory)
- analyzeWorker!!.apply {
- this.stylesReceiver = this@TSAnalyzeManager.stylesReceiver
- init(Init(initText))
- start(analyzerScope)
- }
- }
-
- override fun destroy() {
- analyzeWorker?.stop()
- analyzeWorker = null
-
- (styles.spans as LineSpansGenerator?)?.tree?.close()
- styles.spans = null
-
- spanFactory.close()
- }
-}
\ No newline at end of file
diff --git a/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsAnalyzeManager.kt b/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsAnalyzeManager.kt
index 550acb150f..d4dfa37258 100644
--- a/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsAnalyzeManager.kt
+++ b/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsAnalyzeManager.kt
@@ -1,72 +1,60 @@
-/*******************************************************************************
- * sora-editor - the awesome code editor for Android
- * https://github.com/Rosemoe/sora-editor
- * Copyright (C) 2020-2023 Rosemoe
+/*
+ * This file is part of AndroidIDE.
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * 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.
*
- * This library 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
- * Lesser General Public License for more details.
+ * 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 Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
- * USA
- *
- * Please contact Rosemoe by email 2073412493@qq.com if you need
- * additional information or have any questions
- ******************************************************************************/
+ * You should have received a copy of the GNU General Public License
+ * along with AndroidIDE. If not, see .
+ */
package io.github.rosemoe.sora.editor.ts
import android.os.Bundle
-import android.os.Message
-import android.util.Log
import com.itsaky.androidide.treesitter.TSInputEdit
-import com.itsaky.androidide.treesitter.TSParser
-import com.itsaky.androidide.treesitter.TSQueryCursor
-import com.itsaky.androidide.treesitter.TSTree
-import com.itsaky.androidide.treesitter.api.TreeSitterInputEdit
-import com.itsaky.androidide.treesitter.api.TreeSitterQueryCapture
-import com.itsaky.androidide.treesitter.api.safeExecQueryCursor
-import com.itsaky.androidide.treesitter.string.UTF16String
-import com.itsaky.androidide.treesitter.string.UTF16StringFactory
-import com.itsaky.androidide.utils.ILogger
-import io.github.rosemoe.sora.data.ObjectAllocator
import io.github.rosemoe.sora.editor.ts.spans.DefaultSpanFactory
import io.github.rosemoe.sora.editor.ts.spans.TsSpanFactory
import io.github.rosemoe.sora.lang.analysis.AnalyzeManager
import io.github.rosemoe.sora.lang.analysis.StyleReceiver
-import io.github.rosemoe.sora.lang.styling.CodeBlock
import io.github.rosemoe.sora.lang.styling.Styles
import io.github.rosemoe.sora.text.CharPosition
import io.github.rosemoe.sora.text.ContentReference
-import java.util.concurrent.LinkedBlockingQueue
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
-open class TsAnalyzeManager(val languageSpec: TsLanguageSpec, var theme: TsTheme) :
- AnalyzeManager {
+/**
+ * @author Akash Yadav
+ */
+open class TsAnalyzeManager(val languageSpec: TsLanguageSpec, var theme: TsTheme) : AnalyzeManager {
- var currentReceiver: StyleReceiver? = null
+ var stylesReceiver: StyleReceiver? = null
var reference: ContentReference? = null
- var thread: TsLooperThread? = null
var spanFactory: TsSpanFactory = DefaultSpanFactory()
open var styles = Styles()
- fun updateTheme(theme: TsTheme) {
+ private var analyzeWorker: TsAnalyzeWorker? = null
+ protected val analyzerScope = CoroutineScope(
+ Dispatchers.Default + CoroutineName("TsAnalyzeManager"))
+
+ open fun updateTheme(theme: TsTheme) {
this.theme = theme
- (styles.spans as LineSpansGenerator?)?.let {
+ (styles.spans as LineSpansGenerator?)?.also {
it.theme = theme
}
}
override fun setReceiver(receiver: StyleReceiver?) {
- currentReceiver = receiver
+ stylesReceiver = receiver
+ analyzeWorker?.stylesReceiver = receiver
}
override fun reset(content: ContentReference, extraArguments: Bundle) {
@@ -75,313 +63,50 @@ open class TsAnalyzeManager(val languageSpec: TsLanguageSpec, var theme: TsTheme
}
override fun insert(start: CharPosition, end: CharPosition, insertedContent: CharSequence) {
- thread?.offerMessage(
- MSG_MOD,
- TextModification(
- start.index,
- end.index,
- TSInputEdit.create(
- start.index * 2,
- start.index * 2,
- end.index * 2,
- start.toTSPoint(),
- start.toTSPoint(),
- end.toTSPoint()
- ),
- insertedContent.toString()
- )
- )
-
+ val edit = TSInputEdit.create(start.index shl 1, start.index shl 1, end.index shl 1,
+ start.toTSPoint(), start.toTSPoint(), end.toTSPoint())
(styles.spans as LineSpansGenerator?)?.apply {
lineCount = reference!!.lineCount
- edit(TSInputEdit.create(
- start.index * 2,
- start.index * 2,
- end.index * 2,
- start.toTSPoint(),
- start.toTSPoint(),
- end.toTSPoint()
- ))
+ edit(edit)
}
+ analyzeWorker?.onMod(Mod(TextMod(start.index, end.index, edit, insertedContent.toString())))
}
override fun delete(start: CharPosition, end: CharPosition, deletedContent: CharSequence) {
- thread?.offerMessage(
- MSG_MOD,
- TextModification(
- start.index,
- end.index,
- TSInputEdit.create(
- start.index * 2,
- end.index * 2,
- start.index * 2,
- start.toTSPoint(),
- end.toTSPoint(),
- start.toTSPoint()
- ),
- null
- )
- )
-
+ val edit = TSInputEdit.create(start.index shl 1, start.index shl 1, end.index shl 1,
+ start.toTSPoint(), start.toTSPoint(), end.toTSPoint())
(styles.spans as LineSpansGenerator?)?.apply {
lineCount = reference!!.lineCount
- edit(TSInputEdit.create(
- start.index * 2,
- end.index * 2,
- start.index * 2,
- start.toTSPoint(),
- end.toTSPoint(),
- start.toTSPoint()
- ))
+ edit(edit)
}
+ analyzeWorker?.onMod(Mod(TextMod(start.index, end.index, edit, null)))
}
override fun rerun() {
- thread?.let {
- if (it.isAlive) {
- it.interrupt()
- it.abort = true
- }
- }
-
+ analyzeWorker?.stop()
+ analyzeWorker = null
(styles.spans as LineSpansGenerator?)?.tree?.close()
-
styles.spans = null
+ styles = Styles()
+
val initText = reference?.reference?.toString() ?: ""
- thread = TsLooperThread().also {
- it.name = "TsDaemon-${nextThreadId()}"
- styles = Styles()
- it.offerMessage(MSG_INIT, initText)
- it.start()
+
+ analyzeWorker = TsAnalyzeWorker(this, languageSpec, theme, styles, reference!!, spanFactory)
+ analyzeWorker!!.apply {
+ this.stylesReceiver = this@TsAnalyzeManager.stylesReceiver
+ init(Init(initText))
+ start(analyzerScope)
}
}
override fun destroy() {
- thread?.let {
- if (it.isAlive) {
- it.interrupt()
- it.abort = true
- }
- }
+ analyzeWorker?.stop()
+ analyzeWorker = null
(styles.spans as LineSpansGenerator?)?.tree?.close()
- spanFactory.close()
- }
-
- companion object {
-
- private const val MSG_BASE = 11451400
- private const val MSG_INIT = MSG_BASE + 1
- private const val MSG_MOD = MSG_BASE + 2
-
- @Volatile
- private var threadId = 0
-
- @Synchronized
- fun nextThreadId() = ++threadId
-
- private val log = ILogger.newInstance("TsAnalyzeManager")
- }
-
- inner class TsLooperThread : Thread() {
-
- private val messageQueue = LinkedBlockingQueue()
-
- @Volatile
- var abort: Boolean = false
- val localText: UTF16String = UTF16StringFactory.newString()
- private val parser = TSParser.create().also {
- it.language = languageSpec.language
- }
- var tree: TSTree? = null
-
- fun offerMessage(what: Int, obj: Any?) {
- val msg = Message.obtain()
- msg.what = what
- msg.obj = obj
- offerMessage(msg)
- }
-
- fun offerMessage(msg: Message) {
- // Result ignored: capacity is enough as it is INT_MAX
- messageQueue.offer(msg)
- }
-
- fun updateStyles() {
- if (thread != this || messageQueue.isNotEmpty()) {
- return
- }
-
- val scopedVariables = TsScopedVariables(tree!!, localText, languageSpec)
- val oldTree = (styles.spans as LineSpansGenerator?)?.tree
- val copied = tree!!.copy()
- styles.spans = LineSpansGenerator(
- copied,
- reference!!.lineCount,
- reference!!.reference,
- theme,
- languageSpec,
- scopedVariables,
- spanFactory
- )
- val oldBlocks = styles.blocks
- updateCodeBlocks()
- if (oldBlocks != null) {
- ObjectAllocator.recycleBlockLines(oldBlocks)
- }
- currentReceiver?.setStyles(this@TsAnalyzeManager, styles) {
- oldTree?.close()
- }
- currentReceiver?.updateBracketProvider(
- this@TsAnalyzeManager,
- TsBracketPairs(copied, languageSpec)
- )
- }
-
- fun updateCodeBlocks() {
- if (languageSpec.blocksQuery.patternCount == 0
- || !languageSpec.blocksQuery.canAccess()
- || tree?.canAccess() != true
- ) {
- return
- }
-
- val blocks = mutableListOf()
- TSQueryCursor.create().use { cursor ->
-
- cursor.safeExecQueryCursor(
- query = languageSpec.blocksQuery,
- tree = tree,
- recycleNodeAfterUse = true,
- matchCondition = null,
- whileTrue = null,
- onClosedOrEdited = { blocks.clear() },
- debugName = "TsAnalyzeManager.updateCodeBlocks()"
- ) { match ->
- if (!languageSpec.blocksPredicator.doPredicate(
- languageSpec.predicates,
- localText,
- match
- )
- ) {
- return@safeExecQueryCursor
- }
-
- match.captures.forEach { capture ->
- val block = ObjectAllocator.obtainBlockLine()
- var node = capture.node
- val start = node.startPoint
-
- block.startLine = start.row
- block.startColumn = start.column / 2
-
- val end = if (languageSpec.blocksQuery.getCaptureNameForId(capture.index)
- .endsWith(".marked")
- ) {
- // Goto last terminal element
- while (node.childCount > 0) {
- node = node.getChild(node.childCount - 1)
- }
- node.startPoint
- } else {
- node.endPoint
- }
- block.endLine = end.row
- block.endColumn = end.column / 2
- if (block.endLine - block.startLine > 1) {
- blocks.add(block)
- }
-
- (capture as? TreeSitterQueryCapture?)?.recycle()
- }
- }
- }
- val distinct = blocks.asSequence().distinct().toMutableList()
- styles.blocks = distinct
- styles.finishBuilding()
- }
-
- override fun run() {
- try {
- while (!abort && !isInterrupted) {
- val msg = messageQueue.take()
- if (!handleMessage(msg)) {
- break
- }
- msg.recycle()
- }
- } catch (e: InterruptedException) {
- // ignored
- }
- releaseThreadResources()
- }
-
- fun handleMessage(msg: Message): Boolean {
- try {
- when (msg.what) {
- MSG_INIT -> {
- localText.append(msg.obj!! as String)
- if (!abort && !isInterrupted) {
- if (parser.isParsing) {
- parser.requestCancellation()
- }
- tree = parser.parseString(localText)
- updateStyles()
- }
- }
-
- MSG_MOD -> {
- if (!abort && !isInterrupted) {
- val modification = msg.obj!! as TextModification
- val newText = modification.changedText
- val t = tree!!
- t.edit(modification.tsEdition)
- if (newText == null) {
- localText.delete(modification.start, modification.end)
- } else {
- if (modification.start == localText.length) {
- localText.append(newText)
- } else {
- localText.insert(modification.start, newText)
- }
- }
- (modification.tsEdition as? TreeSitterInputEdit?)?.recycle()
- if (tree != null && parser.isParsing) {
- parser.requestCancellation()
- }
- tree = parser.parseString(t, localText)
- t.close()
- updateStyles()
- }
- }
- }
- return true
- } catch (e: Exception) {
- Log.w(
- "TsAnalyzeManager",
- "Thread $name exited with an error",
- e
- )
- }
- return false
- }
-
- fun releaseThreadResources() {
- parser.close()
- tree?.close()
- localText.close()
- }
+ styles.spans = null
+ spanFactory.close()
}
-
- private data class TextModification(
- val start: Int,
- val end: Int,
- val tsEdition: TSInputEdit,
- /**
- * null for deletion
- */
- val changedText: String?
- )
}
\ No newline at end of file
diff --git a/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsAnalyzeWorker.kt b/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsAnalyzeWorker.kt
index 64a6ce93bd..dc6de098af 100644
--- a/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsAnalyzeWorker.kt
+++ b/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsAnalyzeWorker.kt
@@ -32,7 +32,6 @@ import io.github.rosemoe.sora.lang.analysis.StyleReceiver
import io.github.rosemoe.sora.lang.styling.CodeBlock
import io.github.rosemoe.sora.lang.styling.Styles
import io.github.rosemoe.sora.text.ContentReference
-import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -47,7 +46,7 @@ import java.util.concurrent.LinkedBlockingQueue
* @author Akash Yadav
*/
internal class TsAnalyzeWorker(
- private val analyzer: TSAnalyzeManager,
+ private val analyzer: TsAnalyzeManager,
private val languageSpec: TsLanguageSpec,
private val theme: TsTheme,
private val styles: Styles,
diff --git a/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsLanguage.kt b/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsLanguage.kt
index fc8ba82e01..ebf01ace47 100644
--- a/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsLanguage.kt
+++ b/editor-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/TsLanguage.kt
@@ -61,7 +61,7 @@ open class TsLanguage(
protected var tsTheme = TsThemeBuilder(languageSpec.tsQuery).apply { themeDescription() }.theme
open val analyzer by lazy {
- TSAnalyzeManager(languageSpec, tsTheme)
+ TsAnalyzeManager(languageSpec, tsTheme)
}
/**
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterAnalyzeManager.kt b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterAnalyzeManager.kt
index 64f6520e8d..ee9949c999 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterAnalyzeManager.kt
+++ b/editor/src/main/java/com/itsaky/androidide/editor/language/treesitter/TreeSitterAnalyzeManager.kt
@@ -18,7 +18,6 @@
package com.itsaky.androidide.editor.language.treesitter
import com.itsaky.androidide.editor.schemes.LanguageScheme
-import io.github.rosemoe.sora.editor.ts.TSAnalyzeManager
import io.github.rosemoe.sora.editor.ts.TsAnalyzeManager
import io.github.rosemoe.sora.editor.ts.TsLanguageSpec
import io.github.rosemoe.sora.editor.ts.TsTheme
@@ -32,7 +31,7 @@ import io.github.rosemoe.sora.lang.styling.Styles
class TreeSitterAnalyzeManager(
languageSpec: TsLanguageSpec,
theme: TsTheme
-) : TSAnalyzeManager(languageSpec, theme) {
+) : TsAnalyzeManager(languageSpec, theme) {
override var styles: Styles = Styles()
set(value) {