mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix: dispatch editor events in background
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.ui
|
||||
|
||||
import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent
|
||||
import com.itsaky.androidide.eventbus.events.editor.DocumentCloseEvent
|
||||
import com.itsaky.androidide.eventbus.events.editor.DocumentEvent
|
||||
import com.itsaky.androidide.eventbus.events.editor.DocumentOpenEvent
|
||||
import com.itsaky.androidide.eventbus.events.editor.DocumentSaveEvent
|
||||
import com.itsaky.androidide.projects.FileManager.onDocumentClose
|
||||
import com.itsaky.androidide.projects.FileManager.onDocumentContentChange
|
||||
import com.itsaky.androidide.projects.FileManager.onDocumentOpen
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.util.concurrent.CancellationException
|
||||
import java.util.concurrent.LinkedBlockingQueue
|
||||
|
||||
/**
|
||||
* Dispatches events for the editor.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class EditorEventDispatcher(
|
||||
var editor: IDEEditor? = null
|
||||
) {
|
||||
|
||||
private val eventQueue = LinkedBlockingQueue<DocumentEvent>()
|
||||
private var eventDispatcherJob: Job? = null
|
||||
|
||||
companion object {
|
||||
|
||||
private val log = ILogger.newInstance("EditorEventDispatcher")
|
||||
}
|
||||
|
||||
fun init(scope: CoroutineScope) {
|
||||
eventDispatcherJob = scope.launch(Dispatchers.Default) {
|
||||
while (isActive) {
|
||||
dispatchNextEvent()
|
||||
}
|
||||
}.also {
|
||||
it.invokeOnCompletion { error ->
|
||||
if (error != null && error !is CancellationException) {
|
||||
log.error("Failed to dispatch editor events", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun dispatch(event: DocumentEvent) {
|
||||
check(eventQueue.offer(event)) {
|
||||
"Failed to dispatch event: $event"
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun dispatchNextEvent() {
|
||||
val event = withContext(Dispatchers.IO) {
|
||||
eventQueue.take()
|
||||
}
|
||||
|
||||
if (editor?.isReleased != false) {
|
||||
return
|
||||
}
|
||||
|
||||
when (event) {
|
||||
is DocumentOpenEvent -> dispatchOpen(event)
|
||||
is DocumentChangeEvent -> dispatchChange(event)
|
||||
is DocumentSaveEvent -> dispatchSave(event)
|
||||
is DocumentCloseEvent -> dispatchClose(event)
|
||||
else -> throw IllegalArgumentException("Unknown document event: $event")
|
||||
}
|
||||
}
|
||||
|
||||
private fun dispatchOpen(event: DocumentOpenEvent) {
|
||||
onDocumentOpen(event)
|
||||
post(event)
|
||||
}
|
||||
|
||||
private fun dispatchChange(event: DocumentChangeEvent) {
|
||||
onDocumentContentChange(event)
|
||||
post(event)
|
||||
}
|
||||
|
||||
private fun dispatchSave(event: DocumentSaveEvent) {
|
||||
post(event)
|
||||
}
|
||||
|
||||
private fun dispatchClose(event: DocumentCloseEvent) {
|
||||
onDocumentClose(event)
|
||||
post(event)
|
||||
}
|
||||
|
||||
private fun post(event: DocumentEvent) {
|
||||
EventBus.getDefault().post(event)
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
editor = null
|
||||
eventDispatcherJob?.cancel(CancellationException("Cancellation requested"))
|
||||
}
|
||||
}
|
||||
@@ -64,9 +64,6 @@ import com.itsaky.androidide.models.Range
|
||||
import com.itsaky.androidide.preferences.internal.tabSize
|
||||
import com.itsaky.androidide.preferences.internal.visiblePasswordFlag
|
||||
import com.itsaky.androidide.progress.ICancelChecker
|
||||
import com.itsaky.androidide.projects.FileManager.onDocumentClose
|
||||
import com.itsaky.androidide.projects.FileManager.onDocumentContentChange
|
||||
import com.itsaky.androidide.projects.FileManager.onDocumentOpen
|
||||
import com.itsaky.androidide.syntax.colorschemes.DynamicColorScheme
|
||||
import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE
|
||||
import com.itsaky.androidide.tasks.cancelIfActive
|
||||
@@ -132,6 +129,7 @@ open class IDEEditor @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
protected val editorScope = CoroutineScope(Dispatchers.Default)
|
||||
protected val eventDispatcher = EditorEventDispatcher()
|
||||
|
||||
var languageServer: ILanguageServer? = null
|
||||
private set
|
||||
@@ -189,6 +187,8 @@ open class IDEEditor @JvmOverloads constructor(
|
||||
init {
|
||||
run {
|
||||
editorFeatures.editor = this
|
||||
eventDispatcher.editor = this
|
||||
eventDispatcher.init(editorScope)
|
||||
initEditor()
|
||||
}
|
||||
}
|
||||
@@ -378,6 +378,9 @@ open class IDEEditor @JvmOverloads constructor(
|
||||
markUnmodified()
|
||||
|
||||
editorFeatures.editor = null
|
||||
eventDispatcher.editor = null
|
||||
|
||||
eventDispatcher.destroy()
|
||||
|
||||
selectionChangeRunner?.also { selectionChangeHandler.removeCallbacks(it) }
|
||||
selectionChangeRunner = null
|
||||
@@ -502,8 +505,7 @@ open class IDEEditor @JvmOverloads constructor(
|
||||
if (file == null) {
|
||||
return
|
||||
}
|
||||
val saveEvent = DocumentSaveEvent(file!!.toPath())
|
||||
EventBus.getDefault().post(saveEvent)
|
||||
eventDispatcher.dispatch(DocumentSaveEvent(file!!.toPath()))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -757,9 +759,7 @@ open class IDEEditor @JvmOverloads constructor(
|
||||
fileVersion
|
||||
)
|
||||
|
||||
// Notify FileManager first
|
||||
onDocumentOpen(openEvent)
|
||||
EventBus.getDefault().post(openEvent)
|
||||
eventDispatcher.dispatch(openEvent)
|
||||
}
|
||||
|
||||
protected open fun dispatchDocumentChangeEvent(event: ContentChangeEvent) {
|
||||
@@ -786,9 +786,7 @@ open class IDEEditor @JvmOverloads constructor(
|
||||
val changeEvent = DocumentChangeEvent(file, changedText, text.toString(),
|
||||
++fileVersion, type, changeDelta, changeRange)
|
||||
|
||||
// Notify FileManager first
|
||||
onDocumentContentChange(changeEvent)
|
||||
EventBus.getDefault().post(changeEvent)
|
||||
eventDispatcher.dispatch(changeEvent)
|
||||
}
|
||||
|
||||
protected open fun dispatchDocumentSelectedEvent() {
|
||||
@@ -796,8 +794,7 @@ open class IDEEditor @JvmOverloads constructor(
|
||||
return
|
||||
}
|
||||
val file = file ?: return
|
||||
val selectedEvent = DocumentSelectedEvent(file.toPath())
|
||||
EventBus.getDefault().post(selectedEvent)
|
||||
eventDispatcher.dispatch(DocumentSelectedEvent(file.toPath()))
|
||||
}
|
||||
|
||||
protected open fun dispatchDocumentCloseEvent() {
|
||||
@@ -805,11 +802,8 @@ open class IDEEditor @JvmOverloads constructor(
|
||||
return
|
||||
}
|
||||
val file = file ?: return
|
||||
val closeEvent = DocumentCloseEvent(file.toPath(), cursorLSPRange)
|
||||
|
||||
// Notify FileManager first
|
||||
onDocumentClose(closeEvent)
|
||||
EventBus.getDefault().post(closeEvent)
|
||||
eventDispatcher.dispatch(DocumentCloseEvent(file.toPath(), cursorLSPRange))
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user