Skip to content

Commit 8982a20

Browse files
committed
feat(explorer): add Open action to file/folder context menu
Coffee CLI ships no in-app previewers (markdown / pdf / image / etc.), so before this commit the user's only path from Explorer to a file's content was Reveal in File Explorer → double-click in the OS file manager. Add a top-of-menu Open entry that hands the absolute path straight to the existing open_url command (cmd /C start "" / open / xdg-open) — files launch in their OS-default app, folders launch in the OS file manager, file-type-without-default triggers the OS picker. We don't track defaults or MIME mappings ourselves; the system owns the whole flow. Translation key menu.open added to all 11 i18n bundles. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3af7798 commit 8982a20

12 files changed

Lines changed: 34 additions & 0 deletions

File tree

src-ui/src/components/left/Explorer.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,19 @@ function ContextMenu({ menu, onClose }: { menu: CtxMenuState; onClose: () => voi
128128
}
129129
};
130130

131+
// Hand the path off to the OS default opener — Notepad / browser / image
132+
// viewer / file manager, whichever the user already configured. We don't
133+
// ship in-app previewers (memory: "no in-app file viewers"), so this is
134+
// the user's only one-click path from Explorer to the file's content.
135+
const handleOpen = async () => {
136+
onClose();
137+
try {
138+
await commands.openUrl(menu.absolutePath);
139+
} catch (e) {
140+
console.error('[Explorer] open failed:', e);
141+
}
142+
};
143+
131144
const canPaste = !!fsClipboard;
132145

133146
// Smart menu positioning to prevent off-screen clipping
@@ -149,6 +162,16 @@ function ContextMenu({ menu, onClose }: { menu: CtxMenuState; onClose: () => voi
149162

150163
return createPortal(
151164
<div className="ctx-menu" ref={menuRef} style={style}>
165+
{/* Primary action: open in OS default — most-used, sits at the top */}
166+
<button className="ctx-menu-item" onClick={handleOpen}>
167+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
168+
<path d="M15 3h6v6"/>
169+
<path d="M10 14 21 3"/>
170+
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
171+
</svg>
172+
{t('menu.open' as any)}
173+
</button>
174+
<div className="ctx-menu-divider" />
152175
{/* Path copy group */}
153176
<button className="ctx-menu-item" onClick={() => copyPath(menu.absolutePath)}>
154177
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">

src-ui/src/i18n/de.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const de = {
1515
'menu.rename': 'Umbenennen',
1616
'menu.delete': 'Löschen',
1717
'menu.show_in_folder': 'Im Explorer anzeigen',
18+
'menu.open': 'Öffnen',
1819

1920
// Drive kinds (Quick Access)
2021
'drive.desktop': 'Desktop',

src-ui/src/i18n/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const en = {
1616
'menu.rename': 'Rename',
1717
'menu.delete': 'Delete',
1818
'menu.show_in_folder': 'Reveal in File Explorer',
19+
'menu.open': 'Open',
1920

2021
// Drive kinds (Quick Access)
2122
'drive.desktop': 'Desktop',

src-ui/src/i18n/es.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const es = {
1515
'menu.rename': 'Renombrar',
1616
'menu.delete': 'Eliminar',
1717
'menu.show_in_folder': 'Mostrar en el explorador',
18+
'menu.open': 'Abrir',
1819

1920
// Drive kinds (Quick Access)
2021
'drive.desktop': 'Escritorio',

src-ui/src/i18n/fr.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const fr = {
1515
'menu.rename': 'Renommer',
1616
'menu.delete': 'Supprimer',
1717
'menu.show_in_folder': 'Afficher dans l\u2019explorateur',
18+
'menu.open': 'Ouvrir',
1819

1920
// Drive kinds (Quick Access)
2021
'drive.desktop': 'Bureau',

src-ui/src/i18n/ja.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const ja = {
1515
'menu.rename': '名前を変更',
1616
'menu.delete': '削除',
1717
'menu.show_in_folder': 'エクスプローラーで表示',
18+
'menu.open': '開く',
1819

1920
// Drive kinds (Quick Access)
2021
'drive.desktop': 'デスクトップ',

src-ui/src/i18n/ko.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const ko = {
1515
'menu.rename': '이름 바꾸기',
1616
'menu.delete': '삭제',
1717
'menu.show_in_folder': '파일 탐색기에서 열기',
18+
'menu.open': '열기',
1819

1920
// Drive kinds (Quick Access)
2021
'drive.desktop': '바탕화면',

src-ui/src/i18n/pt.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const pt = {
1515
'menu.rename': 'Renomear',
1616
'menu.delete': 'Excluir',
1717
'menu.show_in_folder': 'Mostrar no explorador',
18+
'menu.open': 'Abrir',
1819

1920
// Drive kinds (Quick Access)
2021
'drive.desktop': 'Área de trabalho',

src-ui/src/i18n/ru.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const ru = {
1515
'menu.rename': 'Переименовать',
1616
'menu.delete': 'Удалить',
1717
'menu.show_in_folder': 'Показать в проводнике',
18+
'menu.open': 'Открыть',
1819

1920
// Drive kinds (Quick Access)
2021
'drive.desktop': 'Рабочий стол',

src-ui/src/i18n/vi.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const vi = {
1616
'menu.rename': 'Đổi tên',
1717
'menu.delete': 'Xóa',
1818
'menu.show_in_folder': 'Hiển thị trong File Explorer',
19+
'menu.open': 'Mở',
1920

2021
// Drive kinds (Quick Access)
2122
'drive.desktop': 'Màn hình nền',

0 commit comments

Comments
 (0)