@eclipse-glsp/server 1.1.0-next.3d7585d.42 → 1.1.0-next.44aae0c.44
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/common/command/command-stack.d.ts +45 -14
- package/lib/common/command/command-stack.d.ts.map +1 -1
- package/lib/common/command/command-stack.js +78 -9
- package/lib/common/command/command-stack.js.map +1 -1
- package/lib/common/command/command-stack.spec.d.ts +2 -0
- package/lib/common/command/command-stack.spec.d.ts.map +1 -0
- package/lib/common/command/command-stack.spec.js +207 -0
- package/lib/common/command/command-stack.spec.js.map +1 -0
- package/lib/common/command/command.d.ts +34 -7
- package/lib/common/command/command.d.ts.map +1 -1
- package/lib/common/command/command.js +73 -0
- package/lib/common/command/command.js.map +1 -1
- package/lib/common/command/command.spec.d.ts +2 -0
- package/lib/common/command/command.spec.d.ts.map +1 -0
- package/lib/common/command/command.spec.js +86 -0
- package/lib/common/command/command.spec.js.map +1 -0
- package/lib/common/command/recording-command.d.ts +75 -0
- package/lib/common/command/recording-command.d.ts.map +1 -0
- package/lib/common/command/recording-command.js +99 -0
- package/lib/common/command/recording-command.js.map +1 -0
- package/lib/common/command/recording-command.spec.d.ts +17 -0
- package/lib/common/command/recording-command.spec.d.ts.map +1 -0
- package/lib/common/command/recording-command.spec.js +62 -0
- package/lib/common/command/recording-command.spec.js.map +1 -0
- package/lib/common/command/undo-redo-action-handler.d.ts +28 -0
- package/lib/common/command/undo-redo-action-handler.d.ts.map +1 -0
- package/lib/common/command/undo-redo-action-handler.js +72 -0
- package/lib/common/command/undo-redo-action-handler.js.map +1 -0
- package/lib/common/di/diagram-module.d.ts +3 -0
- package/lib/common/di/diagram-module.d.ts.map +1 -1
- package/lib/common/di/diagram-module.js +12 -0
- package/lib/common/di/diagram-module.js.map +1 -1
- package/lib/common/features/contextactions/tool-palette-item-provider.d.ts +1 -1
- package/lib/common/features/contextactions/tool-palette-item-provider.d.ts.map +1 -1
- package/lib/common/features/contextactions/tool-palette-item-provider.js +2 -4
- package/lib/common/features/contextactions/tool-palette-item-provider.js.map +1 -1
- package/lib/common/{gmodel → features/layout}/computed-bounds-action-handler.d.ts +8 -3
- package/lib/common/features/layout/computed-bounds-action-handler.d.ts.map +1 -0
- package/lib/common/{gmodel → features/layout}/computed-bounds-action-handler.js +8 -3
- package/lib/common/features/layout/computed-bounds-action-handler.js.map +1 -0
- package/lib/common/features/layout/layout-operation-handler.d.ts +12 -3
- package/lib/common/features/layout/layout-operation-handler.d.ts.map +1 -1
- package/lib/common/features/layout/layout-operation-handler.js +26 -10
- package/lib/common/features/layout/layout-operation-handler.js.map +1 -1
- package/lib/common/features/model/model-state.d.ts +0 -2
- package/lib/common/features/model/model-state.d.ts.map +1 -1
- package/lib/common/features/model/model-state.js +0 -1
- package/lib/common/features/model/model-state.js.map +1 -1
- package/lib/common/features/model/model-submission-handler.d.ts +2 -0
- package/lib/common/features/model/model-submission-handler.d.ts.map +1 -1
- package/lib/common/features/model/model-submission-handler.js +7 -2
- package/lib/common/features/model/model-submission-handler.js.map +1 -1
- package/lib/common/features/model/save-model-action-handler.d.ts +2 -2
- package/lib/common/features/model/save-model-action-handler.d.ts.map +1 -1
- package/lib/common/features/model/save-model-action-handler.js +5 -5
- package/lib/common/features/model/save-model-action-handler.js.map +1 -1
- package/lib/common/gmodel/apply-label-edit-operation-handler.d.ts +4 -5
- package/lib/common/gmodel/apply-label-edit-operation-handler.d.ts.map +1 -1
- package/lib/common/gmodel/apply-label-edit-operation-handler.js +12 -21
- package/lib/common/gmodel/apply-label-edit-operation-handler.js.map +1 -1
- package/lib/common/gmodel/change-bounds-operation-handler.d.ts +9 -6
- package/lib/common/gmodel/change-bounds-operation-handler.d.ts.map +1 -1
- package/lib/common/gmodel/change-bounds-operation-handler.js +14 -14
- package/lib/common/gmodel/change-bounds-operation-handler.js.map +1 -1
- package/lib/common/gmodel/change-routing-points-operation-handler.d.ts +5 -5
- package/lib/common/gmodel/change-routing-points-operation-handler.d.ts.map +1 -1
- package/lib/common/gmodel/change-routing-points-operation-handler.js +11 -14
- package/lib/common/gmodel/change-routing-points-operation-handler.js.map +1 -1
- package/lib/common/{operations → gmodel}/cut-operation-handler.d.ts +5 -4
- package/lib/common/gmodel/cut-operation-handler.d.ts.map +1 -0
- package/lib/common/{operations → gmodel}/cut-operation-handler.js +13 -11
- package/lib/common/gmodel/cut-operation-handler.js.map +1 -0
- package/lib/common/gmodel/delete-operation-handler.d.ts +6 -6
- package/lib/common/gmodel/delete-operation-handler.d.ts.map +1 -1
- package/lib/common/gmodel/delete-operation-handler.js +13 -10
- package/lib/common/gmodel/delete-operation-handler.js.map +1 -1
- package/lib/common/gmodel/gmodel-create-edge-operation-handler.d.ts +11 -7
- package/lib/common/gmodel/gmodel-create-edge-operation-handler.d.ts.map +1 -1
- package/lib/common/gmodel/gmodel-create-edge-operation-handler.js +12 -13
- package/lib/common/gmodel/gmodel-create-edge-operation-handler.js.map +1 -1
- package/lib/common/gmodel/gmodel-create-node-operation-handler.d.ts +32 -5
- package/lib/common/gmodel/gmodel-create-node-operation-handler.d.ts.map +1 -1
- package/lib/common/gmodel/gmodel-create-node-operation-handler.js +45 -3
- package/lib/common/gmodel/gmodel-create-node-operation-handler.js.map +1 -1
- package/lib/common/gmodel/gmodel-diagram-module.d.ts +8 -8
- package/lib/common/gmodel/gmodel-diagram-module.d.ts.map +1 -1
- package/lib/common/gmodel/gmodel-diagram-module.js +15 -21
- package/lib/common/gmodel/gmodel-diagram-module.js.map +1 -1
- package/lib/common/gmodel/gmodel-operation-handler.d.ts +23 -0
- package/lib/common/gmodel/gmodel-operation-handler.d.ts.map +1 -0
- package/lib/common/gmodel/gmodel-operation-handler.js +43 -0
- package/lib/common/gmodel/gmodel-operation-handler.js.map +1 -0
- package/lib/common/gmodel/index.d.ts +2 -1
- package/lib/common/gmodel/index.d.ts.map +1 -1
- package/lib/common/gmodel/index.js +2 -1
- package/lib/common/gmodel/index.js.map +1 -1
- package/lib/common/gmodel/paste-operation-handler.d.ts +7 -6
- package/lib/common/gmodel/paste-operation-handler.d.ts.map +1 -1
- package/lib/common/gmodel/paste-operation-handler.js +20 -15
- package/lib/common/gmodel/paste-operation-handler.js.map +1 -1
- package/lib/common/gmodel/reconnect-edge-operation-handler.d.ts +5 -5
- package/lib/common/gmodel/reconnect-edge-operation-handler.d.ts.map +1 -1
- package/lib/common/gmodel/reconnect-edge-operation-handler.js +11 -14
- package/lib/common/gmodel/reconnect-edge-operation-handler.js.map +1 -1
- package/lib/common/index.d.ts +2 -1
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +2 -1
- package/lib/common/index.js.map +1 -1
- package/lib/common/operations/compound-operation-handler.d.ts +5 -5
- package/lib/common/operations/compound-operation-handler.d.ts.map +1 -1
- package/lib/common/operations/compound-operation-handler.js +37 -9
- package/lib/common/operations/compound-operation-handler.js.map +1 -1
- package/lib/common/operations/create-operation-handler.d.ts +8 -40
- package/lib/common/operations/create-operation-handler.d.ts.map +1 -1
- package/lib/common/operations/create-operation-handler.js +26 -85
- package/lib/common/operations/create-operation-handler.js.map +1 -1
- package/lib/common/operations/operation-action-handler.d.ts +10 -1
- package/lib/common/operations/operation-action-handler.d.ts.map +1 -1
- package/lib/common/operations/operation-action-handler.js +37 -22
- package/lib/common/operations/operation-action-handler.js.map +1 -1
- package/lib/common/operations/operation-handler-registry.d.ts +11 -2
- package/lib/common/operations/operation-handler-registry.d.ts.map +1 -1
- package/lib/common/operations/operation-handler-registry.js +31 -2
- package/lib/common/operations/operation-handler-registry.js.map +1 -1
- package/lib/common/operations/operation-handler.d.ts +28 -11
- package/lib/common/operations/operation-handler.d.ts.map +1 -1
- package/lib/common/operations/operation-handler.js +50 -1
- package/lib/common/operations/operation-handler.js.map +1 -1
- package/lib/common/test/mock-util.d.ts +14 -1
- package/lib/common/test/mock-util.d.ts.map +1 -1
- package/lib/common/test/mock-util.js +42 -37
- package/lib/common/test/mock-util.js.map +1 -1
- package/package.json +4 -3
- package/src/common/command/command-stack.spec.ts +239 -0
- package/src/common/command/command-stack.ts +106 -20
- package/src/common/command/command.spec.ts +92 -0
- package/src/common/command/command.ts +96 -7
- package/src/common/command/recording-command.spec.ts +74 -0
- package/src/common/command/recording-command.ts +119 -0
- package/src/common/command/undo-redo-action-handler.ts +57 -0
- package/src/common/di/diagram-module.ts +13 -0
- package/src/common/features/contextactions/tool-palette-item-provider.ts +2 -4
- package/src/common/{gmodel → features/layout}/computed-bounds-action-handler.ts +9 -4
- package/src/common/features/layout/layout-operation-handler.ts +26 -11
- package/src/common/features/model/model-state.ts +0 -3
- package/src/common/features/model/model-submission-handler.ts +6 -2
- package/src/common/features/model/save-model-action-handler.ts +5 -6
- package/src/common/gmodel/apply-label-edit-operation-handler.ts +13 -15
- package/src/common/gmodel/change-bounds-operation-handler.ts +12 -8
- package/src/common/gmodel/change-routing-points-operation-handler.ts +8 -7
- package/src/common/{operations → gmodel}/cut-operation-handler.ts +9 -8
- package/src/common/gmodel/delete-operation-handler.ts +16 -10
- package/src/common/gmodel/gmodel-create-edge-operation-handler.ts +16 -10
- package/src/common/gmodel/gmodel-create-node-operation-handler.ts +54 -6
- package/src/common/gmodel/gmodel-diagram-module.ts +22 -27
- package/src/common/gmodel/gmodel-operation-handler.ts +31 -0
- package/src/common/gmodel/index.ts +2 -1
- package/src/common/gmodel/paste-operation-handler.ts +19 -11
- package/src/common/gmodel/reconnect-edge-operation-handler.ts +8 -7
- package/src/common/index.ts +2 -1
- package/src/common/operations/compound-operation-handler.ts +14 -12
- package/src/common/operations/create-operation-handler.ts +17 -74
- package/src/common/operations/operation-action-handler.ts +51 -27
- package/src/common/operations/operation-handler-registry.ts +18 -3
- package/src/common/operations/operation-handler.ts +38 -13
- package/src/common/test/mock-util.ts +42 -36
- package/lib/common/gmodel/apply-label-edit-operation-handler.spec.d.ts +0 -2
- package/lib/common/gmodel/apply-label-edit-operation-handler.spec.d.ts.map +0 -1
- package/lib/common/gmodel/apply-label-edit-operation-handler.spec.js +0 -38
- package/lib/common/gmodel/apply-label-edit-operation-handler.spec.js.map +0 -1
- package/lib/common/gmodel/computed-bounds-action-handler.d.ts.map +0 -1
- package/lib/common/gmodel/computed-bounds-action-handler.js.map +0 -1
- package/lib/common/operations/cut-operation-handler.d.ts.map +0 -1
- package/lib/common/operations/cut-operation-handler.js.map +0 -1
- package/src/common/gmodel/apply-label-edit-operation-handler.spec.ts +0 -40
|
@@ -14,26 +14,115 @@
|
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
|
|
17
|
+
import { flatPush, MaybeArray, MaybePromise } from '@eclipse-glsp/protocol';
|
|
18
|
+
|
|
17
19
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
+
* A command implements a specific modification of the source model, which can be applied by invoking `execute()`.
|
|
21
|
+
* Commands may also provide implementations to `undo()` and `redo()` the effect they had.
|
|
22
|
+
* To maintain an order in which commands can be undone and redone, they are managed in the context of a {@link CommandStack}.
|
|
23
|
+
*
|
|
24
|
+
* Each command is self contained and stores all the information it needs to execute, undo or redo itself.
|
|
25
|
+
*
|
|
26
|
+
* In theory commands can be used to execute arbitrary activities and not only modify the source model.
|
|
27
|
+
* However, it is mostly used to record and manage changes made to the source model via GLSP operations.
|
|
20
28
|
*/
|
|
21
29
|
export interface Command {
|
|
22
30
|
/**
|
|
23
|
-
* Performs the command activity required for the effect.
|
|
31
|
+
* Performs the command activity required for the effect (e.g. source model change).
|
|
24
32
|
*/
|
|
25
|
-
execute(): void
|
|
33
|
+
execute(): MaybePromise<void>;
|
|
26
34
|
|
|
27
35
|
/**
|
|
28
36
|
* Performs the command activity required to `undo` the effects of a preceding `execute` (or `redo`).
|
|
29
37
|
* The effect, if any, of calling `undo` before `execute` or `redo` have been called, is undefined.
|
|
30
38
|
*/
|
|
31
|
-
undo(): void
|
|
39
|
+
undo(): MaybePromise<void>;
|
|
32
40
|
|
|
33
41
|
/**
|
|
34
42
|
* Performs the command activity required to `redo` the effect after undoing the effect.
|
|
35
43
|
* The effect, if any, of calling `redo` before `undo` is called is undefined.
|
|
36
|
-
* Note that if you implement `redo` to call `execute` then any derived class will be restricted by that decision also.
|
|
37
44
|
*/
|
|
38
|
-
redo(): void
|
|
45
|
+
redo(): MaybePromise<void>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns whether the command can be undone.
|
|
49
|
+
* This function is optional. If not implemented, it is assumed that the command can be undone.
|
|
50
|
+
* @returns whether the command can be undone
|
|
51
|
+
*/
|
|
52
|
+
canUndo?(): boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export namespace Command {
|
|
56
|
+
export function canUndo(command: Command): boolean {
|
|
57
|
+
return command.canUndo?.() ?? true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A command that comprises a sequence of subcommands.
|
|
63
|
+
*/
|
|
64
|
+
export class CompoundCommand implements Command {
|
|
65
|
+
protected readonly commands: Command[];
|
|
66
|
+
|
|
67
|
+
constructor(commands: Command[]);
|
|
68
|
+
constructor(...commands: Command[]);
|
|
69
|
+
constructor(...commands: MaybeArray<Command>[]) {
|
|
70
|
+
this.commands = [];
|
|
71
|
+
flatPush(this.commands, commands);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async execute(): Promise<void> {
|
|
75
|
+
const alreadyExecuted: Command[] = [];
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
for (const command of this.commands) {
|
|
79
|
+
await command.execute();
|
|
80
|
+
alreadyExecuted.unshift(command);
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
for (const command of alreadyExecuted) {
|
|
84
|
+
if (Command.canUndo(command)) {
|
|
85
|
+
await command.undo();
|
|
86
|
+
} else {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async undo(): Promise<void> {
|
|
95
|
+
const alreadyUndone: Command[] = [];
|
|
96
|
+
try {
|
|
97
|
+
for (const command of [...this.commands].reverse()) {
|
|
98
|
+
await command.undo();
|
|
99
|
+
alreadyUndone.unshift(command);
|
|
100
|
+
}
|
|
101
|
+
} catch (err) {
|
|
102
|
+
for (const command of alreadyUndone) {
|
|
103
|
+
await command.redo();
|
|
104
|
+
}
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async redo(): Promise<void> {
|
|
110
|
+
const alreadyRedone: Command[] = [];
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
for (const command of this.commands) {
|
|
114
|
+
await command.redo();
|
|
115
|
+
alreadyRedone.unshift(command);
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
for (const command of alreadyRedone) {
|
|
119
|
+
await command.undo();
|
|
120
|
+
}
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
canUndo(): boolean {
|
|
126
|
+
return this.commands.every(Command.canUndo);
|
|
127
|
+
}
|
|
39
128
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2023 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { AnyObject } from '@eclipse-glsp/protocol';
|
|
18
|
+
import { expect } from 'chai';
|
|
19
|
+
import { RecordingCommand } from './recording-command';
|
|
20
|
+
|
|
21
|
+
interface TestModel {
|
|
22
|
+
string: string;
|
|
23
|
+
number: number;
|
|
24
|
+
flag: boolean;
|
|
25
|
+
maybe?: AnyObject;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let jsonObject: TestModel;
|
|
29
|
+
|
|
30
|
+
describe('RecordingCommand', () => {
|
|
31
|
+
let beforeState: TestModel;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
jsonObject = {
|
|
35
|
+
string: 'foo',
|
|
36
|
+
number: 0,
|
|
37
|
+
flag: true
|
|
38
|
+
};
|
|
39
|
+
beforeState = JSON.parse(JSON.stringify(jsonObject));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should be undoable after execution', async () => {
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
44
|
+
const command = new RecordingCommand(jsonObject, () => {});
|
|
45
|
+
expect(command.canUndo()).to.be.false;
|
|
46
|
+
await command.execute();
|
|
47
|
+
expect(command.canUndo()).to.be.true;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should restore the pre execution state when undo is called', async () => {
|
|
51
|
+
const command = new RecordingCommand(jsonObject, () => {
|
|
52
|
+
jsonObject.string = 'bar';
|
|
53
|
+
jsonObject.flag = false;
|
|
54
|
+
jsonObject.maybe = { hello: 'world' };
|
|
55
|
+
});
|
|
56
|
+
await command.execute();
|
|
57
|
+
expect(jsonObject).to.not.be.deep.equals(beforeState);
|
|
58
|
+
await command.undo();
|
|
59
|
+
expect(jsonObject).to.be.deep.equals(beforeState);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should restore the post execution state when redo is called', async () => {
|
|
63
|
+
const command = new RecordingCommand(jsonObject, () => {
|
|
64
|
+
jsonObject.string = 'bar';
|
|
65
|
+
jsonObject.flag = false;
|
|
66
|
+
jsonObject.maybe = { hello: 'world' };
|
|
67
|
+
});
|
|
68
|
+
await command.execute();
|
|
69
|
+
const afterState = JSON.parse(JSON.stringify(jsonObject));
|
|
70
|
+
jsonObject = JSON.parse(JSON.stringify(afterState));
|
|
71
|
+
await command.redo();
|
|
72
|
+
expect(jsonObject).to.be.deep.equals(afterState);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2023 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { GModelRootSchema } from '@eclipse-glsp/graph';
|
|
18
|
+
import { AnyObject, MaybePromise } from '@eclipse-glsp/protocol';
|
|
19
|
+
import * as jsonPatch from 'fast-json-patch';
|
|
20
|
+
import { GModelSerializer } from '../features/model/gmodel-serializer';
|
|
21
|
+
import { ModelState } from '../features/model/model-state';
|
|
22
|
+
import { Command } from './command';
|
|
23
|
+
/**
|
|
24
|
+
* An abstract implementation for {@link Command} that should records changes made to a JSON object during execution.
|
|
25
|
+
* These changes are recorded in the form of json patches.
|
|
26
|
+
*/
|
|
27
|
+
export abstract class AbstractRecordingCommand<JsonObject extends AnyObject> implements Command {
|
|
28
|
+
protected undoPatch?: jsonPatch.Operation[];
|
|
29
|
+
protected redoPatch?: jsonPatch.Operation[];
|
|
30
|
+
|
|
31
|
+
async execute(): Promise<void> {
|
|
32
|
+
const beforeState = this.deepClone(this.getJsonObject());
|
|
33
|
+
await this.doExecute();
|
|
34
|
+
const afterState = this.getJsonObject();
|
|
35
|
+
this.undoPatch = jsonPatch.compare(afterState, beforeState);
|
|
36
|
+
this.redoPatch = jsonPatch.compare(beforeState, afterState);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Retrieves the current state of the JSON object. Is called right before and
|
|
41
|
+
* right after {@link AbstractRecordingCommand.doExecute} to derive the undo & redo patches.
|
|
42
|
+
* @returns The current state of the JSON object
|
|
43
|
+
*/
|
|
44
|
+
protected abstract getJsonObject(): JsonObject;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The actual execution i.e. series of changes applied to the JSOn object that should be captured.
|
|
48
|
+
*/
|
|
49
|
+
protected abstract doExecute(): MaybePromise<void>;
|
|
50
|
+
|
|
51
|
+
protected applyPatch(object: JsonObject, patch: jsonPatch.Operation[]): void {
|
|
52
|
+
jsonPatch.applyPatch(object, patch, false, true);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Captures the original state of the JSON object before executing the command routine.
|
|
57
|
+
* This implementation cannot clone circular structures as it relies on `JSON.stringify`.
|
|
58
|
+
* @param object The object that should be cloned
|
|
59
|
+
* @returns A deep clone of the given object
|
|
60
|
+
*/
|
|
61
|
+
protected deepClone(object: JsonObject): JsonObject {
|
|
62
|
+
return jsonPatch.deepClone(object);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
undo(): void {
|
|
66
|
+
if (this.undoPatch) {
|
|
67
|
+
this.applyPatch(this.getJsonObject(), this.undoPatch);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
redo(): void {
|
|
72
|
+
if (this.redoPatch) {
|
|
73
|
+
this.applyPatch(this.getJsonObject(), this.redoPatch);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
canUndo(): boolean {
|
|
78
|
+
return !!this.undoPatch && !!this.redoPatch;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Simple base implementation of {@link AbstractRecordingCommand} that records the changes made to the given JSON object during
|
|
84
|
+
* the the given `doExecute` function.
|
|
85
|
+
*/
|
|
86
|
+
export class RecordingCommand<JsonObject extends AnyObject = AnyObject> extends AbstractRecordingCommand<JsonObject> {
|
|
87
|
+
constructor(protected jsonObject: JsonObject, protected doExecute: () => MaybePromise<void>) {
|
|
88
|
+
super();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
protected getJsonObject(): JsonObject {
|
|
92
|
+
return this.jsonObject;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Simple base implementation of {@link AbstractRecordingCommand} that allows recording of changes made
|
|
98
|
+
* to the `GModelRoot` ({@link ModelState.root}) during the given `doExecute` function
|
|
99
|
+
*/
|
|
100
|
+
export class GModelRecordingCommand extends AbstractRecordingCommand<GModelRootSchema> {
|
|
101
|
+
constructor(protected modelState: ModelState, protected serializer: GModelSerializer, protected doExecute: () => MaybePromise<void>) {
|
|
102
|
+
super();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
override async execute(): Promise<void> {
|
|
106
|
+
await super.execute();
|
|
107
|
+
this.modelState.index.indexRoot(this.modelState.root);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
protected getJsonObject(): GModelRootSchema {
|
|
111
|
+
return this.serializer.createSchema(this.modelState.root);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
protected override applyPatch(rootSchema: GModelRootSchema, patch: jsonPatch.Operation[]): void {
|
|
115
|
+
super.applyPatch(rootSchema, patch);
|
|
116
|
+
const newRoot = this.serializer.createRoot(rootSchema);
|
|
117
|
+
this.modelState.updateRoot(newRoot);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2023 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { Action, MaybePromise, RedoAction, UndoAction } from '@eclipse-glsp/protocol';
|
|
18
|
+
import { inject, injectable } from 'inversify';
|
|
19
|
+
import { ActionHandler } from '../actions/action-handler';
|
|
20
|
+
import { ModelSubmissionHandler } from '../features/model/model-submission-handler';
|
|
21
|
+
import { CommandStack } from './command-stack';
|
|
22
|
+
|
|
23
|
+
@injectable()
|
|
24
|
+
export class UndoRedoActionHandler implements ActionHandler {
|
|
25
|
+
@inject(CommandStack)
|
|
26
|
+
protected commandStack: CommandStack;
|
|
27
|
+
|
|
28
|
+
@inject(ModelSubmissionHandler)
|
|
29
|
+
protected modelSubmissionHandler: ModelSubmissionHandler;
|
|
30
|
+
|
|
31
|
+
readonly actionKinds = [UndoAction.KIND, RedoAction.KIND];
|
|
32
|
+
|
|
33
|
+
execute(action: Action): MaybePromise<Action[]> {
|
|
34
|
+
if (UndoAction.is(action)) {
|
|
35
|
+
return this.undo();
|
|
36
|
+
} else if (RedoAction.is(action)) {
|
|
37
|
+
return this.redo();
|
|
38
|
+
}
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected async undo(): Promise<Action[]> {
|
|
43
|
+
if (this.commandStack.canUndo()) {
|
|
44
|
+
await this.commandStack.undo();
|
|
45
|
+
return this.modelSubmissionHandler.submitModel('undo');
|
|
46
|
+
}
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected async redo(): Promise<Action[]> {
|
|
51
|
+
if (this.commandStack.canRedo()) {
|
|
52
|
+
await this.commandStack.redo();
|
|
53
|
+
return this.modelSubmissionHandler.submitModel('redo');
|
|
54
|
+
}
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -48,6 +48,8 @@ import { ActionDispatcher, DefaultActionDispatcher } from '../actions/action-dis
|
|
|
48
48
|
import { ActionHandlerConstructor, ActionHandlerFactory } from '../actions/action-handler';
|
|
49
49
|
import { ActionHandlerRegistry, ActionHandlerRegistryInitializer } from '../actions/action-handler-registry';
|
|
50
50
|
import { ClientActionHandler } from '../actions/client-action-handler';
|
|
51
|
+
import { CommandStack, DefaultCommandStack } from '../command/command-stack';
|
|
52
|
+
import { UndoRedoActionHandler } from '../command/undo-redo-action-handler';
|
|
51
53
|
import { DiagramConfiguration } from '../diagram/diagram-configuration';
|
|
52
54
|
import { RequestTypeHintsActionHandler } from '../diagram/request-type-hints-action-handler';
|
|
53
55
|
import { CommandPaletteActionProvider } from '../features/contextactions/command-palette-action-provider';
|
|
@@ -63,7 +65,9 @@ import {
|
|
|
63
65
|
} from '../features/directediting/context-edit-validator-registry';
|
|
64
66
|
import { LabelEditValidator } from '../features/directediting/label-edit-validator';
|
|
65
67
|
import { RequestEditValidationHandler } from '../features/directediting/request-edit-validation-handler';
|
|
68
|
+
import { ComputedBoundsActionHandler } from '../features/layout/computed-bounds-action-handler';
|
|
66
69
|
import { LayoutEngine } from '../features/layout/layout-engine';
|
|
70
|
+
import { LayoutOperationHandler } from '../features/layout/layout-operation-handler';
|
|
67
71
|
import { GModelFactory } from '../features/model/gmodel-factory';
|
|
68
72
|
import { GModelIndex } from '../features/model/gmodel-index';
|
|
69
73
|
import { DefaultGModelSerializer, GModelSerializer } from '../features/model/gmodel-serializer';
|
|
@@ -137,6 +141,7 @@ import {
|
|
|
137
141
|
* - {@link OperationHandlerFactory}
|
|
138
142
|
* - {@link OperationHandlerRegistry}
|
|
139
143
|
* - {@link Operations}
|
|
144
|
+
* - {@link CommandStack}
|
|
140
145
|
* - {@link NavigationTargetResolver} as optional binding
|
|
141
146
|
* {@link NavigationTargetProvider} as {@link ClassMultiBinding<NavigationTargetProvider>} (empty)
|
|
142
147
|
* - {@link NavigationTargetProviderRegistry}
|
|
@@ -193,6 +198,7 @@ export abstract class DiagramModule extends GLSPModule {
|
|
|
193
198
|
applyBindingTarget(context, OperationHandlerRegistry, this.bindOperationHandlerRegistry()).inSingletonScope();
|
|
194
199
|
applyBindingTarget(context, OperationHandlerFactory, this.bindOperationHandlerFactory());
|
|
195
200
|
applyBindingTarget(context, Operations, this.bindOperations()).inSingletonScope();
|
|
201
|
+
applyBindingTarget(context, CommandStack, this.bindCommandStack()).inSingletonScope();
|
|
196
202
|
|
|
197
203
|
// Navigation
|
|
198
204
|
applyOptionalBindingTarget(context, NavigationTargetResolver, this.bindNavigationTargetResolver());
|
|
@@ -232,6 +238,8 @@ export abstract class DiagramModule extends GLSPModule {
|
|
|
232
238
|
binding.add(RequestNavigationTargetsActionHandler);
|
|
233
239
|
binding.add(ResolveNavigationTargetsActionHandler);
|
|
234
240
|
binding.add(SaveModelActionHandler);
|
|
241
|
+
binding.add(UndoRedoActionHandler);
|
|
242
|
+
binding.add(ComputedBoundsActionHandler);
|
|
235
243
|
}
|
|
236
244
|
|
|
237
245
|
protected bindDiagramType(): BindingTarget<string> {
|
|
@@ -291,8 +299,13 @@ export abstract class DiagramModule extends GLSPModule {
|
|
|
291
299
|
};
|
|
292
300
|
}
|
|
293
301
|
|
|
302
|
+
protected bindCommandStack(): BindingTarget<CommandStack> {
|
|
303
|
+
return DefaultCommandStack;
|
|
304
|
+
}
|
|
305
|
+
|
|
294
306
|
protected configureOperationHandlers(binding: InstanceMultiBinding<OperationHandlerConstructor>): void {
|
|
295
307
|
binding.add(CompoundOperationHandler);
|
|
308
|
+
binding.add(LayoutOperationHandler);
|
|
296
309
|
}
|
|
297
310
|
|
|
298
311
|
protected configureContextActionProviders(binding: MultiBinding<ContextActionsProvider>): void {
|
|
@@ -63,10 +63,8 @@ export class DefaultToolPaletteItemProvider extends ToolPaletteItemProvider {
|
|
|
63
63
|
@inject(OperationHandlerRegistry) operationHandlerRegistry: OperationHandlerRegistry;
|
|
64
64
|
protected counter: number;
|
|
65
65
|
|
|
66
|
-
getItems(
|
|
67
|
-
const handlers = this.operationHandlerRegistry
|
|
68
|
-
.getAll()
|
|
69
|
-
.filter(handler => handler instanceof CreateOperationHandler) as CreateOperationHandler[];
|
|
66
|
+
getItems(_args?: Args): PaletteItem[] {
|
|
67
|
+
const handlers = this.operationHandlerRegistry.getAll().filter(CreateOperationHandler.is) as CreateOperationHandler[];
|
|
70
68
|
this.counter = 0;
|
|
71
69
|
const nodes = this.createPaletteItem(handlers, CreateNodeOperation.KIND);
|
|
72
70
|
const edges = this.createPaletteItem(handlers, CreateEdgeOperation.KIND);
|
|
@@ -16,11 +16,16 @@
|
|
|
16
16
|
import { GModelRoot } from '@eclipse-glsp/graph';
|
|
17
17
|
import { Action, ComputedBoundsAction, MaybePromise } from '@eclipse-glsp/protocol';
|
|
18
18
|
import { inject, injectable } from 'inversify';
|
|
19
|
-
import { ActionHandler } from '
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
19
|
+
import { ActionHandler } from '../../actions/action-handler';
|
|
20
|
+
import { applyAlignment, applyBounds, applyRoute } from '../../utils/layout-util';
|
|
21
|
+
import { ModelState } from '../model/model-state';
|
|
22
|
+
import { ModelSubmissionHandler } from '../model/model-submission-handler';
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Syncs the bounds computed by the client (i.e. the actual bounds after applying CSS styles) back to the `GModel`.
|
|
26
|
+
* In this default implementation the updated bounds are stored transient. This means they are applied to the graphical model but
|
|
27
|
+
* are not persisted to the source model.
|
|
28
|
+
*/
|
|
24
29
|
@injectable()
|
|
25
30
|
export class ComputedBoundsActionHandler implements ActionHandler {
|
|
26
31
|
@inject(ModelSubmissionHandler)
|
|
@@ -13,15 +13,23 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import { LayoutOperation, Operation } from '@eclipse-glsp/protocol';
|
|
16
|
+
import { LayoutOperation, MaybePromise, Operation } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { inject, injectable, optional } from 'inversify';
|
|
18
|
+
import { Command } from '../../command/command';
|
|
19
|
+
import { GModelRecordingCommand } from '../../command/recording-command';
|
|
18
20
|
import { DiagramConfiguration, ServerLayoutKind } from '../../diagram/diagram-configuration';
|
|
19
21
|
import { OperationHandler } from '../../operations/operation-handler';
|
|
20
22
|
import { Logger } from '../../utils/logger';
|
|
23
|
+
import { GModelSerializer } from '../model/gmodel-serializer';
|
|
21
24
|
import { LayoutEngine } from './layout-engine';
|
|
22
25
|
|
|
26
|
+
/**
|
|
27
|
+
* The default handler for `{@link LayoutOperation}s. Does invoke the (optional) layout engine
|
|
28
|
+
* if the server is configured for manual layouting. Changes are stored transient in the graphical model and are not
|
|
29
|
+
* persisted in the source model.
|
|
30
|
+
*/
|
|
23
31
|
@injectable()
|
|
24
|
-
export class LayoutOperationHandler
|
|
32
|
+
export class LayoutOperationHandler extends OperationHandler {
|
|
25
33
|
@inject(Logger)
|
|
26
34
|
protected logger: Logger;
|
|
27
35
|
|
|
@@ -32,16 +40,23 @@ export class LayoutOperationHandler implements OperationHandler {
|
|
|
32
40
|
@inject(DiagramConfiguration)
|
|
33
41
|
protected diagramConfiguration: DiagramConfiguration;
|
|
34
42
|
|
|
43
|
+
@inject(GModelSerializer)
|
|
44
|
+
protected serializer: GModelSerializer;
|
|
45
|
+
|
|
35
46
|
readonly operationType = LayoutOperation.KIND;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
47
|
+
|
|
48
|
+
createCommand(operation: LayoutOperation): MaybePromise<Command | undefined> {
|
|
49
|
+
if (this.diagramConfiguration.layoutKind !== ServerLayoutKind.MANUAL) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
if (!this.layoutEngine) {
|
|
53
|
+
this.logger.warn('Could not execute layout operation. No `LayoutEngine` is bound!');
|
|
54
|
+
return undefined;
|
|
45
55
|
}
|
|
56
|
+
return new GModelRecordingCommand(this.modelState, this.serializer, () => this.executeOperation(operation));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected async executeOperation(_operation: Operation): Promise<void> {
|
|
60
|
+
await this.layoutEngine?.layout();
|
|
46
61
|
}
|
|
47
62
|
}
|
|
@@ -30,7 +30,6 @@ export interface ModelState {
|
|
|
30
30
|
readonly root: GModelRoot;
|
|
31
31
|
updateRoot(newRoot: GModelRoot): void;
|
|
32
32
|
editMode: string;
|
|
33
|
-
isDirty: boolean;
|
|
34
33
|
sourceUri?: string;
|
|
35
34
|
clientId: string;
|
|
36
35
|
readonly isReadonly: boolean;
|
|
@@ -56,8 +55,6 @@ export class DefaultModelState implements ModelState {
|
|
|
56
55
|
|
|
57
56
|
editMode = EditMode.EDITABLE;
|
|
58
57
|
|
|
59
|
-
isDirty = false;
|
|
60
|
-
|
|
61
58
|
set<P>(key: string, property: P): void {
|
|
62
59
|
this.properties.set(key, property);
|
|
63
60
|
}
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
UpdateModelAction
|
|
25
25
|
} from '@eclipse-glsp/protocol';
|
|
26
26
|
import { inject, injectable, optional } from 'inversify';
|
|
27
|
+
import { CommandStack } from '../../command/command-stack';
|
|
27
28
|
import { DiagramConfiguration, ServerLayoutKind } from '../../diagram/diagram-configuration';
|
|
28
29
|
import { LayoutEngine } from '../layout/layout-engine';
|
|
29
30
|
import { GModelFactory } from './gmodel-factory';
|
|
@@ -48,6 +49,9 @@ export class ModelSubmissionHandler {
|
|
|
48
49
|
@optional()
|
|
49
50
|
protected layoutEngine: LayoutEngine;
|
|
50
51
|
|
|
52
|
+
@inject(CommandStack)
|
|
53
|
+
protected commandStack: CommandStack;
|
|
54
|
+
|
|
51
55
|
/**
|
|
52
56
|
* Returns a list of actions to update the client-side model, based on the specified <code>modelState</code>.
|
|
53
57
|
*
|
|
@@ -63,7 +67,7 @@ export class ModelSubmissionHandler {
|
|
|
63
67
|
const root = this.serializeGModel();
|
|
64
68
|
|
|
65
69
|
if (this.diagramConfiguration.needsClientLayout) {
|
|
66
|
-
return [RequestBoundsAction.create(root), SetDirtyStateAction.create(this.
|
|
70
|
+
return [RequestBoundsAction.create(root), SetDirtyStateAction.create(this.commandStack.isDirty, { reason })];
|
|
67
71
|
}
|
|
68
72
|
return [SetModelAction.create(root)];
|
|
69
73
|
}
|
|
@@ -95,7 +99,7 @@ export class ModelSubmissionHandler {
|
|
|
95
99
|
: UpdateModelAction.create(root, { animate: this.diagramConfiguration.animatedUpdate })
|
|
96
100
|
);
|
|
97
101
|
if (!this.diagramConfiguration.needsClientLayout) {
|
|
98
|
-
result.push(SetDirtyStateAction.create(this.
|
|
102
|
+
result.push(SetDirtyStateAction.create(this.commandStack.isDirty, { reason }));
|
|
99
103
|
}
|
|
100
104
|
return result;
|
|
101
105
|
}
|
|
@@ -16,23 +16,22 @@
|
|
|
16
16
|
import { Action, SaveModelAction, SetDirtyStateAction } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { inject, injectable } from 'inversify';
|
|
18
18
|
import { ActionHandler } from '../../actions/action-handler';
|
|
19
|
-
import {
|
|
19
|
+
import { CommandStack } from '../../command/command-stack';
|
|
20
20
|
import { SourceModelStorage } from './source-model-storage';
|
|
21
21
|
|
|
22
22
|
@injectable()
|
|
23
23
|
export class SaveModelActionHandler implements ActionHandler {
|
|
24
24
|
actionKinds = [SaveModelAction.KIND];
|
|
25
25
|
|
|
26
|
-
@inject(
|
|
27
|
-
protected
|
|
26
|
+
@inject(CommandStack)
|
|
27
|
+
protected commandStack: CommandStack;
|
|
28
28
|
|
|
29
29
|
@inject(SourceModelStorage)
|
|
30
30
|
protected sourceModelStorage: SourceModelStorage;
|
|
31
31
|
|
|
32
32
|
async execute(action: SaveModelAction): Promise<Action[]> {
|
|
33
33
|
await this.sourceModelStorage.saveSourceModel(action);
|
|
34
|
-
this.
|
|
35
|
-
|
|
36
|
-
return [SetDirtyStateAction.create(this.modelState.isDirty, { reason: 'save' })];
|
|
34
|
+
this.commandStack.saveIsDone();
|
|
35
|
+
return [SetDirtyStateAction.create(this.commandStack.isDirty, { reason: 'save' })];
|
|
37
36
|
}
|
|
38
37
|
}
|
|
@@ -15,24 +15,22 @@
|
|
|
15
15
|
********************************************************************************/
|
|
16
16
|
import { GLabel } from '@eclipse-glsp/graph';
|
|
17
17
|
import { ApplyLabelEditOperation, MaybePromise } from '@eclipse-glsp/protocol';
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
18
|
+
import { injectable } from 'inversify';
|
|
19
|
+
import { Command } from '../command/command';
|
|
20
|
+
import { getOrThrow } from '../utils/glsp-server-error';
|
|
21
|
+
import { GModelOperationHandler } from './gmodel-operation-handler';
|
|
22
22
|
|
|
23
23
|
@injectable()
|
|
24
|
-
export class
|
|
24
|
+
export class GModelApplyLabelEditOperationHandler extends GModelOperationHandler {
|
|
25
25
|
readonly operationType = ApplyLabelEditOperation.KIND;
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
throw new GLSPServerError('Element with provided ID cannot be found or is not a GLabel');
|
|
36
|
-
}
|
|
27
|
+
createCommand(operation: ApplyLabelEditOperation): MaybePromise<Command | undefined> {
|
|
28
|
+
const label = getOrThrow(
|
|
29
|
+
this.modelState.index.findByClass(operation.labelId, GLabel),
|
|
30
|
+
'Element with provided ID cannot be found or is not a GLabel'
|
|
31
|
+
);
|
|
32
|
+
return label.text !== operation.text //
|
|
33
|
+
? this.commandOf(() => (label.text = operation.text))
|
|
34
|
+
: undefined;
|
|
37
35
|
}
|
|
38
36
|
}
|