@@ -176,6 +176,7 @@ P.seq = function(...)
176176end
177177
178178local Node = {}
179+ Node .__index = Node
179180
180181Node .Type = {
181182 SNIPPET = 0 ,
@@ -188,6 +189,18 @@ Node.Type = {
188189 TEXT = 7 ,
189190}
190191
192+ -- @see https://github.com/neovim/neovim/blob/9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c/runtime/lua/vim/snippet.lua#L59
193+
194+ --- Transforms the given text into an array of lines (so no line contains `\n`).
195+ ---
196+ --- @param text string | string[]
197+ --- @return string[]
198+ local function text_to_lines (text )
199+ text = type (text ) == ' string' and { text } or text
200+ --- @cast text string[]
201+ return vim .split (table.concat (text ), ' \n ' , { plain = true })
202+ end
203+
191204function Node :__tostring ()
192205 local insert_text = {}
193206 if self .type == Node .Type .SNIPPET then
@@ -206,6 +219,57 @@ function Node:__tostring()
206219 return table.concat (insert_text , ' ' )
207220end
208221
222+ -- @see https://github.com/neovim/neovim/blob/9afa1fd35510c5fe485f4a1dfdabf94e5f051a1c/runtime/lua/vim/snippet.lua#L477
223+ function Node :to_static_text ()
224+ local snippet_text = {}
225+ local base_indent = vim .api .nvim_get_current_line ():match (' ^%s*' ) or ' '
226+
227+ --- Appends the given text to the snippet, taking care of indentation.
228+ ---
229+ --- @param text string | string[]
230+ local function append_to_snippet (text )
231+ local snippet_lines = text_to_lines (snippet_text )
232+ -- Get the base indentation based on the current line and the last line of the snippet.
233+ if # snippet_lines > 0 then
234+ base_indent = base_indent .. (snippet_lines [# snippet_lines ]:match (' (^%s*)%S' ) or ' ' ) --- @type string
235+ end
236+
237+ local shiftwidth = vim .fn .shiftwidth ()
238+ local curbuf = vim .api .nvim_get_current_buf ()
239+ local expandtab = vim .bo [curbuf ].expandtab
240+
241+ local lines = {} --- @type string[]
242+ for i , line in ipairs (text_to_lines (text )) do
243+ -- Replace tabs by spaces.
244+ if expandtab then
245+ line = line :gsub (' \t ' , (' ' ):rep (shiftwidth )) --- @type string
246+ end
247+ -- Add the base indentation.
248+ if i > 1 then
249+ line = base_indent .. line
250+ end
251+ lines [# lines + 1 ] = line
252+ end
253+
254+ table.insert (snippet_text , table.concat (lines , ' \n ' ))
255+ end
256+
257+ for _ , c in ipairs (self .children ) do
258+ if c .type == Node .Type .PLACEHOLDER then
259+ for _ , ic in ipairs (c .children or {}) do
260+ if ic .type == Node .Type .TEXT then
261+ append_to_snippet (ic .esc )
262+ end
263+ end
264+ elseif c .type == Node .Type .TEXT then
265+ append_to_snippet (c .esc )
266+ end
267+ end
268+
269+ snippet_text = text_to_lines (snippet_text )
270+ return snippet_text
271+ end
272+
209273-- @see https://code.visualstudio.com/docs/editor/userdefinedsnippets#_grammar
210274
211275local S = {}
0 commit comments