Skip to content

Conversation

@aweis89
Copy link
Contributor

@aweis89 aweis89 commented Dec 21, 2025

Summary

  • Add a code reference picker (gr keybinding in output window) to navigate to file references mentioned in AI responses
  • Enable easy navigation when asking exploratory questions about a codebase
  • Full support for Snacks, Telescope, and fzf-lua pickers with file preview and line navigation

Use Case

When asking the AI exploratory questions about a codebase (e.g., "how does the session management work?", "where is error handling implemented?"), the AI often responds with file path references like file://lua/opencode/session.lua:42.

This feature makes those references navigable - press gr to open a picker showing all detected references with file preview, then select one to jump directly to that location.

This is specifically designed for read-only exploration, not for navigating to edits (which can be found via git pickers like :Telescope git_status).

Features

  • Reference detection exclusively parses file:// URIs:

    • file://path/to/file.lua (path only)
    • file://path/to/file.lua:42 (with line number)
    • file://path/to/file.lua:42:10 (with line and column)
    • file://path/to/file.lua:42-45 (with line ranges)
  • Picker-specific features:

    • Snacks: File preview with full range highlighting (lines 42-45)
    • Telescope: File preview with full range highlighting (lines 42-45)
    • fzf-lua: File preview with line navigation (highlights line 42)
    • Mini.pick: Basic list without preview
  • Visual icons are displayed before recognized file:// URIs in assistant responses, providing immediate visual confirmation that the path will appear in the reference picker

  • System prompt addition: Instructs the LLM to use file:// URI scheme and wrap in backticks for file references

  • Deduplication across messages (most recent first)

  • Validation - only shows references to files that exist

  • Per-message caching - references are parsed when the AI finishes responding and cached for fast picker opening

  • Session persistence - references are parsed when loading previous sessions

  • Keybinding: gr in output window

  • Slash command: /references

  • Vim command: :Opencode references

Implementation Details

Reference Detection & Parsing

  • Regex pattern matches file:// URIs with optional line numbers, columns, and ranges
  • Validates files exist on disk before adding to picker
  • Caches parsed references per message for performance

Picker Integration

All pickers use the unified base_picker interface with picker-specific optimizations:

Snacks

  • Uses pos and end_pos fields for range highlighting
  • Background highlight for the entire range

Telescope

  • Uses lnum and lnend fields for range highlighting
  • Requires vim_buffer_vimgrep previewer (not the default cat previewer)
  • TelescopePreviewLine highlight group for ranges

fzf-lua

  • Appends file:line:col: format after tab separator
  • Uses builtin previewer with automatic entry parsing
  • Cursorline highlight on start line (range end not supported)

Mini.pick

  • Basic list display without preview support

Highlight Groups

  • OpencodeReference - Icon color for file references in assistant messages
    • Light theme: #1976D2 (blue)
    • Dark theme: #7AA2F7 (lighter blue)

Testing Checklist

  • Snacks picker (with file preview and range highlighting)
  • Telescope picker (with file preview and range highlighting)
  • fzf-lua picker (with file preview and line navigation)
  • mini.pick picker (basic list, no preview)
  • No picker fallback (returns false gracefully)
  • All tests passing (74/74)
  • CI passing on all platforms

- introduce a new configurable system prompt to customize assistant behavior
- include guidance for file referencing to assist users with integration
- modifies message sending logic to incorporate the system prompt if set
- changes to reference detection streamline navigation for file-related responses
@sudo-tee
Copy link
Owner

This is pretty neat. I will have a try today or tomorrow. But it seems really useful.

- Remove dead code referencing non-existent ref.context field
- Only show line number in display when present (avoid 'path:?')
…icons

- Parse file references when session becomes idle (AI done responding)
- Cache parsed references per-message for faster picker opening
- Handle session load from previous sessions
- Display reference icon before recognized file paths in output
- Subscribe to 'messages' state changes to parse loaded sessions
- Update test expected data files with new icon rendering
Remove legacy path:line and path-only pattern detection in favor of
exclusively parsing file:// URIs. This simplifies the code significantly
and avoids false positives from ambiguous path patterns.

