diff --git a/packages/app/src/components/file-tree.tsx b/packages/app/src/components/file-tree.tsx index 4a3e276724d7..4d879508eca2 100644 --- a/packages/app/src/components/file-tree.tsx +++ b/packages/app/src/components/file-tree.tsx @@ -1,5 +1,7 @@ import { useFile } from "@/context/file" +import { useLanguage } from "@/context/language" import { Collapsible } from "@opencode-ai/ui/collapsible" +import { ContextMenu } from "@opencode-ai/ui/context-menu" import { FileIcon } from "@opencode-ai/ui/file-icon" import { Icon } from "@opencode-ai/ui/icon" import { Tooltip } from "@opencode-ai/ui/tooltip" @@ -81,10 +83,15 @@ export default function FileTree(props: { _kinds?: ReadonlyMap }) { const file = useFile() + const language = useLanguage() const level = props.level ?? 0 const draggable = () => props.draggable ?? true const tooltip = () => props.tooltip ?? true + const copyToClipboard = (text: string) => { + navigator.clipboard.writeText(text).catch(() => {}) + } + const filter = createMemo(() => { if (props._filter) return props._filter @@ -349,8 +356,6 @@ export default function FileTree(props: { const expanded = () => file.tree.state(node.path)?.expanded ?? false const deep = () => deeps().get(node.path) ?? -1 const Wrapper = (p: ParentProps) => { - if (!tooltip()) return p.children - const parts = node.path.split("/") const leaf = parts[parts.length - 1] ?? node.path const head = parts.slice(0, -1).join("/") @@ -367,40 +372,61 @@ export default function FileTree(props: { const ignored = () => node.type === "directory" && node.ignored - return ( - - - {prefix} - - {leaf} - - {(t: () => string) => ( + const TooltipWrapper = (tp: ParentProps) => { + if (!tooltip()) return tp.children + return ( + + + {prefix} + + {leaf} + + {(t: () => string) => ( + <> + + {t()} + + )} + + <> - {t()} + Ignored - )} - - - <> - - Ignored - - - - } - > - {p.children} - + + + } + > + {tp.children} + + ) + } + + return ( + + + {p.children} + + + + copyToClipboard(node.path)}> + {language.t("filetree.copyRelativePath")} + + copyToClipboard(node.absolute)}> + {language.t("filetree.copyAbsolutePath")} + + + + ) } diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index 201d63660a39..fdc7ead7588b 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -50,6 +50,9 @@ export const dict = { "command.input.focus": "التركيز على حقل الإدخال", "command.terminal.toggle": "تبديل المحطة الطرفية", "command.fileTree.toggle": "تبديل شجرة الملفات", + + "filetree.copyRelativePath": "نسخ المسار النسبي", + "filetree.copyAbsolutePath": "نسخ المسار المطلق", "command.review.toggle": "تبديل المراجعة", "command.terminal.new": "محطة طرفية جديدة", "command.terminal.new.description": "إنشاء علامة تبويب جديدة للمحطة الطرفية", diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index a4884a1033dc..18cc0e417ec0 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -54,6 +54,9 @@ export const dict = { "command.input.focus": "Eingabefeld fokussieren", "command.terminal.toggle": "Terminal umschalten", "command.fileTree.toggle": "Dateibaum umschalten", + + "filetree.copyRelativePath": "Relativen Pfad kopieren", + "filetree.copyAbsolutePath": "Absoluten Pfad kopieren", "command.review.toggle": "Überprüfung umschalten", "command.terminal.new": "Neues Terminal", "command.terminal.new.description": "Neuen Terminal-Tab erstellen", diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index b0ffa70f84de..575f294249c0 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -50,6 +50,9 @@ export const dict = { "command.input.focus": "Focus input", "command.terminal.toggle": "Toggle terminal", "command.fileTree.toggle": "Toggle file tree", + + "filetree.copyRelativePath": "Copy Relative Path", + "filetree.copyAbsolutePath": "Copy Absolute Path", "command.review.toggle": "Toggle review", "command.terminal.new": "New terminal", "command.terminal.new.description": "Create a new terminal tab", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index 50d9060703ea..28717606eef5 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -50,6 +50,9 @@ export const dict = { "command.input.focus": "Enfocar entrada", "command.terminal.toggle": "Alternar terminal", "command.fileTree.toggle": "Alternar árbol de archivos", + + "filetree.copyRelativePath": "Copiar ruta relativa", + "filetree.copyAbsolutePath": "Copiar ruta absoluta", "command.review.toggle": "Alternar revisión", "command.terminal.new": "Nueva terminal", "command.terminal.new.description": "Crear una nueva pestaña de terminal", diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index 7ad39f340639..bccc40e771f8 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -50,6 +50,9 @@ export const dict = { "command.input.focus": "Focus input", "command.terminal.toggle": "Basculer le terminal", "command.fileTree.toggle": "Basculer l'arborescence des fichiers", + + "filetree.copyRelativePath": "Copier le chemin relatif", + "filetree.copyAbsolutePath": "Copier le chemin absolu", "command.review.toggle": "Basculer la revue", "command.terminal.new": "Nouveau terminal", "command.terminal.new.description": "Créer un nouvel onglet de terminal", diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index a39bfbaf331b..d06743ac321f 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -50,6 +50,9 @@ export const dict = { "command.input.focus": "入力欄にフォーカス", "command.terminal.toggle": "ターミナルの切り替え", "command.fileTree.toggle": "ファイルツリーを切り替え", + + "filetree.copyRelativePath": "相対パスをコピー", + "filetree.copyAbsolutePath": "絶対パスをコピー", "command.review.toggle": "レビューの切り替え", "command.terminal.new": "新しいターミナル", "command.terminal.new.description": "新しいターミナルタブを作成", diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index b5927b210767..f1db16f60f0a 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -54,6 +54,9 @@ export const dict = { "command.input.focus": "입력창 포커스", "command.terminal.toggle": "터미널 토글", "command.fileTree.toggle": "파일 트리 토글", + + "filetree.copyRelativePath": "상대 경로 복사", + "filetree.copyAbsolutePath": "절대 경로 복사", "command.review.toggle": "검토 토글", "command.terminal.new": "새 터미널", "command.terminal.new.description": "새 터미널 탭 생성", diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index e83ce37618c5..330af561adfa 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -50,6 +50,9 @@ export const dict = { "command.input.focus": "Фокус на поле ввода", "command.terminal.toggle": "Переключить терминал", "command.fileTree.toggle": "Переключить дерево файлов", + + "filetree.copyRelativePath": "Копировать относительный путь", + "filetree.copyAbsolutePath": "Копировать абсолютный путь", "command.review.toggle": "Переключить обзор", "command.terminal.new": "Новый терминал", "command.terminal.new.description": "Создать новую вкладку терминала", diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index a48f9e549415..d8c5b65e273a 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -54,6 +54,9 @@ export const dict = { "command.input.focus": "聚焦输入框", "command.terminal.toggle": "切换终端", "command.fileTree.toggle": "切换文件树", + + "filetree.copyRelativePath": "复制相对路径", + "filetree.copyAbsolutePath": "复制绝对路径", "command.review.toggle": "切换审查", "command.terminal.new": "新建终端", "command.terminal.new.description": "创建新的终端标签页", diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index 60363fc99eff..81ad81bbfe23 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -54,6 +54,9 @@ export const dict = { "command.input.focus": "聚焦輸入框", "command.terminal.toggle": "切換終端機", "command.fileTree.toggle": "切換檔案樹", + + "filetree.copyRelativePath": "複製相對路徑", + "filetree.copyAbsolutePath": "複製絕對路徑", "command.review.toggle": "切換審查", "command.terminal.new": "新增終端機", "command.terminal.new.description": "建立新的終端機標籤頁",