import path from 'node:path'; import * as vscode from 'vscode'; import { diagramFromTemplate, diagramName, invalidNameReason, modelFromTemplate, TEMPLATES } from '../language/templates'; import { diagramBaseName, isArchifyFile } from '../sources/detect'; import { readText } from '../util/files'; import { DIAGRAM_EDITOR_VIEW_TYPE } from '../views/diagramView'; import { CommandContext, exists } from './context'; /** Folder for a new diagram: the clicked folder (or a file's folder), else a workspace folder. */ async function newDiagramFolder(arg?: unknown): Promise { if (arg instanceof vscode.Uri) { const stat = await vscode.workspace.fs.stat(arg); return stat.type & vscode.FileType.Directory ? arg : vscode.Uri.joinPath(arg, '..'); } const folders = vscode.workspace.workspaceFolders ?? []; if (folders.length <= 1) return folders[0]?.uri; return (await vscode.window.showWorkspaceFolderPick({ placeHolder: 'Folder for the new diagram' }))?.uri; } export function newDiagramCommands(ctx: CommandContext): vscode.Disposable[] { return [ vscode.commands.registerCommand('archify.newDiagram', async (arg?: unknown) => { const template = await vscode.window.showQuickPick( TEMPLATES.map((item) => ({ label: item.label, description: item.description, template: item })), { title: 'Archify | New Diagram', placeHolder: 'Kind of diagram' }, ); if (!template) return; const { file, defaultName, fixedName } = template.template; const folder = await newDiagramFolder(arg); let target: vscode.Uri | undefined; if (folder && fixedName) { target = vscode.Uri.joinPath(folder, fixedName); if (await exists(target)) { vscode.window.showWarningMessage(`Archify: ${vscode.workspace.asRelativePath(folder, true)} already has a ${fixedName}.`); return; } } else if (folder) { const name = await vscode.window.showInputBox({ title: 'Archify | New Diagram', prompt: `File name in ${vscode.workspace.asRelativePath(folder, true)}`, value: defaultName, validateInput: async (value) => invalidNameReason(value) ?? ((await exists(vscode.Uri.joinPath(folder, `${diagramName(value)}.archify`))) ? `${diagramName(value)}.archify already exists.` : undefined), }); if (name === undefined) return; target = vscode.Uri.joinPath(folder, `${diagramName(name)}.archify`); } else { // No workspace: let the user choose where to save. target = await vscode.window.showSaveDialog({ title: 'Archify | New Diagram', filters: { 'Archify Diagram': ['archify'] }, saveLabel: 'Create', }); if (!target) return; if (!isArchifyFile(target.path)) target = target.with({ path: `${target.path}.archify` }); } const templateText = await readText(vscode.Uri.joinPath(ctx.extension.extensionUri, 'templates', file)); const text = fixedName ? modelFromTemplate(templateText, path.basename(path.dirname(target.fsPath))) : diagramFromTemplate(templateText, diagramBaseName(target.path)); await vscode.workspace.fs.writeFile(target, Buffer.from(text, 'utf8')); await vscode.commands.executeCommand('vscode.openWith', target, DIAGRAM_EDITOR_VIEW_TYPE); }), ]; }