fix(lsp): correctly parse LSP snippets #15579

Fixes #15522
This commit is contained in:
hrsh7th
2021-09-14 20:31:41 +09:00
committed by Justin M. Keyes
parent 5a813160ae
commit 64dc7a1b55
4 changed files with 565 additions and 6 deletions

View File

@@ -0,0 +1,152 @@
local helpers = require('test.functional.helpers')(after_each)
local snippet = require('vim.lsp._snippet')
local eq = helpers.eq
local exec_lua = helpers.exec_lua
describe('vim.lsp._snippet', function()
before_each(helpers.clear)
after_each(helpers.clear)
local parse = function(...)
return exec_lua('return require("vim.lsp._snippet").parse(...)', ...)
end
it('should parse only text', function()
eq({
type = snippet.NodeType.SNIPPET,
children = {
{
type = snippet.NodeType.TEXT,
raw = 'TE\\$\\}XT',
esc = 'TE$}XT'
}
}
}, parse('TE\\$\\}XT'))
end)
it('should parse tabstop', function()
eq({
type = snippet.NodeType.SNIPPET,
children = {
{
type = snippet.NodeType.TABSTOP,
tabstop = 1,
},
{
type = snippet.NodeType.TABSTOP,
tabstop = 2,
}
}
}, parse('$1${2}'))
end)
it('should parse placeholders', function()
eq({
type = snippet.NodeType.SNIPPET,
children = {
{
type = snippet.NodeType.PLACEHOLDER,
tabstop = 1,
children = {
{
type = snippet.NodeType.PLACEHOLDER,
tabstop = 2,
children = {
{
type = snippet.NodeType.TEXT,
raw = 'TE\\$\\}XT',
esc = 'TE$}XT'
},
{
type = snippet.NodeType.TABSTOP,
tabstop = 3,
},
{
type = snippet.NodeType.TABSTOP,
tabstop = 1,
transform = {
type = snippet.NodeType.TRANSFORM,
pattern = 'regex',
option = 'i',
format = {
{
type = snippet.NodeType.FORMAT,
capture_index = 1,
modifier = 'upcase'
}
}
},
},
{
type = snippet.NodeType.TEXT,
raw = 'TE\\$\\}XT',
esc = 'TE$}XT'
},
}
}
}
},
}
}, parse('${1:${2:TE\\$\\}XT$3${1/regex/${1:/upcase}/i}TE\\$\\}XT}}'))
end)
it('should parse variables', function()
eq({
type = snippet.NodeType.SNIPPET,
children = {
{
type = snippet.NodeType.VARIABLE,
name = 'VAR',
},
{
type = snippet.NodeType.VARIABLE,
name = 'VAR',
},
{
type = snippet.NodeType.VARIABLE,
name = 'VAR',
children = {
{
type = snippet.NodeType.TABSTOP,
tabstop = 1,
}
}
},
{
type = snippet.NodeType.VARIABLE,
name = 'VAR',
transform = {
type = snippet.NodeType.TRANSFORM,
pattern = 'regex',
format = {
{
type = snippet.NodeType.FORMAT,
capture_index = 1,
modifier = 'upcase',
}
}
}
},
}
}, parse('$VAR${VAR}${VAR:$1}${VAR/regex/${1:/upcase}/}'))
end)
it('should parse choice', function()
eq({
type = snippet.NodeType.SNIPPET,
children = {
{
type = snippet.NodeType.CHOICE,
tabstop = 1,
items = {
',',
'|'
}
}
}
}, parse('${1|\\,,\\||}'))
end)
end)

View File

@@ -1441,8 +1441,10 @@ describe('LSP', function()
{ label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', insertTextFormat=2, textEdit={} },
-- nested snippet tokens
{ label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} },
-- braced tabstop
{ label='foocar', sortText="j", insertText='foodar()${0}', insertTextFormat=2, textEdit={} },
-- plain text
{ label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} },
{ label='foocar', sortText="k", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} },
}
local completion_list_items = {items=completion_list}
local expected = {
@@ -1454,8 +1456,9 @@ describe('LSP', function()
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="f", textEdit={newText='foobar'} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="g", insertText='foodar', insertTextFormat=2, textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', insertTextFormat=2, textEdit={} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar()', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="j", insertText='foodar()${0}', insertTextFormat=2, textEdit={} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="k", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } },
}
eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix))