codemirror-languageserver 1.12.0 → 1.13.0

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/dist/index.d.ts CHANGED
@@ -1,30 +1,32 @@
1
- import { EditorView, Tooltip, ViewUpdate, PluginValue } from '@codemirror/view';
2
- import * as LSP from 'vscode-languageserver-protocol';
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';
1
+ import { EditorView, Tooltip } from "@codemirror/view";
2
+ import { CompletionTriggerKind } from "vscode-languageserver-protocol";
3
+ import type { CompletionContext, CompletionResult } from "@codemirror/autocomplete";
4
+ import type { PluginValue, ViewUpdate } from "@codemirror/view";
5
+ import { Transport } from "@open-rpc/client-js/build/transports/Transport";
6
+ import type { PublishDiagnosticsParams } from "vscode-languageserver-protocol";
7
+ import type * as LSP from "vscode-languageserver-protocol";
6
8
  interface LSPEventMap {
7
- 'textDocument/publishDiagnostics': LSP.PublishDiagnosticsParams;
9
+ "textDocument/publishDiagnostics": LSP.PublishDiagnosticsParams;
8
10
  }
9
11
  type Notification = {
10
12
  [key in keyof LSPEventMap]: {
11
- jsonrpc: '2.0';
13
+ jsonrpc: "2.0";
12
14
  id?: null | undefined;
13
15
  method: key;
14
16
  params: LSPEventMap[key];
15
17
  };
16
18
  }[keyof LSPEventMap];
