Open dlee opened 2 years ago
I can reproduce this. Also, sometimes, expanding %
doesn't even do anything. I'm not sure how to reproduce that one because it doesn't happen all the time.
I found that this keyword pattern can help prevent cmp from messing with the %
sign:
[^[:blank:]%]*
{ name = 'cmdline', keyword_pattern = [=[[^[:blank:]%]*]=] },
It's similar to the solution to a different issue suggested by @RnYi in https://github.com/hrsh7th/cmp-cmdline/issues/24#issuecomment-1005662931
https://user-images.githubusercontent.com/551858/166122850-1f9bf2a2-8bc2-45cc-80bf-801c1775ac3b.mp4
It doesn't work however with %:h
I suspect a different approach may be necessary. I played with an alternative: a positive regex (as in list the things that DO trigger a completion instead of those that shouldn't) with a negative lookbehind (to ensure the string didn't start with something we don't want to complete).
For example (?<!%:|%)[a-zA-Z0-9#_\.]+
, but I'm not sure how to get this to work in Lua and Neovim
https://regex101.com/r/dCXdz7/1
This is the closest thing I could find for implementing the regex in vim https://stackoverflow.com/a/20409575
So it would look something like this in verymagic
:
(\%)@<!([a-zA-Z0-9_\-# ]+)
Maybe I'm overthinking this and going about it all wrong though..
@hrsh7th any thoughts?
Here's one alternative way to handle this, that also takes care of "%:h" and similar constructs. I use this function in cmp.setup.cmdline(":", ...)
local function delay(fn, time)
local timer = vim.loop.new_timer()
timer:start(time, 0, vim.schedule_wrap(function()
fn()
timer:stop()
end))
end
function M.on_tab(fallback)
local cmp = require"cmp"
if vim.api.nvim_get_mode().mode == "c" then
local text = vim.fn.getcmdline()
local expanded = vim.fn.expandcmd(text)
if expanded ~= text then
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<C-U>", true, true, true) .. expanded, "n", false)
-- triggering right away won't work, need to wait a cycle
delay(cmp.complete, 0)
elseif cmp.visible() then
cmp.select_next_item()
else
cmp.complete()
end
end -- in the real mapping there are other elseif clauses
end
What this does is it expands the commandline on tab and then triggers the completion. It will reset your cursor position to the end of the line, but if that annoys you, you can play with vim.fn.setcmdpos()
and expansion rules.
This is just another workaround though.
couldn't get the workarounds above working somehow. any hints on resolving this?
I am corrently experiencing this, too. And I have a currently not well functionality, that avoids completion in case of a path-expansion-thingy
I do not know why, but currently it is not showing the provided completion options, maybe I am missing something, you can ha ve a look here. https://github.com/m42e/cmp-cmdline
Maybe @hrsh7th give me a hint.
couldn't get the workarounds above working somehow. any hints on resolving this?
I tried this, it works!
local function delay(fn, time)
local timer = vim.loop.new_timer()
timer:start(time, 0, vim.schedule_wrap(function()
fn()
timer:stop()
end))
end
cmd_mapping = cmp.mapping.preset.cmdline()
cmd_mapping_override = {
['<Tab>'] = {
c = function()
if vim.api.nvim_get_mode().mode == "c" and cmp.get_selected_entry() == nil then
local text = vim.fn.getcmdline()
local expanded = vim.fn.expandcmd(text)
if expanded ~= text then
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<C-U>", true, true, true) .. expanded, "n", false)
-- triggering right away won't work, need to wait a cycle
delay(cmp.complete, 0)
elseif cmp.visible() then
cmp.select_next_item()
else
cmp.complete()
end
else
if cmp.visible() then
cmp.select_next_item()
else
cmp.complete()
end
end -- in the real mapping there are other elseif clauses
end,
},
['<S-Tab>'] = {
c = function()
if vim.api.nvim_get_mode().mode == "c" and cmp.get_selected_entry() == nil then
local text = vim.fn.getcmdline()
local expanded = vim.fn.expandcmd(text)
if expanded ~= text then
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<C-U>", true, true, true) .. expanded, "n", false)
-- triggering right away won't work, need to wait a cycle
delay(cmp.complete, 0)
elseif cmp.visible() then
cmp.select_prev_item()
else
cmp.complete()
end
else
if cmp.visible() then
cmp.select_prev_item()
else
cmp.complete()
end
end
end
}
}
for k, v in pairs(cmd_mapping_override) do
cmd_mapping[k] = v
end
-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
cmp.setup.cmdline(':', {
mapping = cmd_mapping,
sources = cmp.config.sources({
{ name = 'cmdline' },
{ name = 'path' },
{ name = 'cmdline_history' }
})
})
My workaround: life is very simple if you like to use <C-n>
and <C-p>
to select completion options. You can just delete the tab binding and the nvim builtin behavior continues to work. 🙂
local cmdline_mapping = cmp.mapping.preset.cmdline{ ... }
cmdline_mapping['<Tab>'] = nil
cmp.setup.cmdline({':'}, {
mapping = cmdline_mapping,
sources = cmp.config.sources({
{ name = 'cmdline' },
}
})
I have a feeling this issue is related to this other one as it only seems to manifest itself after doing a search using /
.
Thanks @chengzeyi for this! I've simplified it a bit with a helper function:
local function delay(cb, time)
local timer = vim.loop.new_timer()
timer:start(
time,
0,
vim.schedule_wrap(function()
cb()
timer:stop()
end)
)
end
local function handle_tab_complete(direction)
return function()
if vim.api.nvim_get_mode().mode == 'c' and cmp.get_selected_entry() == nil then
local text = vim.fn.getcmdline()
---@diagnostic disable-next-line: param-type-mismatch
local expanded = vim.fn.expandcmd(text)
if expanded ~= text then
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<C-U>', true, true, true) .. expanded, 'n', false)
-- triggering right away won't work, need to wait a cycle
delay(cmp.complete, 0)
elseif cmp.visible() then
direction()
else
cmp.complete()
end
else
if cmp.visible() then
direction()
else
cmp.complete()
end
end
end
end
cmp.setup.cmdline(':', {
mapping = cmp.mapping.preset.cmdline {
['<Tab>'] = { c = handle_tab_complete(cmp.select_next_item) },
['<S-Tab>'] = { c = handle_tab_complete(cmp.select_prev_item) },
-- ... rest of your mappings ...
},
-- ... rest of your config ...
}
Also, the delay doesn't seem necessary to me, this seems to work as well:
local function handle_tab_complete(direction)
return function()
if vim.api.nvim_get_mode().mode == 'c' and cmp.get_selected_entry() == nil then
local text = vim.fn.getcmdline()
---@diagnostic disable-next-line: param-type-mismatch
local expanded = vim.fn.expandcmd(text)
if expanded ~= text then
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<C-U>', true, true, true) .. expanded, 'n', false)
cmp.complete()
elseif cmp.visible() then
direction()
else
cmp.complete()
end
else
if cmp.visible() then
direction()
else
cmp.complete()
end
end
end
end
Normally, when you type
:e %
and presstab
, the%
will expand to the current buffer's path. However, withcmp-cmdline
, the%
will expand to the path but with a%
prepended to it.Example:
Should expand to
:e myfile
but instead expands to:e %myfile
.