@hydranium/core 1.0.0-next.285 → 1.0.0-next.288
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/lib/documents/file-system-task-queue.d.ts +3 -0
- package/lib/documents/file-system-task-queue.d.ts.map +1 -1
- package/lib/documents/file-system-task-queue.js +3 -0
- package/lib/documents/file-system-task-queue.js.map +1 -1
- package/lib/documents/hydranium-text-documents.d.ts +5 -1
- package/lib/documents/hydranium-text-documents.d.ts.map +1 -1
- package/lib/documents/hydranium-text-documents.js +12 -5
- package/lib/documents/hydranium-text-documents.js.map +1 -1
- package/lib/langium/model-service/model-service.d.ts +7 -0
- package/lib/langium/model-service/model-service.d.ts.map +1 -1
- package/lib/langium/model-service/model-service.js +4 -0
- package/lib/langium/model-service/model-service.js.map +1 -1
- package/lib/langium/workspace/document-uri-policy.d.ts +9 -5
- package/lib/langium/workspace/document-uri-policy.d.ts.map +1 -1
- package/lib/langium/workspace/document-uri-policy.js +15 -8
- package/lib/langium/workspace/document-uri-policy.js.map +1 -1
- package/lib/langium/workspace/file-system-provider.d.ts +15 -4
- package/lib/langium/workspace/file-system-provider.d.ts.map +1 -1
- package/lib/langium/workspace/file-system-provider.js +13 -4
- package/lib/langium/workspace/file-system-provider.js.map +1 -1
- package/lib/lsp/hydranium-document-update-handler.d.ts +41 -21
- package/lib/lsp/hydranium-document-update-handler.d.ts.map +1 -1
- package/lib/lsp/hydranium-document-update-handler.js +86 -33
- package/lib/lsp/hydranium-document-update-handler.js.map +1 -1
- package/lib/node/node-file-system-provider.d.ts +7 -0
- package/lib/node/node-file-system-provider.d.ts.map +1 -1
- package/lib/node/node-file-system-provider.js +36 -1
- package/lib/node/node-file-system-provider.js.map +1 -1
- package/lib/testing/node/applied-edit-capture.d.ts +1 -1
- package/lib/testing/node/applied-edit-capture.d.ts.map +1 -1
- package/lib/testing/node/applied-edit-capture.js +3 -1
- package/lib/testing/node/applied-edit-capture.js.map +1 -1
- package/lib/testing/node/lsp-server-connection.d.ts +2 -1
- package/lib/testing/node/lsp-server-connection.d.ts.map +1 -1
- package/lib/testing/node/lsp-server-connection.js.map +1 -1
- package/package.json +5 -5
- package/src/documents/file-system-task-queue.ts +6 -0
- package/src/documents/hydranium-text-documents.ts +13 -5
- package/src/langium/model-service/model-service.ts +11 -0
- package/src/langium/workspace/document-uri-policy.ts +17 -8
- package/src/langium/workspace/file-system-provider.ts +23 -4
- package/src/lsp/hydranium-document-update-handler.ts +101 -43
- package/src/node/node-file-system-provider.ts +36 -1
- package/src/testing/node/applied-edit-capture.ts +5 -3
- package/src/testing/node/lsp-server-connection.ts +2 -1
|
@@ -218,8 +218,9 @@ export interface LspServerConnection extends Harness {
|
|
|
218
218
|
*
|
|
219
219
|
* Throwing from the handler surfaces to the server as an RPC failure, which
|
|
220
220
|
* is the other branch (`applyEditToLanguageClient` invalidates and rethrows).
|
|
221
|
+
* A handler returning a promise holds the answer until it settles.
|
|
221
222
|
*/
|
|
222
|
-
setApplyEditHandler(handler: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult): void;
|
|
223
|
+
setApplyEditHandler(handler: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult | Promise<ApplyWorkspaceEditResult>): void;
|
|
223
224
|
/**
|
|
224
225
|
* Release every resource: the diagnostics and applyEdit subscriptions, the
|
|
225
226
|
* client + server connections, the underlying stream pair. Idempotent. Does
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lsp-server-connection.d.ts","sourceRoot":"","sources":["../../../src/testing/node/lsp-server-connection.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAG3D,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,4BAA4B,CAAC;AAgB/E,OAAO,EAYJ,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACrB,MAAM,qCAAqC,CAAC;AAc7C;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACpC;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,oGAAoG;IACpG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IACzB,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAC1C;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACxB;AAED,+DAA+D;AAC/D,MAAM,WAAW,sBAAsB;IACpC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC;CAClD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,mBAAoB,SAAQ,OAAO;IACjD;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,EAAE,UAAU,CAAC;IACtC,oGAAoG;IACpG,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC;;;;;;;;;OASG;IACH,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,wBAAwB,CAAC,CAAC;IAC9D;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAClD,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,MAAM;QACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF;;;;;OAKG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1E;;;;OAIG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpF,+EAA+E;IAC/E,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,8FAA8F;IAC9F,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjE;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACrE,mCAAmC;IACnC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9D,uDAAuD;IACvD,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAE5D;;;;;;;;;;;;;;;;;OAiBG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,sBAAsB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAE1G;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEzG
|
|
1
|
+
{"version":3,"file":"lsp-server-connection.d.ts","sourceRoot":"","sources":["../../../src/testing/node/lsp-server-connection.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAElF,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAG3D,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,4BAA4B,CAAC;AAgB/E,OAAO,EAYJ,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,cAAc,EACrB,MAAM,qCAAqC,CAAC;AAc7C;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACpC;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,oGAAoG;IACpG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IACzB,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAC1C;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACxB;AAED,+DAA+D;AAC/D,MAAM,WAAW,sBAAsB;IACpC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC;CAClD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,mBAAoB,SAAQ,OAAO;IACjD;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,EAAE,UAAU,CAAC;IACtC,oGAAoG;IACpG,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC;;;;;;;;;OASG;IACH,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,wBAAwB,CAAC,CAAC;IAC9D;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAClD,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,MAAM;QACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;KACzB,CAAC;IAEF;;;;;OAKG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1E;;;;OAIG;IACH,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1B;;;;OAIG;IACH,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpF,+EAA+E;IAC/E,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,8FAA8F;IAC9F,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjE;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACrE,mCAAmC;IACnC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC9D,uDAAuD;IACvD,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAE5D;;;;;;;;;;;;;;;;;OAiBG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,sBAAsB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAE1G;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEzG;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,wBAAwB,GAAG,OAAO,CAAC,wBAAwB,CAAC,GAAG,IAAI,CAAC;IAEvI;;;;OAIG;IACH,OAAO,IAAI,IAAI,CAAC;CAClB;AAmCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,IAAI,mBAAmB,CAmM7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lsp-server-connection.js","sourceRoot":"","sources":["../../../src/testing/node/lsp-server-connection.ts"],"names":[],"mappings":"AAAA;;;;;;;kFAOkF;AAGlF,OAAO,EAAE,WAAW,EAA0B,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EAAmB,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,+EAA+E;AAC/E,+EAA+E;AAC/E,kFAAkF;AAClF,wEAAwE;AACxE,gFAAgF;AAChF,gFAAgF;AAChF,gFAAgF;AAChF,mFAAmF;AACnF,oCAAoC;AACpC,8EAA8E;AAC9E,6EAA6E;AAC7E,uCAAuC;AACvC,OAAO,EAAE,gBAAgB,EAAiB,MAAM,uBAAuB,CAAC;AACxE,OAAO,EACJ,iBAAiB,EACjB,iCAAiC,EACjC,gCAAgC,EAChC,+BAA+B,EAC/B,YAAY,EACZ,iBAAiB,EACjB,uBAAuB,EACvB,8BAA8B,EAC9B,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EAY1B,MAAM,qCAAqC,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,8BAA8B,GAAG,KAAK,CAAC;AAE7C,oGAAoG;AACpG,MAAM,wBAAwB,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"lsp-server-connection.js","sourceRoot":"","sources":["../../../src/testing/node/lsp-server-connection.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hydranium/core",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.288",
|
|
4
4
|
"description": "Foundational runtime of the hydranium framework: AST coordination layer (services, integrity, AST extension, serialization, multi-client documents) plus the LSP textual head at the /lsp subpath. Consumed by protocol-head packages (@hydranium/data-server, @hydranium/glsp-server).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ast",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"diff": "^5.2.0"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@hydranium/langium": "1.0.0-next.
|
|
87
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
86
|
+
"@hydranium/langium": "1.0.0-next.288",
|
|
87
|
+
"@hydranium/protocol": "1.0.0-next.288",
|
|
88
88
|
"@playwright/test": "^1.40.0",
|
|
89
89
|
"@types/diff": "^5.2.0",
|
|
90
90
|
"rimraf": "^5.0.0",
|
|
@@ -96,8 +96,8 @@
|
|
|
96
96
|
"vscode-languageserver-types": "^3.17.5"
|
|
97
97
|
},
|
|
98
98
|
"peerDependencies": {
|
|
99
|
-
"@hydranium/langium": "1.0.0-next.
|
|
100
|
-
"@hydranium/protocol": "1.0.0-next.
|
|
99
|
+
"@hydranium/langium": "1.0.0-next.288",
|
|
100
|
+
"@hydranium/protocol": "1.0.0-next.288",
|
|
101
101
|
"@playwright/test": "^1.40.0",
|
|
102
102
|
"vscode-jsonrpc": "^9.0.0",
|
|
103
103
|
"vscode-languageserver": "~10.0.1",
|
|
@@ -33,6 +33,8 @@ export interface FileSystemTaskQueue {
|
|
|
33
33
|
* which wedges the file's queue for good.
|
|
34
34
|
*/
|
|
35
35
|
enqueue<T>(uri: string, task: () => Promise<T>): Promise<T>;
|
|
36
|
+
/** Whether no task of `uri` is running or waiting. */
|
|
37
|
+
isIdle(uri: string): boolean;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
export class DefaultFileSystemTaskQueue implements FileSystemTaskQueue {
|
|
@@ -65,4 +67,8 @@ export class DefaultFileSystemTaskQueue implements FileSystemTaskQueue {
|
|
|
65
67
|
});
|
|
66
68
|
return result;
|
|
67
69
|
}
|
|
70
|
+
|
|
71
|
+
isIdle(uri: string): boolean {
|
|
72
|
+
return !this.queues.has(this.uriPolicy.canonicalUri(uri));
|
|
73
|
+
}
|
|
68
74
|
}
|
|
@@ -583,6 +583,14 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
583
583
|
}
|
|
584
584
|
}
|
|
585
585
|
|
|
586
|
+
/** Release now a document waiting out the grace, as its last close would have; one that is not waiting is left alone. */
|
|
587
|
+
protected releaseIfDeferred(uri: CanonicalUri): void {
|
|
588
|
+
if (this.documentReleaseScheduler.isDeferred(uri)) {
|
|
589
|
+
this.documentReleaseScheduler.cancel(uri);
|
|
590
|
+
this.releaseDocument(uri);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
586
594
|
/**
|
|
587
595
|
* Drop the document no client has open any more, announce it on
|
|
588
596
|
* {@link onDidReleaseDocument}, then hand it to the
|
|
@@ -1310,7 +1318,9 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
1310
1318
|
|
|
1311
1319
|
/**
|
|
1312
1320
|
* The file behind `uri` was deleted: close every open of it except the
|
|
1313
|
-
* language client's
|
|
1321
|
+
* language client's, and release now a document waiting out the grace,
|
|
1322
|
+
* whose lost client's open would otherwise bring its text back with no
|
|
1323
|
+
* file behind it.
|
|
1314
1324
|
*
|
|
1315
1325
|
* The editor's open is left alone because the editor owns it: it keeps the
|
|
1316
1326
|
* buffer of a deleted file and goes on sending changes for it, and a store
|
|
@@ -1324,6 +1334,7 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
1324
1334
|
this.notifyDidCloseTextDocument({ textDocument: { uri: key } }, clientId);
|
|
1325
1335
|
}
|
|
1326
1336
|
}
|
|
1337
|
+
this.releaseIfDeferred(key);
|
|
1327
1338
|
}
|
|
1328
1339
|
|
|
1329
1340
|
/**
|
|
@@ -1343,10 +1354,7 @@ export class HydraniumTextDocuments<T extends TextDocument = TextDocument> exten
|
|
|
1343
1354
|
}
|
|
1344
1355
|
// A document waiting out the grace has no client left to close, and is
|
|
1345
1356
|
// released now as its last close would have released it.
|
|
1346
|
-
|
|
1347
|
-
this.documentReleaseScheduler.cancel(key);
|
|
1348
|
-
this.releaseDocument(key);
|
|
1349
|
-
}
|
|
1357
|
+
this.releaseIfDeferred(key);
|
|
1350
1358
|
super.delete(key);
|
|
1351
1359
|
}
|
|
1352
1360
|
|
|
@@ -302,6 +302,12 @@ export interface ModelService<
|
|
|
302
302
|
* wait is logged and resolves.
|
|
303
303
|
*/
|
|
304
304
|
settleLanguageClient(uri: string, cancelToken?: CancellationToken): Promise<void>;
|
|
305
|
+
/**
|
|
306
|
+
* Whether a push of the document's text into the language client awaits the
|
|
307
|
+
* client's answer. A push a settle already timed out on does not count: that
|
|
308
|
+
* settle has warned about it.
|
|
309
|
+
*/
|
|
310
|
+
isLanguageClientPushPending(uri: string): boolean;
|
|
305
311
|
|
|
306
312
|
/**
|
|
307
313
|
* Fires as a document reaches the filter's phase, `Validated` by default.
|
|
@@ -909,6 +915,11 @@ export class DefaultModelService<
|
|
|
909
915
|
}
|
|
910
916
|
}
|
|
911
917
|
|
|
918
|
+
isLanguageClientPushPending(uri: string): boolean {
|
|
919
|
+
const chain = this.syncChains.get(UriUtils.toUri(this.uriPolicy.canonicalUri(uri)).toString());
|
|
920
|
+
return chain !== undefined && !this.timedOutSyncChains.has(chain);
|
|
921
|
+
}
|
|
922
|
+
|
|
912
923
|
/**
|
|
913
924
|
* True when the document at `uri` is currently open for at least one
|
|
914
925
|
* client. Pure read; no side effects.
|
|
@@ -21,6 +21,8 @@ import { type ServerSharedServicesMinimal } from '../shared-services.js';
|
|
|
21
21
|
*/
|
|
22
22
|
export interface RealpathCapableFileSystem {
|
|
23
23
|
realpath?(uri: URI): URI | undefined;
|
|
24
|
+
/** `uri` with its links followed, those to nothing included; see `WritableFileSystemProvider.resolveLinks`. */
|
|
25
|
+
resolveLinks?(uri: URI): URI;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
@@ -149,11 +151,13 @@ export class DefaultDocumentUriPolicy implements DocumentUriPolicy {
|
|
|
149
151
|
* The raw `realpath` syscall lives on the `FileSystemProvider`
|
|
150
152
|
* (`@hydranium/core/node`'s `DefaultFileSystemProvider`), not here — this policy
|
|
151
153
|
* is pure routing over that seam, so it carries no `node:fs` import and is
|
|
152
|
-
* browser-neutral. Both methods follow the *same* policy: `canonicalUri`
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
154
|
+
* browser-neutral. Both methods follow the *same* policy: `canonicalUri` keys a
|
|
155
|
+
* path that can't be resolved by the links it follows, where the provider has
|
|
156
|
+
* `resolveLinks`, else by its syntactic form (optimistic — a file that appears
|
|
157
|
+
* later canonicalises to the same key once present, also one reached through a
|
|
158
|
+
* link that pointed at nothing), while `loadUri` returns `undefined` for an
|
|
159
|
+
* absent path (honest about existence, so a caller about to read the
|
|
160
|
+
* filesystem skips it).
|
|
157
161
|
*
|
|
158
162
|
* If the provider for a URI's scheme has no `realpath` (in-memory / browser /
|
|
159
163
|
* empty), the framework's `FileSystemProviderRegistry` returns the URI
|
|
@@ -173,9 +177,14 @@ export class RealpathDocumentUriPolicy extends DefaultDocumentUriPolicy {
|
|
|
173
177
|
|
|
174
178
|
override canonicalUri(uri: URI | string): CanonicalUri {
|
|
175
179
|
const parsed = UriUtils.toUri(uri);
|
|
176
|
-
|
|
177
|
-
//
|
|
178
|
-
//
|
|
180
|
+
// An absent path keys by the links it follows, so a file reached through
|
|
181
|
+
// a link keys the same before it exists and once it does; a provider
|
|
182
|
+
// without `resolveLinks`, or without `realpath`, keys it syntactically.
|
|
183
|
+
// `resolveLinks` alone where it exists: it resolves a present path as
|
|
184
|
+
// `realpath` does, and asking both would cost an absent path a second
|
|
185
|
+
// miss.
|
|
186
|
+
const real = parsed && (this.fs.resolveLinks ? this.fs.resolveLinks(parsed) : this.fs.realpath?.(parsed));
|
|
187
|
+
// Mint via `asCanonicalUri` once normalised.
|
|
179
188
|
return real ? asCanonicalUri(UriUtils.normalize(real)) : super.canonicalUri(uri);
|
|
180
189
|
}
|
|
181
190
|
|
|
@@ -67,6 +67,15 @@ export interface WritableFileSystemProvider extends FileSystemProvider {
|
|
|
67
67
|
* browser-neutral (no `node:fs` import).
|
|
68
68
|
*/
|
|
69
69
|
realpath?(uri: URI): URI | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* The path `uri` names with every link followed, a link to nothing
|
|
72
|
+
* included, so that `RealpathDocumentUriPolicy.canonicalUri` keys a file
|
|
73
|
+
* reached through a link the same before it exists and once it does.
|
|
74
|
+
* Where {@link realpath} resolves, the same answer; otherwise what is
|
|
75
|
+
* missing joined as spelled under the real path of what exists. Optional,
|
|
76
|
+
* as `realpath` is: without it an absent path keys by its syntactic form.
|
|
77
|
+
*/
|
|
78
|
+
resolveLinks?(uri: URI): URI;
|
|
70
79
|
/**
|
|
71
80
|
* Whether a file is at `uri`, where a miss counts only once it has lasted:
|
|
72
81
|
* on a disk where replacing a file can hide its name for a moment, a single
|
|
@@ -173,10 +182,11 @@ export interface FileSystemProviderRegistryOptions<
|
|
|
173
182
|
* A directory is listed by the provider of its own scheme, so a workspace
|
|
174
183
|
* root's tree comes from that provider alone.
|
|
175
184
|
*
|
|
176
|
-
* `realpath`, `mtimeMs` and `existsSettled` are always present
|
|
177
|
-
* the scheme's provider. Where that provider lacks one,
|
|
178
|
-
*
|
|
179
|
-
* `exists`: the answers their
|
|
185
|
+
* `realpath`, `resolveLinks`, `mtimeMs` and `existsSettled` are always present
|
|
186
|
+
* and forward to the scheme's provider. Where that provider lacks one,
|
|
187
|
+
* `realpath` and `resolveLinks` return the URI unchanged, `mtimeMs` returns
|
|
188
|
+
* `undefined` and `existsSettled` answers as `exists`: the answers their
|
|
189
|
+
* callers already give a provider without them.
|
|
180
190
|
*/
|
|
181
191
|
export class DefaultFileSystemProviderRegistry<
|
|
182
192
|
THost extends WritableFileSystemProvider = WritableFileSystemProvider
|
|
@@ -223,6 +233,15 @@ export class DefaultFileSystemProviderRegistry<
|
|
|
223
233
|
return provider.realpath ? provider.realpath(uri) : uri;
|
|
224
234
|
}
|
|
225
235
|
|
|
236
|
+
resolveLinks(uri: URI): URI {
|
|
237
|
+
const provider = this.providerFor(uri);
|
|
238
|
+
if (provider.resolveLinks) {
|
|
239
|
+
return provider.resolveLinks(uri);
|
|
240
|
+
}
|
|
241
|
+
// A provider with `realpath` alone still keys a present path by it.
|
|
242
|
+
return provider.realpath?.(uri) ?? uri;
|
|
243
|
+
}
|
|
244
|
+
|
|
226
245
|
async existsSettled(uri: URI): Promise<boolean> {
|
|
227
246
|
const provider = this.providerFor(uri);
|
|
228
247
|
return provider.existsSettled ? provider.existsSettled(uri) : provider.exists(uri);
|
|
@@ -63,13 +63,15 @@ export interface HydraniumDocumentUpdateHandlerOptions {
|
|
|
63
63
|
readonly bypassNonLanguageClientChanges?: boolean;
|
|
64
64
|
/**
|
|
65
65
|
* Longest an editor's save waits on the server, in milliseconds, at each of
|
|
66
|
-
* its two steps: the `willSaveWaitUntil` answer waits for the
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* and
|
|
72
|
-
*
|
|
66
|
+
* its two steps: the `willSaveWaitUntil` answer waits for the language
|
|
67
|
+
* client's answer to the push of the server's text and for the server's
|
|
68
|
+
* disk writes of the document already queued, and server writes queued
|
|
69
|
+
* after the answer wait for the editor's `didSave`. Either wait that runs
|
|
70
|
+
* out is logged, and the editor can then save without the server's text,
|
|
71
|
+
* or its write and the server's land in either order. Default `1000`: VS
|
|
72
|
+
* Code gives up on an answer after about 1.5 s, and switches the listener
|
|
73
|
+
* off for the session once four answers, over all documents, timed out or
|
|
74
|
+
* failed.
|
|
73
75
|
*/
|
|
74
76
|
readonly willSaveGateMs?: number;
|
|
75
77
|
}
|
|
@@ -96,10 +98,11 @@ export interface HydraniumDocumentUpdateHandlerOptions {
|
|
|
96
98
|
* runs, so a subclass that formats build logs can tag its line with the
|
|
97
99
|
* event that caused the build without per-adopter wiring to capture it.
|
|
98
100
|
* 4. **Editor save gate** ({@link willSaveDocumentWaitUntil}) — the editor
|
|
99
|
-
* writes the file itself, so
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
101
|
+
* writes the file itself, so its save waits for the language client to
|
|
102
|
+
* answer the push of the server's newer text, and the server's disk
|
|
103
|
+
* writes of that document are ordered around it: the editor's save waits
|
|
104
|
+
* for the ones already queued, and the ones queued during its save wait
|
|
105
|
+
* for its `didSave`. The answer and the hold are each capped by
|
|
103
106
|
* {@link HydraniumDocumentUpdateHandlerOptions.willSaveGateMs}.
|
|
104
107
|
*
|
|
105
108
|
* What the build keeps after a document's last close is not dispatched here:
|
|
@@ -257,23 +260,27 @@ export class HydraniumDocumentUpdateHandler extends DefaultDocumentUpdateHandler
|
|
|
257
260
|
}
|
|
258
261
|
|
|
259
262
|
/**
|
|
260
|
-
* Answer an editor's `willSaveWaitUntil` with no edits once
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
* the
|
|
263
|
+
* Answer an editor's `willSaveWaitUntil` with no edits once
|
|
264
|
+
* {@link settleBeforeSave} has resolved and then the server's disk writes
|
|
265
|
+
* of the document already queued have landed, or after
|
|
266
|
+
* {@link willSaveGateMs} for both together, whichever is first. From the
|
|
267
|
+
* moment the queue reaches this save, disk tasks of the document queued
|
|
268
|
+
* behind it wait for the editor's `didSave`, reported through
|
|
265
269
|
* `HydraniumTextDocuments.onDidSaveInLanguageClient`, or for
|
|
266
270
|
* {@link willSaveGateMs} more.
|
|
267
271
|
*
|
|
268
272
|
* The hold is a disk task that waits only for that signal or its timer:
|
|
269
273
|
* waiting on a build, a save or anything else queued for the document would
|
|
270
|
-
* wedge its queue
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
* logged
|
|
274
|
-
*
|
|
274
|
+
* wedge its queue, so the settle runs before it is queued. Past the cap the
|
|
275
|
+
* hold is queued while the settle still runs, so a write that build queues,
|
|
276
|
+
* such as an integrity repair, waits behind the hold. A settle that fails is
|
|
277
|
+
* logged and the save goes on. Resolves in every case, since a
|
|
278
|
+
* failed request counts against the listener in VS Code; Langium drops the
|
|
279
|
+
* request's cancellation, so an abandoned request still runs to the cap. A
|
|
280
|
+
* hold that runs out is logged at debug only: an editor skips `didSave` for
|
|
281
|
+
* a save it cancels or that changed nothing.
|
|
275
282
|
*/
|
|
276
|
-
willSaveDocumentWaitUntil(event: TextDocumentWillSaveEvent<TextDocument>): Promise<TextEdit[]> {
|
|
283
|
+
async willSaveDocumentWaitUntil(event: TextDocumentWillSaveEvent<TextDocument>): Promise<TextEdit[]> {
|
|
277
284
|
const uri = event.document.uri;
|
|
278
285
|
this.editorSaves.get(uri)?.();
|
|
279
286
|
const hold = new Deferred();
|
|
@@ -284,32 +291,83 @@ export class HydraniumDocumentUpdateHandler extends DefaultDocumentUpdateHandler
|
|
|
284
291
|
hold.resolve();
|
|
285
292
|
};
|
|
286
293
|
this.editorSaves.set(uri, release);
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
294
|
+
const clock = this.services.Clock;
|
|
295
|
+
const answer = new Deferred<TextEdit[]>();
|
|
296
|
+
let settling = true;
|
|
297
|
+
const cap = clock.setTimer(() => {
|
|
298
|
+
if (settling) {
|
|
299
|
+
// A push unanswered past the cap is the stale-save case, and server
|
|
300
|
+
// writes queued ahead of the hold race the save; a build past the
|
|
301
|
+
// cap alone is routine on a large model.
|
|
302
|
+
if (this.services.model.ModelService.isLanguageClientPushPending(uri)) {
|
|
303
|
+
this.logger.warn(
|
|
304
|
+
`willSaveWaitUntil for ${uri} answered after ${this.willSaveGateMs} ms with the language client's answer to a push of it still pending; the editor may save text older than the server's.`
|
|
305
|
+
);
|
|
306
|
+
} else if (!this.services.workspace.FileSystemTaskQueue.isIdle(uri)) {
|
|
307
|
+
this.logger.warn(
|
|
308
|
+
`willSaveWaitUntil for ${uri} answered after ${this.willSaveGateMs} ms with its settle still pending and server writes of it queued; the editor's save may race them.`
|
|
309
|
+
);
|
|
310
|
+
} else {
|
|
311
|
+
this.logger.debug(
|
|
312
|
+
`willSaveWaitUntil for ${uri} answered after ${this.willSaveGateMs} ms with its settle still pending, on its build or on a push a settle already timed out on.`
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
} else {
|
|
290
316
|
this.logger.warn(
|
|
291
317
|
`willSaveWaitUntil for ${uri} answered after ${this.willSaveGateMs} ms with server writes of it still queued; the editor's save may race them.`
|
|
292
318
|
);
|
|
293
|
-
|
|
294
|
-
|
|
319
|
+
}
|
|
320
|
+
answer.resolve([]);
|
|
321
|
+
}, this.willSaveGateMs);
|
|
322
|
+
// Caught on the settle itself, since a race that the cap has won drops a
|
|
323
|
+
// later rejection without a trace.
|
|
324
|
+
const settled = (async (): Promise<void> => {
|
|
295
325
|
try {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if ((await clock.raceTimer(hold.promise, this.willSaveGateMs)) === TIMED_OUT) {
|
|
300
|
-
this.logger.debug(
|
|
301
|
-
`No didSave for ${uri} within ${this.willSaveGateMs} ms; server writes of it no longer wait for the editor's save.`
|
|
302
|
-
);
|
|
303
|
-
release();
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
} catch (err) {
|
|
307
|
-
cap.dispose();
|
|
308
|
-
this.logger.error(`willSaveWaitUntil for ${uri} answered without waiting. ${describeErrorWithStack(err)}`);
|
|
309
|
-
release();
|
|
310
|
-
resolve([]);
|
|
326
|
+
await this.settleBeforeSave(uri);
|
|
327
|
+
} catch (err: unknown) {
|
|
328
|
+
this.logger.error(`The settle before an editor save of ${uri} failed. ${describeErrorWithStack(err)}`);
|
|
311
329
|
}
|
|
312
|
-
});
|
|
330
|
+
})();
|
|
331
|
+
await Promise.race([settled, answer.promise]);
|
|
332
|
+
settling = false;
|
|
333
|
+
try {
|
|
334
|
+
void this.services.workspace.FileSystemTaskQueue.enqueue(uri, async () => {
|
|
335
|
+
cap.dispose();
|
|
336
|
+
answer.resolve([]);
|
|
337
|
+
if ((await clock.raceTimer(hold.promise, this.willSaveGateMs)) === TIMED_OUT) {
|
|
338
|
+
this.logger.debug(
|
|
339
|
+
`No didSave for ${uri} within ${this.willSaveGateMs} ms; server writes of it no longer wait for the editor's save.`
|
|
340
|
+
);
|
|
341
|
+
release();
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
} catch (err: unknown) {
|
|
345
|
+
cap.dispose();
|
|
346
|
+
this.logger.error(`willSaveWaitUntil for ${uri} answered without waiting for server writes. ${describeErrorWithStack(err)}`);
|
|
347
|
+
release();
|
|
348
|
+
answer.resolve([]);
|
|
349
|
+
}
|
|
350
|
+
return answer.promise;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* What an editor's save of `uri` waits for before it joins the document's
|
|
355
|
+
* disk queue: the language client's answer to the push of the server's
|
|
356
|
+
* newer text, applied or refused and logged
|
|
357
|
+
* (`ModelService.settleLanguageClient`). The editor saves its own buffer,
|
|
358
|
+
* so without it the editor can save text older than the server's. The
|
|
359
|
+
* settle waits for a build of the document's latest text, so a change of it
|
|
360
|
+
* still debounced is flushed first, along with every other debounced
|
|
361
|
+
* change. Runs outside the disk queue, under the save's cap; an override
|
|
362
|
+
* must not wait on a disk task of the document, which past the cap queues
|
|
363
|
+
* behind the save's hold.
|
|
364
|
+
*/
|
|
365
|
+
protected async settleBeforeSave(uri: string): Promise<void> {
|
|
366
|
+
const key = URI.parse(uri).toString();
|
|
367
|
+
if (this.pendingChanged.has(key) || this.pendingDeleted.has(key)) {
|
|
368
|
+
this.flushPending();
|
|
369
|
+
}
|
|
370
|
+
await this.services.model.ModelService.settleLanguageClient(uri);
|
|
313
371
|
}
|
|
314
372
|
|
|
315
373
|
/**
|
|
@@ -11,8 +11,9 @@ import { type Tracer } from '@hydranium/protocol';
|
|
|
11
11
|
import { type FileSystemNode, URI, UriUtils } from '@hydranium/langium';
|
|
12
12
|
import { NodeFileSystemProvider } from '@hydranium/langium/node';
|
|
13
13
|
import { randomUUID } from 'node:crypto';
|
|
14
|
-
import { realpathSync } from 'node:fs';
|
|
14
|
+
import { readlinkSync, realpathSync } from 'node:fs';
|
|
15
15
|
import * as fsp from 'node:fs/promises';
|
|
16
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
16
17
|
import { type WritableFileSystemProvider } from '../langium/workspace/file-system-provider.js';
|
|
17
18
|
import { isFileNotFound } from '../langium/workspace/file-not-found.js';
|
|
18
19
|
import { type SelfSaveRegistry } from '../langium/workspace/self-save-registry.js';
|
|
@@ -314,6 +315,40 @@ export class DefaultFileSystemProvider extends NodeFileSystemProvider implements
|
|
|
314
315
|
return undefined;
|
|
315
316
|
}
|
|
316
317
|
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* The path `uri` names with every link followed, a link to nothing
|
|
321
|
+
* included, so a file reached through a link keys the same before it
|
|
322
|
+
* exists and once it does. What is missing is joined as spelled under the
|
|
323
|
+
* real path of what exists. A non-`file:` URI passes through unchanged.
|
|
324
|
+
*/
|
|
325
|
+
resolveLinks(uri: URI): URI {
|
|
326
|
+
return uri.scheme === 'file' ? URI.file(followLinks(uri.fsPath)) : uri;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** `path` with its links followed; see `DefaultFileSystemProvider.resolveLinks`. */
|
|
331
|
+
function followLinks(path: string, hops = 0): string {
|
|
332
|
+
try {
|
|
333
|
+
return realpathSync(path);
|
|
334
|
+
} catch {
|
|
335
|
+
// Absent somewhere along the way.
|
|
336
|
+
}
|
|
337
|
+
// A link to nothing is followed to what it names; a chain is bounded as
|
|
338
|
+
// the kernel bounds one.
|
|
339
|
+
if (hops < 40) {
|
|
340
|
+
let target: string | undefined;
|
|
341
|
+
try {
|
|
342
|
+
target = readlinkSync(path);
|
|
343
|
+
} catch {
|
|
344
|
+
// Not a link, or not there.
|
|
345
|
+
}
|
|
346
|
+
if (target !== undefined) {
|
|
347
|
+
return followLinks(resolve(dirname(path), target), hops + 1);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const parent = dirname(path);
|
|
351
|
+
return parent === path ? path : join(followLinks(parent, hops), basename(path));
|
|
317
352
|
}
|
|
318
353
|
|
|
319
354
|
/** The "no content here" rejection, for a URI naming no readable file. */
|
|
@@ -23,7 +23,7 @@ import type { AppliedEdit, NextAppliedEditOptions } from './lsp-server-connectio
|
|
|
23
23
|
export interface AppliedEditCapture {
|
|
24
24
|
readonly appliedEdits: ReadonlyArray<AppliedEdit>;
|
|
25
25
|
nextAppliedEdit(uri: string, timeoutMsOrOptions?: number | NextAppliedEditOptions): Promise<AppliedEdit>;
|
|
26
|
-
setApplyEditHandler(handler: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult): void;
|
|
26
|
+
setApplyEditHandler(handler: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult | Promise<ApplyWorkspaceEditResult>): void;
|
|
27
27
|
dispose(): void;
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -37,7 +37,9 @@ export interface AppliedEditCapture {
|
|
|
37
37
|
export function captureAppliedEdits(client: ProtocolConnection, defaultTimeoutMs: number): AppliedEditCapture {
|
|
38
38
|
const appliedEdits: AppliedEdit[] = [];
|
|
39
39
|
const waiters: Array<(edit: AppliedEdit) => boolean> = [];
|
|
40
|
-
let handler: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult = () => ({
|
|
40
|
+
let handler: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult | Promise<ApplyWorkspaceEditResult> = () => ({
|
|
41
|
+
applied: true
|
|
42
|
+
});
|
|
41
43
|
const subscription = client.onRequest(ApplyWorkspaceEditRequest.type, (params: ApplyWorkspaceEditParams) => {
|
|
42
44
|
const edit: AppliedEdit = { params, uris: editedUris(params.edit), text: insertedText(params.edit) };
|
|
43
45
|
// Record before the handler runs, so a handler that rejects the edit or
|
|
@@ -92,7 +94,7 @@ export function captureAppliedEdits(client: ProtocolConnection, defaultTimeoutMs
|
|
|
92
94
|
});
|
|
93
95
|
},
|
|
94
96
|
|
|
95
|
-
setApplyEditHandler(next: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult): void {
|
|
97
|
+
setApplyEditHandler(next: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult | Promise<ApplyWorkspaceEditResult>): void {
|
|
96
98
|
handler = next;
|
|
97
99
|
},
|
|
98
100
|
|
|
@@ -281,8 +281,9 @@ export interface LspServerConnection extends Harness {
|
|
|
281
281
|
*
|
|
282
282
|
* Throwing from the handler surfaces to the server as an RPC failure, which
|
|
283
283
|
* is the other branch (`applyEditToLanguageClient` invalidates and rethrows).
|
|
284
|
+
* A handler returning a promise holds the answer until it settles.
|
|
284
285
|
*/
|
|
285
|
-
setApplyEditHandler(handler: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult): void;
|
|
286
|
+
setApplyEditHandler(handler: (params: ApplyWorkspaceEditParams) => ApplyWorkspaceEditResult | Promise<ApplyWorkspaceEditResult>): void;
|
|
286
287
|
|
|
287
288
|
/**
|
|
288
289
|
* Release every resource: the diagnostics and applyEdit subscriptions, the
|