* Try to fix col adjustment (#843) * Try to fix col adjuastment * Improve duplicated text handling * Bottom up mode for custom entry menu When in command line mode, the custom entry window opens up to an unexpected height, depending on the current count of completion items. The above makes it hard to anticipate where to look at, and makes life a bit harder. This patch adds an option to open the custom entries view in a bottom up mode, and flips the regular behaviour of next/prev entry in this mode. Setup is as easy as: ``` cmp.setup.cmdline(':', { view = { entries = {name = 'custom', direction = 'bottom_up' } } } ``` * fix stylua complaints * sylua barfs * solve some corner cases * properly reverse entries table * make custom view follow cursor * respect default as top_down * stylua * more stylua Co-authored-by: hrsh7th <hrsh7th@gmail.com>
207 lines
5.7 KiB
Lua
207 lines
5.7 KiB
Lua
local mapping = require('cmp.config.mapping')
|
|
local cache = require('cmp.utils.cache')
|
|
local keymap = require('cmp.utils.keymap')
|
|
local misc = require('cmp.utils.misc')
|
|
local api = require('cmp.utils.api')
|
|
|
|
---@class cmp.Config
|
|
---@field public g cmp.ConfigSchema
|
|
local config = {}
|
|
|
|
---@type cmp.Cache
|
|
config.cache = cache.new()
|
|
|
|
---@type cmp.ConfigSchema
|
|
config.global = require('cmp.config.default')()
|
|
|
|
---@type table<number, cmp.ConfigSchema>
|
|
config.buffers = {}
|
|
|
|
---@type table<string, cmp.ConfigSchema>
|
|
config.filetypes = {}
|
|
|
|
---@type table<string, cmp.ConfigSchema>
|
|
config.cmdline = {}
|
|
|
|
---@type cmp.ConfigSchema
|
|
config.onetime = {}
|
|
|
|
---Set configuration for global.
|
|
---@param c cmp.ConfigSchema
|
|
config.set_global = function(c)
|
|
config.global = misc.merge(config.normalize(c), config.normalize(config.global))
|
|
config.global.revision = config.global.revision or 1
|
|
config.global.revision = config.global.revision + 1
|
|
end
|
|
|
|
---Set configuration for buffer
|
|
---@param c cmp.ConfigSchema
|
|
---@param bufnr number|nil
|
|
config.set_buffer = function(c, bufnr)
|
|
local revision = (config.buffers[bufnr] or {}).revision or 1
|
|
config.buffers[bufnr] = c or {}
|
|
config.buffers[bufnr].revision = revision + 1
|
|
end
|
|
|
|
---Set configuration for filetype
|
|
---@param c cmp.ConfigSchema
|
|
---@param filetypes string[]|string
|
|
config.set_filetype = function(c, filetypes)
|
|
for _, filetype in ipairs(type(filetypes) == 'table' and filetypes or { filetypes }) do
|
|
local revision = (config.filetypes[filetype] or {}).revision or 1
|
|
config.filetypes[filetype] = c or {}
|
|
config.filetypes[filetype].revision = revision + 1
|
|
end
|
|
end
|
|
|
|
---Set configuration for cmdline
|
|
---@param c cmp.ConfigSchema
|
|
---@param cmdtype string
|
|
config.set_cmdline = function(c, cmdtype)
|
|
local revision = (config.cmdline[cmdtype] or {}).revision or 1
|
|
config.cmdline[cmdtype] = c or {}
|
|
config.cmdline[cmdtype].revision = revision + 1
|
|
end
|
|
|
|
---Set configuration as oneshot completion.
|
|
---@param c cmp.ConfigSchema
|
|
config.set_onetime = function(c)
|
|
local revision = (config.onetime or {}).revision or 1
|
|
config.onetime = c or {}
|
|
config.onetime.revision = revision + 1
|
|
end
|
|
|
|
---@return cmp.ConfigSchema
|
|
config.get = function()
|
|
local global_config = config.global
|
|
if config.onetime.sources then
|
|
local onetime_config = config.onetime
|
|
return config.cache:ensure({
|
|
'get',
|
|
'onetime',
|
|
global_config.revision or 0,
|
|
onetime_config.revision or 0,
|
|
}, function()
|
|
return misc.merge(config.normalize(onetime_config), config.normalize(global_config))
|
|
end)
|
|
elseif api.is_cmdline_mode() then
|
|
local cmdtype = vim.fn.getcmdtype()
|
|
local cmdline_config = config.cmdline[cmdtype] or { revision = 1, sources = {} }
|
|
return config.cache:ensure({
|
|
'get',
|
|
'cmdline',
|
|
global_config.revision or 0,
|
|
cmdtype,
|
|
cmdline_config.revision or 0,
|
|
}, function()
|
|
return misc.merge(config.normalize(cmdline_config), config.normalize(global_config))
|
|
end)
|
|
else
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
local filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype')
|
|
local buffer_config = config.buffers[bufnr] or { revision = 1 }
|
|
local filetype_config = config.filetypes[filetype] or { revision = 1 }
|
|
return config.cache:ensure({
|
|
'get',
|
|
'default',
|
|
global_config.revision or 0,
|
|
filetype,
|
|
filetype_config.revision or 0,
|
|
bufnr,
|
|
buffer_config.revision or 0,
|
|
}, function()
|
|
local c = {}
|
|
c = misc.merge(c, config.normalize(buffer_config))
|
|
c = misc.merge(c, config.normalize(filetype_config))
|
|
c = misc.merge(c, config.normalize(global_config))
|
|
return c
|
|
end)
|
|
end
|
|
end
|
|
|
|
---Return cmp is enabled or not.
|
|
config.enabled = function()
|
|
local enabled = config.get().enabled
|
|
if type(enabled) == 'function' then
|
|
enabled = enabled()
|
|
end
|
|
return enabled and api.is_suitable_mode()
|
|
end
|
|
|
|
---Return source config
|
|
---@param name string
|
|
---@return cmp.SourceConfig
|
|
config.get_source_config = function(name)
|
|
local c = config.get()
|
|
for _, s in ipairs(c.sources) do
|
|
if s.name == name then
|
|
return s
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
---Return the current menu is native or not.
|
|
config.is_native_menu = function()
|
|
local c = config.get()
|
|
if c.experimental and c.experimental.native_menu then
|
|
return true
|
|
end
|
|
if c.view and c.view.entries then
|
|
return c.view.entries == 'native' or c.view.entries.name == 'native'
|
|
end
|
|
return false
|
|
end
|
|
|
|
---Normalize mapping key
|
|
---@param c cmp.ConfigSchema
|
|
---@return cmp.ConfigSchema
|
|
config.normalize = function(c)
|
|
-- make sure c is not 'nil'
|
|
c = c == nil and {} or c
|
|
|
|
if c.mapping then
|
|
local normalized = {}
|
|
for k, v in pairs(c.mapping) do
|
|
normalized[keymap.normalize(k)] = mapping(v, { 'i' })
|
|
end
|
|
c.mapping = normalized
|
|
end
|
|
|
|
if c.experimental and c.experimental.native_menu then
|
|
vim.api.nvim_echo({
|
|
{ '[nvim-cmp] ', 'Normal' },
|
|
{ 'experimental.native_menu', 'WarningMsg' },
|
|
{ ' is deprecated.\n', 'Normal' },
|
|
{ '[nvim-cmp] Please use ', 'Normal' },
|
|
{ 'view.entries = "native"', 'WarningMsg' },
|
|
{ ' instead.', 'Normal' },
|
|
}, true, {})
|
|
|
|
c.view = c.view or {}
|
|
c.view.entries = c.view.entries or 'native'
|
|
end
|
|
|
|
if c.sources then
|
|
for _, s in ipairs(c.sources) do
|
|
if s.opts and not s.option then
|
|
s.option = s.opts
|
|
s.opts = nil
|
|
vim.api.nvim_echo({
|
|
{ '[nvim-cmp] ', 'Normal' },
|
|
{ 'sources[number].opts', 'WarningMsg' },
|
|
{ ' is deprecated.\n', 'Normal' },
|
|
{ '[nvim-cmp] Please use ', 'Normal' },
|
|
{ 'sources[number].option', 'WarningMsg' },
|
|
{ ' instead.', 'Normal' },
|
|
}, true, {})
|
|
end
|
|
s.option = s.option or {}
|
|
end
|
|
end
|
|
|
|
return c
|
|
end
|
|
|
|
return config
|