@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.
@@ -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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"}