|
| 1 | +local luasnip_ns_id = require("luasnip.session").ns_id |
| 2 | +local ls = require("luasnip") |
| 3 | + |
| 4 | +local M = {} |
| 5 | + |
| 6 | +---Apply text/snippetTextEdits (at most one snippetText though). |
| 7 | +---@param snippet_or_text_edits `(snippetTextEdit|textEdit)[]` |
| 8 | +--- snippetTextEdit as defined in https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#snippet-textedit) |
| 9 | +---@param bufnr number, buffer where the snippet should be expanded. |
| 10 | +---@param offset_encoding string|nil, 'utf-8,16,32' or ni |
| 11 | +---@param apply_text_edits_fn function, has to apply regular textEdits, most |
| 12 | +--- likely `vim.lsp.util.apply_text_edits` (we expect its' interface). |
| 13 | +function M.apply_text_edits(snippet_or_text_edits, bufnr, offset_encoding, apply_text_edits_fn) |
| 14 | + -- plain textEdits, applied using via `apply_text_edits_fn`. |
| 15 | + local text_edits = {} |
| 16 | + -- contains keys |
| 17 | + -- - snippet (parsed snippet) |
| 18 | + -- - mark (extmark, textrange replaced by the snippet) |
| 19 | + local snippet_params |
| 20 | + |
| 21 | + for _, v in ipairs(snippet_or_text_edits) do |
| 22 | + if v.newText and v.insertTextFormat == 2 then |
| 23 | + assert(snippet_params == nil, "Only one snippetTextEdit may be applied at once.") |
| 24 | + |
| 25 | + -- from vim.lsp.apply_text_edits. |
| 26 | + local start_row = v.range.start.line |
| 27 | + local start_col = vim.lsp.util._get_line_byte_from_position(bufnr, v.range.start, offset_encoding) |
| 28 | + local end_row = v.range['end'].line |
| 29 | + local end_col = vim.lsp.util._get_line_byte_from_position(bufnr, v.range['end'], offset_encoding) |
| 30 | + |
| 31 | + snippet_params = { |
| 32 | + snippet_body = v.newText, |
| 33 | + mark = vim.api.nvim_buf_set_extmark(bufnr, luasnip_ns_id, start_row, start_col, { |
| 34 | + end_row = end_row, |
| 35 | + end_col = end_col |
| 36 | + }), |
| 37 | + } |
| 38 | + else |
| 39 | + table.insert(text_edits, v) |
| 40 | + end |
| 41 | + end |
| 42 | + |
| 43 | + -- first apply regular textEdits... |
| 44 | + apply_text_edits_fn(text_edits, bufnr, offset_encoding) |
| 45 | + |
| 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 | + }) |
| 61 | +end |
| 62 | + |
| 63 | +return M |
0 commit comments