17
- declare class LanguageServerClient {
19
+ export declare class LanguageServerClient {
20
+ ready: boolean;
21
+ capabilities: LSP.ServerCapabilities<any>;
22
+ initializePromise: Promise<void>;
18
23
  private rootUri;
19
24
  private workspaceFolders;
20
25
  private autoClose?;
21
26
  private transport;
22
27
  private requestManager;
23
28
  private client;
24
- ready: boolean;
25
- capabilities: LSP.ServerCapabilities<any>;
26
29
  private plugins;
27
- initializePromise: Promise<void>;
28
30
  constructor(options: LanguageServerClientOptions);
29
31
  initialize(): Promise<void>;
30
32
  close(): void;
@@ -87,10 +89,10 @@ interface LanguageServerOptions extends LanguageServerClientOptions {
87
89
  interface LanguageServerWebsocketOptions extends LanguageServerBaseOptions {
88
90
  serverUri: `ws://${string}` | `wss://${string}`;
89
91
  }
90
- declare function languageServer(options: LanguageServerWebsocketOptions): ({
92
+ export declare function languageServer(options: LanguageServerWebsocketOptions): ({
91
93
  extension: import("@codemirror/state").Extension;
92
94
  } | readonly import("@codemirror/state").Extension[])[];
93
- declare function languageServerWithTransport(options: LanguageServerOptions): ({
95
+ export declare function languageServerWithTransport(options: LanguageServerOptions): ({
94
96
  extension: import("@codemirror/state").Extension;
95
97
  } | readonly import("@codemirror/state").Extension[])[];
96
- export { LanguageServerClient, languageServer, languageServerWithTransport };
98
+ export {};
package/dist/index.js CHANGED
@@ -4,11 +4,12 @@ import { Facet } from '@codemirror/state';
4
4
  import { ViewPlugin, hoverTooltip } from '@codemirror/view';
5
5
  import { RequestManager, Client, WebSocketTransport } from '@open-rpc/client-js';
6
6
  import { CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity } from 'vscode-languageserver-protocol';
7
+ import { marked } from 'marked/lib/marked.esm.js';
7
8
 
8
9
  const timeout = 10000;
9
10
  const changesDelay = 500;
10
11
  const CompletionItemKindMap = Object.fromEntries(Object.entries(CompletionItemKind).map(([key, value]) => [value, key]));
11
- const useLast = (values) => values.reduce((_, v) => v, '');
12
+ const useLast = (values) => values.reduce((_, v) => v, "");
12
13
  const client = Facet.define({ combine: useLast });
13
14
  const documentUri = Facet.define({ combine: useLast });
14
15
  const languageId = Facet.define({ combine: useLast });
@@ -28,13 +29,13 @@ class LanguageServerClient {
28
29
  if (webSocketTransport && webSocketTransport.connection) {
29
30
  // XXX(hjr265): Need a better way to do this. Relevant issue:
30
31
  // https://github.com/FurqanSoftware/codemirror-languageserver/issues/9
31
- webSocketTransport.connection.addEventListener('message', (message) => {
32
+ webSocketTransport.connection.addEventListener("message", (message) => {
32
33
  const data = JSON.parse(message.data);
33
34
  if (data.method && data.id) {
34
35
  webSocketTransport.connection.send(JSON.stringify({
35
- jsonrpc: '2.0',
36
+ jsonrpc: "2.0",
36
37
  id: data.id,
37
- result: null
38
+ result: null,
38
39
  }));
39
40
  }
40
41
  });
@@ -42,12 +43,12 @@ class LanguageServerClient {
42
43
  this.initializePromise = this.initialize();
43
44
  }
44
45
  async initialize() {
45
- const { capabilities } = await this.request('initialize', {
46
+ const { capabilities } = await this.request("initialize", {
46
47
  capabilities: {
47
48
  textDocument: {
48
49
  hover: {
49
50
  dynamicRegistration: true,
50
- contentFormat: ['plaintext', 'markdown'],
51
+ contentFormat: ["plaintext", "markdown"],
51
52
  },
52
53
  moniker: {},
53
54
  synchronization: {
@@ -61,7 +62,7 @@ class LanguageServerClient {
61
62
  completionItem: {
62
63
  snippetSupport: false,
63
64
  commitCharactersSupport: true,
64
- documentationFormat: ['plaintext', 'markdown'],
65
+ documentationFormat: ["plaintext", "markdown"],
65
66
  deprecatedSupport: false,
66
67
  preselectSupport: false,
67
68
  },
@@ -70,7 +71,7 @@ class LanguageServerClient {
70
71
  signatureHelp: {
71
72
  dynamicRegistration: true,
72
73
  signatureInformation: {
73
- documentationFormat: ['plaintext', 'markdown'],
74
+ documentationFormat: ["plaintext", "markdown"],
74
75
  },
75
76
  },
76
77
  declaration: {
@@ -102,34 +103,36 @@ class LanguageServerClient {
102
103
  workspaceFolders: this.workspaceFolders,
103
104
  }, timeout * 3);
104
105
  this.capabilities = capabilities;
105
- this.notify('initialized', {});
106
+ this.notify("initialized", {});
106
107
  this.ready = true;
107
108
  }
108
109
  close() {
109
110
  this.client.close();
110
111
  }
111
112
  textDocumentDidOpen(params) {
112
- return this.notify('textDocument/didOpen', params);
113
+ return this.notify("textDocument/didOpen", params);
113
114
  }
114
115
  textDocumentDidChange(params) {
115
- return this.notify('textDocument/didChange', params);
116
+ return this.notify("textDocument/didChange", params);
116
117
  }
117
118
  async textDocumentHover(params) {
118
- return await this.request('textDocument/hover', params, timeout);
119
+ return await this.request("textDocument/hover", params, timeout);
119
120
  }
120
121
  async textDocumentCompletion(params) {
121
- return await this.request('textDocument/completion', params, timeout);
122
+ return await this.request("textDocument/completion", params, timeout);
122
123
  }
123
124
  attachPlugin(plugin) {
124
125
  this.plugins.push(plugin);
125
126
  }
126
127
  detachPlugin(plugin) {
127
128
  const i = this.plugins.indexOf(plugin);
128
- if (i === -1)
129
+ if (i === -1) {
129
130
  return;
131
+ }
130
132
  this.plugins.splice(i, 1);
131
- if (this.autoClose)
133
+ if (this.autoClose) {
132
134
  this.close();
135
+ }
133
136
  }
134
137
  request(method, params, timeout) {
135
138
  return this.client.request({ method, params }, timeout);
@@ -138,8 +141,9 @@ class LanguageServerClient {
138
141
  return this.client.notify({ method, params });
139
142
  }
140
143
  processNotification(notification) {
141
- for (const plugin of this.plugins)
144
+ for (const plugin of this.plugins) {
142
145
  plugin.processNotification(notification);
146
+ }
143
147
  }
144
148
  }
145
149
  class LanguageServerPlugin {
@@ -157,10 +161,12 @@ class LanguageServerPlugin {
157
161
  });
158
162
  }
159
163
  update({ docChanged }) {
160
- if (!docChanged)
164
+ if (!docChanged) {
161
165
  return;
162
- if (this.changesTimeout)
166
+ }
167
+ if (this.changesTimeout) {
163
168
  clearTimeout(this.changesTimeout);
169
+ }
164
170
  this.changesTimeout = self.setTimeout(() => {
165
171
  this.sendChange({
166
172
  documentText: this.view.state.doc.toString(),
@@ -180,12 +186,13 @@ class LanguageServerPlugin {
180
186
  languageId: this.languageId,
181
187
  text: documentText,
182
188
  version: this.documentVersion,
183
- }
189
+ },
184
190
  });
185
191
  }
186
192
  async sendChange({ documentText }) {
187
- if (!this.client.ready)
193
+ if (!this.client.ready) {
188
194
  return;
195
+ }
189
196
  try {
190
197
  await this.client.textDocumentDidChange({
191
198
  textDocument: {
@@ -203,15 +210,17 @@ class LanguageServerPlugin {
203
210
  this.sendChange({ documentText: view.state.doc.toString() });
204
211
  }
205
212
  async requestHoverTooltip(view, { line, character }) {
206
- if (!this.client.ready || !this.client.capabilities.hoverProvider)
213
+ if (!this.client.ready || !this.client.capabilities.hoverProvider) {
207
214
  return null;
215
+ }
208
216
  this.sendChange({ documentText: view.state.doc.toString() });
209
217
  const result = await this.client.textDocumentHover({
210
218
  textDocument: { uri: this.documentUri },
211
219
  position: { line, character },
212
220
  });
213
- if (!result)
221
+ if (!result) {
214
222
  return null;
223
+ }
215
224
  const { contents, range } = result;
216
225
  let pos = posToOffset(view.state.doc, { line, character });
217
226
  let end;
@@ -219,19 +228,28 @@ class LanguageServerPlugin {
219
228
  pos = posToOffset(view.state.doc, range.start);
220
229
  end = posToOffset(view.state.doc, range.end);
221
230
  }
222
- if (pos === null)
231
+ if (pos === null) {
223
232
  return null;
224
- const dom = document.createElement('div');
225
- dom.classList.add('documentation');
226
- if (this.allowHTMLContent)
233
+ }
234
+ const dom = document.createElement("div");
235
+ dom.classList.add("documentation");
236
+ if (this.allowHTMLContent) {
227
237
  dom.innerHTML = formatContents(contents);
228
- else
238
+ }
239
+ else {
229
240
  dom.textContent = formatContents(contents);
230
- return { pos, end, create: (view) => ({ dom }), above: true };
241
+ }
242
+ return {
243
+ pos,
244
+ end,
245
+ create: (view) => ({ dom }),
246
+ above: true,
247
+ };
231
248
  }
232
249
  async requestCompletion(context, { line, character }, { triggerKind, triggerCharacter, }) {
233
- if (!this.client.ready || !this.client.capabilities.completionProvider)
250
+ if (!this.client.ready || !this.client.capabilities.completionProvider) {
234
251
  return null;
252
+ }
235
253
  this.sendChange({
236
254
  documentText: context.state.doc.toString(),
237
255
  });
@@ -241,11 +259,12 @@ class LanguageServerPlugin {
241
259
  context: {
242
260
  triggerKind,
243
261
  triggerCharacter,
244
- }
262
+ },
245
263
  });
246
- if (!result)
264
+ if (!result) {
247
265
  return null;
248
- let items = 'items' in result ? result.items : result;
266
+ }
267
+ let items = "items" in result ? result.items : result;
249
268
  const [span, match] = prefixMatch(items);
250
269
  const token = context.matchBefore(match);
251
270
  let { pos } = context;
@@ -278,10 +297,13 @@ class LanguageServerPlugin {
278
297
  const completion = {
279
298
  label,
280
299
  detail,
281
- apply: function (view, completion, from, to) {
282
- var _a;
283
- const text = (_a = textEdit === null || textEdit === void 0 ? void 0 : textEdit.newText) !== null && _a !== void 0 ? _a : label;
284
- view.dispatch(insertCompletionText(view.state, text, from, to));
300
+ apply(view, completion, from, to) {
301
+ if (isLSPTextEdit(textEdit)) {
302
+ view.dispatch(insertCompletionText(view.state, textEdit.newText, posToOffset(view.state.doc, textEdit.range.start), posToOffset(view.state.doc, textEdit.range.end)));
303
+ }
304
+ else {
305
+ view.dispatch(insertCompletionText(view.state, label, from, to));
306
+ }
285
307
  if (!additionalTextEdits) {
286
308
  return;
287
309
  }
@@ -300,12 +322,12 @@ class LanguageServerPlugin {
300
322
  changes: {
301
323
  from: posToOffset(view.state.doc, textEdit.range.start),
302
324
  to: posToOffset(view.state.doc, textEdit.range.end),
303
- insert: textEdit.newText
304
- }
325
+ insert: textEdit.newText,
326
+ },
305
327
  }));
306
328
  });
307
329
  },
308
- type: kind && CompletionItemKindMap[kind].toLowerCase()
330
+ type: kind && CompletionItemKindMap[kind].toLowerCase(),
309
331
  };
310
332
  if (documentation) {
311
333
  completion.info = formatContents(documentation);
@@ -315,32 +337,33 @@ class LanguageServerPlugin {
315
337
  return {
316
338
  from: pos,
317
339
  options,
318
- filter: false
340
+ filter: false,
319
341
  };
320
342
  }
321
343
  processNotification(notification) {
322
344
  try {
323
345
  switch (notification.method) {
324
- case 'textDocument/publishDiagnostics':
346
+ case "textDocument/publishDiagnostics":
325
347
  this.processDiagnostics(notification.params);
326
348
  }
327
349
  }
328
350
  catch (error) {
329
- console.error(error);
351
+ console.log(error);
330
352
  }
331
353
  }
332
354
  processDiagnostics(params) {
333
- if (params.uri !== this.documentUri)
355
+ if (params.uri !== this.documentUri) {
334
356
  return;
357
+ }
335
358
  const diagnostics = params.diagnostics
336
359
  .map(({ range, message, severity }) => ({
337
360
  from: posToOffset(this.view.state.doc, range.start),
338
361
  to: posToOffset(this.view.state.doc, range.end),
339
362
  severity: {
340
- [DiagnosticSeverity.Error]: 'error',
341
- [DiagnosticSeverity.Warning]: 'warning',
342
- [DiagnosticSeverity.Information]: 'info',
343
- [DiagnosticSeverity.Hint]: 'info',
363
+ [DiagnosticSeverity.Error]: "error",
364
+ [DiagnosticSeverity.Warning]: "warning",
365
+ [DiagnosticSeverity.Information]: "info",
366
+ [DiagnosticSeverity.Hint]: "info",
344
367
  }[severity],
345
368
  message,
346
369
  }))
@@ -362,7 +385,7 @@ function languageServer(options) {
362
385
  delete options.serverUri;
363
386
  return languageServerWithTransport({
364
387
  ...options,
365
- transport: new WebSocketTransport(serverUri)
388
+ transport: new WebSocketTransport(serverUri),
366
389
  });
367
390
  }
368
391
  function languageServerWithTransport(options) {
@@ -380,8 +403,9 @@ function languageServerWithTransport(options) {
380
403
  override: [
381
404
  async (context) => {
382
405
  var _a, _b, _c;
383
- if (plugin == null)
406
+ if (plugin == null) {
384
407
  return null;
408
+ }
385
409
  const { state, pos, explicit } = context;
386
410
  const line = state.doc.lineAt(pos);
387
411
  let trigKind = CompletionTriggerKind.Invoked;
@@ -396,8 +420,8 @@ function languageServerWithTransport(options) {
396
420
  return null;
397
421
  }
398
422
  return await plugin.requestCompletion(context, offsetToPos(state.doc, pos), {
399
- triggerKind: trigKind,
400
423
  triggerCharacter: trigChar,
424
+ triggerKind: trigKind,
401
425
  });
402
426
  },
403
427
  ],
@@ -405,40 +429,46 @@ function languageServerWithTransport(options) {
405
429
  ];
406
430
  }
407
431
  function posToOffset(doc, pos) {
408
- if (pos.line >= doc.lines)
432
+ if (pos.line >= doc.lines) {
409
433
  return;
434
+ }
410
435
  const offset = doc.line(pos.line + 1).from + pos.character;
411
- if (offset > doc.length)
436
+ if (offset > doc.length) {
412
437
  return;
438
+ }
413
439
  return offset;
414
440
  }
415
441
  function offsetToPos(doc, offset) {
416
442
  const line = doc.lineAt(offset);
417
443
  return {
418
- line: line.number - 1,
419
444
  character: offset - line.from,
445
+ line: line.number - 1,
420
446
  };
421
447
  }
422
448
  function formatContents(contents) {
423
- if (Array.isArray(contents)) {
424
- return contents.map((c) => formatContents(c) + '\n\n').join('');
449
+ if (isLSPMarkupContent(contents)) {
450
+ let value = contents.value;
451
+ if (contents.kind === "markdown") {
452
+ value = marked.parse(value);
453
+ }
454
+ return value;
425
455
  }
426
- else if (typeof contents === 'string') {
427
- return contents;
456
+ else if (Array.isArray(contents)) {
457
+ return contents.map((c) => formatContents(c) + "\n\n").join("");
428
458
  }
429
- else {
430
- return contents.value;
459
+ else if (typeof contents === "string") {
460
+ return contents;
431
461
  }
432
462
  }
433
463
  function toSet(chars) {
434
- let preamble = '';
435
- let flat = Array.from(chars).join('');
464
+ let preamble = "";
465
+ let flat = Array.from(chars).join("");
436
466
  const words = /\w/.test(flat);
437
467
  if (words) {
438
- preamble += '\\w';
439
- flat = flat.replace(/\w/g, '');
468
+ preamble += "\\w";
469
+ flat = flat.replace(/\w/g, "");
440
470
  }
441
- return `[${preamble}${flat.replace(/[^\w\s]/g, '\\$&')}]`;
471
+ return `[${preamble}${flat.replace(/[^\w\s]/g, "\\$&")}]`;
442
472
  }
443
473
  function prefixMatch(items) {
444
474
  var _a;
@@ -451,8 +481,14 @@ function prefixMatch(items) {
451
481
  rest.add(char);
452
482
  }
453
483
  }
454
- const source = toSet(first) + toSet(rest) + '*$';
455
- return [new RegExp('^' + source), new RegExp(source)];
484
+ const source = toSet(first) + toSet(rest) + "*$";
485
+ return [new RegExp("^" + source), new RegExp(source)];
486
+ }
487
+ function isLSPTextEdit(textEdit) {
488
+ return (textEdit === null || textEdit === void 0 ? void 0 : textEdit.range) !== undefined;
489
+ }
490
+ function isLSPMarkupContent(contents) {
491
+ return contents.kind !== undefined;
456
492
  }
457
493
 
458
494
  export { LanguageServerClient, languageServer, languageServerWithTransport };
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "codemirror-languageserver",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Language Server Plugin for CodeMirror 6",
5
5
  "main": "dist/index.js",
6
+ "type": "module",
6
7
  "scripts": {
7
8
  "prepare": "rollup -c rollup.config.js"
8
9
  },
@@ -21,20 +22,23 @@
21
22
  },
22
23
  "license": "BSD-3-Clause",
23
24
  "devDependencies": {
24
- "@babel/core": "^7.18.6",
25
- "@babel/preset-env": "^7.18.6",
26
- "@rollup/plugin-babel": "^5.3.1",
27
- "prettier": "^2.2.1",
28
- "rollup": "^2.75.7",
29
- "rollup-plugin-ts": "^3.0.2",
30
- "typescript": "^4.7.4"
25
+ "@babel/core": "^7.28.0",
26
+ "@babel/preset-env": "^7.28.0",
27
+ "@rollup/plugin-babel": "^6.0.4",
28
+ "@rollup/plugin-typescript": "^12.1.4",
29
+ "prettier": "^3.6.2",
30
+ "rollup": "^4.46.2",
31
+ "tslib": "^2.8.1",
32
+ "tslint": "^6.1.3",
33
+ "typescript": "^5.9.2"
31
34
  },
32
35
  "dependencies": {
33
- "@codemirror/autocomplete": "^6.18.4",
34
- "@codemirror/lint": "^6.8.4",
35
- "@codemirror/state": "^6.5.1",
36
- "@codemirror/view": "^6.36.2",
36
+ "@codemirror/autocomplete": "^6.18.6",
37
+ "@codemirror/lint": "^6.8.5",
38
+ "@codemirror/state": "^6.5.2",
39
+ "@codemirror/view": "^6.38.1",
37
40
  "@open-rpc/client-js": "^1.8.1",
41
+ "marked": "^16.1.2",
38
42
  "vscode-languageserver-protocol": "^3.17.5"
39
43
  },
40
44
  "prettier": {
package/tslint.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "defaultSeverity": "error",
3
+ "extends": [
4
+ "tslint:recommended"
5
+ ],
6
+ "jsRules": {},
7
+ "rules": {},
8
+ "rulesDirectory": []
9
+ }