@hydranium/glsp-server 1.0.0-next.31 → 1.0.0-next.315
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 +80 -88
- package/lib/browser/start-glsp-server-in-worker.d.ts +43 -42
- package/lib/browser/start-glsp-server-in-worker.d.ts.map +1 -1
- package/lib/browser/start-glsp-server-in-worker.js +62 -13
- package/lib/browser/start-glsp-server-in-worker.js.map +1 -1
- package/lib/command/diagram-edit-dropped-error.d.ts +31 -0
- package/lib/command/diagram-edit-dropped-error.d.ts.map +1 -0
- package/lib/command/diagram-edit-dropped-error.js +48 -0
- package/lib/command/diagram-edit-dropped-error.js.map +1 -0
- package/lib/command/hydranium-glsp-command-stack.d.ts +33 -0
- package/lib/command/hydranium-glsp-command-stack.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-command-stack.js +63 -0
- package/lib/command/hydranium-glsp-command-stack.js.map +1 -0
- package/lib/command/hydranium-glsp-operation-action-handler.d.ts +64 -0
- package/lib/command/hydranium-glsp-operation-action-handler.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-operation-action-handler.js +142 -0
- package/lib/command/hydranium-glsp-operation-action-handler.js.map +1 -0
- package/lib/command/hydranium-glsp-operation-command.d.ts +250 -0
- package/lib/command/hydranium-glsp-operation-command.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-operation-command.js +491 -0
- package/lib/command/hydranium-glsp-operation-command.js.map +1 -0
- package/lib/command/hydranium-glsp-recording-command.d.ts +26 -87
- package/lib/command/hydranium-glsp-recording-command.d.ts.map +1 -1
- package/lib/command/hydranium-glsp-recording-command.js +40 -117
- package/lib/command/hydranium-glsp-recording-command.js.map +1 -1
- package/lib/command/hydranium-glsp-undo-redo-action-handler.d.ts +23 -0
- package/lib/command/hydranium-glsp-undo-redo-action-handler.d.ts.map +1 -0
- package/lib/command/hydranium-glsp-undo-redo-action-handler.js +41 -0
- package/lib/command/hydranium-glsp-undo-redo-action-handler.js.map +1 -0
- package/lib/command/index.d.ts +5 -0
- package/lib/command/index.d.ts.map +1 -1
- package/lib/command/index.js +5 -0
- package/lib/command/index.js.map +1 -1
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts +1 -1
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.d.ts.map +1 -1
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js +2 -2
- package/lib/computed-bounds/hydranium-glsp-computed-bounds-action-handler.js.map +1 -1
- package/lib/dispatcher/server-action-dispatcher.d.ts +25 -24
- package/lib/dispatcher/server-action-dispatcher.d.ts.map +1 -1
- package/lib/dispatcher/server-action-dispatcher.js +38 -26
- package/lib/dispatcher/server-action-dispatcher.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts +35 -59
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.d.ts.map +1 -1
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.js +60 -71
- package/lib/launcher/abstract-hydranium-glsp-diagram-module.js.map +1 -1
- package/lib/launcher/drop-notifications-to-gone-client.d.ts +23 -0
- package/lib/launcher/drop-notifications-to-gone-client.d.ts.map +1 -0
- package/lib/launcher/drop-notifications-to-gone-client.js +43 -0
- package/lib/launcher/drop-notifications-to-gone-client.js.map +1 -0
- package/lib/launcher/glsp-app-module.d.ts +1 -2
- package/lib/launcher/glsp-app-module.d.ts.map +1 -1
- package/lib/launcher/glsp-app-module.js.map +1 -1
- package/lib/launcher/glsp-connection-logger.d.ts +19 -0
- package/lib/launcher/glsp-connection-logger.d.ts.map +1 -0
- package/lib/launcher/glsp-connection-logger.js +24 -0
- package/lib/launcher/glsp-connection-logger.js.map +1 -0
- package/lib/launcher/glsp-server-overrides.d.ts +10 -8
- package/lib/launcher/glsp-server-overrides.d.ts.map +1 -1
- package/lib/launcher/glsp-server-overrides.js +25 -11
- package/lib/launcher/glsp-server-overrides.js.map +1 -1
- package/lib/launcher/hydranium-glsp-server.d.ts +60 -15
- package/lib/launcher/hydranium-glsp-server.d.ts.map +1 -1
- package/lib/launcher/hydranium-glsp-server.js +145 -22
- package/lib/launcher/hydranium-glsp-server.js.map +1 -1
- package/lib/launcher/index.d.ts +2 -0
- package/lib/launcher/index.d.ts.map +1 -1
- package/lib/launcher/index.js +5 -4
- package/lib/launcher/index.js.map +1 -1
- package/lib/logging/glsp-client-logger.d.ts +10 -6
- package/lib/logging/glsp-client-logger.d.ts.map +1 -1
- package/lib/logging/glsp-client-logger.js +14 -7
- package/lib/logging/glsp-client-logger.js.map +1 -1
- package/lib/messages/index.d.ts +11 -6
- package/lib/messages/index.d.ts.map +1 -1
- package/lib/messages/index.js +11 -6
- package/lib/messages/index.js.map +1 -1
- package/lib/node/start-glsp-server.d.ts +50 -15
- package/lib/node/start-glsp-server.d.ts.map +1 -1
- package/lib/node/start-glsp-server.js +97 -30
- package/lib/node/start-glsp-server.js.map +1 -1
- package/lib/state/abstract-hydranium-glsp-state.d.ts +326 -102
- package/lib/state/abstract-hydranium-glsp-state.d.ts.map +1 -1
- package/lib/state/abstract-hydranium-glsp-state.js +529 -139
- package/lib/state/abstract-hydranium-glsp-state.js.map +1 -1
- package/lib/state/diagram-status.d.ts +38 -0
- package/lib/state/diagram-status.d.ts.map +1 -0
- package/lib/state/diagram-status.js +27 -0
- package/lib/state/diagram-status.js.map +1 -0
- package/lib/state/full-text-hydranium-glsp-state.d.ts +22 -9
- package/lib/state/full-text-hydranium-glsp-state.d.ts.map +1 -1
- package/lib/state/full-text-hydranium-glsp-state.js +45 -18
- package/lib/state/full-text-hydranium-glsp-state.js.map +1 -1
- package/lib/state/hydranium-glsp-index.d.ts +40 -29
- package/lib/state/hydranium-glsp-index.d.ts.map +1 -1
- package/lib/state/hydranium-glsp-index.js +82 -45
- package/lib/state/hydranium-glsp-index.js.map +1 -1
- package/lib/state/hydranium-shared-core-services.d.ts +16 -29
- package/lib/state/hydranium-shared-core-services.d.ts.map +1 -1
- package/lib/state/hydranium-shared-core-services.js +15 -28
- package/lib/state/hydranium-shared-core-services.js.map +1 -1
- package/lib/state/index.d.ts +1 -0
- package/lib/state/index.d.ts.map +1 -1
- package/lib/state/index.js +1 -0
- package/lib/state/index.js.map +1 -1
- package/lib/state/model-ready-timeout-error.d.ts.map +1 -1
- package/lib/state/model-ready-timeout-error.js.map +1 -1
- package/lib/state/reconcile-source-model-write.d.ts +13 -27
- package/lib/state/reconcile-source-model-write.d.ts.map +1 -1
- package/lib/state/reconcile-source-model-write.js +44 -32
- package/lib/state/reconcile-source-model-write.js.map +1 -1
- package/lib/state/reconciling-multi-document-glsp-state.d.ts +125 -69
- package/lib/state/reconciling-multi-document-glsp-state.d.ts.map +1 -1
- package/lib/state/reconciling-multi-document-glsp-state.js +242 -100
- package/lib/state/reconciling-multi-document-glsp-state.js.map +1 -1
- package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts +36 -28
- package/lib/state/reconciling-transfer-hydranium-glsp-state.d.ts.map +1 -1
- package/lib/state/reconciling-transfer-hydranium-glsp-state.js +59 -42
- package/lib/state/reconciling-transfer-hydranium-glsp-state.js.map +1 -1
- package/lib/status/diagram-status-reporter.d.ts +44 -0
- package/lib/status/diagram-status-reporter.d.ts.map +1 -0
- package/lib/status/diagram-status-reporter.js +88 -0
- package/lib/status/diagram-status-reporter.js.map +1 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.d.ts +27 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.d.ts.map +1 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.js +52 -0
- package/lib/status/hydranium-glsp-request-model-action-handler.js.map +1 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.d.ts +27 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.d.ts.map +1 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.js +53 -0
- package/lib/status/hydranium-glsp-set-edit-mode-action-handler.js.map +1 -0
- package/lib/status/index.d.ts +12 -0
- package/lib/status/index.d.ts.map +1 -0
- package/lib/status/index.js +12 -0
- package/lib/status/index.js.map +1 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.d.ts +30 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.d.ts.map +1 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.js +47 -0
- package/lib/storage/hydranium-glsp-request-save-model-action-handler.js.map +1 -0
- package/lib/storage/hydranium-glsp-storage.d.ts +324 -143
- package/lib/storage/hydranium-glsp-storage.d.ts.map +1 -1
- package/lib/storage/hydranium-glsp-storage.js +569 -213
- package/lib/storage/hydranium-glsp-storage.js.map +1 -1
- package/lib/storage/index.d.ts +2 -1
- package/lib/storage/index.d.ts.map +1 -1
- package/lib/storage/index.js +2 -1
- package/lib/storage/index.js.map +1 -1
- package/lib/storage/save-delivery-policy.d.ts +51 -0
- package/lib/storage/save-delivery-policy.d.ts.map +1 -0
- package/lib/storage/{save-conflict-policy.js → save-delivery-policy.js} +7 -8
- package/lib/storage/save-delivery-policy.js.map +1 -0
- package/lib/submission/hydranium-glsp-submission-handler.d.ts +44 -4
- package/lib/submission/hydranium-glsp-submission-handler.d.ts.map +1 -1
- package/lib/submission/hydranium-glsp-submission-handler.js +82 -6
- package/lib/submission/hydranium-glsp-submission-handler.js.map +1 -1
- package/lib/testing/glsp-harness.d.ts +34 -7
- package/lib/testing/glsp-harness.d.ts.map +1 -1
- package/lib/testing/glsp-harness.js +47 -19
- package/lib/testing/glsp-harness.js.map +1 -1
- package/lib/validation/diagnostic-markers.d.ts +3 -3
- package/lib/validation/diagnostic-markers.d.ts.map +1 -1
- package/lib/validation/diagnostic-markers.js +1 -1
- package/lib/validation/diagnostic-markers.js.map +1 -1
- package/lib/validation/hydranium-glsp-model-validator.d.ts +1 -2
- package/lib/validation/hydranium-glsp-model-validator.d.ts.map +1 -1
- package/lib/validation/hydranium-glsp-model-validator.js +1 -1
- package/lib/validation/hydranium-glsp-model-validator.js.map +1 -1
- package/package.json +31 -52
- package/src/browser/start-glsp-server-in-worker.ts +79 -51
- package/src/command/diagram-edit-dropped-error.ts +51 -0
- package/src/command/hydranium-glsp-command-stack.ts +47 -0
- package/src/command/hydranium-glsp-operation-action-handler.ts +141 -0
- package/src/command/hydranium-glsp-operation-command.ts +602 -0
- package/src/command/hydranium-glsp-recording-command.ts +40 -121
- package/src/command/hydranium-glsp-undo-redo-action-handler.ts +29 -0
- package/src/command/index.ts +10 -0
- package/src/computed-bounds/hydranium-glsp-computed-bounds-action-handler.ts +2 -2
- package/src/dispatcher/server-action-dispatcher.ts +39 -31
- package/src/index.ts +1 -0
- package/src/launcher/abstract-hydranium-glsp-diagram-module.ts +79 -91
- package/src/launcher/drop-notifications-to-gone-client.ts +47 -0
- package/src/launcher/glsp-app-module.ts +1 -2
- package/src/launcher/glsp-connection-logger.ts +27 -0
- package/src/launcher/glsp-server-overrides.ts +27 -11
- package/src/launcher/hydranium-glsp-server.ts +153 -23
- package/src/launcher/index.ts +5 -4
- package/src/logging/glsp-client-logger.ts +16 -9
- package/src/messages/index.ts +16 -6
- package/src/node/start-glsp-server.ts +133 -40
- package/src/state/abstract-hydranium-glsp-state.ts +609 -154
- package/src/state/diagram-status.ts +41 -0
- package/src/state/full-text-hydranium-glsp-state.ts +46 -18
- package/src/state/hydranium-glsp-index.ts +85 -41
- package/src/state/hydranium-shared-core-services.ts +16 -29
- package/src/state/index.ts +1 -0
- package/src/state/reconcile-source-model-write.ts +51 -53
- package/src/state/reconciling-multi-document-glsp-state.ts +276 -102
- package/src/state/reconciling-transfer-hydranium-glsp-state.ts +67 -45
- package/src/status/diagram-status-reporter.ts +106 -0
- package/src/status/hydranium-glsp-request-model-action-handler.ts +43 -0
- package/src/status/hydranium-glsp-set-edit-mode-action-handler.ts +38 -0
- package/src/status/index.ts +12 -0
- package/src/storage/hydranium-glsp-request-save-model-action-handler.ts +40 -0
- package/src/storage/hydranium-glsp-storage.ts +647 -223
- package/src/storage/index.ts +2 -1
- package/src/storage/save-delivery-policy.ts +49 -0
- package/src/submission/hydranium-glsp-submission-handler.ts +91 -5
- package/src/testing/glsp-harness.ts +67 -25
- package/src/validation/diagnostic-markers.ts +3 -3
- package/src/validation/hydranium-glsp-model-validator.ts +4 -5
- package/lib/storage/save-conflict-policy.d.ts +0 -56
- package/lib/storage/save-conflict-policy.d.ts.map +0 -1
- package/lib/storage/save-conflict-policy.js.map +0 -1
- package/src/storage/save-conflict-policy.ts +0 -52
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
import { type JsonModelState } from '@eclipse-glsp/server';
|
|
11
11
|
import { injectable } from 'inversify';
|
|
12
12
|
import { type AstNode } from '@hydranium/langium';
|
|
13
|
-
import { type TransferElement } from '@hydranium/protocol';
|
|
13
|
+
import { type BaseVersion, type TransferElement, type VersionedModel } from '@hydranium/protocol';
|
|
14
|
+
import { type OperationTransition } from '../command/hydranium-glsp-operation-command.js';
|
|
14
15
|
import { AbstractHydraniumGlspState } from './abstract-hydranium-glsp-state.js';
|
|
15
16
|
import { reconcileSourceModelWrite } from './reconcile-source-model-write.js';
|
|
16
17
|
|
|
@@ -27,16 +28,16 @@ import { reconcileSourceModelWrite } from './reconcile-source-model-write.js';
|
|
|
27
28
|
* field-level shape is what lets `fast-json-patch` diff per field, so undo /
|
|
28
29
|
* redo and forward-write reconcile act per field instead of clobbering the
|
|
29
30
|
* whole document.
|
|
30
|
-
* - {@link
|
|
31
|
-
*
|
|
32
|
-
* intent (
|
|
31
|
+
* - {@link base} — the last in-sync projection, taken on every capture of
|
|
32
|
+
* the built root. A forward-write conflict reconciles the user's
|
|
33
|
+
* intent (base → ours) against the server's current root (theirs).
|
|
33
34
|
* - {@link updateSourceModel} — the concrete reconcile template: persist,
|
|
34
35
|
* and on a `ConflictError` consult the injected `conflictResolver` and act
|
|
35
|
-
* on
|
|
36
|
+
* on its outcome.
|
|
36
37
|
* - {@link persist} / {@link refetch} — the only I/O seams. Defaults route
|
|
37
|
-
* through `
|
|
38
|
-
*
|
|
39
|
-
*
|
|
38
|
+
* through the diagram session's `update` and `ModelService.validated`;
|
|
39
|
+
* adopters whose document round-trip differs override these without
|
|
40
|
+
* touching the orchestration.
|
|
40
41
|
*
|
|
41
42
|
* Adopters whose source model is whole-document text (a bare `{ text }`
|
|
42
43
|
* source model) or that are read-only do NOT extend this class — they extend
|
|
@@ -51,13 +52,10 @@ export class ReconcilingTransferHydraniumGlspState<TRoot extends AstNode, TSourc
|
|
|
51
52
|
implements JsonModelState<TSourceModel>
|
|
52
53
|
{
|
|
53
54
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* forward-write conflict reconciles against: it stays the pre-command
|
|
57
|
-
* state because operation handlers mutate `_sourceRoot` in place during
|
|
58
|
-
* `execute` while `setSourceRoot` only re-runs once the write commits.
|
|
55
|
+
* The projection a forward-write conflict reconciles the user's intent
|
|
56
|
+
* from, taken from the built root on every capture.
|
|
59
57
|
*/
|
|
60
|
-
protected
|
|
58
|
+
protected base!: TSourceModel;
|
|
61
59
|
|
|
62
60
|
/**
|
|
63
61
|
* Persisted-shape projection of the current source root, consumed by GLSP's
|
|
@@ -68,65 +66,89 @@ export class ReconcilingTransferHydraniumGlspState<TRoot extends AstNode, TSourc
|
|
|
68
66
|
* Synchronous — the encoder walks the in-memory AST without serialising.
|
|
69
67
|
*/
|
|
70
68
|
get sourceModel(): TSourceModel {
|
|
71
|
-
return this.
|
|
69
|
+
return this.projectRoot(this.sourceRoot);
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
/**
|
|
73
|
+
* The source model of `root`. The single projection seam: the source
|
|
74
|
+
* model, the refetch and {@link normalizeTransition} all project through it.
|
|
75
|
+
*/
|
|
76
|
+
protected projectRoot(root: AstNode): TSourceModel {
|
|
77
|
+
return this.sharedServices.model.TransferEncoder.toTransfer(root, 'grammar') as unknown as TSourceModel;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Both ends serialized for the source document and parsed back, unless they are equal. */
|
|
81
|
+
override async normalizeTransition(transition: OperationTransition<TSourceModel>): Promise<OperationTransition<TSourceModel>> {
|
|
82
|
+
if (JSON.stringify(transition.from) === JSON.stringify(transition.to)) {
|
|
83
|
+
return transition;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
from: this.projectRoot(await this.roundTrip(this._sourceUri, transition.from)),
|
|
87
|
+
to: this.projectRoot(await this.roundTrip(this._sourceUri, transition.to))
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
protected override captureSourceRoot(uri: string, root: TRoot): void {
|
|
92
|
+
super.captureSourceRoot(uri, root);
|
|
93
|
+
this.base = this.sourceModel;
|
|
77
94
|
}
|
|
78
95
|
|
|
79
96
|
/**
|
|
80
97
|
* Persist `model` back to the document store, then capture the resulting
|
|
81
|
-
* AST root. On a `ConflictError` (the
|
|
82
|
-
* reconcile the user's intent against the
|
|
98
|
+
* AST root. On a `ConflictError` (the base version was superseded),
|
|
99
|
+
* reconcile the user's intent against the server's current root via the bound
|
|
83
100
|
* `conflictResolver` and act on the outcome — one declarative policy
|
|
84
101
|
* (force = last-writer-wins, reconciling = field-level merge) shared with
|
|
85
102
|
* undo / redo.
|
|
86
103
|
*/
|
|
87
|
-
async updateSourceModel(model: TSourceModel,
|
|
104
|
+
async updateSourceModel(model: TSourceModel, baseVersion: BaseVersion = this.baseVersion): Promise<void> {
|
|
88
105
|
// Orchestration lives in `reconcileSourceModelWrite` so the multi-document
|
|
89
106
|
// state gets the identical conflict handling; this method supplies only
|
|
90
107
|
// the single-document meaning of persist / project.
|
|
91
|
-
return reconcileSourceModelWrite<TSourceModel>(model,
|
|
92
|
-
persist: async (candidate,
|
|
93
|
-
const { root } = await this.persist(candidate,
|
|
94
|
-
this.
|
|
108
|
+
return reconcileSourceModelWrite<TSourceModel>(model, baseVersion, {
|
|
109
|
+
persist: async (candidate, candidateBaseVersion) => {
|
|
110
|
+
const { root } = await this.persist(candidate, candidateBaseVersion);
|
|
111
|
+
this.captureWrittenRoot(root);
|
|
95
112
|
},
|
|
96
113
|
refetch: () => this.refetch(),
|
|
97
|
-
|
|
114
|
+
base: this.base,
|
|
98
115
|
conflictResolver: this.conflictResolver,
|
|
99
116
|
logger: this.logger,
|
|
100
|
-
onConflictDropped: () => this.
|
|
117
|
+
onConflictDropped: () => this.writeDropped(),
|
|
118
|
+
onAlreadyApplied: () => this.captureBuiltRoot(),
|
|
119
|
+
maxWrites: this.maxSourceModelWrites
|
|
101
120
|
});
|
|
102
121
|
}
|
|
103
122
|
|
|
104
123
|
/**
|
|
105
124
|
* Persist hook — the only write-side I/O. Default routes the structured
|
|
106
|
-
* model through `
|
|
107
|
-
* the `ConflictError` gate
|
|
108
|
-
*
|
|
125
|
+
* model through the diagram session's `update` (serialize → reparse),
|
|
126
|
+
* opting into the `ConflictError` gate unless `baseVersion` is `'any'`,
|
|
127
|
+
* and throws without a session. Adopters whose document
|
|
128
|
+
* round-trip differs override this, and {@link normalizeTransition}
|
|
129
|
+
* alongside so undo compares what this writes; the orchestration in
|
|
109
130
|
* {@link updateSourceModel} is unchanged.
|
|
110
131
|
*/
|
|
111
|
-
protected async persist(model: TSourceModel, baseVersion
|
|
112
|
-
const document = await this.
|
|
113
|
-
uri: this._sourceUri,
|
|
114
|
-
model,
|
|
115
|
-
clientId: this.clientId,
|
|
116
|
-
baseVersion
|
|
117
|
-
});
|
|
132
|
+
protected async persist(model: TSourceModel, baseVersion: BaseVersion): Promise<{ root: TRoot }> {
|
|
133
|
+
const document = await this.requireModelSession().update({ uri: this._sourceUri, model, baseVersion });
|
|
118
134
|
return document as unknown as { root: TRoot };
|
|
119
135
|
}
|
|
120
136
|
|
|
121
137
|
/**
|
|
122
|
-
* Refetch hook —
|
|
123
|
-
* projection (or `undefined` when
|
|
124
|
-
* replays the user's
|
|
125
|
-
*
|
|
126
|
-
* adopters override alongside
|
|
138
|
+
* Refetch hook — the stored text parsed afresh, as a persisted-shape
|
|
139
|
+
* projection with the version of that text (or `undefined` when
|
|
140
|
+
* unavailable): theirs, which the `conflictResolver` replays the user's
|
|
141
|
+
* intent onto. Default uses {@link AbstractHydraniumGlspState.readCurrentRoot}
|
|
142
|
+
* + the framework encoder's `'grammar'` mode; adopters override alongside
|
|
143
|
+
* {@link persist}.
|
|
127
144
|
*/
|
|
128
|
-
protected async refetch(): Promise<TSourceModel | undefined> {
|
|
129
|
-
const
|
|
130
|
-
return
|
|
145
|
+
protected async refetch(): Promise<VersionedModel<TSourceModel> | undefined> {
|
|
146
|
+
const theirs = await this.readCurrentRoot(this._sourceUri);
|
|
147
|
+
return (
|
|
148
|
+
theirs && {
|
|
149
|
+
model: this.projectRoot(theirs.root),
|
|
150
|
+
baseVersion: theirs.version
|
|
151
|
+
}
|
|
152
|
+
);
|
|
131
153
|
}
|
|
132
154
|
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, 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
|
+
import {
|
|
11
|
+
type Action,
|
|
12
|
+
ActionDispatcher,
|
|
13
|
+
type ClientSession,
|
|
14
|
+
type ClientSessionInitializer,
|
|
15
|
+
type ClientSessionListener,
|
|
16
|
+
ClientSessionManager,
|
|
17
|
+
EditMode,
|
|
18
|
+
ModelState,
|
|
19
|
+
SetEditModeAction,
|
|
20
|
+
StatusAction
|
|
21
|
+
} from '@eclipse-glsp/server';
|
|
22
|
+
import { type AstNode } from '@hydranium/langium';
|
|
23
|
+
import { DisposableCollection, describeErrorWithStack } from '@hydranium/protocol';
|
|
24
|
+
import { inject, injectable } from 'inversify';
|
|
25
|
+
import { type AbstractHydraniumGlspState } from '../state/abstract-hydranium-glsp-state.js';
|
|
26
|
+
import { type DiagramStatusEntry } from '../state/diagram-status.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sends the client what {@link AbstractHydraniumGlspState.onStatusChanged}
|
|
30
|
+
* announces: the current status for its status overlay and the edit mode.
|
|
31
|
+
*
|
|
32
|
+
* The only sender of either action. A status or edit mode dispatched from
|
|
33
|
+
* anywhere else is overwritten by the next change, and the state's account of
|
|
34
|
+
* why the diagram is read-only no longer matches the client's.
|
|
35
|
+
*/
|
|
36
|
+
export interface DiagramStatusReporter extends ClientSessionInitializer {
|
|
37
|
+
/**
|
|
38
|
+
* The client switched itself to `editMode`, as GLSP's client does before it
|
|
39
|
+
* forwards an edit-mode request. Sends the effective mode back if it differs.
|
|
40
|
+
*/
|
|
41
|
+
clientEditModeChanged(editMode: EditMode): void;
|
|
42
|
+
}
|
|
43
|
+
export const DiagramStatusReporter = Symbol('DiagramStatusReporter');
|
|
44
|
+
|
|
45
|
+
@injectable()
|
|
46
|
+
export class DefaultDiagramStatusReporter implements DiagramStatusReporter, ClientSessionListener {
|
|
47
|
+
@inject(ModelState) protected readonly state!: AbstractHydraniumGlspState<AstNode, unknown>;
|
|
48
|
+
@inject(ActionDispatcher) protected readonly actionDispatcher!: ActionDispatcher;
|
|
49
|
+
@inject(ClientSessionManager) protected readonly sessionManager!: ClientSessionManager;
|
|
50
|
+
|
|
51
|
+
protected readonly toDispose = new DisposableCollection();
|
|
52
|
+
/** What the client shows; it starts editable with an empty overlay. */
|
|
53
|
+
protected sentStatus = statusKey(undefined);
|
|
54
|
+
protected sentEditMode: string = EditMode.EDITABLE;
|
|
55
|
+
|
|
56
|
+
initialize(): void {
|
|
57
|
+
this.sessionManager.addListener(this, this.state.clientId);
|
|
58
|
+
this.toDispose.push(this.state.onStatusChanged(() => this.send()));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
clientEditModeChanged(editMode: EditMode): void {
|
|
62
|
+
this.sentEditMode = editMode;
|
|
63
|
+
this.send();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
protected send(): void {
|
|
67
|
+
this.actionDispatcher
|
|
68
|
+
.dispatchAll(this.changedActions())
|
|
69
|
+
.catch((error: unknown) => this.state.logger.warn(`Could not send the diagram status: ${describeErrorWithStack(error)}`));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** The actions that bring the client up to date, recording them as sent. */
|
|
73
|
+
protected changedActions(): Action[] {
|
|
74
|
+
const actions: Action[] = [];
|
|
75
|
+
const current = this.state.currentStatus;
|
|
76
|
+
if (statusKey(current) !== this.sentStatus) {
|
|
77
|
+
this.sentStatus = statusKey(current);
|
|
78
|
+
actions.push(
|
|
79
|
+
current?.message === undefined
|
|
80
|
+
? // `NONE` is the client's spelling for "clear": an empty message at any
|
|
81
|
+
// other severity leaves an empty band with an icon on the canvas.
|
|
82
|
+
StatusAction.create('', { severity: 'NONE' })
|
|
83
|
+
: StatusAction.create(current.message, { severity: current.severity ?? 'INFO' })
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
if (this.state.editMode !== this.sentEditMode) {
|
|
87
|
+
this.sentEditMode = this.state.editMode;
|
|
88
|
+
actions.push(SetEditModeAction.create(this.state.editMode));
|
|
89
|
+
}
|
|
90
|
+
if (actions.length > 0) {
|
|
91
|
+
this.state.logger.debug(
|
|
92
|
+
`Sending status ${this.sentStatus} (from ${this.state.currentStatusSource ?? 'none'}); ` +
|
|
93
|
+
`edit mode ${this.sentEditMode} (held by ${this.state.readonlyStatuses.join(', ') || 'none'})`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
return actions;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
sessionDisposed(_clientSession: ClientSession): void {
|
|
100
|
+
this.toDispose.dispose();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function statusKey(entry: DiagramStatusEntry | undefined): string {
|
|
105
|
+
return entry?.message === undefined ? 'none' : `${entry.severity ?? 'INFO'} "${entry.message}"`;
|
|
106
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, 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
|
+
import { ModelState, type ProgressMonitor, RequestModelActionHandler } from '@eclipse-glsp/server';
|
|
11
|
+
import { type AstNode } from '@hydranium/langium';
|
|
12
|
+
import { inject, injectable } from 'inversify';
|
|
13
|
+
import { type AbstractHydraniumGlspState } from '../state/abstract-hydranium-glsp-state.js';
|
|
14
|
+
import { DiagramStatus } from '../state/diagram-status.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Reports model loading as {@link DiagramStatus.MODEL_LOAD} rather than
|
|
18
|
+
* writing the client's status overlay directly, whose closing clear would
|
|
19
|
+
* erase a status set while the model loaded.
|
|
20
|
+
*
|
|
21
|
+
* The status is withdrawn on a failed load as well: GLSP rethrows from
|
|
22
|
+
* `handleModelLoadingError` before it reports the load finished, which would
|
|
23
|
+
* leave the loading message standing.
|
|
24
|
+
*/
|
|
25
|
+
@injectable()
|
|
26
|
+
export class HydraniumGlspRequestModelActionHandler extends RequestModelActionHandler {
|
|
27
|
+
@inject(ModelState) declare protected modelState: AbstractHydraniumGlspState<AstNode, unknown>;
|
|
28
|
+
|
|
29
|
+
protected override reportModelLoading(message: string): ProgressMonitor | undefined {
|
|
30
|
+
this.modelState.setStatus(DiagramStatus.MODEL_LOAD, { message, severity: 'INFO' });
|
|
31
|
+
return this.progressService.start(message);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
protected override reportModelLoadingFinished(monitor?: ProgressMonitor): void {
|
|
35
|
+
this.modelState.setStatus(DiagramStatus.MODEL_LOAD, undefined);
|
|
36
|
+
monitor?.end();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
protected override handleModelLoadingError(error: unknown, monitor?: ProgressMonitor): void {
|
|
40
|
+
this.modelState.setStatus(DiagramStatus.MODEL_LOAD, undefined);
|
|
41
|
+
super.handleModelLoadingError(error, monitor);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, 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
|
+
import { type Action, ClientAction, EditMode, ModelState, type SetEditModeAction, SetEditModeActionHandler } from '@eclipse-glsp/server';
|
|
11
|
+
import { type AstNode } from '@hydranium/langium';
|
|
12
|
+
import { inject, injectable } from 'inversify';
|
|
13
|
+
import { type AbstractHydraniumGlspState } from '../state/abstract-hydranium-glsp-state.js';
|
|
14
|
+
import { DiagramStatus } from '../state/diagram-status.js';
|
|
15
|
+
import { DiagramStatusReporter } from './diagram-status-reporter.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Records a client's request for a read-only diagram as
|
|
19
|
+
* {@link DiagramStatus.CLIENT_REQUEST}, instead of assigning the edit mode
|
|
20
|
+
* over every other status that holds it.
|
|
21
|
+
*
|
|
22
|
+
* Only an action the client sent counts. GLSP also runs this handler for the
|
|
23
|
+
* edit mode the server itself sends, and recording that as a request would
|
|
24
|
+
* keep the diagram read-only after its own reason has gone.
|
|
25
|
+
*/
|
|
26
|
+
@injectable()
|
|
27
|
+
export class HydraniumGlspSetEditModeActionHandler extends SetEditModeActionHandler {
|
|
28
|
+
@inject(ModelState) declare protected modelState: AbstractHydraniumGlspState<AstNode, unknown>;
|
|
29
|
+
@inject(DiagramStatusReporter) protected readonly reporter!: DiagramStatusReporter;
|
|
30
|
+
|
|
31
|
+
override async execute(action: SetEditModeAction): Promise<Action[]> {
|
|
32
|
+
if (ClientAction.is(action)) {
|
|
33
|
+
this.modelState.setStatus(DiagramStatus.CLIENT_REQUEST, action.editMode === EditMode.READONLY ? { readonly: true } : undefined);
|
|
34
|
+
this.reporter.clientEditModeChanged(action.editMode);
|
|
35
|
+
}
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, 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
|
+
export * from './diagram-status-reporter.js';
|
|
11
|
+
export * from './hydranium-glsp-request-model-action-handler.js';
|
|
12
|
+
export * from './hydranium-glsp-set-edit-mode-action-handler.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2026 CrossBreeze, 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
|
+
import { type Action, SaveModelAction, SaveModelActionHandler } from '@eclipse-glsp/server';
|
|
11
|
+
import { ModelSavedAction, RequestSaveModelAction } from '@hydranium/protocol';
|
|
12
|
+
import { injectable } from 'inversify';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Answers a {@link RequestSaveModelAction}: saves exactly as GLSP's
|
|
16
|
+
* {@link SaveModelActionHandler} saves a `SaveModelAction` carrying the same
|
|
17
|
+
* `fileUri`, dirty-state change included, then replies with a
|
|
18
|
+
* {@link ModelSavedAction}.
|
|
19
|
+
*
|
|
20
|
+
* A failed save throws, and the server turns the throw into a `RejectAction`
|
|
21
|
+
* for the request. The save handler's own `SaveModelAction` stays registered,
|
|
22
|
+
* so a client that sends it is unaffected.
|
|
23
|
+
*
|
|
24
|
+
* `AbstractHydraniumGlspDiagramModule` registers it. A diagram module that does
|
|
25
|
+
* not extend that base adds it in `configureActionHandlers`. Without it no
|
|
26
|
+
* handler is advertised for the request, and the Theia client saves as GLSP's
|
|
27
|
+
* saveable does: a save nothing answers, so a failed one surfaces only as a
|
|
28
|
+
* timeout, and a window can close over a save still under way.
|
|
29
|
+
*/
|
|
30
|
+
@injectable()
|
|
31
|
+
export class HydraniumGlspRequestSaveModelActionHandler extends SaveModelActionHandler {
|
|
32
|
+
override actionKinds = [RequestSaveModelAction.KIND];
|
|
33
|
+
|
|
34
|
+
// Typed `Action`, the one parameter type both this kind and the base's accept.
|
|
35
|
+
override async execute(action: Action): Promise<Action[]> {
|
|
36
|
+
const fileUri = 'fileUri' in action && typeof action.fileUri === 'string' ? action.fileUri : undefined;
|
|
37
|
+
const actions = await super.execute(SaveModelAction.create({ fileUri }));
|
|
38
|
+
return [...actions, ModelSavedAction.create()];
|
|
39
|
+
}
|
|
40
|
+
}
|