summaryrefslogtreecommitdiff
path: root/lua/blink/cmp/completion/trigger/context.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/blink/cmp/completion/trigger/context.lua')
-rw-r--r--lua/blink/cmp/completion/trigger/context.lua118
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