Skip to content

Commit 384d465

Browse files
Improve Cursor Handling
- Show just a bar for the remote cursors - Clear bars when stopping client
1 parent c7787bb commit 384d465

File tree

1 file changed

+36
-16
lines changed

1 file changed

+36
-16
lines changed

src/main/kotlin/io/github/ethersync/sync/Cursortracker.kt

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
package io.github.ethersync.sync
22

3-
import com.intellij.openapi.application.EDT
43
import com.intellij.openapi.editor.LogicalPosition
54
import com.intellij.openapi.editor.event.CaretEvent
65
import com.intellij.openapi.editor.event.CaretListener
76
import com.intellij.openapi.editor.markup.*
87
import com.intellij.openapi.fileEditor.FileEditorManager
98
import com.intellij.openapi.fileEditor.TextEditor
109
import com.intellij.openapi.project.Project
10+
import com.intellij.openapi.rd.util.withUiContext
1111
import com.intellij.ui.JBColor
1212
import com.intellij.util.io.await
1313
import io.github.ethersync.protocol.CursorEvent
1414
import io.github.ethersync.protocol.CursorRequest
1515
import io.github.ethersync.protocol.RemoteEthersyncClientProtocol
1616
import kotlinx.coroutines.CoroutineScope
17-
import kotlinx.coroutines.Dispatchers
1817
import kotlinx.coroutines.launch
19-
import kotlinx.coroutines.withContext
2018
import org.eclipse.lsp4j.Position
2119
import org.eclipse.lsp4j.Range
2220
import org.eclipse.lsp4j.jsonrpc.ResponseErrorException
2321
import java.util.*
22+
import kotlin.collections.HashMap
2423

2524
class Cursortracker(
2625
private val project: Project,
2726
private val cs: CoroutineScope,
2827
) : CaretListener {
2928

30-
private val highlighter = HashMap<String, List<RangeHighlighter>>()
29+
private data class Key(val documentUri: String, val user: String)
30+
private val highlighter = HashMap<Key, List<RangeHighlighter>>()
3131

3232
var remoteProxy: RemoteEthersyncClientProtocol? = null
3333

@@ -38,14 +38,15 @@ class Cursortracker(
3838
.filter { editor -> editor.file.canonicalFile != null }
3939
.firstOrNull { editor -> editor.file.canonicalFile!!.url == cursorEvent.documentUri } ?: return
4040

41+
val key = Key(cursorEvent.documentUri, cursorEvent.userId)
4142
val editor = fileEditor.editor
4243

4344
cs.launch {
44-
withContext(Dispatchers.EDT) {
45+
withUiContext {
4546
synchronized(highlighter) {
4647
val markupModel = editor.markupModel
4748

48-
val previous = highlighter.remove(cursorEvent.userId)
49+
val previous = highlighter.remove(key)
4950
if (previous != null) {
5051
for (hl in previous) {
5152
markupModel.removeHighlighter(hl)
@@ -58,16 +59,12 @@ class Cursortracker(
5859
val endPosition = editor.logicalPositionToOffset(LogicalPosition(range.end.line, range.end.character))
5960

6061
val textAttributes = TextAttributes().apply {
61-
// foregroundColor = JBColor(JBColor.YELLOW, JBColor.DARK_GRAY)
62-
63-
// TODO: unclear which is the best effect type
6462
effectType = EffectType.ROUNDED_BOX
6563
effectColor = JBColor(JBColor.YELLOW, JBColor.DARK_GRAY)
6664
}
67-
6865
val hl = markupModel.addRangeHighlighter(
6966
startPosition,
70-
endPosition + 1,
67+
endPosition,
7168
HighlighterLayer.ADDITIONAL_SYNTAX,
7269
textAttributes,
7370
HighlighterTargetArea.EXACT_RANGE
@@ -78,7 +75,7 @@ class Cursortracker(
7875

7976
newHighlighter.add(hl)
8077
}
81-
highlighter[cursorEvent.userId] = newHighlighter
78+
highlighter[key] = newHighlighter
8279
}
8380
}
8481
}
@@ -87,9 +84,15 @@ class Cursortracker(
8784
override fun caretPositionChanged(event: CaretEvent) {
8885
val canonicalFile = event.editor.virtualFile?.canonicalFile ?: return
8986
val uri = canonicalFile.url
90-
val pos = Position(event.newPosition.line, event.newPosition.column)
91-
val range = Range(pos, pos)
92-
launchCursorRequest(CursorRequest(uri, Collections.singletonList(range)))
87+
88+
val ranges = event.editor.caretModel
89+
.allCarets
90+
.map {caret ->
91+
val pos = Position(caret.logicalPosition.line, caret.logicalPosition.column)
92+
Range(pos, pos)
93+
}
94+
95+
launchCursorRequest(CursorRequest(uri, ranges))
9396
}
9497

9598
private fun launchCursorRequest(cursorRequest: CursorRequest) {
@@ -103,7 +106,24 @@ class Cursortracker(
103106
}
104107
}
105108

106-
fun clear() {
109+
suspend fun clear() {
107110
remoteProxy = null
111+
withUiContext {
112+
synchronized(highlighter) {
113+
for (entry in highlighter) {
114+
val fileEditor = FileEditorManager.getInstance(project)
115+
.allEditors
116+
.filterIsInstance<TextEditor>()
117+
.filter { editor -> editor.file.canonicalFile != null }
118+
.firstOrNull { editor -> editor.file.canonicalFile!!.url == entry.key.documentUri } ?: continue
119+
120+
for (rangeHighlighter in entry.value) {
121+
fileEditor.editor.markupModel.removeHighlighter(rangeHighlighter)
122+
}
123+
}
124+
125+
highlighter.clear()
126+
}
127+
}
108128
}
109129
}

0 commit comments

Comments
 (0)