|
16 | 16 | import { |
17 | 17 | Action, |
18 | 18 | ActionDispatcher, |
| 19 | + ActionHandler, |
19 | 20 | ActionHandlerRegistry, |
20 | 21 | Deferred, |
21 | 22 | EMPTY_ROOT, |
22 | 23 | GModelRoot, |
23 | 24 | IActionDispatcher, |
| 25 | + RejectAction, |
24 | 26 | RequestAction, |
25 | 27 | ResponseAction, |
26 | 28 | SetModelAction, |
27 | 29 | TYPES |
28 | 30 | } from '@eclipse-glsp/sprotty'; |
29 | 31 | import { inject, injectable } from 'inversify'; |
| 32 | +import * as sprotty from 'sprotty-protocol/lib/actions'; |
30 | 33 | import { GLSPActionHandlerRegistry } from './action-handler-registry'; |
31 | 34 | import { IGModelRootListener } from './editor-context-service'; |
32 | 35 | import { OptionalAction } from './model/glsp-model-source'; |
@@ -125,26 +128,96 @@ export class GLSPActionDispatcher extends ActionDispatcher implements IGModelRoo |
125 | 128 | return result; |
126 | 129 | } |
127 | 130 |
|
128 | | - protected override handleAction(action: Action): Promise<void> { |
| 131 | + protected override async handleAction(action: Action): Promise<void> { |
129 | 132 | if (ResponseAction.hasValidResponseId(action)) { |
130 | | - // clear timeout |
131 | | - const timeout = this.timeouts.get(action.responseId); |
132 | | - if (timeout !== undefined) { |
133 | | - clearTimeout(timeout); |
134 | | - this.timeouts.delete(action.responseId); |
135 | | - } |
| 133 | + return this.handleResponseAction(action); |
| 134 | + } |
| 135 | + if (OptionalAction.is(action) && !this.hasHandler(action)) { |
| 136 | + return Promise.resolve(); |
| 137 | + } |
| 138 | + if (sprotty.UndoAction.KIND === action.kind) { |
| 139 | + return this.handleUndoAction(action); |
| 140 | + } |
| 141 | + if (sprotty.RedoAction.KIND === action.kind) { |
| 142 | + return this.handleRedoAction(action); |
| 143 | + } |
| 144 | + return this.doHandleAction(action); |
| 145 | + } |
| 146 | + |
| 147 | + protected handleResponseAction(action: ResponseAction): Promise<void> { |
| 148 | + // clear any pending timeout |
| 149 | + const timeout = this.timeouts.get(action.responseId); |
| 150 | + if (timeout !== undefined) { |
| 151 | + clearTimeout(timeout); |
| 152 | + this.timeouts.delete(action.responseId); |
| 153 | + } |
136 | 154 |
|
137 | | - // Check if we have a pending request for the response. |
138 | | - // If not the we clear the responseId => action will be dispatched normally |
139 | | - const deferred = this.requests.get(action.responseId); |
140 | | - if (deferred === undefined) { |
141 | | - action.responseId = ''; |
| 155 | + // check for matching request |
| 156 | + const request = this.requests.get(action.responseId); |
| 157 | + if (!request) { |
| 158 | + // treat no matching request by dispatching action normally |
| 159 | + this.logger.log(this, 'No matching request for response, dispatch normally', action); |
| 160 | + action.responseId = ''; |
| 161 | + return this.handleAction(action); |
| 162 | + } |
| 163 | + |
| 164 | + this.requests.delete(action.responseId); |
| 165 | + if (RejectAction.is(action)) { |
| 166 | + // translation reject action to request rejection |
| 167 | + request.reject(new Error(action.message)); |
| 168 | + this.logger.warn(this, `Request with id ${action.responseId} failed.`, action.message, action.detail); |
| 169 | + } else { |
| 170 | + request.resolve(action); |
| 171 | + } |
| 172 | + return Promise.resolve(); |
| 173 | + } |
| 174 | + |
| 175 | + protected handleUndoAction(action: Action): Promise<void> { |
| 176 | + return this.commandStack.undo().then(() => {}); |
| 177 | + } |
| 178 | + |
| 179 | + protected handleRedoAction(action: Action): Promise<void> { |
| 180 | + return this.commandStack.redo().then(() => {}); |
| 181 | + } |
| 182 | + |
| 183 | + protected async doHandleAction(action: Action): Promise<void> { |
| 184 | + const handlers = this.actionHandlerRegistry.get(action.kind); |
| 185 | + if (handlers.length === 0) { |
| 186 | + return this.handleActionWithoutHandler(action); |
| 187 | + } else { |
| 188 | + return this.handlerActionWithHandler(action, handlers); |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + protected handleActionWithoutHandler(action: Action): Promise<void> { |
| 193 | + this.logger.warn(this, 'Missing handler for action', action); |
| 194 | + const error = new Error(`Missing handler for action '${action.kind}'`); |
| 195 | + if (RequestAction.is(action)) { |
| 196 | + const request = this.requests.get(action.requestId); |
| 197 | + if (request !== undefined) { |
| 198 | + this.requests.delete(action.requestId); |
| 199 | + request.reject(error); |
142 | 200 | } |
143 | 201 | } |
144 | | - if (!this.hasHandler(action) && OptionalAction.is(action)) { |
145 | | - return Promise.resolve(); |
| 202 | + return Promise.reject(error); |
| 203 | + } |
| 204 | + |
| 205 | + protected async handlerActionWithHandler(action: Action, handlers: ActionHandler[]): Promise<any> { |
| 206 | + this.logger.log(this, 'Handle', action); |
| 207 | + const handlerResults: Promise<any>[] = []; |
| 208 | + for (const handler of handlers) { |
| 209 | + const handlerResult = Promise.resolve(handler.handle(action)).then<any>(result => { |
| 210 | + if (Action.is(result)) { |
| 211 | + return this.dispatch(result); |
| 212 | + } else if (result !== undefined) { |
| 213 | + this.blockUntil = result.blockUntil; |
| 214 | + return this.commandStack.execute(result); |
| 215 | + } |
| 216 | + return undefined; |
| 217 | + }); |
| 218 | + handlerResults.push(handlerResult); |
146 | 219 | } |
147 | | - return super.handleAction(action); |
| 220 | + return Promise.all(handlerResults) as Promise<any>; |
148 | 221 | } |
149 | 222 |
|
150 | 223 | override request<Res extends ResponseAction>(action: RequestAction<Res>): Promise<Res> { |
|
0 commit comments