diff --git a/frontend/obsidian-plugin/src/views/cursors/remote-cursors-plugin.ts b/frontend/obsidian-plugin/src/views/cursors/remote-cursors-plugin.ts index a0de390c..86ddd6cd 100644 --- a/frontend/obsidian-plugin/src/views/cursors/remote-cursors-plugin.ts +++ b/frontend/obsidian-plugin/src/views/cursors/remote-cursors-plugin.ts @@ -9,6 +9,7 @@ import type { ViewUpdate } from "@codemirror/view"; import { RemoteCursorWidget } from "./remote-cursor-widget"; +import type { RelativePath } from "sync-client"; import { utils, type CursorSpan, @@ -32,12 +33,14 @@ export class RemoteCursorsPluginValue implements PluginValue { isOutdated: boolean; }[] = []; + private static app: App; public decorations: DecorationSet = RangeSet.of([]); public static setCursors( clients: MaybeOutdatedClientCursors[], app: App ): void { + RemoteCursorsPluginValue.app = app; RemoteCursorsPluginValue.cursors = [ ...RemoteCursorsPluginValue.cursors.filter(({ deviceId }) => clients.some( @@ -82,6 +85,30 @@ export class RemoteCursorsPluginValue implements PluginValue { }); } + private static findFileForEditor( + editor: EditorView + ): RelativePath | undefined { + return RemoteCursorsPluginValue.app.workspace + .getLeavesOfType("markdown") + .map((leaf) => leaf.view) + .filter((view) => view instanceof MarkdownView) + .flatMap((view) => { + // @ts-expect-error, not typed + // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion + if ((view.editor.cm as EditorView) !== editor) { + return []; + } + + const { file } = view; + if (!file) { + return; + } + + return [file.path]; + }) + .first(); + } + private static interpolateRemoteCursorPositions( original: string, edited: string @@ -155,9 +182,12 @@ export class RemoteCursorsPluginValue implements PluginValue { ); const decorations: Range[] = []; - - RemoteCursorsPluginValue.cursors.forEach( - ({ name, span: { start, end } }) => { + const relative_path = RemoteCursorsPluginValue.findFileForEditor( + update.view + ); + RemoteCursorsPluginValue.cursors + .filter(({ path }) => path == relative_path) + .forEach(({ name, span: { start, end } }) => { const color = utils.getRandomColor(name); const startLine = update.view.state.doc.lineAt(start); const endLine = update.view.state.doc.lineAt(end); @@ -221,8 +251,7 @@ export class RemoteCursorsPluginValue implements PluginValue { widget: new RemoteCursorWidget(color, name) }) }); - } - ); + }); this.decorations = Decoration.set(decorations, true); } diff --git a/frontend/package.json b/frontend/package.json index 718efea1..526b6ee4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -27,4 +27,4 @@ "prettier": "^3.6.2", "typescript-eslint": "8.41.0" } -} \ No newline at end of file +} diff --git a/sync-server/src/server/websocket.rs b/sync-server/src/server/websocket.rs index 0e4f705f..5e94b277 100644 --- a/sync-server/src/server/websocket.rs +++ b/sync-server/src/server/websocket.rs @@ -106,7 +106,19 @@ async fn websocket( continue; } - send_update_over_websocket(&update.message, &mut sender).await?; + let message = match update.message { + WebSocketServerMessage::CursorPositions(CursorPositionFromServer { clients }) => { + WebSocketServerMessage::CursorPositions(CursorPositionFromServer { + clients: clients + .into_iter() + .filter(|client| client.device_id != device_id) + .collect(), + }) + } + WebSocketServerMessage::VaultUpdate(_) => update.message, + }; + + send_update_over_websocket(&message, &mut sender).await?; } Ok::<(), SyncServerError>(())