1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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
|