codemirror-languageserver 1.10.0 → 1.12.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/README.md CHANGED
@@ -51,9 +51,7 @@ Contributions are welcome.
51
51
 
52
52
  https://user-images.githubusercontent.com/348107/120141150-c6bb9180-c1fd-11eb-8ada-9b7b7a1e4ade.mp4
53
53
 
54
- | | |
55
- | --- | --- |
56
- | [Toph](https://toph.co) | Competitive programming platform |
54
+ - [Toph](https://toph.co): Competitive programming platform. Toph uses Language Server Plugin for CodeMirror 6 with its integrated code editor.
57
55
 
58
56
  ## License
59
57
 
package/dist/index.d.ts CHANGED
@@ -40,12 +40,13 @@ declare class LanguageServerClient {
40
40
  }
41
41
  declare class LanguageServerPlugin implements PluginValue {
42
42
  private view;
43
+ private allowHTMLContent;
43
44
  client: LanguageServerClient;
44
45
  private documentUri;
45
46
  private languageId;
46
47
  private documentVersion;
47
48
  private changesTimeout;
48
- constructor(view: EditorView);
49
+ constructor(view: EditorView, allowHTMLContent: boolean);
49
50
  update({ docChanged }: ViewUpdate): void;
50
51
  destroy(): void;
51
52
  initialize({ documentText }: {
@@ -81,10 +82,15 @@ interface LanguageServerClientOptions extends LanguageServerBaseOptions {
81
82
  }
82
83
  interface LanguageServerOptions extends LanguageServerClientOptions {
83
84
  client?: LanguageServerClient;
85
+ allowHTMLContent?: boolean;
84
86
  }
85
87
  interface LanguageServerWebsocketOptions extends LanguageServerBaseOptions {
86
88
  serverUri: `ws://${string}` | `wss://${string}`;
87
89
  }
88
- declare function languageServer(options: LanguageServerWebsocketOptions): import("@codemirror/state").Extension[];
89
- declare function languageServerWithTransport(options: LanguageServerOptions): import("@codemirror/state").Extension[];
90
+ declare function languageServer(options: LanguageServerWebsocketOptions): ({
91
+ extension: import("@codemirror/state").Extension;
92
+ } | readonly import("@codemirror/state").Extension[])[];
93
+ declare function languageServerWithTransport(options: LanguageServerOptions): ({
94
+ extension: import("@codemirror/state").Extension;
95
+ } | readonly import("@codemirror/state").Extension[])[];
90
96
  export { LanguageServerClient, languageServer, languageServerWithTransport };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { autocompletion } from '@codemirror/autocomplete';
1
+ import { autocompletion, insertCompletionText } from '@codemirror/autocomplete';
2
2
  import { setDiagnostics } from '@codemirror/lint';
3
3
  import { Facet } from '@codemirror/state';
4
- import { EditorView, ViewPlugin, hoverTooltip } from '@codemirror/view';
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
7
 
@@ -143,8 +143,9 @@ class LanguageServerClient {
143
143
  }
144
144
  }
145
145
  class LanguageServerPlugin {
146
- constructor(view) {
146
+ constructor(view, allowHTMLContent) {
147
147
  this.view = view;
148
+ this.allowHTMLContent = allowHTMLContent;
148
149
  this.client = this.view.state.facet(client);
149
150
  this.documentUri = this.view.state.facet(documentUri);
150
151
  this.languageId = this.view.state.facet(languageId);
@@ -222,7 +223,10 @@ class LanguageServerPlugin {
222
223
  return null;
223
224
  const dom = document.createElement('div');
224
225
  dom.classList.add('documentation');
225
- dom.textContent = formatContents(contents);
226
+ if (this.allowHTMLContent)
227
+ dom.innerHTML = formatContents(contents);
228
+ else
229
+ dom.textContent = formatContents(contents);
226
230
  return { pos, end, create: (view) => ({ dom }), above: true };
227
231
  }
228
232
  async requestCompletion(context, { line, character }, { triggerKind, triggerCharacter, }) {
@@ -241,47 +245,77 @@ class LanguageServerPlugin {
241
245
  });
242
246
  if (!result)
243
247
  return null;
244
- const items = 'items' in result ? result.items : result;
245
- let options = items.map(({ detail, label, kind, textEdit, documentation, sortText, filterText, }) => {
246
- var _a;
247
- const completion = {
248
- label,
249
- detail,
250
- apply: (_a = textEdit === null || textEdit === void 0 ? void 0 : textEdit.newText) !== null && _a !== void 0 ? _a : label,
251
- type: kind && CompletionItemKindMap[kind].toLowerCase(),
252
- sortText: sortText !== null && sortText !== void 0 ? sortText : label,
253
- filterText: filterText !== null && filterText !== void 0 ? filterText : label,
254
- };
255
- if (documentation) {
256
- completion.info = formatContents(documentation);
257
- }
258
- return completion;
259
- });
260
- const [span, match] = prefixMatch(options);
248
+ let items = 'items' in result ? result.items : result;
249
+ const [span, match] = prefixMatch(items);
261
250
  const token = context.matchBefore(match);
262
251
  let { pos } = context;
263
252
  if (token) {
264
253
  pos = token.from;
265
254
  const word = token.text.toLowerCase();
266
255
  if (/^\w+$/.test(word)) {
267
- options = options
268
- .filter(({ filterText }) => filterText.toLowerCase().startsWith(word))
269
- .sort(({ apply: a }, { apply: b }) => {
256
+ items = items
257
+ .filter(({ label, filterText }) => {
258
+ const text = filterText !== null && filterText !== void 0 ? filterText : label;
259
+ return text.toLowerCase().startsWith(word);
260
+ })
261
+ .sort((a, b) => {
262
+ var _a, _b;
263
+ const aText = (_a = a.sortText) !== null && _a !== void 0 ? _a : a.label;
264
+ const bText = (_b = b.sortText) !== null && _b !== void 0 ? _b : b.label;
270
265
  switch (true) {
271
- case a.startsWith(token.text) &&
272
- !b.startsWith(token.text):
266
+ case aText.startsWith(token.text) &&
267
+ !bText.startsWith(token.text):
273
268
  return -1;
274
- case !a.startsWith(token.text) &&
275
- b.startsWith(token.text):
269
+ case !aText.startsWith(token.text) &&
270
+ bText.startsWith(token.text):
276
271
  return 1;
277
272
  }
278
273
  return 0;
279
274
  });
280
275
  }
281
276
  }
277
+ const options = items.map(({ detail, label, kind, textEdit, documentation, additionalTextEdits, }) => {
278
+ const completion = {
279
+ label,
280
+ 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));
285
+ if (!additionalTextEdits) {
286
+ return;
287
+ }
288
+ additionalTextEdits
289
+ .sort(({ range: { end: a } }, { range: { end: b } }) => {
290
+ if (posToOffset(view.state.doc, a) < posToOffset(view.state.doc, b)) {
291
+ return 1;
292
+ }
293
+ else if (posToOffset(view.state.doc, a) > posToOffset(view.state.doc, b)) {
294
+ return -1;
295
+ }
296
+ return 0;
297
+ })
298
+ .forEach((textEdit) => {
299
+ view.dispatch(view.state.update({
300
+ changes: {
301
+ from: posToOffset(view.state.doc, textEdit.range.start),
302
+ to: posToOffset(view.state.doc, textEdit.range.end),
303
+ insert: textEdit.newText
304
+ }
305
+ }));
306
+ });
307
+ },
308
+ type: kind && CompletionItemKindMap[kind].toLowerCase()
309
+ };
310
+ if (documentation) {
311
+ completion.info = formatContents(documentation);
312
+ }
313
+ return completion;
314
+ });
282
315
  return {
283
316
  from: pos,
284
317
  options,
318
+ filter: false
285
319
  };
286
320
  }
287
321
  processNotification(notification) {
@@ -337,7 +371,7 @@ function languageServerWithTransport(options) {
337
371
  client.of(options.client || new LanguageServerClient({ ...options, autoClose: true })),
338
372
  documentUri.of(options.documentUri),
339
373
  languageId.of(options.languageId),
340
- ViewPlugin.define((view) => (plugin = new LanguageServerPlugin(view))),
374
+ ViewPlugin.define((view) => (plugin = new LanguageServerPlugin(view, options.allowHTMLContent))),
341
375
  hoverTooltip((view, pos) => {
342
376
  var _a;
343
377
  return (_a = plugin === null || plugin === void 0 ? void 0 : plugin.requestHoverTooltip(view, offsetToPos(view.state.doc, pos))) !== null && _a !== void 0 ? _a : null;
@@ -368,7 +402,6 @@ function languageServerWithTransport(options) {
368
402
  },
369
403
  ],
370
404
  }),
371
- baseTheme,
372
405
  ];
373
406
  }
374
407
  function posToOffset(doc, pos) {
@@ -407,11 +440,12 @@ function toSet(chars) {
407
440
  }
408
441
  return `[${preamble}${flat.replace(/[^\w\s]/g, '\\$&')}]`;
409
442
  }
410
- function prefixMatch(options) {
443
+ function prefixMatch(items) {
444
+ var _a;
411
445
  const first = new Set();
412
446
  const rest = new Set();
413
- for (const { apply } of options) {
414
- const [initial, ...restStr] = apply;
447
+ for (const item of items) {
448
+ const [initial, ...restStr] = ((_a = item.textEdit) === null || _a === void 0 ? void 0 : _a.newText) || item.label;
415
449
  first.add(initial);
416
450
  for (const char of restStr) {
417
451
  rest.add(char);
@@ -420,17 +454,5 @@ function prefixMatch(options) {
420
454
  const source = toSet(first) + toSet(rest) + '*$';
421
455
  return [new RegExp('^' + source), new RegExp(source)];
422
456
  }
423
- const baseTheme = EditorView.baseTheme({
424
- '.cm-tooltip.documentation': {
425
- display: 'block',
426
- marginLeft: '0',
427
- padding: '3px 6px 3px 8px',
428
- borderLeft: '5px solid #999',
429
- whiteSpace: 'pre',
430
- },
431
- '.cm-tooltip.lint': {
432
- whiteSpace: 'pre',
433
- },
434
- });
435
457
 
436
458
  export { LanguageServerClient, languageServer, languageServerWithTransport };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codemirror-languageserver",
3
- "version": "1.10.0",
3
+ "version": "1.12.0",
4
4
  "description": "Language Server Plugin for CodeMirror 6",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -30,12 +30,12 @@
30
30
  "typescript": "^4.7.4"
31
31
  },
32
32
  "dependencies": {
33
- "@codemirror/autocomplete": "^6.0.2",
34
- "@codemirror/lint": "^6.0.0",
35
- "@codemirror/state": "^6.1.0",
36
- "@codemirror/view": "^6.0.2",
37
- "@open-rpc/client-js": "^1.7.1",
38
- "vscode-languageserver-protocol": "^3.16.0"
33
+ "@codemirror/autocomplete": "^6.18.4",
34
+ "@codemirror/lint": "^6.8.4",
35
+ "@codemirror/state": "^6.5.1",
36
+ "@codemirror/view": "^6.36.2",
37
+ "@open-rpc/client-js": "^1.8.1",
38
+ "vscode-languageserver-protocol": "^3.17.5"
39
39
  },
40
40
  "prettier": {
41
41
  "tabWidth": 4,