|
| 1 | +local M = {} |
| 2 | + |
| 3 | +---@param bufnr integer |
| 4 | +---@param suggestion_ui nes.EditSuggestionUI |
| 5 | +---@param ns_id integer |
| 6 | +local function _dismiss_suggestion_ui(bufnr, suggestion_ui, ns_id) |
| 7 | + pcall(vim.api.nvim_win_close, suggestion_ui.preview_winnr, true) |
| 8 | + pcall(vim.api.nvim_buf_clear_namespace, bufnr, ns_id, 0, -1) |
| 9 | +end |
| 10 | + |
| 11 | +---@param bufnr? integer |
| 12 | +---@param ns_id integer |
| 13 | +function M.clear_suggestion(bufnr, ns_id) |
| 14 | + bufnr = bufnr and bufnr > 0 and bufnr or vim.api.nvim_get_current_buf() |
| 15 | + vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1) |
| 16 | + ---@type copilotlsp.InlineEdit |
| 17 | + local state = vim.b[bufnr].nes_state |
| 18 | + if not state then |
| 19 | + return |
| 20 | + end |
| 21 | + |
| 22 | + _dismiss_suggestion_ui(bufnr, state.ui, ns_id) |
| 23 | + vim.b[bufnr].nes_state = nil |
| 24 | +end |
| 25 | + |
| 26 | +---@private |
| 27 | +---@param edits copilotlsp.InlineEdit[] |
| 28 | +---@param ns_id integer |
| 29 | +function M._display_next_suggestion(edits, ns_id) |
| 30 | + if not edits or #edits == 0 then |
| 31 | + vim.notify("No suggestion available", vim.log.levels.INFO) |
| 32 | + return |
| 33 | + end |
| 34 | + local bufnr = vim.uri_to_bufnr(edits[1].textDocument.uri) |
| 35 | + local win_id = vim.fn.win_findbuf(bufnr)[1] |
| 36 | + local suggestion = edits[1] |
| 37 | + |
| 38 | + local ui = {} |
| 39 | + local deleted_lines_count = suggestion.range["end"].line - suggestion.range.start.line |
| 40 | + local added_lines = vim.split(suggestion.newText, "\n") |
| 41 | + local added_lines_count = suggestion.newText == "" and 0 or #added_lines - 1 |
| 42 | + local same_line = 0 |
| 43 | + |
| 44 | + if deleted_lines_count == 0 and added_lines_count == 0 then |
| 45 | + ---changing within line |
| 46 | + deleted_lines_count = 1 |
| 47 | + added_lines_count = 1 |
| 48 | + same_line = 1 |
| 49 | + added_lines = { suggestion.newText } |
| 50 | + end |
| 51 | + |
| 52 | + if deleted_lines_count > 0 then |
| 53 | + vim.api.nvim_buf_set_extmark(bufnr, ns_id, suggestion.range.start.line, 0, { |
| 54 | + hl_group = "NesDelete", |
| 55 | + end_line = suggestion.range["end"].line, |
| 56 | + }) |
| 57 | + end |
| 58 | + if added_lines_count > 0 then |
| 59 | + local virt_lines = {} |
| 60 | + for _ = 1, added_lines_count do |
| 61 | + table.insert(virt_lines, { |
| 62 | + { "", "Normal" }, |
| 63 | + }) |
| 64 | + end |
| 65 | + local line = suggestion.range.start.line + deleted_lines_count - 1 + same_line |
| 66 | + |
| 67 | + vim.api.nvim_buf_set_extmark(bufnr, ns_id, line, 0, { |
| 68 | + virt_lines = virt_lines, |
| 69 | + }) |
| 70 | + |
| 71 | + local preview_bufnr = vim.api.nvim_create_buf(false, true) |
| 72 | + vim.api.nvim_buf_set_lines(preview_bufnr, 0, -1, false, added_lines) |
| 73 | + vim.bo[preview_bufnr].modifiable = false |
| 74 | + vim.bo[preview_bufnr].buflisted = false |
| 75 | + vim.bo[preview_bufnr].bufhidden = "wipe" |
| 76 | + vim.bo[preview_bufnr].filetype = vim.bo[bufnr].filetype |
| 77 | + |
| 78 | + local cursor = vim.api.nvim_win_get_cursor(win_id) |
| 79 | + local win_width = vim.api.nvim_win_get_width(win_id) |
| 80 | + local offset = vim.fn.getwininfo(win_id)[1].textoff |
| 81 | + local preview_winnr = vim.api.nvim_open_win(preview_bufnr, false, { |
| 82 | + relative = "cursor", |
| 83 | + width = win_width - offset, |
| 84 | + height = (#added_lines + same_line) - 1, |
| 85 | + row = (suggestion.range["end"].line + same_line) - cursor[1] + 1, |
| 86 | + col = 0, |
| 87 | + style = "minimal", |
| 88 | + border = "none", |
| 89 | + }) |
| 90 | + vim.wo[preview_winnr].number = false |
| 91 | + vim.wo[preview_winnr].winhighlight = "Normal:NesAdd" |
| 92 | + vim.wo[preview_winnr].winblend = 0 |
| 93 | + |
| 94 | + ui.preview_winnr = preview_winnr |
| 95 | + end |
| 96 | + |
| 97 | + suggestion.ui = ui |
| 98 | + |
| 99 | + vim.b[bufnr].nes_state = suggestion |
| 100 | + |
| 101 | + vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { |
| 102 | + buffer = bufnr, |
| 103 | + callback = function() |
| 104 | + if not vim.b.nes_state then |
| 105 | + return true |
| 106 | + end |
| 107 | + |
| 108 | + local accepted_cursor = vim.b.nes_state.accepted_cursor |
| 109 | + if accepted_cursor then |
| 110 | + local cursor = vim.api.nvim_win_get_cursor(win_id) |
| 111 | + if cursor[1] == accepted_cursor[1] and cursor[2] == accepted_cursor[2] then |
| 112 | + return |
| 113 | + end |
| 114 | + end |
| 115 | + |
| 116 | + M.clear_suggestion(bufnr, ns_id) |
| 117 | + return true |
| 118 | + end, |
| 119 | + }) |
| 120 | +end |
| 121 | + |
| 122 | +return M |
0 commit comments