11/* Copyright 2024 Marimo. All rights reserved. */
22
3+ import type { EditorView } from "@codemirror/view" ;
34import type * as LSP from "vscode-languageserver-protocol" ;
5+ import { getNotebook } from "@/core/cells/cells" ;
46import type { CellId } from "@/core/cells/ids" ;
57import { store } from "@/core/state/jotai" ;
68import { invariant } from "@/utils/invariant" ;
79import { Logger } from "@/utils/Logger" ;
810import { LRUCache } from "@/utils/lru" ;
11+ import { Objects } from "@/utils/objects" ;
912import { topologicalCodesAtom } from "../copilot/getCodes" ;
1013import { createNotebookLens , type NotebookLens } from "./lens" ;
1114import {
1215 CellDocumentUri ,
1316 type ILanguageServerClient ,
1417 isClientWithNotify ,
15- isClientWithPlugins ,
1618} from "./types" ;
1719import { getLSPDocument } from "./utils" ;
1820
@@ -84,18 +86,32 @@ class Snapshotter {
8486 }
8587}
8688
89+ const defaultGetNotebookEditors = ( ) => {
90+ const evs = getNotebook ( ) . cellHandles ;
91+ return Objects . mapValues ( evs , ( r ) => r . current ?. editorViewOrNull ) ;
92+ } ;
93+
8794export class NotebookLanguageServerClient implements ILanguageServerClient {
8895 public readonly documentUri : LSP . DocumentUri ;
8996 private readonly client : ILanguageServerClient ;
9097 private readonly snapshotter : Snapshotter ;
98+ private readonly getNotebookEditors : ( ) => Record <
99+ CellId ,
100+ EditorView | null | undefined
101+ > ;
91102
92103 private static readonly SEEN_CELL_DOCUMENT_URIS = new Set < CellDocumentUri > ( ) ;
93104
94105 constructor (
95106 client : ILanguageServerClient ,
96107 initialSettings : Record < string , unknown > ,
108+ getNotebookEditors : ( ) => Record <
109+ CellId ,
110+ EditorView | null | undefined
111+ > = defaultGetNotebookEditors ,
97112 ) {
98113 this . documentUri = getLSPDocument ( ) ;
114+ this . getNotebookEditors = getNotebookEditors ;
99115
100116 this . client = client ;
101117 this . patchProcessNotification ( ) ;
@@ -114,6 +130,17 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
114130 this . snapshotter = new Snapshotter ( this . getNotebookCode . bind ( this ) ) ;
115131 }
116132
133+ onNotification (
134+ listener : ( n : {
135+ jsonrpc : "2.0" ;
136+ id ?: null | undefined ;
137+ method : "textDocument/publishDiagnostics" ;
138+ params : LSP . PublishDiagnosticsParams ;
139+ } ) => void ,
140+ ) : ( ) => boolean {
141+ return this . client . onNotification ( listener ) ;
142+ }
143+
117144 get ready ( ) : boolean {
118145 return this . client . ready ;
119146 }
@@ -150,16 +177,6 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
150177 this . client . close ( ) ;
151178 }
152179
153- // eslint-disable-next-line @typescript-eslint/no-explicit-any
154- detachPlugin ( plugin : any ) : void {
155- this . client . detachPlugin ( plugin ) ;
156- }
157-
158- // eslint-disable-next-line @typescript-eslint/no-explicit-any
159- attachPlugin ( plugin : any ) : void {
160- this . client . attachPlugin ( plugin ) ;
161- }
162-
163180 private getNotebookCode ( ) {
164181 return store . get ( topologicalCodesAtom ) ;
165182 }
@@ -371,37 +388,26 @@ export class NotebookLanguageServerClient implements ILanguageServerClient {
371388 const newEdits = lens . getEditsForNewText ( edit . newText ) ;
372389 const editsToNewCode = new Map ( newEdits . map ( ( e ) => [ e . cellId , e . text ] ) ) ;
373390
374- invariant (
375- isClientWithPlugins ( this . client ) ,
376- "Expected client with plugins." ,
377- ) ;
378-
379391 // Update the code in the plugins manually
380- for ( const plugin of this . client . plugins ) {
381- const documentUri : string = plugin . documentUri ;
382- if ( ! CellDocumentUri . is ( documentUri ) ) {
383- Logger . warn ( "Invalid cell document URI" , documentUri ) ;
384- continue ;
385- }
386-
387- const cellId = CellDocumentUri . parse ( documentUri ) ;
392+ const editors = this . getNotebookEditors ( ) ;
393+ for ( const [ cellId , ev ] of Objects . entries ( editors ) ) {
388394 const newCode = editsToNewCode . get ( cellId ) ;
389395 if ( newCode == null ) {
390396 Logger . warn ( "No new code for cell" , cellId ) ;
391397 continue ;
392398 }
393399
394- if ( ! plugin . view ) {
395- Logger . warn ( "No view for plugin" , plugin ) ;
400+ if ( ! ev ) {
401+ Logger . warn ( "No view for plugin" , cellId ) ;
396402 continue ;
397403 }
398404
399405 // Only update if it has changed
400- if ( plugin . view . state . doc . toString ( ) !== newCode ) {
401- plugin . view . dispatch ( {
406+ if ( ev . state . doc . toString ( ) !== newCode ) {
407+ ev . dispatch ( {
402408 changes : {
403409 from : 0 ,
404- to : plugin . view . state . doc . length ,
410+ to : ev . state . doc . length ,
405411 insert : newCode ,
406412 } ,
407413 } ) ;
0 commit comments