|
| 1 | +local utils = {} |
| 2 | + |
| 3 | +local function accept(item) |
| 4 | + local sources = require('blink.cmp.sources') |
| 5 | + local fuzzy = require('blink.cmp.fuzzy') |
| 6 | + |
| 7 | + local text_edit = item.textEdit |
| 8 | + if text_edit ~= nil then |
| 9 | + -- Adjust the position of the text edit to be the current cursor position |
| 10 | + -- since the data might be outdated. We compare the cursor column position |
| 11 | + -- from when the items were fetched versus the current. |
| 12 | + -- hack: figure out a better way |
| 13 | + local offset = vim.api.nvim_win_get_cursor(0)[2] - item.cursor_column |
| 14 | + text_edit.range['end'].character = text_edit.range['end'].character + offset |
| 15 | + else |
| 16 | + -- No text edit so we fallback to our own resolution |
| 17 | + text_edit = utils.guess_text_edit(vim.api.nvim_get_current_buf(), item) |
| 18 | + end |
| 19 | + |
| 20 | + -- Snippet |
| 21 | + if item.insertTextFormat == vim.lsp.protocol.InsertTextFormat.Snippet then |
| 22 | + -- We want to handle offset_encoding and the text edit api can do this for us |
| 23 | + -- so we empty the newText and apply |
| 24 | + local temp_text_edit = vim.deepcopy(text_edit) |
| 25 | + temp_text_edit.newText = '' |
| 26 | + utils.apply_text_edits(item.client_id, { temp_text_edit }) |
| 27 | + |
| 28 | + -- Expand the snippet |
| 29 | + -- todo: use the snippet plugin api |
| 30 | + vim.snippet.expand(text_edit.newText) |
| 31 | + else |
| 32 | + -- Apply the text edit and move the cursor |
| 33 | + utils.apply_text_edits(item.client_id, { text_edit }) |
| 34 | + vim.api.nvim_win_set_cursor( |
| 35 | + 0, |
| 36 | + { text_edit.range.start.line + 1, text_edit.range.start.character + #text_edit.newText } |
| 37 | + ) |
| 38 | + end |
| 39 | + |
| 40 | + -- Apply additional text edits |
| 41 | + -- LSPs can either include these in the initial response or require a resolve |
| 42 | + -- These are used for things like auto-imports |
| 43 | + -- todo: check capabilities to know ahead of time |
| 44 | + if item.additionalTextEdits ~= nil then |
| 45 | + utils.apply_text_edits(item.client_id, item.additionalTextEdits) |
| 46 | + else |
| 47 | + sources.resolve( |
| 48 | + item, |
| 49 | + function(resolved_item) utils.apply_text_edits(item.client_id, resolved_item.additionalTextEdits or {}) end |
| 50 | + ) |
| 51 | + end |
| 52 | + |
| 53 | + -- Notify the rust module that the item was accessed |
| 54 | + fuzzy.access(item.label) |
| 55 | +end |
| 56 | + |
| 57 | +---------- UTILS ------------ |
| 58 | + |
| 59 | +function utils.guess_text_edit(bufnr, item) |
| 60 | + local word = item.insertText or item.label |
| 61 | + |
| 62 | + local current_line = vim.api.nvim_win_get_cursor(0)[1] |
| 63 | + local current_col = vim.api.nvim_win_get_cursor(0)[2] |
| 64 | + local line = vim.api.nvim_buf_get_lines(bufnr, current_line - 1, current_line, false)[1] |
| 65 | + |
| 66 | + -- Search forward/backward for the start/end of the word |
| 67 | + local start_col = current_col |
| 68 | + while start_col > 1 do |
| 69 | + local char = line:sub(start_col, start_col) |
| 70 | + if char:match('[%w_\\-]') == nil then |
| 71 | + start_col = start_col + 1 |
| 72 | + break |
| 73 | + end |
| 74 | + start_col = start_col - 1 |
| 75 | + end |
| 76 | + |
| 77 | + -- todo: dont search forward since LSPs dont typically do this so it will be inconsistent |
| 78 | + local end_col = current_col |
| 79 | + while end_col < #line do |
| 80 | + local char = line:sub(end_col + 1, end_col + 1) |
| 81 | + if char:match('[%w_\\-]') == nil then break end |
| 82 | + end_col = end_col + 1 |
| 83 | + end |
| 84 | + |
| 85 | + -- convert to 0-index |
| 86 | + return { |
| 87 | + range = { |
| 88 | + start = { line = current_line - 1, character = start_col - 1 }, |
| 89 | + ['end'] = { line = current_line - 1, character = end_col }, |
| 90 | + }, |
| 91 | + newText = word, |
| 92 | + } |
| 93 | +end |
| 94 | + |
| 95 | +function utils.apply_text_edits(client_id, edits) |
| 96 | + local client = vim.lsp.get_client_by_id(client_id) |
| 97 | + vim.print(vim.inspect(client_id)) |
| 98 | + local offset_encoding = client ~= nil and client.offset_encoding or 'utf-16' |
| 99 | + vim.lsp.util.apply_text_edits(edits, vim.api.nvim_get_current_buf(), offset_encoding) |
| 100 | +end |
| 101 | + |
| 102 | +return accept |
0 commit comments