From 6edee1bcec7ecdd5799bce8149f9c64d3e297d8e Mon Sep 17 00:00:00 2001 From: Vladimir Iakovlev Date: Fri, 15 Jul 2016 02:56:29 +0300 Subject: [PATCH] Listen to editor events instead of polling --- .../actions/ToggleShowingCodeAction.kt | 2 + .../client_idea/services/SyncService.kt | 24 ++++++--- .../client_idea/utils/EditorListener.kt | 51 +++++++++++++++++++ .../client_idea/utils/SyncLoopThread.kt | 28 ---------- .../code_view/client_idea/utils/context.kt | 1 + 5 files changed, 70 insertions(+), 36 deletions(-) create mode 100644 src/main/code_view/client_idea/utils/EditorListener.kt delete mode 100644 src/main/code_view/client_idea/utils/SyncLoopThread.kt diff --git a/src/main/code_view/client_idea/actions/ToggleShowingCodeAction.kt b/src/main/code_view/client_idea/actions/ToggleShowingCodeAction.kt index d2d8722..9b20277 100644 --- a/src/main/code_view/client_idea/actions/ToggleShowingCodeAction.kt +++ b/src/main/code_view/client_idea/actions/ToggleShowingCodeAction.kt @@ -67,9 +67,11 @@ class ToggleShowingCodeAction : AnAction() { override fun actionPerformed(e: AnActionEvent) { context(e) { if (it.sync.syncing) { + it.listener.stop() it.sync.stop() } else { if (it.sync.start()) { + it.listener.listen() showSyncingNotification(it.sync.project, it.sync.session) } else { showErrorNotification(it.sync.project) diff --git a/src/main/code_view/client_idea/services/SyncService.kt b/src/main/code_view/client_idea/services/SyncService.kt index 53942c2..8b945c7 100644 --- a/src/main/code_view/client_idea/services/SyncService.kt +++ b/src/main/code_view/client_idea/services/SyncService.kt @@ -2,9 +2,9 @@ package code_view.client_idea.services import code_view.client_idea.Client import code_view.client_idea.Session -import code_view.client_idea.utils.SyncLoopThread import code_view.client_idea.settings.url import code_view.client_idea.utils.context +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Editor @@ -12,22 +12,21 @@ import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import com.intellij.psi.util.PsiUtilBase +import java.util.concurrent.LinkedBlockingQueue class SyncService { lateinit var project: Project lateinit var client: Client lateinit var session: Session - var previousSession: Session? = null + val queue = LinkedBlockingQueue() var syncing = false init { - SyncLoopThread { - if (syncing && project is Project) { - onDispatchThread { - session = updateSession(session) - } - + ApplicationManager.getApplication().executeOnPooledThread { + var previousSession: Session? = null + while (true) { + val session = queue.take() if (session != previousSession && session.fileName != null) { client.updateSession(session) previousSession = session @@ -74,6 +73,15 @@ class SyncService { return this } + fun sync() { + session = updateSession(session) + if (!queue.isEmpty()) { + queue.clear() + } + + queue.offer(session) + } + companion object { fun getInstance(project: Project) = ServiceManager .getService(project, SyncService::class.java) diff --git a/src/main/code_view/client_idea/utils/EditorListener.kt b/src/main/code_view/client_idea/utils/EditorListener.kt new file mode 100644 index 0000000..8c1e4b3 --- /dev/null +++ b/src/main/code_view/client_idea/utils/EditorListener.kt @@ -0,0 +1,51 @@ +package code_view.client_idea.utils + +import com.intellij.openapi.editor.EditorFactory +import com.intellij.openapi.editor.event.* + + +class EditorListener(val ctx: Context) : CaretListener, DocumentListener, SelectionListener, VisibleAreaListener { + val editorManager: EditorEventMulticaster = EditorFactory.getInstance().eventMulticaster + + fun listen() { + editorManager.addDocumentListener(this) + editorManager.addSelectionListener(this) + editorManager.addCaretListener(this) + editorManager.addVisibleAreaListener(this) + } + + fun stop() { + editorManager.removeSelectionListener(this) + editorManager.removeDocumentListener(this) + editorManager.removeCaretListener(this) + editorManager.removeVisibleAreaListener(this) + } + + override fun documentChanged(event: DocumentEvent) { + ctx.sync.sync() + } + + override fun caretAdded(caretEvent: CaretEvent) { + ctx.sync.sync() + } + + override fun caretRemoved(caretEvent: CaretEvent) { + ctx.sync.sync() + } + + override fun beforeDocumentChange(event: DocumentEvent) { + ctx.sync.sync() + } + + override fun caretPositionChanged(event: CaretEvent) { + ctx.sync.sync() + } + + override fun visibleAreaChanged(event: VisibleAreaEvent) { + ctx.sync.sync() + } + + override fun selectionChanged(event: SelectionEvent) { + ctx.sync.sync() + } +} diff --git a/src/main/code_view/client_idea/utils/SyncLoopThread.kt b/src/main/code_view/client_idea/utils/SyncLoopThread.kt deleted file mode 100644 index 664e5d1..0000000 --- a/src/main/code_view/client_idea/utils/SyncLoopThread.kt +++ /dev/null @@ -1,28 +0,0 @@ -package code_view.client_idea.utils - -import com.intellij.openapi.application.ApplicationManager - -class SyncLoopThread(run: SyncLoopThread.() -> Unit) { - val delay = 20L - var shouldStop = false - - - val thread = ApplicationManager.getApplication().executeOnPooledThread { - while (!shouldStop) { - run() - Thread.sleep(delay) - } - } - - fun onDispatchThread(run: SyncLoopThread.() -> Unit) { - synchronized(this) { - ApplicationManager.getApplication().invokeLater { - run() - } - } - } - - fun stop() { - shouldStop = true - } -} \ No newline at end of file diff --git a/src/main/code_view/client_idea/utils/context.kt b/src/main/code_view/client_idea/utils/context.kt index e7cafd9..7eb7308 100644 --- a/src/main/code_view/client_idea/utils/context.kt +++ b/src/main/code_view/client_idea/utils/context.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project class Context(val project: Project) { val sync by lazy { SyncService.getInstance(project) } val settings by lazy { PropertiesComponent.getInstance(project)!! } + val listener by lazy { EditorListener(this) } } fun context(project: Project, run: (context: Context) -> T) =