5.2 KiB
fff.picker_ui — Picker UI Module
This directory contains the full implementation of the FFF file picker UI. Originally a single monolithic ~2535-line file, it has been split into focused submodules.
Entry point
picker_ui.lua — requires require('fff.picker_ui.picker_ui').
This is the coordinator. It wires all submodules together and exposes the public API:
| Function | Purpose |
|---|---|
M.open(opts) |
Open the file picker |
M.open_with_callback(query, callback, opts) |
Search with a callback, fall back to opening the picker |
M.select(action) |
Open the selected file (edit/split/vsplit/tab) |
M.toggle_select() |
Toggle multi-selection for the current item |
M.send_to_quickfix() |
Send selected items to the quickfix list |
M.toggle_debug() |
Toggle debug score display |
M.monitor_scan_progress() |
Poll indexing progress during initial scan |
Submodules
| Module | File | Purpose | Key exports via picker_ui.lua |
|---|---|---|---|
| picker_ui_state | picker_ui_state.lua |
Single source of truth for all picker state | M.state, M.clear_selections, M.reset_history_state |
| ui_creator | ui_creator.lua |
Creates buffers, windows, and keymaps for the picker UI | M.create_ui, M.setup_buffers, M.setup_windows, M.setup_keymaps, M.focus_*_win, M.open_preview, M.close_preview |
| search_manager | search_manager.lua |
Executes searches, manages pagination, handles query history | M.update_results_sync, M.update_results, M.load_*_page, M.on_input_change, M.cycle_grep_modes, M.recall_query_from_history, M.cycle_forward_query, M.get_suggestion_renderer |
| renderer | renderer.lua |
Renders the file list, handles combo separator, scrollbar, and empty state | M.render_list, M.scroll_to_bottom |
| preview_manager | preview_manager.lua |
Manages file preview rendering, debounced updates, and preview title | M.update_preview, M.update_preview_smart, M.update_preview_debounced, M.update_preview_title, M.clear_preview |
| navigation | navigation.lua |
Handles cursor movement, pagination wrap-around, and preview scrolling | M.move_up, M.move_down, M.wrap_to_first, M.wrap_to_last, M.scroll_preview_up, M.scroll_preview_down |
| layout_manager | layout_manager.lua |
Recalculates layout on terminal resize (VimResized) and cleans up on close | M.relayout, M.close |
| file_renderer | file_renderer.lua |
Renders individual file lines with icon, path, and score | M.render_line, M.apply_highlights |
| grep_renderer | grep_renderer.lua |
Grep search execution and rendering of grep result lines | M.search, M.get_search_metadata, M.render_line, M.apply_highlights |
| combo_renderer | combo_renderer.lua |
Detects combo (directory common prefix) items from a list | M.detect |
| list_renderer | list_renderer.lua |
Renders the full file list with separator, scrollbar, and combo display | M.render |
| utils | utils.lua |
Utility functions (quickfix list building) | M.send_to_quickfix |
Module relationships
picker_ui.lua (coordinator)
├── ui_creator.lua — buffer/window/keymap creation
├── search_manager.lua → grep_renderer.lua → file_renderer.lua
├── renderer.lua → list_renderer.lua, combo_renderer.lua
│ ├─ file_renderer.lua
│ └─ list_separator (external)
├── preview_manager.lua
├── navigation.lua
├── layout_manager.lua
└── utils.lua → grep_renderer.lua (for exhaustive grep in send_to_quickfix)
Architecture
All submodules follow the same pattern:
local M = {}
local P = nil -- parent module reference
function M.init(parent_module) P = parent_module end
local S = picker_ui_state.state -- shared state
-- ... functions that use S.* and P.* ...
return M
The coordinator (picker_ui.lua) calls module.init(M) on each submodule, passing itself as the parent. This lets submodules call back into picker_ui.lua for cross-module coordination — for example, navigation.lua calls P.render_list() and P.update_preview() after moving the cursor.
State is shared via a single table reference (picker_ui_state.state). Every submodule writes to and reads from the same table — no message passing or event bus.
Modules without init() are either pure data stores (picker_ui_state) or standalone utility modules without cross-module dependencies (file_renderer, grep_renderer, combo_renderer, list_renderer, utils).
Key design decisions
picker_ui_stateis a pure data store — no parent module reference, noinit(). It owns the state table and selection helpers.picker_ui.luakeeps cross-cutting concerns —update_status,select,toggle_debug,openlives here because they coordinate across multiple submodules.- Module purpose is reflected in the filename — anything with
_managerin the name manages state or lifecycle;rendererandnavigationare purely behavioral;*_renderermodules handle rendering of specific item types. vim.scheduleusage is intentional — deferred calls prevent re-entrancy issues during buffer mutations and window teardown.