diff options
Diffstat (limited to 'lua/blink/cmp/sources/cmdline/init.lua')
| -rw-r--r-- | lua/blink/cmp/sources/cmdline/init.lua | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/lua/blink/cmp/sources/cmdline/init.lua b/lua/blink/cmp/sources/cmdline/init.lua new file mode 100644 index 0000000..5ff5e11 --- /dev/null +++ b/lua/blink/cmp/sources/cmdline/init.lua @@ -0,0 +1,107 @@ +-- Credit goes to @hrsh7th for the code that this was based on +-- https://github.com/hrsh7th/cmp-cmdline +-- License: MIT + +local async = require('blink.cmp.lib.async') +local constants = require('blink.cmp.sources.cmdline.constants') + +--- @class blink.cmp.Source +local cmdline = {} + +function cmdline.new() + local self = setmetatable({}, { __index = cmdline }) + self.before_line = '' + self.offset = -1 + self.ctype = '' + self.items = {} + return self +end + +function cmdline:get_trigger_characters() return { ' ', '.', '#', '-', '=', '/', ':' } end + +function cmdline:get_completions(context, callback) + local arguments = vim.split(context.line, ' ', { plain = true }) + local arg_number = #vim.split(context.line:sub(1, context.cursor[2] + 1), ' ', { plain = true }) + local text_before_argument = table.concat(require('blink.cmp.lib.utils').slice(arguments, 1, arg_number - 1), ' ') + .. (arg_number > 1 and ' ' or '') + + local current_arg = arguments[arg_number] + local keyword_config = require('blink.cmp.config').completion.keyword + local keyword = context.get_bounds(keyword_config.range) + local current_arg_prefix = current_arg:sub(1, keyword.start_col - #text_before_argument - 1) + + local task = async.task + .empty() + :map(function() + -- Special case for help where we read all the tags ourselves + if vim.tbl_contains(constants.help_commands, arguments[1] or '') then + return require('blink.cmp.sources.cmdline.help').get_completions(current_arg_prefix) + end + + local completions = {} + local completion_type = vim.fn.getcmdcompltype() + -- Handle custom completions explicitly, since otherwise they won't work in input() mode (getcmdtype() == '@') + if vim.startswith(completion_type, 'custom,') or vim.startswith(completion_type, 'customlist,') then + local fun = completion_type:gsub('custom,', ''):gsub('customlist,', '') + completions = vim.fn.call(fun, { current_arg_prefix, vim.fn.getcmdline(), vim.fn.getcmdpos() }) + -- `custom,` type returns a string, delimited by newlines + if type(completions) == 'string' then completions = vim.split(completions, '\n') end + else + local query = (text_before_argument .. current_arg_prefix):gsub([[\\]], [[\\\\]]) + completions = vim.fn.getcompletion(query, 'cmdline') + end + + -- Special case for files, escape special characters + if vim.tbl_contains(constants.file_commands, arguments[1] or '') then + completions = vim.tbl_map(function(completion) return vim.fn.fnameescape(completion) end, completions) + end + + return completions + end) + :map(function(completions) + local items = {} + for _, completion in ipairs(completions) do + local has_prefix = string.find(completion, current_arg_prefix, 1, true) == 1 + + -- remove prefix from the filter text + local filter_text = completion + if has_prefix then filter_text = completion:sub(#current_arg_prefix + 1) end + + -- for lua, use the filter text as the label since it doesn't include the prefix + local label = arguments[1] == 'lua' and filter_text or completion + + -- add prefix to the newText + local new_text = completion + if not has_prefix then new_text = current_arg_prefix .. completion end + + table.insert(items, { + label = label, + filterText = filter_text, + -- move items starting with special characters to the end of the list + sortText = label:lower():gsub('^([!-@\\[-`])', '~%1'), + textEdit = { + newText = new_text, + range = { + start = { line = 0, character = #text_before_argument }, + ['end'] = { line = 0, character = #text_before_argument + #current_arg }, + }, + }, + kind = require('blink.cmp.types').CompletionItemKind.Property, + }) + end + + callback({ + is_incomplete_backward = true, + is_incomplete_forward = false, + items = items, + }) + end) + :catch(function(err) + vim.notify('Error while fetching completions: ' .. err, vim.log.levels.ERROR, { title = 'blink.cmp' }) + callback({ is_incomplete_backward = false, is_incomplete_forward = false, items = {} }) + end) + + return function() task:cancel() end +end + +return cmdline |
