@hydranium/client-browser 1.0.0-next.303 → 1.0.0-next.305
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 +63 -14
- package/lib/language-client.d.ts +1 -1
- package/lib/language-client.d.ts.map +1 -1
- package/lib/language-client.js +6 -2
- package/lib/language-client.js.map +1 -1
- package/lib/monaco/index.d.ts +10 -0
- package/lib/monaco/index.d.ts.map +1 -0
- package/lib/monaco/index.js +29 -0
- package/lib/monaco/index.js.map +1 -0
- package/lib/monaco/monaco-lsp-client.d.ts +495 -0
- package/lib/monaco/monaco-lsp-client.d.ts.map +1 -0
- package/lib/monaco/monaco-lsp-client.js +1277 -0
- package/lib/monaco/monaco-lsp-client.js.map +1 -0
- package/package.json +17 -4
- package/src/language-client.ts +6 -3
- package/src/monaco/index.ts +13 -0
- package/src/monaco/monaco-lsp-client.ts +1462 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the MIT License which is available in the project root.
|
|
6
|
+
*
|
|
7
|
+
* SPDX-License-Identifier: MIT
|
|
8
|
+
********************************************************************************/
|
|
9
|
+
/**
|
|
10
|
+
* The client half of the LSP head for a Monaco editor, over the connection the
|
|
11
|
+
* page already holds for the head.
|
|
12
|
+
*
|
|
13
|
+
* Hand-written rather than `monaco-languageclient`, which drags in the
|
|
14
|
+
* `@codingame/monaco-vscode-*` shim stack: at `platform: 'browser'` a bundler
|
|
15
|
+
* refuses a `node:*` builtin rather than shimming it, and that refusal is what
|
|
16
|
+
* keeps a page bundle a neutrality gate over the head composition it carries.
|
|
17
|
+
*
|
|
18
|
+
* A Theia or VS Code integration hands `vscode-languageclient` a document
|
|
19
|
+
* store, a marker service and a provider registry. Here Monaco is all three,
|
|
20
|
+
* and the three translations between it and LSP are the whole of the work:
|
|
21
|
+
*
|
|
22
|
+
* - **Identity.** A Monaco model URI must be string-identical to the LSP URI, or
|
|
23
|
+
* `publishDiagnostics` addresses a document Monaco does not have and the
|
|
24
|
+
* markers land nowhere, silently.
|
|
25
|
+
* - **Coordinates.** LSP lines and characters are 0-based; Monaco lines and
|
|
26
|
+
* columns are 1-based. Every range crossing this file is converted.
|
|
27
|
+
* - **Versions.** Monaco's `versionId` is monotonic per model, which is exactly
|
|
28
|
+
* what the server's text store wants for its stale-write gate, so it is used
|
|
29
|
+
* directly rather than counted here in parallel.
|
|
30
|
+
*/
|
|
31
|
+
import { type BaseVersion, type TextState } from '@hydranium/protocol';
|
|
32
|
+
import * as monaco from 'monaco-editor-core';
|
|
33
|
+
import { type MessageConnection } from 'vscode-jsonrpc/browser';
|
|
34
|
+
import { type AnnotatedTextEdit, type ApplyWorkspaceEditResult, type ClientCapabilities, type PublishDiagnosticsParams, type ServerCapabilities, SnippetTextEdit, type TextEdit, type WorkspaceEdit } from 'vscode-languageserver-protocol';
|
|
35
|
+
export interface MonacoLspClientOptions {
|
|
36
|
+
/**
|
|
37
|
+
* The languages the server speaks, as Monaco registers them. A document is
|
|
38
|
+
* routed to the first entry whose `extensions` its URI ends with, and that
|
|
39
|
+
* id is the `languageId` on `didOpen`, which the server routes the document
|
|
40
|
+
* to a grammar by. No entry means the open throws rather than guessing: a
|
|
41
|
+
* document parsed by the wrong grammar reports a page of syntax errors that
|
|
42
|
+
* read as the file being broken.
|
|
43
|
+
*/
|
|
44
|
+
readonly languages: readonly monaco.languages.ILanguageExtensionPoint[];
|
|
45
|
+
/** The owner of the markers this client sets, which a host reads them back by; {@link DEFAULT_MARKER_OWNER} by default. */
|
|
46
|
+
readonly markerOwner?: string;
|
|
47
|
+
}
|
|
48
|
+
/** The marker owner a client sets diagnostics under when its options name none. */
|
|
49
|
+
export declare const DEFAULT_MARKER_OWNER = "lsp";
|
|
50
|
+
/**
|
|
51
|
+
* The client capabilities for a host whose editor is a {@link MonacoLspClient},
|
|
52
|
+
* to pass as `initializeLanguageClient`'s `capabilities`: the two workspace
|
|
53
|
+
* answers of the default, plus every form the client renders, so a server that
|
|
54
|
+
* gates a form on its capability sends it. Multi-line semantic tokens stay
|
|
55
|
+
* undeclared, since Monaco cannot render one, and Langium then splits them
|
|
56
|
+
* per line. Frozen: a host that declares more spreads it.
|
|
57
|
+
*/
|
|
58
|
+
export declare const MONACO_CLIENT_CAPABILITIES: ClientCapabilities;
|
|
59
|
+
/** One document's worth of an inbound workspace edit, ready to push into Monaco. */
|
|
60
|
+
export interface ResolvedDocumentEdit {
|
|
61
|
+
readonly model: monaco.editor.ITextModel;
|
|
62
|
+
readonly operations: readonly monaco.editor.IIdentifiedSingleEditOperation[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Whether one document's worth of an inbound workspace edit can be applied, and
|
|
66
|
+
* if not, what to tell the server.
|
|
67
|
+
*
|
|
68
|
+
* A REASON rather than a bare `false`, because the reason travels: it becomes
|
|
69
|
+
* `ApplyWorkspaceEditResult.failureReason`, which is the only thing the server
|
|
70
|
+
* learns about a refusal beyond the fact of it.
|
|
71
|
+
*/
|
|
72
|
+
export type EditResolution = {
|
|
73
|
+
readonly applicable: true;
|
|
74
|
+
readonly edit: ResolvedDocumentEdit;
|
|
75
|
+
} | {
|
|
76
|
+
readonly applicable: false;
|
|
77
|
+
readonly reason: string;
|
|
78
|
+
};
|
|
79
|
+
/** One open document's content and the buffer version that content was read at. */
|
|
80
|
+
export interface EditorDocument {
|
|
81
|
+
/**
|
|
82
|
+
* Monaco's form of the URI, as the server knows the document: a host
|
|
83
|
+
* compares it with `Uri.parse(uri).toString()` of its own, since a space or
|
|
84
|
+
* a drive-letter colon is encoded here and not in the string it opened with.
|
|
85
|
+
*/
|
|
86
|
+
readonly uri: string;
|
|
87
|
+
readonly text: string;
|
|
88
|
+
readonly version: number;
|
|
89
|
+
/** The model the text was read from: a reopened URI is a new model, and a record of the old one marks nothing. */
|
|
90
|
+
readonly model: monaco.editor.ITextModel;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Registers the server's languages with Monaco and keeps its models in step
|
|
94
|
+
* with the LSP head on the other end of `connection`.
|
|
95
|
+
*
|
|
96
|
+
* Construction registers the languages, the providers and the inbound
|
|
97
|
+
* `workspace/applyEdit` handler; {@link openDocument} opens one document and
|
|
98
|
+
* {@link closeDocument} closes it; {@link dispose} closes every document and
|
|
99
|
+
* releases every registration. Diagnostics are NOT subscribed here — see
|
|
100
|
+
* {@link applyDiagnostics}.
|
|
101
|
+
*/
|
|
102
|
+
export declare class MonacoLspClient {
|
|
103
|
+
protected readonly options: MonacoLspClientOptions;
|
|
104
|
+
/**
|
|
105
|
+
* The models this client opened, by URI in Monaco's form. Every inbound
|
|
106
|
+
* edit, diagnostic and dirty read goes through this map rather than
|
|
107
|
+
* Monaco's global lookup: a page may hold a second client, and a model
|
|
108
|
+
* that client holds is not this one's to write, mark or save, however
|
|
109
|
+
* its URI reads.
|
|
110
|
+
*/
|
|
111
|
+
protected readonly models: Map<string, monaco.editor.ITextModel>;
|
|
112
|
+
/** Per URI, the buffer version last known to be persisted. */
|
|
113
|
+
protected readonly savedVersions: Map<string, number>;
|
|
114
|
+
/** Everything construction and {@link registerEditorOpener} registered, released in reverse by {@link dispose}. */
|
|
115
|
+
protected readonly registrations: monaco.IDisposable[];
|
|
116
|
+
protected readonly markerOwner: string;
|
|
117
|
+
/**
|
|
118
|
+
* The host's connection, sending by method name: the LSP message types come
|
|
119
|
+
* from `vscode-languageserver-protocol`'s copy of `vscode-jsonrpc`, which
|
|
120
|
+
* need not be the connection's.
|
|
121
|
+
*/
|
|
122
|
+
protected readonly connection: MessageConnection;
|
|
123
|
+
constructor(connection: MessageConnection, capabilities: ServerCapabilities, options: MonacoLspClientOptions);
|
|
124
|
+
/**
|
|
125
|
+
* The language id for `uri`, by the extensions the options name.
|
|
126
|
+
*
|
|
127
|
+
* Throws rather than falling back to a default id. An unknown extension means
|
|
128
|
+
* the host named a document the server has no grammar for, and the failure of
|
|
129
|
+
* the guessing version is that the document opens, parses as the wrong
|
|
130
|
+
* language and reports a page of syntax errors that look like the file being
|
|
131
|
+
* broken.
|
|
132
|
+
*/
|
|
133
|
+
protected languageIdFor(uri: string): string;
|
|
134
|
+
/**
|
|
135
|
+
* Apply one `publishDiagnostics` notification to the model it addresses.
|
|
136
|
+
*
|
|
137
|
+
* **Called by the host's single notification handler rather than subscribing
|
|
138
|
+
* here, and that is forced rather than stylistic.**
|
|
139
|
+
* `MessageConnection.onNotification` stores handlers in a map keyed by method,
|
|
140
|
+
* so a second registration for `textDocument/publishDiagnostics` REPLACES the
|
|
141
|
+
* first and returns a disposable as though it had worked. A host with a
|
|
142
|
+
* handler for its own diagnostics view would have it taken over by a client
|
|
143
|
+
* that registered its own, and its view would freeze at whatever it had
|
|
144
|
+
* reached — with nothing on the console to say so.
|
|
145
|
+
*
|
|
146
|
+
* A URI with no model of this client's is not an error: a workspace has more
|
|
147
|
+
* documents than the host opens, so most publishes address a file Monaco
|
|
148
|
+
* has never heard of, and a model another client holds is that client's.
|
|
149
|
+
*/
|
|
150
|
+
applyDiagnostics(params: PublishDiagnosticsParams): void;
|
|
151
|
+
/**
|
|
152
|
+
* Answer `workspace/applyEdit` — the server→text direction, and the half of
|
|
153
|
+
* the sync a client that only sends `didOpen` silently loses.
|
|
154
|
+
*
|
|
155
|
+
* A server-side write (a diagram drag, a form edit, an integrity repair) goes
|
|
156
|
+
* through the framework's `ModelService`, which rewrites the in-memory text
|
|
157
|
+
* document and then mirrors the settled text to whichever client holds it
|
|
158
|
+
* open, as a MINIMAL `workspace/applyEdit` computed against a shadow of that
|
|
159
|
+
* client's buffer. So the request goes out on every such write the moment the
|
|
160
|
+
* host opens a document — and a client with no handler makes
|
|
161
|
+
* `vscode-jsonrpc` answer `MethodNotFound`, which the framework logs through
|
|
162
|
+
* its tracer and therefore onto `window/logMessage`. A host that has no
|
|
163
|
+
* handler for that either loses the whole inbound direction with nothing on
|
|
164
|
+
* the console, in the editor or in the server's own report to say so.
|
|
165
|
+
*
|
|
166
|
+
* **Registered here rather than by the host, unlike `publishDiagnostics`.**
|
|
167
|
+
* `onRequest` keys handlers by method exactly as `onNotification` does, so a
|
|
168
|
+
* second registration would silently replace this one — but nothing else
|
|
169
|
+
* answers `workspace/applyEdit`, so there is no fan-out to arbitrate, and the
|
|
170
|
+
* handler needs the model store, which is this class's business.
|
|
171
|
+
*
|
|
172
|
+
* **The framework does not gate this on a client capability.**
|
|
173
|
+
* `HydraniumTextDocuments.applyEditToLanguageClient` checks that an LSP
|
|
174
|
+
* connection is bound and that the client has the document open, never a
|
|
175
|
+
* capability, and `vscode-languageserver`'s own
|
|
176
|
+
* `RemoteWorkspaceImpl.applyEdit` forwards unconditionally — so declaring
|
|
177
|
+
* `workspace.applyEdit` in `initialize` does not turn the request on and
|
|
178
|
+
* omitting it does not turn it off.
|
|
179
|
+
*
|
|
180
|
+
* **The echo does not LOOP, and is deliberately not suppressed here.**
|
|
181
|
+
* Applying the edit makes Monaco fire `onDidChangeContent`, which
|
|
182
|
+
* {@link openDocument} turns into a `didChange`. The server answers that
|
|
183
|
+
* echo with no push of its own, so nothing ping-pongs.
|
|
184
|
+
* The server correlates that `didChange` against the push still in flight
|
|
185
|
+
* and reconstructs it against the buffer this client held BEFORE the push —
|
|
186
|
+
* which is the only text its incremental ranges address — so an echo mints
|
|
187
|
+
* no version and drives no rebuild.
|
|
188
|
+
*
|
|
189
|
+
* Suppressing it would break what that correlation runs on: `didChange` is
|
|
190
|
+
* what keeps the server's per-URI shadow and its per-client version aligned
|
|
191
|
+
* with this buffer, so withholding it makes the next outbound diff wrong and
|
|
192
|
+
* makes every versioned push arrive stale. A conforming client echoes.
|
|
193
|
+
*
|
|
194
|
+
* **This client echoes the ranges it was handed, and a server must not assume
|
|
195
|
+
* that.** A host is free to minimise a coarse edit against its own buffer
|
|
196
|
+
* before applying it — Theia routes every workspace edit through
|
|
197
|
+
* `computeMoreMinimalEdits` — so the echo of a single full-document replace
|
|
198
|
+
* can arrive as a set of small ranges keyed to text the server never sent.
|
|
199
|
+
*/
|
|
200
|
+
protected registerApplyEdit(): void;
|
|
201
|
+
/**
|
|
202
|
+
* Apply `edit` to the models it addresses, or refuse all of it.
|
|
203
|
+
*
|
|
204
|
+
* **Every target is resolved before any is written.** An LSP workspace edit
|
|
205
|
+
* is a unit — `failureHandling` exists precisely because a partially applied
|
|
206
|
+
* one leaves the workspace in a state no participant described — and here the
|
|
207
|
+
* server's text shadow is what would carry the damage: it tracks one text per
|
|
208
|
+
* URI, so a half-applied multi-document edit desynchronises the untouched
|
|
209
|
+
* half's baseline and every later minimal diff for it addresses the wrong
|
|
210
|
+
* lines.
|
|
211
|
+
*
|
|
212
|
+
* The framework's own egress never exercises that: it sends a write that
|
|
213
|
+
* touches two documents as two requests of one `TextDocumentEdit` each,
|
|
214
|
+
* because `applyEditToLanguageClient` is per-URI and coalesced per-URI.
|
|
215
|
+
* The loop is therefore for an adopter's server that batches, and the
|
|
216
|
+
* all-or-nothing shape is what keeps this client honest for one.
|
|
217
|
+
*/
|
|
218
|
+
protected applyWorkspaceEdit(edit: WorkspaceEdit): ApplyWorkspaceEditResult;
|
|
219
|
+
/**
|
|
220
|
+
* Resolve one document's worth of an inbound edit against the model it names.
|
|
221
|
+
*
|
|
222
|
+
* Refuses, rather than dropping quietly, in three cases:
|
|
223
|
+
*
|
|
224
|
+
* - **No model for the URI.** `applied: true` for an edit that went nowhere
|
|
225
|
+
* would leave the server's shadow believing this client holds text it does
|
|
226
|
+
* not, and every later minimal diff for that URI would be computed against
|
|
227
|
+
* the wrong baseline. The framework pushes only to documents the language
|
|
228
|
+
* client has opened, and stages or keeps in the store a write to any
|
|
229
|
+
* other, so this branch should stay unreached — it exists so that if it is
|
|
230
|
+
* ever reached the failure is loud rather than a slow desynchronisation.
|
|
231
|
+
* - **A stale version.** The framework addresses a position-dependent
|
|
232
|
+
* (line-keyed) push at its last known version of this buffer, precisely so
|
|
233
|
+
* the client can refuse a push its buffer has outrun: applying a stale
|
|
234
|
+
* range does not fail, it splices the file at the wrong lines. Refusing is
|
|
235
|
+
* not a dead branch — `ModelService` re-pushes a full-range replace on
|
|
236
|
+
* `applied: false`, which is position-independent and therefore correct
|
|
237
|
+
* against whatever the buffer now holds. That retry arrives with
|
|
238
|
+
* `version: null` and passes this gate by construction.
|
|
239
|
+
* - **A snippet edit.** Monaco applies snippets through a controller rather
|
|
240
|
+
* than through the model, so a `SnippetTextEdit` pushed as text would
|
|
241
|
+
* insert its placeholder syntax literally.
|
|
242
|
+
*/
|
|
243
|
+
protected resolveDocumentEdit(uri: string, version: number | null, edits: readonly (TextEdit | AnnotatedTextEdit | SnippetTextEdit)[]): EditResolution;
|
|
244
|
+
/**
|
|
245
|
+
* Create a model for `uri` holding `text`, and tell the server the document is
|
|
246
|
+
* open. Returns the model this client already holds for the URI; a model
|
|
247
|
+
* another client of this page holds is refused, since this client would
|
|
248
|
+
* neither announce it nor send its changes.
|
|
249
|
+
*
|
|
250
|
+
* **`text` must be the bytes the server already has.** A browser host takes
|
|
251
|
+
* it from the worker's own filesystem, so `didOpen` carries what the heads
|
|
252
|
+
* came up on. Inventing placeholder text would not fail — it would
|
|
253
|
+
* OVERWRITE the server's copy through the text-document store and quietly
|
|
254
|
+
* change the diagnostics the server reports.
|
|
255
|
+
*
|
|
256
|
+
* `didOpen` carries the model's text rather than `text` itself: Monaco drops
|
|
257
|
+
* a BOM and rewrites mixed line endings to the majority form when it builds
|
|
258
|
+
* the model, as any editor does, and a server holding the bytes instead
|
|
259
|
+
* would be one character off every position and never match the buffer a
|
|
260
|
+
* save compares it with.
|
|
261
|
+
*
|
|
262
|
+
* Which is also why the second call for a URI is a no-op rather than a
|
|
263
|
+
* refresh: by then the buffer may hold a server write the snapshot never had,
|
|
264
|
+
* and the snapshot is the older claim.
|
|
265
|
+
*
|
|
266
|
+
* The URI is sent in Monaco's form: `Uri.parse(uri).toString()` encodes a
|
|
267
|
+
* space or a drive-letter colon, and the providers name the document by the
|
|
268
|
+
* model's URI, so a `didOpen` with the host's string would open a document
|
|
269
|
+
* no provider request ever addresses.
|
|
270
|
+
*/
|
|
271
|
+
openDocument(uri: string, text: string): monaco.editor.ITextModel;
|
|
272
|
+
/**
|
|
273
|
+
* Dispose the model for `uri` and tell the server the document is closed, so
|
|
274
|
+
* the server drops this client's shadow of it and stops pushing to it. A URI
|
|
275
|
+
* this client never opened is left alone. An editor still showing the model
|
|
276
|
+
* is the host's to re-point first: Monaco detaches a disposed model from it.
|
|
277
|
+
* A model the host disposed itself is closed on the server all the same,
|
|
278
|
+
* here or by the next {@link openDocument} of its URI.
|
|
279
|
+
*
|
|
280
|
+
* The markers go first: Monaco drops a disposed model's markers only for its
|
|
281
|
+
* own schemes, so a `file:` document reopened later would start with the
|
|
282
|
+
* squiggles the server published before the close.
|
|
283
|
+
*
|
|
284
|
+
* The model goes before `didClose`, and a connection already closed does not
|
|
285
|
+
* fail the call: the page's side of the sync is this client's to release
|
|
286
|
+
* whatever became of the worker, and the server's side ends with its
|
|
287
|
+
* connection.
|
|
288
|
+
*/
|
|
289
|
+
closeDocument(uri: string): void;
|
|
290
|
+
/**
|
|
291
|
+
* Close every open document and release every registration, in reverse
|
|
292
|
+
* order, the `workspace/applyEdit` handler included: a later request is
|
|
293
|
+
* answered as an unknown method, as for a client that never registered.
|
|
294
|
+
* The languages stay registered, since Monaco cannot unregister one.
|
|
295
|
+
*/
|
|
296
|
+
dispose(): void;
|
|
297
|
+
/**
|
|
298
|
+
* Create one editor over `model`, with the settings a server-driven language
|
|
299
|
+
* needs under `options`: the host's theme, layout and chrome spread over
|
|
300
|
+
* them, so a host cannot lose one by spreading in the wrong order.
|
|
301
|
+
*
|
|
302
|
+
* Separate from {@link openDocument} because a host may hold a FIXED number
|
|
303
|
+
* of editors and swap their models rather than create an editor per
|
|
304
|
+
* document. That is what keeps a `didOpen` a statement about the workspace
|
|
305
|
+
* instead of about which pane happens to be showing what.
|
|
306
|
+
*
|
|
307
|
+
* `suggest` is merged one level deep: it is the one nested setting here, and
|
|
308
|
+
* a host's own suggest options would otherwise replace the insert mode the
|
|
309
|
+
* forwarded `InsertReplaceEdit` ranges depend on.
|
|
310
|
+
*/
|
|
311
|
+
createEditor(container: HTMLElement, model: monaco.editor.ITextModel, options?: monaco.editor.IStandaloneEditorConstructionOptions): monaco.editor.IStandaloneCodeEditor;
|
|
312
|
+
/**
|
|
313
|
+
* The open documents whose buffer has moved since it was opened or last
|
|
314
|
+
* saved, with the text to persist.
|
|
315
|
+
*
|
|
316
|
+
* **The editor's buffer is the right source for a save**, not the host's copy
|
|
317
|
+
* of the workspace: a server write reaches this buffer through
|
|
318
|
+
* `workspace/applyEdit`, so Monaco's model is the one place both directions of
|
|
319
|
+
* the sync are already merged.
|
|
320
|
+
*
|
|
321
|
+
* **Dirty rather than every open document, and that is not cosmetic.** A save
|
|
322
|
+
* of an unmodified file writes its current bytes into the backing store, and
|
|
323
|
+
* a store that wins over a seed on the next load would then pin a file nobody
|
|
324
|
+
* changed.
|
|
325
|
+
*
|
|
326
|
+
* `getAlternativeVersionId` rather than `getVersionId`, because it is the one
|
|
327
|
+
* that returns to its old value when an edit is UNDONE — undoing a server
|
|
328
|
+
* write leaves nothing to save, which `getVersionId` (monotonic) would report
|
|
329
|
+
* as a change.
|
|
330
|
+
*/
|
|
331
|
+
dirtyDocuments(): EditorDocument[];
|
|
332
|
+
/**
|
|
333
|
+
* The document at `uri`, in any form, if it has unsaved changes, read from
|
|
334
|
+
* its model alone; nothing for a document that is saved or that this client
|
|
335
|
+
* does not hold.
|
|
336
|
+
*/
|
|
337
|
+
dirtyDocument(uri: string): EditorDocument | undefined;
|
|
338
|
+
/** The model this client holds for a URI in any form, if it still exists. */
|
|
339
|
+
protected modelOf(uri: string): monaco.editor.ITextModel | undefined;
|
|
340
|
+
/**
|
|
341
|
+
* Run one provider's request. A request nobody wants an answer to any more,
|
|
342
|
+
* since the server gave it up or the connection closed, rejects with
|
|
343
|
+
* Monaco's cancellation, which Monaco drops silently. Any other rejection
|
|
344
|
+
* reaches Monaco, which reports it as an uncaught page error.
|
|
345
|
+
*/
|
|
346
|
+
protected request<R>(send: () => Promise<R>): Promise<R>;
|
|
347
|
+
/**
|
|
348
|
+
* Whether `model` is one this client opened. Monaco picks a provider by
|
|
349
|
+
* language id, so a second client of the same language is handed this
|
|
350
|
+
* client's models and this client the other's; a request for one of those
|
|
351
|
+
* would name a document this client's server never opened.
|
|
352
|
+
*/
|
|
353
|
+
protected owns(model: monaco.editor.ITextModel): boolean;
|
|
354
|
+
/**
|
|
355
|
+
* Record that `document`'s content has been persisted.
|
|
356
|
+
*
|
|
357
|
+
* Takes the document rather than the URI so the version recorded is the one
|
|
358
|
+
* the TEXT was read at: a keystroke landing while the save was in flight must
|
|
359
|
+
* leave the document dirty, and marking it against the buffer's current
|
|
360
|
+
* version would silently swallow that edit. A record of a model since closed
|
|
361
|
+
* marks nothing: a reopened URI is a new model whose versions start over, so
|
|
362
|
+
* the old record's version could name an edit of the new one.
|
|
363
|
+
*/
|
|
364
|
+
markSaved(document: EditorDocument): void;
|
|
365
|
+
/**
|
|
366
|
+
* Register one `DocumentSemanticTokensProvider` per language, reading the
|
|
367
|
+
* legend off the `initialize` result.
|
|
368
|
+
*
|
|
369
|
+
* The legend has to come from the server rather than being restated here: it
|
|
370
|
+
* is the index space the token stream is encoded in, so a client legend that
|
|
371
|
+
* merely LOOKS right renders every token as the wrong kind — a colouring bug
|
|
372
|
+
* with no error anywhere. Langium builds it by merging every registered
|
|
373
|
+
* language's provider options, which is why one legend serves them all.
|
|
374
|
+
*
|
|
375
|
+
* Absent capability means no provider at all rather than an empty legend: an
|
|
376
|
+
* empty one would decode every token index to nothing and produce a file with
|
|
377
|
+
* no highlighting, which is what a broken server looks like.
|
|
378
|
+
*/
|
|
379
|
+
protected registerSemanticTokens(capabilities: ServerCapabilities): void;
|
|
380
|
+
/**
|
|
381
|
+
* Register one `CompletionItemProvider` per language.
|
|
382
|
+
*
|
|
383
|
+
* `triggerCharacters` is taken from the server rather than guessed. It is what
|
|
384
|
+
* makes the list appear on `.` without a letter after it; a client that
|
|
385
|
+
* invents its own set either misses a trigger the grammar defines or asks on a
|
|
386
|
+
* character the server has nothing to say about.
|
|
387
|
+
*/
|
|
388
|
+
protected registerCompletion(capabilities: ServerCapabilities): void;
|
|
389
|
+
/**
|
|
390
|
+
* Register one `HoverProvider` per language.
|
|
391
|
+
*
|
|
392
|
+
* Registered unconditionally rather than behind `capabilities.hoverProvider`,
|
|
393
|
+
* unlike the semantic-token provider above, because the two failure modes are
|
|
394
|
+
* not alike: a hover request a server does not implement answers `null` and
|
|
395
|
+
* Monaco shows nothing, whereas a semantic-token provider without the
|
|
396
|
+
* server's legend would decode the token stream against the wrong index space
|
|
397
|
+
* and mis-colour the file.
|
|
398
|
+
*/
|
|
399
|
+
protected registerHover(): void;
|
|
400
|
+
/**
|
|
401
|
+
* Route a definition target in ANOTHER document to `open`, which answers
|
|
402
|
+
* whether it could show it.
|
|
403
|
+
*
|
|
404
|
+
* **Monaco's standalone editor service can only navigate within the editor
|
|
405
|
+
* that was clicked in**, and it declines the rest by doing nothing: it looks
|
|
406
|
+
* the target resource up on the source editor alone, finds a different model,
|
|
407
|
+
* and returns — no message, no marker, no console line. That is the same
|
|
408
|
+
* observable as a server that resolved no reference, which is what makes the
|
|
409
|
+
* seam worth stating rather than discovering. A host with a workbench behind
|
|
410
|
+
* it supplies this step; a plain page supplies it by hand.
|
|
411
|
+
*
|
|
412
|
+
* `false` from `open` leaves the reader where they are, and that is the
|
|
413
|
+
* honest answer for a target the host holds no text for rather than a
|
|
414
|
+
* failure: a `virtual:` in-code contribution is a document to the server and
|
|
415
|
+
* no file to anyone.
|
|
416
|
+
*
|
|
417
|
+
* **A source editor on a model this client does not own is left to the next
|
|
418
|
+
* opener.** Monaco calls every opener for every editor, so on a page with
|
|
419
|
+
* two clients this one would otherwise claim a jump the other client's
|
|
420
|
+
* server resolved, and hand its host a document that host never opened.
|
|
421
|
+
*
|
|
422
|
+
* **A target in the SOURCE editor's own model is deliberately NOT routed
|
|
423
|
+
* here.** Monaco calls the last-registered opener first and falls through to
|
|
424
|
+
* its own on a `false`, and its own is better for that case: it selects the
|
|
425
|
+
* declaration's whole range where this seam could only place a caret, and it
|
|
426
|
+
* is the path the editor's navigation history is recorded on.
|
|
427
|
+
*
|
|
428
|
+
* Released by {@link dispose} as well as by the returned disposable.
|
|
429
|
+
*/
|
|
430
|
+
registerEditorOpener(open: (uri: string, position: monaco.IPosition) => boolean): monaco.IDisposable;
|
|
431
|
+
/**
|
|
432
|
+
* Register one `DefinitionProvider` per language.
|
|
433
|
+
*
|
|
434
|
+
* **This is half of go-to-definition, and on its own it moves nothing for a
|
|
435
|
+
* target in another document.** A provider answers where the declaration is;
|
|
436
|
+
* going there is the host's job, and {@link registerEditorOpener} is the
|
|
437
|
+
* other half. Registered unconditionally, for the reason {@link registerHover}
|
|
438
|
+
* states.
|
|
439
|
+
*/
|
|
440
|
+
protected registerDefinition(): void;
|
|
441
|
+
/**
|
|
442
|
+
* Register one `DocumentHighlightProvider` per language.
|
|
443
|
+
*
|
|
444
|
+
* **Document-scoped by the protocol, unlike every other reference-following
|
|
445
|
+
* request here**, so it answers what a name does in the file being read
|
|
446
|
+
* rather than where it comes from — the declaration and its uses in one view,
|
|
447
|
+
* with no jump and nothing opened. Registered unconditionally, for the reason
|
|
448
|
+
* {@link registerHover} states.
|
|
449
|
+
*/
|
|
450
|
+
protected registerDocumentHighlight(): void;
|
|
451
|
+
}
|
|
452
|
+
/** The two calls of a data session {@link saveDirtyDocuments} makes, which `DataSession` satisfies. */
|
|
453
|
+
export interface DocumentPersister {
|
|
454
|
+
/** Open `args.uri`, run `fn` with the opened document, whose `text` is the server's state of it, and close it after. */
|
|
455
|
+
withOpenDocument<T>(args: {
|
|
456
|
+
readonly uri: string;
|
|
457
|
+
}, fn: (document: {
|
|
458
|
+
readonly text?: TextState;
|
|
459
|
+
}) => Promise<T>): Promise<T>;
|
|
460
|
+
persistDocument(args: {
|
|
461
|
+
readonly uri: string;
|
|
462
|
+
readonly baseVersion: BaseVersion;
|
|
463
|
+
}): Promise<unknown>;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Persist the dirty documents of `client`, or those of them `uris` names, in
|
|
467
|
+
* the host's form or Monaco's, through `session`, one after another, and
|
|
468
|
+
* return what was saved.
|
|
469
|
+
*
|
|
470
|
+
* **A save persists; it does not author.** Every keystroke already reached the
|
|
471
|
+
* server as a `didChange`, and every server write reached the buffer as a
|
|
472
|
+
* `workspace/applyEdit`, so the server's text is the buffer and disk is the
|
|
473
|
+
* only thing behind. `persistDocument` at `'any'` writes that text without a
|
|
474
|
+
* model: a write of the buffer's text would be authored against no read, so
|
|
475
|
+
* no `ModelVersion` could gate it, and `'any'` on such a write could put an
|
|
476
|
+
* older buffer over a server write still in flight.
|
|
477
|
+
*
|
|
478
|
+
* **The open's text hash is the gate.** A `didChange` travels the LSP port and
|
|
479
|
+
* the persist the data port, and nothing orders one port's messages before
|
|
480
|
+
* the other's, so the open can answer with text a keystroke has not reached.
|
|
481
|
+
* The open answer's hash is `textHash` of the server's text; when it is not
|
|
482
|
+
* the buffer's, the save throws, naming the document, and the document stays
|
|
483
|
+
* dirty for the next save. A keystroke landing after the open persists as
|
|
484
|
+
* newer text, which leaves the buffer dirty the same way.
|
|
485
|
+
*
|
|
486
|
+
* Each document's text is read just before its own open, not once for the
|
|
487
|
+
* set: an earlier document's persist takes time, and a keystroke in a later
|
|
488
|
+
* one during it would otherwise fail that one's hash check for nothing. Each
|
|
489
|
+
* is marked saved at the version its text was read at, one at a time, so a
|
|
490
|
+
* failure part-way through leaves the documents it never reached dirty and a
|
|
491
|
+
* second call retries exactly those. Sequential, not concurrent: each persist
|
|
492
|
+
* runs over the server's shared store.
|
|
493
|
+
*/
|
|
494
|
+
export declare function saveDirtyDocuments(client: MonacoLspClient, session: DocumentPersister, uris?: readonly string[]): Promise<EditorDocument[]>;
|
|
495
|
+
//# sourceMappingURL=monaco-lsp-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monaco-lsp-client.d.ts","sourceRoot":"","sources":["../../src/monaco/monaco-lsp-client.ts"],"names":[],"mappings":"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"}
|