From c2652f0ac0983ca05614551bb0002f70179e262f Mon Sep 17 00:00:00 2001 From: hrsh7th Date: Thu, 2 Dec 2021 15:56:42 +0900 Subject: [PATCH] Implement #349 --- doc/cmp.txt | 47 ++++++++++++++------------ lua/cmp/config/mapping.lua | 2 +- lua/cmp/core.lua | 67 ++++++++++++++++++++++++++------------ lua/cmp/init.lua | 8 +++-- lua/cmp/types/cmp.lua | 4 +++ 5 files changed, 82 insertions(+), 46 deletions(-) diff --git a/doc/cmp.txt b/doc/cmp.txt index 9ae7a86..62bd07b 100644 --- a/doc/cmp.txt +++ b/doc/cmp.txt @@ -23,7 +23,8 @@ Abstract *cmp-abstract* This is nvim-cmp's document. -1. The `cmp` object that appears in this docs is the return value of `require('cmp')`. +1. This docs uses the type definition notation like `{lsp,cmp,vim}.*` + - You can find it `../lua/cmp/types/init.lua`. @@ -174,10 +175,22 @@ NOTE: You can call these functions in mapping via `require('cmp').complete( Scroll docs if it visible. *cmp.complete* (option: { reason = cmp.ContextReason }) - Invoke manual completion. + Invoke completion. -*cmp.confirm* (option: cmp.ConfirmOption) - Confirm current selected completion item. + The following configurations defines the key mapping to invoke only snippet completion. +> + cmp.setup { + mapping = { + [''] = cmp.mapping.complete({ sources = { { name = 'vsnip' } } }) + } + } +< > + inoremap require('cmp').complete({ sources = { { name = 'vsnip' } } }) +< +*cmp.confirm* (option: cmp.ConfirmOption, callback: function) + Accept current selected completion item. + If you didn't select any items and specified the `{ select = true }` for + this, nvim-cmp will automatically select the first item. *cmp.event:on* ('%EVENT_NAME%, callback) Subscribe nvim-cmp's events below. @@ -231,34 +244,26 @@ And you can specify the different mapping function for each modes. You can also use built-in mapping helpers. *cmp.mapping.close* () - Close the completion menu. + Same as |cmp.close| *cmp.mapping.abort* () - Closes the completion menu and restore the current line to the state when completion was started. + Same as |cmp.abort| *cmp.mapping.select_next_item* (option: { behavior = cmp.SelectBehavior }) - Select the next completion item. (NOTE: This function can be used with omni completion menu) + Same as |cmp.select_next_item| *cmp.mapping.select_prev_item* (option: { behavior = cmp.SelectBehavior }) - Select the prev completion item. (NOTE: This function can be used with omni completion menu) + Same as |cmp.select_prev_item| *cmp.mapping.scroll_docs* (delta: number) - Scroll the documentation window if it's visible. + Same as |cmp.scroll_docs| - *cmp.mapping.complete* (option: { reason = cmp.ContextReason }) - Invoke completion. + *cmp.mapping.complete* (option: cmp.CompleteParams) + Same as |cmp.complete| *cmp.mapping.confirm* (option: cmp.ConfirmOption) - Accept current selected completion item. - If you didn't select any items and specified the `{ select = true }`, - nvim-cmp will automatically select the first item. -> - cmp.setup { - mapping = { - [''] = cmp.mapping.confirm({ select = true }) - } - } -< + Same as |cmp.confirm| + The built-in mapping helper is only available as a configuration option. If you want to call the nvim-cmp features directly, please use |cmp-function| instead. diff --git a/lua/cmp/config/mapping.lua b/lua/cmp/config/mapping.lua index 2080e27..ec73ed3 100644 --- a/lua/cmp/config/mapping.lua +++ b/lua/cmp/config/mapping.lua @@ -13,7 +13,7 @@ mapping = setmetatable({}, { }) ---Invoke completion ----@param option cmp.ContextOption +---@param option cmp.CompleteParams mapping.complete = function(option) return function(fallback) if not require('cmp').complete(option) then diff --git a/lua/cmp/core.lua b/lua/cmp/core.lua index c886564..38957bb 100644 --- a/lua/cmp/core.lua +++ b/lua/cmp/core.lua @@ -14,13 +14,13 @@ local api = require('cmp.utils.api') local event = require('cmp.utils.event') local SOURCE_TIMEOUT = 500 -local THROTTLE_TIME = 100 +local THROTTLE_TIME = 120 ---@class cmp.Core ---@field public suspending boolean ---@field public view cmp.View ---@field public sources cmp.Source[] ----@field public sources_by_name table +---@field public source_configs cmp.SourceConfig[] ---@field public context cmp.Context ---@field public event cmp.Event local core = {} @@ -29,7 +29,7 @@ core.new = function() local self = setmetatable({}, { __index = core }) self.suspending = false self.sources = {} - self.sources_by_name = {} + self.source_configs = {} self.context = context.new() self.event = event.new() self.view = view.new() @@ -43,19 +43,11 @@ end ---@param s cmp.Source core.register_source = function(self, s) self.sources[s.id] = s - if not self.sources_by_name[s.name] then - self.sources_by_name[s.name] = {} - end - table.insert(self.sources_by_name[s.name], s) end ---Unregister source ---@param source_id string core.unregister_source = function(self, source_id) - local name = self.sources[source_id].name - self.sources_by_name[name] = vim.tbl_filter(function(s) - return s.id ~= source_id - end, self.sources_by_name[name]) self.sources[source_id] = nil end @@ -85,14 +77,24 @@ core.suspend = function(self) end ---Get sources that sorted by priority ----@param statuses cmp.SourceStatus[] +---@param filter cmp.SourceStatus[]|fun(s: cmp.Source): boolean ---@return cmp.Source[] -core.get_sources = function(self, statuses) +core.get_sources = function(self, filter) + local f = function(s) + if type(filter) == 'table' then + return vim.tbl_contains(filter, s.status) + elseif type(filter) == 'function' then + return filter(s) + end + return true + end + local sources = {} - for _, c in pairs(config.get().sources) do - for _, s in ipairs(self.sources_by_name[c.name] or {}) do - if not statuses or vim.tbl_contains(statuses, s.status) then - if s:is_available() then + local source_configs = #self.source_configs > 0 and self.source_configs or config.get().sources + for _, c in pairs(source_configs) do + for _, s in pairs(self.sources) do + if c.name == s.name then + if s:is_available() and f(s) then table.insert(sources, s) end end @@ -216,13 +218,18 @@ end ---Invoke completion ---@param ctx cmp.Context -core.complete = function(self, ctx) +---@param source_configs? cmp.SourceConfig[] +core.complete = function(self, ctx, source_configs) if not api.is_suitable_mode() then return end - self:set_context(ctx) - for _, s in ipairs(self:get_sources()) do + self:set_context(ctx) + self.source_configs = source_configs or self.source_configs + + -- Invoke completion sources. + local sources = self:get_sources() + for _, s in ipairs(sources) do local callback callback = (function(s_) return function() @@ -272,7 +279,25 @@ core.filter = async.throttle( end table.insert(sources, s) end - self.view:open(self:get_context(), sources) + + local ctx = self:get_context() + + -- Display completion results. + self.view:open(ctx, sources) + + -- Check specific source config. + if #self.source_configs > 0 then + if #self:get_sources(function(s) + if s.status == source.SourceStatus.FETCHING then + return true + elseif s.status == source.SourceStatus.COMPLETED and #s:get_entries(ctx) > 0 then + return true + end + return false + end) == 0 then + self.source_configs = {} + end + end end), THROTTLE_TIME ) diff --git a/lua/cmp/init.lua b/lua/cmp/init.lua index 03b9c8f..1796843 100644 --- a/lua/cmp/init.lua +++ b/lua/cmp/init.lua @@ -52,12 +52,14 @@ cmp.get_config = function() end ---Invoke completion manually ----@param option cmp.ContextOption +---@param option cmp.CompleteParams cmp.complete = function(option) option = option or {} - option.reason = option.reason or cmp.ContextReason.Manual - cmp.core:complete(cmp.core:get_context(option)) + cmp.core:complete( + cmp.core:get_context({ reason = option.reason or cmp.ContextReason.Manual }), + option.sources + ) return true end diff --git a/lua/cmp/types/cmp.lua b/lua/cmp/types/cmp.lua index 7625508..7d7ab7d 100644 --- a/lua/cmp/types/cmp.lua +++ b/lua/cmp/types/cmp.lua @@ -46,6 +46,10 @@ cmp.ItemField.Menu = 'menu' ---@field public body string ---@field public insert_text_mode number +---@class cmp.CompleteParams +---@field public reason? cmp.ContextReason +---@field public sources? cmp.SourceConfig[] + ---@class cmp.Setup ---@field public __call fun(c: cmp.ConfigSchema) ---@field public buffer fun(c: cmp.ConfigSchema)