From c85553d41a87353e9d286610d0be1c695658a305 Mon Sep 17 00:00:00 2001 From: Jette Petzold Date: Mon, 25 Sep 2023 09:14:45 +0200 Subject: [PATCH] revision (extension) --- .../fta/analysis/fta-cutSet-calculator.ts | 6 +- .../fta/fta-message-handler.ts | 9 +- extension/src-language-server/fta/utils.ts | 23 ++-- extension/src-webview/stpa-views.tsx | 4 +- extension/src-webview/views-rendering.tsx | 81 ++++++------ extension/src/actions.ts | 2 +- extension/src/extension.ts | 119 +++++++++--------- extension/src/language-extension.ts | 4 +- extension/src/utils.ts | 25 +++- extension/src/wview.ts | 2 - 10 files changed, 145 insertions(+), 130 deletions(-) diff --git a/extension/src-language-server/fta/analysis/fta-cutSet-calculator.ts b/extension/src-language-server/fta/analysis/fta-cutSet-calculator.ts index 15816679..c103cb5c 100644 --- a/extension/src-language-server/fta/analysis/fta-cutSet-calculator.ts +++ b/extension/src-language-server/fta/analysis/fta-cutSet-calculator.ts @@ -34,9 +34,9 @@ import { namedFtaElement } from "../utils"; * @param allNodes All nodes in the fault tree. * @returns the minimal cut sets for a fault tree. */ -export function determineMinimalCutSet(allNodes: AstNode[]): Set[] { +export function determineMinimalCutSets(allNodes: AstNode[]): Set[] { // TODO: add minimal flag (could reduce computation cost) - const allCutSets = generateCutSetsForFT(allNodes); + const allCutSets = determineCutSetsForFT(allNodes); // Cut sets are minimal if removing one element destroys the cut set // If cut set contains another cut set from the array, remove it since it is not minimal @@ -71,7 +71,7 @@ function checkMinimalCutSet(cutSet: Set, allCutSets: Set[] { +export function determineCutSetsForFT(allNodes: AstNode[]): Set[] { /* Idea: Start from the top event. Get the only child of top event (will always be only one) as our starting node. diff --git a/extension/src-language-server/fta/fta-message-handler.ts b/extension/src-language-server/fta/fta-message-handler.ts index f121fc53..56839aa2 100644 --- a/extension/src-language-server/fta/fta-message-handler.ts +++ b/extension/src-language-server/fta/fta-message-handler.ts @@ -18,7 +18,7 @@ import { LangiumSprottySharedServices } from "langium-sprotty"; import { Connection } from "vscode-languageserver"; import { getFTAModel } from "../utils"; -import { determineMinimalCutSet, generateCutSetsForFT } from "./analysis/fta-cutSet-calculator"; +import { determineMinimalCutSets, determineCutSetsForFT } from "./analysis/fta-cutSet-calculator"; import { FtaServices } from "./fta-module"; import { cutSetsToString } from "./utils"; @@ -44,14 +44,13 @@ function addCutSetsHandler(connection: Connection, sharedServices: LangiumSprott connection.onRequest("generate/getCutSets", async (uri: string) => { const model = await getFTAModel(uri, sharedServices); const nodes = [model.topEvent, ...model.components, ...model.conditions, ...model.gates]; - const cutSets = generateCutSetsForFT(nodes); + const cutSets = determineCutSetsForFT(nodes); return cutSetsToString(cutSets); }); - connection.onRequest("generate/getMinimalCutSets", async (uri: string) => { const model = await getFTAModel(uri, sharedServices); const nodes = [model.topEvent, ...model.components, ...model.conditions, ...model.gates]; - const minimalCutSets = determineMinimalCutSet(nodes); - return cutSetsToString(minimalCutSets, true); + const minimalCutSets = determineMinimalCutSets(nodes); + return cutSetsToString(minimalCutSets); }); } diff --git a/extension/src-language-server/fta/utils.ts b/extension/src-language-server/fta/utils.ts index cd4e023d..b1524eab 100644 --- a/extension/src-language-server/fta/utils.ts +++ b/extension/src-language-server/fta/utils.ts @@ -20,17 +20,16 @@ import { Component, Condition, Gate, TopEvent } from "../generated/ast"; export type namedFtaElement = Component | Condition | Gate | TopEvent; /** - * Translates the given {@code cutSets} to a string. - * @param cutSets The cut sets to translate. - * @param minimal Determines whether the given {@code cutSets} are minimal. - * @returns a string that contains every cut set. + * Translates the cut sets in the given {@code cutSets} to lists. + * @param cutSets The list containing the cut sets to translate. + * @returns a list containing the cut sets in {@code cutSets} as a list. */ -export function cutSetsToString(cutSets: Set[], minimal?: boolean): string { - let text = `The resulting ${cutSets.length}`; - if (minimal) { - text += ` minimal`; +export function cutSetsToString(cutSets: Set[]): string[][] { + const result: string[][] = []; + for (const set of cutSets) { + const newSet: string[] = []; + set.forEach((element) => newSet.push(element.name)); + result.push(newSet); } - text += ` cut sets are:\n`; - text += `[${cutSets.map((cutSet) => `[${[...cutSet].map((element) => element.name).join(", ")}]`).join(",\n")}]`; - return text; -} \ No newline at end of file + return result; +} diff --git a/extension/src-webview/stpa-views.tsx b/extension/src-webview/stpa-views.tsx index b2204be9..3345d514 100644 --- a/extension/src-webview/stpa-views.tsx +++ b/extension/src-webview/stpa-views.tsx @@ -22,14 +22,12 @@ import { IView, IViewArgs, Point, PolylineEdgeView, RectangularNodeView, Renderi import { DISymbol } from './di.symbols'; import { collectAllChildren } from './helper-methods'; import { ColorStyleOption, DifferentFormsOption, RenderOptionsRegistry } from './options/render-options-registry'; -import { CSEdge, CS_EDGE_TYPE, CS_NODE_TYPE, EdgeType, PARENT_TYPE, STPAAspect, STPAEdge, STPANode, STPA_EDGE_TYPE, STPA_INTERMEDIATE_EDGE_TYPE, STPA_NODE_TYPE } from './stpa-model'; +import { CSEdge, CS_EDGE_TYPE, EdgeType, STPAAspect, STPAEdge, STPANode, STPA_EDGE_TYPE, STPA_INTERMEDIATE_EDGE_TYPE } from './stpa-model'; import { renderCircle, renderDiamond, renderHexagon, renderMirroredTriangle, renderPentagon, renderRectangle, renderRoundedRectangle, renderTrapez, renderTriangle } from './views-rendering'; - /** Determines if path/aspect highlighting is currently on. */ let highlighting: boolean; - @injectable() export class PolylineArrowEdgeView extends PolylineEdgeView { diff --git a/extension/src-webview/views-rendering.tsx b/extension/src-webview/views-rendering.tsx index fa5abdbf..bc978deb 100644 --- a/extension/src-webview/views-rendering.tsx +++ b/extension/src-webview/views-rendering.tsx @@ -3,7 +3,7 @@ * * http://rtsys.informatik.uni-kiel.de/kieler * - * Copyright 2021 by + * Copyright 2021-2023 by * + Kiel University * + Department of Computer Science * + Real-Time and Embedded Systems Group @@ -21,7 +21,7 @@ import { SNode, svg } from 'sprotty'; /** * Creates a circle for {@code node}. - * @param node The node whch should be represented by a circle. + * @param node The node that should be represented by a circle. * @returns A circle for {@code node}. */ export function renderCircle(node: SNode): VNode { @@ -33,7 +33,7 @@ export function renderCircle(node: SNode): VNode { /** * Creates a rectangle for {@code node}. - * @param node The node whch should be represented by a rectangle. + * @param node The node that should be represented by a rectangle. * @returns A rectangle for {@code node}. */ export function renderRectangle(node: SNode): VNode { @@ -45,7 +45,7 @@ export function renderRectangle(node: SNode): VNode { /** * Creates a rounded rectangle for {@code node}. - * @param node The node whch should be represented by a rounded rectangle. + * @param node The node that should be represented by a rounded rectangle. * @returns A rounded rectangle for {@code node}. */ export function renderRoundedRectangle(node: SNode): VNode { @@ -59,7 +59,7 @@ export function renderRoundedRectangle(node: SNode): VNode { /** * Creates a triangle for {@code node}. - * @param node The node whch should be represented by a triangle. + * @param node The node that should be represented by a triangle. * @returns A triangle for {@code node}. */ export function renderTriangle(node: SNode): VNode { @@ -76,7 +76,7 @@ export function renderTriangle(node: SNode): VNode { /** * Creates a mirrored triangle for {@code node}. - * @param node The node whch should be represented by a mirrored triangle. + * @param node The node that should be represented by a mirrored triangle. * @returns A mrrored triangle for {@code node}. */ export function renderMirroredTriangle(node: SNode): VNode { @@ -93,7 +93,7 @@ export function renderMirroredTriangle(node: SNode): VNode { /** * Creates a trapez for {@code node}. - * @param node The node whch should be represented by a trapez. + * @param node The node that should be represented by a trapez. * @returns A trapez for {@code node}. */ export function renderTrapez(node: SNode): VNode { @@ -112,7 +112,7 @@ export function renderTrapez(node: SNode): VNode { /** * Creates a diamond for {@code node}. - * @param node The node whch should be represented by a diamond. + * @param node The node that should be represented by a diamond. * @returns A diamond for {@code node}. */ export function renderDiamond(node: SNode): VNode { @@ -131,7 +131,7 @@ export function renderDiamond(node: SNode): VNode { /** * Creates a pentagon for {@code node}. - * @param node The node whch should be represented by a pentagon. + * @param node The node that should be represented by a pentagon. * @returns A pentagon for {@code node}. */ export function renderPentagon(node: SNode): VNode { @@ -152,7 +152,7 @@ export function renderPentagon(node: SNode): VNode { /** * Creates a hexagon for {@code node}. - * @param node The node whch should be represented by a hexagon. + * @param node The node that should be represented by a hexagon. * @returns A hexagon for {@code node}. */ export function renderHexagon(node: SNode): VNode { @@ -172,89 +172,88 @@ export function renderHexagon(node: SNode): VNode { /** * Creates an And-Gate for {@code node}. - * @param node The node whch should be represented by an And-Gate. + * @param node The node that should be represented by an And-Gate. * @returns An And-Gate for {@code node}. */ -export function renderAndGate(node:SNode): VNode{ +export function renderAndGate(node: SNode): VNode { const leftX = 0; const rightX = Math.max(node.size.width, 0); - const midX = Math.max(node.size.width, 0) / 2.0; const botY = Math.max(node.size.height, 0); const midY = Math.max(node.size.height, 0) / 2.0; const topY = 0; - const d = 'M' + leftX + " " + botY + " L " + leftX + " " + midY + " C " + leftX + " " + topY + " " + rightX + " " + topY + " " + rightX + " " + midY + - " L " + rightX + " " + botY + 'Z'; + const d = 'M' + leftX + " " + botY + " L " + leftX + " " + midY + " C " + leftX + " " + topY + " " + rightX + " " + + topY + " " + rightX + " " + midY + " L " + rightX + " " + botY + 'Z'; - return ; } /** * Creates an Or-Gate for {@code node}. - * @param node The node whch should be represented by an Or-Gate. + * @param node The node that should be represented by an Or-Gate. * @returns An Or-Gate for {@code node}. */ -export function renderOrGate(node:SNode): VNode{ +export function renderOrGate(node: SNode): VNode { const leftX = 0; const rightX = Math.max(node.size.width, 0); const midX = rightX / 2.0; const botY = Math.max(node.size.height, 0); - const nearBotY = Math.max(node.size.height, 0) - (Math.max(node.size.height, 0) / 10.0); + const nearBotY = Math.max(node.size.height, 0) - (Math.max(node.size.height, 0) / 10.0); const midY = Math.max(node.size.height, 0) / 2; const topY = 0; - const d = 'M' + leftX + " " + botY + " L " + leftX + " " + midY + " C " + midX + " " + topY + " "+ midX + " " + topY + " " + rightX + " " + midY + - " L " + rightX + " " + botY + " L " + midX + " " + nearBotY + " Z "; + const d = 'M' + leftX + " " + botY + " L " + leftX + " " + midY + " C " + midX + " " + topY + " " + midX + " " + + topY + " " + rightX + " " + midY + " L " + rightX + " " + botY + " L " + midX + " " + nearBotY + " Z "; return + d={d} + />; } /** * Creates an Kn-Gate for {@code node}. - * @param node The node whch should be represented by an Kn-Gate. + * @param node The node that should be represented by an Kn-Gate. * @returns An Kn-Gate for {@code node}. */ -export function renderKnGate(node:SNode, k:number, n:number): VNode{ +export function renderKnGate(node: SNode, k: number, n: number): VNode { const leftX = 0; const rightX = Math.max(node.size.width, 0); const midX = rightX / 2.0; const botY = Math.max(node.size.height, 0); - const nearBotY = Math.max(node.size.height, 0) - (Math.max(node.size.height, 0) / 10.0); + const nearBotY = Math.max(node.size.height, 0) - (Math.max(node.size.height, 0) / 10.0); const midY = Math.max(node.size.height, 0) / 2; const topY = 0; - const d = 'M' + leftX + " " + botY + " L " + leftX + " " + midY + " C " + midX + " " + topY + " "+ midX + " " + topY + " " + rightX + " " + midY + - " L " + rightX + " " + botY + " L " + midX + " " + nearBotY + " Z "; + const d = 'M' + leftX + " " + botY + " L " + leftX + " " + midY + " C " + midX + " " + topY + " " + midX + " " + + topY + " " + rightX + " " + midY + " L " + rightX + " " + botY + " L " + midX + " " + nearBotY + " Z "; return ( - - - {`${k}/${n}`} - + + + {`${k}/${n}`} + - ); + ); } /** * Creates an Inhibit-Gate for {@code node}. - * @param node The node whch should be represented by an Inhibit-Gate. + * @param node The node that should be represented by an Inhibit-Gate. * @returns An Inhibit-Gate for {@code node}. */ -export function renderInhibitGate(node:SNode): VNode{ +export function renderInhibitGate(node: SNode): VNode { const leftX = 0; - const midX = Math.max(node.size.width, 0) / 2.0 ; + const midX = Math.max(node.size.width, 0) / 2.0; const rightX = Math.max(node.size.width, 0); const lowestY = Math.max(node.size.height, 0); const lowY = Math.max(node.size.height, 0) - (Math.max(node.size.height, 0) / 4.0); const highY = Math.max(node.size.height, 0) / 4.0; const highestY = 0; - const d = 'M' + leftX + " " + lowY + " L " + leftX + " " + highY + " L " + midX + " " + highestY + " L " + rightX + " " + highY + - " L " + rightX + " " + lowY + " L " + midX + " " + lowestY + "Z"; + const d = 'M' + leftX + " " + lowY + " L " + leftX + " " + highY + " L " + midX + " " + highestY + " L " + rightX + + " " + highY + " L " + rightX + " " + lowY + " L " + midX + " " + lowestY + "Z"; return + d={d} + />; } \ No newline at end of file diff --git a/extension/src/actions.ts b/extension/src/actions.ts index 7313715a..24713be5 100644 --- a/extension/src/actions.ts +++ b/extension/src/actions.ts @@ -61,7 +61,7 @@ export namespace GenerateSVGsAction { } } -// TODO: better type for cut sets +// TODO: better type for cut sets? /** Contains the cut sets for a fault tree */ export interface SendCutSetAction extends Action { kind: typeof SendCutSetAction.KIND; diff --git a/extension/src/extension.ts b/extension/src/extension.ts index 6cda7cf9..2e63aca9 100644 --- a/extension/src/extension.ts +++ b/extension/src/extension.ts @@ -21,14 +21,14 @@ import { LspSprottyEditorProvider, LspSprottyViewProvider } from 'sprotty-vscode import * as vscode from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind } from 'vscode-languageclient/node'; import { Messenger } from 'vscode-messenger'; +import { SendCutSetAction } from './actions'; import { command } from './constants'; import { StpaLspVscodeExtension } from './language-extension'; -import { createOutputChannel, createQuickPickForWorkspaceOptions } from './utils'; import { createSTPAResultMarkdownFile } from './report/md-export'; -import { LTLFormula } from './sbm/utils'; -import { createSBMs } from './sbm/sbm-generation'; import { StpaResult } from './report/utils'; -import { SendCutSetAction } from './actions'; +import { createSBMs } from './sbm/sbm-generation'; +import { LTLFormula } from './sbm/utils'; +import { createOutputChannel, createQuickPickForWorkspaceOptions } from './utils'; let languageClient: LanguageClient; @@ -100,42 +100,51 @@ export async function deactivate(): Promise { function registerSTPACommands(manager: StpaLspVscodeExtension, context: vscode.ExtensionContext, options: { extensionPrefix: string; }): void { context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.contextTable.open', async (...commandArgs: any[]) => { - manager.createContextTable(context); - await manager.contextTable.ready(); - const uri = (commandArgs[0] as vscode.Uri).toString(); - languageClient.sendNotification('contextTable/getData', uri); - }) + vscode.commands.registerCommand( + options.extensionPrefix + ".contextTable.open", + async (...commandArgs: any[]) => { + manager.createContextTable(context); + await manager.contextTable.ready(); + const uri = (commandArgs[0] as vscode.Uri).toString(); + languageClient.sendNotification("contextTable/getData", uri); + } + ) ); // commands for toggling the provided validation checks context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.stpa.checks.setCheckResponsibilitiesForConstraints', async () => { - createQuickPickForWorkspaceOptions("checkResponsibilitiesForConstraints"); - }) + vscode.commands.registerCommand( + options.extensionPrefix + ".stpa.checks.setCheckResponsibilitiesForConstraints", + async () => { + createQuickPickForWorkspaceOptions("checkResponsibilitiesForConstraints"); + } + ) ); context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.stpa.checks.checkConstraintsForUCAs', async () => { + vscode.commands.registerCommand(options.extensionPrefix + ".stpa.checks.checkConstraintsForUCAs", async () => { createQuickPickForWorkspaceOptions("checkConstraintsForUCAs"); }) ); context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.stpa.checks.checkScenariosForUCAs', async () => { + vscode.commands.registerCommand(options.extensionPrefix + ".stpa.checks.checkScenariosForUCAs", async () => { createQuickPickForWorkspaceOptions("checkScenariosForUCAs"); }) ); context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.stpa.checks.checkSafetyRequirementsForUCAs', async () => { - createQuickPickForWorkspaceOptions("checkSafetyRequirementsForUCAs"); - }) + vscode.commands.registerCommand( + options.extensionPrefix + ".stpa.checks.checkSafetyRequirementsForUCAs", + async () => { + createQuickPickForWorkspaceOptions("checkSafetyRequirementsForUCAs"); + } + ) ); context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.IDs.undo', async () => { + vscode.commands.registerCommand(options.extensionPrefix + ".IDs.undo", async () => { manager.ignoreNextTextChange = true; vscode.commands.executeCommand("undo"); }) ); context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.IDs.redo', async () => { + vscode.commands.registerCommand(options.extensionPrefix + ".IDs.redo", async () => { manager.ignoreNextTextChange = true; vscode.commands.executeCommand("redo"); }) @@ -143,67 +152,65 @@ function registerSTPACommands(manager: StpaLspVscodeExtension, context: vscode.E // command for creating a pdf context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.stpa.md.creation', async (uri: vscode.Uri) => { - const data: StpaResult = await languageClient.sendRequest('result/getData', uri.toString()); + vscode.commands.registerCommand(options.extensionPrefix + ".stpa.md.creation", async (uri: vscode.Uri) => { + const data: StpaResult = await languageClient.sendRequest("result/getData", uri.toString()); await createSTPAResultMarkdownFile(data, manager); }) ); context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.stpa.SBM.generation', async (uri: vscode.Uri) => { + vscode.commands.registerCommand(options.extensionPrefix + ".stpa.SBM.generation", async (uri: vscode.Uri) => { await manager.lsReady; - const formulas: Record = await languageClient.sendRequest('verification/generateLTL', uri.path); + const formulas: Record = await languageClient.sendRequest( + "verification/generateLTL", + uri.path + ); // controlAction names are just the action without the controller as prefix // generate a safe behavioral model - const controlActions: Record = await languageClient.sendRequest('verification/getControlActions', uri.path); + const controlActions: Record = await languageClient.sendRequest( + "verification/getControlActions", + uri.path + ); createSBMs(controlActions, formulas); }) ); // register commands that other extensions can use - context.subscriptions.push(vscode.commands.registerCommand( - command.getLTLFormula, - async (uri: string) => { + context.subscriptions.push( + vscode.commands.registerCommand(command.getLTLFormula, async (uri: string) => { // generate and send back the LTLs based on the STPA UCAs await manager.lsReady; - const formulas: Record = await languageClient.sendRequest('verification/generateLTL', uri); + const formulas: Record = await languageClient.sendRequest( + "verification/generateLTL", + uri + ); return formulas; - } - )); + }) + ); // commands for computing and displaying the (minimal) cut sets of the fault tree. context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.fta.cutSets', async (uri: vscode.Uri) =>{ - const cutSets:string = await languageClient.sendRequest('generate/getCutSets', uri.path); - //Send cut sets to webview to display them in a dropdown menu. - dispatchCutSetsToWebview(manager, cutSets); - createOutputChannel(cutSets, "FTA Cut Sets"); + vscode.commands.registerCommand(options.extensionPrefix + ".fta.cutSets", async (uri: vscode.Uri) => { + const cutSets: string[][] = await languageClient.sendRequest("generate/getCutSets", uri.path); + handleCutSets(manager, cutSets, false); }) ); context.subscriptions.push( - vscode.commands.registerCommand(options.extensionPrefix + '.fta.minimalCutSets', async (uri: vscode.Uri) =>{ - const minimalCutSets:string = await languageClient.sendRequest('generate/getMinimalCutSets', uri.path); - dispatchCutSetsToWebview(manager, minimalCutSets); - createOutputChannel(minimalCutSets, "FTA Cut Sets"); + vscode.commands.registerCommand(options.extensionPrefix + ".fta.minimalCutSets", async (uri: vscode.Uri) => { + const minimalCutSets: string[][] = await languageClient.sendRequest("generate/getMinimalCutSets", uri.path); + handleCutSets(manager, minimalCutSets, true); }) - ); + ); } -// TODO: inspect -/** - * Sends the cut sets to webview as a SendCutSetAction so that they can be displayed in a dropdown menu. - * @param cutSets The (minimal) cut sets of the current Fault Tree. - */ -function dispatchCutSetsToWebview(manager: StpaLspVscodeExtension, cutSets:string):void{ - cutSets = cutSets.substring(cutSets.indexOf("[")); - cutSets = cutSets.slice(1,-2); - const cutSetArray = cutSets.split(",\n"); - - const cutSetsList: string[] = []; - for(const set of cutSetArray){ - cutSetsList.push(set); - } - manager.endpoints.find(endpoint => endpoint.diagramIdentifier?.diagramType === 'fta')?.sendAction({ kind: SendCutSetAction.KIND, cutSets: cutSetsList } as SendCutSetAction); +function handleCutSets(manager: StpaLspVscodeExtension, cutSets: string[][], minimal?: boolean): void { + const cutSetStrings = cutSets.map((cutSet) => `[${cutSet.join(", ")}]`); + // print cut sets to output channel + createOutputChannel(cutSetStrings, "FTA Cut Sets", minimal); + // send cut sets to the webview + manager.endpoints + .find((endpoint) => endpoint.diagramIdentifier?.diagramType === "fta") + ?.sendAction({ kind: SendCutSetAction.KIND, cutSets: cutSetStrings } as SendCutSetAction); } function createLanguageClient(context: vscode.ExtensionContext): LanguageClient { diff --git a/extension/src/language-extension.ts b/extension/src/language-extension.ts index f5426a06..6b20ab5e 100644 --- a/extension/src/language-extension.ts +++ b/extension/src/language-extension.ts @@ -100,8 +100,6 @@ export class StpaLspVscodeExtension extends LspWebviewPanelManager { }); } - - /** * Notifies the language server that a textdocument has changed. * @param changeEvent The change in the text document. @@ -116,7 +114,7 @@ export class StpaLspVscodeExtension extends LspWebviewPanelManager { const changes = changeEvent.contentChanges; const uri = changeEvent.document.uri.toString(); // TODO: ID enforcer for FTA - if (uri.endsWith('.stpa')){ + if (uri.endsWith(".stpa")) { this.languageClient.sendNotification("editor/textChange", { changes: changes, uri: uri }); } } diff --git a/extension/src/utils.ts b/extension/src/utils.ts index 6bd7aa8f..525ae85b 100644 --- a/extension/src/utils.ts +++ b/extension/src/utils.ts @@ -115,12 +115,29 @@ export class UCA_TYPE { } /** - * Creates an output channel with the given name and prints the given cut sets. + * Creates an output channel with the given name and prints the given cut sets. * @param cutSets The cut sets to print. * @param channelName The name of the channel. */ -export function createOutputChannel(cutSets:string, channelName:string):void{ +export function createOutputChannel(cutSets: string[], channelName: string, minimal?: boolean): void { + const text = cutSetsToString(cutSets, minimal); const outputCutSets = vscode.window.createOutputChannel(channelName); - outputCutSets.append(cutSets); + outputCutSets.append(text); outputCutSets.show(); -} \ No newline at end of file +} + +/** + * Translates the given {@code cutSets} to a string. + * @param cutSets The cut sets to translate. + * @param minimal Determines whether the given {@code cutSets} are minimal. + * @returns a string that contains every cut set. + */ +export function cutSetsToString(cutSets: string[], minimal?: boolean): string { + let text = `The resulting ${cutSets.length}`; + if (minimal) { + text += ` minimal`; + } + text += ` cut sets are:\n`; + text += `[${cutSets.join(",\n")}]`; + return text; +} diff --git a/extension/src/wview.ts b/extension/src/wview.ts index 3ad6567e..117eb755 100644 --- a/extension/src/wview.ts +++ b/extension/src/wview.ts @@ -33,7 +33,6 @@ export class StpaLspWebview extends LspWebviewEndpoint { case SelectAction.KIND: this.handleSelectAction(message.action as SelectAction); break; - } } return super.receiveAction(message); @@ -75,5 +74,4 @@ export class StpaLspWebview extends LspWebviewEndpoint { const configOptions = vscode.workspace.getConfiguration("pasta"); action.options.forEach((element) => configOptions.update(element.id, element.value)); } - }