From 6f6286e4f90da25a7d1b6bcc96b79b0ccbaf5c26 Mon Sep 17 00:00:00 2001 From: L3MON4D3 <41961280+L3MON4D3@users.noreply.github.com> Date: Wed, 29 Jun 2022 18:53:49 +0200 Subject: 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 :) --- runtime/lua/vim/lsp/_snippet.lua | 57 +++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) (limited to 'runtime/lua/vim/lsp/_snippet.lua') 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 ) -- cgit