From 63ecbc96c7e3b1ac0d3b816607a392cc8fced309 Mon Sep 17 00:00:00 2001 From: Jean Caiza Date: Sat, 7 Feb 2026 09:43:45 -0500 Subject: [PATCH 1/2] feat(file): navigate to files from @file prompt input --- packages/app/src/components/prompt-input.tsx | 38 ++++++++++++++++++- .../components/prompt-input/context-items.tsx | 2 +- packages/desktop/src/bindings.ts | 1 - packages/util/src/path.ts | 34 +++++++++++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 46d7f93eb32..c34f219396c 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -45,6 +45,7 @@ import { PromptImageAttachments } from "./prompt-input/image-attachments" import { PromptDragOverlay } from "./prompt-input/drag-overlay" import { promptPlaceholder } from "./prompt-input/placeholder" import { ImagePreview } from "@opencode-ai/ui/image-preview" +import { isCodeFile } from "@opencode-ai/util/path" interface PromptInputProps { class?: string @@ -148,7 +149,13 @@ export const PromptInput: Component = (props) => { } const openComment = (item: { path: string; commentID?: string; commentOrigin?: "review" | "file" }) => { - if (!item.commentID) return + if (!item.commentID) { + if (!isCodeFile(item.path)) return + const tab = files.tab(item.path) + tabs().open(tab) + files.load(item.path) + return + } const focus = { file: item.path, id: item.commentID } comments.setActive(focus) @@ -425,10 +432,30 @@ export const PromptInput: Component = (props) => { if (part.type === "agent") pill.setAttribute("data-name", part.name) pill.setAttribute("contenteditable", "false") pill.style.userSelect = "text" - pill.style.cursor = "default" + + if (part.type === "file" && isCodeFile(part.path)) { + pill.classList.add("prompt-pill--code") + } + return pill } + const handleEditorClick = (e: MouseEvent) => { + const target = e.target as HTMLElement + const pill = target.closest('[data-type="file"]') as HTMLElement | null + if (!pill) return + + const path = pill.dataset.path + if (!path || !isCodeFile(path)) return + + if (!view().reviewPanel.opened()) view().reviewPanel.open() + layout.fileTree.open() + layout.fileTree.setTab("all") + const tab = files.tab(path) + tabs().open(tab) + files.load(path) + } + const isNormalizedEditor = () => Array.from(editorRef.childNodes).every((node) => { if (node.nodeType === Node.TEXT_NODE) { @@ -988,12 +1015,19 @@ export const PromptInput: Component = (props) => { onCompositionStart={() => setComposing(true)} onCompositionEnd={() => setComposing(false)} onKeyDown={handleKeyDown} + onClick={handleEditorClick} classList={{ "select-text": true, "w-full p-3 pr-12 text-14-regular text-text-strong focus:outline-none whitespace-pre-wrap": true, "[&_[data-type=file]]:text-syntax-property": true, "[&_[data-type=agent]]:text-syntax-type": true, "font-mono!": store.mode === "shell", + "[&_.prompt-pill--code]:cursor-pointer": true, + "[&_.prompt-pill--code]:rounded": true, + "[&_.prompt-pill--code]:px-1": true, + "[&_.prompt-pill--code]:bg-violet-500/10": true, + "[&_.prompt-pill--code]:hover:bg-violet-500/25": true, + "[&_.prompt-pill--code]:transition-colors": true, }} /> diff --git a/packages/app/src/components/prompt-input/context-items.tsx b/packages/app/src/components/prompt-input/context-items.tsx index a843e109d82..a9e8b93f3a2 100644 --- a/packages/app/src/components/prompt-input/context-items.tsx +++ b/packages/app/src/components/prompt-input/context-items.tsx @@ -36,7 +36,7 @@ export const PromptContextItems: Component = (props) => {
__TAURI_INVOKE("kill_sidecar"), installCli: () => __TAURI_INVOKE("install_cli"), awaitInitialization: (events: Channel) => __TAURI_INVOKE("await_initialization", { events }), - getDefaultServerUrl: () => __TAURI_INVOKE("get_default_server_url"), setDefaultServerUrl: (url: string | null) => __TAURI_INVOKE("set_default_server_url", { url }), parseMarkdownCommand: (markdown: string) => __TAURI_INVOKE("parse_markdown_command", { markdown }), diff --git a/packages/util/src/path.ts b/packages/util/src/path.ts index bb191f5120a..b5113337ee9 100644 --- a/packages/util/src/path.ts +++ b/packages/util/src/path.ts @@ -35,3 +35,37 @@ export function truncateMiddle(text: string, maxLength: number = 20) { const end = Math.floor(available / 2) return text.slice(0, start) + "…" + text.slice(-end) } + +const MEDIA_EXTENSIONS = new Set([ + "png", + "jpg", + "jpeg", + "gif", + "webp", + "svg", + "bmp", + "ico", + "mp4", + "mov", + "avi", + "webm", + "mp3", + "wav", + "ogg", + "pdf", + "zip", + "tar", + "gz", + "rar", + "7z", + "exe", + "dll", + "so", + "dylib", +]) + +export const isCodeFile = (path: string) => { + const ext = path.split(".").pop()?.toLowerCase() + if (!ext) return false + return !MEDIA_EXTENSIONS.has(ext) +} From 7934618941bf9abf74141e9b70bd665f6c586196 Mon Sep 17 00:00:00 2001 From: Jean Caiza Date: Sat, 7 Feb 2026 11:36:49 -0500 Subject: [PATCH 2/2] feat(file): fix type file hover color --- packages/app/src/components/prompt-input.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index c34f219396c..e2f9a58e78f 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -1025,8 +1025,7 @@ export const PromptInput: Component = (props) => { "[&_.prompt-pill--code]:cursor-pointer": true, "[&_.prompt-pill--code]:rounded": true, "[&_.prompt-pill--code]:px-1": true, - "[&_.prompt-pill--code]:bg-violet-500/10": true, - "[&_.prompt-pill--code]:hover:bg-violet-500/25": true, + "[&_.prompt-pill--code]:hover:text-syntax-property/70": true, "[&_.prompt-pill--code]:transition-colors": true, }} />