88
99package com.maddyhome.idea.vim.group.bookmark
1010
11+ import com.intellij.ide.bookmark.BookmarkType
12+ import com.intellij.ide.bookmark.BookmarksManager
13+ import com.intellij.ide.bookmark.LineBookmark
14+ import com.intellij.ide.bookmark.providers.LineBookmarkProvider
1115import com.intellij.ide.vfs.VirtualFileId
12- import com.intellij.openapi.components.service
16+ import com.intellij.ide.vfs.virtualFile
17+ import com.intellij.openapi.fileEditor.FileEditorManager
18+ import com.intellij.openapi.fileEditor.TextEditor
19+ import com.intellij.openapi.project.ProjectManager
1320import com.intellij.platform.project.ProjectId
21+ import com.intellij.platform.project.findProjectOrNull
22+ import com.intellij.openapi.application.readAction
23+ import com.maddyhome.idea.vim.api.VimMarkService
1424import com.maddyhome.idea.vim.group.onEdt
1525
1626/* *
1727 * RPC handler for [BookmarkRemoteApi].
18- * Delegates to [BookmarkBackendServiceImpl] for the actual bookmark operations .
28+ * Contains all bookmark logic directly — no intermediate service layer .
1929 *
20- * Uses [onEdt] to dispatch to EDT only when not already on it:
21- * - **Monolith**: RPC resolves locally, handler runs on EDT → skip `withContext(EDT)`
22- * - **Split**: RPC arrives on a background thread → `withContext(EDT)` dispatches to backend EDT
30+ * Read-only methods use [readAction]; mutating methods use [onEdt].
2331 */
2432internal class BookmarkRemoteApiImpl : BookmarkRemoteApi {
2533
26- private val bookmarkBackend : BookmarkBackendServiceImpl
27- get() = service ()
34+ // LineBookmark doesn't store column, so we track it separately
35+ private val columnByMark = mutableMapOf< Char , Int > ()
2836
2937 override suspend fun createOrGetSystemMark (
3038 char : Char ,
@@ -33,18 +41,107 @@ internal class BookmarkRemoteApiImpl : BookmarkRemoteApi {
3341 virtualFileId : VirtualFileId ,
3442 projectId : ProjectId ? ,
3543 ): BookmarkInfo ? = onEdt {
36- bookmarkBackend.createOrGetSystemMark(char, line, col, virtualFileId, projectId)
44+ val type = BookmarkType .get(char)
45+ if (type == BookmarkType .DEFAULT ) return @onEdt null
46+
47+ val project = projectId?.findProjectOrNull() ? : return @onEdt null
48+ val bookmarksManager = BookmarksManager .getInstance(project) ? : return @onEdt null
49+
50+ // If a bookmark with this mnemonic already exists, check if it's at the right line
51+ val existing = bookmarksManager.getBookmark(type)
52+ if (existing != null ) {
53+ if (existing is LineBookmark && existing.line == line) {
54+ columnByMark[char] = col
55+ return @onEdt BookmarkInfo (
56+ key = char,
57+ line = existing.line,
58+ col = col,
59+ filepath = existing.file.path,
60+ protocol = existing.file.fileSystem.protocol,
61+ )
62+ }
63+ bookmarksManager.remove(existing)
64+ }
65+
66+ // Create a new line bookmark — find editor for the virtual file
67+ val vf = virtualFileId.virtualFile() ? : return @onEdt null
68+ val editor = FileEditorManager .getInstance(project).getAllEditors(vf)
69+ .filterIsInstance<TextEditor >()
70+ .firstOrNull()
71+ ?.editor ? : return @onEdt null
72+ val lineBookmarkProvider = LineBookmarkProvider .Util .find(project) ? : return @onEdt null
73+ val bookmark = lineBookmarkProvider.createBookmark(editor, line) as ? LineBookmark ? : return @onEdt null
74+
75+ val group = bookmarksManager.defaultGroup
76+ ? : bookmarksManager.getGroup(" IdeaVim" )
77+ ? : bookmarksManager.addGroup(" IdeaVim" , true )
78+ ? : return @onEdt null
79+ if (! group.canAdd(bookmark)) return @onEdt null
80+ group.add(bookmark, type)
81+
82+ columnByMark[char] = col
83+ BookmarkInfo (
84+ key = char,
85+ line = bookmark.line,
86+ col = col,
87+ filepath = bookmark.file.path,
88+ protocol = bookmark.file.fileSystem.protocol,
89+ )
3790 }
3891
3992 override suspend fun removeBookmark (char : Char ) = onEdt {
40- bookmarkBackend.removeBookmark(char)
93+ val type = BookmarkType .get(char)
94+ if (type == BookmarkType .DEFAULT ) return @onEdt
95+ columnByMark.remove(char)
96+ for (project in ProjectManager .getInstance().openProjects) {
97+ val bookmarksManager = BookmarksManager .getInstance(project) ? : continue
98+ val bookmark = bookmarksManager.getBookmark(type) ? : continue
99+ bookmarksManager.remove(bookmark)
100+ return @onEdt
101+ }
41102 }
42103
43- override suspend fun getBookmarkForMark (char : Char ): BookmarkInfo ? = onEdt {
44- bookmarkBackend.getBookmarkForMark(char)
104+ override suspend fun getBookmarkForMark (char : Char ): BookmarkInfo ? = readAction {
105+ val type = BookmarkType .get(char)
106+ if (type == BookmarkType .DEFAULT ) return @readAction null
107+ for (project in ProjectManager .getInstance().openProjects) {
108+ val bookmarksManager = BookmarksManager .getInstance(project) ? : continue
109+ val bookmark = bookmarksManager.getBookmark(type) ? : continue
110+ if (bookmark is LineBookmark ) {
111+ return @readAction BookmarkInfo (
112+ key = char,
113+ line = bookmark.line,
114+ col = columnByMark[char] ? : 0 ,
115+ filepath = bookmark.file.path,
116+ protocol = bookmark.file.fileSystem.protocol,
117+ )
118+ }
119+ }
120+ null
45121 }
46122
47- override suspend fun getAllBookmarks (): List <BookmarkInfo > = onEdt {
48- bookmarkBackend.getAllBookmarks()
123+ override suspend fun getAllBookmarks (): List <BookmarkInfo > = readAction {
124+ val result = mutableListOf<BookmarkInfo >()
125+ for (project in ProjectManager .getInstance().openProjects) {
126+ val bookmarksManager = BookmarksManager .getInstance(project) ? : continue
127+ for (typeChar in (VimMarkService .UPPERCASE_MARKS + VimMarkService .NUMBERED_MARKS )) {
128+ val type = BookmarkType .get(typeChar)
129+ if (type == BookmarkType .DEFAULT ) continue
130+ val bookmark = bookmarksManager.getBookmark(type) ? : continue
131+ if (bookmark is LineBookmark ) {
132+ result.add(
133+ BookmarkInfo (
134+ key = typeChar,
135+ line = bookmark.line,
136+ col = columnByMark[typeChar] ? : 0 ,
137+ filepath = bookmark.file.path,
138+ protocol = bookmark.file.fileSystem.protocol,
139+ )
140+ )
141+ }
142+ }
143+ break // mnemonic bookmarks are per-application, first project is sufficient
144+ }
145+ result
49146 }
50147}
0 commit comments