From 59a6ee577a9eb56d43e84ed4778c140115052cc6 Mon Sep 17 00:00:00 2001 From: hrsh7th Date: Tue, 10 Aug 2021 21:41:34 +0900 Subject: [PATCH] Add test --- lua/cmp/core.lua | 19 +++++---- lua/cmp/entry_spec.lua | 42 ++++++++++++------- lua/cmp/source.lua | 4 +- lua/cmp/source_spec.lua | 89 ++++++++++++++++++++++++++++++++++++++-- lua/cmp/utils/keymap.lua | 5 +-- lua/cmp/utils/spec.lua | 16 +++++++- 6 files changed, 141 insertions(+), 34 deletions(-) diff --git a/lua/cmp/core.lua b/lua/cmp/core.lua index d1900a6..f4e8208 100644 --- a/lua/cmp/core.lua +++ b/lua/cmp/core.lua @@ -153,16 +153,17 @@ end ---Invoke completion ---@param ctx cmp.Context core.complete = function(ctx) + local callback = vim.schedule_wrap(function() + local new = context.new(ctx) + if new:changed(new.prev_context) then + core.complete(new) + else + core.filter.timeout = 50 + core.filter() + end + end) for _, s in ipairs(core.get_sources()) do - s:complete(ctx, function() - local new = context.new(ctx) - if new:changed(new.prev_context) then - core.complete(new) - else - core.filter.timeout = 50 - core.filter() - end - end) + s:complete(ctx, callback) end core.filter.timeout = ctx.pumvisible and 50 or 0 diff --git a/lua/cmp/entry_spec.lua b/lua/cmp/entry_spec.lua index 01e8d5f..f3db891 100644 --- a/lua/cmp/entry_spec.lua +++ b/lua/cmp/entry_spec.lua @@ -7,7 +7,8 @@ describe('entry', function() it('one char', function() 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 = '@', }) assert.are.equal(e:get_offset(), 3) @@ -16,7 +17,8 @@ describe('entry', function() it('word length (no fix)', function() 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', }) assert.are.equal(e:get_offset(), 5) @@ -25,7 +27,8 @@ describe('entry', function() it('word length (fix)', function() 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.', }) assert.are.equal(e:get_offset(), 3) @@ -34,7 +37,8 @@ describe('entry', function() it('semantic index (no fix)', function() 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.', }) assert.are.equal(e:get_offset(), 6) @@ -43,7 +47,8 @@ describe('entry', function() it('semantic index (fix)', function() 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.', }) assert.are.equal(e:get_offset(), 3) @@ -52,7 +57,8 @@ describe('entry', function() it('[vscode-html-language-server] 1', function() 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', textEdit = { range = { @@ -76,7 +82,8 @@ describe('entry', function() --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. 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', label = ' foo', textEdit = { @@ -99,7 +106,8 @@ describe('entry', function() it('[typescript-language-server] 1', function() 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', }) -- 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() 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', label = 'Symbol', textEdit = { @@ -135,7 +144,8 @@ describe('entry', function() local e -- press g - e = entry.new(state.press('g'), state.source(), { + state.input('g') + e = entry.new(state.manual(), state.source(), { insertTextFormat = 2, label = 'cmp.config', textEdit = { @@ -156,7 +166,8 @@ describe('entry', function() assert.are.equal(e:get_filter_text(), 'cmp.config') -- press ' - e = entry.new(state.press("'"), state.source(), { + state.input("'") + e = entry.new(state.manual(), state.source(), { insertTextFormat = 2, label = 'cmp.config', textEdit = { @@ -182,7 +193,8 @@ describe('entry', function() local e -- press g - e = entry.new(state.press('g'), state.source(), { + state.input('g') + e = entry.new(state.manual(), state.source(), { insertTextFormat = 2, label = 'lua.cmp.config', textEdit = { @@ -203,7 +215,8 @@ describe('entry', function() assert.are.equal(e:get_filter_text(), 'lua.cmp.config') -- press ' - e = entry.new(state.press("'"), state.source(), { + state.input("'") + e = entry.new(state.manual(), state.source(), { insertTextFormat = 2, label = 'lua.cmp.config', textEdit = { @@ -228,7 +241,8 @@ describe('entry', function() local state = spec.state('\t\t', 1, 4) -- press g - local e = entry.new(state.press('$'), state.source(), { + state.input('$') + local e = entry.new(state.manual(), state.source(), { detail = '\\Nico_URLConf', kind = 6, label = '$this', diff --git a/lua/cmp/source.lua b/lua/cmp/source.lua index d57feb9..d06c259 100644 --- a/lua/cmp/source.lua +++ b/lua/cmp/source.lua @@ -261,7 +261,7 @@ source.complete = function(self, ctx, callback) option = self:get_option(), completion_context = completion_context, }, - vim.schedule_wrap(self.complete_dedup(function(response) + self.complete_dedup(function(response) self.revision = self.revision + 1 if #(misc.safe(response) and response.items or response or {}) > 0 then 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 end callback() - end)) + end) ) return true end diff --git a/lua/cmp/source_spec.lua b/lua/cmp/source_spec.lua index a9e28a5..ed86888 100644 --- a/lua/cmp/source_spec.lua +++ b/lua/cmp/source_spec.lua @@ -1,11 +1,94 @@ +local config = require('cmp.config') local spec = require('cmp.utils.spec') --- local source = require "cmp.source" +local source = require('cmp.source') describe('source', function() before_each(spec.before) - it('new', function() - -- local s = source.new() + describe('keyword length', function() + 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) diff --git a/lua/cmp/utils/keymap.lua b/lua/cmp/utils/keymap.lua index 05d1cc7..db00f59 100644 --- a/lua/cmp/utils/keymap.lua +++ b/lua/cmp/utils/keymap.lua @@ -64,10 +64,7 @@ __call = function(self, keys, mode, callback) self.callbacks[id] = nil vim.api.nvim_buf_del_keymap(0, current_mode, cb) callback() - if ctrl_r then - return '' - end - return keymap.t('') + return '' end local rhs = ctrl_r and '=v:lua.cmp.utils.keymap.feedkeys.run(%s)' or ':v:lua.cmp.utils.keymap.feedkeys.run(%s)' diff --git a/lua/cmp/utils/spec.lua b/lua/cmp/utils/spec.lua index 3a85e2a..ce86c3d 100644 --- a/lua/cmp/utils/spec.lua +++ b/lua/cmp/utils/spec.lua @@ -27,10 +27,22 @@ spec.state = function(text, row, col) source = function() return s 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(('l'):format(char), 'nx') + vim.fn.feedkeys(string.rep('l', #char), 'nx') 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 }) s:complete(ctx, function() end) return ctx