Skip to content

Commit c7787bb

Browse files
Fix Deletion Issue
It is important that the Changetracker subscribes to change events before the change is applied because then it can determine the logical positions of edits correctly.
1 parent 3a62c7e commit c7787bb

File tree

3 files changed

+77
-61
lines changed

3 files changed

+77
-61
lines changed

src/main/kotlin/io/github/ethersync/EthersyncServiceImpl.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,44 @@ class EthersyncServiceImpl(
5454
val bus = project.messageBus.connect()
5555
bus.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, object : FileEditorManagerListener {
5656
override fun fileOpened(source: FileEditorManager, file: VirtualFile) {
57-
launchDocumentOpenRequest(file.canonicalFile!!.url)
57+
val canonicalFile = file.canonicalFile ?: return
58+
launchDocumentOpenRequest(canonicalFile.url)
5859
}
5960

6061
override fun fileClosed(source: FileEditorManager, file: VirtualFile) {
61-
launchDocumentCloseNotification(file.canonicalFile!!.url)
62+
val canonicalFile = file.canonicalFile ?: return
63+
launchDocumentCloseNotification(canonicalFile.url)
6264
}
6365
})
6466

6567
for (editor in FileEditorManager.getInstance(project).allEditors) {
6668
if (editor is TextEditor) {
69+
val file = editor.file ?: continue
70+
if (!file.exists()) {
71+
continue
72+
}
6773
editor.editor.caretModel.addCaretListener(cursortracker)
6874
editor.editor.document.addDocumentListener(changetracker)
6975
}
7076
}
7177

7278
EditorFactory.getInstance().addEditorFactoryListener(object : EditorFactoryListener {
7379
override fun editorCreated(event: EditorFactoryEvent) {
80+
val file = event.editor.virtualFile ?: return
81+
if (!file.exists()) {
82+
return
83+
}
84+
7485
event.editor.caretModel.addCaretListener(cursortracker)
7586
event.editor.document.addDocumentListener(changetracker)
7687
}
7788

7889
override fun editorReleased(event: EditorFactoryEvent) {
90+
val file = event.editor.virtualFile ?: return
91+
if (!file.exists()) {
92+
return
93+
}
94+
7995
event.editor.caretModel.removeCaretListener(cursortracker)
8096
event.editor.document.removeDocumentListener(changetracker)
8197
}

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

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ class Changetracker(
4040

4141
var remoteProxy: RemoteEthersyncClientProtocol? = null
4242

43-
override fun documentChanged(event: DocumentEvent) {
43+
override fun beforeDocumentChange(event: DocumentEvent) {
4444
if (ignoreChangeEvent.get()) {
4545
return
4646
}
4747

4848
val file = FileDocumentManager.getInstance().getFile(event.document)!!
4949
val fileEditor = FileEditorManager.getInstance(project).getEditors(file)
50+
.filter{ editor -> editor.file.canonicalFile != null }
5051
.filterIsInstance<TextEditor>()
51-
.first()
52+
.firstOrNull() ?: return
5253

5354
val editor = fileEditor.editor
54-
5555
val uri = file.canonicalFile!!.url
5656

5757
val rev = revisions[uri]!!
@@ -79,34 +79,34 @@ class Changetracker(
7979
}
8080

8181
fun handleRemoteEditEvent(editEvent: EditEvent) {
82-
val revision = revisions[editEvent.documentUri]!!
82+
val revision = revisions[editEvent.documentUri] ?: return
8383

8484
// Check if operation is up-to-date to our content.
8585
// If it's not, ignore it! The daemon will send a transformed one later.
8686
if (editEvent.editorRevision == revision.editor) {
87-
ignoreChangeEvent.set(true)
8887

8988
val fileEditorManager = FileEditorManager.getInstance(project)
9089

9190
val fileEditor = fileEditorManager.allEditors
92-
.first { editor -> editor.file.canonicalFile!!.url == editEvent.documentUri } ?: return
91+
.filter { editor -> editor.file.canonicalFile != null }
92+
.filterIsInstance<TextEditor>()
93+
.firstOrNull { editor -> editor.file.canonicalFile!!.url == editEvent.documentUri } ?: return
9394

94-
if (fileEditor is TextEditor) {
95-
val editor = fileEditor.editor
95+
val editor = fileEditor.editor
9696

97-
WriteCommandAction.runWriteCommandAction(project, {
98-
for(delta in editEvent.delta) {
99-
val start = editor.logicalPositionToOffset(LogicalPosition(delta.range.start.line, delta.range.start.character))
100-
val end = editor.logicalPositionToOffset(LogicalPosition(delta.range.end.line, delta.range.end.character))
97+
WriteCommandAction.runWriteCommandAction(project, {
98+
ignoreChangeEvent.set(true)
99+
for(delta in editEvent.delta) {
100+
val start = editor.logicalPositionToOffset(LogicalPosition(delta.range.start.line, delta.range.start.character))
101+
val end = editor.logicalPositionToOffset(LogicalPosition(delta.range.end.line, delta.range.end.character))
101102

102-
editor.document.replaceString(start, end, delta.replacement)
103-
}
104-
})
103+
editor.document.replaceString(start, end, delta.replacement)
104+
}
105+
ignoreChangeEvent.set(false)
106+
})
105107

106-
revision.daemon += 1u
108+
revision.daemon += 1u
107109

108-
ignoreChangeEvent.set(false)
109-
}
110110
}
111111
}
112112

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

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -32,61 +32,61 @@ class Cursortracker(
3232
var remoteProxy: RemoteEthersyncClientProtocol? = null
3333

3434
fun handleRemoteCursorEvent(cursorEvent: CursorEvent) {
35-
val fileEditorManager = FileEditorManager.getInstance(project)
36-
37-
val fileEditor = fileEditorManager.allEditors
35+
val fileEditor = FileEditorManager.getInstance(project)
36+
.allEditors
37+
.filterIsInstance<TextEditor>()
38+
.filter { editor -> editor.file.canonicalFile != null }
3839
.firstOrNull { editor -> editor.file.canonicalFile!!.url == cursorEvent.documentUri } ?: return
3940

40-
if (fileEditor is TextEditor) {
41-
val editor = fileEditor.editor
41+
val editor = fileEditor.editor
4242

43-
cs.launch {
44-
withContext(Dispatchers.EDT) {
45-
synchronized(highlighter) {
46-
val markupModel = editor.markupModel
43+
cs.launch {
44+
withContext(Dispatchers.EDT) {
45+
synchronized(highlighter) {
46+
val markupModel = editor.markupModel
47+
48+
val previous = highlighter.remove(cursorEvent.userId)
49+
if (previous != null) {
50+
for (hl in previous) {
51+
markupModel.removeHighlighter(hl)
52+
}
53+
}
4754

48-
val previous = highlighter.remove(cursorEvent.userId)
49-
if (previous != null) {
50-
for (hl in previous) {
51-
markupModel.removeHighlighter(hl)
52-
}
55+
val newHighlighter = LinkedList<RangeHighlighter>()
56+
for(range in cursorEvent.ranges) {
57+
val startPosition = editor.logicalPositionToOffset(LogicalPosition(range.start.line, range.start.character))
58+
val endPosition = editor.logicalPositionToOffset(LogicalPosition(range.end.line, range.end.character))
59+
60+
val textAttributes = TextAttributes().apply {
61+
// foregroundColor = JBColor(JBColor.YELLOW, JBColor.DARK_GRAY)
62+
63+
// TODO: unclear which is the best effect type
64+
effectType = EffectType.ROUNDED_BOX
65+
effectColor = JBColor(JBColor.YELLOW, JBColor.DARK_GRAY)
5366
}
5467

55-
val newHighlighter = LinkedList<RangeHighlighter>()
56-
for(range in cursorEvent.ranges) {
57-
val startPosition = editor.logicalPositionToOffset(LogicalPosition(range.start.line, range.start.character))
58-
val endPosition = editor.logicalPositionToOffset(LogicalPosition(range.end.line, range.end.character))
59-
60-
val textAttributes = TextAttributes().apply {
61-
// foregroundColor = JBColor(JBColor.YELLOW, JBColor.DARK_GRAY)
62-
63-
// TODO: unclear which is the best effect type
64-
effectType = EffectType.ROUNDED_BOX
65-
effectColor = JBColor(JBColor.YELLOW, JBColor.DARK_GRAY)
66-
}
67-
68-
val hl = markupModel.addRangeHighlighter(
69-
startPosition,
70-
endPosition + 1,
71-
HighlighterLayer.ADDITIONAL_SYNTAX,
72-
textAttributes,
73-
HighlighterTargetArea.EXACT_RANGE
74-
)
75-
if (cursorEvent.name != null) {
76-
hl.errorStripeTooltip = cursorEvent.name
77-
}
78-
79-
newHighlighter.add(hl)
68+
val hl = markupModel.addRangeHighlighter(
69+
startPosition,
70+
endPosition + 1,
71+
HighlighterLayer.ADDITIONAL_SYNTAX,
72+
textAttributes,
73+
HighlighterTargetArea.EXACT_RANGE
74+
)
75+
if (cursorEvent.name != null) {
76+
hl.errorStripeTooltip = cursorEvent.name
8077
}
81-
highlighter[cursorEvent.userId] = newHighlighter
78+
79+
newHighlighter.add(hl)
8280
}
81+
highlighter[cursorEvent.userId] = newHighlighter
8382
}
8483
}
8584
}
8685
}
8786

8887
override fun caretPositionChanged(event: CaretEvent) {
89-
val uri = event.editor.virtualFile.canonicalFile!!.url
88+
val canonicalFile = event.editor.virtualFile?.canonicalFile ?: return
89+
val uri = canonicalFile.url
9090
val pos = Position(event.newPosition.line, event.newPosition.column)
9191
val range = Range(pos, pos)
9292
launchCursorRequest(CursorRequest(uri, Collections.singletonList(range)))

0 commit comments

Comments
 (0)