11local luasnip_ns_id = require (" luasnip.session" ).ns_id
22local ls = require (" luasnip" )
3+ local session = ls .session
4+ local log = require (" luasnip.util.log" ).new (" lsp" )
5+ local util = require (" luasnip.util.util" )
36
47local M = {}
58
9+ -- copied from init.lua, maybe find some better way to get it.
10+ local function _jump_into_default (snippet )
11+ local current_buf = vim .api .nvim_get_current_buf ()
12+ if session .current_nodes [current_buf ] then
13+ local current_node = session .current_nodes [current_buf ]
14+ if current_node .pos > 0 then
15+ -- snippet is nested, notify current insertNode about expansion.
16+ current_node .inner_active = true
17+ else
18+ -- snippet was expanded behind a previously active one, leave the i(0)
19+ -- properly (and remove the snippet on error).
20+ local ok , err = pcall (current_node .input_leave , current_node )
21+ if not ok then
22+ log .warn (" Error while leaving snippet: " , err )
23+ current_node .parent .snippet :remove_from_jumplist ()
24+ end
25+ end
26+ end
27+
28+ return util .no_region_check_wrap (snippet .jump_into , snippet , 1 )
29+ end
30+
631--- Apply text/snippetTextEdits (at most one snippetText though).
732--- @param snippet_or_text_edits ` (snippetTextEdit | textEdit )[] `
833--- snippetTextEdit as defined in https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#snippet-textedit)
@@ -13,28 +38,27 @@ local M = {}
1338function M .apply_text_edits (snippet_or_text_edits , bufnr , offset_encoding , apply_text_edits_fn )
1439 -- plain textEdits, applied using via `apply_text_edits_fn`.
1540 local text_edits = {}
16- -- contains keys
41+
42+ -- list of snippet-parameters. These contain keys
1743 -- - snippet (parsed snippet)
1844 -- - mark (extmark, textrange replaced by the snippet)
19- local snippet_params
45+ local all_snippet_params = {}
2046
2147 for _ , v in ipairs (snippet_or_text_edits ) do
2248 if v .newText and v .insertTextFormat == 2 then
23- assert (snippet_params == nil , " Only one snippetTextEdit may be applied at once." )
24-
2549 -- from vim.lsp.apply_text_edits.
2650 local start_row = v .range .start .line
2751 local start_col = vim .lsp .util ._get_line_byte_from_position (bufnr , v .range .start , offset_encoding )
2852 local end_row = v .range [' end' ].line
2953 local end_col = vim .lsp .util ._get_line_byte_from_position (bufnr , v .range [' end' ], offset_encoding )
3054
31- snippet_params = {
55+ table.insert ( all_snippet_params , {
3256 snippet_body = v .newText ,
3357 mark = vim .api .nvim_buf_set_extmark (bufnr , luasnip_ns_id , start_row , start_col , {
3458 end_row = end_row ,
3559 end_col = end_col
3660 }),
37- }
61+ })
3862 else
3963 table.insert (text_edits , v )
4064 end
@@ -43,21 +67,63 @@ function M.apply_text_edits(snippet_or_text_edits, bufnr, offset_encoding, apply
4367 -- first apply regular textEdits...
4468 apply_text_edits_fn (text_edits , bufnr , offset_encoding )
4569
46- -- ...then the snippet.
47- local mark_info = vim .api .nvim_buf_get_extmark_by_id (bufnr , luasnip_ns_id , snippet_params .mark , {details = true })
48- local mark_begin_pos = {mark_info [1 ], mark_info [2 ]}
49- local mark_end_pos = {mark_info [3 ].end_row , mark_info [3 ].end_col }
50-
51- -- luasnip can only expand snippets in the active buffer, so switch (nop if
52- -- buf already active).
53- vim .api .nvim_set_current_buf (bufnr )
54- ls .lsp_expand (snippet_params .snippet_body , {
55- pos = mark_begin_pos ,
56- clear_region = {
57- from = mark_begin_pos ,
58- to = mark_end_pos ,
59- },
60- })
70+ -- ...then the snippetTextEdits.
71+
72+ -- store expanded snippets, if there are multiple we need to properly chain them together.
73+ local expanded_snippets = {}
74+ for i , snippet_params in ipairs (all_snippet_params ) do
75+ local mark_info = vim .api .nvim_buf_get_extmark_by_id (bufnr , luasnip_ns_id , snippet_params .mark , {details = true })
76+ local mark_begin_pos = {mark_info [1 ], mark_info [2 ]}
77+ local mark_end_pos = {mark_info [3 ].end_row , mark_info [3 ].end_col }
78+
79+ -- luasnip can only expand snippets in the active buffer, so switch (nop if
80+ -- buf already active).
81+ vim .api .nvim_set_current_buf (bufnr )
82+
83+ -- use expand_opts to chain snippets behind each other and store the
84+ -- expanded snippets.
85+ -- With the regular expand_opts, we will immediately jump into the
86+ -- first snippet, if it contains an i(1), the following snippets will
87+ -- belong inside it, which we don't want here: we want the i(0) of a
88+ -- snippet to lead to the next (also skipping the i(-1)).
89+ -- Even worse: by default, we would jump into the snippets during
90+ -- snip_expand, which should only happen for the first, the later
91+ -- snippets should be reached by jumping through the previous ones.
92+ local expand_opts = {
93+ pos = mark_begin_pos ,
94+ clear_region = {
95+ from = mark_begin_pos ,
96+ to = mark_end_pos ,
97+ },
98+ }
99+
100+ if i == 1 then
101+ -- for first snippet: jump into it, and store the expanded snippet.
102+ expand_opts .jump_into_func = function (snip )
103+ expanded_snippets [i ] = snip
104+ local cr = _jump_into_default (snip )
105+ print (cr )
106+ return cr
107+ end
108+ else
109+ -- don't jump into the snippet, just store it.
110+ expand_opts .jump_into_func = function (snip )
111+ expanded_snippets [i ] = snip
112+
113+ print (session .current_nodes [bufnr ])
114+
115+ -- let the already-active node stay active.
116+ return session .current_nodes [bufnr ]
117+ end
118+ -- jump from previous i0 directly into this snippet (ignore start_node).
119+ expand_opts .jumplist_insert_func = function (snippet , _ , _ , _ )
120+ snippet .prev = expanded_snippets [i - 1 ].insert_nodes [0 ]
121+ expanded_snippets [i - 1 ].insert_nodes [0 ].next = snippet
122+ end
123+ end
124+
125+ ls .lsp_expand (snippet_params .snippet_body , expand_opts )
126+ end
61127end
62128
63129function M .update_capabilities (capabilities )
0 commit comments