Skip to content

fix(nvim): don't require the picker UI for file_search/content_search with cwd - #966

Merged
dkovalenko-oai merged 3 commits into
dmtrKovalenko:mainfrom
Nyarlathoteppppp:fix/programmatic-search-without-picker
Nov 6, 2026
Merged

dkovalenko-oai merged 3 commits into
dmtrKovalenko:mainfrom
Nyarlathoteppppp:fix/programmatic-search-without-picker

Conversation

@Nyarlathoteppppp

@Nyarlathoteppppp Nyarlathoteppppp commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Refs #938

This is the "separate, smaller issue" from #938. The watcher hang itself is handled in #939; this PR doesn't touch it.

Problem

file_search and content_search with a cwd that differs from the current root fail at once with timeout waiting for index scan and return nothing, unless require('fff.file_picker').setup() was called first.

ensure_indexed (lua/fff/main.lua) calls core.ensure_initialized(), switches the root, then waits on file_picker.wait_for_initial_scan. That returns false while file_picker.state.initialized is unset, and only file_picker.setup() sets it. setup() is only called from the picker UI (picker_ui.lua:126,626), so a caller that only uses the programmatic API never gets past the wait. The existing specs call setup() in before_each, which is why they didn't catch it.

Reproduction

From a checkout of main (7353971), nvim --headless -u NONE -i NONE -l repro.lua:

vim.opt.rtp:prepend(vim.fn.getcwd())
vim.g.fff = { frecency = { db_path = vim.fn.tempname() }, history = { db_path = vim.fn.tempname() } }
local r = require('fff').file_search('', { cwd = vim.fn.getcwd() .. '/crates' })
print(#r.items)

Before: FFF file_search: timeout waiting for index scan, then 0. After: 100.

Fix

ensure_indexed calls file_picker.setup() right after core.ensure_initialized() if it hasn't run yet, the same check the picker UI does before opening. setup() only sets the Lua-side flag and base_path, so nothing changes for callers that open the picker or already call setup(). No public API change.

I left wait_for_initial_scan and the other file_picker guards as they are. If you'd rather have core.ensure_initialized() set the flag, I can move it there.

Tests

New cwd switching without the picker UI block in tests/programmatic_search_spec.lua. It saves file_picker.state.initialized and sets it to false in before_each (restored in after_each), then runs file_search and content_search against a fresh sandbox cwd and checks that nothing is notified as an error and the sandbox file or match comes back. The notify check matters for content_search: polling for the match alone would pass without the fix.

With lua/fff/main.lua reverted the spec gives 12 pass / 2 fail, both timeout waiting for index scan; with the fix, 14/14.

Ran locally on macOS arm64, Neovim 0.12.6, with the prebuilt aarch64-apple-darwin.dylib from the 0.11.1-nightly.7353971 release in target/release/ (I don't have cargo here, and this PR only changes Lua):

  • PlenaryBustedDirectory tests/ (what make test-lua runs): 71 pass, 0 fail
  • stylua --check ., luacheck lua/, lua-language-server --check=.: clean (the vim.notify stub needs a duplicate-set-field disable)

programmatic_search_spec.lua is flaky on macOS under load, both on main and on this branch (3/30 runs each, every failure stuck ~50 s on a scan wait), which looks like the #938 hang that #939 fixes. On an otherwise idle machine, 50 more runs of this branch had no hangs.

Not run: a Rust build, Neovim 0.10.4 (CI's version), Linux, Windows, make test-lua-snap.

… with cwd

ensure_indexed waits through file_picker.wait_for_initial_scan, which
returns false until file_picker.setup() has run. Only the picker UI calls
setup(), so API-only callers that pass a different cwd got
"timeout waiting for index scan". Call setup() from ensure_indexed when
it has not run yet.

Refs dmtrKovalenko#938
@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 680ba193-9d5d-4b9c-b581-8bbdf485ade2
Commits

Reviewing files that changed from the base of the PR and between bc64f01 and fb97ef5.

Files selected for processing: 1
  • tests/programmatic_search_spec.lua

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

Programmatic searches now set up the file picker when it is uninitialized. Tests cover file and content searches in a new working directory without opening the picker UI.

Changes: Programmatic search

Layer / File(s) Summary
Initialize the picker for programmatic searches
lua/fff/main.lua, tests/programmatic_search_spec.lua
ensure_indexed sets up the file picker when it is uninitialized and uses the loaded module to wait for the initial scan. Tests check sandbox search results and error notifications when picker UI setup is disabled.

Priority: Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: dmtrkovalenko

Merge Risk: Minimal · up to fb97e

No concrete merge-blocking risk is established by the reviewed evidence.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly identifies the main fix: file_search and content_search work with a different cwd without requiring the picker UI.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…r-UI case

Follow the cwd switching block: skip the delete when before_each did not
create the sandbox, nil it afterwards, and wait 250 ms on Windows after
writing grep_target.lua.
@dkovalenko-oai
dkovalenko-oai merged commit 423807d into dmtrKovalenko:main Nov 6, 2026
54 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.

2 participants