diff --git a/src/renderer/src/components/terminal-pane/terminal-link-handlers.ts b/src/renderer/src/components/terminal-pane/terminal-link-handlers.ts index 0a60ed5a983..91e4c4c339f 100644 --- a/src/renderer/src/components/terminal-pane/terminal-link-handlers.ts +++ b/src/renderer/src/components/terminal-pane/terminal-link-handlers.ts @@ -66,7 +66,12 @@ export function openDetectedFilePath( })() } -export function createFilePathLinkProvider(paneId: number, deps: LinkHandlerDeps): ILinkProvider { +export function createFilePathLinkProvider( + paneId: number, + deps: LinkHandlerDeps, + linkTooltip: HTMLElement, + openLinkHint: string +): ILinkProvider { const { startupCwd, managerRef, pathExistsCache, worktreeId, worktreePath } = deps return { provideLinks: (bufferLineNumber, callback) => { @@ -109,11 +114,21 @@ export function createFilePathLinkProvider(paneId: number, deps: LinkHandlerDeps end: { x: parsed.endIndex + 1, y: bufferLineNumber } }, text: parsed.displayText, - activate: () => { + activate: (event) => { + if (!isTerminalLinkActivation(event)) { + return + } openDetectedFilePath(resolved.absolutePath, resolved.line, resolved.column, { worktreeId, worktreePath }) + }, + hover: () => { + linkTooltip.textContent = `${resolved.absolutePath} (${openLinkHint})` + linkTooltip.style.display = '' + }, + leave: () => { + linkTooltip.style.display = 'none' } } }) @@ -125,7 +140,9 @@ export function createFilePathLinkProvider(paneId: number, deps: LinkHandlerDeps } } -export function isTerminalLinkActivation(event: Pick | undefined): boolean { +export function isTerminalLinkActivation( + event: Pick | undefined +): boolean { const isMac = navigator.userAgent.includes('Mac') return isMac ? Boolean(event?.metaKey) : Boolean(event?.ctrlKey) } diff --git a/src/renderer/src/components/terminal-pane/use-terminal-pane-lifecycle.ts b/src/renderer/src/components/terminal-pane/use-terminal-pane-lifecycle.ts index 1aed5603ae3..2ef6386f706 100644 --- a/src/renderer/src/components/terminal-pane/use-terminal-pane-lifecycle.ts +++ b/src/renderer/src/components/terminal-pane/use-terminal-pane-lifecycle.ts @@ -159,15 +159,28 @@ export function useTerminalPaneLifecycle({ markWorktreeUnread } + const isMac = navigator.userAgent.includes('Mac') + const openLinkHint = isMac ? '⌘+click to open' : 'Ctrl+click to open' + const manager = new PaneManager(container, { onPaneCreated: (pane) => { const linkProviderDisposable = pane.terminal.registerLinkProvider( - createFilePathLinkProvider(pane.id, linkDeps) + createFilePathLinkProvider(pane.id, linkDeps, pane.linkTooltip, openLinkHint) ) linkProviderDisposablesRef.current.set(pane.id, linkProviderDisposable) pane.terminal.options.linkHandler = { allowNonHttpProtocols: true, - activate: (event, text) => handleOscLink(text, event as MouseEvent | undefined) + activate: (event, text) => handleOscLink(text, event as MouseEvent | undefined), + // Show bottom-left tooltip on hover for OSC 8 hyperlinks (e.g. + // GitHub owner/repo#issue references emitted by CLI tools) — same + // behaviour as the WebLinksAddon provides for plain-text URLs. + hover: (_event, text) => { + pane.linkTooltip.textContent = `${text} (${openLinkHint})` + pane.linkTooltip.style.display = '' + }, + leave: () => { + pane.linkTooltip.style.display = 'none' + } } applyAppearance(manager) connectPanePty(pane, manager, ptyDeps) diff --git a/src/renderer/src/lib/pane-manager/pane-manager-types.ts b/src/renderer/src/lib/pane-manager/pane-manager-types.ts index dac890f1f08..858c4edb6b9 100644 --- a/src/renderer/src/lib/pane-manager/pane-manager-types.ts +++ b/src/renderer/src/lib/pane-manager/pane-manager-types.ts @@ -33,6 +33,7 @@ export type ManagedPane = { id: number terminal: Terminal container: HTMLElement // the .pane element + linkTooltip: HTMLElement fitAddon: FitAddon searchAddon: SearchAddon serializeAddon: SerializeAddon diff --git a/src/renderer/src/lib/pane-manager/pane-manager.ts b/src/renderer/src/lib/pane-manager/pane-manager.ts index 2d43504e3aa..512cf2c981a 100644 --- a/src/renderer/src/lib/pane-manager/pane-manager.ts +++ b/src/renderer/src/lib/pane-manager/pane-manager.ts @@ -317,6 +317,7 @@ export class PaneManager { id: pane.id, terminal: pane.terminal, container: pane.container, + linkTooltip: pane.linkTooltip, fitAddon: pane.fitAddon, searchAddon: pane.searchAddon, serializeAddon: pane.serializeAddon