diff --git a/neovim/lua/plugins/fzf.lua b/neovim/lua/plugins/fzf.lua index 5a4974d..b73b316 100644 --- a/neovim/lua/plugins/fzf.lua +++ b/neovim/lua/plugins/fzf.lua @@ -3,6 +3,7 @@ return { { "ibhagwan/fzf-lua", dependencies = { "echasnovski/mini.nvim", version = "*" }, + event = "VeryLazy", keys = { { "gd", "FzfLua lsp_definitions", desc = "Go to definition" }, { @@ -10,7 +11,7 @@ return { "vsplit | FzfLua lsp_definitions", desc = "Go to definition in a split", }, - { "gy", "FzfLua lsp_typedefs", desc = "Go to type definition" }, + { "grt", "FzfLua lsp_typedefs", desc = "Go to type definition" }, { "grr", "FzfLua lsp_references", desc = "Go to references" }, { "gri", diff --git a/neovim/lua/plugins/mini.lua b/neovim/lua/plugins/mini.lua index 7362e64..d0583d8 100644 --- a/neovim/lua/plugins/mini.lua +++ b/neovim/lua/plugins/mini.lua @@ -10,6 +10,7 @@ return { event = "UIEnter", opts = { cmdline = { + autocorrect = { enable = false }, autopeek = { enable = false }, }, completion = {}, diff --git a/neovim/plugin/fuzzy.lua b/neovim/plugin/fuzzy.lua new file mode 100644 index 0000000..6d22706 --- /dev/null +++ b/neovim/plugin/fuzzy.lua @@ -0,0 +1,73 @@ +-- Fuzzy finder using findfunc + matchfuzzy, with wildtrigger autocomplete. + +-- Files cache, cleared on each cmdline entry. +local filescache = {} + +--- Get a list of all files using built-in globpath. +local function glob_files() + local raw = vim.fn.globpath(".", "**", true, true) + local files = {} + for _, path in ipairs(raw) do + if vim.fn.isdirectory(path) == 0 then + files[#files + 1] = vim.fn.fnamemodify(path, ":.") + end + end + return files +end + +--- Get a list of all files using fd. +local function fd_files() + local result = vim.fn.systemlist({ + "fd", + "--exclude", + ".git", + "--follow", + "--full-path", + "--hidden", + "--type", + "file", + }) + if vim.v.shell_error ~= 0 then + vim.api.nvim_err_writeln(table.concat(result, "\n")) + return {} + end + return result +end + +local files_fetcher = vim.fn.executable("fd") == 1 and fd_files or glob_files + +--- findfunc: return fuzzy-matched filenames for :find. +--- Exposed as a global for v:lua access. +function _G.FindFunc(file) + if #filescache == 0 then + filescache = files_fetcher() + end + if file == "" then + return filescache + end + return vim.fn.matchfuzzy(filescache, file) +end + +vim.o.findfunc = "v:lua.FindFunc" + +-- Cmdline autocompletion via wildtrigger + cache clearing. +-- FIXME(kirill.morozov): create autocommand only if Neovim >= 0.12 +local fuzzy_group = vim.api.nvim_create_augroup("fuzzy", { clear = true }) + +vim.api.nvim_create_autocmd("CmdlineChanged", { + group = fuzzy_group, + pattern = { ":", "/", "?" }, + desc = "Trigger cmdline autocompletion", + callback = function() + vim.fn.wildtrigger() + end, +}) + +vim.api.nvim_create_autocmd("CmdlineEnter", { + group = fuzzy_group, + pattern = ":", + desc = "Clear files cache on cmdline entry", + callback = function() + filescache = {} + end, +}) diff --git a/neovim/plugin/keymaps.lua b/neovim/plugin/keymaps.lua index 5605a43..c9fe477 100644 --- a/neovim/plugin/keymaps.lua +++ b/neovim/plugin/keymaps.lua @@ -69,6 +69,21 @@ vim.keymap.set( vim.lsp.buf.code_action, { desc = "Select a code action" } ) +vim.keymap.set("n", "gsd", function() + vim.cmd.vsplit() + vim.lsp.buf.definition() +end, { desc = "Go to definition in a split" }) +vim.keymap.set("n", "s", function() + if next(vim.lsp.get_clients({ bufnr = 0 })) then + vim.lsp.buf.document_symbol() + end +end, { desc = "Document symbols" }) +vim.keymap.set( + "n", + "S", + vim.lsp.buf.workspace_symbol, + { desc = "Workspace symbols" } +) -- Move text up and down vim.keymap.set("n", "", ":m .+1==", { desc = "Move line down" }) @@ -78,3 +93,47 @@ vim.keymap.set("v", "", ":m '<-2gv=gv", { desc = "Move selection up" } -- Open in split vim.keymap.set("n", "gsf", "vgf", { desc = "Go to file in a split" }) + +-- Search +vim.keymap.set("n", "/", ":grep ", { desc = "Grep" }) + +-- Find and buffer navigation +vim.keymap.set("n", "f", ":find ", { desc = "Find file" }) +vim.keymap.set("n", "b", ":buffer ", { desc = "Switch buffer" }) +vim.keymap.set("n", "h", ":help ", { desc = "Help" }) +vim.keymap.set("n", "j", vim.cmd.jumps, { desc = "List jumps" }) + +-- Diagnostics +vim.keymap.set("n", "d", function() + vim.diagnostic.setloclist({ open = true }) +end, { desc = "Document diagnostics" }) +vim.keymap.set("n", "D", function() + vim.diagnostic.setqflist({ open = true }) +end, { desc = "Workspace diagnostics" }) + +-- in cmdline: open :find, :buffer, :help in a vertical split. +local vert_replacements = { + find = "vert sfind", + buffer = "vert sbuffer", + help = "vert help", +} + +vim.keymap.set("c", "", function() + if vim.fn.getcmdtype() ~= ":" then + return "" + end + local line = vim.fn.getcmdline() + for cmd, vert_cmd in pairs(vert_replacements) do + if line:match("^%s*" .. cmd .. "%s") then + local new_line = + line:gsub("^(%s*)" .. cmd .. "%s", "%1" .. vert_cmd .. " ", 1) + return "" .. new_line .. "" + end + end + return "" +end, { expr = true, desc = "Open in vertical split from cmdline" }) + +-- Re-open last command pre-filled for editing +vim.keymap.set("n", "'", function() + vim.fn.feedkeys(":" .. vim.fn.histget(":"), "tn") +end, { silent = true, desc = "Resume last command" })