@kerebron/extension-lsp 0.8.4 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/esm/ExtensionLsp.d.ts +1 -7
  2. package/esm/ExtensionLsp.d.ts.map +1 -1
  3. package/esm/ExtensionLsp.js +62 -79
  4. package/esm/ExtensionLsp.js.map +1 -1
  5. package/esm/LSPClient.d.ts +60 -15
  6. package/esm/LSPClient.d.ts.map +1 -1
  7. package/esm/LSPClient.js +91 -40
  8. package/esm/LSPClient.js.map +1 -1
  9. package/esm/LSPPlugin.d.ts +6 -35
  10. package/esm/LSPPlugin.d.ts.map +1 -1
  11. package/esm/LSPPlugin.js +40 -165
  12. package/esm/LSPPlugin.js.map +1 -1
  13. package/esm/LSPSync.d.ts +28 -0
  14. package/esm/LSPSync.d.ts.map +1 -0
  15. package/esm/LSPSync.js +111 -0
  16. package/esm/LSPSync.js.map +1 -0
  17. package/esm/computeIncrementalChanges.d.ts +1 -0
  18. package/esm/computeIncrementalChanges.d.ts.map +1 -1
  19. package/esm/computeIncrementalChanges.js +11 -0
  20. package/esm/computeIncrementalChanges.js.map +1 -1
  21. package/esm/mod.d.ts +0 -1
  22. package/esm/mod.d.ts.map +1 -1
  23. package/esm/mod.js +0 -1
  24. package/esm/mod.js.map +1 -1
  25. package/package.json +4 -7
  26. package/src/ExtensionLsp.ts +91 -94
  27. package/src/LSPClient.ts +217 -54
  28. package/src/LSPPlugin.ts +59 -292
  29. package/src/LSPSync.ts +169 -0
  30. package/src/computeIncrementalChanges.ts +17 -0
  31. package/src/mod.ts +0 -1
  32. package/esm/LSPWorkspace.d.ts +0 -39
  33. package/esm/LSPWorkspace.d.ts.map +0 -1
  34. package/esm/LSPWorkspace.js +0 -118
  35. package/esm/LSPWorkspace.js.map +0 -1
  36. package/esm/createLspAutocomplete.d.ts +0 -17
  37. package/esm/createLspAutocomplete.d.ts.map +0 -1
  38. package/esm/createLspAutocomplete.js +0 -68
  39. package/esm/createLspAutocomplete.js.map +0 -1
  40. package/esm/types.d.ts +0 -19
  41. package/esm/types.d.ts.map +0 -1
  42. package/esm/types.js +0 -2
  43. package/esm/types.js.map +0 -1
  44. package/esm/workspace.d.ts +0 -33
  45. package/esm/workspace.d.ts.map +0 -1
  46. package/esm/workspace.js +0 -23
  47. package/esm/workspace.js.map +0 -1
  48. package/src/LSPWorkspace.ts +0 -172
  49. package/src/createLspAutocomplete.ts +0 -98
  50. package/src/types.ts +0 -14
  51. package/src/workspace.ts +0 -53
@@ -1,12 +1,15 @@
1
1
  import { Plugin } from 'prosemirror-state';
2
+ import * as lsp from 'vscode-languageserver-protocol';
2
3
 
3
- import { Extension } from '@kerebron/editor';
4
- import { type ExtensionMarkdown } from '@kerebron/extension-markdown';
5
- import { PositionMapper } from '@kerebron/extension-markdown/PositionMapper';
4
+ import { Extension, TextRange } from '@kerebron/editor';
5
+ import type {
6
+ HoverMatch,
7
+ HoverSource,
8
+ HoverTrigger,
9
+ } from '@kerebron/extension-ui/hover';
6
10
 
7
- import { LSPClient, Transport } from './LSPClient.js';
8
- import { LSPPlugin } from './LSPPlugin.js';
9
- import { createLspAutocomplete } from './createLspAutocomplete.js';
11
+ import { Transport } from './LSPClient.js';
12
+ import { LSPPlugin, LSPPluginKey } from './LSPPlugin.js';
10
13
 
11
14
  export type LSPTransportGetter = (lang: string) => Transport | undefined;
12
15
 
