Skip to content

Commit 815f4df

Browse files
committed
feat: support using suffix for fuzzy matching
closes #88
1 parent abcb2a0 commit 815f4df

File tree

5 files changed

+56
-30
lines changed

5 files changed

+56
-30
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ MiniDeps.add({
202202
},
203203

204204
fuzzy = {
205+
-- 'prefix' will fuzzy match on the text before the cursor
206+
-- 'full' will fuzzy match on the text befor *and* after the cursor
207+
-- example: 'foo_|_bar' will match 'foo_' for 'prefix' and 'foo__bar' for 'full'
208+
keyword_range = 'prefix',
205209
-- frencency tracks the most recently/frequently used items and boosts the score of the item
206210
use_frecency = true,
207211
-- proximity bonus boosts the score of items with a value in the buffer

lua/blink/cmp/accept/text-edits.lua

+6-14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local config = require('blink.cmp.config')
12
local text_edits = {}
23

34
function text_edits.get_from_item(item)
@@ -13,7 +14,7 @@ function text_edits.get_from_item(item)
1314
end
1415

1516
-- No text edit so we fallback to our own resolution
16-
return text_edits.guess_text_edit(vim.api.nvim_get_current_buf(), item)
17+
return text_edits.guess_text_edit(item)
1718
end
1819

1920
function text_edits.apply_text_edits(client_id, edits)
@@ -38,26 +39,17 @@ function text_edits.apply_additional_text_edits(item)
3839
end
3940

4041
-- todo: doesnt work when the item contains characters not included in the context regex
41-
function text_edits.guess_text_edit(bufnr, item)
42+
function text_edits.guess_text_edit(item)
4243
local word = item.textEditText or item.insertText or item.label
4344

45+
local range = require('blink.cmp.utils').get_regex_around_cursor('[%w_\\-]', config.fuzzy.keyword_range)
4446
local current_line = vim.api.nvim_win_get_cursor(0)[1]
45-
local current_col = vim.api.nvim_win_get_cursor(0)[2]
46-
local line = vim.api.nvim_buf_get_lines(bufnr, current_line - 1, current_line, false)[1]
47-
48-
-- Search forward/backward for the start/end of the word
49-
local start_col = current_col
50-
while start_col > 0 do
51-
local char = line:sub(start_col, start_col)
52-
if char:match('[%w_\\-]') == nil then break end
53-
start_col = start_col - 1
54-
end
5547

5648
-- convert to 0-index
5749
return {
5850
range = {
59-
start = { line = current_line - 1, character = start_col },
60-
['end'] = { line = current_line - 1, character = current_col },
51+
start = { line = current_line - 1, character = range[1] },
52+
['end'] = { line = current_line - 1, character = range[2] },
6153
},
6254
newText = word,
6355
}

lua/blink/cmp/config.lua

+5
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
--- @field forceVersion? string | nil
6969

7070
--- @class blink.cmp.FuzzyConfig
71+
--- @field keyword_range? 'prefix' | 'full'
7172
--- @field use_frecency? boolean
7273
--- @field use_proximity? boolean
7374
--- @field max_items? number
@@ -207,6 +208,10 @@ local config = {
207208
},
208209

209210
fuzzy = {
211+
-- 'prefix' will fuzzy match on the text before the cursor
212+
-- 'full' will fuzzy match on the text befor *and* after the cursor
213+
-- example: 'foo_|_bar' will match 'foo_' for 'prefix' and 'foo__bar' for 'full'
214+
keyword_range = 'prefix',
210215
-- frencency tracks the most recently/frequently used items and boosts the score of the item
211216
use_frecency = true,
212217
-- proximity bonus boosts the score of items with a value in the buffer

lua/blink/cmp/fuzzy/init.lua

+12-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
local config = require('blink.cmp.config').fuzzy
1+
local config = require('blink.cmp.config')
22

33
local fuzzy = {
44
---@type blink.cmp.Context?
@@ -59,10 +59,10 @@ function fuzzy.filter_items(needle, items)
5959
-- so this should generally be good
6060
-- TODO: make this configurable
6161
min_score = 6 * needle:len(),
62-
max_items = config.max_items,
63-
use_frecency = config.use_frecency,
64-
use_proximity = config.use_proximity,
65-
sorts = config.sorts,
62+
max_items = config.fuzzy.max_items,
63+
use_frecency = config.fuzzy.use_frecency,
64+
use_proximity = config.fuzzy.use_proximity,
65+
sorts = config.fuzzy.sorts,
6666
nearby_words = nearby_words,
6767
})
6868

@@ -88,18 +88,14 @@ function fuzzy.filter_items_with_cache(needle, context, items)
8888
end
8989

9090
--- Gets the text under the cursor to be used for fuzzy matching
91-
--- @param regex string | nil
9291
--- @return string
93-
function fuzzy.get_query(regex)
94-
if regex == nil then regex = '[%w_\\-]+$' end
95-
96-
local bufnr = vim.api.nvim_get_current_buf()
97-
98-
local current_line = vim.api.nvim_win_get_cursor(0)[1] - 1
99-
local current_col = vim.api.nvim_win_get_cursor(0)[2] - 1
100-
local line = vim.api.nvim_buf_get_lines(bufnr, current_line, current_line + 1, false)[1]
101-
102-
return string.sub(line, 1, current_col + 1):match(regex) or ''
92+
function fuzzy.get_query()
93+
local line = vim.api.nvim_get_current_line()
94+
local range = require('blink.cmp.utils').get_regex_around_cursor(
95+
config.trigger.completion.keyword_regex,
96+
config.fuzzy.keyword_range
97+
)
98+
return string.sub(line, range[1] + 1, range[2] + 1)
10399
end
104100

105101
return fuzzy

lua/blink/cmp/utils.lua

+29
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,33 @@ function utils.highlight_with_treesitter(bufnr, root_lang, start_line, end_line)
134134
end)
135135
end
136136

137+
--- Gets characters around the cursor and returns the range, 0-indexed
138+
--- @param regex string
139+
--- @param range 'prefix' | 'full'
140+
--- @return number[]
141+
function utils.get_regex_around_cursor(regex, range)
142+
local current_col = vim.api.nvim_win_get_cursor(0)[2]
143+
local line = vim.api.nvim_get_current_line()
144+
145+
-- Search backward for the start of the word
146+
local start_col = current_col
147+
while start_col > 0 do
148+
local char = line:sub(start_col, start_col)
149+
if char:match(regex) == nil then break end
150+
start_col = start_col - 1
151+
end
152+
153+
if range == 'prefix' then return { start_col, current_col } end
154+
155+
-- Search forward for the end of the word
156+
local end_col = current_col
157+
while end_col < #line do
158+
local char = line:sub(end_col + 1, end_col + 1)
159+
if char:match(regex) == nil then break end
160+
end_col = end_col + 1
161+
end
162+
163+
return { start_col, end_col }
164+
end
165+
137166
return utils

0 commit comments

Comments
 (0)