From f821010dc92cc6fd1f2e6a3b99ea4197f1ebb251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Sat, 28 Feb 2026 18:56:16 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20add=20open-folder=20button=20[=E2=96=B8?= =?UTF-8?q?]=20to=20pane=20subtitle=20row?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cyan [▸] button on each pane's subtitle row opens the project folder in Finder. Path text truncates with … prefix when too long. Co-Authored-By: Claude Opus 4.6 --- src/components/direct-grid.ts | 20 +++++++++++++++++--- src/input/handlers.ts | 5 +++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/components/direct-grid.ts b/src/components/direct-grid.ts index 5968da7..3a4e419 100644 --- a/src/components/direct-grid.ts +++ b/src/components/direct-grid.ts @@ -370,7 +370,7 @@ export class DirectGridRenderer { // Check if a click hit a button on the top border. Returns action + pane index. // Hit areas are widened beyond the visible dot characters to make clicking easier. - checkButtonClick(col: number, row: number): { action: "max" | "min" | "sel" | "tab" | "newtab" | "panefocus" | "closetab" | "closepane", paneIndex: number, tabId?: number } | null { + checkButtonClick(col: number, row: number): { action: "max" | "min" | "sel" | "tab" | "newtab" | "panefocus" | "closetab" | "closepane" | "openfolder", paneIndex: number, tabId?: number } | null { // Tab bar check (row 1) — includes inline pane names if (row === 1) { // Check close buttons first — widened ±1 around the × character @@ -428,6 +428,14 @@ export class DirectGridRenderer { if (row === by + 1 && !this.isExpanded) { return { action: "max", paneIndex: i } } + + // Subtitle row (by+2) — folder button [▸] at right edge + if (row === by + 2) { + const folderBtnCol = bx + bw - 1 - 3 - 1 // matches render position + if (col >= folderBtnCol && col <= folderBtnCol + 2) { + return { action: "openfolder", paneIndex: i } + } + } } return null } @@ -864,8 +872,14 @@ export class DirectGridRenderer { out += `\x1b[${by + 1};${bx}H${borderColor}${vt}${RESET}\x1b[${bw - 2}X${titleContent}` out += `\x1b[${by + 1};${bx + bw - 1}H${borderColor}${vt}${RESET}` - // Subtitle row - out += `\x1b[${by + 2};${bx}H${borderColor}${vt}${RESET}\x1b[${bw - 2}X ${DIM}${pane.session.projectPath}${RESET}` + // Subtitle row — path + open folder button + const FOLDER_BTN = `${hexFg("#7dcfff")}[▸]${RESET}` + const maxPathLen = bw - 2 - 1 - 1 - 3 - 1 // border - pad - space - [▸] - pad + const pathStr = pane.session.projectPath.length > maxPathLen + ? "…" + pane.session.projectPath.slice(-(maxPathLen - 1)) + : pane.session.projectPath + out += `\x1b[${by + 2};${bx}H${borderColor}${vt}${RESET}\x1b[${bw - 2}X ${DIM}${pathStr}${RESET}` + out += `\x1b[${by + 2};${bx + bw - 1 - 3 - 1}H${FOLDER_BTN}` out += `\x1b[${by + 2};${bx + bw - 1}H${borderColor}${vt}${RESET}` // Side borders for content rows diff --git a/src/input/handlers.ts b/src/input/handlers.ts index 60489eb..995a25b 100644 --- a/src/input/handlers.ts +++ b/src/input/handlers.ts @@ -715,6 +715,11 @@ function processGridInput(str: string) { else if (btn?.action === "max") { dg.cancelPendingClose(); dg.expandPane(btn.paneIndex) } else if (btn?.action === "min") { dg.cancelPendingClose(); dg.collapsePane() } else if (btn?.action === "sel") { dg.cancelPendingClose(); dg.enterSelectMode() } + else if (btn?.action === "openfolder") { + dg.cancelPendingClose() + const p = dg.getTabPanes(dg.activeTabId)[btn.paneIndex] + if (p) Bun.spawn(["open", p.session.projectPath]) + } else if (btn?.action === "tab") { dg.cancelPendingClose() if (btn.tabId === -1) {