From 1fd6c19cb345810e445f77e8084e6042d83a0590 Mon Sep 17 00:00:00 2001 From: Mathias Elle Date: Wed, 12 Aug 2026 17:07:03 +0200 Subject: [PATCH] feat: add inline commands for theme build and watch in the themes view fix: improve error handling with user-friendly messages in ThemesProvider --- package.json | 20 ++++++++++++++++++++ src/extension.ts | 14 +++++++++++++- src/magento.ts | 2 +- src/themesProvider.ts | 30 +++++++++++++++++++++++++++++- 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 4c4e456..7607104 100644 --- a/package.json +++ b/package.json @@ -106,6 +106,16 @@ "category": "MageForge", "icon": "$(eye)" }, + { + "command": "mageforge.theme.buildInline", + "title": "Build", + "category": "MageForge" + }, + { + "command": "mageforge.theme.watchInline", + "title": "Watch", + "category": "MageForge" + }, { "command": "mageforge.theme.clean", "title": "Theme: Clean", @@ -207,6 +217,16 @@ } ], "view/item/context": [ + { + "command": "mageforge.theme.buildInline", + "when": "view == mageforge.themes && viewItem == mageforgeTheme", + "group": "inline@1" + }, + { + "command": "mageforge.theme.watchInline", + "when": "view == mageforge.themes && viewItem == mageforgeTheme", + "group": "inline@2" + }, { "command": "mageforge.theme.build", "when": "view == mageforge.themes && viewItem == mageforgeTheme", diff --git a/src/extension.ts b/src/extension.ts index 3561b40..9fa3e16 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -24,7 +24,7 @@ export function activate(context: vscode.ExtensionContext) { new WelcomeViewProvider(context.extensionUri), ), vscode.window.registerTreeDataProvider('mageforge.commands', commandsProvider), - vscode.window.registerTreeDataProvider('mageforge.themes', themesProvider), + vscode.window.createTreeView('mageforge.themes', { treeDataProvider: themesProvider }), ); // Notify the user and open the changelog after the extension was updated. @@ -39,6 +39,18 @@ export function activate(context: vscode.ExtensionContext) { ); } + // Inline text-only aliases for the themes view. + const buildCmd = MAGEFORGE_COMMANDS.find((c) => c.id === 'mageforge.theme.build')!; + const watchCmd = MAGEFORGE_COMMANDS.find((c) => c.id === 'mageforge.theme.watch')!; + context.subscriptions.push( + vscode.commands.registerCommand('mageforge.theme.buildInline', (item?: ThemeTreeItem) => + runMageforgeCommand(buildCmd, themesProvider, item), + ), + vscode.commands.registerCommand('mageforge.theme.watchInline', (item?: ThemeTreeItem) => + runMageforgeCommand(watchCmd, themesProvider, item), + ), + ); + context.subscriptions.push( vscode.commands.registerCommand('mageforge.refreshThemes', () => themesProvider.refresh()), vscode.commands.registerCommand( diff --git a/src/magento.ts b/src/magento.ts index b597884..1fe36fe 100644 --- a/src/magento.ts +++ b/src/magento.ts @@ -196,7 +196,7 @@ export function execMageforge( { cwd: magentoRoot, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => { if (error) { - reject(new Error(stderr || error.message)); + reject(new Error(stderr || error.message || 'Command failed')); return; } resolve(stdout); diff --git a/src/themesProvider.ts b/src/themesProvider.ts index 125b899..7e744b9 100644 --- a/src/themesProvider.ts +++ b/src/themesProvider.ts @@ -76,7 +76,9 @@ export class ThemesProvider implements vscode.TreeDataProvider { this.loadError = undefined; } catch (error) { this.themes = []; - this.loadError = error instanceof Error ? error.message : String(error); + const message = error instanceof Error ? error.message : String(error); + const cleaned = stripAnsi(message); + this.loadError = formatLoadError(cleaned); } } } @@ -86,6 +88,32 @@ function stripAnsi(text: string): string { return text.replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, ''); } +/** + * Convert a raw command failure into a user-friendly error message. + * Long messages are truncated so they do not break the tree view layout. + */ +function formatLoadError(message: string): string { + const normalized = message.toLowerCase(); + + if ( + normalized.includes('ddev') && + /not (running|started)|could not|failed|unable/i.test(message) + ) { + return 'DDEV is not running. Start the project with `ddev start` and try again.'; + } + if (normalized.includes('docker-compose') || normalized.includes('docker compose')) { + return 'Docker Compose service unavailable. Check that containers are running.'; + } + if (normalized.includes('lando')) { + return 'Lando environment unavailable. Start the project with `lando start`.'; + } + if (normalized.includes('command not found') || normalized.includes('no such file')) { + return 'MageForge CLI not found. Run `composer require openforgeproject/mageforge`.'; + } + + return message.length > 120 ? `${message.slice(0, 120)}…` : message; +} + /** * Parse `mageforge:theme:list` output. The command renders a Symfony console * table with the columns Code | Title | Path – we extract the theme codes