2KAbhishek/seeker.nvim

github github
search
stars 58
issues 2
subscribers 2
forks 2
CREATED

UPDATED


https://github.com/user-attachments/assets/4f16a8b9-7e39-4053-bde7-37646b8954cd

seeker.nvim is a Neovim plugin that enables progressive file investigation by seamlessly switching between file filtering and content searching (grep), with each switch refining your results.

Built on top of snacks.nvim picker, seeker provides a powerful workflow for narrowing down files by name, then searching within those files, then further refining the file list based on grep results - all without losing context.

โœจ Features

  • Progressive Refinement: Each mode switch narrows down results (File โ†’ Grep โ†’ File progressively filters)
  • Seamless Mode Switching: Toggle between file and grep modes with a single keybinding
  • Smart File Selection: Supports both Tab-selection and automatic filtering of visible results
  • Configurable: Customize toggle keys, picker options, and more

โšก Setup

โš™๏ธ Requirements

๐Ÿ’ป Installation

-- Lazy.nvim
{
    '2kabhishek/seeker.nvim',
    dependencies = { 'folke/snacks.nvim' },
    cmd = { 'Seeker' },
    keys = {
        { '<leader>fa', ':Seeker files<CR>', desc = 'Seek Files' },
        { '<leader>ff', ':Seeker git_files<CR>', desc = 'Seek Git Files' },
        { '<leader>fg', ':Seeker grep<CR>', desc = 'Seek Grep' },
    },
    opts = { }, -- Required unless you call seeker.setup() manually, add your configs here
}

๐Ÿš€ Usage

Basic Workflow

  1. Start Seeker: Run :Seeker or press <leader>ff
  2. Filter Files: Type to filter files by name (standard file picker behavior)
  3. Switch to Grep: Press <C-e> to search within the filtered files
  4. Search Content: Type to search for content within those files
  5. Refine Files: Press <C-e> again to see only files with matches
  6. Continue Refining: Keep switching between modes to progressively narrow results

Multi-Selection

  • Press <Tab> to select specific files to search before switching modes
  • If no files are selected, all visible filtered results are used
  • Works in both file and grep modes

Configuration

seeker.nvim can be configured using the following options:

require('seeker').setup({
    toggle_key = '<C-e>', -- Key to toggle between modes (default)
    picker_opts = {}, -- Options passed to snacks.picker (optional)
})

Commands

The :Seeker command accepts an optional mode argument with tab completion:

  • :Seeker - Auto-detect (uses git_files in git repos, files otherwise)
  • :Seeker files - Force files picker (all files)
  • :Seeker git_files - Force git_files picker (git tracked files only)
  • :Seeker grep - Start with grep picker directly

Keybindings

Keybinding Mode Description
<leader>fa Normal Seek Files
<leader>ff Normal Seek Git Files
<leader>fg Normal Seek Grep
<C-e> File Picker (n/i) Toggle Grep / File mode
<Tab> Picker (n/i) Multi Selection

You can customize the toggle key via config, and others using lazy's key definitions.

If you use pickme.nvim, you need to add Seeker keybindgings manually / via which key.

API

-- Start seeker programmatically
require('seeker').seek()

-- Start with custom options (merged with setup config)
require('seeker').seek({
    picker_opts = {
        layout = { preset = 'vertical' }
    }
})

๐Ÿ—๏ธ How It Works

Progressive Refinement

Seeker uses a stateful approach to maintain context across mode switches:

  1. File โ†’ Grep: Extracts filtered/selected files and searches only within those
  2. Grep โ†’ File: Extracts unique files from grep results and shows only those files
  3. Repeat: Each cycle progressively narrows down the result set

State Management

  • state.file_list: Files to search in grep mode
  • state.grep_files: Files with matches (shown in file mode)
  • state.mode: Current mode ('file' | 'grep')

Smart Path Handling

  • Auto-detects git repositories
  • Handles both absolute and relative paths
  • Validates file existence
  • Supports multiple path formats from snacks.picker

๐Ÿงช Testing

# Run all tests
nvim --headless -c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/init.lua'}"
# or
make

# Run specific test file
nvim --headless -c "PlenaryBustedFile tests/seeker/state_spec.lua {minimal_init = 'tests/init.lua'}"

โ›… Behind The Code

๐ŸŒˆ Inspiration

I frequently needed to investigate codebases by filtering files, then searching within those files, then further refining based on content - but existing tools required starting over each time. Seeker solves this by maintaining context across mode switches.

๐Ÿ’ก Challenges/Learnings

  • Understanding snacks.picker's API and item formats
  • Managing state across picker instances
  • Handling multiple path formats (string vs table items)
  • Progressive refinement without losing context

๐Ÿงฐ Tooling

  • dots2k โ€” Dev Environment
  • nvim2k โ€” Personalized Editor
  • sway2k โ€” Desktop Environment
  • qute2k โ€” Personalized Browser

๐Ÿ” More Plugins

โญ hit the star button if you found this useful โญ

Source | Blog | Twitter | LinkedIn | More Links | Other Projects