diff options
Diffstat (limited to 'lua/blink/cmp/completion/trigger/context.lua')
| -rw-r--r-- | lua/blink/cmp/completion/trigger/context.lua | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/lua/blink/cmp/completion/trigger/context.lua b/lua/blink/cmp/completion/trigger/context.lua new file mode 100644 index 0000000..6eb367d --- /dev/null +++ b/lua/blink/cmp/completion/trigger/context.lua @@ -0,0 +1,118 @@ +-- TODO: remove the end_col field from ContextBounds + +--- @class blink.cmp.ContextBounds +--- @field line string +--- @field line_number number +--- @field start_col number +--- @field length number + +--- @class blink.cmp.Context +--- @field mode blink.cmp.Mode +--- @field id number +--- @field bufnr number +--- @field cursor number[] +--- @field line string +--- @field bounds blink.cmp.ContextBounds +--- @field trigger blink.cmp.ContextTrigger +--- @field providers string[] +--- +--- @field new fun(opts: blink.cmp.ContextOpts): blink.cmp.Context +--- @field get_keyword fun(): string +--- @field within_query_bounds fun(self: blink.cmp.Context, cursor: number[]): boolean +--- +--- @field get_mode fun(): blink.cmp.Mode +--- @field get_cursor fun(): number[] +--- @field set_cursor fun(cursor: number[]) +--- @field get_line fun(num?: number): string +--- @field get_bounds fun(range: blink.cmp.CompletionKeywordRange): blink.cmp.ContextBounds + +--- @class blink.cmp.ContextTrigger +--- @field initial_kind blink.cmp.CompletionTriggerKind The trigger kind when the context was first created +--- @field initial_character? string The trigger character when initial_kind == 'trigger_character' +--- @field kind blink.cmp.CompletionTriggerKind The current trigger kind +--- @field character? string The trigger character when kind == 'trigger_character' + +--- @class blink.cmp.ContextOpts +--- @field id number +--- @field providers string[] +--- @field initial_trigger_kind blink.cmp.CompletionTriggerKind +--- @field initial_trigger_character? string +--- @field trigger_kind blink.cmp.CompletionTriggerKind +--- @field trigger_character? string + +--- @type blink.cmp.Context +--- @diagnostic disable-next-line: missing-fields +local context = {} + +function context.new(opts) + local cursor = context.get_cursor() + local line = context.get_line() + + return setmetatable({ + mode = context.get_mode(), + id = opts.id, + bufnr = vim.api.nvim_get_current_buf(), + cursor = cursor, + line = line, + bounds = context.get_bounds('full'), + trigger = { + initial_kind = opts.initial_trigger_kind, + initial_character = opts.initial_trigger_character, + kind = opts.trigger_kind, + character = opts.trigger_character, + }, + providers = opts.providers, + }, { __index = context }) +end + +function context.get_keyword() + local keyword = require('blink.cmp.config').completion.keyword + local range = context.get_bounds(keyword.range) + return string.sub(context.get_line(), range.start_col, range.start_col + range.length - 1) +end + +--- @param cursor number[] +--- @return boolean +function context:within_query_bounds(cursor) + local row, col = cursor[1], cursor[2] + local bounds = self.bounds + return row == bounds.line_number and col >= bounds.start_col and col < (bounds.start_col + bounds.length) +end + +function context.get_mode() return vim.api.nvim_get_mode().mode == 'c' and 'cmdline' or 'default' end + +function context.get_cursor() + return context.get_mode() == 'cmdline' and { 1, vim.fn.getcmdpos() - 1 } or vim.api.nvim_win_get_cursor(0) +end + +function context.set_cursor(cursor) + local mode = context.get_mode() + if mode == 'default' then return vim.api.nvim_win_set_cursor(0, cursor) end + + assert(mode == 'cmdline', 'Unsupported mode for setting cursor: ' .. mode) + assert(cursor[1] == 1, 'Cursor must be on the first line in cmdline mode') + vim.fn.setcmdpos(cursor[2]) +end + +function context.get_line(num) + if context.get_mode() == 'cmdline' then + assert( + num == nil or num == 0, + 'Cannot get line number ' .. tostring(num) .. ' in cmdline mode. Only 0 is supported' + ) + return vim.fn.getcmdline() + end + + if num == nil then num = context.get_cursor()[1] - 1 end + return vim.api.nvim_buf_get_lines(0, num, num + 1, false)[1] +end + +--- Gets characters around the cursor and returns the range, 0-indexed +function context.get_bounds(range) + local line = context.get_line() + local cursor = context.get_cursor() + local start_col, end_col = require('blink.cmp.fuzzy').get_keyword_range(line, cursor[2], range) + return { line_number = cursor[1], start_col = start_col + 1, length = end_col - start_col } +end + +return context |
