https://github.com/linrongbin16/fzfx.nvim/assets/6496887/b5e2b0dc-4dd6-4c18-b1da-f54419efbba3
Search
require("fzfx
with rg's-g *spec.lua -F
option.
Please see Demo for more use cases.
Windows users will have to install the linux shell environment, since basic linux commands such as echo
, mkdir
are internally required.
There're many ways to install portable linux shell and builtin commands on Windows, but personally I would recommend below two methods:
Install with the below 3 options:
In Select Components, select Associate .sh files to be run with Bash.
In Adjusting your PATH environment, select Use Git and optional Unix tools from the Command Prompt.
In Configuring the terminal emulator to use with Git Bash, select Use Windows's default console window.
After this step, git.exe and builtin linux commands(such as echo.exe, ls.exe, curl.exe) will be available in %PATH%
.
Run below powershell commands:
# scoop
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
irm get.scoop.sh | iex
scoop bucket add extras
scoop install git # git, bash, sh
scoop install uutils-coreutils # echo, ls, cat
scoop install curl # curl
scoop install grep # grep
Note: Install the rust rewritten uutils-coreutils instead of GNU coreutils, some GNU commands (for example
ls
) is actually broken on Windows 10 x86_64 PC.
C:\Windows\System32
and portable linux commandsWindows actually already provide some commands (find.exe
, bash.exe
) in C:\Windows\System32
(or %SystemRoot%\system32
), while they are not the linux commands they are named after, but could override our installations. To fix this issue, we could prioritize the git or scoop environment variables in %PATH%
.
[!IMPORTANT]
Specify plugin version/tag (e.g.
v5.*
) to avoid break changes between major versions!
require("lazy").setup({
-- optional for icons
{ "nvim-tree/nvim-web-devicons" },
-- optional for the 'fzf' command
{
"junegunn/fzf",
build = function()
vim.fn["fzf#install"]()
end,
},
{
"linrongbin16/fzfx.nvim",
dependencies = { "nvim-tree/nvim-web-devicons", 'junegunn/fzf' },
-- specify version to avoid break changes
version = 'v5.*',
config = function()
require("fzfx").setup()
end,
},
})
return require("packer").startup(function(use)
-- optional for icons
use({ "nvim-tree/nvim-web-devicons" })
-- optional for the 'fzf' command
use({
"junegunn/fzf",
run = function()
vim.fn["fzf#install"]()
end,
})
use({
"linrongbin16/fzfx.nvim",
-- specify version to avoid break changes
version = 'v5.0.0',
config = function()
require("fzfx").setup()
end,
})
end)
call plug#begin()
" optional for icons
Plug 'nvim-tree/nvim-web-devicons'
" optional for the 'fzf' command
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
" specify version to avoid break changes
Plug 'linrongbin16/fzfx.nvim', { 'tag': 'v5.0.0' }
call plug#end()
lua require('fzfx').setup()
There're multiple commands provided, named with prefix Fzfx
. The sub commands indicates the user query's input method, (e.g. the variants) named with below rules:
args
, accepts the following arguments as query content.visual
, uses visual selection as query content.cword
, uses the word text under cursor as query content.put
(just like press the p
key), uses the yank text as query content.resume
, uses the last search content as query content.[!NOTE]
The
args
sub command can be omitted, for example:FzfxFiles<CR>
is equivalent to:FzfxFiles args<CR>
.To specify query text, for example
asdf
, you will have to type:FzfxFiles args asdf<CR>
.
Below keys are binded by default:
--expect
option)esc
: quit.double-click
/enter
: open/jump to file (behave different on some specific commands).alt-p
: toggle preview.ctrl-f
: preview half page down.ctrl-b
: preview half page up.ctrl-e
: toggle select.ctrl-a
: toggle select all." ======== files ========
" by args
nnoremap <space>f :\<C-U>FzfxFiles<CR>
" by visual select
xnoremap <space>f :\<C-U>FzfxFiles visual<CR>
" by cursor word
nnoremap <space>wf :\<C-U>FzfxFiles cword<CR>
" by yank text
nnoremap <space>pf :\<C-U>FzfxFiles put<CR>
" by resume
nnoremap <space>rf :\<C-U>FzfxFiles resume<CR>
" ======== live grep ========
" by args
nnoremap <space>l :\<C-U>FzfxLiveGrep<CR>
" by visual select
xnoremap <space>l :\<C-U>FzfxLiveGrep visual<CR>
" by cursor word
nnoremap <space>wl :\<C-U>FzfxLiveGrep cword<CR>
" by yank text
nnoremap <space>pl :\<C-U>FzfxLiveGrep put<CR>
" by resume
nnoremap <space>rl :\<C-U>FzfxLiveGrep resume<CR>
" ======== buffers ========
" by args
nnoremap <space>bf :\<C-U>FzfxBuffers<CR>
" ======== git files ========
" by args
nnoremap <space>gf :\<C-U>FzfxGFiles<CR>
" ======== git live grep ========
" by args
nnoremap <space>gl :\<C-U>FzfxGLiveGrep<CR>
" by visual select
xnoremap <space>gl :\<C-U>FzfxGLiveGrep visual<CR>
" by cursor word
nnoremap <space>wgl :\<C-U>FzfxGLiveGrep cword<CR>
" by yank text
nnoremap <space>pgl :\<C-U>FzfxGLiveGrep put<CR>
" by resume
nnoremap <space>rgl :\<C-U>FzfxGLiveGrep resume<CR>
" ======== git changed files (status) ========
" by args
nnoremap <space>gs :\<C-U>FzfxGStatus<CR>
" ======== git branches ========
" by args
nnoremap <space>br :\<C-U>FzfxGBranches<CR>
" ======== git commits ========
" by args
nnoremap <space>gc :\<C-U>FzfxGCommits<CR>
" ======== git blame ========
" by args
nnoremap <space>gb :\<C-U>FzfxGBlame<CR>
" ======== lsp diagnostics ========
" by args
nnoremap <space>dg :\<C-U>FzfxLspDiagnostics<CR>
" ======== lsp locations ========
" lsp definitions
nnoremap gd :\<C-U>FzfxLspDefinitions<CR>
" lsp type definitions
nnoremap gt :\<C-U>FzfxLspTypeDefinitions<CR>
" lsp references
nnoremap gr :\<C-U>FzfxLspReferences<CR>
" lsp implementations
nnoremap gi :\<C-U>FzfxLspImplementations<CR>
" lsp incoming calls
nnoremap gI :\<C-U>FzfxLspIncomingCalls<CR>
" lsp outgoing calls
nnoremap gO :\<C-U>FzfxLspOutgoingCalls<CR>
" ======== vim commands ========
" by args
nnoremap <space>cm :\<C-U>FzfxCommands<CR>
" ======== vim key maps ========
" by args
nnoremap <space>km :\<C-U>FzfxKeyMaps<CR>
" ======== vim marks ========
" by args
nnoremap <space>mk :\<C-U>FzfxMarks<CR>
" ======== file explorer ========
" by args
nnoremap <space>xp :\<C-U>FzfxFileExplorer<CR>
-- ======== files ========
-- by args
vim.keymap.set(
"n",
"<space>f",
"<cmd>FzfxFiles<cr>",
{ silent = true, noremap = true, desc = "Find files" }
)
-- by visual select
vim.keymap.set(
"x",
"<space>f",
"<cmd>FzfxFiles visual<CR>",
{ silent = true, noremap = true, desc = "Find files" }
)
-- by cursor word
vim.keymap.set(
"n",
"<space>wf",
"<cmd>FzfxFiles cword<cr>",
{ silent = true, noremap = true, desc = "Find files by cursor word" }
)
-- by yank text
vim.keymap.set(
"n",
"<space>pf",
"<cmd>FzfxFiles put<cr>",
{ silent = true, noremap = true, desc = "Find files by yank text" }
)
-- by resume
vim.keymap.set(
"n",
"<space>rf",
"<cmd>FzfxFiles resume<cr>",
{ silent = true, noremap = true, desc = "Find files by resume last" }
)
-- ======== live grep ========
-- live grep
vim.keymap.set(
"n",
"<space>l",
"<cmd>FzfxLiveGrep<cr>",
{ silent = true, noremap = true, desc = "Live grep" }
)
-- by visual select
vim.keymap.set(
"x",
"<space>l",
"<cmd>FzfxLiveGrep visual<cr>",
{ silent = true, noremap = true, desc = "Live grep" }
)
-- by cursor word
vim.keymap.set(
"n",
"<space>wl",
"<cmd>FzfxLiveGrep cword<cr>",
{ silent = true, noremap = true, desc = "Live grep by cursor word" }
)
-- by yank text
vim.keymap.set(
"n",
"<space>pl",
"<cmd>FzfxLiveGrep put<cr>",
{ silent = true, noremap = true, desc = "Live grep by yank text" }
)
-- by resume
vim.keymap.set(
"n",
"<space>rl",
"<cmd>FzfxLiveGrep resume<cr>",
{ silent = true, noremap = true, desc = "Live grep by resume last" }
)
-- ======== buffers ========
-- by args
vim.keymap.set(
"n",
"<space>bf",
"<cmd>FzfxBuffers<cr>",
{ silent = true, noremap = true, desc = "Find buffers" }
)
-- ======== git files ========
-- by args
vim.keymap.set(
"n",
"<space>gf",
"<cmd>FzfxGFiles<cr>",
{ silent = true, noremap = true, desc = "Find git files" }
)
-- ======== git live grep ========
-- by args
vim.keymap.set(
"n",
"<space>gl",
"<cmd>FzfxGLiveGrep<cr>",
{ silent = true, noremap = true, desc = "Git live grep" }
)
-- by visual select
vim.keymap.set(
"x",
"<space>gl",
"<cmd>FzfxGLiveGrep visual<cr>",
{ silent = true, noremap = true, desc = "Git live grep" }
)
-- by cursor word
vim.keymap.set(
"n",
"<space>wgl",
"<cmd>FzfxGLiveGrep cword<cr>",
{ silent = true, noremap = true, desc = "Git live grep by cursor word" }
)
-- by yank text
vim.keymap.set(
"n",
"<space>pgl",
"<cmd>FzfxGLiveGrep put<cr>",
{ silent = true, noremap = true, desc = "Git live grep by yank text" }
)
-- by resume
vim.keymap.set(
"n",
"<space>rgl",
"<cmd>FzfxGLiveGrep resume<cr>",
{ silent = true, noremap = true, desc = "Git live grep by resume last" }
)
-- ======== git changed files (status) ========
-- by args
vim.keymap.set(
"n",
"<space>gs",
"<cmd>FzfxGStatus<cr>",
{ silent = true, noremap = true, desc = "Find git changed files (status)" }
)
-- ======== git branches ========
-- by args
vim.keymap.set(
"n",
"<space>br",
"<cmd>FzfxGBranches<cr>",
{ silent = true, noremap = true, desc = "Search git branches" }
)
-- ======== git commits ========
-- by args
vim.keymap.set(
"n",
"<space>gc",
"<cmd>FzfxGCommits<cr>",
{ silent = true, noremap = true, desc = "Search git commits" }
)
-- ======== git blame ========
-- by args
vim.keymap.set(
"n",
"<space>gb",
"<cmd>FzfxGBlame<cr>",
{ silent = true, noremap = true, desc = "Search git blame" }
)
-- ======== lsp diagnostics ========
-- by args
vim.keymap.set(
"n",
"<space>dg",
"<cmd>FzfxLspDiagnostics<cr>",
{ silent = true, noremap = true, desc = "Search lsp diagnostics" }
)
-- ======== lsp symbols ========
-- lsp definitions
vim.keymap.set(
"n",
"gd",
"<cmd>FzfxLspDefinitions<cr>",
{ silent = true, noremap = true, desc = "Goto lsp definitions" }
)
-- lsp type definitions
vim.keymap.set(
"n",
"gt",
"<cmd>FzfxLspTypeDefinitions<cr>",
{ silent = true, noremap = true, desc = "Goto lsp type definitions" }
)
-- lsp references
vim.keymap.set(
"n",
"gr",
"<cmd>FzfxLspReferences<cr>",
{ silent = true, noremap = true, desc = "Goto lsp references" }
)
-- lsp implementations
vim.keymap.set(
"n",
"gi",
"<cmd>FzfxLspImplementations<cr>",
{ silent = true, noremap = true, desc = "Goto lsp implementations" }
)
-- lsp incoming calls
vim.keymap.set(
"n",
"gI",
"<cmd>FzfxLspIncomingCalls<cr>",
{ silent = true, noremap = true, desc = "Goto lsp incoming calls" }
)
-- lsp outgoing calls
vim.keymap.set(
"n",
"gO",
"<cmd>FzfxLspOutgoingCalls<cr>",
{ silent = true, noremap = true, desc = "Goto lsp outgoing calls" }
)
-- ======== vim commands ========
-- by args
vim.keymap.set(
"n",
"<space>cm",
"<cmd>FzfxCommands<cr>",
{ silent = true, noremap = true, desc = "Search vim commands" }
)
-- ======== vim key maps ========
-- by args
vim.keymap.set(
"n",
"<space>km",
"<cmd>FzfxKeyMaps<cr>",
{ silent = true, noremap = true, desc = "Search vim keymaps" }
)
-- ======== vim marks ========
-- by args
vim.keymap.set(
"n",
"<space>mk",
"<cmd>FzfxMarks<cr>",
{ silent = true, noremap = true, desc = "Search vim marks" }
)
-- ======== file explorer ========
-- by args
vim.keymap.set(
"n",
"<space>xp",
"<cmd>FzfxFileExplorer<cr>",
{ silent = true, noremap = true, desc = "File explorer" }
)
To configure options, please use:
require('fzfx').setup(opts)
The opts
is an optional lua table that override the default options.
For complete default options, please see config.lua.
For advanced configurations, please check Advanced Configuration.
To enable/disable some features, please define below global variables before setup this plugin:
vim.g.fzfx_disable_buffer_previewer
: Disable nvim buffer for previewing file contents, use fzf builtin preview window via bat
with best performance.
" vim scripts
let g:fzfx_disable_buffer_previewer = 1 " or v:true
-- lua scripts
vim.g.fzfx_disable_buffer_previewer = 1 -- or true
Here's a minimal example that implement the ls -1
like FzfxLs
command:
https://github.com/linrongbin16/fzfx.nvim/assets/6496887/c704e5b2-d82a-45f2-8920-adeec5d3e7c2
require("fzfx").setup({
users = {
ls = {
--- @type CommandConfig
command = {
name = "FzfxLs",
desc = "File Explorer (ls -1)",
},
variants = {
{
name = "args",
feed = "args",
default_provider = "filter_hiddens",
},
{
name = "hidden_args",
feed = "args",
default_provider = "include_hiddens",
},
},
--- @type table<string, ProviderConfig>
providers = {
filter_hiddens = {
key = "ctrl-h",
provider = { "ls", "--color=always", "-1" },
},
include_hiddens = {
key = "ctrl-u",
provider = { "ls", "--color=always", "-1a" },
},
},
--- @type table<string, PreviewerConfig>
previewers = {
filter_hiddens = {
previewer = function(line)
-- each line is either a folder or a file
return vim.fn.isdirectory(line) > 0 and { "ls", "--color=always", "-lha", line }
or { "cat", line }
end,
previewer_type = "command_list",
},
include_hiddens = {
previewer = function(line)
return vim.fn.isdirectory(line) > 0 and { "ls", "--color=always", "-lha", line }
or { "cat", line }
end,
previewer_type = "command_list",
},
},
actions = {
["esc"] = function(lines)
-- do nothing
end,
["enter"] = function(lines)
for _, line in ipairs(lines) do
vim.cmd(string.format([[edit %s]], line))
end
end,
},
fzf_opts = {
"--multi",
{ "--prompt", "Ls > " },
},
},
},
})
You can also use the require("fzfx").register("ls", {...})
api to do that.
For detailed explanation of each components, please see A Generic Schema for Creating FZF Command and schema.lua.
To help easier customizing/integrating, fzfx provides below builtin modules and APIs:
fzfx.cfg
: Top-level configurations, e.g. directly create the FzfxFiles
, FzfxLiveGrep
, etc search commands. Easy to read and learn all the components used in those commands, as well as easy to copy and paste.
fzfx.helper
: Line-oriented helper utilities for parsing and rendering user queries and lines, since a search command is actually all about the lines in (both left and right side of) the fzf binary: generate lines, preview lines, invoke callbacks on selected lines, etc.
fzfx.lib
: Low-level fundamental infrastructures, fzfx use the commons lua library for most of the common utilities, please also refer to commons.nvim's documentation.
The commons library was originally part of fzfx.lib, since I found they're so commonly used that I almost need them for every of my Neovim plugins, I extracted them from fzfx and build up this library.
Please see API References for more details.
Please see Known Issues if you encountered any issue.
To develop the project and make PR, please setup with:
To run unit tests, please install below dependencies:
Then test with vusted ./spec
.
Please open issue/PR for anything about fzfx.nvim.
Like fzfx.nvim? Consider