Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
scottmckendry authored Oct 9, 2024
2 parents 94a38ff + 6a21d7c commit 74f1b93
Show file tree
Hide file tree
Showing 18 changed files with 257 additions and 88 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Liam Dyer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ For LazyVim/distro users, you can disable nvim-cmp via:
show = '<C-space>',
hide = '<C-e>',
accept = '<Tab>',
select_prev = { '<Up>', '<C-j>' },
select_next = { '<Down>', '<C-k>' },
select_prev = { '<Up>', '<C-k>' },
select_next = { '<Down>', '<C-j>' },

show_documentation = {},
hide_documentation = {},
Expand Down Expand Up @@ -164,6 +164,17 @@ For LazyVim/distro users, you can disable nvim-cmp via:
max_items = 200,
-- controls which sorts to use and in which order, these three are currently the only allowed options
sorts = { 'label', 'kind', 'score' },

prebuiltBinaries = {
-- Whether or not to automatically download a prebuilt binary from github. If this is set to `false`
-- you will need to manually build the fuzzy binary dependencies by running `cargo build --release`
download = true,
-- When downloading a prebuilt binary force the downloader to resolve this version. If this is uset
-- then the downloader will attempt to infer the version from the checked out git tag (if any).
--
-- Beware that if the FFI ABI changes while tracking main then this may result in blink breaking.
forceVersion = nil,
},
},

