Experimental: Ghost text (#119)
* Inline suggest experimental * Fix flicker * Fix ci fails * Reduce flicker * Improve menu functions * Default false * README.md * Add require * Rename inline_preview to ghost_text
This commit is contained in:
@@ -61,6 +61,10 @@ return function()
|
||||
end
|
||||
},
|
||||
|
||||
experimental = {
|
||||
ghost_text = false,
|
||||
},
|
||||
|
||||
sources = {},
|
||||
}
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
local debug = require('cmp.utils.debug')
|
||||
local char = require('cmp.utils.char')
|
||||
local str = require('cmp.utils.str')
|
||||
local pattern = require('cmp.utils.pattern')
|
||||
local async = require('cmp.utils.async')
|
||||
local keymap = require('cmp.utils.keymap')
|
||||
@@ -18,6 +19,16 @@ core.SOURCE_TIMEOUT = 500
|
||||
---Suspending state.
|
||||
core.suspending = false
|
||||
|
||||
core.GHOST_TEXT_NS = vim.api.nvim_create_namespace('cmp:GHOST_TEXT');
|
||||
|
||||
vim.api.nvim_set_decoration_provider(core.GHOST_TEXT_NS, {
|
||||
on_win = function()
|
||||
if config.get().experimental.ghost_text then
|
||||
core.ghost_text(core.menu:get_first_entry())
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
---@type cmp.Menu
|
||||
core.menu = menu.new({
|
||||
on_select = function(e)
|
||||
@@ -27,6 +38,43 @@ core.menu = menu.new({
|
||||
end,
|
||||
})
|
||||
|
||||
---Show ghost text if possible
|
||||
---@param e cmp.Entry
|
||||
core.ghost_text = function(e)
|
||||
if not e then
|
||||
return
|
||||
end
|
||||
|
||||
local ctx = context.new()
|
||||
if ctx.cursor_after_line ~= '' then
|
||||
return
|
||||
end
|
||||
|
||||
local diff = ctx.cursor.col - e:get_offset()
|
||||
local text = e:get_insert_text()
|
||||
if e.completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet then
|
||||
text = vim.lsp.util.parse_snippet(text)
|
||||
end
|
||||
text = string.sub(str.oneline(text), diff + 1)
|
||||
if #text > 0 then
|
||||
vim.api.nvim_buf_set_extmark(
|
||||
ctx.bufnr,
|
||||
core.GHOST_TEXT_NS,
|
||||
ctx.cursor.row - 1,
|
||||
ctx.cursor.col - 1,
|
||||
{
|
||||
right_gravity = true,
|
||||
virt_text = { { text, 'Comment' } },
|
||||
virt_text_pos = 'overlay',
|
||||
virt_text_win_col = ctx.cursor.col - 1,
|
||||
hl_mode = 'blend',
|
||||
priority = 0,
|
||||
ephemeral = true,
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
---@type table<number, cmp.Source>
|
||||
core.sources = {}
|
||||
|
||||
|
||||
@@ -193,58 +193,39 @@ end
|
||||
---Geta current active entry
|
||||
---@return cmp.Entry|nil
|
||||
menu.get_active_entry = function(self)
|
||||
local completed_item = vim.v.completed_item or {}
|
||||
if vim.fn.pumvisible() == 0 or not completed_item.user_data then
|
||||
if vim.fn.pumvisible() == 0 or not (vim.v.completed_item or {}).user_data then
|
||||
return nil
|
||||
end
|
||||
|
||||
local id = completed_item.user_data.cmp
|
||||
if id then
|
||||
return self.entry_map[id]
|
||||
end
|
||||
return nil
|
||||
return self:get_selected_entry()
|
||||
end
|
||||
|
||||
---Get current selected entry
|
||||
---@return cmp.Entry|nil
|
||||
menu.get_selected_entry = function(self)
|
||||
local e = self:get_active_entry()
|
||||
if e then
|
||||
return e
|
||||
if not self:is_valid_mode() then
|
||||
return nil
|
||||
end
|
||||
|
||||
local selected = vim.fn.complete_info({ 'selected' }).selected
|
||||
if selected == -1 then
|
||||
return nil
|
||||
end
|
||||
local items = vim.fn.complete_info({ 'items' }).items
|
||||
|
||||
local completed_item = items[math.max(selected, 0) + 1] or {}
|
||||
if not completed_item.user_data then
|
||||
return nil
|
||||
end
|
||||
|
||||
local id = completed_item.user_data.cmp
|
||||
if id then
|
||||
return self.entry_map[id]
|
||||
end
|
||||
return nil
|
||||
return self.entries[math.max(selected, 0) + 1]
|
||||
end
|
||||
|
||||
---Get first entry
|
||||
---@param self cmp.Entry|nil
|
||||
menu.get_first_entry = function(self)
|
||||
local info = vim.fn.complete_info({ 'items' })
|
||||
local completed_item = info.items[1] or {}
|
||||
if not completed_item.user_data then
|
||||
if not self:is_valid_mode() then
|
||||
return nil
|
||||
end
|
||||
return self.entries[1]
|
||||
end
|
||||
|
||||
local id = completed_item.user_data.cmp
|
||||
if id then
|
||||
return self.entry_map[id]
|
||||
end
|
||||
return nil
|
||||
---Return the completion menu is visible or not.
|
||||
---@return boolean
|
||||
menu.is_valid_mode = function()
|
||||
return vim.fn.complete_info({ 'mode' }).mode == 'eval'
|
||||
end
|
||||
|
||||
return menu
|
||||
|
||||
@@ -57,6 +57,7 @@ cmp.PreselectMode.None = 'none'
|
||||
---@field public event cmp.EventConfig
|
||||
---@field public mapping table<string, fun(core: cmp.Core, fallback: function)>
|
||||
---@field public sources cmp.SourceConfig[]
|
||||
---@field public experimental cmp.ExperimentalConfig
|
||||
|
||||
---@class cmp.CompletionConfig
|
||||
---@field public autocomplete cmp.TriggerEvent[]
|
||||
@@ -88,6 +89,9 @@ cmp.PreselectMode.None = 'none'
|
||||
---@class cmp.EventConfig
|
||||
---@field on_confirm_done function(e: cmp.Entry)
|
||||
|
||||
---@class cmp.ExperimentalConfig
|
||||
---@field public ghost_text boolean
|
||||
|
||||
---@class cmp.SourceConfig
|
||||
---@field public name string
|
||||
---@field public opts table
|
||||
|
||||
Reference in New Issue
Block a user