diff options
Diffstat (limited to '.config/nvim/plugin/50-completion.lua')
| -rw-r--r-- | .config/nvim/plugin/50-completion.lua | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/.config/nvim/plugin/50-completion.lua b/.config/nvim/plugin/50-completion.lua index caf749d..56c99d7 100644 --- a/.config/nvim/plugin/50-completion.lua +++ b/.config/nvim/plugin/50-completion.lua @@ -36,6 +36,62 @@ vim.keymap.set({ "i", "s" }, "<C-p>", function() end, { expr = true }) ------------------------------------------------------------------------------------------------------------------------ +-- Snippet expansion fallback +------------------------------------------------------------------------------------------------------------------------ +-- Work around Neovim's snippet grammar rejecting placeholder defaults that mix text with nested tabstops (e.g. lua_ls's +-- `${1:pairs(${2:t})}`): the `any_or_text` rule matches a single node, not a `(any + text)^1` sequence. On parse failure, +-- strip the snippet markup and insert it as plain text instead of throwing. Remove once fixed upstream. +-- The `@as table` cast retypes the module here so overriding `expand` isn't flagged as a duplicate field set. +local snippet = vim.snippet --[[@as table]] +local orig_expand = snippet.expand + +-- Reduce LSP snippet syntax to plain text: keep placeholder/variable defaults, the first choice, drop bare tabstops. +local function strip_snippet(s) + local prev + repeat + prev = s + s = s:gsub("%$(%b{})", function(group) + local body = group:sub(2, -2) + local choice = body:match("^%d+|(.*)|$") + if choice then + return (choice:gsub(",.*$", "")) -- first choice + end + local default = body:match("^[%w_]+:(.*)$") + if default then + return default -- ${n:default} / ${VAR:default} + end + return "" -- bare ${n} / ${VAR} + end) + until s == prev + s = s:gsub("%$[%w_]+", "") -- bare $n / $VAR + s = s:gsub("\\([%$}{|,\\])", "%1") -- unescape + return s +end + +local function insert_plain(text) + local win = vim.api.nvim_get_current_win() + local row, col = unpack(vim.api.nvim_win_get_cursor(win)) + local indent = vim.api.nvim_get_current_line():match("^%s*") or "" + local lines = vim.split(text, "\n", { plain = true }) + for i = 2, #lines do + lines[i] = indent .. lines[i] + end + vim.api.nvim_buf_set_text(0, row - 1, col, row - 1, col, lines) + local last = #lines + local new_row = row - 1 + (last - 1) + local new_col = last == 1 and col + #lines[1] or #lines[last] + vim.api.nvim_win_set_cursor(win, { new_row + 1, new_col }) +end + +snippet.expand = function(input) + local ok = pcall(orig_expand, input) + if not ok then + insert_plain(strip_snippet(input)) + vim.notify("Snippet parse failed, inserted as plain text: " .. vim.inspect(input), vim.log.levels.WARN) + end +end + +------------------------------------------------------------------------------------------------------------------------ -- Command-line mode completion ------------------------------------------------------------------------------------------------------------------------ -- See `:help cmdline-completion` and `:help cmdline-autocompletion` |