The system prompt instructs the LLM to use file:// URIs, making the
legacy patterns unnecessary.
- refine explanation for system prompt usage in assistant responses
- emphasize file URI scheme for better navigation and tooling integration
- remove old system prompt setting in configuration
- replace it with a hardcoded prompt including URI format examples
- modifies behavior to improve navigation and tooling integration
- add support for line range format: file://path:start-end
- modify regex pattern to accommodate optional end line numbers
- update reference structure to include optional end_pos for highlighting
- enhance clarity in the instructions for referencing files
- emphasize the use of the file:// URI scheme as critical
- provide examples to illustrate correct and incorrect formats
- ensure compatibility with the existing reference picker for navigation
- improve reference location display by including line and column info
- handle cases where end position is available for better accuracy
- simplify display logic to ensure consistent output for references
@sudo-tee
Copy link
Owner

I played a little bit with this.

It seems to work as intended.

I have a couple of small comments:

I think it would be better if we could also trigger with ta keymam in the input window. I know there is the /references but having the leymap is faster.

File previews are supported by fzf-lua and Telescope, I think we should support it.

Can you add the new /references and Opencode references to the README

- populate entry path, lnum, and col in telescope entries to support previewers
- enable file previewer configuration when options request file preview
- ensures code references can be previewed directly in the telescope picker UI
- update system prompt to explicitly require backticks around file:// URIs
- add examples distinguishing correct backticked format from incorrect ones
- ensures file references are consistently formatted for UI and parsing
- add key binding for timeline picker with `<leader>oT`
- include new key binding for browsing code references with `gr`
- clarify command usage for creating and selecting sessions
- touches(config): update default keyboard shortcuts for new features
Resolves conflicts in:
- lua/opencode/ui/highlight.lua: Added both OpencodeReference and OpencodeReasoningText highlights
- lua/opencode/ui/icons.lua: Added both reference and reasoning icons to nerdfonts preset, added reference to text preset
Icon characters changed in upstream, requiring test snapshot updates
Telescope supports highlighting line ranges in the file previewer using
the lnend field. Map end_pos[1] to lnend so that references with line
ranges (file://path:start-end) get highlighted in Telescope previewer.
The default file_previewer uses the 'cat' previewer which doesn't call
jump_to_line, so lnend field is ignored. Switch to vim_buffer_vimgrep
which properly highlights line ranges using the lnend field.
Add builtin previewer support to fzf-lua picker backend with automatic
line/column positioning for code references.

Changes:
- Enable 'builtin' previewer when preview='file'
- Append file:line:col: format to entries for fzf-lua parsing
- Update fn_fzf_index to strip position info before matching
- Supports navigation to specific lines (range highlighting shows start line only)

Implementation details:
- Uses tab separator between display text and file position
- fzf-lua's entry_to_file() automatically parses path:line:col: format
- Cursorline highlights the target line in preview
- Gracefully degrades when preview is disabled

Comparison with other pickers:
- Telescope: Full range highlighting (start-end lines)
- Snacks: Full range highlighting (start-end lines)
- fzf-lua: Single line highlighting (cursorline at start)
- Mini.pick: No file preview support
fzf-lua uses nbsp (U+2002 EN SPACE) as the standard separator between
display text and file path info, not tab. The builtin previewer parses
entries by splitting on utils.nbsp and extracting the path:line:col:
portion.

From fzf-lua/path.lua entry_to_file():
  local parts = utils.strsplit(entry, utils.nbsp)
  for i = 1, #parts - 1 do
    if s:match(".-:%d+:") then break end
    idx0 = idx0 + #s + #utils.nbsp
  end
  return entry:sub(idx0), idx0

Changes:
- Use nbsp (\xe2\x80\x82) instead of \t as separator
- Update fn_fzf_index to split by nbsp
- Use file_path (relative) before file (absolute) for correct resolution

This fixes 'Unable to stat file' errors in preview.
@aweis89 aweis89 force-pushed the feat/picker-ai-code-referenes branch from 851fc38 to ddcc145 Compare December 22, 2025 20:22
@aaronweisberg
Copy link

  • Added full support for Telescope file previews with range highlighting
  • Added preview support for fzf-lua as well (however it doesn't have an explicit API for range highlights, so it just highlights the first line when there's a range)

@sudo-tee
Copy link
Owner

Looks great to me

Thanks for the PR

@sudo-tee sudo-tee merged commit b575131 into sudo-tee:main Dec 23, 2025
5 checks passed
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.

3 participants