@@ -16,11 +19,6 @@ export interface LspConfig {
16
19
 
17
20
  export class ExtensionLsp extends Extension {
18
21
  name = 'lsp';
19
- clients: Record<string, LSPClient> = {};
20
- uri: string | undefined;
21
- extensionMarkdown!: ExtensionMarkdown;
22
- mainLang: string = 'markdown';
23
- // source!: LSPSource;
24
22
 
25
23
  constructor(public override config: LspConfig) {
26
24
  super(config);
@@ -28,91 +26,90 @@ export class ExtensionLsp extends Extension {
28
26
 
29
27
  override getProseMirrorPlugins(): Plugin[] {
30
28
  const plugins: Plugin[] = [];
31
-
32
- const { autocompleteConfig } = createLspAutocomplete(this);
33
-
34
- plugins.push(new LSPPlugin(this.config, this));
35
-
29
+ // const { autocompleteConfig } = createLspAutocomplete(this);
30
+ plugins.push(new LSPPlugin(this.config, this.editor));
36
31
  return plugins;
37
32
  }
38
33
 
39
- override created() {
40
- this.mainLang = this.editor.config.languageID || 'markdown';
41
-
42
- // this.source = {
43
- // ui: this.editor.ui,
44
- // getMappedContent: async () => {
45
- // const editor = this.editor;
46
- // const result = await this.extensionMarkdown.toMarkdown(
47
- // editor.state.doc,
48
- // );
49
- // const mapper = new PositionMapper(editor, result.rawTextMap);
50
- // return {
51
- // ...result,
52
- // mapper,
53
- // };
54
- // },
55
- // };
56
-
57
- const extensionMarkdown: ExtensionMarkdown | undefined = this.editor
58
- .ci.resolve('markdown');
59
- if (!extensionMarkdown) {
60
- throw new Error('No markdown extension');
61
- }
62
- this.extensionMarkdown = extensionMarkdown;
63
-
64
- this.editor.addEventListener('doc:loaded', async () => {
65
- this.uri = this.editor.config.uri;
66
- if (this.editor.config.uri) {
67
- const tr = this.editor.view.state.tr;
68
- tr.setMeta('workspace', {
69
- operation: 'openFile',
70
- node: this.editor.view.state.doc,
71
- // pos: this.getPos(),
72
- uri: this.editor.config.uri,
73
- lang: this.mainLang,
74
- });
75
- this.editor.view.dispatch(tr);
76
- }
77
-
78
- // TODO start autocomplete...
79
- // this.editor.chain()/aaaa.run();
80
- });
81
-
82
- this.editor.addEventListener('changed', () => {
83
- if (this.editor.config.uri) {
84
- const tr = this.editor.view.state.tr;
85
- tr.setMeta('workspace', {
86
- operation: 'modifyFile',
87
- node: this.editor.view.state.doc,
88
- // pos: this.getPos(),
89
- uri: this.editor.config.uri,
90
- lang: this.mainLang,
91
- });
92
- this.editor.view.dispatch(tr);
93
- }
94
- });
95
-
96
- this.editor.addEventListener('beforeDestroy', () => {
97
- if (this.uri) {
98
- const tr = this.editor.view.state.tr;
99
- tr.setMeta('workspace', {
100
- operation: 'closeFile',
101
- uri: this.editor.config.uri,
102
- });
103
- }
104
- });
105
- }
106
-
107
- getClient(lang: string): LSPClient | undefined {
108
- if (!this.clients[lang]) {
109
- const transport = this.config.getLspTransport(lang);
110
- if (!transport) {
111
- console.warn(`No lsp transport for ${lang}`);
112
- return undefined;
113
- }
114
- this.clients[lang] = new LSPClient(transport, { rootUri: 'file:///' });
115
- }
116
- return this.clients[lang];
34
+ override created(): void {
35
+ const source3: HoverSource = {
36
+ match: function (trigger: HoverTrigger): HoverMatch | undefined {
37
+ let pos = trigger.pos;
38
+ if (trigger.uri) {
39
+ pos = pos + trigger.inside;
40
+ }
41
+
42
+ return {
43
+ source: source3,
44
+ uri: trigger.uri,
45
+ range: {
46
+ from: pos,
47
+ to: pos,
48
+ },
49
+ trigger,
50
+ text: '...',
51
+ };
52
+ },
53
+ getItem: async (range: TextRange, trigger: HoverTrigger) => {
54
+ if (!trigger.uri) {
55
+ return;
56
+ }
57
+
58
+ const lspSync = LSPPluginKey.getState(this.editor.state);
59
+ if (!lspSync) {
60
+ return;
61
+ }
62
+
63
+ const lspClient = lspSync.uriToClient[trigger.uri];
64
+ const entry = lspClient.getEntry(trigger.uri);
65
+ if (!entry) {
66
+ return;
67
+ }
68
+
69
+ const contentMapper = await entry.getContentMapper();
70
+ const [line, character] = contentMapper.toRawTextLineCol(
71
+ trigger.inside,
72
+ );
73
+
74
+ const hover = await lspClient.request<
75
+ lsp.HoverParams,
76
+ lsp.Hover | null
77
+ >(
78
+ 'textDocument/hover',
79
+ {
80
+ textDocument: {
81
+ uri: trigger.uri,
82
+ },
83
+ position: {
84
+ line,
85
+ character,
86
+ },
87
+ },
88
+ );
89
+
90
+ if (!hover) {
91
+ return;
92
+ }
93
+
94
+ const contents = hover.contents;
95
+ if (Array.isArray(contents)) {
96
+ return { text: contents.map((a) => a.toString).join('\n') };
97
+ }
98
+
99
+ if ('string' === typeof contents) {
100
+ return { text: contents };
101
+ }
102
+
103
+ if ('kind' in contents) {
104
+ return { text: contents.value };
105
+ }
106
+
107
+ return { text: contents.value, a: contents.language };
108
+ },
109
+ };
110
+
111
+ this.editor.addEventListener('ready', () => {
112
+ this.editor.chain().addHoverSource(source3).run();
113
+ }, { once: true });
117
114
  }
118
115
  }
package/src/LSPClient.ts CHANGED
@@ -1,15 +1,19 @@
1
- import type * as lsp from 'vscode-languageserver-protocol';
1
+ import * as lsp from 'vscode-languageserver-protocol';
2
2
  import {
3
3
  MessageType,
4
4
  TextDocumentSyncKind,
5
5
  } from 'vscode-languageserver-protocol';
6
6
 
7
- import { Workspace, WorkspaceFile } from './workspace.js';
8
-
9
- import { LSPSource, LSPWorkspace } from './LSPWorkspace.js';
7
+ import { EditorUi } from '@kerebron/editor';
8
+ import type { ContentMapper, WorkspaceModifyParams } from '@kerebron/workspace';
9
+ import { contentChangesFor } from './computeIncrementalChanges.js';
10
10
 
11
11
  const defaultNotificationHandlers: {
12
- [method: string]: (client: LSPClient, params: any) => void;
12
+ [method: string]: (
13
+ client: LSPClient,
14
+ params: any,
15
+ config: LSPClientConfig,
16
+ ) => void;
13
17
  } = {
14
18
  'window/logMessage': (client, params: lsp.LogMessageParams) => {
15
19
  if (params.type == MessageType.Error) {
@@ -22,10 +26,14 @@ const defaultNotificationHandlers: {
22
26
  console.log('[lsp] ' + params.message);
23
27
  }
24
28
  },
25
- 'window/showMessage': (client, params: lsp.ShowMessageParams) => {
29
+ 'window/showMessage': (
30
+ client,
31
+ params: lsp.ShowMessageParams,
32
+ config: LSPClientConfig,
33
+ ) => {
26
34
  if (params.type > MessageType.Info) return;
27
- for (const f of client.workspace.files) {
28
- const ui = f.getUi();
35
+ for (const f of Object.entries(client.entries)) {
36
+ const ui = config.ui;
29
37
  if (!ui) continue;
30
38
  ui.showMessage(params.message);
31
39
  }
@@ -119,14 +127,10 @@ const clientCapabilities: lsp.ClientCapabilities = {
119
127
 
120
128
  /// Configuration options that can be passed to the LSP client.
121
129
  export type LSPClientConfig = {
130
+ ui: EditorUi;
131
+ lang: string;
122
132
  /// The project root URI passed to the server, when necessary.
123
133
  rootUri?: string;
124
- /// An optional function to create a
125
- /// [workspace](#lsp-client.Workspace) object for the client to use.
126
- /// When not given, this will default to a simple workspace that
127
- /// only opens files that have an active editor, and only allows one
128
- /// editor per file.
129
- workspace?: (client: LSPClient) => Workspace;
130
134
  /// The amount of milliseconds after which requests are
131
135
  /// automatically timed out. Defaults to 3000.
132
136
  timeout?: number;
@@ -136,7 +140,7 @@ export type LSPClientConfig = {
136
140
  /// someone is able to compromise your LSP server or your connection
137
141
  /// to it. You can pass an HTML sanitizer here to strip out
138
142
  /// suspicious HTML structure.
139
- sanitizeHTML?: (html: string) => string;
143
+ // sanitizeHTML?: (html: string) => string;
140
144
  /// When no handler is found for a notification, it will be passed
141
145
  /// to this function, if given.
142
146
  unhandledNotification?: (
@@ -157,10 +161,86 @@ export class LSPError extends Error {
157
161
  }
158
162
  }
159
163
 
160
- export class LSPClient extends EventTarget {
161
- sources: Record<string, LSPSource> = {};
164
+ export interface LSPClientEventMap {
165
+ 'initialize': CustomEvent<lsp.InitializeParams>;
166
+ 'initialized': CustomEvent<lsp.InitializedParams>;
167
+ 'textDocument/didOpen': CustomEvent<lsp.DidOpenTextDocumentParams>;
168
+ 'textDocument/didChange': CustomEvent<lsp.DidChangeTextDocumentParams>;
169
+ 'textDocument/didClose': CustomEvent<lsp.DidCloseTextDocumentParams>;
170
+ 'textDocument/completion': CustomEvent<lsp.CompletionParams>;
171
+ 'textDocument/diagnostic': CustomEvent<lsp.DocumentDiagnosticParams>;
172
+ 'textDocument/publishDiagnostics': CustomEvent<
173
+ { params: lsp.PublishDiagnosticsParams }
174
+ >;
175
+ 'window/logMessage': CustomEvent<lsp.LogMessageParams>;
176
+ 'window/showMessage': CustomEvent<lsp.ShowMessageParams>;
177
+ 'close': CustomEvent<void>;
178
+ }
179
+
180
+ export interface LSPClient extends EventTarget {
181
+ addEventListener<K extends keyof LSPClientEventMap>(
182
+ type: K,
183
+ listener: (event: LSPClientEventMap[K]) => void,
184
+ options?: boolean | AddEventListenerOptions,
185
+ ): void;
186
+
187
+ // fallback DOM signature (required)
188
+ addEventListener(
189
+ type: string,
190
+ listener: EventListenerOrEventListenerObject | null,
191
+ options?: boolean | AddEventListenerOptions,
192
+ ): void;
193
+
194
+ removeEventListener<K extends keyof LSPClientEventMap>(
195
+ type: K,
196
+ listener: (event: LSPClientEventMap[K]) => void,
197
+ options?: boolean | EventListenerOptions,
198
+ ): void;
199
+ // fallback DOM signature (required)
200
+ removeEventListener(
201
+ type: string,
202
+ listener: EventListenerOrEventListenerObject | null,
203
+ options?: boolean | EventListenerOptions,
204
+ ): void;
205
+
206
+ dispatchEvent<K extends keyof LSPClientEventMap>(
207
+ event: LSPClientEventMap[K],
208
+ ): boolean;
209
+ dispatchEvent(event: Event): boolean;
210
+
211
+ lang: string;
212
+
213
+ hasCapability(name: keyof lsp.ServerCapabilities): boolean;
214
+ connect(): void;
162
215
 
163
- workspace: Workspace;
216
+ restart(): Promise<void>;
217
+ changeFile(modified: WorkspaceModifyParams): Promise<boolean>;
218
+ closeFile(uri: string): Promise<void>;
219
+
220
+ request<Params, Result>(
221
+ method: string,
222
+ params: Params,
223
+ ): Promise<Result>;
224
+ notification<Params>(method: string, params: Params): Promise<boolean>;
225
+
226
+ getEntry(uri: string): LSPEntry | undefined;
227
+
228
+ destroy(): void;
229
+ }
230
+
231
+ interface LSPEntry {
232
+ getContentMapper: () => Promise<ContentMapper>;
233
+ uri: string;
234
+ version: number;
235
+ syncedText?: string;
236
+ opened: boolean;
237
+ }
238
+
239
+ export class LSPClientImpl extends EventTarget implements LSPClient {
240
+ entries: Record<string, LSPEntry> = {};
241
+
242
+ // sources: Record<string, () => Promise<ContentMapper>> = {};
243
+ // workspace: Workspace;
164
244
  private nextReqID = 0;
165
245
  private requests: Request<any>[] = [];
166
246
 
@@ -171,19 +251,23 @@ export class LSPClient extends EventTarget {
171
251
  private initializing: ReturnType<typeof setInterval> | undefined;
172
252
 
173
253
  private readonly receiveListener: EventListenerOrEventListenerObject;
254
+ private readonly startInitializingListener:
255
+ EventListenerOrEventListenerObject;
256
+
174
257
  active: boolean = false;
175
258
 
176
259
  constructor(
177
260
  private readonly transport: Transport,
178
- readonly config: LSPClientConfig = {},
261
+ readonly config: LSPClientConfig,
179
262
  ) {
180
263
  super();
181
264
 
182
265
  this.timeout = config.timeout ?? 3000;
183
266
 
184
267
  this.receiveListener = (event) => this.receiveMessage(event);
268
+ this.startInitializingListener = (event) => this.startInitializing();
185
269
 
186
- transport.addEventListener('message', this.receiveListener);
270
+ transport.addEventListener('open', this.startInitializingListener);
187
271
  transport.addEventListener('initialized', () => {
188
272
  try {
189
273
  console.info('LSP initialized');
@@ -200,18 +284,21 @@ export class LSPClient extends EventTarget {
200
284
  }
201
285
  }
202
286
  });
203
- transport.addEventListener('open', () => {
204
- this.startInitializing();
205
- });
287
+ transport.addEventListener('message', this.receiveListener);
206
288
  transport.addEventListener('close', (event) => {
207
289
  this.active = false;
208
290
  this.serverCapabilities = null;
209
291
  this.dispatchEvent(new CloseEvent('close'));
210
292
  });
293
+ }
211
294
 
212
- this.workspace = config.workspace
213
- ? config.workspace(this)
214
- : new LSPWorkspace(this);
295
+ destroy(): void {
296
+ this.transport.removeEventListener('message', this.receiveListener);
297
+ this.transport.removeEventListener('open', this.startInitializingListener);
298
+ }
299
+
300
+ get lang(): string {
301
+ return this.config.lang;
215
302
  }
216
303
 
217
304
  startInitializing() {
@@ -266,19 +353,23 @@ export class LSPClient extends EventTarget {
266
353
  }
267
354
  }
268
355
 
269
- onInitialized() {
356
+ async onInitialized() {
270
357
  this.transport.send(
271
358
  JSON.stringify({ jsonrpc: '2.0', method: 'initialized', params: {} }),
272
359
  );
273
360
 
274
- this.workspace.connected();
275
- }
361
+ for (const [uri, entry] of Object.entries(this.entries)) {
362
+ if (entry.opened) {
363
+ return;
364
+ }
276
365
 
277
- connect(uri: string, source: LSPSource) {
278
- if (this.sources[uri] && this.sources[uri] !== source) {
279
- throw new Error(`Source for ${uri} already connected`);
366
+ await this.didOpen(entry);
280
367
  }
281
- this.sources[uri] = source;
368
+
369
+ this.dispatchEvent(new CustomEvent('initialized'));
370
+ }
371
+
372
+ connect() {
282
373
  this.active = true;
283
374
  if (!this.transport.isConnected()) {
284
375
  this.transport.connect();
@@ -286,52 +377,120 @@ export class LSPClient extends EventTarget {
286
377
  }
287
378
 
288
379
  disconnect(uri: string) {
289
- delete this.sources[uri];
290
- this.workspace.closeFile(uri);
291
- if (Object.keys(this.sources).length === 0) {
380
+ if (Object.keys(this.entries).length === 0) {
292
381
  this.active = false;
293
382
  this.serverCapabilities = null;
294
383
  this.transport.removeEventListener('data', this.receiveListener);
295
- this.workspace.disconnected();
296
384
  this.dispatchEvent(new CloseEvent('close'));
297
385
  }
298
386
  }
299
387
 
388
+ async changeFile(modified: WorkspaceModifyParams): Promise<boolean> {
389
+ const entry: LSPEntry = this.entries[modified.uri] || {
390
+ uri: modified.uri,
391
+ version: modified.version,
392
+ syncedText: undefined,
393
+ opened: false,
394
+ };
395
+
396
+ entry.version = modified.version;
397
+ entry.getContentMapper = modified.getContentMapper;
398
+
399
+ if (!this.entries[modified.uri]) {
400
+ this.entries[modified.uri] = entry;
401
+ return await this.didOpen(entry);
402
+ } else {
403
+ return await this.didChange(entry);
404
+ }
405
+ }
406
+
300
407
  /// Send a `textDocument/didOpen` notification to the server.
301
- async didOpen(file: WorkspaceFile) {
408
+ async didOpen(entry: LSPEntry) {
302
409
  if (!this.transport.isInitialized()) {
410
+ entry.opened = false;
411
+ this.connect();
303
412
  return false;
304
413
  }
414
+
415
+ const mapper = await entry.getContentMapper();
416
+ const text = mapper.getTextContent();
417
+
305
418
  await this.notification<lsp.DidOpenTextDocumentParams>(
306
419
  'textDocument/didOpen',
307
420
  {
308
421
  textDocument: {
309
- uri: file.uri,
310
- languageId: file.languageId,
311
- text: file.content,
312
- version: file.version,
422
+ uri: entry.uri,
423
+ languageId: this.lang,
424
+ text,
425
+ version: entry.version,
313
426
  },
314
427
  },
315
428
  );
429
+
430
+ entry.opened = true;
431
+ entry.syncedText = text;
432
+
316
433
  await this.notification<lsp.DocumentDiagnosticParams>(
317
434
  'textDocument/diagnostic',
318
435
  {
319
436
  textDocument: {
320
- uri: file.uri,
437
+ uri: entry.uri,
321
438
  },
322
439
  },
323
440
  );
324
441
  return true;
325
442
  }
326
443
 
327
- /// Send a `textDocument/didClose` notification to the server.
328
- didClose(uri: string) {
444
+ async didChange(entry: LSPEntry): Promise<boolean> {
445
+ if (!this.transport.isInitialized()) {
446
+ entry.opened = false;
447
+ this.connect();
448
+ return false;
449
+ }
450
+
451
+ if (!entry.opened) {
452
+ return this.didOpen(entry);
453
+ }
454
+
455
+ const mapper = await entry.getContentMapper();
456
+ const text = mapper.getTextContent();
457
+
458
+ await this.notification<lsp.DidChangeTextDocumentParams>(
459
+ 'textDocument/didChange',
460
+ {
461
+ textDocument: { uri: entry.uri, version: entry.version },
462
+ contentChanges: contentChangesFor(
463
+ this.supportSync == lsp.TextDocumentSyncKind.Incremental,
464
+ text,
465
+ entry.syncedText,
466
+ ),
467
+ },
468
+ );
469
+
470
+ entry.syncedText = text;
471
+
472
+ await this.notification<lsp.DocumentDiagnosticParams>(
473
+ 'textDocument/diagnostic',
474
+ {
475
+ textDocument: {
476
+ uri: entry.uri,
477
+ },
478
+ },
479
+ );
480
+ return true;
481
+ }
482
+
483
+ async closeFile(uri: string): Promise<void> {
484
+ delete this.entries[uri];
329
485
  if (!this.transport.isInitialized()) {
330
486
  return;
331
487
  }
332
- this.notification<lsp.DidCloseTextDocumentParams>('textDocument/didClose', {
333
- textDocument: { uri },
334
- });
488
+ await this.notification<lsp.DidCloseTextDocumentParams>(
489
+ 'textDocument/didClose',
490
+ {
491
+ textDocument: { uri },
492
+ },
493
+ );
335
494
  }
336
495
 
337
496
  private receiveMessage(event: Event) {
@@ -364,7 +523,11 @@ export class LSPClient extends EventTarget {
364
523
  this.config.unhandledNotification(this, value.method, value.params);
365
524
  } else {
366
525
  if (defaultNotificationHandlers[value.method]) {
367
- defaultNotificationHandlers[value.method](this, value.params);
526
+ defaultNotificationHandlers[value.method](
527
+ this,
528
+ value.params,
529
+ this.config,
530
+ );
368
531
  }
369
532
  }
370
533
  }
@@ -471,11 +634,7 @@ export class LSPClient extends EventTarget {
471
634
  }
472
635
 
473
636
  hasCapability(name: keyof lsp.ServerCapabilities) {
474
- return this.serverCapabilities ? !!this.serverCapabilities[name] : null;
475
- }
476
-
477
- syncFiles() {
478
- this.workspace.syncFiles();
637
+ return this.serverCapabilities ? !!this.serverCapabilities[name] : false;
479
638
  }
480
639
 
481
640
  private timeoutRequest<T>(
@@ -490,4 +649,8 @@ export class LSPClient extends EventTarget {
490
649
  this.requests.splice(index, 1);
491
650
  }
492
651
  }
652
+
653
+ getEntry(uri: string): LSPEntry | undefined {
654
+ return this.entries[uri];
655
+ }
493
656
  }