Skip to content

Commit 51d5f59

Browse files
committed
feat: support non-latin characters for keyword and buffer source
Closes #130 Closes #388
1 parent d0b0e16 commit 51d5f59

File tree

5 files changed

+38
-29
lines changed

5 files changed

+38
-29
lines changed

lua/blink/cmp/completion/trigger.lua

+8-7
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
local keyword_config = require('blink.cmp.config').completion.keyword
3737
local config = require('blink.cmp.config').completion.trigger
3838

39+
local keyword_regex = vim.regex(keyword_config.regex)
40+
3941
--- @type blink.cmp.CompletionTrigger
4042
--- @diagnostic disable-next-line: missing-fields
4143
local trigger = {
@@ -62,7 +64,7 @@ function trigger.activate()
6264
trigger.show({ trigger_character = char })
6365

6466
-- character is part of a keyword
65-
elseif char:match(keyword_config.regex) ~= nil and (config.show_on_keyword or trigger.context ~= nil) then
67+
elseif keyword_regex:match_str(char) ~= nil and (config.show_on_keyword or trigger.context ~= nil) then
6668
trigger.show()
6769

6870
-- nothing matches so hide
@@ -82,7 +84,7 @@ function trigger.activate()
8284
local char_under_cursor = vim.api.nvim_get_current_line():sub(cursor_col, cursor_col)
8385
local is_on_trigger_for_show = trigger.is_trigger_character(char_under_cursor)
8486
local is_on_trigger_for_show_on_insert = trigger.is_trigger_character(char_under_cursor, true)
85-
local is_on_keyword_char = char_under_cursor:match(keyword_config.regex) ~= nil
87+
local is_on_keyword_char = keyword_regex:match_str(char_under_cursor) ~= nil
8688

8789
local insert_enter_on_trigger_character = config.show_on_trigger_character
8890
and config.show_on_insert_on_trigger_character
@@ -197,17 +199,16 @@ function trigger.within_query_bounds(cursor)
197199
end
198200

199201
--- Moves forward and backwards around the cursor looking for word boundaries
200-
--- @param regex string
201202
--- @return blink.cmp.ContextBounds
202-
function trigger.get_context_bounds(regex)
203+
function trigger.get_context_bounds()
203204
local cursor_line = vim.api.nvim_win_get_cursor(0)[1]
204205
local cursor_col = vim.api.nvim_win_get_cursor(0)[2]
205206

206207
local line = vim.api.nvim_buf_get_lines(0, cursor_line - 1, cursor_line, false)[1]
207208
local start_col = cursor_col
208209
while start_col >= 1 do
209210
local char = line:sub(start_col, start_col)
210-
if char:match(regex) == nil then
211+
if keyword_regex:match_str(char) == nil then
211212
start_col = start_col + 1
212213
break
213214
end
@@ -218,7 +219,7 @@ function trigger.get_context_bounds(regex)
218219
local end_col = cursor_col
219220
while end_col < #line do
220221
local char = line:sub(end_col + 1, end_col + 1)
221-
if char:match(regex) == nil then break end
222+
if keyword_regex:match_str(char) == nil then break end
222223
end_col = end_col + 1
223224
end
224225

@@ -228,7 +229,7 @@ function trigger.get_context_bounds(regex)
228229
local length = end_col - start_col + 1
229230
-- Since sub(1, 1) returns a single char string, we need to check if that single char matches
230231
-- and otherwise mark the length as 0
231-
if start_col == end_col and line:sub(start_col, end_col):match(regex) == nil then length = 0 end
232+
if start_col == end_col and keyword_regex:match_str(line:sub(start_col, end_col)) == nil then length = 0 end
232233

233234
return { line_number = cursor_line, start_col = start_col, end_col = end_col, length = length }
234235
end

lua/blink/cmp/config/completion/keyword.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ local keyword = {
1515
--- @type blink.cmp.CompletionKeywordConfig
1616
default = {
1717
range = 'prefix',
18-
regex = '[%w_\\-]',
19-
exclude_from_prefix_regex = '[\\-]',
18+
regex = '[-_]\\|\\k',
19+
exclude_from_prefix_regex = '-',
2020
},
2121
}
2222

lua/blink/cmp/fuzzy/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod fuzzy;
1212
mod lsp_item;
1313

1414
lazy_static! {
15-
static ref REGEX: Regex = Regex::new(r"\w[\w0-9_\\-]{2,32}").unwrap();
15+
static ref REGEX: Regex = Regex::new(r"\p{L}[\p{L}0-9_\\-]{2,32}").unwrap();
1616
static ref FRECENCY: RwLock<Option<FrecencyTracker>> = RwLock::new(None);
1717
}
1818

lua/blink/cmp/lib/text_edits.lua

+7-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,13 @@ function text_edits.get_from_item(item)
9797
if text_edit == nil then return text_edits.guess(item) end
9898

9999
-- FIXME: temporarily convert insertReplaceEdit to regular textEdit
100-
text_edit.range = text_edit.range or text_edit.insert or text_edit.replace
100+
if text_edit.range == nil then
101+
if config.completion.keyword.range == 'full' and text_edit.replace ~= nil then
102+
text_edit.range = text_edit.replace
103+
else
104+
text_edit.range = text_edit.insert or text_edit.replace
105+
end
106+
end
101107
text_edit.insert = nil
102108
text_edit.replace = nil
103109
--- @cast text_edit lsp.TextEdit

lua/blink/cmp/lib/utils.lua

+20-18
Original file line numberDiff line numberDiff line change
@@ -54,39 +54,41 @@ end
5454

5555
--- Gets characters around the cursor and returns the range, 0-indexed
5656
--- @param range 'prefix' | 'full'
57-
--- @param regex string
58-
--- @param exclude_from_prefix_regex string
57+
--- @param regex_str string
58+
--- @param exclude_from_prefix_regex_str string
5959
--- @return { start_col: number, length: number }
6060
--- TODO: switch to return start_col, length to simplify downstream logic
61-
function utils.get_regex_around_cursor(range, regex, exclude_from_prefix_regex)
61+
function utils.get_regex_around_cursor(range, regex_str, exclude_from_prefix_regex_str)
62+
local backward_regex = vim.regex('\\(' .. regex_str .. '\\)\\+$')
63+
local forward_regex = vim.regex('^\\(' .. regex_str .. '\\)\\+')
64+
6265
local current_col = vim.api.nvim_win_get_cursor(0)[2] + 1
6366
local line = vim.api.nvim_get_current_line()
6467

65-
-- Search backward for the start of the word
66-
local start_col = current_col
6768
local length = 0
68-
while start_col > 0 do
69-
local char = line:sub(start_col - 1, start_col - 1)
70-
if char:match(regex) == nil then break end
71-
start_col = start_col - 1
72-
length = length + 1
69+
local start_col = current_col
70+
71+
-- Search backward for the start of the word
72+
local line_before = line:sub(1, current_col - 1)
73+
local before_match_start, _ = backward_regex:match_str(line_before)
74+
if before_match_start ~= nil then
75+
start_col = before_match_start + 1
76+
length = current_col - start_col
7377
end
7478

7579
-- Search forward for the end of the word if configured
7680
if range == 'full' then
77-
while start_col + length <= #line do
78-
local col = start_col + length
79-
local char = line:sub(col, col)
80-
if char:match(regex) == nil then break end
81-
length = length + 1
82-
end
81+
local line_after = line:sub(current_col)
82+
local _, after_match_end = forward_regex:match_str(line_after)
83+
if after_match_end ~= nil then length = length + after_match_end end
8384
end
8485

8586
-- exclude characters matching exclude_prefix_regex from the beginning of the bounds
86-
if exclude_from_prefix_regex ~= nil then
87+
if exclude_from_prefix_regex_str ~= nil then
88+
local exclude_from_prefix_regex = vim.regex(exclude_from_prefix_regex_str)
8789
while length > 0 do
8890
local char = line:sub(start_col, start_col)
89-
if char:match(exclude_from_prefix_regex) == nil then break end
91+
if exclude_from_prefix_regex:match_str(char) == nil then break end
9092
start_col = start_col + 1
9193
length = length - 1
9294
end

0 commit comments

Comments
 (0)