Skip to content

Commit

Permalink
GLSP-1163: Fix deletion of nested elements
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-fleck-at authored Nov 16, 2023
2 parents 9f86a52 + 6fe5b13 commit 1a0997e
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 35 deletions.
1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"javascript",
"typescript"
],
"prettier.prettierPath": "node_modules/prettier",
"search.exclude": {
"**/node_modules": true,
"**/lib": true
Expand Down
14 changes: 7 additions & 7 deletions packages/server/src/common/features/model/gmodel-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import { GEdge, GModelElement, GModelElementConstructor, GModelRoot, GNode } from '@eclipse-glsp/graph';
import { GEdge, GModelElement, GModelElementConstructor, GModelRoot } from '@eclipse-glsp/graph';
import { TypeGuard } from '@eclipse-glsp/protocol';
import { injectable } from 'inversify';
import { getOrThrow, GLSPServerError } from '../../utils/glsp-server-error';
import { GLSPServerError, getOrThrow } from '../../utils/glsp-server-error';

/**
* Is used to index all child elements of a {@link GModelRoot} by their id. Offers a set
Expand Down Expand Up @@ -137,20 +137,20 @@ export class GModelIndex {
}

/**
* Returns all incoming edges for a node.
* Returns all incoming edges for a node (or port).
*
* @param node The node where the edges are connected.
* @param node The node (or port) where the edges are connected.
*
* @returns All incoming edges.
*/
getIncomingEdges(node: GNode): GEdge[] {
getIncomingEdges(node: GModelElement): GEdge[] {
return this.getAllEdges().filter(edge => edge.targetId === node.id);
}

/**
* Returns all outgoing edges for a node.
* Returns all outgoing edges for a node (or port).
*
* @param node The node where the edges are connected.
* @param node The node (or port) where the edges are connected.
*
* @returns All outgoing edges.
*/
Expand Down
42 changes: 15 additions & 27 deletions packages/server/src/common/gmodel/delete-operation-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import { GEdge, GModelElement, GNode } from '@eclipse-glsp/graph';
import { GModelElement, GNode, GPort } from '@eclipse-glsp/graph';
import { DeleteElementOperation, MaybePromise } from '@eclipse-glsp/protocol';
import { inject, injectable } from 'inversify';
import { Command } from '../command/command';
Expand Down Expand Up @@ -65,58 +65,46 @@ export class GModelDeleteOperationHandler extends GModelOperationHandler {
return false;
}

const nodeToDelete = this.findTopLevelElement(element);
if (!nodeToDelete.parent) {
this.logger.warn("The requested node doesn't have a parent; it can't be deleted");
if (!element.parent) {
this.logger.warn("The requested element doesn't have a parent; it can't be deleted");
return false;
}

const dependents = new Set<GModelElement>();
this.collectDependents(dependents, nodeToDelete, false);
this.collectDependents(dependents, element, false);

dependents.forEach(dependant => {
const index = this.modelState.root.children.findIndex(element => element === dependant);
const index = dependant.parent.children.findIndex(element => element === dependant);
if (index > -1) {
this.modelState.root.children.splice(index, 1);
dependant.parent.children.splice(index, 1);
}
this.allDependentsIds.add(dependant.id);
});

return true;
}

protected collectDependents(dependents: Set<GModelElement>, nodeToDelete: GModelElement, isChild: boolean): void {
if (dependents.has(nodeToDelete)) {
protected collectDependents(dependents: Set<GModelElement>, elementToDelete: GModelElement, isChild: boolean): void {
if (dependents.has(elementToDelete)) {
return;
}

if (nodeToDelete.children.length > 0) {
nodeToDelete.children.forEach(child => this.collectDependents(dependents, child, true));
if (elementToDelete.children.length > 0) {
elementToDelete.children.forEach(child => this.collectDependents(dependents, child, true));
}

if (nodeToDelete instanceof GNode) {
if (elementToDelete instanceof GNode || elementToDelete instanceof GPort) {
const index = this.modelState.index;

index.getIncomingEdges(nodeToDelete).forEach(incoming => {
index.getIncomingEdges(elementToDelete).forEach(incoming => {
dependents.add(incoming);
});
index.getOutgoingEdges(nodeToDelete).forEach(outgoing => {
index.getOutgoingEdges(elementToDelete).forEach(outgoing => {
dependents.add(outgoing);
});
}

dependents.add(nodeToDelete);
}

protected findTopLevelElement(element: GModelElement): GModelElement {
if (element instanceof GNode || element instanceof GEdge) {
return element;
}

const parent = element.parent;
if (!parent) {
return element;
if (!isChild) {
dependents.add(elementToDelete);
}
return this.findTopLevelElement(parent);
}
}

0 comments on commit 1a0997e

Please sign in to comment.