codemirror-languageserver 1.6.0 → 1.8.1
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/README.md +13 -3
- package/dist/index.d.ts +83 -4
- package/dist/index.js +117 -68
- package/package.json +5 -6
package/README.md
CHANGED
|
@@ -15,10 +15,20 @@ npm i codemirror-languageserver
|
|
|
15
15
|
``` js
|
|
16
16
|
import { languageServer } from 'codemirror-languageserver';
|
|
17
17
|
|
|
18
|
+
const transport = new WebSocketTransport(serverUri)
|
|
19
|
+
|
|
18
20
|
var ls = languageServer({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
// WebSocket server uri and other client options.
|
|
22
|
+
serverUri,
|
|
23
|
+
rootUri: 'file:///',
|
|
24
|
+
|
|
25
|
+
// Alternatively, to share the same client across multiple instances of this plugin.
|
|
26
|
+
client: new LanguageServerClient({
|
|
27
|
+
serverUri,
|
|
28
|
+
rootUri: 'file:///'
|
|
29
|
+
}),
|
|
30
|
+
|
|
31
|
+
documentUri: `file:///${filename}`,
|
|
22
32
|
languageId: 'cpp' // As defined at https://microsoft.github.io/language-server-protocol/specification#textDocumentItem.
|
|
23
33
|
});
|
|
24
34
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,89 @@
|
|
|
1
|
+
import { EditorView, Tooltip, ViewUpdate, PluginValue } from '@codemirror/view';
|
|
1
2
|
import * as LSP from 'vscode-languageserver-protocol';
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
import { CompletionTriggerKind, PublishDiagnosticsParams } from "vscode-languageserver-protocol";
|
|
4
|
+
import { CompletionContext, CompletionResult } from '@codemirror/autocomplete';
|
|
5
|
+
import { Transport } from '@open-rpc/client-js/build/transports/Transport';
|
|
6
|
+
interface LSPEventMap {
|
|
7
|
+
'textDocument/publishDiagnostics': LSP.PublishDiagnosticsParams;
|
|
8
|
+
}
|
|
9
|
+
type Notification = {
|
|
10
|
+
[key in keyof LSPEventMap]: {
|
|
11
|
+
jsonrpc: '2.0';
|
|
12
|
+
id?: null | undefined;
|
|
13
|
+
method: key;
|
|
14
|
+
params: LSPEventMap[key];
|
|
15
|
+
};
|
|
16
|
+
}[keyof LSPEventMap];
|
|
17
|
+
declare class LanguageServerClient {
|
|
18
|
+
private rootUri;
|
|
19
|
+
private workspaceFolders;
|
|
20
|
+
private autoClose?;
|
|
21
|
+
private transport;
|
|
22
|
+
private requestManager;
|
|
23
|
+
private client;
|
|
24
|
+
ready: boolean;
|
|
25
|
+
capabilities: LSP.ServerCapabilities<any>;
|
|
26
|
+
private plugins;
|
|
27
|
+
constructor(options: LanguageServerClientOptions);
|
|
28
|
+
initialize(): Promise<void>;
|
|
29
|
+
close(): void;
|
|
30
|
+
textDocumentDidOpen(params: LSP.DidOpenTextDocumentParams): Promise<LSP.DidOpenTextDocumentParams>;
|
|
31
|
+
textDocumentDidChange(params: LSP.DidChangeTextDocumentParams): Promise<LSP.DidChangeTextDocumentParams>;
|
|
32
|
+
textDocumentHover(params: LSP.HoverParams): Promise<LSP.Hover>;
|
|
33
|
+
textDocumentCompletion(params: LSP.CompletionParams): Promise<LSP.CompletionList | LSP.CompletionItem[]>;
|
|
34
|
+
attachPlugin(plugin: LanguageServerPlugin): void;
|
|
35
|
+
detachPlugin(plugin: LanguageServerPlugin): void;
|
|
36
|
+
private request;
|
|
37
|
+
private notify;
|
|
38
|
+
private processNotification;
|
|
39
|
+
}
|
|
40
|
+
declare class LanguageServerPlugin implements PluginValue {
|
|
41
|
+
private view;
|
|
42
|
+
client: LanguageServerClient;
|
|
43
|
+
private documentUri;
|
|
44
|
+
private languageId;
|
|
45
|
+
private documentVersion;
|
|
46
|
+
private changesTimeout;
|
|
47
|
+
constructor(view: EditorView);
|
|
48
|
+
update({ docChanged }: ViewUpdate): void;
|
|
49
|
+
destroy(): void;
|
|
50
|
+
initialize({ documentText }: {
|
|
51
|
+
documentText: string;
|
|
52
|
+
}): Promise<void>;
|
|
53
|
+
sendChange({ documentText }: {
|
|
54
|
+
documentText: string;
|
|
55
|
+
}): Promise<void>;
|
|
56
|
+
requestDiagnostics(view: EditorView): void;
|
|
57
|
+
requestHoverTooltip(view: EditorView, { line, character }: {
|
|
58
|
+
line: number;
|
|
59
|
+
character: number;
|
|
60
|
+
}): Promise<Tooltip | null>;
|
|
61
|
+
requestCompletion(context: CompletionContext, { line, character }: {
|
|
62
|
+
line: number;
|
|
63
|
+
character: number;
|
|
64
|
+
}, { triggerKind, triggerCharacter, }: {
|
|
65
|
+
triggerKind: CompletionTriggerKind;
|
|
66
|
+
triggerCharacter: string | undefined;
|
|
67
|
+
}): Promise<CompletionResult | null>;
|
|
68
|
+
processNotification(notification: Notification): void;
|
|
69
|
+
processDiagnostics(params: PublishDiagnosticsParams): void;
|
|
70
|
+
}
|
|
71
|
+
interface LanguageServerBaseOptions {
|
|
4
72
|
rootUri: string | null;
|
|
5
73
|
workspaceFolders: LSP.WorkspaceFolder[] | null;
|
|
6
74
|
documentUri: string;
|
|
7
75
|
languageId: string;
|
|
8
76
|
}
|
|
9
|
-
|
|
10
|
-
|
|
77
|
+
interface LanguageServerClientOptions extends LanguageServerBaseOptions {
|
|
78
|
+
transport: Transport;
|
|
79
|
+
autoClose?: boolean;
|
|
80
|
+
}
|
|
81
|
+
interface LanguageServerOptions extends LanguageServerClientOptions {
|
|
82
|
+
client?: LanguageServerClient;
|
|
83
|
+
}
|
|
84
|
+
interface LanguageServerWebsocketOptions extends LanguageServerBaseOptions {
|
|
85
|
+
serverUri: `ws://${string}` | `wss://${string}`;
|
|
86
|
+
}
|
|
87
|
+
declare function languageServer(options: LanguageServerWebsocketOptions): import("@codemirror/state").Extension[];
|
|
88
|
+
declare function languageServerWithTransport(options: LanguageServerOptions): import("@codemirror/state").Extension[];
|
|
89
|
+
export { LanguageServerClient, languageServer, languageServerWithTransport };
|
package/dist/index.js
CHANGED
|
@@ -1,65 +1,47 @@
|
|
|
1
1
|
import { autocompletion } from '@codemirror/autocomplete';
|
|
2
2
|
import { setDiagnostics } from '@codemirror/lint';
|
|
3
3
|
import { Facet } from '@codemirror/state';
|
|
4
|
-
import { hoverTooltip } from '@codemirror/
|
|
5
|
-
import {
|
|
6
|
-
import { WebSocketTransport, RequestManager, Client } from '@open-rpc/client-js';
|
|
4
|
+
import { ViewPlugin, hoverTooltip, EditorView } from '@codemirror/view';
|
|
5
|
+
import { RequestManager, Client, WebSocketTransport } from '@open-rpc/client-js';
|
|
7
6
|
import { CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity } from 'vscode-languageserver-protocol';
|
|
8
7
|
|
|
9
8
|
const timeout = 10000;
|
|
10
9
|
const changesDelay = 500;
|
|
11
10
|
const CompletionItemKindMap = Object.fromEntries(Object.entries(CompletionItemKind).map(([key, value]) => [value, key]));
|
|
12
11
|
const useLast = (values) => values.reduce((_, v) => v, '');
|
|
13
|
-
const
|
|
14
|
-
const rootUri = Facet.define({ combine: useLast });
|
|
15
|
-
const workspaceFolders = Facet.define({ combine: useLast });
|
|
12
|
+
const client = Facet.define({ combine: useLast });
|
|
16
13
|
const documentUri = Facet.define({ combine: useLast });
|
|
17
14
|
const languageId = Facet.define({ combine: useLast });
|
|
18
|
-
class
|
|
19
|
-
constructor(
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
this.documentVersion = 0;
|
|
26
|
-
this.changesTimeout = 0;
|
|
27
|
-
this.transport = new WebSocketTransport(this.view.state.facet(serverUri));
|
|
15
|
+
class LanguageServerClient {
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.rootUri = options.rootUri;
|
|
18
|
+
this.workspaceFolders = options.workspaceFolders;
|
|
19
|
+
this.autoClose = options.autoClose;
|
|
20
|
+
this.plugins = [];
|
|
21
|
+
this.transport = options.transport;
|
|
28
22
|
this.requestManager = new RequestManager([this.transport]);
|
|
29
23
|
this.client = new Client(this.requestManager);
|
|
30
24
|
this.client.onNotification((data) => {
|
|
31
25
|
this.processNotification(data);
|
|
32
26
|
});
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
clearTimeout(this.changesTimeout);
|
|
47
|
-
this.changesTimeout = self.setTimeout(() => {
|
|
48
|
-
this.sendChange({
|
|
49
|
-
documentText: this.view.state.doc.toString(),
|
|
27
|
+
const webSocketTransport = this.transport;
|
|
28
|
+
if (webSocketTransport && webSocketTransport.connection) {
|
|
29
|
+
// XXX(hjr265): Need a better way to do this. Relevant issue:
|
|
30
|
+
// https://github.com/FurqanSoftware/codemirror-languageserver/issues/9
|
|
31
|
+
webSocketTransport.connection.addEventListener('message', (message) => {
|
|
32
|
+
const data = JSON.parse(message.data);
|
|
33
|
+
if (data.method && data.id) {
|
|
34
|
+
webSocketTransport.connection.send(JSON.stringify({
|
|
35
|
+
jsonrpc: '2.0',
|
|
36
|
+
id: data.id,
|
|
37
|
+
result: null
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
50
40
|
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
destroy() {
|
|
54
|
-
this.client.close();
|
|
55
|
-
}
|
|
56
|
-
request(method, params, timeout) {
|
|
57
|
-
return this.client.request({ method, params }, timeout);
|
|
58
|
-
}
|
|
59
|
-
notify(method, params) {
|
|
60
|
-
return this.client.notify({ method, params });
|
|
41
|
+
}
|
|
42
|
+
this.initialize();
|
|
61
43
|
}
|
|
62
|
-
async initialize(
|
|
44
|
+
async initialize() {
|
|
63
45
|
const { capabilities } = await this.request('initialize', {
|
|
64
46
|
capabilities: {
|
|
65
47
|
textDocument: {
|
|
@@ -121,21 +103,87 @@ class LanguageServerPlugin {
|
|
|
121
103
|
}, timeout * 3);
|
|
122
104
|
this.capabilities = capabilities;
|
|
123
105
|
this.notify('initialized', {});
|
|
124
|
-
this.
|
|
106
|
+
this.ready = true;
|
|
107
|
+
}
|
|
108
|
+
close() {
|
|
109
|
+
this.client.close();
|
|
110
|
+
}
|
|
111
|
+
textDocumentDidOpen(params) {
|
|
112
|
+
return this.notify('textDocument/didOpen', params);
|
|
113
|
+
}
|
|
114
|
+
textDocumentDidChange(params) {
|
|
115
|
+
return this.notify('textDocument/didChange', params);
|
|
116
|
+
}
|
|
117
|
+
async textDocumentHover(params) {
|
|
118
|
+
return await this.request('textDocument/hover', params, timeout);
|
|
119
|
+
}
|
|
120
|
+
async textDocumentCompletion(params) {
|
|
121
|
+
return await this.request('textDocument/completion', params, timeout);
|
|
122
|
+
}
|
|
123
|
+
attachPlugin(plugin) {
|
|
124
|
+
this.plugins.push(plugin);
|
|
125
|
+
}
|
|
126
|
+
detachPlugin(plugin) {
|
|
127
|
+
const i = this.plugins.indexOf(plugin);
|
|
128
|
+
if (i === -1)
|
|
129
|
+
return;
|
|
130
|
+
this.plugins.splice(i, 1);
|
|
131
|
+
if (this.autoClose)
|
|
132
|
+
this.close();
|
|
133
|
+
}
|
|
134
|
+
request(method, params, timeout) {
|
|
135
|
+
return this.client.request({ method, params }, timeout);
|
|
136
|
+
}
|
|
137
|
+
notify(method, params) {
|
|
138
|
+
return this.client.notify({ method, params });
|
|
139
|
+
}
|
|
140
|
+
processNotification(notification) {
|
|
141
|
+
for (const plugin of this.plugins)
|
|
142
|
+
plugin.processNotification(notification);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
class LanguageServerPlugin {
|
|
146
|
+
constructor(view) {
|
|
147
|
+
this.view = view;
|
|
148
|
+
this.client = this.view.state.facet(client);
|
|
149
|
+
this.documentUri = this.view.state.facet(documentUri);
|
|
150
|
+
this.languageId = this.view.state.facet(languageId);
|
|
151
|
+
this.documentVersion = 0;
|
|
152
|
+
this.changesTimeout = 0;
|
|
153
|
+
this.client.attachPlugin(this);
|
|
154
|
+
this.initialize({
|
|
155
|
+
documentText: this.view.state.doc.toString(),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
update({ docChanged }) {
|
|
159
|
+
if (!docChanged)
|
|
160
|
+
return;
|
|
161
|
+
if (this.changesTimeout)
|
|
162
|
+
clearTimeout(this.changesTimeout);
|
|
163
|
+
this.changesTimeout = self.setTimeout(() => {
|
|
164
|
+
this.sendChange({
|
|
165
|
+
documentText: this.view.state.doc.toString(),
|
|
166
|
+
});
|
|
167
|
+
}, changesDelay);
|
|
168
|
+
}
|
|
169
|
+
destroy() {
|
|
170
|
+
this.client.detachPlugin(this);
|
|
171
|
+
}
|
|
172
|
+
async initialize({ documentText }) {
|
|
173
|
+
this.client.textDocumentDidOpen({
|
|
125
174
|
textDocument: {
|
|
126
175
|
uri: this.documentUri,
|
|
127
176
|
languageId: this.languageId,
|
|
128
177
|
text: documentText,
|
|
129
178
|
version: this.documentVersion,
|
|
130
|
-
}
|
|
179
|
+
}
|
|
131
180
|
});
|
|
132
|
-
this.ready = true;
|
|
133
181
|
}
|
|
134
182
|
async sendChange({ documentText }) {
|
|
135
|
-
if (!this.ready)
|
|
183
|
+
if (!this.client.ready)
|
|
136
184
|
return;
|
|
137
185
|
try {
|
|
138
|
-
await this.
|
|
186
|
+
await this.client.textDocumentDidChange({
|
|
139
187
|
textDocument: {
|
|
140
188
|
uri: this.documentUri,
|
|
141
189
|
version: this.documentVersion++,
|
|
@@ -151,13 +199,13 @@ class LanguageServerPlugin {
|
|
|
151
199
|
this.sendChange({ documentText: view.state.doc.toString() });
|
|
152
200
|
}
|
|
153
201
|
async requestHoverTooltip(view, { line, character }) {
|
|
154
|
-
if (!this.ready || !this.capabilities.hoverProvider)
|
|
202
|
+
if (!this.client.ready || !this.client.capabilities.hoverProvider)
|
|
155
203
|
return null;
|
|
156
204
|
this.sendChange({ documentText: view.state.doc.toString() });
|
|
157
|
-
const result = await this.
|
|
205
|
+
const result = await this.client.textDocumentHover({
|
|
158
206
|
textDocument: { uri: this.documentUri },
|
|
159
207
|
position: { line, character },
|
|
160
|
-
}
|
|
208
|
+
});
|
|
161
209
|
if (!result)
|
|
162
210
|
return null;
|
|
163
211
|
const { contents, range } = result;
|
|
@@ -175,19 +223,19 @@ class LanguageServerPlugin {
|
|
|
175
223
|
return { pos, end, create: (view) => ({ dom }), above: true };
|
|
176
224
|
}
|
|
177
225
|
async requestCompletion(context, { line, character }, { triggerKind, triggerCharacter, }) {
|
|
178
|
-
if (!this.ready || !this.capabilities.completionProvider)
|
|
226
|
+
if (!this.client.ready || !this.client.capabilities.completionProvider)
|
|
179
227
|
return null;
|
|
180
228
|
this.sendChange({
|
|
181
229
|
documentText: context.state.doc.toString(),
|
|
182
230
|
});
|
|
183
|
-
const result = await this.
|
|
231
|
+
const result = await this.client.textDocumentCompletion({
|
|
184
232
|
textDocument: { uri: this.documentUri },
|
|
185
233
|
position: { line, character },
|
|
186
234
|
context: {
|
|
187
235
|
triggerKind,
|
|
188
236
|
triggerCharacter,
|
|
189
|
-
}
|
|
190
|
-
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
191
239
|
if (!result)
|
|
192
240
|
return null;
|
|
193
241
|
const items = 'items' in result ? result.items : result;
|
|
@@ -233,13 +281,6 @@ class LanguageServerPlugin {
|
|
|
233
281
|
options,
|
|
234
282
|
};
|
|
235
283
|
}
|
|
236
|
-
processRequest({ id }) {
|
|
237
|
-
this.transport.connection.send(JSON.stringify({
|
|
238
|
-
jsonrpc: '2.0',
|
|
239
|
-
id,
|
|
240
|
-
result: null
|
|
241
|
-
}));
|
|
242
|
-
}
|
|
243
284
|
processNotification(notification) {
|
|
244
285
|
try {
|
|
245
286
|
switch (notification.method) {
|
|
@@ -252,6 +293,8 @@ class LanguageServerPlugin {
|
|
|
252
293
|
}
|
|
253
294
|
}
|
|
254
295
|
processDiagnostics(params) {
|
|
296
|
+
if (params.uri !== this.documentUri)
|
|
297
|
+
return;
|
|
255
298
|
const diagnostics = params.diagnostics
|
|
256
299
|
.map(({ range, message, severity }) => ({
|
|
257
300
|
from: posToOffset(this.view.state.doc, range.start),
|
|
@@ -278,11 +321,17 @@ class LanguageServerPlugin {
|
|
|
278
321
|
}
|
|
279
322
|
}
|
|
280
323
|
function languageServer(options) {
|
|
324
|
+
const serverUri = options.serverUri;
|
|
325
|
+
delete options.serverUri;
|
|
326
|
+
return languageServerWithTransport({
|
|
327
|
+
...options,
|
|
328
|
+
transport: new WebSocketTransport(serverUri)
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
function languageServerWithTransport(options) {
|
|
281
332
|
let plugin = null;
|
|
282
333
|
return [
|
|
283
|
-
|
|
284
|
-
workspaceFolders.of(options.workspaceFolders),
|
|
285
|
-
rootUri.of(options.rootUri),
|
|
334
|
+
client.of(options.client || new LanguageServerClient({ ...options, autoClose: true })),
|
|
286
335
|
documentUri.of(options.documentUri),
|
|
287
336
|
languageId.of(options.languageId),
|
|
288
337
|
ViewPlugin.define((view) => (plugin = new LanguageServerPlugin(view))),
|
|
@@ -301,7 +350,7 @@ function languageServer(options) {
|
|
|
301
350
|
let trigKind = CompletionTriggerKind.Invoked;
|
|
302
351
|
let trigChar;
|
|
303
352
|
if (!explicit &&
|
|
304
|
-
((_c = (_b = (_a = plugin.capabilities) === null || _a === void 0 ? void 0 : _a.completionProvider) === null || _b === void 0 ? void 0 : _b.triggerCharacters) === null || _c === void 0 ? void 0 : _c.includes(line.text[pos - line.from - 1]))) {
|
|
353
|
+
((_c = (_b = (_a = plugin.client.capabilities) === null || _a === void 0 ? void 0 : _a.completionProvider) === null || _b === void 0 ? void 0 : _b.triggerCharacters) === null || _c === void 0 ? void 0 : _c.includes(line.text[pos - line.from - 1]))) {
|
|
305
354
|
trigKind = CompletionTriggerKind.TriggerCharacter;
|
|
306
355
|
trigChar = line.text[pos - line.from - 1];
|
|
307
356
|
}
|
|
@@ -381,4 +430,4 @@ const baseTheme = EditorView.baseTheme({
|
|
|
381
430
|
},
|
|
382
431
|
});
|
|
383
432
|
|
|
384
|
-
export { languageServer };
|
|
433
|
+
export { LanguageServerClient, languageServer, languageServerWithTransport };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codemirror-languageserver",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "Language Server Plugin for CodeMirror 6",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -30,11 +30,10 @@
|
|
|
30
30
|
"typescript": "^4.2.4"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@codemirror/autocomplete": "^0.
|
|
34
|
-
"@codemirror/lint": "^0.
|
|
35
|
-
"@codemirror/state": "^0.
|
|
36
|
-
"@codemirror/
|
|
37
|
-
"@codemirror/view": "^0.19.43",
|
|
33
|
+
"@codemirror/autocomplete": "^0.20.0",
|
|
34
|
+
"@codemirror/lint": "^0.20.0",
|
|
35
|
+
"@codemirror/state": "^0.20.0",
|
|
36
|
+
"@codemirror/view": "^0.20.0",
|
|
38
37
|
"@open-rpc/client-js": "^1.7.1",
|
|
39
38
|
"vscode-languageserver-protocol": "^3.16.0"
|
|
40
39
|
},
|