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
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()
anduv.fs_stat()
is not necessary in my parent directory selector. because thedirs
table will simply be empty if eithervim.uv.cwd()
somehow returns an invalid directory.