Theo's ʕ•ᴥ•ʔ Park

Custom fzf-lua Picker to Search Files in the Parent Directory

The Problem

I use GNU Stow to manage and deploy my Dotfiles. That means that my dotfiles repository has lots of nested directories:

dotfiles/
├── aerospace
│   └── .aerospace.toml
├── ...
├── nvim
│   └── .config
│       └── nvim
│           ├── after
│           │   └── ftplugin
│           │       └── ...
│           ├── doc
│           │   └── ...
│           ├── init.lua
│           ├── lsp
│           │   └── ...
│           ├── lua
│           │   ├── plugins
│           │   │   └── ...
│           │   ├── theovim
│           │   │   └── ...
│           │   └── ui
│           │       └── ...
│           └── spell
│               └── ...
├── README.md
└── ...

Often I am working inside of the nested directory (e.g., dotfiles/nvim/.config/nvim/lua/plugins) and need to access files in the root directory (e.g., dotfiles/README.md). It gets annoying to manually type :cd .. until I reach the desired parent directory. When I was using Telescope, I used the file-browser extension and navigated to the parent directories within the Telescope window, but it was not exactly the behavior I was hoping for. So during the process of migrating to fzf-lua, I wrote a custom picker to select a parent directory to launch the file picker from, and it is the single most used fzf-lua function in my use case.

Solution

In /nvim/lua/plugins/fzf-lua.lua

 1return {
 2  "ibhagwan/fzf-lua",
 3  config = function()
 4  -- ... other config and keymaps ...
 5
 6  vim.keymap.set("n", "<leader>s.", function()
 7    -- Fill the table with parent directories
 8    local dirs = {}
 9    for dir in vim.fs.parents(vim.uv.cwd()) do
10      table.insert(dirs, dir)
11    end
12
13    -- Open a custom fzf to select a directory and launch fzf-files
14    require("fzf-lua").fzf_exec(dirs, {
15      prompt = "Parent Directories❯ ",
16      actions = {
17        ["default"] = function(selected)
18          fzf.files({ cwd = selected[1] })
19        end
20      }
21    })
22  end, { desc = "[S]earch Parent Directories [..]" })
23
24  -- ... other config and keymaps ...
25  end
26}

Bonus: Receiving a path from the user input

Credit: https://www.reddit.com/r/neovim/comments/1k56ih4/custom_fzflua_function_to_select_a_parent/mogbz1b/?context=3

 1  vim.keymap.set("n", "<leader>s/", function()
 2    vim.ui.input({
 3      prompt = "Enter a directory: ",
 4      completion = "dir",
 5    }, function(input)
 6      if input then
 7        local dir = vim.fs.normalize(input)
 8        local stat = vim.uv.fs_stat(dir)
 9        if stat and stat.type == "directory" then
10          require("fzf-lua").files({ cwd = dir })
11        else
12          print("Invalid directory!")
13        end
14      end
15    end)
16  end, { desc = "[S]earch the Given Directory" })

[!Note] I believe that the path validation using fs.normalize() and uv.fs_stat() is not necessary in my parent directory selector. because the dirs table will simply be empty if either vim.uv.cwd() somehow returns an invalid directory.

#neovim