import { resolve } from 'path' import type { ReactNode } from 'react' import Link from './Link.js' import Text from './Text.js' export type Editor = 'vscode' | 'vscode-insiders' | 'cursor' | 'windsurf' export type FileLinkProps = { /** Absolute or relative file path. Relative paths are resolved against cwd. */ readonly path: string /** 1-based line number */ readonly line?: number /** 1-based column number */ readonly column?: number /** Editor to open with (default: 'vscode') */ readonly editor?: Editor /** Custom display content. Defaults to "path:line:col" */ readonly children?: ReactNode } const SCHEME: Record = { vscode: 'vscode', 'vscode-insiders': 'vscode-insiders', cursor: 'cursor', windsurf: 'windsurf', } /** * Build a URI that opens a file at a specific location in an editor. * * VS Code URI format: vscode://file/{absolute_path}:{line}:{column} */ export function buildEditorUri( path: string, line?: number, column?: number, editor: Editor = 'vscode', ): string { const abs = resolve(path) const scheme = SCHEME[editor] let uri = `${scheme}://file/${abs}` if (line != null) { uri += `:${line}` if (column != null) { uri += `:${column}` } } return uri } /** * Clickable terminal hyperlink that opens a file in VS Code (or compatible editor). * * Uses OSC 8 hyperlinks with `vscode://file/` URIs. In terminals that support * hyperlinks (iTerm2, Windows Terminal, Hyper, kitty, etc.), clicking the link * opens the file at the specified line/column in VS Code. * * Usage: * ```tsx * * * open file * * ``` */ export default function FileLink({ path, line, column, editor = 'vscode', children }: FileLinkProps) { const url = buildEditorUri(path, line, column, editor) const defaultLabel = line != null ? column != null ? `${path}:${line}:${column}` : `${path}:${line}` : path return ( {defaultLabel}} > {children ?? {defaultLabel}} ) }