codemirror-languageserver 1.19.0 → 1.21.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 +167 -43
- package/dist/definition.d.ts +12 -0
- package/dist/formatting.d.ts +8 -0
- package/dist/highlight.d.ts +6 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +90 -3
- package/dist/jsonrpc.d.ts +12 -0
- package/dist/plugin.d.ts +27 -0
- package/dist/rename.d.ts +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/codemirror-languageserver)
|
|
4
4
|
|
|
5
|
-
This plugin
|
|
5
|
+
This plugin connects a [CodeMirror 6](https://codemirror.net/) editor with a [Language Server](https://microsoft.github.io/language-server-protocol/) over WebSocket, providing IDE-like features in the browser.
|
|
6
6
|
|
|
7
7
|
[How It Works](https://hjr265.me/blog/codemirror-lsp/)
|
|
8
8
|
|
|
@@ -18,61 +18,136 @@ https://user-images.githubusercontent.com/348107/120141150-c6bb9180-c1fd-11eb-8a
|
|
|
18
18
|
- 🎨 Document Formatting and Range Formatting
|
|
19
19
|
- ✏️ Rename Symbol
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## Installation
|
|
22
22
|
|
|
23
23
|
```
|
|
24
24
|
npm i codemirror-languageserver
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
**Peer dependencies:** This package requires `@codemirror/autocomplete`, `@codemirror/lint`, `@codemirror/state`, and `@codemirror/view` as peer dependencies. If you're using CodeMirror 6, you likely already have these installed.
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
27
31
|
```js
|
|
32
|
+
import { EditorState } from '@codemirror/state';
|
|
33
|
+
import { EditorView } from '@codemirror/view';
|
|
28
34
|
import { languageServer } from 'codemirror-languageserver';
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
serverUri,
|
|
36
|
+
const ls = languageServer({
|
|
37
|
+
serverUri: 'ws://localhost:8080',
|
|
33
38
|
rootUri: 'file:///',
|
|
34
|
-
|
|
35
|
-
// Alternatively, to share the same client across multiple instances of this plugin.
|
|
36
|
-
client: new LanguageServerClient({
|
|
37
|
-
transport: new WebSocketTransport(serverUri),
|
|
38
|
-
rootUri: 'file:///',
|
|
39
|
-
}),
|
|
40
|
-
|
|
41
39
|
documentUri: `file:///${filename}`,
|
|
42
40
|
languageId: 'cpp', // As defined at https://microsoft.github.io/language-server-protocol/specification#textDocumentItem.
|
|
43
41
|
});
|
|
44
42
|
|
|
45
|
-
|
|
43
|
+
const view = new EditorView({
|
|
46
44
|
state: EditorState.create({
|
|
47
45
|
extensions: [
|
|
48
|
-
// ...
|
|
46
|
+
// ... other extensions
|
|
49
47
|
ls,
|
|
50
|
-
// ...
|
|
51
48
|
],
|
|
52
49
|
}),
|
|
53
50
|
});
|
|
54
51
|
```
|
|
55
52
|
|
|
56
|
-
|
|
53
|
+
This sets up all built-in features: completion, hover, diagnostics, go-to-definition, document highlight, and rename support.
|
|
54
|
+
|
|
55
|
+
## Options
|
|
56
|
+
|
|
57
|
+
| Option | Type | Description |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `serverUri` | `ws://...` or `wss://...` | WebSocket server URI |
|
|
60
|
+
| `rootUri` | `string` | Root URI of the workspace |
|
|
61
|
+
| `workspaceFolders` | `WorkspaceFolder[]` | LSP workspace folders |
|
|
62
|
+
| `documentUri` | `string` | URI of the document being edited |
|
|
63
|
+
| `languageId` | `string` | Language identifier ([spec](https://microsoft.github.io/language-server-protocol/specification#textDocumentItem)) |
|
|
64
|
+
| `initializationOptions` | `object` | Server-specific initialization options |
|
|
65
|
+
| `locale` | `string` | Locale for the LSP session (e.g. `'en'`) |
|
|
66
|
+
| `allowHTMLContent` | `boolean` | Trust raw HTML in hover/completion content (default: `false`) |
|
|
67
|
+
| `synchronizationMethod` | `SynchronizationMethod` | `'full'` or `'incremental'` document sync (default: `'full'`) |
|
|
68
|
+
| `client` | `LanguageServerClient` | Share a client across multiple editor instances |
|
|
69
|
+
| `onCapabilities` | `(capabilities) => void` | Called when server capabilities are available |
|
|
70
|
+
| `onError` | `(error: Error) => void` | Called when the connection encounters an error |
|
|
71
|
+
| `onClose` | `() => void` | Called when the connection is closed |
|
|
72
|
+
|
|
73
|
+
## Error Handling
|
|
74
|
+
|
|
75
|
+
The plugin does not crash on connection failures. Use `onError` and `onClose` to handle disconnections:
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
languageServer({
|
|
79
|
+
serverUri: 'ws://localhost:8080',
|
|
80
|
+
rootUri: 'file:///',
|
|
81
|
+
documentUri: `file:///${filename}`,
|
|
82
|
+
languageId: 'cpp',
|
|
83
|
+
onError(error) {
|
|
84
|
+
console.error('LSP error:', error);
|
|
85
|
+
},
|
|
86
|
+
onClose() {
|
|
87
|
+
console.log('LSP connection closed');
|
|
88
|
+
// Recreate the editor extensions to reconnect
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Shared Client
|
|
94
|
+
|
|
95
|
+
To share the same language server connection across multiple editor instances:
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
import { LanguageServerClient, languageServerWithTransport, WebSocketTransport } from 'codemirror-languageserver';
|
|
99
|
+
|
|
100
|
+
const client = new LanguageServerClient({
|
|
101
|
+
transport: new WebSocketTransport('ws://localhost:8080'),
|
|
102
|
+
rootUri: 'file:///',
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Use the same client for multiple editors
|
|
106
|
+
const ls1 = languageServerWithTransport({
|
|
107
|
+
client,
|
|
108
|
+
documentUri: 'file:///main.cpp',
|
|
109
|
+
languageId: 'cpp',
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const ls2 = languageServerWithTransport({
|
|
113
|
+
client,
|
|
114
|
+
documentUri: 'file:///utils.cpp',
|
|
115
|
+
languageId: 'cpp',
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Custom Transport
|
|
57
120
|
|
|
58
|
-
Use `languageServerWithTransport`
|
|
121
|
+
Use `languageServerWithTransport` for non-WebSocket connections:
|
|
59
122
|
|
|
60
123
|
```js
|
|
61
124
|
import { languageServerWithTransport } from 'codemirror-languageserver';
|
|
62
125
|
|
|
63
|
-
|
|
64
|
-
transport: myCustomTransport,
|
|
126
|
+
const ls = languageServerWithTransport({
|
|
127
|
+
transport: myCustomTransport,
|
|
65
128
|
rootUri: 'file:///',
|
|
66
129
|
documentUri: `file:///${filename}`,
|
|
67
130
|
languageId: 'cpp',
|
|
68
131
|
});
|
|
69
132
|
```
|
|
70
133
|
|
|
71
|
-
The `Transport` interface
|
|
134
|
+
The `Transport` interface:
|
|
72
135
|
|
|
73
|
-
|
|
136
|
+
```ts
|
|
137
|
+
interface Transport {
|
|
138
|
+
send(message: string): void;
|
|
139
|
+
onMessage(callback: (message: string) => void): void;
|
|
140
|
+
onClose(callback: () => void): void;
|
|
141
|
+
onError(callback: (error: Error) => void): void;
|
|
142
|
+
close(): void;
|
|
143
|
+
}
|
|
144
|
+
```
|
|
74
145
|
|
|
75
|
-
|
|
146
|
+
You can import `Transport` and `WebSocketTransport` from the package.
|
|
147
|
+
|
|
148
|
+
## Document Highlight
|
|
149
|
+
|
|
150
|
+
Enabled by default. When the cursor is on a symbol, all occurrences in the document are highlighted. Style with CSS:
|
|
76
151
|
|
|
77
152
|
```css
|
|
78
153
|
.cm-lsp-highlight-text,
|
|
@@ -80,21 +155,25 @@ Document highlights are enabled by default. When the cursor is on a symbol, all
|
|
|
80
155
|
.cm-lsp-highlight-write { background-color: rgba(255, 165, 0, 0.3); }
|
|
81
156
|
```
|
|
82
157
|
|
|
83
|
-
|
|
158
|
+
The three classes correspond to [DocumentHighlightKind](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#documentHighlightKind): general text occurrences, read accesses, and write accesses.
|
|
159
|
+
|
|
160
|
+
## Formatting
|
|
84
161
|
|
|
85
|
-
`formatDocument` and `formatSelection` are CodeMirror commands
|
|
162
|
+
`formatDocument` and `formatSelection` are CodeMirror [commands](https://codemirror.net/docs/ref/#view.Command) — bind them to keys:
|
|
86
163
|
|
|
87
164
|
```js
|
|
88
165
|
import { keymap } from '@codemirror/view';
|
|
89
166
|
import { formatDocument, formatSelection } from 'codemirror-languageserver';
|
|
90
167
|
|
|
91
|
-
keymap.of([
|
|
168
|
+
const formattingKeymap = keymap.of([
|
|
92
169
|
{ key: 'Shift-Alt-f', run: formatDocument },
|
|
93
170
|
{ key: 'Ctrl-k Ctrl-f', run: formatSelection },
|
|
94
|
-
])
|
|
171
|
+
]);
|
|
95
172
|
```
|
|
96
173
|
|
|
97
|
-
|
|
174
|
+
### Formatting Options
|
|
175
|
+
|
|
176
|
+
Configure formatting with the `formattingOptions` facet. By default, `tabSize` is read from the editor state.
|
|
98
177
|
|
|
99
178
|
```js
|
|
100
179
|
import { formattingOptions } from 'codemirror-languageserver';
|
|
@@ -105,36 +184,81 @@ formattingOptions.of({
|
|
|
105
184
|
insertSpaces: true,
|
|
106
185
|
trimTrailingWhitespace: true,
|
|
107
186
|
insertFinalNewline: true,
|
|
187
|
+
trimFinalNewlines: true,
|
|
108
188
|
})
|
|
109
189
|
```
|
|
110
190
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
### Rename Symbol
|
|
191
|
+
## Rename Symbol
|
|
114
192
|
|
|
115
|
-
`renameSymbol` is a CodeMirror command that opens a rename prompt at the top of the editor
|
|
193
|
+
`renameSymbol` is a CodeMirror command that opens a rename prompt at the top of the editor. If the server supports `prepareRename`, the current symbol name is used as the placeholder.
|
|
116
194
|
|
|
117
195
|
```js
|
|
118
196
|
import { keymap } from '@codemirror/view';
|
|
119
197
|
import { renameSymbol } from 'codemirror-languageserver';
|
|
120
198
|
|
|
121
|
-
keymap.of([
|
|
199
|
+
const renameKeymap = keymap.of([
|
|
122
200
|
{ key: 'F2', run: renameSymbol },
|
|
123
|
-
])
|
|
201
|
+
]);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Style the panel with CSS:
|
|
205
|
+
|
|
206
|
+
```css
|
|
207
|
+
.cm-lsp-rename-panel {
|
|
208
|
+
padding: 4px 8px;
|
|
209
|
+
border-bottom: 1px solid #ddd;
|
|
210
|
+
}
|
|
211
|
+
.cm-lsp-rename-input {
|
|
212
|
+
font-family: inherit;
|
|
213
|
+
font-size: inherit;
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Server Capabilities
|
|
218
|
+
|
|
219
|
+
Use the `onCapabilities` callback to react when the server finishes initializing — e.g. to show or hide toolbar buttons:
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
languageServer({
|
|
223
|
+
serverUri: 'ws://localhost:8080',
|
|
224
|
+
rootUri: 'file:///',
|
|
225
|
+
documentUri: `file:///${filename}`,
|
|
226
|
+
languageId: 'cpp',
|
|
227
|
+
onCapabilities(capabilities) {
|
|
228
|
+
// capabilities.documentFormattingProvider
|
|
229
|
+
// capabilities.renameProvider
|
|
230
|
+
// capabilities.completionProvider
|
|
231
|
+
// etc.
|
|
232
|
+
toolbar.update({ capabilities });
|
|
233
|
+
},
|
|
234
|
+
})
|
|
124
235
|
```
|
|
125
236
|
|
|
126
|
-
|
|
237
|
+
## Initialization Options
|
|
238
|
+
|
|
239
|
+
The package includes TypeScript definitions for popular language servers:
|
|
127
240
|
|
|
128
|
-
|
|
241
|
+
- `PyrightInitializationOptions` — Python (Pyright)
|
|
242
|
+
- `RustAnalyzerInitializationOptions` — Rust (rust-analyzer)
|
|
243
|
+
- `TypeScriptInitializationOptions` — TypeScript/JavaScript
|
|
244
|
+
- `ESLintInitializationOptions` — ESLint
|
|
245
|
+
- `ClangdInitializationOptions` — C/C++ (Clangd)
|
|
246
|
+
- `GoplsInitializationOptions` — Go (Gopls)
|
|
129
247
|
|
|
130
|
-
|
|
248
|
+
```ts
|
|
249
|
+
import { languageServer } from 'codemirror-languageserver';
|
|
250
|
+
import type { ClangdInitializationOptions } from 'codemirror-languageserver';
|
|
131
251
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
252
|
+
const ls = languageServer<ClangdInitializationOptions>({
|
|
253
|
+
serverUri: 'ws://localhost:8080',
|
|
254
|
+
rootUri: 'file:///',
|
|
255
|
+
documentUri: 'file:///main.cpp',
|
|
256
|
+
languageId: 'cpp',
|
|
257
|
+
initializationOptions: {
|
|
258
|
+
// Type-checked options specific to Clangd
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
```
|
|
138
262
|
|
|
139
263
|
## Contributing
|
|
140
264
|
|
|
@@ -142,7 +266,7 @@ Contributions are welcome.
|
|
|
142
266
|
|
|
143
267
|
## Real World Uses
|
|
144
268
|
|
|
145
|
-
-
|
|
269
|
+
- [Toph](https://toph.co): Competitive programming platform. Toph uses Language Server Plugin for CodeMirror 6 with its integrated code editor.
|
|
146
270
|
|
|
147
271
|
## License
|
|
148
272
|
|
package/dist/definition.d.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import { Command, KeyBinding } from '@codemirror/view';
|
|
2
|
+
/** Command: jump to the definition of the symbol at the cursor. */
|
|
2
3
|
export declare const jumpToDefinition: Command;
|
|
4
|
+
/** Returns a command that jumps to the definition of the symbol at `pos`. */
|
|
3
5
|
export declare const jumpToDefinitionPos: (pos: number) => Command;
|
|
6
|
+
/** Command: jump to the declaration of the symbol at the cursor. */
|
|
4
7
|
export declare const jumpToDeclaration: Command;
|
|
8
|
+
/** Returns a command that jumps to the declaration of the symbol at `pos`. */
|
|
5
9
|
export declare const jumpToDeclarationPos: (pos: number) => Command;
|
|
10
|
+
/** Command: jump to the type definition of the symbol at the cursor. */
|
|
6
11
|
export declare const jumpToTypeDefinition: Command;
|
|
12
|
+
/** Returns a command that jumps to the type definition of the symbol at `pos`. */
|
|
7
13
|
export declare const jumpToTypeDefinitionPos: (pos: number) => Command;
|
|
14
|
+
/**
|
|
15
|
+
* Default keymap for go-to-definition commands.
|
|
16
|
+
*
|
|
17
|
+
* - `F12` — jump to definition
|
|
18
|
+
* - `Mod-F12` — jump to type definition
|
|
19
|
+
*/
|
|
8
20
|
export declare const jumpToDefinitionKeymap: readonly KeyBinding[];
|
package/dist/formatting.d.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { Facet } from '@codemirror/state';
|
|
2
2
|
import type { EditorView } from '@codemirror/view';
|
|
3
3
|
import type * as LSP from 'vscode-languageserver-protocol';
|
|
4
|
+
/**
|
|
5
|
+
* Facet for configuring LSP formatting options (tab size, spaces vs tabs, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Defaults to `{ tabSize: 4, insertSpaces: true }`. The `tabSize` falls back
|
|
8
|
+
* to the editor state's `tabSize` if not explicitly set.
|
|
9
|
+
*/
|
|
4
10
|
export declare const formattingOptions: Facet<LSP.FormattingOptions, LSP.FormattingOptions>;
|
|
11
|
+
/** Command: format the entire document using the language server. */
|
|
5
12
|
export declare function formatDocument(view: EditorView): boolean;
|
|
13
|
+
/** Command: format the current selection using the language server. */
|
|
6
14
|
export declare function formatSelection(view: EditorView): boolean;
|
package/dist/highlight.d.ts
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import { Extension } from '@codemirror/state';
|
|
2
|
+
/**
|
|
3
|
+
* Extension that highlights all occurrences of the symbol under the cursor.
|
|
4
|
+
*
|
|
5
|
+
* Applies CSS classes `cm-lsp-highlight-text`, `cm-lsp-highlight-read`, and
|
|
6
|
+
* `cm-lsp-highlight-write` based on the highlight kind returned by the server.
|
|
7
|
+
*/
|
|
2
8
|
export declare const documentHighlight: () => Extension;
|
package/dist/index.d.ts
CHANGED
|
@@ -16,5 +16,16 @@ interface LanguageServerWebsocketOptions<InitializationOptions = unknown> extend
|
|
|
16
16
|
serverUri: `ws://${string}` | `wss://${string}`;
|
|
17
17
|
initializationOptions?: InitializationOptions;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates a set of CodeMirror extensions that connect to a language server over WebSocket.
|
|
21
|
+
*
|
|
22
|
+
* Includes completion, hover, diagnostics, go-to-definition, document highlight,
|
|
23
|
+
* and rename support. This is the main entry point for most use cases.
|
|
24
|
+
*/
|
|
19
25
|
export declare function languageServer<InitializationOptions = unknown>(options: LanguageServerWebsocketOptions<InitializationOptions>): (import("@codemirror/state").Extension | import("@codemirror/state").StateField<string>)[];
|
|
26
|
+
/**
|
|
27
|
+
* Like {@link languageServer}, but accepts a custom {@link Transport} instead of a WebSocket URI.
|
|
28
|
+
*
|
|
29
|
+
* Use this when communicating with the language server over a non-WebSocket channel.
|
|
30
|
+
*/
|
|
20
31
|
export declare function languageServerWithTransport<InitializationOptions = unknown>(options: LanguageServerOptions<InitializationOptions>): (import("@codemirror/state").Extension | import("@codemirror/state").StateField<string>)[];
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { CompletionItemKind, DiagnosticSeverity, CompletionTriggerKind, Document
|
|
|
5
5
|
import { marked } from 'marked';
|
|
6
6
|
import { autocompletion as autocompletion$1 } from '@codemirror/autocomplete';
|
|
7
7
|
|
|
8
|
+
/** A {@link Transport} that communicates over a browser-native WebSocket. */
|
|
8
9
|
class WebSocketTransport {
|
|
9
10
|
constructor(uri) {
|
|
10
11
|
this.connection = new WebSocket(uri);
|
|
@@ -34,8 +35,10 @@ class JSONRPCClient {
|
|
|
34
35
|
this.nextId = 0;
|
|
35
36
|
this.pending = new Map();
|
|
36
37
|
this.notificationHandlers = [];
|
|
38
|
+
this.errorHandlers = [];
|
|
39
|
+
this.closeHandlers = [];
|
|
37
40
|
this.transport = transport;
|
|
38
|
-
this.ready = new Promise((resolve
|
|
41
|
+
this.ready = new Promise((resolve) => {
|
|
39
42
|
if (transport instanceof WebSocketTransport) {
|
|
40
43
|
const ws = transport.connection;
|
|
41
44
|
if (ws.readyState === WebSocket.OPEN) {
|
|
@@ -43,13 +46,27 @@ class JSONRPCClient {
|
|
|
43
46
|
}
|
|
44
47
|
else {
|
|
45
48
|
ws.addEventListener('open', () => resolve());
|
|
46
|
-
ws.addEventListener('error', () => reject(new Error('WebSocket connection failed')));
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
else {
|
|
50
52
|
resolve();
|
|
51
53
|
}
|
|
52
54
|
});
|
|
55
|
+
transport.onError((error) => {
|
|
56
|
+
for (const handler of this.errorHandlers) {
|
|
57
|
+
handler(error);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
transport.onClose(() => {
|
|
61
|
+
for (const [, pending] of this.pending) {
|
|
62
|
+
clearTimeout(pending.timer);
|
|
63
|
+
pending.reject(new Error('Connection closed'));
|
|
64
|
+
}
|
|
65
|
+
this.pending.clear();
|
|
66
|
+
for (const handler of this.closeHandlers) {
|
|
67
|
+
handler();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
53
70
|
transport.onMessage((raw) => {
|
|
54
71
|
let msg;
|
|
55
72
|
try {
|
|
@@ -106,6 +123,12 @@ class JSONRPCClient {
|
|
|
106
123
|
onNotification(handler) {
|
|
107
124
|
this.notificationHandlers.push(handler);
|
|
108
125
|
}
|
|
126
|
+
onError(handler) {
|
|
127
|
+
this.errorHandlers.push(handler);
|
|
128
|
+
}
|
|
129
|
+
onClose(handler) {
|
|
130
|
+
this.closeHandlers.push(handler);
|
|
131
|
+
}
|
|
109
132
|
close() {
|
|
110
133
|
for (const [id, pending] of this.pending) {
|
|
111
134
|
clearTimeout(pending.timer);
|
|
@@ -164,6 +187,12 @@ Facet.define({
|
|
|
164
187
|
});
|
|
165
188
|
Facet.define({ combine: useLast });
|
|
166
189
|
Facet.define({ combine: useLast });
|
|
190
|
+
/**
|
|
191
|
+
* Manages the JSON-RPC connection to a language server.
|
|
192
|
+
*
|
|
193
|
+
* Handles initialization, request/response routing, and notification dispatch.
|
|
194
|
+
* Can be shared across multiple editor instances via the `client` option.
|
|
195
|
+
*/
|
|
167
196
|
class LanguageServerClient {
|
|
168
197
|
constructor(options) {
|
|
169
198
|
this.options = options;
|
|
@@ -185,7 +214,19 @@ class LanguageServerClient {
|
|
|
185
214
|
}
|
|
186
215
|
this.processNotification(data);
|
|
187
216
|
});
|
|
188
|
-
this.
|
|
217
|
+
this.client.onError((error) => {
|
|
218
|
+
var _a, _b;
|
|
219
|
+
(_b = (_a = this.options).onError) === null || _b === void 0 ? void 0 : _b.call(_a, error);
|
|
220
|
+
});
|
|
221
|
+
this.client.onClose(() => {
|
|
222
|
+
var _a, _b;
|
|
223
|
+
this.ready = false;
|
|
224
|
+
(_b = (_a = this.options).onClose) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
225
|
+
});
|
|
226
|
+
this.initializePromise = this.initialize().catch((error) => {
|
|
227
|
+
var _a, _b;
|
|
228
|
+
(_b = (_a = this.options).onError) === null || _b === void 0 ? void 0 : _b.call(_a, error);
|
|
229
|
+
});
|
|
189
230
|
}
|
|
190
231
|
getInitializeParams() {
|
|
191
232
|
var _a;
|
|
@@ -267,10 +308,12 @@ class LanguageServerClient {
|
|
|
267
308
|
};
|
|
268
309
|
}
|
|
269
310
|
async initialize() {
|
|
311
|
+
var _a, _b;
|
|
270
312
|
const { capabilities } = await this.request('initialize', this.getInitializeParams(), timeout * 3);
|
|
271
313
|
this.capabilities = capabilities;
|
|
272
314
|
this.notify('initialized', {});
|
|
273
315
|
this.ready = true;
|
|
316
|
+
(_b = (_a = this.options).onCapabilities) === null || _b === void 0 ? void 0 : _b.call(_a, capabilities);
|
|
274
317
|
}
|
|
275
318
|
close() {
|
|
276
319
|
this.client.close();
|
|
@@ -339,9 +382,12 @@ class LanguageServerClient {
|
|
|
339
382
|
}
|
|
340
383
|
}
|
|
341
384
|
}
|
|
385
|
+
/** Controls how document changes are sent to the language server. */
|
|
342
386
|
var SynchronizationMethod;
|
|
343
387
|
(function (SynchronizationMethod) {
|
|
388
|
+
/** Send the full document text on every change. */
|
|
344
389
|
SynchronizationMethod["Full"] = "full";
|
|
390
|
+
/** Send only the changed ranges. More efficient for large documents. */
|
|
345
391
|
SynchronizationMethod["Incremental"] = "incremental";
|
|
346
392
|
})(SynchronizationMethod || (SynchronizationMethod = {}));
|
|
347
393
|
class LanguageServerPlugin {
|
|
@@ -735,15 +781,31 @@ function requestTypeDefinition(view, pos) {
|
|
|
735
781
|
plugin.requestTypeDefinition(view, offsetToPos(view.state.doc, pos));
|
|
736
782
|
return true;
|
|
737
783
|
}
|
|
784
|
+
/** Command: jump to the definition of the symbol at the cursor. */
|
|
738
785
|
const jumpToDefinition = (view) => requestDefinition(view, view.state.selection.main.head);
|
|
786
|
+
/** Returns a command that jumps to the definition of the symbol at `pos`. */
|
|
739
787
|
const jumpToDefinitionPos = (pos) => (view) => requestDefinition(view, pos);
|
|
788
|
+
/** Command: jump to the type definition of the symbol at the cursor. */
|
|
740
789
|
const jumpToTypeDefinition = (view) => requestTypeDefinition(view, view.state.selection.main.head);
|
|
790
|
+
/** Returns a command that jumps to the type definition of the symbol at `pos`. */
|
|
741
791
|
const jumpToTypeDefinitionPos = (pos) => (view) => requestTypeDefinition(view, pos);
|
|
792
|
+
/**
|
|
793
|
+
* Default keymap for go-to-definition commands.
|
|
794
|
+
*
|
|
795
|
+
* - `F12` — jump to definition
|
|
796
|
+
* - `Mod-F12` — jump to type definition
|
|
797
|
+
*/
|
|
742
798
|
const jumpToDefinitionKeymap = [
|
|
743
799
|
{ key: 'F12', run: jumpToDefinition, preventDefault: true },
|
|
744
800
|
{ key: 'Mod-F12', run: jumpToTypeDefinition, preventDefault: true },
|
|
745
801
|
];
|
|
746
802
|
|
|
803
|
+
/**
|
|
804
|
+
* Facet for configuring LSP formatting options (tab size, spaces vs tabs, etc.).
|
|
805
|
+
*
|
|
806
|
+
* Defaults to `{ tabSize: 4, insertSpaces: true }`. The `tabSize` falls back
|
|
807
|
+
* to the editor state's `tabSize` if not explicitly set.
|
|
808
|
+
*/
|
|
747
809
|
const formattingOptions = Facet.define({
|
|
748
810
|
combine(values) {
|
|
749
811
|
return Object.assign({ tabSize: 4, insertSpaces: true }, ...values);
|
|
@@ -765,6 +827,7 @@ function applyTextEdits(view, edits) {
|
|
|
765
827
|
}));
|
|
766
828
|
view.dispatch(view.state.update({ changes }));
|
|
767
829
|
}
|
|
830
|
+
/** Command: format the entire document using the language server. */
|
|
768
831
|
function formatDocument(view) {
|
|
769
832
|
var _a;
|
|
770
833
|
const plugin = view.plugin(languageServerPlugin);
|
|
@@ -786,6 +849,7 @@ function formatDocument(view) {
|
|
|
786
849
|
});
|
|
787
850
|
return true;
|
|
788
851
|
}
|
|
852
|
+
/** Command: format the current selection using the language server. */
|
|
789
853
|
function formatSelection(view) {
|
|
790
854
|
var _a;
|
|
791
855
|
const plugin = view.plugin(languageServerPlugin);
|
|
@@ -920,6 +984,12 @@ async function performRename(view, newName) {
|
|
|
920
984
|
applyWorkspaceEdit(view, result);
|
|
921
985
|
}
|
|
922
986
|
}
|
|
987
|
+
/**
|
|
988
|
+
* Command: open a rename prompt for the symbol at the cursor.
|
|
989
|
+
*
|
|
990
|
+
* Uses `textDocument/prepareRename` to pre-fill the current name if supported
|
|
991
|
+
* by the server. Press Enter to confirm or Escape to cancel.
|
|
992
|
+
*/
|
|
923
993
|
function renameSymbol(view) {
|
|
924
994
|
var _a;
|
|
925
995
|
const plugin = view.plugin(languageServerPlugin);
|
|
@@ -1088,6 +1158,12 @@ const highlightPlugin = ViewPlugin.fromClass(class {
|
|
|
1088
1158
|
clearTimeout(this.pending);
|
|
1089
1159
|
}
|
|
1090
1160
|
});
|
|
1161
|
+
/**
|
|
1162
|
+
* Extension that highlights all occurrences of the symbol under the cursor.
|
|
1163
|
+
*
|
|
1164
|
+
* Applies CSS classes `cm-lsp-highlight-text`, `cm-lsp-highlight-read`, and
|
|
1165
|
+
* `cm-lsp-highlight-write` based on the highlight kind returned by the server.
|
|
1166
|
+
*/
|
|
1091
1167
|
const documentHighlight = () => [
|
|
1092
1168
|
highlightField,
|
|
1093
1169
|
highlightPlugin,
|
|
@@ -1109,6 +1185,12 @@ const mouseHandler = () => EditorView.domEventHandlers({
|
|
|
1109
1185
|
},
|
|
1110
1186
|
});
|
|
1111
1187
|
|
|
1188
|
+
/**
|
|
1189
|
+
* Creates a set of CodeMirror extensions that connect to a language server over WebSocket.
|
|
1190
|
+
*
|
|
1191
|
+
* Includes completion, hover, diagnostics, go-to-definition, document highlight,
|
|
1192
|
+
* and rename support. This is the main entry point for most use cases.
|
|
1193
|
+
*/
|
|
1112
1194
|
function languageServer(options) {
|
|
1113
1195
|
const serverUri = options.serverUri;
|
|
1114
1196
|
const { serverUri: _, ...optionsWithoutServerUri } = options;
|
|
@@ -1117,6 +1199,11 @@ function languageServer(options) {
|
|
|
1117
1199
|
transport: new WebSocketTransport(serverUri),
|
|
1118
1200
|
});
|
|
1119
1201
|
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Like {@link languageServer}, but accepts a custom {@link Transport} instead of a WebSocket URI.
|
|
1204
|
+
*
|
|
1205
|
+
* Use this when communicating with the language server over a non-WebSocket channel.
|
|
1206
|
+
*/
|
|
1120
1207
|
function languageServerWithTransport(options) {
|
|
1121
1208
|
return [
|
|
1122
1209
|
languageServerPlugin.of({
|
package/dist/jsonrpc.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for sending and receiving JSON-RPC messages.
|
|
3
|
+
*
|
|
4
|
+
* Implement this to use a custom communication channel (e.g. Web Workers,
|
|
5
|
+
* MessagePort, or HTTP). See {@link WebSocketTransport} for a reference
|
|
6
|
+
* implementation.
|
|
7
|
+
*/
|
|
1
8
|
export interface Transport {
|
|
2
9
|
send(message: string): void;
|
|
3
10
|
onMessage(callback: (message: string) => void): void;
|
|
@@ -5,6 +12,7 @@ export interface Transport {
|
|
|
5
12
|
onError(callback: (error: Error) => void): void;
|
|
6
13
|
close(): void;
|
|
7
14
|
}
|
|
15
|
+
/** A {@link Transport} that communicates over a browser-native WebSocket. */
|
|
8
16
|
export declare class WebSocketTransport implements Transport {
|
|
9
17
|
connection: WebSocket;
|
|
10
18
|
constructor(uri: string);
|
|
@@ -19,6 +27,8 @@ export declare class JSONRPCClient {
|
|
|
19
27
|
private nextId;
|
|
20
28
|
private pending;
|
|
21
29
|
private notificationHandlers;
|
|
30
|
+
private errorHandlers;
|
|
31
|
+
private closeHandlers;
|
|
22
32
|
private ready;
|
|
23
33
|
constructor(transport: Transport);
|
|
24
34
|
request(req: {
|
|
@@ -30,5 +40,7 @@ export declare class JSONRPCClient {
|
|
|
30
40
|
params: any;
|
|
31
41
|
}): Promise<void>;
|
|
32
42
|
onNotification(handler: (data: any) => void): void;
|
|
43
|
+
onError(handler: (error: Error) => void): void;
|
|
44
|
+
onClose(handler: () => void): void;
|
|
33
45
|
close(): void;
|
|
34
46
|
}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -67,8 +67,16 @@ interface LanguageServerClientLocationMethods {
|
|
|
67
67
|
textDocumentDeclaration(params: LSP.DeclarationParams): LSP.Location | LSP.Location[] | LSP.LocationLink[] | null;
|
|
68
68
|
textDocumentTypeDefinition(params: LSP.TypeDefinitionParams): LSP.Location | LSP.Location[] | LSP.LocationLink[] | null;
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Manages the JSON-RPC connection to a language server.
|
|
72
|
+
*
|
|
73
|
+
* Handles initialization, request/response routing, and notification dispatch.
|
|
74
|
+
* Can be shared across multiple editor instances via the `client` option.
|
|
75
|
+
*/
|
|
70
76
|
export declare class LanguageServerClient<InitializationOptions = unknown> {
|
|
77
|
+
/** Whether the server has finished initializing. */
|
|
71
78
|
ready: boolean;
|
|
79
|
+
/** The server's capabilities, available after initialization. */
|
|
72
80
|
capabilities: LSP.ServerCapabilities<any>;
|
|
73
81
|
initializePromise: Promise<void>;
|
|
74
82
|
private rootUri;
|
|
@@ -104,8 +112,11 @@ export declare class LanguageServerClient<InitializationOptions = unknown> {
|
|
|
104
112
|
protected notify<K extends keyof LSPNotifyMap>(method: K, params: LSPNotifyMap[K]): Promise<void>;
|
|
105
113
|
protected processNotification(notification: Notification): void;
|
|
106
114
|
}
|
|
115
|
+
/** Controls how document changes are sent to the language server. */
|
|
107
116
|
export declare enum SynchronizationMethod {
|
|
117
|
+
/** Send the full document text on every change. */
|
|
108
118
|
Full = "full",
|
|
119
|
+
/** Send only the changed ranges. More efficient for large documents. */
|
|
109
120
|
Incremental = "incremental"
|
|
110
121
|
}
|
|
111
122
|
export declare class LanguageServerPlugin implements PluginValue {
|
|
@@ -181,16 +192,32 @@ export declare const languageServerPlugin: ViewPlugin<LanguageServerPlugin, {
|
|
|
181
192
|
allowHTMLContent: boolean;
|
|
182
193
|
synchronizationMethod: SynchronizationMethod;
|
|
183
194
|
}>;
|
|
195
|
+
/** Base options shared by all language server configurations. */
|
|
184
196
|
export interface LanguageServerBaseOptions {
|
|
197
|
+
/** Root URI of the workspace (e.g. `'file:///'`). */
|
|
185
198
|
rootUri: string | null;
|
|
199
|
+
/** LSP workspace folders, if applicable. */
|
|
186
200
|
workspaceFolders: LSP.WorkspaceFolder[] | null;
|
|
201
|
+
/** URI of the document being edited (e.g. `'file:///main.cpp'`). */
|
|
187
202
|
documentUri: string;
|
|
203
|
+
/** Language identifier as defined by the LSP specification. */
|
|
188
204
|
languageId: string;
|
|
189
205
|
}
|
|
206
|
+
/** Options for creating a {@link LanguageServerClient}. */
|
|
190
207
|
export interface LanguageServerClientOptions<InitializationOptions = unknown> extends LanguageServerBaseOptions {
|
|
208
|
+
/** The transport used to communicate with the language server. */
|
|
191
209
|
transport: Transport;
|
|
210
|
+
/** Close the transport when the last plugin detaches. */
|
|
192
211
|
autoClose?: boolean;
|
|
212
|
+
/** Server-specific initialization options. */
|
|
193
213
|
initializationOptions?: InitializationOptions;
|
|
214
|
+
/** Locale for the LSP session (e.g. `'en'`). Sent in the `initialize` request. */
|
|
194
215
|
locale?: string;
|
|
216
|
+
/** Called once after initialization with the server's capabilities. */
|
|
217
|
+
onCapabilities?: (capabilities: LSP.ServerCapabilities) => void;
|
|
218
|
+
/** Called when the connection encounters an error. */
|
|
219
|
+
onError?: (error: Error) => void;
|
|
220
|
+
/** Called when the connection is closed. */
|
|
221
|
+
onClose?: () => void;
|
|
195
222
|
}
|
|
196
223
|
export {};
|
package/dist/rename.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { StateField } from '@codemirror/state';
|
|
2
2
|
import { EditorView } from '@codemirror/view';
|
|
3
|
+
/**
|
|
4
|
+
* Command: open a rename prompt for the symbol at the cursor.
|
|
5
|
+
*
|
|
6
|
+
* Uses `textDocument/prepareRename` to pre-fill the current name if supported
|
|
7
|
+
* by the server. Press Enter to confirm or Escape to cancel.
|
|
8
|
+
*/
|
|
3
9
|
export declare function renameSymbol(view: EditorView): boolean;
|
|
4
10
|
export declare const renameExtension: () => StateField<string>;
|