20
doc/cmp.txt
20
doc/cmp.txt
@@ -204,6 +204,23 @@ NOTE: You can call these functions in mapping via `<Cmd>lua require('cmp').compl
|
|||||||
<
|
<
|
||||||
NOTE: The `config` means a temporary setting, but the `config.mapping` remains permanent.
|
NOTE: The `config` means a temporary setting, but the `config.mapping` remains permanent.
|
||||||
|
|
||||||
|
*cmp.complete_common_string* ()
|
||||||
|
Complete common string as like as shell completion behavior.
|
||||||
|
>
|
||||||
|
cmp.setup {
|
||||||
|
mapping = {
|
||||||
|
['<C-n>'] = cmp.mapping(function(fallback)
|
||||||
|
if cmp.visible() then
|
||||||
|
if cmp.complete_common_string() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
return cmp.select_next_item()
|
||||||
|
end
|
||||||
|
fallback()
|
||||||
|
end, { 'i', 'c' }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<
|
||||||
*cmp.confirm* (option: cmp.ConfirmOption, callback: function)
|
*cmp.confirm* (option: cmp.ConfirmOption, callback: function)
|
||||||
Accept current selected completion item.
|
Accept current selected completion item.
|
||||||
If you didn't select any items and specified the `{ select = true }` for
|
If you didn't select any items and specified the `{ select = true }` for
|
||||||
@@ -279,6 +296,9 @@ You can also use built-in mapping helpers.
|
|||||||
*cmp.mapping.complete* (option: cmp.CompleteParams)
|
*cmp.mapping.complete* (option: cmp.CompleteParams)
|
||||||
Same as |cmp.complete|
|
Same as |cmp.complete|
|
||||||
|
|
||||||
|
*cmp.mapping.complete_common_string* ()
|
||||||
|
Same as |cmp.complete_common_string|
|
||||||
|
|
||||||
*cmp.mapping.confirm* (option: cmp.ConfirmOption)
|
*cmp.mapping.confirm* (option: cmp.ConfirmOption)
|
||||||
Same as |cmp.confirm|
|
Same as |cmp.confirm|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,15 @@ mapping.complete = function(option)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Complete common string.
|
||||||
|
mapping.complete_common_string = function()
|
||||||
|
return function(fallback)
|
||||||
|
if not require('cmp').complete_common_string() then
|
||||||
|
fallback()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---Close current completion menu if it displayed.
|
---Close current completion menu if it displayed.
|
||||||
mapping.close = function()
|
mapping.close = function()
|
||||||
return function(fallback)
|
return function(fallback)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
local debug = require('cmp.utils.debug')
|
local debug = require('cmp.utils.debug')
|
||||||
|
local str = require('cmp.utils.str')
|
||||||
local char = require('cmp.utils.char')
|
local char = require('cmp.utils.char')
|
||||||
local pattern = require('cmp.utils.pattern')
|
local pattern = require('cmp.utils.pattern')
|
||||||
local feedkeys = require('cmp.utils.feedkeys')
|
local feedkeys = require('cmp.utils.feedkeys')
|
||||||
@@ -217,6 +218,32 @@ core.autoindent = function(self, trigger_event, callback)
|
|||||||
callback()
|
callback()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Complete common string for current completed entries.
|
||||||
|
core.complete_common_string = function(self)
|
||||||
|
if not self.view:visible() then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
self.filter:sync(1000)
|
||||||
|
|
||||||
|
local cursor = api.get_cursor()
|
||||||
|
local offset = self.view:get_offset()
|
||||||
|
local common_string
|
||||||
|
for _, e in ipairs(self.view:get_entries()) do
|
||||||
|
local vim_item = e:get_vim_item(offset)
|
||||||
|
if not common_string then
|
||||||
|
common_string = vim_item.word
|
||||||
|
else
|
||||||
|
common_string = str.get_common_string(common_string, vim_item.word)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if common_string and #common_string > (1 + cursor[2] - offset) then
|
||||||
|
feedkeys.call(keymap.backspace(string.sub(api.get_current_line(), offset, cursor[2])) .. common_string, 'n')
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
---Invoke completion
|
---Invoke completion
|
||||||
---@param ctx cmp.Context
|
---@param ctx cmp.Context
|
||||||
core.complete = function(self, ctx)
|
core.complete = function(self, ctx)
|
||||||
|
|||||||
@@ -75,6 +75,10 @@ cmp.complete = cmp.sync(function(option)
|
|||||||
return true
|
return true
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
cmp.complete_common_string = cmp.sync(function()
|
||||||
|
return cmp.core:complete_common_string()
|
||||||
|
end)
|
||||||
|
|
||||||
---Return view is visible or not.
|
---Return view is visible or not.
|
||||||
cmp.visible = cmp.sync(function()
|
cmp.visible = cmp.sync(function()
|
||||||
return cmp.core.view:visible() or vim.fn.pumvisible() == 1
|
return cmp.core.view:visible() or vim.fn.pumvisible() == 1
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ end
|
|||||||
---@param count number
|
---@param count number
|
||||||
---@return string
|
---@return string
|
||||||
keymap.backspace = function(count)
|
keymap.backspace = function(count)
|
||||||
|
if type(count) == 'string' then
|
||||||
|
count = vim.fn.strchars(count, true)
|
||||||
|
end
|
||||||
if count <= 0 then
|
if count <= 0 then
|
||||||
return ''
|
return ''
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -43,6 +43,17 @@ str.has_prefix = function(text, prefix)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---get_common_string
|
||||||
|
str.get_common_string = function(text1, text2)
|
||||||
|
local min = math.min(#text1, #text2)
|
||||||
|
for i = 1, min do
|
||||||
|
if not char.match(string.byte(text1, i), string.byte(text2, i)) then
|
||||||
|
return string.sub(text1, 1, i - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return string.sub(text1, 1, min)
|
||||||
|
end
|
||||||
|
|
||||||
---Remove suffix
|
---Remove suffix
|
||||||
---@param text string
|
---@param text string
|
||||||
---@param suffix string
|
---@param suffix string
|
||||||
|
|||||||
@@ -161,6 +161,17 @@ view.select_prev_item = function(self, option)
|
|||||||
self:_get_entries_view():select_prev_item(option)
|
self:_get_entries_view():select_prev_item(option)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Get offset.
|
||||||
|
view.get_offset = function(self)
|
||||||
|
return self:_get_entries_view():get_offset()
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get entries.
|
||||||
|
---@return cmp.Entry[]
|
||||||
|
view.get_entries = function(self)
|
||||||
|
return self:_get_entries_view():get_entries()
|
||||||
|
end
|
||||||
|
|
||||||
---Get first entry
|
---Get first entry
|
||||||
---@param self cmp.Entry|nil
|
---@param self cmp.Entry|nil
|
||||||
view.get_first_entry = function(self)
|
view.get_first_entry = function(self)
|
||||||
|
|||||||
@@ -257,6 +257,20 @@ custom_entries_view.select_prev_item = function(self, option)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
custom_entries_view.get_offset = function(self)
|
||||||
|
if self:visible() then
|
||||||
|
return self.offset
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
custom_entries_view.get_entries = function(self)
|
||||||
|
if self:visible() then
|
||||||
|
return self.entries
|
||||||
|
end
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
custom_entries_view.get_first_entry = function(self)
|
custom_entries_view.get_first_entry = function(self)
|
||||||
if self:visible() then
|
if self:visible() then
|
||||||
return self.entries[1]
|
return self.entries[1]
|
||||||
@@ -301,8 +315,7 @@ custom_entries_view._insert = setmetatable({
|
|||||||
word = word or ''
|
word = word or ''
|
||||||
if api.is_cmdline_mode() then
|
if api.is_cmdline_mode() then
|
||||||
local cursor = api.get_cursor()
|
local cursor = api.get_cursor()
|
||||||
local length = vim.fn.strchars(string.sub(api.get_current_line(), self.offset, cursor[2]), true)
|
vim.api.nvim_feedkeys(keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2])) .. word, 'int', true)
|
||||||
vim.api.nvim_feedkeys(keymap.backspace(length) .. word, 'int', true)
|
|
||||||
else
|
else
|
||||||
if this.pending then
|
if this.pending then
|
||||||
return
|
return
|
||||||
@@ -312,10 +325,9 @@ custom_entries_view._insert = setmetatable({
|
|||||||
local release = require('cmp').suspend()
|
local release = require('cmp').suspend()
|
||||||
feedkeys.call('', '', function()
|
feedkeys.call('', '', function()
|
||||||
local cursor = api.get_cursor()
|
local cursor = api.get_cursor()
|
||||||
local length = vim.fn.strchars(string.sub(api.get_current_line(), self.offset, cursor[2]), true)
|
|
||||||
local keys = {}
|
local keys = {}
|
||||||
table.insert(keys, keymap.indentkeys())
|
table.insert(keys, keymap.indentkeys())
|
||||||
table.insert(keys, keymap.backspace(length))
|
table.insert(keys, keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2])))
|
||||||
table.insert(keys, word)
|
table.insert(keys, word)
|
||||||
table.insert(keys, keymap.indentkeys(vim.bo.indentkeys))
|
table.insert(keys, keymap.indentkeys(vim.bo.indentkeys))
|
||||||
feedkeys.call(
|
feedkeys.call(
|
||||||
|
|||||||
@@ -143,6 +143,20 @@ native_entries_view.select_prev_item = function(self, option)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
native_entries_view.get_offset = function(self)
|
||||||
|
if self:visible() then
|
||||||
|
return self.offset
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
native_entries_view.get_entries = function(self)
|
||||||
|
if self:visible() then
|
||||||
|
return self.entries
|
||||||
|
end
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
native_entries_view.get_first_entry = function(self)
|
native_entries_view.get_first_entry = function(self)
|
||||||
if self:visible() then
|
if self:visible() then
|
||||||
return self.entries[1]
|
return self.entries[1]
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ local api = require('cmp.utils.api')
|
|||||||
---@field private active boolean
|
---@field private active boolean
|
||||||
---@field private entries cmp.Entry[]
|
---@field private entries cmp.Entry[]
|
||||||
---@field public event cmp.Event
|
---@field public event cmp.Event
|
||||||
local statusline_entries_view = {}
|
local wildmenu_entries_view = {}
|
||||||
|
|
||||||
local function get_separator()
|
local function get_separator()
|
||||||
local c = config.get()
|
local c = config.get()
|
||||||
return (c and c.view and c.view.entries and c.view.entries.separator) or ' '
|
return (c and c.view and c.view.entries and c.view.entries.separator) or ' '
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.ns = vim.api.nvim_create_namespace('cmp.view.statusline_entries_view')
|
wildmenu_entries_view.ns = vim.api.nvim_create_namespace('cmp.view.statusline_entries_view')
|
||||||
|
|
||||||
statusline_entries_view.init = function(self)
|
wildmenu_entries_view.init = function(self)
|
||||||
self.event = event.new()
|
self.event = event.new()
|
||||||
self.offset = -1
|
self.offset = -1
|
||||||
self.active = false
|
self.active = false
|
||||||
@@ -33,8 +33,8 @@ statusline_entries_view.init = function(self)
|
|||||||
self.moving_forwards = nil
|
self.moving_forwards = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.new = function()
|
wildmenu_entries_view.new = function()
|
||||||
local self = setmetatable({}, { __index = statusline_entries_view })
|
local self = setmetatable({}, { __index = wildmenu_entries_view })
|
||||||
self:init()
|
self:init()
|
||||||
|
|
||||||
self.entries_win = window.new()
|
self.entries_win = window.new()
|
||||||
@@ -47,7 +47,7 @@ statusline_entries_view.new = function()
|
|||||||
self.entries_win:option('winhighlight', 'Normal:Pmenu,FloatBorder:Pmenu,CursorLine:PmenuSel,Search:None')
|
self.entries_win:option('winhighlight', 'Normal:Pmenu,FloatBorder:Pmenu,CursorLine:PmenuSel,Search:None')
|
||||||
self.entries_win:buffer_option('tabstop', 1)
|
self.entries_win:buffer_option('tabstop', 1)
|
||||||
|
|
||||||
vim.api.nvim_set_decoration_provider(statusline_entries_view.ns, {
|
vim.api.nvim_set_decoration_provider(wildmenu_entries_view.ns, {
|
||||||
on_win = function(_, win, buf, _, _)
|
on_win = function(_, win, buf, _, _)
|
||||||
if win ~= self.entries_win.win or buf ~= self.entries_win:get_buffer() then
|
if win ~= self.entries_win.win or buf ~= self.entries_win:get_buffer() then
|
||||||
return
|
return
|
||||||
@@ -58,7 +58,7 @@ statusline_entries_view.new = function()
|
|||||||
local e = self.entries[i]
|
local e = self.entries[i]
|
||||||
if e then
|
if e then
|
||||||
local view = e:get_view(self.offset, buf)
|
local view = e:get_view(self.offset, buf)
|
||||||
vim.api.nvim_buf_set_extmark(buf, statusline_entries_view.ns, 0, location, {
|
vim.api.nvim_buf_set_extmark(buf, wildmenu_entries_view.ns, 0, location, {
|
||||||
end_line = 0,
|
end_line = 0,
|
||||||
end_col = location + view['abbr'].bytes,
|
end_col = location + view['abbr'].bytes,
|
||||||
hl_group = view['abbr'].hl_group,
|
hl_group = view['abbr'].hl_group,
|
||||||
@@ -67,7 +67,7 @@ statusline_entries_view.new = function()
|
|||||||
})
|
})
|
||||||
|
|
||||||
if i == self.selected_index then
|
if i == self.selected_index then
|
||||||
vim.api.nvim_buf_set_extmark(buf, statusline_entries_view.ns, 0, location, {
|
vim.api.nvim_buf_set_extmark(buf, wildmenu_entries_view.ns, 0, location, {
|
||||||
end_line = 0,
|
end_line = 0,
|
||||||
end_col = location + view['abbr'].bytes,
|
end_col = location + view['abbr'].bytes,
|
||||||
hl_group = 'PmenuSel',
|
hl_group = 'PmenuSel',
|
||||||
@@ -77,7 +77,7 @@ statusline_entries_view.new = function()
|
|||||||
end
|
end
|
||||||
|
|
||||||
for _, m in ipairs(e.matches or {}) do
|
for _, m in ipairs(e.matches or {}) do
|
||||||
vim.api.nvim_buf_set_extmark(buf, statusline_entries_view.ns, 0, location + m.word_match_start - 1, {
|
vim.api.nvim_buf_set_extmark(buf, wildmenu_entries_view.ns, 0, location + m.word_match_start - 1, {
|
||||||
end_line = 0,
|
end_line = 0,
|
||||||
end_col = location + m.word_match_end,
|
end_col = location + m.word_match_end,
|
||||||
hl_group = m.fuzzy and 'CmpItemAbbrMatchFuzzy' or 'CmpItemAbbrMatch',
|
hl_group = m.fuzzy and 'CmpItemAbbrMatchFuzzy' or 'CmpItemAbbrMatch',
|
||||||
@@ -103,20 +103,20 @@ statusline_entries_view.new = function()
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.close = function(self)
|
wildmenu_entries_view.close = function(self)
|
||||||
self.entries_win:close()
|
self.entries_win:close()
|
||||||
self:init()
|
self:init()
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.ready = function()
|
wildmenu_entries_view.ready = function()
|
||||||
return vim.fn.pumvisible() == 0
|
return vim.fn.pumvisible() == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.on_change = function(self)
|
wildmenu_entries_view.on_change = function(self)
|
||||||
self.active = false
|
self.active = false
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.open = function(self, offset, entries)
|
wildmenu_entries_view.open = function(self, offset, entries)
|
||||||
self.offset = offset
|
self.offset = offset
|
||||||
self.entries = {}
|
self.entries = {}
|
||||||
self.last_displayed_indices = {}
|
self.last_displayed_indices = {}
|
||||||
@@ -159,13 +159,13 @@ statusline_entries_view.open = function(self, offset, entries)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.abort = function(self)
|
wildmenu_entries_view.abort = function(self)
|
||||||
feedkeys.call('', 'n', function()
|
feedkeys.call('', 'n', function()
|
||||||
self:close()
|
self:close()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.draw = function(self)
|
wildmenu_entries_view.draw = function(self)
|
||||||
local entries_buf = self.entries_win:get_buffer()
|
local entries_buf = self.entries_win:get_buffer()
|
||||||
local texts = {}
|
local texts = {}
|
||||||
local lengths = {}
|
local lengths = {}
|
||||||
@@ -235,15 +235,15 @@ statusline_entries_view.draw = function(self)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.visible = function(self)
|
wildmenu_entries_view.visible = function(self)
|
||||||
return self.entries_win:visible()
|
return self.entries_win:visible()
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.info = function(self)
|
wildmenu_entries_view.info = function(self)
|
||||||
return self.entries_win:info()
|
return self.entries_win:info()
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.select_next_item = function(self, option)
|
wildmenu_entries_view.select_next_item = function(self, option)
|
||||||
if self:visible() then
|
if self:visible() then
|
||||||
self.moving_forwards = true
|
self.moving_forwards = true
|
||||||
if self.selected_index == nil or self.selected_index == #self.entries then
|
if self.selected_index == nil or self.selected_index == #self.entries then
|
||||||
@@ -254,7 +254,7 @@ statusline_entries_view.select_next_item = function(self, option)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.select_prev_item = function(self, option)
|
wildmenu_entries_view.select_prev_item = function(self, option)
|
||||||
if self:visible() then
|
if self:visible() then
|
||||||
self.moving_forwards = false
|
self.moving_forwards = false
|
||||||
if self.selected_index == nil or self.selected_index <= 1 then
|
if self.selected_index == nil or self.selected_index <= 1 then
|
||||||
@@ -265,33 +265,46 @@ statusline_entries_view.select_prev_item = function(self, option)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.get_first_entry = function(self)
|
wildmenu_entries_view.get_offset = function(self)
|
||||||
|
if self:visible() then
|
||||||
|
return self.offset
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
wildmenu_entries_view.get_entries = function(self)
|
||||||
|
if self:visible() then
|
||||||
|
return self.entries
|
||||||
|
end
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
wildmenu_entries_view.get_first_entry = function(self)
|
||||||
if self:visible() then
|
if self:visible() then
|
||||||
return self.entries[1]
|
return self.entries[1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.get_selected_entry = function(self)
|
wildmenu_entries_view.get_selected_entry = function(self)
|
||||||
if self:visible() and self.active then
|
if self:visible() and self.active then
|
||||||
return self.entries[self.selected_index]
|
return self.entries[self.selected_index]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view.get_active_entry = function(self)
|
wildmenu_entries_view.get_active_entry = function(self)
|
||||||
if self:visible() and self.active then
|
if self:visible() and self.active then
|
||||||
return self:get_selected_entry()
|
return self:get_selected_entry()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
statusline_entries_view._select = function(self, selected_index, _)
|
wildmenu_entries_view._select = function(self, selected_index, _)
|
||||||
self.selected_index = selected_index
|
self.selected_index = selected_index
|
||||||
self.active = (selected_index ~= nil)
|
self.active = (selected_index ~= nil)
|
||||||
|
|
||||||
if self.active then
|
if self.active then
|
||||||
local cursor = api.get_cursor()
|
local cursor = api.get_cursor()
|
||||||
local word = self:get_active_entry():get_vim_item(self.offset).word
|
local word = self:get_active_entry():get_vim_item(self.offset).word
|
||||||
local length = vim.fn.strchars(string.sub(api.get_current_line(), self.offset, cursor[2]), true)
|
vim.api.nvim_feedkeys(keymap.backspace(string.sub(api.get_current_line(), self.offset, cursor[2])) .. word, 'int', true)
|
||||||
vim.api.nvim_feedkeys(keymap.backspace(length) .. word, 'int', true)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self.entries_win:update()
|
self.entries_win:update()
|
||||||
@@ -299,4 +312,4 @@ statusline_entries_view._select = function(self, selected_index, _)
|
|||||||
self.event:emit('change')
|
self.event:emit('change')
|
||||||
end
|
end
|
||||||
|
|
||||||
return statusline_entries_view
|
return wildmenu_entries_view
|
||||||
|
|||||||
Reference in New Issue
Block a user