summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Vanbesien <tvanbesi@proton.me>2026-06-12 23:14:19 +0200
committerThomas Vanbesien <tvanbesi@proton.me>2026-06-12 23:14:19 +0200
commit815118736104b3adbdc449cf0024611994e377b1 (patch)
treea18a385aca3e3102b3fbf875da804e232ee1308d
parentaa15a0fe47418a2fe1354589a3dafd3ae8c3db42 (diff)
downloaddotfiles-815118736104b3adbdc449cf0024611994e377b1.tar.gz
dotfiles-815118736104b3adbdc449cf0024611994e377b1.zip
refactor(nvim): rewrite autocompletion plugin
-rw-r--r--.config/nvim/plugin/50-autocompletion.lua116
1 files changed, 69 insertions, 47 deletions
diff --git a/.config/nvim/plugin/50-autocompletion.lua b/.config/nvim/plugin/50-autocompletion.lua
index caf749d..dbc5dee 100644
--- a/.config/nvim/plugin/50-autocompletion.lua
+++ b/.config/nvim/plugin/50-autocompletion.lua
@@ -1,81 +1,103 @@
--
--- Completion configuration plugin
+-- 50-autocompletion.lua
--
+-- * Configures insert-mode/command-mode autocompletion.
+-- In both modes:
+-- * The list of completions shows up automatically
+-- * Tab/Shift+Tab selects (and inserts) the next/previous item
+-- In cmd-line mode:
+-- * Tab selects a lone match outright, inserts it, closes the menu
+-- (Useful when completing file names)
+-- * CTRL+Y inserts the selection; with no selection it dismisses the menu
+--
+
+----------------------------------------------------------------------------------------------------
+-- Insert mode autocompletion
+----------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------
--- Insert mode completion
-------------------------------------------------------------------------------------------------------------------------
--- See `:help ins-completion-menu`
+local function i_select_next_menu_item()
+ return vim.fn.pumvisible() == 1 and "<C-n>" or "<Tab>"
+end
+
+local function i_select_previous_menu_item()
+ return vim.fn.pumvisible() == 1 and "<C-p>" or "<S-Tab>"
+end
+
+----------------------------------------------------------------------------------------------------
vim.opt.autocomplete = true -- Show completion menu automatically
vim.opt.completeopt = {
"noselect", -- No item selected initially
- "fuzzy",
"menuone", -- Show matches in a menu, even if there's only one match
"popup", -- Menu items show extra info in the popup window
+ "fuzzy",
}
-
-- Completion sources (in order of priority)
vim.opt.complete = {
"o", -- 'omnifunc'
}
-vim.opt.pumwidth = 25
-vim.keymap.set("i", "<Tab>", function()
- return vim.fn.pumvisible() == 1 and "<C-n>" or "<Tab>"
-end, { expr = true })
-vim.keymap.set("i", "<S-Tab>", function()
- return vim.fn.pumvisible() == 1 and "<C-p>" or "<S-Tab>"
-end, { expr = true })
--- Jump between snippet placeholders, falling back to native behavior when no snippet is active
-vim.keymap.set({ "i", "s" }, "<C-n>", function()
- return vim.snippet.active({ direction = 1 }) and "<Cmd>lua vim.snippet.jump(1)<CR>" or "<C-n>"
-end, { expr = true })
-vim.keymap.set({ "i", "s" }, "<C-p>", function()
- return vim.snippet.active({ direction = -1 }) and "<Cmd>lua vim.snippet.jump(-1)<CR>" or "<C-p>"
-end, { expr = true })
+vim.keymap.set("i", "<Tab>", i_select_next_menu_item, { expr = true })
+vim.keymap.set("i", "<S-Tab>", i_select_previous_menu_item, { expr = true })
+
+----------------------------------------------------------------------------------------------------
+-- Command-line mode autocompletion
+----------------------------------------------------------------------------------------------------
+-- `<Space><BS>` is a self-cancelling edit: it closes the menu, then `CmdLineChanged` fires and
+-- tries to perform completion on the text before the cursor.
+
+local function c_insert_unique_or_wildtrigger()
+ local complete_info = vim.fn.cmdcomplete_info()
+ if complete_info.pum_visible == 1 then
+ return #complete_info.matches == 1 and "<C-n><Space><BS>" or "<C-n>"
+ end
+ -- After navigating the command-line history, it takes two `wildtrigger()` calls to show the
+ -- menu. The first is performed by the `CmdLineChanged` autocommand, the second is performed
+ -- here.
+ vim.fn.wildtrigger()
+ return nil
+end
+
+local function c_accept_selection_or_dismiss()
+ local complete_info = vim.fn.cmdcomplete_info()
+ if complete_info.pum_visible == 1 then
+ return complete_info.selected ~= -1 and "<Space><BS>" or "<C-e>"
+ end
+ return "<C-y>"
+end
-------------------------------------------------------------------------------------------------------------------------
--- Command-line mode completion
-------------------------------------------------------------------------------------------------------------------------
--- See `:help cmdline-completion` and `:help cmdline-autocompletion`
+----------------------------------------------------------------------------------------------------
-- Show completion menu automatically
-vim.api.nvim_create_autocmd({ "CmdlineChanged", "CmdlineEnter" }, {
+vim.api.nvim_create_autocmd({ "CmdLineChanged", "CmdlineEnter" }, {
desc = "Autocompletion",
group = vim.g.dotfiles.augroup,
- pattern = "[:\\/\\?]",
+ pattern = "[:\\/\\?]", -- Matches : commands plus / and ? searches, but not = and @
callback = function()
vim.fn.wildtrigger()
end,
})
+
vim.opt.wildmenu = true -- Show completions in a menu
-vim.opt.wildchar = 9 -- Char code assigned to command line wildcard expansion
-vim.opt.pumborder = "rounded"
+vim.opt.wildchar = 9 -- Char code (`<Tab>`) assigned to command line wildcard expansion
vim.opt.wildoptions = {
"exacttext", -- Discard regex artifacts when performing search pattern completion
"pum", -- Show completions in a popup menu
"tagfile", -- Show tag kind and file
- "fuzzy", -- Fuzzy matching (doesn't work with files/dirs, see `:help 'wildoptions'`, but patterns do work!)
+ "fuzzy", -- Fuzzy matching (except for files/dirs, use patterns)
}
-- Completion modes triggered in order by `wildtrigger()` or 'wildchar'
vim.opt.wildmode = {
"noselect", -- List matches without inserting
- "full", -- List matches and insert first full match
+ "full", -- List matches and inserts first full match
}
--- Insert unique match
-vim.keymap.set("c", string.format("%c", vim.o.wildchar), function()
- local complete_info = vim.fn.cmdcomplete_info()
- if complete_info.pum_visible == 1 then
- return #complete_info.matches == 1 and "<C-n><Space><BS>" or "<C-n>"
- end
- vim.fn.wildtrigger()
-end, { expr = true, desc = "Command line wildcard expansion" })
--- Show next completion choices after accepting an entry with `<C-y>`
-vim.keymap.set("c", "<C-y>", function()
- local complete_info = vim.fn.cmdcomplete_info()
- if complete_info.pum_visible == 1 then
- return complete_info.selected ~= -1 and "<Space><BS>" or "<C-e>"
- end
- return "<C-y>"
-end, { expr = true })
+
+-- Converts `vim.opt.wildchar` char code into a key string that can be used by `vim.keymap.set()`.
+local wildchar_key = string.format("%c", vim.o.wildchar)
+vim.keymap.set(
+ "c",
+ wildchar_key,
+ c_insert_unique_or_wildtrigger,
+ { expr = true, desc = "Command line wildcard expansion" }
+)
+vim.keymap.set("c", "<C-y>", c_accept_selection_or_dismiss, { expr = true })