Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 20 additions & 26 deletions src/features/dfdElements/AssignmentLanguage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Token,
WordCompletion,
} from "../constraintMenu/AutoCompletion";
import { SModelElementImpl, SModelRootImpl, SParentElementImpl, SPortImpl } from "sprotty";
import { SModelElementImpl, SParentElementImpl, SPortImpl } from "sprotty";
import { LabelTypeRegistry } from "../labels/labelTypeRegistry";
import { DfdNodeImpl } from "./nodes";

Expand Down Expand Up @@ -148,14 +148,14 @@ export class ReplaceAutoCompleteTree extends AutoCompleteTree {

export namespace TreeBuilder {
export function buildTree(
model: SModelRootImpl,
labelTypeRegistry: LabelTypeRegistry,
port?: SPortImpl,
): AutoCompleteNode<WordOrReplacableWord>[] {
return [
buildSetOrUnsetStatement(labelTypeRegistry, "set"),
buildSetOrUnsetStatement(labelTypeRegistry, "unset"),
buildForwardStatement(model),
buildAssignStatement(labelTypeRegistry, model),
buildForwardStatement(port),
buildAssignStatement(labelTypeRegistry, port),
];
}

Expand All @@ -173,9 +173,9 @@ export namespace TreeBuilder {
};
}

function buildForwardStatement(model: SModelRootImpl) {
function buildForwardStatement(port?: SPortImpl) {
const inputNode: AutoCompleteNode = {
word: new InputListWord(model),
word: new InputListWord(port),
children: [],
};
return {
Expand All @@ -186,20 +186,20 @@ export namespace TreeBuilder {

function buildAssignStatement(
labelTypeRegistry: LabelTypeRegistry,
model: SModelRootImpl,
port?: SPortImpl,
): AutoCompleteNode<WordOrReplacableWord> {
const fromNode: AutoCompleteNode = {
word: new ConstantWord("from"),
children: [
{
word: new InputListWord(model),
word: new InputListWord(port),
children: [],
},
],
};
const ifNode: AutoCompleteNode = {
word: new ConstantWord("if"),
children: buildCondition(model, labelTypeRegistry, fromNode),
children: buildCondition(labelTypeRegistry, fromNode, port),
};
return {
word: new ConstantWord("assign"),
Expand All @@ -212,7 +212,7 @@ export namespace TreeBuilder {
};
}

function buildCondition(model: SModelRootImpl, labelTypeRegistry: LabelTypeRegistry, nextNode: AutoCompleteNode) {
function buildCondition(labelTypeRegistry: LabelTypeRegistry, nextNode: AutoCompleteNode, port?: SPortImpl) {
const connectors: AutoCompleteNode[] = ["&&", "||"].map((o) => ({
word: new ConstantWord(o),
children: [],
Expand All @@ -221,7 +221,7 @@ export namespace TreeBuilder {
const expressors: AutoCompleteNode[] = [
new ConstantWord("TRUE"),
new ConstantWord("FALSE"),
new InputLabelWord(model, labelTypeRegistry),
new InputLabelWord(labelTypeRegistry, port),
].map((e) => ({
word: e,
children: [...connectors, nextNode],
Expand All @@ -236,20 +236,14 @@ export namespace TreeBuilder {
}

abstract class InputAwareWord {
constructor(private model: SModelRootImpl) {}
constructor(private port?: SPortImpl) {}

protected getAvailableInputs(): string[] {
const selectedPorts = this.getSelectedPorts(this.model);
if (selectedPorts.length === 0) {
return [];
}
return selectedPorts.flatMap((port) => {
const parent = port.parent;
if (!(parent instanceof DfdNodeImpl)) {
return [];
}
const parent = this.port?.parent;
if (parent && parent instanceof DfdNodeImpl) {
return parent.getAvailableInputs().filter((input) => input !== undefined) as string[];
});
}
return [];
}

private getSelectedPorts(node: SModelElementImpl): SPortImpl[] {
Expand Down Expand Up @@ -386,8 +380,8 @@ class InputWord extends InputAwareWord implements ReplaceableAbstractWord {

class InputListWord implements ReplaceableAbstractWord {
private inputWord: InputWord;
constructor(model: SModelRootImpl) {
this.inputWord = new InputWord(model);
constructor(port?: SPortImpl) {
this.inputWord = new InputWord(port);
}

completionOptions(word: string): WordCompletion[] {
Expand Down Expand Up @@ -426,8 +420,8 @@ class InputLabelWord implements ReplaceableAbstractWord {
private inputWord: InputWord;
private labelWord: LabelWord;

constructor(model: SModelRootImpl, labelTypeRegistry: LabelTypeRegistry) {
this.inputWord = new InputWord(model);
constructor(labelTypeRegistry: LabelTypeRegistry, port?: SPortImpl) {
this.inputWord = new InputWord(port);
this.labelWord = new LabelWord(labelTypeRegistry);
}

Expand Down
7 changes: 2 additions & 5 deletions src/features/dfdElements/behaviorRefactorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
SEdgeImpl,
SLabelImpl,
SModelElementImpl,
SModelRootImpl,
SParentElementImpl,
TYPES,
} from "sprotty";
Expand Down Expand Up @@ -87,8 +86,8 @@ export class DFDBehaviorRefactorer {
this.logger.log(this, "Changed labels", changedLabels);

const model = await this.commandStack.executeAll([]);
const tree = new ReplaceAutoCompleteTree(TreeBuilder.buildTree(model, this.registry));
this.traverseDfdOutputPorts(model, (port) => {
const tree = new ReplaceAutoCompleteTree(TreeBuilder.buildTree(this.registry, port));
this.renameLabelsForPort(port, changedLabels, tree);
});

Expand Down Expand Up @@ -118,7 +117,6 @@ export class DFDBehaviorRefactorer {
port: DfdInputPortImpl,
oldLabelText: string,
newLabelText: string,
root: SModelRootImpl,
): Map<string, string> {
label.text = oldLabelText;
const oldInputName = port.getName();
Expand All @@ -131,7 +129,7 @@ export class DFDBehaviorRefactorer {
return behaviorChanges;
}

const tree = new ReplaceAutoCompleteTree(TreeBuilder.buildTree(root, this.registry));
const tree = new ReplaceAutoCompleteTree(TreeBuilder.buildTree(this.registry, port));

node.children.forEach((child) => {
if (!(child instanceof DfdOutputPortImpl)) {
Expand Down Expand Up @@ -209,7 +207,6 @@ export class RefactorInputNameInDFDBehaviorCommand extends Command {
port,
oldInputName,
newInputName,
context.root,
);
behaviorChanges.forEach((updatedBehavior, id) => {
const port = context.root.index.getById(id);
Expand Down
4 changes: 2 additions & 2 deletions src/features/dfdElements/elementStyles.css
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@
/* Ports */

.sprotty-port rect {
stroke: var(--color-foreground);
fill: color-mix(in srgb, var(--color-primary), var(--color-background) 25%);
stroke: var(--port-border, var(--color-foreground));
fill: color-mix(in srgb, var(--port-color, var(--color-primary)), var(--color-background) 25%);
stroke-width: 0.5;
}

Expand Down
2 changes: 1 addition & 1 deletion src/features/dfdElements/outputPortEditUi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ export class OutputPortEditUI extends AbstractUIExtension implements Switchable
readOnly: this.editorModeController?.isReadOnly() ?? false,
});

this.tree = new ReplaceAutoCompleteTree(TreeBuilder.buildTree(root, this.labelTypeRegistry));
this.tree = new ReplaceAutoCompleteTree(TreeBuilder.buildTree(this.labelTypeRegistry, this.port));

// Validation of loaded behavior text.
this.validateBehavior();
Expand Down
33 changes: 30 additions & 3 deletions src/features/dfdElements/ports.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ import {
} from "sprotty";
import { Bounds, SPort } from "sprotty-protocol";
import { injectable } from "inversify";
import { VNode } from "snabbdom";
import { VNode, VNodeStyle } from "snabbdom";
import { ArrowEdgeImpl } from "./edges";
import { AutoCompleteTree } from "../constraintMenu/AutoCompletion";
import { TreeBuilder } from "./AssignmentLanguage";
import { labelTypeRegistry } from "../..";

const defaultPortFeatures = [...SPortImpl.DEFAULT_FEATURES, moveFeature, deletableFeature];
const portSize = 7;
Expand Down Expand Up @@ -94,6 +97,12 @@ export class DfdOutputPortImpl extends SPortImpl {
static readonly DEFAULT_FEATURES = [...defaultPortFeatures, withEditLabelFeature];

behavior: string = "";
private tree: AutoCompleteTree;

constructor() {
super();
this.tree = new AutoCompleteTree(TreeBuilder.buildTree(labelTypeRegistry, this));
}

override get bounds(): Bounds {
return {
Expand All @@ -117,19 +126,37 @@ export class DfdOutputPortImpl extends SPortImpl {
// Only allow edges from this port outwards
return role === "source";
}

/**
* Generates the per-node inline style object for the view.
*/
geViewStyleObject(): VNodeStyle {
const style: VNodeStyle = {
opacity: this.opacity.toString(),
};
if (!labelTypeRegistry) return style;
const valid = this.tree.verify(this.behavior.split("\n")).length == 0;

if (!valid) {
style["--port-border"] = "#ff0000";
style["--port-color"] = "#ff6961";
}

return style;
}
}

@injectable()
export class DfdOutputPortView extends ShapeView {
render(node: Readonly<SPortImpl>, context: RenderingContext): VNode | undefined {
render(node: Readonly<DfdOutputPortImpl>, context: RenderingContext): VNode | undefined {
if (!this.isVisible(node, context)) {
return undefined;
}

const { width, height } = node.bounds;

return (
<g class-sprotty-port={true} class-selected={node.selected} style={{ opacity: node.opacity.toString() }}>
<g class-sprotty-port={true} class-selected={node.selected} style={node.geViewStyleObject()}>
<rect x="0" y="0" width={width} height={height} />
<text x={width / 2} y={height / 2} class-port-text={true}>
O
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { settingsModule } from "./features/settingsMenu/di.config";
import { LoadDiagramAction } from "./features/serialize/load";
import { commandPaletteModule } from "./features/commandPalette/di.config";
import { LoadingIndicator } from "./common/loadingIndicator";
import { LabelTypeRegistry } from "./features/labels/labelTypeRegistry";

const container = new Container();

Expand Down Expand Up @@ -77,6 +78,7 @@ export function setModelFileName(name: string): void {
export function getModelFileName(): string {
return modelFileName;
}
export const labelTypeRegistry = container.get<LabelTypeRegistry>(LabelTypeRegistry);

export function setModelSource(file: File): void {
modelSource
Expand Down