diff --git a/docs/configuration/completion.md b/docs/configuration/completion.md index a0d4eb74..13a42056 100644 --- a/docs/configuration/completion.md +++ b/docs/configuration/completion.md @@ -59,6 +59,14 @@ TODO: Find a case where this actually fires : ) Manages the completion list and its behavior when selecting items. The most commonly changed option is `completion.list.selection`, which controls whether the list will automatically select the first item in the list, and whether selection shows a preview: +To control the selection behavior per mode, pass a function to `completion.list.selection` that returns the selection mode: + +```lua +completion.list.selection = function(ctx) + return ctx.mode == 'cmdline' and 'auto_insert' or 'preselect' +end +``` + :::tabs == Preselect Selects the first item automatically diff --git a/docs/configuration/general.md b/docs/configuration/general.md index b0a217e5..50ece7af 100644 --- a/docs/configuration/general.md +++ b/docs/configuration/general.md @@ -4,6 +4,8 @@ Blink cmp has *a lot* of configuration options, the following code block highlig For more common configurations, see the [recipes](../recipes.md). +> [!IMPORTANT] Do not copy this entire configuration! It contains only non-default options + ```lua { -- Disable for some filetypes @@ -25,6 +27,8 @@ For more common configurations, see the [recipes](../recipes.md). -- Insert completion item on selection, don't select by default list = { selection = 'auto_insert' }, + -- or set per mode + list = { selection = function(ctx) return ctx.mode == 'cmdline' and 'auto_insert' or 'preselect' end }, menu = { -- Don't automatically show the completion menu diff --git a/docs/configuration/reference.md b/docs/configuration/reference.md index 9f9223bb..ea648301 100644 --- a/docs/configuration/reference.md +++ b/docs/configuration/reference.md @@ -92,9 +92,12 @@ completion.trigger = { completion.list = { -- Maximum number of items to display max_items = 200, + -- Controls if completion items will be selected automatically, -- and whether selection automatically inserts selection = 'preselect', + -- selection = function(ctx) return ctx.mode == 'cmdline' and 'auto_insert' or 'preselect' end, + -- Controls how the completion items are selected -- 'preselect' will automatically select the first item in the completion list -- 'manual' will not select any item by default diff --git a/docs/recipes.md b/docs/recipes.md index d3bb2dd4..d8075382 100644 --- a/docs/recipes.md +++ b/docs/recipes.md @@ -1,6 +1,5 @@ # Recipes - ## Disable per filetype ```lua @@ -21,6 +20,18 @@ completion = { signature = { window = { border = 'single' } }, ``` +## Change selection mode per mode + +```lua +completion = { + list = { + selection = function(ctx) + return ctx.mode == 'cmdline' and 'auto_insert' or 'preselect' + end + } +} +``` + ## Select Nth item from the list Here's an example configuration that allows you to select the nth item from the list, based on [#382](https://github.com/Saghen/blink.cmp/issues/382): diff --git a/lua/blink/cmp/completion/list.lua b/lua/blink/cmp/completion/list.lua index d308bdd5..3604c431 100644 --- a/lua/blink/cmp/completion/list.lua +++ b/lua/blink/cmp/completion/list.lua @@ -15,6 +15,7 @@ --- @field hide fun() --- --- @field get_selected_item fun(): blink.cmp.CompletionItem? +--- @field get_selection_mode fun(context: blink.cmp.Context): blink.cmp.CompletionListSelection --- @field select fun(idx?: number, opts?: { undo_preview?: boolean, is_explicit_selection?: boolean }) --- @field select_next fun() --- @field select_prev fun() @@ -57,7 +58,7 @@ local list = { config = require('blink.cmp.config').completion.list, context = nil, items = {}, - selected_item_idx = nil, + selection_mode = nil, is_explicitly_selected = false, preview_undo = nil, } @@ -83,6 +84,7 @@ function list.show(context, items_by_source) -- update the context/list and emit list.context = context list.items = list.fuzzy(context, items_by_source) + list.selection_mode = list.get_selection_mode(list.context) if #list.items == 0 then list.hide_emitter:emit({ context = context }) @@ -98,7 +100,7 @@ function list.show(context, items_by_source) -- otherwise, use the default selection else list.select( - list.config.selection == 'preselect' and 1 or nil, + list.selection_mode == 'preselect' and 1 or nil, { undo_preview = false, is_explicit_selection = false } ) end @@ -121,6 +123,13 @@ function list.hide() list.hide_emitter:emit({ context = list.context }) end function list.get_selected_item() return list.items[list.selected_item_idx] end +function list.get_selection_mode(context) + assert(context ~= nil, 'Context must be set before getting selection mode') + if type(list.config.selection) == 'function' then return list.config.selection(context) end + --- @diagnostic disable-next-line: return-type-mismatch + return list.config.selection +end + function list.select(idx, opts) opts = opts or {} local item = list.items[idx] @@ -128,7 +137,7 @@ function list.select(idx, opts) require('blink.cmp.completion.trigger').suppress_events_for_callback(function() -- default to undoing the preview if opts.undo_preview ~= false then list.undo_preview() end - if list.config.selection == 'auto_insert' and item then list.apply_preview(item) end + if list.selection_mode == 'auto_insert' and item then list.apply_preview(item) end end) --- @diagnostic disable-next-line: assign-type-mismatch @@ -149,7 +158,7 @@ function list.select_next() if not list.config.cycle.from_bottom then return end -- preselect is not enabled, we go back to no selection - if list.config.selection ~= 'preselect' then return list.select(nil) end + if list.selection_mode ~= 'preselect' then return list.select(nil) end -- otherwise, we cycle around return list.select(1) @@ -171,7 +180,7 @@ function list.select_prev() if not list.config.cycle.from_top then return end -- auto_insert is enabled, we go back to no selection - if list.config.selection == 'auto_insert' then return list.select(nil) end + if list.selection_mode == 'auto_insert' then return list.select(nil) end -- otherwise, we cycle around return list.select(#list.items) diff --git a/lua/blink/cmp/config/completion/list.lua b/lua/blink/cmp/config/completion/list.lua index ab2e25a4..c49c831f 100644 --- a/lua/blink/cmp/config/completion/list.lua +++ b/lua/blink/cmp/config/completion/list.lua @@ -1,6 +1,6 @@ --- @class (exact) blink.cmp.CompletionListConfig --- @field max_items number Maximum number of items to display ---- @field selection blink.cmp.CompletionListSelection Controls if completion items will be selected automatically, and whether selection automatically inserts +--- @field selection blink.cmp.CompletionListSelection | fun(ctx: blink.cmp.Context): blink.cmp.CompletionListSelection Controls if completion items will be selected automatically, and whether selection automatically inserts --- @field cycle blink.cmp.CompletionListCycleConfig --- @alias blink.cmp.CompletionListSelection @@ -30,7 +30,10 @@ function list.validate(config) max_items = { config.max_items, 'number' }, selection = { config.selection, - function() return vim.tbl_contains({ 'preselect', 'manual', 'auto_insert' }, config.selection) end, + function() + return vim.tbl_contains({ 'preselect', 'manual', 'auto_insert' }, config.selection) + or type(config.selection) == 'function' + end, 'one of: preselect, manual, auto_insert', }, cycle = { config.cycle, 'table' },