Skip to content

Commit 1187172

Browse files
authored
feat: nuke the debt (#389)
Sweeping refactor of the codebase touching just about everything: reworked config with validation, trigger, new list component for managing state, stateless windows, etc. This will set us up for cmdline completions (#323), sources v3 (keywords, async, fallback tree, ...), and documentation. After which, we can hopefully release v1
1 parent 12d9ecd commit 1187172

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+2900
-2294
lines changed

README.md

+295-254
Large diffs are not rendered by default.

lua/blink/cmp/accept/brackets/init.lua

-6
This file was deleted.

lua/blink/cmp/accept/init.lua renamed to lua/blink/cmp/completion/accept/init.lua

+13-9
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
local text_edits_lib = require('blink.cmp.accept.text-edits')
2-
local brackets_lib = require('blink.cmp.accept.brackets')
1+
local text_edits_lib = require('blink.cmp.lib.text_edits')
2+
local brackets_lib = require('blink.cmp.completion.brackets')
33

44
--- Applies a completion item to the current buffer
55
--- @param ctx blink.cmp.Context
66
--- @param item blink.cmp.CompletionItem
7-
local function accept(ctx, item)
7+
--- @param callback fun()
8+
local function accept(ctx, item, callback)
89
local sources = require('blink.cmp.sources.lib')
9-
require('blink.cmp.trigger.completion').hide()
10+
require('blink.cmp.completion.trigger').hide()
1011

1112
-- let the source execute the item itself if it indicates it can
1213
if sources.should_execute(item) then
1314
sources.execute(ctx, item)
15+
callback()
1416
return
1517
end
1618

@@ -48,7 +50,7 @@ local function accept(ctx, item)
4850
text_edits_lib.apply(all_text_edits)
4951

5052
-- Expand the snippet
51-
require('blink.cmp.config').accept.expand_snippet(item.textEdit.newText)
53+
require('blink.cmp.config').snippets.expand(item.textEdit.newText)
5254

5355
-- OR Normal: Apply the text edit and move the cursor
5456
else
@@ -66,12 +68,14 @@ local function accept(ctx, item)
6668
-- TODO: since we apply the additional text edits after, auto imported functions will not
6769
-- get auto brackets. If we apply them before, we have to modify the textEdit to compensate
6870
brackets_lib.add_brackets_via_semantic_token(vim.bo.filetype, item, function()
69-
require('blink.cmp.trigger.completion').show_if_on_trigger_character({ is_accept = true })
70-
require('blink.cmp.trigger.signature').show_if_on_trigger_character()
71+
require('blink.cmp.completion.trigger').show_if_on_trigger_character({ is_accept = true })
72+
require('blink.cmp.signature.trigger').show_if_on_trigger_character()
73+
callback()
7174
end)
7275
else
73-
require('blink.cmp.trigger.completion').show_if_on_trigger_character({ is_accept = true })
74-
require('blink.cmp.trigger.signature').show_if_on_trigger_character()
76+
require('blink.cmp.completion.trigger').show_if_on_trigger_character({ is_accept = true })
77+
require('blink.cmp.signature.trigger').show_if_on_trigger_character()
78+
callback()
7579
end
7680

7781
-- Notify the rust module that the item was accessed
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
local PAIRS_AND_INVALID_CHARS = {}
2+
string.gsub('\'"=$()[]<>{} \t\n\r', '.', function(char) PAIRS_AND_INVALID_CHARS[string.byte(char)] = true end)
3+
4+
local CLOSING_PAIR = {
5+
[string.byte('<')] = string.byte('>'),
6+
[string.byte('[')] = string.byte(']'),
7+
[string.byte('(')] = string.byte(')'),
8+
[string.byte('{')] = string.byte('}'),
9+
[string.byte('"')] = string.byte('"'),
10+
[string.byte("'")] = string.byte("'"),
11+
}
12+
13+
local ALPHANUMERIC = {}
14+
string.gsub(
15+
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
16+
'.',
17+
function(char) ALPHANUMERIC[string.byte(char)] = true end
18+
)
19+
20+
--- Gets the prefix of the given text, stopping at brackets and quotes
21+
--- @param text string
22+
--- @return string
23+
local function get_prefix_before_brackets_and_quotes(text)
24+
local closing_pairs_stack = {}
25+
local word = ''
26+
27+
local add = function(char)
28+
word = word .. string.char(char)
29+
30+
-- if we've seen the opening pair, and we've just received the closing pair,
31+
-- remove it from the closing pairs stack
32+
if closing_pairs_stack[#closing_pairs_stack] == char then
33+
table.remove(closing_pairs_stack, #closing_pairs_stack)
34+
-- if the character is an opening pair, add it to the closing pairs stack
35+
elseif CLOSING_PAIR[char] ~= nil then
36+
table.insert(closing_pairs_stack, CLOSING_PAIR[char])
37+
end
38+
end
39+
40+
local has_alphanumeric = false
41+
for i = 1, #text do
42+
local char = string.byte(text, i)
43+
if PAIRS_AND_INVALID_CHARS[char] == nil then
44+
add(char)
45+
has_alphanumeric = has_alphanumeric or ALPHANUMERIC[char]
46+
elseif not has_alphanumeric or #closing_pairs_stack ~= 0 then
47+
add(char)
48+
-- if we had an alphanumeric, and the closing pairs stack *just* emptied,
49+
-- because the current character is a closing pair, we exit
50+
if has_alphanumeric and #closing_pairs_stack == 0 then break end
51+
else
52+
break
53+
end
54+
end
55+
return word
56+
end
57+
58+
return get_prefix_before_brackets_and_quotes

lua/blink/cmp/accept/preview.lua renamed to lua/blink/cmp/completion/accept/preview.lua

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
--- @param item blink.cmp.CompletionItem
22
local function preview(item)
3-
local text_edits_lib = require('blink.cmp.accept.text-edits')
3+
local text_edits_lib = require('blink.cmp.lib.text_edits')
44
local text_edit = text_edits_lib.get_from_item(item)
55

66
if item.insertTextFormat == vim.lsp.protocol.InsertTextFormat.Snippet then
77
local expanded_snippet = require('blink.cmp.sources.snippets.utils').safe_parse(text_edit.newText)
8-
text_edit.newText = require('blink.cmp.utils').get_prefix_before_brackets_and_quotes(
9-
expanded_snippet and tostring(expanded_snippet) or text_edit.newText
10-
)
8+
local snippet = expanded_snippet and tostring(expanded_snippet) or text_edit.newText
9+
local get_prefix_before_brackets_and_quotes = require('blink.cmp.completion.accept.prefix')
10+
text_edit.newText = get_prefix_before_brackets_and_quotes(snippet)
1111
end
1212

1313
local undo_text_edit = text_edits_lib.get_undo_text_edit(text_edit)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
local brackets = {}
2+
3+
brackets.add_brackets = require('blink.cmp.completion.brackets.kind')
4+
brackets.add_brackets_via_semantic_token = require('blink.cmp.completion.brackets.semantic')
5+
6+
return brackets

lua/blink/cmp/accept/brackets/kind.lua renamed to lua/blink/cmp/completion/brackets/kind.lua

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
local config = require('blink.cmp.config').accept.auto_brackets
2-
local utils = require('blink.cmp.accept.brackets.utils')
1+
local utils = require('blink.cmp.completion.brackets.utils')
32

43
--- @param filetype string
54
--- @param item blink.cmp.CompletionItem

lua/blink/cmp/accept/brackets/semantic.lua renamed to lua/blink/cmp/completion/brackets/semantic.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
local config = require('blink.cmp.config').accept.auto_brackets
2-
local utils = require('blink.cmp.accept.brackets.utils')
1+
local config = require('blink.cmp.config').completion.accept.auto_brackets
2+
local utils = require('blink.cmp.completion.brackets.utils')
33

44
local semantic = {}
55

lua/blink/cmp/accept/brackets/utils.lua renamed to lua/blink/cmp/completion/brackets/utils.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
local config = require('blink.cmp.config').accept.auto_brackets
2-
local brackets = require('blink.cmp.accept.brackets.config')
1+
local config = require('blink.cmp.config').completion.accept.auto_brackets
2+
local brackets = require('blink.cmp.completion.brackets.config')
33
local utils = {}
44

55
--- @param snippet string

lua/blink/cmp/completion/init.lua

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
local config = require('blink.cmp.config')
2+
local completion = {}
3+
4+
function completion.setup()
5+
-- trigger controls when to show the window and the current context for caching
6+
local trigger = require('blink.cmp.completion.trigger')
7+
trigger.activate()
8+
9+
-- sources fetch completion items and documentation
10+
local sources = require('blink.cmp.sources.lib')
11+
12+
-- manages the completion list state:
13+
-- fuzzy matching items
14+
-- when to show/hide the windows
15+
-- selection
16+
-- accepting and previewing items
17+
local list = require('blink.cmp.completion.list')
18+
19+
-- trigger -> sources: request completion items from the sources on show
20+
trigger.show_emitter:on(function(event) sources.request_completions(event.context) end)
21+
trigger.hide_emitter:on(function()
22+
sources.cancel_completions()
23+
list.hide()
24+
end)
25+
26+
-- sources -> list
27+
sources.completions_emitter:on(function(event)
28+
-- schedule for later to avoid adding 0.5-4ms to insertion latency
29+
vim.schedule(function()
30+
-- since this was performed asynchronously, we check if the context has changed
31+
if trigger.context == nil or event.context.id ~= trigger.context.id then return end
32+
list.show(event.context, event.items)
33+
end)
34+
end)
35+
36+
--- list -> windows: ghost text and completion menu
37+
-- setup completion menu
38+
if config.completion.menu.enabled then
39+
list.show_emitter:on(
40+
function(event) require('blink.cmp.completion.windows.menu').open_with_items(event.context, event.items) end
41+
)
42+
list.hide_emitter:on(function() require('blink.cmp.completion.windows.menu').close() end)
43+
list.select_emitter:on(function(event)
44+
require('blink.cmp.completion.windows.menu').set_selected_item_idx(event.idx)
45+
if config.completion.documentation.auto_show then
46+
require('blink.cmp.completion.windows.documentation').auto_show_item(event.context, event.item)
47+
end
48+
end)
49+
end
50+
51+
-- setup ghost text
52+
if config.completion.ghost_text.enabled then
53+
list.select_emitter:on(
54+
function(event) require('blink.cmp.completion.windows.ghost_text').show_preview(event.item) end
55+
)
56+
list.hide_emitter:on(function() require('blink.cmp.completion.windows.ghost_text').clear_preview() end)
57+
end
58+
59+
-- run 'resolve' on the item ahead of time to avoid delays
60+
-- when accepting the item or showing documentation
61+
list.select_emitter:on(function(event)
62+
if event.item == nil then return end
63+
require('blink.cmp.completion.prefetch')(event.context, event.item)
64+
end)
65+
end
66+
67+
return completion

0 commit comments

Comments
 (0)