This commit is contained in:
hrsh7th
2021-08-10 21:41:34 +09:00
parent 22ec3ad442
commit 59a6ee577a
6 changed files with 141 additions and 34 deletions

View File

@@ -153,8 +153,7 @@ end
---Invoke completion ---Invoke completion
---@param ctx cmp.Context ---@param ctx cmp.Context
core.complete = function(ctx) core.complete = function(ctx)
for _, s in ipairs(core.get_sources()) do local callback = vim.schedule_wrap(function()
s:complete(ctx, function()
local new = context.new(ctx) local new = context.new(ctx)
if new:changed(new.prev_context) then if new:changed(new.prev_context) then
core.complete(new) core.complete(new)
@@ -163,6 +162,8 @@ core.complete = function(ctx)
core.filter() core.filter()
end end
end) end)
for _, s in ipairs(core.get_sources()) do
s:complete(ctx, callback)
end end
core.filter.timeout = ctx.pumvisible and 50 or 0 core.filter.timeout = ctx.pumvisible and 50 or 0

View File

@@ -7,7 +7,8 @@ describe('entry', function()
it('one char', function() it('one char', function()
local state = spec.state('@.', 1, 3) local state = spec.state('@.', 1, 3)
local e = entry.new(state.press('@'), state.source(), { state.input('@')
local e = entry.new(state.manual(), state.source(), {
label = '@', label = '@',
}) })
assert.are.equal(e:get_offset(), 3) assert.are.equal(e:get_offset(), 3)
@@ -16,7 +17,8 @@ describe('entry', function()
it('word length (no fix)', function() it('word length (no fix)', function()
local state = spec.state('a.b', 1, 4) local state = spec.state('a.b', 1, 4)
local e = entry.new(state.press('.'), state.source(), { state.input('.')
local e = entry.new(state.manual(), state.source(), {
label = 'b', label = 'b',
}) })
assert.are.equal(e:get_offset(), 5) assert.are.equal(e:get_offset(), 5)
@@ -25,7 +27,8 @@ describe('entry', function()
it('word length (fix)', function() it('word length (fix)', function()
local state = spec.state('a.b', 1, 4) local state = spec.state('a.b', 1, 4)
local e = entry.new(state.press('.'), state.source(), { state.input('.')
local e = entry.new(state.manual(), state.source(), {
label = 'b.', label = 'b.',
}) })
assert.are.equal(e:get_offset(), 3) assert.are.equal(e:get_offset(), 3)
@@ -34,7 +37,8 @@ describe('entry', function()
it('semantic index (no fix)', function() it('semantic index (no fix)', function()
local state = spec.state('a.bc', 1, 5) local state = spec.state('a.bc', 1, 5)
local e = entry.new(state.press('.'), state.source(), { state.input('.')
local e = entry.new(state.manual(), state.source(), {
label = 'c.', label = 'c.',
}) })
assert.are.equal(e:get_offset(), 6) assert.are.equal(e:get_offset(), 6)
@@ -43,7 +47,8 @@ describe('entry', function()
it('semantic index (fix)', function() it('semantic index (fix)', function()
local state = spec.state('a.bc', 1, 5) local state = spec.state('a.bc', 1, 5)
local e = entry.new(state.press('.'), state.source(), { state.input('.')
local e = entry.new(state.manual(), state.source(), {
label = 'bc.', label = 'bc.',
}) })
assert.are.equal(e:get_offset(), 3) assert.are.equal(e:get_offset(), 3)
@@ -52,7 +57,8 @@ describe('entry', function()
it('[vscode-html-language-server] 1', function() it('[vscode-html-language-server] 1', function()
local state = spec.state(' </>', 1, 7) local state = spec.state(' </>', 1, 7)
local e = entry.new(state.press('.'), state.source(), { state.input('.')
local e = entry.new(state.manual(), state.source(), {
label = '/div', label = '/div',
textEdit = { textEdit = {
range = { range = {
@@ -76,7 +82,8 @@ describe('entry', function()
--NOTE: clangd does not return `.foo` as filterText but we should care about it. --NOTE: clangd does not return `.foo` as filterText but we should care about it.
--nvim-cmp does care it by special handling in entry.lua. --nvim-cmp does care it by special handling in entry.lua.
local state = spec.state('foo', 1, 4) local state = spec.state('foo', 1, 4)
local e = entry.new(state.press('.'), state.source(), { state.input('.')
local e = entry.new(state.manual(), state.source(), {
insertText = '->foo', insertText = '->foo',
label = ' foo', label = ' foo',
textEdit = { textEdit = {
@@ -99,7 +106,8 @@ describe('entry', function()
it('[typescript-language-server] 1', function() it('[typescript-language-server] 1', function()
local state = spec.state('Promise.resolve()', 1, 18) local state = spec.state('Promise.resolve()', 1, 18)
local e = entry.new(state.press('.'), state.source(), { state.input('.')
local e = entry.new(state.manual(), state.source(), {
label = 'catch', label = 'catch',
}) })
-- The offset will be 18 in this situation because the server returns `[Symbol]` as candidate. -- The offset will be 18 in this situation because the server returns `[Symbol]` as candidate.
@@ -109,7 +117,8 @@ describe('entry', function()
it('[typescript-language-server] 2', function() it('[typescript-language-server] 2', function()
local state = spec.state('Promise.resolve()', 1, 18) local state = spec.state('Promise.resolve()', 1, 18)
local e = entry.new(state.press('.'), state.source(), { state.input('.')
local e = entry.new(state.manual(), state.source(), {
filterText = '.Symbol', filterText = '.Symbol',
label = 'Symbol', label = 'Symbol',
textEdit = { textEdit = {
@@ -135,7 +144,8 @@ describe('entry', function()
local e local e
-- press g -- press g
e = entry.new(state.press('g'), state.source(), { state.input('g')
e = entry.new(state.manual(), state.source(), {
insertTextFormat = 2, insertTextFormat = 2,
label = 'cmp.config', label = 'cmp.config',
textEdit = { textEdit = {
@@ -156,7 +166,8 @@ describe('entry', function()
assert.are.equal(e:get_filter_text(), 'cmp.config') assert.are.equal(e:get_filter_text(), 'cmp.config')
-- press ' -- press '
e = entry.new(state.press("'"), state.source(), { state.input("'")
e = entry.new(state.manual(), state.source(), {
insertTextFormat = 2, insertTextFormat = 2,
label = 'cmp.config', label = 'cmp.config',
textEdit = { textEdit = {
@@ -182,7 +193,8 @@ describe('entry', function()
local e local e
-- press g -- press g
e = entry.new(state.press('g'), state.source(), { state.input('g')
e = entry.new(state.manual(), state.source(), {
insertTextFormat = 2, insertTextFormat = 2,
label = 'lua.cmp.config', label = 'lua.cmp.config',
textEdit = { textEdit = {
@@ -203,7 +215,8 @@ describe('entry', function()
assert.are.equal(e:get_filter_text(), 'lua.cmp.config') assert.are.equal(e:get_filter_text(), 'lua.cmp.config')
-- press ' -- press '
e = entry.new(state.press("'"), state.source(), { state.input("'")
e = entry.new(state.manual(), state.source(), {
insertTextFormat = 2, insertTextFormat = 2,
label = 'lua.cmp.config', label = 'lua.cmp.config',
textEdit = { textEdit = {
@@ -228,7 +241,8 @@ describe('entry', function()
local state = spec.state('\t\t', 1, 4) local state = spec.state('\t\t', 1, 4)
-- press g -- press g
local e = entry.new(state.press('$'), state.source(), { state.input('$')
local e = entry.new(state.manual(), state.source(), {
detail = '\\Nico_URLConf', detail = '\\Nico_URLConf',
kind = 6, kind = 6,
label = '$this', label = '$this',

View File

@@ -261,7 +261,7 @@ source.complete = function(self, ctx, callback)
option = self:get_option(), option = self:get_option(),
completion_context = completion_context, completion_context = completion_context,
}, },
vim.schedule_wrap(self.complete_dedup(function(response) self.complete_dedup(function(response)
self.revision = self.revision + 1 self.revision = self.revision + 1
if #(misc.safe(response) and response.items or response or {}) > 0 then if #(misc.safe(response) and response.items or response or {}) > 0 then
debug.log('retrieve', self.name, self.id, #(response.items or response)) debug.log('retrieve', self.name, self.id, #(response.items or response))
@@ -279,7 +279,7 @@ source.complete = function(self, ctx, callback)
self.status = prev_status self.status = prev_status
end end
callback() callback()
end)) end)
) )
return true return true
end end

View File

@@ -1,11 +1,94 @@
local config = require('cmp.config')
local spec = require('cmp.utils.spec') local spec = require('cmp.utils.spec')
-- local source = require "cmp.source" local source = require('cmp.source')
describe('source', function() describe('source', function()
before_each(spec.before) before_each(spec.before)
it('new', function() describe('keyword length', function()
-- local s = source.new() it('not enough', function()
config.set_buffer({
completion = {
keyword_length = 3,
},
}, vim.api.nvim_get_current_buf())
local state = spec.state('', 1, 1)
local s = source.new('spec', {
complete = function(_, _, callback)
callback({ { label = 'spec' } })
end,
})
assert.is.truthy(not s:complete(state.input('a'), function() end))
end)
it('enough', function()
config.set_buffer({
completion = {
keyword_length = 3,
},
}, vim.api.nvim_get_current_buf())
local state = spec.state('', 1, 1)
local s = source.new('spec', {
complete = function(_, _, callback)
callback({ { label = 'spec' } })
end,
})
assert.is.truthy(s:complete(state.input('aiu'), function() end))
end)
it('enough -> not enough', function()
config.set_buffer({
completion = {
keyword_length = 3,
},
}, vim.api.nvim_get_current_buf())
local state = spec.state('', 1, 1)
local s = source.new('spec', {
complete = function(_, _, callback)
callback({ { label = 'spec' } })
end,
})
assert.is.truthy(s:complete(state.input('aiu'), function() end))
assert.is.truthy(not s:complete(state.backspace(), function() end))
end)
it('continue', function()
config.set_buffer({
completion = {
keyword_length = 3,
},
}, vim.api.nvim_get_current_buf())
local state = spec.state('', 1, 1)
local s = source.new('spec', {
complete = function(_, _, callback)
callback({ { label = 'spec' } })
end,
})
assert.is.truthy(s:complete(state.input('aiu'), function() end))
assert.is.truthy(not s:complete(state.input('eo'), function() end))
end)
end)
describe('isIncomplete', function()
it('isIncomplete=true', function()
local state = spec.state('', 1, 1)
local s = source.new('spec', {
complete = function(_, _, callback)
callback({
items = { { label = 'spec' } },
isIncomplete = true,
})
end,
})
assert.is.truthy(s:complete(state.input('s'), function() end))
assert.is.truthy(s:complete(state.input('p'), function() end))
assert.is.truthy(s:complete(state.input('e'), function() end))
assert.is.truthy(s:complete(state.input('c'), function() end))
end)
end) end)
end) end)

View File

@@ -64,11 +64,8 @@ __call = function(self, keys, mode, callback)
self.callbacks[id] = nil self.callbacks[id] = nil
vim.api.nvim_buf_del_keymap(0, current_mode, cb) vim.api.nvim_buf_del_keymap(0, current_mode, cb)
callback() callback()
if ctrl_r then
return '' return ''
end end
return keymap.t('<Ignore>')
end
local rhs = ctrl_r and '<C-r>=v:lua.cmp.utils.keymap.feedkeys.run(%s)<CR>' or ':<C-u>v:lua.cmp.utils.keymap.feedkeys.run(%s)<CR>' local rhs = ctrl_r and '<C-r>=v:lua.cmp.utils.keymap.feedkeys.run(%s)<CR>' or ':<C-u>v:lua.cmp.utils.keymap.feedkeys.run(%s)<CR>'
vim.api.nvim_buf_set_keymap(0, current_mode, cb, string.format(rhs, id), { vim.api.nvim_buf_set_keymap(0, current_mode, cb, string.format(rhs, id), {

View File

@@ -27,10 +27,22 @@ spec.state = function(text, row, col)
source = function() source = function()
return s return s
end, end,
press = function(char) backspace = function()
vim.fn.feedkeys('x', 'nx')
vim.fn.feedkeys('h', 'nx')
ctx = context.new(ctx, { reason = types.cmp.ContextReason.Auto })
s:complete(ctx, function() end)
return ctx
end,
input = function(char)
vim.fn.feedkeys(('i%s'):format(char), 'nx') vim.fn.feedkeys(('i%s'):format(char), 'nx')
vim.fn.feedkeys(('l'):format(char), 'nx') vim.fn.feedkeys(string.rep('l', #char), 'nx')
ctx.prev_context = nil ctx.prev_context = nil
ctx = context.new(ctx, { reason = types.cmp.ContextReason.Auto })
s:complete(ctx, function() end)
return ctx
end,
manual = function()
ctx = context.new(ctx, { reason = types.cmp.ContextReason.Manual }) ctx = context.new(ctx, { reason = types.cmp.ContextReason.Manual })
s:complete(ctx, function() end) s:complete(ctx, function() end)
return ctx return ctx