diff options
author | L3MON4D3 <41961280+L3MON4D3@users.noreply.github.com> | 2022-06-29 18:53:49 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-29 09:53:49 -0700 |
commit | 6f6286e4f90da25a7d1b6bcc96b79b0ccbaf5c26 (patch) | |
tree | 4b7851722cd50277f4f87a8e04ef4fcbbc305a9d | |
parent | 1eb9624666a8478d66e693c7f00fc633a6b1b8ca (diff) | |
download | rneovim-6f6286e4f90da25a7d1b6bcc96b79b0ccbaf5c26.tar.gz rneovim-6f6286e4f90da25a7d1b6bcc96b79b0ccbaf5c26.tar.bz2 rneovim-6f6286e4f90da25a7d1b6bcc96b79b0ccbaf5c26.zip |
fix(lsp): small bugs in snippet-parser #18998
This fixes the following bugs:
`${1:else_text}` -> format with if_text: "else_text"
`${1:-else_text}` -> format with if_text: "else_text"
`${1:}` in `format` (eg. empty else_text) -> error.
`${1:}` (eg. empty placeholder) -> error.
Thanks hrsh7th :)
-rw-r--r-- | runtime/lua/vim/lsp/_snippet.lua | 57 | ||||
-rw-r--r-- | test/functional/plugin/lsp/snippet_spec.lua | 134 |
2 files changed, 154 insertions, 37 deletions
diff --git a/runtime/lua/vim/lsp/_snippet.lua b/runtime/lua/vim/lsp/_snippet.lua index 28064f36e9..910deba556 100644 --- a/runtime/lua/vim/lsp/_snippet.lua +++ b/runtime/lua/vim/lsp/_snippet.lua @@ -156,10 +156,10 @@ P.seq = function(...) return function(input, pos) local values = {} local new_pos = pos - for _, parser in ipairs(parsers) do + for i, parser in ipairs(parsers) do local result = parser(input, new_pos) if result.parsed then - table.insert(values, result.value) + values[i] = result.value new_pos = result.pos else return P.unmatch(pos) @@ -272,22 +272,48 @@ S.format = P.any( S.open, S.int, S.colon, - P.any( - P.seq(S.question, P.take_until({ ':' }, { '\\' }), S.colon, P.take_until({ '}' }, { '\\' })), - P.seq(S.plus, P.take_until({ '}' }, { '\\' })), - P.seq(S.minus, P.take_until({ '}' }, { '\\' })) - ), + P.seq(S.question, P.opt(P.take_until({ ':' }, { '\\' })), S.colon, P.opt(P.take_until({ '}' }, { '\\' }))), S.close ), function(values) return setmetatable({ type = Node.Type.FORMAT, capture_index = values[3], - if_text = values[5][2].esc, - else_text = (values[5][4] or {}).esc, + if_text = values[5][2] and values[5][2].esc or '', + else_text = values[5][4] and values[5][4].esc or '', }, Node) end - ) + ), + P.map( + P.seq(S.dollar, S.open, S.int, S.colon, P.seq(S.plus, P.opt(P.take_until({ '}' }, { '\\' }))), S.close), + function(values) + return setmetatable({ + type = Node.Type.FORMAT, + capture_index = values[3], + if_text = values[5][2] and values[5][2].esc or '', + else_text = '', + }, Node) + end + ), + P.map( + P.seq(S.dollar, S.open, S.int, S.colon, S.minus, P.opt(P.take_until({ '}' }, { '\\' })), S.close), + function(values) + return setmetatable({ + type = Node.Type.FORMAT, + capture_index = values[3], + if_text = '', + else_text = values[6] and values[6].esc or '', + }, Node) + end + ), + P.map(P.seq(S.dollar, S.open, S.int, S.colon, P.opt(P.take_until({ '}' }, { '\\' })), S.close), function(values) + return setmetatable({ + type = Node.Type.FORMAT, + capture_index = values[3], + if_text = '', + else_text = values[5] and values[5].esc or '', + }, Node) + end) ) S.transform = P.map( @@ -333,12 +359,19 @@ S.tabstop = P.any( S.placeholder = P.any( P.map( - P.seq(S.dollar, S.open, S.int, S.colon, P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), S.close), + P.seq(S.dollar, S.open, S.int, S.colon, P.opt(P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' })))), S.close), function(values) return setmetatable({ type = Node.Type.PLACEHOLDER, tabstop = values[3], - children = values[5], + -- insert empty text if opt did not match. + children = values[5] or { + setmetatable({ + type = Node.Type.TEXT, + raw = '', + esc = '', + }, Node), + }, }, Node) end ) diff --git a/test/functional/plugin/lsp/snippet_spec.lua b/test/functional/plugin/lsp/snippet_spec.lua index 4e127743eb..7903885420 100644 --- a/test/functional/plugin/lsp/snippet_spec.lua +++ b/test/functional/plugin/lsp/snippet_spec.lua @@ -19,9 +19,9 @@ describe('vim.lsp._snippet', function() { type = snippet.NodeType.TEXT, raw = 'TE\\$\\}XT', - esc = 'TE$}XT' - } - } + esc = 'TE$}XT', + }, + }, }, parse('TE\\$\\}XT')) end) @@ -36,8 +36,8 @@ describe('vim.lsp._snippet', function() { type = snippet.NodeType.TABSTOP, tabstop = 2, - } - } + }, + }, }, parse('$1${2}')) end) @@ -56,7 +56,7 @@ describe('vim.lsp._snippet', function() { type = snippet.NodeType.TEXT, raw = 'TE\\$\\}XT', - esc = 'TE$}XT' + esc = 'TE$}XT', }, { type = snippet.NodeType.TABSTOP, @@ -73,21 +73,21 @@ describe('vim.lsp._snippet', function() { type = snippet.NodeType.FORMAT, capture_index = 1, - modifier = 'upcase' - } - } + modifier = 'upcase', + }, + }, }, }, { type = snippet.NodeType.TEXT, raw = 'TE\\$\\}XT', - esc = 'TE$}XT' + esc = 'TE$}XT', }, - } - } - } + }, + }, + }, }, - } + }, }, parse('${1:${2:TE\\$\\}XT$3${1/regex/${1:/upcase}/i}TE\\$\\}XT}}')) end) @@ -110,8 +110,8 @@ describe('vim.lsp._snippet', function() { type = snippet.NodeType.TABSTOP, tabstop = 1, - } - } + }, + }, }, { type = snippet.NodeType.VARIABLE, @@ -124,11 +124,11 @@ describe('vim.lsp._snippet', function() type = snippet.NodeType.FORMAT, capture_index = 1, modifier = 'upcase', - } - } - } + }, + }, + }, }, - } + }, }, parse('$VAR${VAR}${VAR:$1}${VAR/regex/${1:/upcase}/}')) end) @@ -141,12 +141,96 @@ describe('vim.lsp._snippet', function() tabstop = 1, items = { ',', - '|' - } - } - } + '|', + }, + }, + }, }, parse('${1|\\,,\\||}')) end) -end) + it('should parse format', function() + eq({ + type = snippet.NodeType.SNIPPET, + children = { + { + type = snippet.NodeType.VARIABLE, + name = 'VAR', + transform = { + type = snippet.NodeType.TRANSFORM, + pattern = 'regex', + format = { + { + type = snippet.NodeType.FORMAT, + capture_index = 1, + modifier = 'upcase', + }, + { + type = snippet.NodeType.FORMAT, + capture_index = 1, + if_text = 'if_text', + else_text = '', + }, + { + type = snippet.NodeType.FORMAT, + capture_index = 1, + if_text = '', + else_text = 'else_text', + }, + { + type = snippet.NodeType.FORMAT, + capture_index = 1, + else_text = 'else_text', + if_text = 'if_text', + }, + { + type = snippet.NodeType.FORMAT, + capture_index = 1, + if_text = '', + else_text = 'else_text', + }, + }, + }, + }, + }, + }, parse('${VAR/regex/${1:/upcase}${1:+if_text}${1:-else_text}${1:?if_text:else_text}${1:else_text}/}')) + end) + it('should parse empty strings', function() + eq({ + children = { + { + children = { { + esc = '', + raw = '', + type = 7, + } }, + tabstop = 1, + type = 2, + }, + { + esc = ' ', + raw = ' ', + type = 7, + }, + { + name = 'VAR', + transform = { + format = { + { + capture_index = 1, + else_text = '', + if_text = '', + type = 6, + }, + }, + option = 'g', + pattern = 'erg', + type = 5, + }, + type = 3, + }, + }, + type = 0, + }, parse('${1:} ${VAR/erg/${1:?:}/g}')) + end) +end) |