@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.
- package/esm/ExtensionLsp.d.ts +1 -7
- package/esm/ExtensionLsp.d.ts.map +1 -1
- package/esm/ExtensionLsp.js +62 -79
- package/esm/ExtensionLsp.js.map +1 -1
- package/esm/LSPClient.d.ts +60 -15
- package/esm/LSPClient.d.ts.map +1 -1
- package/esm/LSPClient.js +91 -40
- package/esm/LSPClient.js.map +1 -1
- package/esm/LSPPlugin.d.ts +6 -35
- package/esm/LSPPlugin.d.ts.map +1 -1
- package/esm/LSPPlugin.js +40 -165
- package/esm/LSPPlugin.js.map +1 -1
- package/esm/LSPSync.d.ts +28 -0
- package/esm/LSPSync.d.ts.map +1 -0
- package/esm/LSPSync.js +111 -0
- package/esm/LSPSync.js.map +1 -0
- package/esm/computeIncrementalChanges.d.ts +1 -0
- package/esm/computeIncrementalChanges.d.ts.map +1 -1
- package/esm/computeIncrementalChanges.js +11 -0
- package/esm/computeIncrementalChanges.js.map +1 -1
- package/esm/mod.d.ts +0 -1
- package/esm/mod.d.ts.map +1 -1
- package/esm/mod.js +0 -1
- package/esm/mod.js.map +1 -1
- package/package.json +4 -7
- package/src/ExtensionLsp.ts +91 -94
- package/src/LSPClient.ts +217 -54
- package/src/LSPPlugin.ts +59 -292
- package/src/LSPSync.ts +169 -0
- package/src/computeIncrementalChanges.ts +17 -0
- package/src/mod.ts +0 -1
- package/esm/LSPWorkspace.d.ts +0 -39
- package/esm/LSPWorkspace.d.ts.map +0 -1
- package/esm/LSPWorkspace.js +0 -118
- package/esm/LSPWorkspace.js.map +0 -1
- package/esm/createLspAutocomplete.d.ts +0 -17
- package/esm/createLspAutocomplete.d.ts.map +0 -1
- package/esm/createLspAutocomplete.js +0 -68
- package/esm/createLspAutocomplete.js.map +0 -1
- package/esm/types.d.ts +0 -19
- package/esm/types.d.ts.map +0 -1
- package/esm/types.js +0 -2
- package/esm/types.js.map +0 -1
- package/esm/workspace.d.ts +0 -33
- package/esm/workspace.d.ts.map +0 -1
- package/esm/workspace.js +0 -23
- package/esm/workspace.js.map +0 -1
- package/src/LSPWorkspace.ts +0 -172
- package/src/createLspAutocomplete.ts +0 -98
- package/src/types.ts +0 -14
- package/src/workspace.ts +0 -53
package/src/ExtensionLsp.ts
CHANGED
|
@@ -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
|
|
5
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
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 {
|
|
8
|
-
|
|
9
|
-
import {
|
|
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]: (
|
|
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': (
|
|
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.
|
|
28
|
-
const ui =
|
|
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
|
|
161
|
-
|
|
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
|
-
|
|
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('
|
|
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('
|
|
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
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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.
|
|
275
|
-
|
|
361
|
+
for (const [uri, entry] of Object.entries(this.entries)) {
|
|
362
|
+
if (entry.opened) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
276
365
|
|
|
277
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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:
|
|
310
|
-
languageId:
|
|
311
|
-
text
|
|
312
|
-
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:
|
|
437
|
+
uri: entry.uri,
|
|
321
438
|
},
|
|
322
439
|
},
|
|
323
440
|
);
|
|
324
441
|
return true;
|
|
325
442
|
}
|
|
326
443
|
|
|
327
|
-
|
|
328
|
-
|
|
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>(
|
|
333
|
-
textDocument
|
|
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](
|
|
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] :
|
|
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
|
}
|