Skip to content

feat(tui): add a path picker for the last response - #60048

Closed
spaxe-dev wants to merge 1 commit into
anomalyco:devfrom
spaxe-dev:path-picker
Closed

spaxe-dev wants to merge 1 commit into
anomalyco:devfrom
spaxe-dev:path-picker

Conversation

@spaxe-dev

Copy link
Copy Markdown

Issue for this PR

Related: #58242, #54816, #55769, #48609

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Agent responses usually end with a list of files. In the TUI those paths are plain text, so getting to one means selecting and copying it. This adds /paths (and <leader>f): it numbers the paths in the last completed response, tags each one in red, and opens the path you type.

It covers the shapes that show up in practice: relative and .//../, absolute POSIX, Windows drive and UNC, file:// URLs with #L12C3, directories, quoted paths with spaces, and path:line or path:line:column. Markdown links and inline code are read through their delimiters. Fenced code, URLs, and commands are left alone.

Opening prefers $VISUAL/$EDITOR, passes line and column in the syntax each editor understands (--goto, file:line:column, +line), and groups files into one process when the editor accepts several targets. Without an editor, files go to the OS handler, directories to the file manager, and executable types are refused with a message instead of being launched.

Multi-select is m, numbers toggle, a selects up to 10, and enter opens the selection. The cap keeps one keypress from starting an unbounded number of processes. If one number is a prefix of another (1 and 12), the picker waits 600ms before opening so typing 12 does not open 1.

Tags are inserted as ~~1~~, ~~●1~~, or ~~○1~~, which Markdown conceals. While the picker is open, the marked text parts use a derived SyntaxStyle that maps markup.strikethrough to text.feedback.error.base; closing the picker restores the shared style. This gives red tags without adding a theme token and without recoloring real strikethrough, links, or inline code. generateSyntax takes optional per-scope overrides for this and keeps its current behavior by default.

This is keyboard driven, so it does not implement #58242 as filed. It sits next to #55769, which opens Markdown links to local files with the OS handler, and #48609, which asks for clickable file names on tool blocks. Both are complementary; nothing here changes link handling or tool headers. The feature is behind a command and a keybinding, so it does not add work to the normal transcript path until the picker is opened. Happy to adjust the interaction if maintainers want a different shape.

How did you verify your code works?

Automated, from the affected packages:

cd packages/tui
bun test --timeout 30000 test/file-links.test.ts test/editor.test.ts test/path-link-tags.test.tsx test/theme/v2/resolve.test.ts
bun run typecheck:tsc

cd packages/theme
bun test --timeout 30000
bun run typecheck:tsc

Full TUI suite: 1565 pass, 21 skip, 7 fail. The only failures are seven Windows EPERM: operation not permitted, symlink tests in plugin and watcher suites, which reproduce on a clean checkout on this machine.

Coverage added:

  • scanner and resolver: relative paths, directories, spaces, Markdown links, file URLs, ~, fenced code and URLs ignored, explicit missing paths, Windows drive/UNC/file URLs, POSIX normalization, dedupe, numbering across parts, multi-digit disambiguation, tag spacing
  • editor: command splitting, per-editor line/column arguments, batching, missing path, launchable refusal, mixed batch failures
  • renderer: tag spacing and color, no leftover ~~ markers
  • theme: overrides win over theme rules

Manual check:

  1. Start the TUI with EDITOR set to an editor. Terminal editors suspend the renderer until exit.
  2. Ask the agent to write several files, then run /paths.
  3. Type a number to open it. Press m, toggle numbers, press enter.
  4. Try a missing absolute path: it gets a number and reports that it does not exist instead of opening.

The storybook story renders the production component with a temp fixture:

OPENCODE_STORY=path-picker bun run dev:live

Visual

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="72" viewBox="0 0 240 72" fill="currentColor" font-family="ui-monospace, SFMono-Regular, Menlo, monospace">
  <style>
    .tag { animation: tag 2.8s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
    .caret { animation: caret 1.4s steps(1) infinite; }
    @keyframes tag { 0%, 12% { opacity: 0; transform: scale(.7) } 26%, 82% { opacity: 1; transform: scale(1) } 100% { opacity: 0 } }
    @keyframes caret { 50% { opacity: 0 } }
  </style>
  <text x="12" y="26" font-size="12" opacity=".5">Report: out/report.md</text>
  <g class="tag"><text x="154" y="26" font-size="12" font-weight="700">●1</text></g>
  <rect x="12" y="38" width="216" height="1" opacity=".15"/>
  <text x="12" y="56" font-size="10" opacity=".7">● Paths</text>
  <text x="54" y="56" font-size="10">2/12</text>
  <text x="84" y="56" font-size="10" opacity=".4">·</text>
  <text x="94" y="56" font-size="10" opacity=".55">●○ toggle</text>
  <text x="152" y="56" font-size="10" opacity=".4">·</text>
  <text x="162" y="56" font-size="10" opacity=".55">enter open</text>
  <rect class="caret" x="212" y="47" width="6" height="10" opacity=".5"/>
</svg>

Screenshots / recordings

No recording. The story above shows the tagged transcript and the picker bar with a fixture that includes quoted paths, directories, a file:// URL, a missing path, and generated files.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Numbers existing paths in the last completed assistant response and opens one with the configured editor. Supports relative, absolute, Windows, UNC, and file:// paths, directories, quoted paths with spaces, and line/column suffixes. Code fences and URLs stay untouched.

Adds /paths and <leader>f, with multi-select and a picker bar built from existing theme tokens.
@opencodejr opencodejr Bot closed this Oct 28, 2026
@opencodejr

opencodejr Bot commented Oct 28, 2026

Copy link
Copy Markdown

Thanks for the detailed write-up and the tests, @spaxe-dev! This is about 1,460 changed lines without tests across several layers (path scanning, the picker UI, editor launching, theme overrides and a storybook story). That's more than we can review well in one pull request, so I'm closing it and asking you to split it into smaller, focused PRs that can each be reviewed on its own. One possible split:

  • A basic /paths picker: scan the last response for common path shapes (relative, .//../, absolute POSIX, path:line[:col]), number them, and open a single selection in $VISUAL/$EDITOR at the line, falling back to the OS handler
  • Multi-select (m, a, enter) and grouping several files into one editor process
  • More path forms: Windows drive and UNC paths, file:// URLs with #L..C.., quoted paths with spaces, and Markdown link and inline code handling
  • The red tag styling (the generateSyntax per-scope overrides and the derived SyntaxStyle)
  • The storybook story

Since the interaction is new and doesn't follow #58242 as filed, you could also check the UX direction with maintainers on an issue first. You're welcome to open those PRs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant