diff --git a/lua/dressing/input.lua b/lua/dressing/input.lua index 810d82a..086a73c 100644 --- a/lua/dressing/input.lua +++ b/lua/dressing/input.lua @@ -47,6 +47,55 @@ M.highlight = function() end end +local function split(string, pattern) + local ret = {} + for token in string.gmatch(string, "[^" .. pattern .. "]+") do + table.insert(ret, token) + end + return ret +end + +M.completefunc = function(findstart, base) + if not context.opts or not context.opts.completion then + return findstart == 1 and 0 or {} + end + if findstart == 1 then + return vim.api.nvim_strwidth(context.opts.prompt) + else + local completion = context.opts.completion + local pieces = split(completion, ",") + if pieces[1] == "custom" or pieces[1] == "customlist" then + local vimfunc = pieces[2] + local ret = vim.fn[vimfunc](base, base, vim.fn.strlen(base)) + print(vim.inspect(ret)) + if pieces[1] == "custom" then + ret = split(ret, "\n") + end + return ret + else + local ok, result = pcall(vim.fn.getcompletion, base, context.opts.completion) + if ok then + return result + else + vim.api.nvim_err_writeln( + string.format("dressing.nvim: unsupported completion method '%s'", completion) + ) + return {} + end + end + end +end + +_G.dressing_input_complete = M.completefunc + +M.trigger_completion = function() + if vim.fn.pumvisible() == 1 then + return vim.api.nvim_replace_termcodes("", true, false, true) + else + return vim.api.nvim_replace_termcodes("", true, false, true) + end +end + setmetatable(M, { __call = function(_, opts, on_confirm) vim.validate({ @@ -69,7 +118,6 @@ setmetatable(M, { border = config.border, width = width, height = 1, - zindex = 150, style = "minimal", } local winnr @@ -94,7 +142,7 @@ setmetatable(M, { bufnr, "i", "", - "lua require('dressing.input').confirm()", + ":lua require('dressing.input').confirm()", keyopts ) vim.fn.prompt_setprompt(bufnr, prompt) @@ -105,7 +153,18 @@ setmetatable(M, { vim.cmd([[ autocmd TextChanged lua require('dressing.input').highlight() autocmd TextChangedI lua require('dressing.input').highlight() - ]]) + ]]) + end + if opts.completion then + vim.api.nvim_buf_set_option(bufnr, "completefunc", "v:lua.dressing_input_complete") + vim.api.nvim_buf_set_option(bufnr, "omnifunc", "") + vim.api.nvim_buf_set_keymap( + bufnr, + "i", + "", + [[luaeval("require('dressing.input').trigger_completion()")]], + { expr = true } + ) end vim.cmd([[ autocmd BufLeave ++nested ++once lua require('dressing.input').confirm() @@ -114,6 +173,13 @@ setmetatable(M, { if opts.default then vim.api.nvim_feedkeys(opts.default, "n", false) end + + -- Close the completion menu if visible + if vim.fn.pumvisible() == 1 then + local escape_key = vim.api.nvim_replace_termcodes("", true, false, true) + vim.api.nvim_feedkeys(escape_key, "n", true) + end + M.highlight() end, }) diff --git a/tests/manual/completion.lua b/tests/manual/completion.lua new file mode 100644 index 0000000..305921f --- /dev/null +++ b/tests/manual/completion.lua @@ -0,0 +1,41 @@ +-- Run this test with :source % + +local idx = 1 +local cases = { + { + prompt = "Complete file: ", + completion = "file", + }, + { + prompt = "Complete cmd: ", + completion = "command", + }, + { + prompt = "Complete custom: ", + completion = "custom,CustomComplete", + }, + { + prompt = "Complete customlist: ", + completion = "customlist,CustomCompleteList", + }, +} + +vim.cmd([[ +function! CustomComplete(arglead, cmdline, cursorpos) + return "first\nsecond\nthird" +endfunction + +function! CustomCompleteList(arglead, cmdline, cursorpos) + return ['first', 'second', 'third'] +endfunction +]]) + +local function next() + local opts = cases[idx] + if opts then + idx = idx + 1 + vim.ui.input(opts, next) + end +end + +next() diff --git a/test/manual/highlight.lua b/tests/manual/highlight.lua similarity index 100% rename from test/manual/highlight.lua rename to tests/manual/highlight.lua