From 691b37f9ea91dd0f6ab4607db027361e750ca36b Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Sat, 25 Feb 2023 10:41:18 -0700 Subject: [PATCH 1/2] Handle completion of % and # completion correctly. The current behavior if you try to complete :e %:p:h or something similar replaces only the h with the path, which isn't the desired behavior, because then nvim tries to open the wrong filename. Detect this case and produce edits that will replace the entire `%` chain with modifiers. --- lua/cmp_cmdline/init.lua | 47 +++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/lua/cmp_cmdline/init.lua b/lua/cmp_cmdline/init.lua index 53e7593..1756d24 100644 --- a/lua/cmp_cmdline/init.lua +++ b/lua/cmp_cmdline/init.lua @@ -83,6 +83,8 @@ local definitions = { isIncomplete = true, ---@param option cmp-cmdline.Option exec = function(option, arglead, cmdline, force) + -- Any edits we produce are relative to the whole command line. + local cmdline_length = #cmdline -- Ignore range only cmdline. (e.g.: 4, '<,'>) if not force and ONLY_RANGE_REGEX:match_str(cmdline) then return {} @@ -120,11 +122,7 @@ local definitions = { -- In this case, the `vim.fn.getcompletion` will return only `get_query` for `vim.treesitter.get_|`. -- We should detect `vim.treesitter.` and `get_query` separately. -- TODO: The `\h\w*` was choosed by huristic. We should consider more suitable detection. - local fixed_input - do - local suffix_pos = vim.regex([[\h\w*$]]):match_str(arglead) - fixed_input = string.sub(arglead, 1, suffix_pos or #arglead) - end + local fixed_input = arglead -- The `vim.fn.getcompletion` does not return `*no*cursorline` option. -- cmp-cmdline corrects `no` prefix for option name. @@ -133,6 +131,13 @@ local definitions = { --- create items. local items = {} local escaped = cmdline:gsub([[\\]], [[\\\\]]); + local is_magic_file = false + local input_start = string.sub(fixed_input, 1, 1) + if input_start == '%' then + is_magic_file = true + elseif input_start == '#' then + is_magic_file = true + end for _, word_or_item in ipairs(vim.fn.getcompletion(escaped, 'cmdline')) do local word = type(word_or_item) == 'string' and word_or_item or word_or_item.word local item = { label = word } @@ -147,9 +152,25 @@ local definitions = { -- fix label with `fixed_input` for _, item in ipairs(items) do - if not string.find(item.label, fixed_input, 1, true) then + if not is_magic_file and not string.find(item.label, fixed_input, 1, true) then item.label = fixed_input .. item.label end + if is_magic_file then + local replace_range = { + start = { + character = cmdline_length - #fixed_input - 1 + }, + ['end'] = { + character = cmdline_length - 1 + } + } + item.textEdit = { + replace = replace_range, + range = replace_range, + newText = item.label + } + item.label = fixed_input .. ' → ' .. item.label + end end -- fix trailing slash for path like item @@ -217,6 +238,20 @@ source.complete = function(self, params, callback) for _, item in ipairs(items) do item.kind = kind labels[item.label] = true + if item['textEdit'] ~= nil then + local new_range = { + start = { + character = item.textEdit.range.start.character, + line = params.context.cursor.line + }, + ['end'] = { + character = item.textEdit.range['end'].character, + line = params.context.cursor.line + } + } + item.textEdit.replace = new_range + item.textEdit.range = new_range + end end -- `vim.fn.getcompletion` does not handle fuzzy matches. So, we must return all items, including items that were matched in the previous input. From 7e3167457e1ff7cae13bca81dade7fbf4578ec84 Mon Sep 17 00:00:00 2001 From: Kyle Butt Date: Wed, 24 Apr 2024 14:01:57 -0600 Subject: [PATCH 2/2] Add back the `fixed_input` detection Ignore fixed_input and use arglead directly in the case of a magic file match. This unbreaks `%:.:h:h`, while still handling fixed_input correctly in the non magic_file case. --- lua/cmp_cmdline/init.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lua/cmp_cmdline/init.lua b/lua/cmp_cmdline/init.lua index 1756d24..0eb5ee4 100644 --- a/lua/cmp_cmdline/init.lua +++ b/lua/cmp_cmdline/init.lua @@ -122,7 +122,11 @@ local definitions = { -- In this case, the `vim.fn.getcompletion` will return only `get_query` for `vim.treesitter.get_|`. -- We should detect `vim.treesitter.` and `get_query` separately. -- TODO: The `\h\w*` was choosed by huristic. We should consider more suitable detection. - local fixed_input = arglead + local fixed_input + do + local suffix_pos = vim.regex([[\h\w*$]]):match_str(arglead) + fixed_input = string.sub(arglead, 1, suffix_pos or #arglead) + end -- The `vim.fn.getcompletion` does not return `*no*cursorline` option. -- cmp-cmdline corrects `no` prefix for option name. @@ -158,7 +162,7 @@ local definitions = { if is_magic_file then local replace_range = { start = { - character = cmdline_length - #fixed_input - 1 + character = cmdline_length - #arglead - 1 }, ['end'] = { character = cmdline_length - 1 @@ -169,7 +173,7 @@ local definitions = { range = replace_range, newText = item.label } - item.label = fixed_input .. ' → ' .. item.label + item.label = arglead .. ' → ' .. item.label end end