summaryrefslogtreecommitdiffstats
path: root/.config/nvim/plugin/50-autocompletion.lua
blob: 853a528f4249188f43bba6eff9cf43acd2bb8196 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
--
-- 50-autocompletion.lua
--
-- * Configures autocompletion for insert mode and command-line mode.
--   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
----------------------------------------------------------------------------------------------------

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
	"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.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

----------------------------------------------------------------------------------------------------

-- Show completion menu automatically
vim.api.nvim_create_autocmd({ "CmdLineChanged", "CmdlineEnter" }, {
	desc = "Autocompletion",
	group = vim.g.dotfiles.augroup,
	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 (`<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 (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
}

-- 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 })
vim.keymap.set("c", "<C-y>", c_accept_selection_or_dismiss, { expr = true })