From 11a1383527d0018414edcfe4333718b09f1dd690 Mon Sep 17 00:00:00 2001 From: Bozhidar Date: Mon, 3 Nov 2025 19:22:09 +0200 Subject: [PATCH 1/5] up --- .../editor/layout/assets-browser/items/item.tsx | 10 +++++++++- editor/src/electron/events/shell.ts | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/editor/src/editor/layout/assets-browser/items/item.tsx b/editor/src/editor/layout/assets-browser/items/item.tsx index d6e6209f5..e782ca239 100644 --- a/editor/src/editor/layout/assets-browser/items/item.tsx +++ b/editor/src/editor/layout/assets-browser/items/item.tsx @@ -396,6 +396,12 @@ export class AssetsBrowserItem extends Component {`Show in ${isDarwin ? "Finder" : "Explorer"}`} + {!this.state.isDirectory && ( + ipcRenderer.send("editor:open-with", this.props.absolutePath)}> + Edit + + )} + {items.map((item, index) => ( @@ -418,7 +424,7 @@ export class AssetsBrowserItem extends Component this._handleTrashItem()}> - Remove + Delete ); @@ -438,6 +444,8 @@ export class AssetsBrowserItem extends Component { const files = await readdir(this.props.absolutePath); const previewImage = files.find((f) => f.startsWith("editor_preview") && (f.endsWith(".png") || f.endsWith(".jpg") || f.endsWith(".jpeg"))); diff --git a/editor/src/electron/events/shell.ts b/editor/src/electron/events/shell.ts index a574f0789..17bff4fb8 100644 --- a/editor/src/electron/events/shell.ts +++ b/editor/src/electron/events/shell.ts @@ -20,3 +20,17 @@ ipcMain.on("editor:show-item", (_, item) => { shell.showItemInFolder(item); }); + +ipcMain.on("editor:open-in-external-editor", (_, item) => { + const isWindows = platform() === "win32"; + item = isWindows ? item.replace(/\//g, "\\") : item.replace(/\\/g, "/"); + + shell.openPath(item); +}); + +ipcMain.on("editor:open-with", (_, item) => { + const isWindows = platform() === "win32"; + item = isWindows ? item.replace(/\//g, "\\") : item.replace(/\\/g, "/"); + + shell.openPath(item); +}); From 7fca39d45e9b675927aeade445e8b8e6edfc1b4a Mon Sep 17 00:00:00 2001 From: Bozhidar Date: Mon, 3 Nov 2025 19:22:49 +0200 Subject: [PATCH 2/5] Update item.tsx --- editor/src/editor/layout/assets-browser/items/item.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/editor/src/editor/layout/assets-browser/items/item.tsx b/editor/src/editor/layout/assets-browser/items/item.tsx index e782ca239..187b0c7e8 100644 --- a/editor/src/editor/layout/assets-browser/items/item.tsx +++ b/editor/src/editor/layout/assets-browser/items/item.tsx @@ -250,7 +250,10 @@ export class AssetsBrowserItem extends Component { - // Nothing to do by default. + // If it's a file (not a directory), open it in the default editor + if (!this.state.isDirectory) { + ipcRenderer.send("editor:open-with", this.props.absolutePath); + } } private _handleDragStart(ev: DragEvent): void { From 38624e2b9181d1803cc1ac821b5b92075712e3b9 Mon Sep 17 00:00:00 2001 From: Bozhidar Date: Mon, 3 Nov 2025 19:26:21 +0200 Subject: [PATCH 3/5] Update item.tsx --- .../src/editor/layout/assets-browser/items/item.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/editor/src/editor/layout/assets-browser/items/item.tsx b/editor/src/editor/layout/assets-browser/items/item.tsx index 187b0c7e8..4c49fc39c 100644 --- a/editor/src/editor/layout/assets-browser/items/item.tsx +++ b/editor/src/editor/layout/assets-browser/items/item.tsx @@ -395,17 +395,17 @@ export class AssetsBrowserItem extends Component - ipcRenderer.send("editor:show-item", this.props.absolutePath)}> - {`Show in ${isDarwin ? "Finder" : "Explorer"}`} - + {!this.state.isDirectory && ( ipcRenderer.send("editor:open-with", this.props.absolutePath)}> - Edit + Open )} - + ipcRenderer.send("editor:show-item", this.props.absolutePath)}> + {`Show in ${isDarwin ? "Finder" : "Explorer"}`} + {items.map((item, index) => ( {item} @@ -429,6 +429,8 @@ export class AssetsBrowserItem extends Component this._handleTrashItem()}> Delete + + ); } From d9685842f041f36385fd4d9b759cf5dcd013d760 Mon Sep 17 00:00:00 2001 From: Bozhidar Date: Mon, 3 Nov 2025 19:45:45 +0200 Subject: [PATCH 4/5] up --- editor/src/dashboard/item.tsx | 11 ++ .../layout/assets-browser/items/item.tsx | 10 +- editor/src/editor/layout/toolbar.tsx | 13 +++ editor/src/electron/events/shell.ts | 101 +++++++++++++++++- 4 files changed, 124 insertions(+), 11 deletions(-) diff --git a/editor/src/dashboard/item.tsx b/editor/src/dashboard/item.tsx index f96374a9f..71fbdaeb8 100644 --- a/editor/src/dashboard/item.tsx +++ b/editor/src/dashboard/item.tsx @@ -131,6 +131,11 @@ export function DashboardProjectItem(props: IDashboardProjectItemProps) { execNodePty(`code "${dirname(props.project.absolutePath)}"`); } + function handleOpenInDefaultIde() { + const projectDir = dirname(props.project.absolutePath); + ipcRenderer.send("editor:open-with", projectDir); + } + return ( setContextMenuOpen(o)}> @@ -174,6 +179,9 @@ export function DashboardProjectItem(props: IDashboardProjectItemProps) { {`Show in ${isDarwin() ? "Finder" : "Explorer"}`} + handleOpenInDefaultIde()}> + Open in Default IDE + handleOpenInVisualStudioCode()}> Open in Visual Studio Code @@ -219,6 +227,9 @@ export function DashboardProjectItem(props: IDashboardProjectItemProps) { {`Show in ${isDarwin() ? "Finder" : "Explorer"}`} + handleOpenInDefaultIde()}> + Open in Default IDE + handleOpenInVisualStudioCode()}> Open in Visual Studio Code diff --git a/editor/src/editor/layout/assets-browser/items/item.tsx b/editor/src/editor/layout/assets-browser/items/item.tsx index 4c49fc39c..938340614 100644 --- a/editor/src/editor/layout/assets-browser/items/item.tsx +++ b/editor/src/editor/layout/assets-browser/items/item.tsx @@ -395,8 +395,6 @@ export class AssetsBrowserItem extends Component - - {!this.state.isDirectory && ( ipcRenderer.send("editor:open-with", this.props.absolutePath)}> Open @@ -404,8 +402,8 @@ export class AssetsBrowserItem extends Component ipcRenderer.send("editor:show-item", this.props.absolutePath)}> - {`Show in ${isDarwin ? "Finder" : "Explorer"}`} - + {`Show in ${isDarwin ? "Finder" : "Explorer"}`} + {items.map((item, index) => ( {item} @@ -429,8 +427,6 @@ export class AssetsBrowserItem extends Component this._handleTrashItem()}> Delete - - ); } @@ -449,8 +445,6 @@ export class AssetsBrowserItem extends Component { const files = await readdir(this.props.absolutePath); const previewImage = files.find((f) => f.startsWith("editor_preview") && (f.endsWith(".png") || f.endsWith(".jpg") || f.endsWith(".jpeg"))); diff --git a/editor/src/editor/layout/toolbar.tsx b/editor/src/editor/layout/toolbar.tsx index 7e23c7a7a..340546d5b 100644 --- a/editor/src/editor/layout/toolbar.tsx +++ b/editor/src/editor/layout/toolbar.tsx @@ -90,6 +90,10 @@ export class EditorToolbar extends Component { + this._handleOpenInDefaultIde()}> + Open in Default IDE + + this._handleOpenVisualStudioCode()}> Open in Visual Studio Code @@ -258,4 +262,13 @@ export class EditorToolbar extends Component { const p = await execNodePty(`code "${join(dirname(this.props.editor.state.projectPath), "/")}"`); await p.wait(); } + + private _handleOpenInDefaultIde(): void { + if (!this.props.editor.state.projectPath) { + return; + } + + const projectDir = dirname(this.props.editor.state.projectPath); + ipcRenderer.send("editor:open-with", projectDir); + } } diff --git a/editor/src/electron/events/shell.ts b/editor/src/electron/events/shell.ts index 17bff4fb8..1c4856fce 100644 --- a/editor/src/electron/events/shell.ts +++ b/editor/src/electron/events/shell.ts @@ -1,5 +1,7 @@ import { platform } from "os"; import { ipcMain, shell } from "electron"; +import { exec } from "child_process"; +import { statSync } from "fs"; ipcMain.on("editor:trash-items", async (ev, items) => { const isWindows = platform() === "win32"; @@ -28,9 +30,102 @@ ipcMain.on("editor:open-in-external-editor", (_, item) => { shell.openPath(item); }); -ipcMain.on("editor:open-with", (_, item) => { +async function checkCommandAvailable(command: string): Promise { + return new Promise((resolve) => { + exec(`${command} --version`, (error) => { + resolve(!error); + }); + }); +} + +async function openInIde(path: string, isDirectory: boolean): Promise { const isWindows = platform() === "win32"; - item = isWindows ? item.replace(/\//g, "\\") : item.replace(/\\/g, "/"); + const normalizedPath = isWindows ? path.replace(/\//g, "\\") : path.replace(/\\/g, "/"); - shell.openPath(item); + if (isDirectory) { + // Try to open directory in IDEs + const ideCommands = [ + { command: "code", args: [normalizedPath] }, + { command: "cursor", args: [normalizedPath] }, + { command: "subl", args: [normalizedPath] }, // Sublime Text + ]; + + // Try each IDE in order + for (const ide of ideCommands) { + if (await checkCommandAvailable(ide.command)) { + const fullCommand = `${ide.command} "${normalizedPath}"`; + exec(fullCommand, (error) => { + if (error) { + console.error(`Failed to open with ${ide.command}:`, error); + } + }); + return; + } + } + + // On macOS, try JetBrains IDEs (PhpStorm, WebStorm, IntelliJ IDEA) + if (platform() === "darwin") { + exec(`open -a "PhpStorm" "${normalizedPath}"`, (error) => { + if (!error) return; + exec(`open -a "WebStorm" "${normalizedPath}"`, (error) => { + if (!error) return; + exec(`open -a "IntelliJ IDEA" "${normalizedPath}"`, (error) => { + if (!error) return; + exec(`open -a "IntelliJ IDEA CE" "${normalizedPath}"`, (error) => { + if (!error) return; + // Fallback to shell.openPath + shell.openPath(normalizedPath); + }); + }); + }); + }); + return; + } + + // On Windows, try JetBrains IDEs via CLI + if (isWindows) { + if (await checkCommandAvailable("phpstorm")) { + exec(`phpstorm "${normalizedPath}"`, (error) => { + if (error) { + console.error("Failed to open with PhpStorm:", error); + } + }); + return; + } + if (await checkCommandAvailable("webstorm")) { + exec(`webstorm "${normalizedPath}"`, (error) => { + if (error) { + console.error("Failed to open with WebStorm:", error); + } + }); + return; + } + if (await checkCommandAvailable("idea")) { + exec(`idea "${normalizedPath}"`, (error) => { + if (error) { + console.error("Failed to open with IntelliJ IDEA:", error); + shell.openPath(normalizedPath); + } + }); + return; + } + } + + // Fallback: open with default application + shell.openPath(normalizedPath); + } else { + // For files, use shell.openPath which uses OS default application + shell.openPath(normalizedPath); + } +} + +ipcMain.on("editor:open-with", async (_, item) => { + try { + const stats = statSync(item); + const isDirectory = stats.isDirectory(); + await openInIde(item, isDirectory); + } catch (e) { + // If stat fails, try as directory first, then as file + await openInIde(item, true); + } }); From e98ecf65674ebd33af9995d6acf551f2faeb6222 Mon Sep 17 00:00:00 2001 From: Bozhidar Date: Mon, 3 Nov 2025 19:48:08 +0200 Subject: [PATCH 5/5] up --- editor/src/editor/layout/toolbar.tsx | 1 + editor/src/editor/menu.ts | 4 ++++ editor/src/electron/events/shell.ts | 16 ++++++++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/editor/src/editor/layout/toolbar.tsx b/editor/src/editor/layout/toolbar.tsx index 340546d5b..d2e9e1298 100644 --- a/editor/src/editor/layout/toolbar.tsx +++ b/editor/src/editor/layout/toolbar.tsx @@ -39,6 +39,7 @@ export class EditorToolbar extends Component { super(props); ipcRenderer.on("editor:open-project", () => this._handleOpenProject()); + ipcRenderer.on("editor:open-default-ide", () => this._handleOpenInDefaultIde()); ipcRenderer.on("editor:open-vscode", () => this._handleOpenVisualStudioCode()); this._nodeCommands = getNodeCommands(this.props.editor); diff --git a/editor/src/editor/menu.ts b/editor/src/editor/menu.ts index a98116f5e..381c2f1a5 100644 --- a/editor/src/editor/menu.ts +++ b/editor/src/editor/menu.ts @@ -55,6 +55,10 @@ export function setupEditorMenu(): void { { type: "separator", }, + { + label: "Open in Default IDE", + click: () => BrowserWindow.getFocusedWindow()?.webContents.send("editor:open-default-ide"), + }, { label: "Open in Visual Studio Code", click: () => BrowserWindow.getFocusedWindow()?.webContents.send("editor:open-vscode"), diff --git a/editor/src/electron/events/shell.ts b/editor/src/electron/events/shell.ts index 1c4856fce..020c85bb7 100644 --- a/editor/src/electron/events/shell.ts +++ b/editor/src/electron/events/shell.ts @@ -66,13 +66,21 @@ async function openInIde(path: string, isDirectory: boolean): Promise { // On macOS, try JetBrains IDEs (PhpStorm, WebStorm, IntelliJ IDEA) if (platform() === "darwin") { exec(`open -a "PhpStorm" "${normalizedPath}"`, (error) => { - if (!error) return; + if (!error) { + return; + } exec(`open -a "WebStorm" "${normalizedPath}"`, (error) => { - if (!error) return; + if (!error) { + return; + } exec(`open -a "IntelliJ IDEA" "${normalizedPath}"`, (error) => { - if (!error) return; + if (!error) { + return; + } exec(`open -a "IntelliJ IDEA CE" "${normalizedPath}"`, (error) => { - if (!error) return; + if (!error) { + return; + } // Fallback to shell.openPath shell.openPath(normalizedPath); });