diff --git a/packages/safe-ds-vscode/package.json b/packages/safe-ds-vscode/package.json index b2ac82208..44b3d9217 100644 --- a/packages/safe-ds-vscode/package.json +++ b/packages/safe-ds-vscode/package.json @@ -133,20 +133,30 @@ }, "commands": [ { - "command": "safe-ds.runPipelineFile", - "title": "Run Pipeline", - "category": "Safe-DS", - "icon": "$(play)" + "command": "safe-ds.dumpDiagnostics", + "title": "Dump Diagnostics to JSON", + "category": "Safe-DS" + }, + { + "command": "safe-ds.openDiagnosticsDumps", + "title": "Open Diagnostics Dumps in New VS Code Window", + "category": "Safe-DS" }, { "command": "safe-ds.refreshWebview", "title": "Refresh Webview", - "category": "EDA" + "category": "Safe-DS" }, { "command": "safe-ds.runEdaFromContext", "title": "Explore Table", - "category": "EDA" + "category": "Safe-DS" + }, + { + "command": "safe-ds.runPipelineFile", + "title": "Run Pipeline", + "category": "Safe-DS", + "icon": "$(play)" } ], "snippets": [ diff --git a/packages/safe-ds-vscode/src/extension/commands/dumpDiagnostics.ts b/packages/safe-ds-vscode/src/extension/commands/dumpDiagnostics.ts new file mode 100644 index 000000000..b39d89ae1 --- /dev/null +++ b/packages/safe-ds-vscode/src/extension/commands/dumpDiagnostics.ts @@ -0,0 +1,53 @@ +import vscode, { ExtensionContext, Uri } from 'vscode'; + +export const dumpDiagnostics = (context: ExtensionContext) => async () => { + // Get the current document + const currentDocument = vscode.window.activeTextEditor?.document; + if (!currentDocument) { + vscode.window.showErrorMessage('No active document.'); + return; + } else if (currentDocument.languageId !== 'safe-ds') { + vscode.window.showErrorMessage('The active document is not a Safe-DS document.'); + return; + } + + // Get diagnostics for the current document + const diagnostics = vscode.languages.getDiagnostics(currentDocument.uri); + if (diagnostics.length === 0) { + vscode.window.showErrorMessage('The active document has no diagnostics.'); + return; + } + + // Dump diagnostics to a file + const machineId = vscode.env.machineId; + const timestamp = new Date(); + const fileName = `${machineId}-${toBasicISOString(timestamp)}.json`; + const uri = vscode.Uri.joinPath(diagnosticsDumpsUri(context), fileName); + const content = JSON.stringify( + { + machineId, + timestamp: timestamp.toISOString(), + text: currentDocument.getText(), + diagnostics, + }, + null, + 2, + ); + + await vscode.workspace.fs.writeFile(uri, Buffer.from(content)); + + // Inform the user and ask for further action + const item = await vscode.window.showInformationMessage(`Diagnostics successfully dumped.`, 'Open file', 'Close'); + + if (item === 'Open file') { + vscode.window.showTextDocument(uri); + } +}; + +export const diagnosticsDumpsUri = (context: ExtensionContext): Uri => { + return vscode.Uri.joinPath(context.globalStorageUri, 'diagnosticsDumps'); +}; + +const toBasicISOString = (date: Date): string => { + return date.toISOString().replaceAll(/[-:]/gu, ''); +}; diff --git a/packages/safe-ds-vscode/src/extension/commands/openDiagnosticsDumps.ts b/packages/safe-ds-vscode/src/extension/commands/openDiagnosticsDumps.ts new file mode 100644 index 000000000..df049af46 --- /dev/null +++ b/packages/safe-ds-vscode/src/extension/commands/openDiagnosticsDumps.ts @@ -0,0 +1,7 @@ +import vscode, { ExtensionContext } from 'vscode'; +import { diagnosticsDumpsUri } from './dumpDiagnostics.js'; + +export const openDiagnosticsDumps = (context: ExtensionContext) => async () => { + const uri = diagnosticsDumpsUri(context); + vscode.commands.executeCommand('vscode.openFolder', uri, { forceNewWindow: true }); +}; diff --git a/packages/safe-ds-vscode/src/extension/mainClient.ts b/packages/safe-ds-vscode/src/extension/mainClient.ts index 801985e29..1b3e54d43 100644 --- a/packages/safe-ds-vscode/src/extension/mainClient.ts +++ b/packages/safe-ds-vscode/src/extension/mainClient.ts @@ -8,6 +8,8 @@ import { getSafeDSOutputChannel, initializeLog, logError, logOutput, printOutput import crypto from 'crypto'; import { LangiumDocument, URI } from 'langium'; import { EDAPanel, undefinedPanelIdentifier } from './eda/edaPanel.ts'; +import { dumpDiagnostics } from './commands/dumpDiagnostics.js'; +import { openDiagnosticsDumps } from './commands/openDiagnosticsDumps.js'; let client: LanguageClient; let services: SafeDsServices; @@ -153,6 +155,11 @@ const registerVSCodeCommands = function (context: vscode.ExtensionContext) { }); }; + context.subscriptions.push(vscode.commands.registerCommand('safe-ds.dumpDiagnostics', dumpDiagnostics(context))); + context.subscriptions.push( + vscode.commands.registerCommand('safe-ds.openDiagnosticsDumps', openDiagnosticsDumps(context)), + ); + context.subscriptions.push(vscode.commands.registerCommand('safe-ds.runPipelineFile', commandRunPipelineFile)); context.subscriptions.push(