sources = {
Expand Down Expand Up @@ -234,6 +245,13 @@ For LazyVim/distro users, you can disable nvim-cmp via:
-- 'reversed' will render the label on the left and the kind icon + name on the right
-- 'function(blink.cmp.CompletionRenderContext): blink.cmp.Component[]' for custom rendering
draw = 'simple',
-- Controls the cycling behavior when reaching the beginning or end of the completion list.
cycle = {
-- When `true`, calling `select_next` at the *bottom* of the completion list will select the *first* completion item.
from_bottom = true,
-- When `true`, calling `select_prev` at the *top* of the completion list will select the *last* completion item.
from_top = true
},
},
documentation = {
min_width = 10,
Expand Down
3 changes: 3 additions & 0 deletions lua/blink/cmp/accept/brackets.lua
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ function brackets.add_brackets_via_semantic_token(filetype, item, callback)
if client == nil then return callback() end

local start_time = vim.uv.hrtime()
if not (client.server_capabilities.semanticTokensProvider and client.server_capabilities.semanticTokensProvider.legend) then
return callback()
end
local numToTokenType = client.server_capabilities.semanticTokensProvider.legend.tokenTypes
local params = {
textDocument = vim.lsp.util.make_text_document_params(),
Expand Down
11 changes: 5 additions & 6 deletions lua/blink/cmp/accept/text-edits.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ function text_edits.guess_text_edit(bufnr, item)
-- Search forward/backward for the start/end of the word
local start_col = current_col
while start_col > 1 do
local char = line:sub(start_col, start_col)
if char:match('[%w_\\-]') == nil then
start_col = start_col + 1
break
end
local char = line:sub(start_col - 1, start_col - 1)
if char:match('[%w_\\-]') == nil then break end
start_col = start_col - 1
end

-- todo: dont search forward since LSPs dont typically do this so it will be inconsistent
-- todo: optionally dont search forward since LSPs dont typically do this with textEdits
-- so this will lead to inconsistent behavior
-- OR add support on textEdits
local end_col = current_col
while end_col < #line do
local char = line:sub(end_col + 1, end_col + 1)
Expand Down
29 changes: 27 additions & 2 deletions lua/blink/cmp/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,17 @@
--- @field enabled? boolean
--- @field priority? number

--- @class blink.cmp.PrebuiltBinariesConfig
--- @field download boolean
--- @field forceVersion string | nil

--- @class blink.cmp.FuzzyConfig

--- @field use_frecency? boolean
--- @field use_proximity? boolean
--- @field max_items? number
--- @field sorts? ("label" | "kind" | "score")[]
--- @field prebuiltBinaries? blink.cmp.PrebuiltBinariesConfig

--- @class blink.cmp.WindowConfig
--- @field autocomplete? blink.cmp.AutocompleteConfig
Expand All @@ -87,6 +93,11 @@
--- @field winhighlight? string
--- @field scrolloff? number
--- @field draw? 'simple' | 'reversed' | function(blink.cmp.CompletionRenderContext): blink.cmp.Component[]
--- @field cycle? blink.cmp.AutocompleteConfig.CycleConfig

--- @class blink.cmp.AutocompleteConfig.CycleConfig
--- @field from_bottom? boolean When `true`, calling `select_next` at the *bottom* of the completion list will select the *first* completion item.
--- @field from_top? boolean When `true`, calling `select_prev` at the *top* of the completion list will select the *last* completion item.

--- @class blink.cmp.DocumentationDirectionPriorityConfig
--- @field autocomplete_north? ("n" | "s" | "e" | "w")[]
Expand Down Expand Up @@ -131,8 +142,8 @@ local config = {
show = '<C-space>',
hide = '<C-e>',
accept = '<Tab>',
select_prev = { '<Up>', '<C-j>' },
select_next = { '<Down>', '<C-k>' },
select_prev = { '<Up>', '<C-k>' },
select_next = { '<Down>', '<C-j>' },

show_documentation = {},
hide_documentation = {},
Expand Down Expand Up @@ -196,6 +207,16 @@ local config = {
max_items = 200,
-- controls which sorts to use and in which order, these three are currently the only allowed options
sorts = { 'label', 'kind', 'score' },
prebuiltBinaries = {
-- Whether or not to automatically download a prebuilt binary from github. If this is set to `false`
-- you will need to manually build the fuzzy binary dependencies by running `cargo build --release`
download = true,
-- When downloading a prebuilt binary force the downloader to resolve this version. If this is uset
-- then the downloader will attempt to infer the version from the checked out git tag (if any).
--
-- Beware that if the FFI ABI changes while tracking main then this may result in blink breaking.
forceVersion = nil,
},
},

sources = {
Expand Down Expand Up @@ -233,6 +254,10 @@ local config = {
-- 'reversed' will render the label on the left and the kind icon + name on the right
-- 'function(blink.cmp.CompletionRenderContext): blink.cmp.Component[]' for custom rendering
draw = 'simple',
cycle = {
from_bottom = true,
from_top = true,
},
},
documentation = {
min_width = 10,
Expand Down
20 changes: 14 additions & 6 deletions lua/blink/cmp/fuzzy/download.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
local download_config = require('blink.cmp.config').fuzzy.prebuiltBinaries

local download = {}

--- @return string
Expand All @@ -17,28 +19,34 @@ function download.ensure_downloaded(callback)
vim.schedule(function() callback(err) end)
end

if not download_config.download then return cb() end

download.get_git_tag(function(git_version_err, git_version)
if git_version_err then return cb(git_version_err) end

download.get_downloaded_version(function(version_err, version)
download.is_downloaded(function(downloaded)
local target_version = download_config.forceVersion or git_version

-- not built locally, not a git tag, error
if not downloaded and not git_version then
if not downloaded and not target_version then
return cb(
"Can't download from github due to not being on a git tag but found no built version of the library. Either run cargo build --release via your package manager or switch to a git tag. See the README for more info."
"Can't download from github due to not being on a git tag and no native_download.version set, but found no built version of the library. "
.. 'Either run `cargo build --release` via your package manager, switch to a git tag, or set `native_download.version` in config. '
.. 'See the README for more info.'
)
end
-- built locally, ignore
if downloaded and (version_err or version == nil) then return cb() end
-- already downloaded and the correct version
if version == git_version and downloaded then return cb() end
if version == target_version and downloaded then return cb() end
-- unknown state
if not git_version then return cb('Unknown error while getting pre-built binary. Consider re-installing') end
if not target_version then return cb('Unknown error while getting pre-built binary. Consider re-installing') end

-- download from github and set version
download.from_github(git_version, function(download_err)
download.from_github(target_version, function(download_err)
if download_err then return cb(download_err) end
download.set_downloaded_version(git_version, function(set_err)
download.set_downloaded_version(target_version, function(set_err)
if set_err then return cb(set_err) end
cb()
end)
Expand Down
2 changes: 1 addition & 1 deletion lua/blink/cmp/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ cmp.setup_signature_help = function()
signature_trigger.listen_on_show(function(context)
cmp.sources.cancel_signature_help()
cmp.sources.get_signature_help(context, function(signature_help)
if signature_help ~= nil and signature_trigger.context.id == context.id then
if signature_help ~= nil and signature_trigger.context ~= nil and signature_trigger.context.id == context.id then
signature_trigger.set_active_signature_help(signature_help)
signature_window.open_with_signature_help(context, signature_help)
else
Expand Down
97 changes: 76 additions & 21 deletions lua/blink/cmp/keymap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function keymap.setup(opts)
-- convert string to string[] for consistency
if type(keys) == 'string' then keys = { keys } end

-- add keymaps
-- reverse the command -> key[] mapping into key -> command[]
for _, key in ipairs(keys) do
if is_insert_command then
if insert_keys_to_commands[key] == nil then insert_keys_to_commands[key] = {} end
Expand All @@ -38,28 +38,83 @@ function keymap.setup(opts)
end
end

for key, _ in pairs(insert_keys_to_commands) do
vim.keymap.set('i', key, function()
for _, command in ipairs(insert_keys_to_commands[key] or {}) do
local did_run = require('blink.cmp')[command]()
if did_run then return end
end
for _, command in ipairs(snippet_keys_to_commands[key] or {}) do
local did_run = require('blink.cmp')[command]()
if did_run then return end
end
return key
end, { expr = true, silent = true })
-- apply keymaps
-- we set on the buffer directly to avoid buffer-local keymaps (such as from autopairs)
-- from overriding our mappings
local set_buffer_keymap = function()
-- insert mode
for key, _ in pairs(insert_keys_to_commands) do
keymap.set('i', key, function()
for _, command in ipairs(insert_keys_to_commands[key] or {}) do
local did_run = require('blink.cmp')[command]()
if did_run then return end
end
for _, command in ipairs(snippet_keys_to_commands[key] or {}) do
local did_run = require('blink.cmp')[command]()
if did_run then return end
end

return keymap.run_non_blink_keymap('i', key)
end)
end

-- snippet mode
for key, _ in pairs(snippet_keys_to_commands) do
keymap.set('s', key, function()
for _, command in ipairs(snippet_keys_to_commands[key] or {}) do
local did_run = require('blink.cmp')[command]()
if did_run then return end
end

return keymap.run_non_blink_keymap('s', key)
end)
end
end
for key, _ in pairs(snippet_keys_to_commands) do
vim.keymap.set('s', key, function()
for _, command in ipairs(snippet_keys_to_commands[key] or {}) do
local did_run = require('blink.cmp')[command]()
if did_run then return end
end
return key
end, { expr = true, silent = true })

set_buffer_keymap() -- apply immediately since the plugin starts asynchronously
vim.api.nvim_create_autocmd('BufEnter', { callback = set_buffer_keymap })
end

--- Gets the first non blink.cmp keymap for the given mode and key
function keymap.get_non_blink_mapping_for_key(mode, key)
local normalized_key = vim.api.nvim_replace_termcodes(key, true, true, true)

-- get buffer local and global mappings
local mappings = vim.api.nvim_buf_get_keymap(0, mode)
vim.list_extend(mappings, vim.api.nvim_get_keymap(mode))

for _, mapping in ipairs(mappings) do
local mapping_key = vim.api.nvim_replace_termcodes(mapping.lhs, true, true, true)
if mapping_key == normalized_key and mapping.desc ~= 'blink.cmp' then return mapping end
end
end

--- Runs the first non blink.cmp keymap for the given mode and key
function keymap.run_non_blink_keymap(mode, key)
local mapping = keymap.get_non_blink_mapping_for_key(mode, key) or {}

-- todo: there's likely many edge cases here. the nvim-cmp version is lacking documentation
-- and is quite complex. we should look to see if we can simplify their logic
-- /~https://github.com/hrsh7th/nvim-cmp/blob/ae644feb7b67bf1ce4260c231d1d4300b19c6f30/lua/cmp/utils/keymap.lua
if type(mapping.callback) == 'function' then
return mapping.callback()
elseif mapping.rhs then
return vim.api.nvim_eval(vim.api.nvim_replace_termcodes(mapping.rhs, true, true, true))
end

-- pass the key along as usual
return vim.api.nvim_replace_termcodes(key, true, true, true)
end

function keymap.set(mode, key, callback)
vim.api.nvim_buf_set_keymap(0, mode, key, '', {
callback = callback,
expr = true,
silent = true,
noremap = true,
replace_keycodes = false,
desc = 'blink.cmp',
})
end

return keymap
2 changes: 1 addition & 1 deletion lua/blink/cmp/sources/lib/context.lua
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ function sources_context:get_completions_for_group(sources_group_idx, sources_gr
and vim.tbl_contains(source:get_trigger_characters(), context.trigger.character)

-- The TriggerForIncompleteCompletions kind is handled by the source itself
local source_context = vim.fn.deepcopy(context)
local source_context = require('blink.cmp.utils').shallow_copy(context)
source_context.trigger = trigger_character
and { kind = vim.lsp.protocol.CompletionTriggerKind.TriggerCharacter, character = context.trigger.character }
or { kind = vim.lsp.protocol.CompletionTriggerKind.Invoked }
Expand Down
3 changes: 3 additions & 0 deletions lua/blink/cmp/sources/path/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ end
function path:get_trigger_characters() return { '/', '.' } end

function path:get_completions(context, callback)
-- we use libuv, but the rest of the library expects to be synchronous
callback = vim.schedule_wrap(callback)

local lib = require('blink.cmp.sources.path.lib')

local dirname = lib.dirname(PATH_REGEX, self.opts.get_cwd, context)
Expand Down
5 changes: 4 additions & 1 deletion lua/blink/cmp/sources/path/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ local lib = {}
--- @param get_cwd fun(context: blink.cmp.Context): string
--- @param context blink.cmp.Context
function lib.dirname(path_regex, get_cwd, context)
local line_before_cursor = context.line:sub(1, context.cursor[2])
-- HACK: move this :sub logic into the context?
-- it's not obvious that you need to avoid going back a char if the start_col == end_col
local line_before_cursor =
context.line:sub(1, context.bounds.start_col - (context.bounds.start_col ~= context.bounds.end_col and 1 or 0))
local s = path_regex:match_str(line_before_cursor)
if not s then return nil end

Expand Down
Loading

0 comments on commit 74f1b93

Please sign in to comment.