@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/LSPPlugin.ts
CHANGED
|
@@ -1,323 +1,90 @@
|
|
|
1
1
|
import { Plugin, PluginKey, Transaction } from 'prosemirror-state';
|
|
2
|
-
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
3
|
-
import { Diagnostic } from 'vscode-languageserver-protocol';
|
|
2
|
+
import { Decoration, DecorationSet, EditorView } from 'prosemirror-view';
|
|
4
3
|
|
|
5
|
-
import { PositionMapper } from '@kerebron/extension-markdown/PositionMapper';
|
|
6
4
|
import { CoreEditor } from '@kerebron/editor';
|
|
7
|
-
import {
|
|
8
|
-
type ExtensionMarkdown,
|
|
9
|
-
type MarkdownResult,
|
|
10
|
-
} from '@kerebron/extension-markdown';
|
|
11
5
|
|
|
12
|
-
import {
|
|
6
|
+
import type { LspConfig } from './ExtensionLsp.js';
|
|
7
|
+
import { LSPSync } from './LSPSync.js';
|
|
13
8
|
|
|
14
|
-
export
|
|
15
|
-
line: number;
|
|
16
|
-
character: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface DiagnosticsItem {
|
|
20
|
-
severity: number;
|
|
21
|
-
range: {
|
|
22
|
-
start: LspRange;
|
|
23
|
-
end: LspRange;
|
|
24
|
-
};
|
|
25
|
-
message: string;
|
|
26
|
-
source: string;
|
|
27
|
-
code: string;
|
|
28
|
-
data: any; // "data":{"kind":"todo","keyword":"TODO"}},
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface LSPMeta {
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface WorkspaceMetaOpen {
|
|
35
|
-
operation: 'openFile';
|
|
36
|
-
uri: string;
|
|
37
|
-
lang: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface WorkspaceMetaModify {
|
|
41
|
-
operation: 'modifyFile';
|
|
42
|
-
uri: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface WorkspaceMetaClose {
|
|
46
|
-
operation: 'closeFile';
|
|
47
|
-
uri: string;
|
|
48
|
-
}
|
|
9
|
+
export const LSPPluginKey = new PluginKey<LSPSync>('lsp');
|
|
49
10
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
| WorkspaceMetaClose
|
|
53
|
-
| WorkspaceMetaModify;
|
|
54
|
-
|
|
55
|
-
class LSPPluginState {
|
|
56
|
-
diagnostics: DiagnosticsItem[] = [];
|
|
57
|
-
|
|
58
|
-
snapshot?: {
|
|
59
|
-
version: number;
|
|
60
|
-
mapper: PositionMapper;
|
|
61
|
-
markdownResult: MarkdownResult;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
constructor(private editor: CoreEditor) {
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const LSPPluginKey = new PluginKey('lsp');
|
|
69
|
-
|
|
70
|
-
export class LSPPlugin extends Plugin<LSPPluginState> {
|
|
71
|
-
listenerDiag: ((event: Event) => void) | undefined;
|
|
72
|
-
listenerDisconnect: ((event: Event) => void) | undefined;
|
|
73
|
-
listenerChange: ((event: Event) => void) | undefined;
|
|
74
|
-
|
|
75
|
-
constructor(config: LspConfig, extension: ExtensionLsp) {
|
|
11
|
+
export class LSPPlugin extends Plugin<LSPSync> {
|
|
12
|
+
constructor(config: LspConfig, editor: CoreEditor) {
|
|
76
13
|
super({
|
|
77
14
|
key: LSPPluginKey,
|
|
78
|
-
view(view) {
|
|
79
|
-
return {
|
|
80
|
-
destroy: () => {
|
|
81
|
-
const client = extension.getClient(extension.mainLang);
|
|
82
|
-
|
|
83
|
-
if (this.listenerDiag && client) {
|
|
84
|
-
client.removeEventListener(
|
|
85
|
-
'textDocument/publishDiagnostics',
|
|
86
|
-
this.listenerDiag,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
if (this.listenerDisconnect && client) {
|
|
90
|
-
client.removeEventListener(
|
|
91
|
-
'close',
|
|
92
|
-
this.listenerDisconnect,
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
// if (this.listenerChange) {
|
|
96
|
-
// extension.getEditor().removeEventListener(
|
|
97
|
-
// 'change',
|
|
98
|
-
// this.listenerChange,
|
|
99
|
-
// );
|
|
100
|
-
// }
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
},
|
|
104
15
|
state: {
|
|
105
16
|
init() {
|
|
106
|
-
return new
|
|
17
|
+
return new LSPSync(config, editor);
|
|
107
18
|
},
|
|
108
|
-
apply(
|
|
109
|
-
tr: Transaction,
|
|
110
|
-
value: LSPPluginState,
|
|
111
|
-
oldState,
|
|
112
|
-
newState,
|
|
113
|
-
) {
|
|
114
|
-
const workspaceMeta: WorkspaceMeta | undefined = tr.getMeta(
|
|
115
|
-
'workspace',
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
if (workspaceMeta) {
|
|
119
|
-
console.log(
|
|
120
|
-
'workspaceMeta',
|
|
121
|
-
workspaceMeta.operation,
|
|
122
|
-
workspaceMeta,
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const uri = workspaceMeta.uri;
|
|
126
|
-
// const lang = workspaceMeta.lang;
|
|
127
|
-
|
|
128
|
-
switch (workspaceMeta.operation) {
|
|
129
|
-
case 'openFile':
|
|
130
|
-
{
|
|
131
|
-
const client = extension.getClient(workspaceMeta.lang);
|
|
132
|
-
if (client) {
|
|
133
|
-
client.addEventListener(
|
|
134
|
-
'textDocument/publishDiagnostics',
|
|
135
|
-
this.diagListener,
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
const go = async () => {
|
|
139
|
-
client.connect(uri, this.source);
|
|
140
|
-
if (uri === editor.config.uri) {
|
|
141
|
-
await client.restart();
|
|
142
|
-
}
|
|
143
|
-
client.workspace.openFile(
|
|
144
|
-
workspaceMeta.uri,
|
|
145
|
-
workspaceMeta.lang,
|
|
146
|
-
this.source,
|
|
147
|
-
);
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
go();
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
break;
|
|
154
|
-
case 'modifyFile':
|
|
155
|
-
break;
|
|
156
|
-
case 'closeFile':
|
|
157
|
-
// this.editor.view.dispatch(tr);
|
|
158
|
-
// const client = this.getClient(this.mainLang);
|
|
159
|
-
// if (client) {
|
|
160
|
-
// client.disconnect(this.uri);
|
|
161
|
-
// }
|
|
162
|
-
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return value;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const meta: LSPMeta | undefined = tr.getMeta(LSPPluginKey);
|
|
170
|
-
if (meta?.diagnostics) {
|
|
171
|
-
value.diagnostics = meta.diagnostics;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const markdownMeta = tr.getMeta('markdown');
|
|
175
|
-
if (markdownMeta?.snapshot) {
|
|
176
|
-
value.snapshot = markdownMeta.snapshot;
|
|
177
|
-
return value;
|
|
178
|
-
}
|
|
179
|
-
if (markdownMeta?.clearSnapshot) {
|
|
180
|
-
value.snapshot = undefined;
|
|
181
|
-
return value;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (tr.docChanged) {
|
|
185
|
-
// value.snapshot = undefined;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// let codeBlockChanged = false;
|
|
189
|
-
|
|
190
|
-
// // Compare changed ranges only
|
|
191
|
-
// tr.mapping.maps.forEach((stepMap) => {
|
|
192
|
-
// stepMap.forEach((oldStart, oldEnd, newStart, newEnd) => {
|
|
193
|
-
// oldState.doc.nodesBetween(oldStart, oldEnd, (node) => {
|
|
194
|
-
// if (node.type.name === "code_block") {
|
|
195
|
-
// codeBlockChanged = true;
|
|
196
|
-
// }
|
|
197
|
-
// });
|
|
198
|
-
|
|
199
|
-
// newState.doc.nodesBetween(newStart, newEnd, (node) => {
|
|
200
|
-
// if (node.type.name === "code_block") {
|
|
201
|
-
// codeBlockChanged = true;
|
|
202
|
-
// }
|
|
203
|
-
// });
|
|
204
|
-
// });
|
|
205
|
-
// });
|
|
206
|
-
|
|
207
|
-
// if (codeBlockChanged) {
|
|
208
|
-
// console.log("Code block changed");
|
|
209
|
-
// // trigger your logic here
|
|
210
|
-
// }
|
|
211
|
-
|
|
19
|
+
apply(_tr: Transaction, value) {
|
|
212
20
|
return value;
|
|
213
21
|
},
|
|
214
22
|
},
|
|
23
|
+
view(view) {
|
|
24
|
+
const pluginState = LSPPluginKey.getState(view.state);
|
|
25
|
+
return {
|
|
26
|
+
destroy() {
|
|
27
|
+
pluginState?.destroy();
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
},
|
|
215
31
|
props: {
|
|
216
32
|
decorations(state) {
|
|
217
33
|
const decorations: Decoration[] = [];
|
|
218
34
|
|
|
219
|
-
const pluginState =
|
|
35
|
+
const pluginState = LSPPluginKey.getState(editor.state);
|
|
36
|
+
|
|
220
37
|
if (pluginState) {
|
|
221
|
-
|
|
38
|
+
state.doc.forEach((node, pos) => {
|
|
39
|
+
const dom = (editor.view as EditorView).nodeDOM(
|
|
40
|
+
pos,
|
|
41
|
+
) as HTMLElement;
|
|
42
|
+
if (!dom || !dom.querySelector) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
222
45
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
46
|
+
const editorElement = dom.querySelector('[data-uri]');
|
|
47
|
+
const uri = (editorElement
|
|
48
|
+
? editorElement.getAttribute('data-uri')
|
|
49
|
+
: undefined) ||
|
|
50
|
+
undefined;
|
|
51
|
+
|
|
52
|
+
if (uri) {
|
|
53
|
+
const diags = pluginState.uriToDiagnostics[uri];
|
|
54
|
+
if (!diags) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const { diagnostics, version, contentMapper } = diags;
|
|
58
|
+
|
|
59
|
+
if (version === editor.version) {
|
|
60
|
+
for (const diag of diagnostics) {
|
|
61
|
+
const from = contentMapper.fromLineChar(
|
|
62
|
+
diag.range.start.line,
|
|
63
|
+
diag.range.start.character,
|
|
64
|
+
);
|
|
65
|
+
const end = contentMapper.fromLineChar(
|
|
66
|
+
diag.range.end.line,
|
|
67
|
+
diag.range.end.character,
|
|
68
|
+
);
|
|
233
69
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
70
|
+
if (from > -1 && end > -1) {
|
|
71
|
+
const decoration = Decoration.inline(
|
|
72
|
+
pos + 1 + from,
|
|
73
|
+
pos + 1 + end,
|
|
74
|
+
{},
|
|
75
|
+
{ class: 'kb-lsp__error', title: diag.message },
|
|
76
|
+
);
|
|
77
|
+
decorations.push(decoration);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
241
80
|
}
|
|
242
81
|
}
|
|
243
|
-
}
|
|
82
|
+
});
|
|
244
83
|
}
|
|
245
84
|
|
|
246
85
|
return DecorationSet.create(state.doc, decorations);
|
|
247
86
|
},
|
|
248
87
|
},
|
|
249
88
|
});
|
|
250
|
-
|
|
251
|
-
let lastDiag = 0;
|
|
252
|
-
|
|
253
|
-
const editor = extension.getEditor();
|
|
254
|
-
|
|
255
|
-
const uri = editor.config.uri;
|
|
256
|
-
if (uri) {
|
|
257
|
-
const client = extension.getClient(extension.mainLang);
|
|
258
|
-
|
|
259
|
-
this.listenerDiag = (event: Event) => {
|
|
260
|
-
const detail = (event as CustomEvent).detail;
|
|
261
|
-
if (detail.params.uri !== uri) {
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
event.preventDefault();
|
|
266
|
-
|
|
267
|
-
lastDiag = +Date();
|
|
268
|
-
|
|
269
|
-
if (client) {
|
|
270
|
-
const file = client.workspace.getFile(uri);
|
|
271
|
-
if (file) {
|
|
272
|
-
const { mapper } = file;
|
|
273
|
-
|
|
274
|
-
const diagnostics: Array<Diagnostic> = detail.params.diagnostics;
|
|
275
|
-
|
|
276
|
-
// file.dia
|
|
277
|
-
|
|
278
|
-
const tr = editor.view.state.tr.setMeta(LSPPluginKey, {
|
|
279
|
-
diagnostics: detail.params.diagnostics,
|
|
280
|
-
mapper,
|
|
281
|
-
});
|
|
282
|
-
editor.view.dispatch(tr);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
if (client) {
|
|
288
|
-
client.addEventListener(
|
|
289
|
-
'textDocument/publishDiagnostics',
|
|
290
|
-
this.listenerDiag,
|
|
291
|
-
);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
this.listenerDisconnect = (event: Event) => {
|
|
295
|
-
const tr = editor.view.state.tr.setMeta(LSPPluginKey, {
|
|
296
|
-
diagnostics: [],
|
|
297
|
-
mapper: undefined,
|
|
298
|
-
});
|
|
299
|
-
editor.view.dispatch(tr);
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
if (client) {
|
|
303
|
-
client.addEventListener(
|
|
304
|
-
'close',
|
|
305
|
-
this.listenerDisconnect,
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
this.listenerChange = (event: Event) => {
|
|
310
|
-
if (lastDiag === 0 && +Date() - lastDiag > 10_1000) {
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
const tr = editor.view.state.tr.setMeta(LSPPluginKey, {
|
|
314
|
-
diagnostics: [],
|
|
315
|
-
mapper: undefined,
|
|
316
|
-
});
|
|
317
|
-
editor.view.dispatch(tr);
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
// extension.getEditor().addEventListener('changed', this.listenerChange);
|
|
321
|
-
}
|
|
322
89
|
}
|
|
323
90
|
}
|
package/src/LSPSync.ts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import * as lsp from 'vscode-languageserver-protocol';
|
|
2
|
+
|
|
3
|
+
import { CoreEditor } from '@kerebron/editor';
|
|
4
|
+
import type {
|
|
5
|
+
ContentMapper,
|
|
6
|
+
Workspace,
|
|
7
|
+
WorkspaceCloseParams,
|
|
8
|
+
WorkspaceModifyParams,
|
|
9
|
+
} from '@kerebron/workspace';
|
|
10
|
+
|
|
11
|
+
import type { LspConfig } from './ExtensionLsp.js';
|
|
12
|
+
import { LSPClient, LSPClientImpl } from './LSPClient.js';
|
|
13
|
+
|
|
14
|
+
export class LSPSync {
|
|
15
|
+
clients: Record<string, LSPClient> = {};
|
|
16
|
+
|
|
17
|
+
uriToClient: Record<string, LSPClient> = {};
|
|
18
|
+
uriToDiagnostics: Record<
|
|
19
|
+
string,
|
|
20
|
+
{
|
|
21
|
+
diagnostics: lsp.Diagnostic[];
|
|
22
|
+
version: number;
|
|
23
|
+
contentMapper: ContentMapper;
|
|
24
|
+
}
|
|
25
|
+
> = {};
|
|
26
|
+
|
|
27
|
+
listenerDiag: (
|
|
28
|
+
event: CustomEvent<{ params: lsp.PublishDiagnosticsParams }>,
|
|
29
|
+
) => void;
|
|
30
|
+
listenerDisconnect: (event: CustomEvent<void>) => void;
|
|
31
|
+
listenerChange: (event: CustomEvent<WorkspaceModifyParams>) => Promise<void>;
|
|
32
|
+
|
|
33
|
+
constructor(private config: LspConfig, private editor: CoreEditor) {
|
|
34
|
+
this.listenerDiag = async (
|
|
35
|
+
event: CustomEvent<{ params: lsp.PublishDiagnosticsParams }>,
|
|
36
|
+
) => {
|
|
37
|
+
const { uri, diagnostics, version } = event.detail.params;
|
|
38
|
+
|
|
39
|
+
const client = event.target as LSPClientImpl;
|
|
40
|
+
|
|
41
|
+
const entry = client.entries[uri];
|
|
42
|
+
if (!entry || !version) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const contentMapper = await entry.getContentMapper();
|
|
47
|
+
|
|
48
|
+
this.uriToDiagnostics[uri] = {
|
|
49
|
+
diagnostics,
|
|
50
|
+
version,
|
|
51
|
+
contentMapper,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const tr = editor.state.tr;
|
|
55
|
+
editor.dispatchTransaction(tr);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
this.listenerDisconnect = (event: Event) => {
|
|
59
|
+
const client = event.target as LSPClient;
|
|
60
|
+
this.disconnected(client);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const workspace: Workspace = this.editor.ci.resolve('workspace');
|
|
64
|
+
|
|
65
|
+
this.listenerChange = async (event: CustomEvent<WorkspaceModifyParams>) => {
|
|
66
|
+
await this.changeFile(event.detail);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
workspace.addEventListener('openFile', this.listenerChange);
|
|
70
|
+
workspace.addEventListener('modifyFile', this.listenerChange);
|
|
71
|
+
workspace.addEventListener(
|
|
72
|
+
'closeFile',
|
|
73
|
+
(event: CustomEvent<WorkspaceCloseParams>) => {
|
|
74
|
+
this.closeFile(event.detail.uri);
|
|
75
|
+
},
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async changeFile(modified: WorkspaceModifyParams) {
|
|
80
|
+
const langClient = this.getClient(modified.lang);
|
|
81
|
+
if (!langClient) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const client: LSPClient | undefined = this.uriToClient[modified.uri];
|
|
86
|
+
|
|
87
|
+
if (!client) {
|
|
88
|
+
this.uriToClient[modified.uri] = langClient;
|
|
89
|
+
await langClient.changeFile(modified);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (client.lang !== langClient.lang) {
|
|
94
|
+
await client.closeFile(modified.uri);
|
|
95
|
+
this.uriToClient[modified.uri] = langClient;
|
|
96
|
+
await langClient.changeFile(modified);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
await client.changeFile(modified);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async closeFile(uri: string) {
|
|
104
|
+
const client = this.uriToClient[uri];
|
|
105
|
+
|
|
106
|
+
if (client) {
|
|
107
|
+
delete this.uriToClient[uri];
|
|
108
|
+
await client.closeFile(uri);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
disconnected(disconnectedClient: LSPClient): void {
|
|
113
|
+
for (const [uri, client] of Object.entries(this.uriToClient)) {
|
|
114
|
+
if (client !== disconnectedClient) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
this.closeFile(uri);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
getClient(lang: string): LSPClient | undefined {
|
|
122
|
+
if (!this.clients[lang]) {
|
|
123
|
+
const transport = this.config.getLspTransport(lang);
|
|
124
|
+
if (!transport) {
|
|
125
|
+
console.warn(`No lsp transport for ${lang}`);
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
const ui = this.editor.ui;
|
|
129
|
+
|
|
130
|
+
const client: LSPClient = new LSPClientImpl(transport, {
|
|
131
|
+
lang,
|
|
132
|
+
rootUri: 'file:///',
|
|
133
|
+
ui,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
client.addEventListener(
|
|
137
|
+
'textDocument/publishDiagnostics',
|
|
138
|
+
this.listenerDiag,
|
|
139
|
+
);
|
|
140
|
+
client.addEventListener('close', this.listenerDisconnect);
|
|
141
|
+
|
|
142
|
+
this.clients[lang] = client;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return this.clients[lang];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
destroy() {
|
|
149
|
+
const workspace: Workspace = this.editor.ci.resolve('workspace');
|
|
150
|
+
|
|
151
|
+
workspace.removeEventListener('openFile', this.listenerChange);
|
|
152
|
+
workspace.removeEventListener('modifyFile', this.listenerChange);
|
|
153
|
+
|
|
154
|
+
for (const client of Object.values(this.clients)) {
|
|
155
|
+
client.removeEventListener(
|
|
156
|
+
'textDocument/publishDiagnostics',
|
|
157
|
+
this.listenerDiag,
|
|
158
|
+
);
|
|
159
|
+
client.removeEventListener(
|
|
160
|
+
'close',
|
|
161
|
+
this.listenerDisconnect,
|
|
162
|
+
);
|
|
163
|
+
client.destroy();
|
|
164
|
+
}
|
|
165
|
+
this.clients = {};
|
|
166
|
+
this.uriToClient = {};
|
|
167
|
+
this.uriToDiagnostics = {};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -99,3 +99,20 @@ export function computeIncrementalChanges(
|
|
|
99
99
|
|
|
100
100
|
return changes;
|
|
101
101
|
}
|
|
102
|
+
|
|
103
|
+
const enum Sync {
|
|
104
|
+
AlwaysIfSmaller = 1024,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function contentChangesFor(
|
|
108
|
+
supportInc: boolean,
|
|
109
|
+
newContent: string,
|
|
110
|
+
oldContent?: string,
|
|
111
|
+
): lsp.TextDocumentContentChangeEvent[] {
|
|
112
|
+
if (!supportInc || newContent.length < Sync.AlwaysIfSmaller || !oldContent) {
|
|
113
|
+
return [{ text: newContent }];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const changes = computeIncrementalChanges(oldContent, newContent);
|
|
117
|
+
return changes.reverse();
|
|
118
|
+
}
|
package/src/mod.ts
CHANGED
package/esm/LSPWorkspace.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type * as lsp from 'vscode-languageserver-protocol';
|
|
2
|
-
import type { EditorUi } from '@kerebron/editor';
|
|
3
|
-
import { Workspace, WorkspaceFile } from './workspace.js';
|
|
4
|
-
import { PositionMapper } from '@kerebron/extension-markdown/PositionMapper';
|
|
5
|
-
import { LSPClient } from './LSPClient.js';
|
|
6
|
-
export interface LSPSource {
|
|
7
|
-
ui: EditorUi;
|
|
8
|
-
getMappedContent(): Promise<{
|
|
9
|
-
content: string;
|
|
10
|
-
mapper: PositionMapper;
|
|
11
|
-
}>;
|
|
12
|
-
}
|
|
13
|
-
declare class LSPWorkspaceFile implements WorkspaceFile {
|
|
14
|
-
readonly uri: string;
|
|
15
|
-
readonly languageId: string;
|
|
16
|
-
version: number;
|
|
17
|
-
content: string;
|
|
18
|
-
mapper: PositionMapper;
|
|
19
|
-
source: LSPSource;
|
|
20
|
-
syncedContent: string;
|
|
21
|
-
diagnostics: Array<lsp.Diagnostic>;
|
|
22
|
-
constructor(uri: string, languageId: string, version: number, content: string, mapper: PositionMapper, source: LSPSource);
|
|
23
|
-
getUi(): EditorUi;
|
|
24
|
-
}
|
|
25
|
-
export declare class LSPWorkspace extends Workspace {
|
|
26
|
-
private client;
|
|
27
|
-
files: LSPWorkspaceFile[];
|
|
28
|
-
private fileVersions;
|
|
29
|
-
constructor(client: LSPClient);
|
|
30
|
-
nextFileVersion(uri: string): number;
|
|
31
|
-
connected(): Promise<void>;
|
|
32
|
-
disconnected(): void;
|
|
33
|
-
syncFiles(): void;
|
|
34
|
-
changedFile(uri: string): Promise<void>;
|
|
35
|
-
openFile(uri: string, languageId: string, source: LSPSource): Promise<void>;
|
|
36
|
-
closeFile(uri: string): void;
|
|
37
|
-
}
|
|
38
|
-
export {};
|
|
39
|
-
//# sourceMappingURL=LSPWorkspace.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"LSPWorkspace.d.ts","sourceRoot":"","sources":["../src/LSPWorkspace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,gCAAgC,CAAC;AAG3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,QAAQ,CAAC;IACb,gBAAgB,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,cAAc,CAAA;KAAE,CAAC,CAAC;CAC1E;AAED,cAAM,gBAAiB,YAAW,aAAa;IAK3C,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM;IACpB,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,cAAc;IACtB,MAAM,EAAE,SAAS;IATnB,aAAa,EAAE,MAAM,CAAM;IAC3B,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAM;gBAGpC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,SAAS;IAI1B,KAAK;CAGN;AAED,qBAAa,YAAa,SAAQ,SAAS;IAI7B,OAAO,CAAC,MAAM;IAH1B,KAAK,EAAE,gBAAgB,EAAE,CAAM;IAC/B,OAAO,CAAC,YAAY,CAAkD;gBAElD,MAAM,EAAE,SAAS;IAIrC,eAAe,CAAC,GAAG,EAAE,MAAM;IAIZ,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAOhC,YAAY,IAAI,IAAI;IAO7B,SAAS;IAUH,WAAW,CAAC,GAAG,EAAE,MAAM;IAqDvB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS;IAsBjE,SAAS,CAAC,GAAG,EAAE,MAAM;CAOtB"}
|