Repository: copilotlsp-nvim/copilot-lsp
Pull request #34: feat(ui): inline edit preview
Author: login: Xuyuanp
Created: 2025-04-30T14:59:38Z | Merged: 2025-05-16T09:01:57Z

![image](https://github.com/user-attachments/assets/156e215e-3ff4-4288-ba30-dc059e6cf311)

Related https://github.com/Xuyuanp/nes.nvim/pull/6

Close #29 


Linked issue #29: Improvement: More readable diff view of suggestions
The current view is not clear enough, and when the suggestion is long, it is difficult to understand what would be modified at a glance. Stopping to analyze it interrupts my workflow.

no idea yet.
Linked issue comments: user: login: tris203
created_at: 2025-04-28T15:37:03Z
body: We could potentially use a inline diff like gitsigns has an option to do. 

![image](https://github.com/user-attachments/assets/409a1f91-5cee-404b-8b12-66b7db3ecac7)
author_association: COLLABORATOR

Diff:
diff --git a/lsp/copilot_ls.lua b/lsp/copilot_ls.lua
index f0b606d..d5ac4c8 100644
--- a/lsp/copilot_ls.lua
+++ b/lsp/copilot_ls.lua
@@ -30,10 +30,6 @@ return {
     }),
     root_dir = vim.uv.cwd(),
     on_init = function(client)
-        vim.api.nvim_set_hl(0, "CopilotLspNesAdd", { link = "DiffAdd", default = true })
-        vim.api.nvim_set_hl(0, "CopilotLspNesDelete", { link = "DiffDelete", default = true })
-        vim.api.nvim_set_hl(0, "CopilotLspNesApply", { link = "DiffText", default = true })
-
         local au = vim.api.nvim_create_augroup("copilotlsp.init", { clear = true })
         --NOTE: Inline Completions
         --TODO: We dont currently use this code path, so comment for now until a UI is built
diff --git a/lua/copilot-lsp/nes/init.lua b/lua/copilot-lsp/nes/init.lua
index b855232..6e9a147 100644
--- a/lua/copilot-lsp/nes/init.lua
+++ b/lua/copilot-lsp/nes/init.lua
@@ -8,7 +8,8 @@ local nes_ns = vim.api.nvim_create_namespace("copilotlsp.nes")
 
 ---@param err lsp.ResponseError?
 ---@param result copilotlsp.copilotInlineEditResponse
-local function handle_nes_response(err, result)
+---@param ctx lsp.HandlerContext
+local function handle_nes_response(err, result, ctx)
     if err then
         -- vim.notify(err.message)
         return
@@ -17,14 +18,17 @@ local function handle_nes_response(err, result)
         --- Convert to textEdit fields
         edit.newText = edit.text
     end
-    nes_ui._display_next_suggestion(result.edits, nes_ns)
+    nes_ui._display_next_suggestion(ctx.bufnr, nes_ns, result.edits)
 end
 
 --- Requests the NextEditSuggestion from the current cursor position
----@param copilot_lss vim.lsp.Client?
+---@param copilot_lss? vim.lsp.Client|string
 function M.request_nes(copilot_lss)
     local pos_params = vim.lsp.util.make_position_params(0, "utf-16")
     local version = vim.lsp.util.buf_versions[vim.api.nvim_get_current_buf()]
+    if type(copilot_lss) == "string" then
+        copilot_lss = vim.lsp.get_clients({ name = copilot_lss })[1]
+    end
     assert(copilot_lss, errs.ErrNotStarted)
     ---@diagnostic disable-next-line: inject-field
     pos_params.textDocument.version = version
@@ -109,4 +113,10 @@ function M.apply_pending_nes(bufnr)
     return true
 end
 
+---@param bufnr? integer
+function M.clear_suggestion(bufnr)
+    bufnr = bufnr and bufnr > 0 and bufnr or vim.api.nvim_get_current_buf()
+    nes_ui.clear_suggestion(bufnr, nes_ns)
+end
+
 return M
diff --git a/lua/copilot-lsp/nes/state.lua b/lua/copilot-lsp/nes/state.lua
deleted file mode 100644
index e69de29..0000000
diff --git a/lua/copilot-lsp/nes/ui.lua b/lua/copilot-lsp/nes/ui.lua
index 3affd13..e5f3fac 100644
--- a/lua/copilot-lsp/nes/ui.lua
+++ b/lua/copilot-lsp/nes/ui.lua
@@ -14,108 +14,159 @@ function M.clear_suggestion(bufnr, ns_id)
         vim.b[bufnr].nes_jump = false
         return
     end
-    vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1)
+    _dismiss_suggestion(bufnr, ns_id)
     ---@type copilotlsp.InlineEdit
     local state = vim.b[bufnr].nes_state
     if not state then
         return
     end
 
-    _dismiss_suggestion(bufnr, ns_id)
     vim.b[bufnr].nes_state = nil
 end
 
-local function trim_end(s)
-    return s:gsub("%s+$", "")
-end
-
 ---@private
----@param suggestion copilotlsp.InlineEdit
----@return copilotlsp.nes.LineCalculationResult
-function M._calculate_lines(suggestion)
-    local deleted_lines_count = suggestion.range["end"].line - suggestion.range.start.line
-    local added_lines = vim.split(trim_end(suggestion.newText), "\n")
-    local added_lines_count = suggestion.newText == "" and 0 or #added_lines
-    local same_line = 0
-
-    if deleted_lines_count == 0 and added_lines_count == 1 then
-        ---changing within line
-        deleted_lines_count = 1
-        same_line = 1
+---@param bufnr integer
+---@param edit lsp.TextEdit
+---@return copilotlsp.nes.InlineEditPreview
+function M._calculate_preview(bufnr, edit)
+    local text = edit.newText
+    local range = edit.range
+    local start_line = range.start.line
+    local start_char = range.start.character
+    local end_line = range["end"].line
+    local end_char = range["end"].character
+
+    -- Split text by newline. Use plain=true to handle trailing newline correctly.
+    local new_lines = vim.split(text, "\n", { plain = true })
+    local num_new_lines = #new_lines
+
+    local old_lines = vim.api.nvim_buf_get_lines(bufnr, start_line, end_line + 1, false)
+    local num_old_lines = #old_lines
+
+    local is_same_line = start_line == end_line
+    local is_deletion = text == ""
+    local lines_edit = is_same_line or (start_char == 0 and end_char == 0)
+    local is_insertion = is_same_line and start_char == end_char
+
+    if is_deletion and is_insertion then
+        -- no-op
+        return {}
     end
 
-    -- if
-    --     suggestion.range.start.line == suggestion.range["end"].line
-    --     and suggestion.range.start.character == suggestion.range["end"].character
-    -- then
-    --     --add only
-    --     TODO: Do we need to position specifically for add only?
-    --     UI tests seem to say no
-    -- end
-
-    -- Calculate positions for delete highlight extmark
-    ---@type copilotlsp.nes.DeleteExtmark
-    local delete_extmark = {
-        row = suggestion.range.start.line,
-        end_row = (
-            suggestion.range["end"].character ~= 0 and suggestion.range["end"].line + 1
-            or suggestion.range["end"].line
-        ),
-    }
+    if is_deletion and lines_edit then
+        return {
+            deletion = {
+                range = edit.range,
+            },
+        }
+    end
 
-    -- Calculate positions for virtual lines extmark
-    ---@type copilotlsp.nes.AddExtmark
-    local virt_lines_extmark = {
-        row = (
-            suggestion.range["end"].character ~= 0 and suggestion.range["end"].line
-            or suggestion.range["end"].line - 1
-        ),
-        virt_lines_count = added_lines_count,
-    }
+    if is_insertion and num_new_lines == 1 and text ~= "" then
+        -- inline insertion
+        return {
+            inline_insertion = {
+                text = text,
+                line = start_line,
+                character = start_char,
+            },
+        }
+    end
+
+    if is_insertion and num_new_lines > 1 then
+        if start_char == #old_lines[1] and new_lines[1] == "" then
+            -- insert lines after the start line
+            return {
+                lines_insertion = {
+                    text = table.concat(vim.list_slice(new_lines, 2), "\n"),
+                    line = start_line,
+                },
+            }
+        end
+
+        if end_char == 0 and new_lines[num_new_lines] == "" then
+            -- insert lines before the end line
+            return {
+                lines_insertion = {
+                    text = table.concat(vim.list_slice(new_lines, 1, num_new_lines - 1), "\n"),
+                    line = start_line,
+                    above = true,
+                },
+            }
+        end
+    end
+
+    -- insert lines in the middle
+    local prefix = old_lines[1]:sub(1, start_char)
+    local suffix = old_lines[num_old_lines]:sub(end_char + 1)
+    local new_lines_extend = vim.deepcopy(new_lines)
+    new_lines_extend[1] = prefix .. new_lines_extend[1]
+    new_lines_extend[num_new_lines] = new_lines_extend[num_new_lines] .. suffix
+    local insertion = table.concat(new_lines_extend, "\n")
 
     return {
-        deleted_lines_count = deleted_lines_count,
-        added_lines = added_lines,
-        added_lines_count = added_lines_count,
-        same_line = same_line,
-        delete_extmark = delete_extmark,
-        virt_lines_extmark = virt_lines_extmark,
+        deletion = {
+            range = {
+                start = { line = start_line, character = 0 },
+                ["end"] = { line = end_line, character = #old_lines[num_old_lines] },
+            },
+        },
+        lines_insertion = {
+            text = insertion,
+            line = end_line,
+        },
     }
 end
 
 ---@private
----@param edits copilotlsp.InlineEdit[]
+---@param bufnr integer
 ---@param ns_id integer
-function M._display_next_suggestion(edits, ns_id)
-    local state = vim.b[vim.api.nvim_get_current_buf()].nes_state
-    if state then
-        M.clear_suggestion(vim.api.nvim_get_current_buf(), ns_id)
-    end
-
-    if not edits or #edits == 0 then
-        -- vim.notify("No suggestion available", vim.log.levels.INFO)
-        return
+---@param preview copilotlsp.nes.InlineEditPreview
+function M._display_preview(bufnr, ns_id, preview)
+    if preview.deletion then
+        local range = preview.deletion.range
+        vim.api.nvim_buf_set_extmark(bufnr, ns_id, range.start.line, range.start.character, {
+            hl_group = "CopilotLspNesDelete",
+            end_row = range["end"].line,
+            end_col = range["end"].character,
+        })
     end
-    local bufnr = vim.uri_to_bufnr(edits[1].textDocument.uri)
-    local suggestion = edits[1]
 
-    local lines = M._calculate_lines(suggestion)
-
-    if lines.deleted_lines_count > 0 then
-        -- Deleted range red highlight
-        vim.api.nvim_buf_set_extmark(bufnr, ns_id, lines.delete_extmark.row, 0, {
-            hl_group = "CopilotLspNesDelete",
-            end_row = lines.delete_extmark.end_row,
+    local inline_insertion = preview.inline_insertion
+    if inline_insertion then
+        local virt_lines =
+            require("copilot-lsp.util").hl_text_to_virt_lines(inline_insertion.text, vim.bo[bufnr].filetype)
+        vim.api.nvim_buf_set_extmark(bufnr, ns_id, inline_insertion.line, inline_insertion.character, {
+            virt_text = virt_lines[1],
+            virt_text_pos = "inline",
         })
     end
-    if lines.added_lines_count > 0 then
-        local text = trim_end(edits[1].text)
-        local virt_lines = require("copilot-lsp.util").hl_text_to_virt_lines(text, vim.bo[bufnr].filetype)
 
-        vim.api.nvim_buf_set_extmark(bufnr, ns_id, lines.virt_lines_extmark.row, 0, {
+    local lines_insertion = preview.lines_insertion
+    if lines_insertion then
+        local virt_lines =
+            require("copilot-lsp.util").hl_text_to_virt_lines(lines_insertion.text, vim.bo[bufnr].filetype)
+        vim.api.nvim_buf_set_extmark(bufnr, ns_id, lines_insertion.line, 0, {
             virt_lines = virt_lines,
+            virt_lines_above = lines_insertion.above,
         })
     end
+end
+
+---@private
+---@param bufnr integer
+---@param ns_id integer
+---@param edits copilotlsp.InlineEdit[]
+function M._display_next_suggestion(bufnr, ns_id, edits)
+    M.clear_suggestion(bufnr, ns_id)
+    if not edits or #edits == 0 then
+        -- vim.notify("No suggestion available", vim.log.levels.INFO)
+        return
+    end
+
+    local suggestion = edits[1]
+
+    local preview = M._calculate_preview(bufnr, suggestion)
+    M._display_preview(bufnr, ns_id, preview)
 
     vim.b[bufnr].nes_state = suggestion
 
diff --git a/lua/copilot-lsp/types.lua b/lua/copilot-lsp/types.lua
index f3e5bc6..3e03240 100644
--- a/lua/copilot-lsp/types.lua
+++ b/lua/copilot-lsp/types.lua
@@ -1,31 +1,25 @@
----@class copilotlsp.InlineEdit
+---@class copilotlsp.InlineEdit : lsp.TextEdit
 ---@field command lsp.Command
----@field range lsp.Range
 ---@field text string
----@field newText string
 ---@field textDocument lsp.VersionedTextDocumentIdentifier
 
 ---@class copilotlsp.copilotInlineEditResponse
 ---@field edits copilotlsp.InlineEdit[]
 
----@class copilotlsp.nes.EditSuggestionUI
----@field preview_winnr? integer
+---@class copilotlsp.nes.TextDeletion
+---@field range lsp.Range
 
----@class copilotlsp.nes.DeleteExtmark
---- Holds row information for delete highlight extmark.
----@field row number
----@field end_row number
+---@class copilotlsp.nes.InlineInsertion
+---@field text string
+---@field line integer
+---@field character integer
 
----@class copilotlsp.nes.AddExtmark
--- Holds row and virtual lines count for virtual lines extmark.
----@field row number
----@field virt_lines_count number
+---@class copilotlsp.nes.TextInsertion
+---@field text string
+---@field line integer insert lines at this line
+---@field above? boolean above the line
 
----@class copilotlsp.nes.LineCalculationResult
---- The result of calculating lines for inline suggestion UI.
----@field deleted_lines_count number
----@field added_lines string[]
----@field added_lines_count number
----@field same_line number
----@field delete_extmark copilotlsp.nes.DeleteExtmark
----@field virt_lines_extmark copilotlsp.nes.AddExtmark
+---@class copilotlsp.nes.InlineEditPreview
+---@field deletion? copilotlsp.nes.TextDeletion
+---@field inline_insertion? copilotlsp.nes.InlineInsertion
+---@field lines_insertion? copilotlsp.nes.TextInsertion
diff --git a/plugin/copilot-lsp.lua b/plugin/copilot-lsp.lua
new file mode 100644
index 0000000..15cd59a
--- /dev/null
+++ b/plugin/copilot-lsp.lua
@@ -0,0 +1,3 @@
+vim.api.nvim_set_hl(0, "CopilotLspNesAdd", { link = "DiffAdd", default = true })
+vim.api.nvim_set_hl(0, "CopilotLspNesDelete", { link = "DiffDelete", default = true })
+vim.api.nvim_set_hl(0, "CopilotLspNesApply", { link = "DiffText", default = true })
diff --git a/tests/mock_lsp.lua b/tests/mock_lsp.lua
index 0e0c207..97af04c 100644
--- a/tests/mock_lsp.lua
+++ b/tests/mock_lsp.lua
@@ -74,7 +74,7 @@ local function getNesResponse(td)
                     command = { title = "mock", command = "mock" },
                     range = {
                         start = { line = 4, character = 0 },
-                        ["end"] = { line = 4, character = 30 },
+                        ["end"] = { line = 4, character = 31 },
                     },
                     textDocument = td,
                     text = [[  printf("Goodb, %s!\n", name);]],
diff --git a/tests/nes/test_ui.lua b/tests/nes/test_ui.lua
deleted file mode 100644
index 0b91e92..0000000
--- a/tests/nes/test_ui.lua
+++ /dev/null
@@ -1,158 +0,0 @@
-local eq = MiniTest.expect.equality
-local nes_ui = require("copilot-lsp.nes.ui")
-
-local T = MiniTest.new_set()
-
-T["diff placement calculations"] = MiniTest.new_set({
-    ---@type [ copilotlsp.InlineEdit, copilotlsp.nes.LineCalculationResult][]
-    parametrize = {
-        {
-            --- Same line edit
-            {
-                command = { title = "sameline", command = "mock" },
-                range = {
-                    start = {
-                        line = 0,
-                        character = 0,
-                    },
-                    ["end"] = {
-                        line = 0,
-                        character = 10,
-                    },
-                },
-                textDocument = {
-                    uri = "mock",
-                    version = 1,
-                },
-                text = "mock",
-                newText = "mock",
-            },
-            {
-                added_lines = { "mock" },
-                added_lines_count = 1,
-                delete_extmark = {
-                    end_row = 1,
-                    row = 0,
-                },
-                deleted_lines_count = 1,
-                same_line = 1,
-                virt_lines_extmark = {
-                    row = 0,
-                    virt_lines_count = 1,
-                },
-            },
-        },
-        {
-            --- removal only
-            {
-                command = { title = "removal", command = "mock" },
-                range = {
-                    start = {
-                        line = 0,
-                        character = 0,
-                    },
-                    ["end"] = {
-                        line = 1,
-                        character = 0,
-                    },
-                },
-                textDocument = {
-                    uri = "mock",
-                    version = 1,
-                },
-                text = "",
-                newText = "",
-            },
-            {
-                added_lines = { "" },
-                added_lines_count = 0,
-                delete_extmark = {
-                    end_row = 1,
-                    row = 0,
-                },
-                deleted_lines_count = 1,
-                same_line = 0,
-                virt_lines_extmark = {
-                    row = 0,
-                    virt_lines_count = 0,
-                },
-            },
-        },
-        {
-            --- remove one add 2
-            {
-                command = { title = "remove1add2", command = "mock" },
-                range = {
-                    start = {
-                        line = 0,
-                        character = 0,
-                    },
-                    ["end"] = {
-                        line = 1,
-                        character = 0,
-                    },
-                },
-                textDocument = {
-                    uri = "mock",
-                    version = 1,
-                },
-                text = "mock\nmore text",
-                newText = "mock\nmore text",
-            },
-            {
-                added_lines = { "mock", "more text" },
-                added_lines_count = 2,
-                delete_extmark = {
-                    end_row = 1,
-                    row = 0,
-                },
-                deleted_lines_count = 1,
-                same_line = 0,
-                virt_lines_extmark = {
-                    row = 0,
-                    virt_lines_count = 2,
-                },
-            },
-        },
-        {
-            --- add only
-            {
-                command = { title = "add only", command = "mock" },
-                range = {
-                    start = { line = 2, character = 0 },
-                    ["end"] = { line = 2, character = 0 },
-                },
-                textDocument = {
-                    uri = "mock",
-                    version = 1,
-                },
-                text = "line 3\n",
-                newText = "line 3\n",
-            },
-            {
-                added_lines = { "line 3" },
-                added_lines_count = 1,
-                deleted_lines_count = 1,
-                delete_extmark = {
-                    end_row = 2,
-                    row = 2,
-                },
-                same_line = 1,
-                virt_lines_extmark = {
-                    row = 1,
-                    virt_lines_count = 1,
-                },
-            },
-        },
-    },
-})
-
-T["diff placement calculations"]["calculates locations"] =
-    ---@param edit copilotlsp.InlineEdit
-    ---@param result copilotlsp.nes.LineCalculationResult
-    function(edit, result)
-        local placement = nes_ui._calculate_lines(edit)
-        eq(result, placement)
-    end
-
-return T
diff --git a/tests/nes/test_ui_preview.lua b/tests/nes/test_ui_preview.lua
new file mode 100644
index 0000000..0cfde21
--- /dev/null
+++ b/tests/nes/test_ui_preview.lua
@@ -0,0 +1,261 @@
+local ref = MiniTest.expect.reference_screenshot
+local eq = MiniTest.expect.equality
+
+local child = MiniTest.new_child_neovim()
+
+local T = MiniTest.new_set()
+T["ui_preview"] = MiniTest.new_set({
+    hooks = {
+        pre_case = function()
+            child.restart({ "-u", "scripts/minimal_init.lua" })
+            child.bo.filetype = "txt"
+        end,
+        post_once = child.stop,
+    },
+})
+
+local cases = {
+    ["inline insertion"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 2,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 2,
+                },
+            },
+            newText = "XYZ",
+        },
+        preview = {
+            inline_insertion = {
+                text = "XYZ",
+                line = 1,
+                character = 2,
+            },
+        },
+        final = "123456\nabXYZcdefg\nhijklmn",
+    },
+    ["inline deletion"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 2,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 5,
+                },
+            },
+            newText = "",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    start = {
+                        line = 1,
+                        character = 2,
+                    },
+                    ["end"] = {
+                        line = 1,
+                        character = 5,
+                    },
+                },
+            },
+        },
+        final = "123456\nabfg\nhijklmn",
+    },
+    ["insert lines below"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 7,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 7,
+                },
+            },
+            newText = "\nXXXX\nYYY",
+        },
+        preview = {
+            lines_insertion = {
+                text = "XXXX\nYYY",
+                line = 1,
+            },
+        },
+        final = "123456\nabcdefg\nXXXX\nYYY\nhijklmn",
+    },
+    ["insert lines above"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 0,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 0,
+                },
+            },
+            newText = "XXXX\nYYY\n",
+        },
+        preview = {
+            lines_insertion = {
+                text = "XXXX\nYYY",
+                line = 1,
+                above = true,
+            },
+        },
+        final = "123456\nXXXX\nYYY\nabcdefg\nhijklmn",
+    },
+    ["inline replacement"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 0,
+                    character = 3,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 4,
+                },
+            },
+            newText = "XXXX\nYYY",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    ["end"] = {
+                        character = 7,
+                        line = 1,
+                    },
+                    start = {
+                        character = 0,
+                        line = 0,
+                    },
+                },
+            },
+            lines_insertion = {
+                line = 1,
+                text = "123XXXX\nYYYefg",
+            },
+        },
+        final = "123XXXX\nYYYefg\nhijklmn",
+    },
+    ["single line replacement"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 0,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 8,
+                },
+            },
+            newText = "XXXX",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    ["end"] = {
+                        character = 7,
+                        line = 1,
+                    },
+                    start = {
+                        character = 0,
+                        line = 1,
+                    },
+                },
+            },
+            lines_insertion = {
+                line = 1,
+                text = "XXXX",
+            },
+        },
+        final = "123456\nXXXX\nhijklmn",
+    },
+    ["delete lines"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 0,
+                    character = 0,
+                },
+                ["end"] = {
+                    line = 2,
+                    character = 0,
+                },
+            },
+            newText = "",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    ["end"] = {
+                        character = 0,
+                        line = 2,
+                    },
+                    start = {
+                        character = 0,
+                        line = 0,
+                    },
+                },
+            },
+        },
+        final = "hijklmn",
+    },
+}
+
+local function set_content(content)
+    child.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(content, "\n", { plain = true }))
+end
+
+local function get_content()
+    return table.concat(child.api.nvim_buf_get_lines(0, 0, -1, false), "\n")
+end
+
+do
+    for name, case in pairs(cases) do
+        T["ui_preview"][name] = function()
+            set_content(case.content)
+            ref(child.get_screenshot())
+
+            child.g.inline_edit = case.edit
+            local preview = child.lua_func(function()
+                return require("copilot-lsp.nes.ui")._calculate_preview(0, vim.g.inline_edit)
+            end)
+            eq(preview, case.preview)
+
+            child.g.inline_preview = preview
+            child.lua_func(function()
+                local ns_id = vim.api.nvim_create_namespace("nes")
+                require("copilot-lsp.nes.ui")._display_preview(0, ns_id, vim.g.inline_preview)
+            end)
+            ref(child.get_screenshot())
+
+            child.lua_func(function()
+                local bufnr = vim.api.nvim_get_current_buf()
+                vim.lsp.util.apply_text_edits({ vim.g.inline_edit }, bufnr, "utf-16")
+            end)
+
+            local final = get_content()
+            eq(final, case.final)
+        end
+    end
+end
+
+return T
diff --git a/tests/screenshots/tests-nes-test_nes.lua---nes---highlights-replacement-003 b/tests/screenshots/tests-nes-test_nes.lua---nes---highlights-replacement-003
index f7c2c8d..a48f1af 100644
--- a/tests/screenshots/tests-nes-test_nes.lua---nes---highlights-replacement-003
+++ b/tests/screenshots/tests-nes-test_nes.lua---nes---highlights-replacement-003
@@ -3,7 +3,7 @@
 02|                                                                                
 03|int main(void) {                                                                
 04|  const char *name = "World";                                                   
-05|  printf("Goodb, %s!\n", name);;                                                
+05|  printf("Goodb, %s!\n", name);                                                 
 06|  return 0;                                                                     
 07|}                                                                               
 08|~                                                                               
@@ -29,7 +29,7 @@
 02|11111111111111111111111111111111111111111111111111111111111111111111111111111111
 03|33314444333333131111111111111111111111111111111111111111111111111111111111111111
 04|11555551333315444415122222223111111111111111111111111111111111111111111111111111
-05|11444444322222222222332314444333111111111111111111111111111111111111111111111111
+05|11444444322222222222332314444331111111111111111111111111111111111111111111111111
 06|11555555123111111111111111111111111111111111111111111111111111111111111111111111
 07|31111111111111111111111111111111111111111111111111111111111111111111111111111111
 08|66666666666666666666666666666666666666666666666666666666666666666666666666666666
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---delete-lines b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---delete-lines
new file mode 100644
index 0000000..99da93c
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---delete-lines
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+03|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+04|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+05|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+06|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+07|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+08|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+09|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+10|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+11|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+12|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+13|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+14|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+15|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+16|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+17|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+18|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+19|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+20|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+21|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+22|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+23|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---delete-lines-002 b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---delete-lines-002
new file mode 100644
index 0000000..b4b820f
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---delete-lines-002
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000011111111111111111111111111111111111111111111111111111111111111111111111111
+02|00000001111111111111111111111111111111111111111111111111111111111111111111111111
+03|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+04|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+05|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+06|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+07|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+08|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+09|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+10|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+11|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+12|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+13|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+14|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+15|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+16|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+17|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+18|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+19|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+20|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+21|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+22|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+23|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+24|11111111111111111111111111111111111111111111111111111111111111111111111111111111
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-deletion b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-deletion
new file mode 100644
index 0000000..99da93c
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-deletion
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+03|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+04|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+05|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+06|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+07|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+08|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+09|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+10|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+11|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+12|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+13|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+14|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+15|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+16|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+17|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+18|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+19|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+20|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+21|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+22|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+23|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-deletion-002 b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-deletion-002
new file mode 100644
index 0000000..26d5ac1
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-deletion-002
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00111000000000000000000000000000000000000000000000000000000000000000000000000000
+03|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+04|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+05|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+06|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+07|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+08|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+09|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+10|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+11|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+12|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+13|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+14|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+15|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+16|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+17|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+18|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+19|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+20|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+21|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+22|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+23|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-insertion b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-insertion
new file mode 100644
index 0000000..99da93c
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-insertion
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+03|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+04|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+05|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+06|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+07|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+08|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+09|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+10|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+11|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+12|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+13|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+14|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+15|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+16|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+17|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+18|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+19|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+20|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+21|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+22|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+23|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-insertion-002 b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-insertion-002
new file mode 100644
index 0000000..aa825b2
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-insertion-002
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abXYZcdefg                                                                      
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00111000000000000000000000000000000000000000000000000000000000000000000000000000
+03|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+04|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+05|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+06|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+07|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+08|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+09|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+10|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+11|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+12|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+13|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+14|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+15|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+16|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+17|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+18|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+19|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+20|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+21|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+22|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+23|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-replacement b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-replacement
new file mode 100644
index 0000000..99da93c
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-replacement
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+03|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+04|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+05|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+06|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+07|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+08|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+09|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+10|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+11|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+12|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+13|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+14|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+15|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+16|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+17|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+18|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+19|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+20|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+21|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+22|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+23|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-replacement-002 b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-replacement-002
new file mode 100644
index 0000000..4984dc0
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---inline-replacement-002
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|123XXXX                                                                         
+04|YYYefg                                                                          
+05|hijklmn                                                                         
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000011111111111111111111111111111111111111111111111111111111111111111111111111
+02|00000001111111111111111111111111111111111111111111111111111111111111111111111111
+03|22222221111111111111111111111111111111111111111111111111111111111111111111111111
+04|22222211111111111111111111111111111111111111111111111111111111111111111111111111
+05|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+06|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+07|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+08|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+09|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+10|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+11|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+12|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+13|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+14|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+15|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+16|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+17|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+18|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+19|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+20|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+21|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+22|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+23|44444444444444444444444444444444444444444444444444444444444444444444444444444444
+24|11111111111111111111111111111111111111111111111111111111111111111111111111111111
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-above b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-above
new file mode 100644
index 0000000..99da93c
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-above
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+03|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+04|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+05|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+06|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+07|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+08|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+09|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+10|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+11|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+12|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+13|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+14|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+15|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+16|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+17|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+18|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+19|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+20|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+21|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+22|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+23|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-above-002 b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-above-002
new file mode 100644
index 0000000..ce87ac0
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-above-002
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|XXXX                                                                            
+03|YYY                                                                             
+04|abcdefg                                                                         
+05|hijklmn                                                                         
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|11110000000000000000000000000000000000000000000000000000000000000000000000000000
+03|11100000000000000000000000000000000000000000000000000000000000000000000000000000
+04|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+05|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+06|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+07|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+08|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+09|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+10|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+11|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+12|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+13|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+14|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+15|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+16|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+17|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+18|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+19|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+20|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+21|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+22|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+23|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-below b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-below
new file mode 100644
index 0000000..99da93c
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-below
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+03|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+04|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+05|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+06|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+07|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+08|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+09|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+10|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+11|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+12|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+13|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+14|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+15|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+16|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+17|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+18|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+19|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+20|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+21|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+22|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+23|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-below-002 b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-below-002
new file mode 100644
index 0000000..7013178
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---insert-lines-below-002
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|XXXX                                                                            
+04|YYY                                                                             
+05|hijklmn                                                                         
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+03|11110000000000000000000000000000000000000000000000000000000000000000000000000000
+04|11100000000000000000000000000000000000000000000000000000000000000000000000000000
+05|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+06|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+07|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+08|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+09|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+10|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+11|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+12|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+13|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+14|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+15|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+16|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+17|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+18|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+19|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+20|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+21|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+22|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+23|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---single-line-replacement b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---single-line-replacement
new file mode 100644
index 0000000..99da93c
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---single-line-replacement
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|hijklmn                                                                         
+04|~                                                                               
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+03|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+04|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+05|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+06|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+07|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+08|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+09|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+10|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+11|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+12|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+13|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+14|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+15|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+16|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+17|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+18|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+19|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+20|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+21|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+22|11111111111111111111111111111111111111111111111111111111111111111111111111111111
+23|22222222222222222222222222222222222222222222222222222222222222222222222222222222
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000
diff --git a/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---single-line-replacement-002 b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---single-line-replacement-002
new file mode 100644
index 0000000..128180c
--- /dev/null
+++ b/tests/screenshots/tests-nes-test_ui_preview.lua---ui_preview---single-line-replacement-002
@@ -0,0 +1,51 @@
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|123456                                                                          
+02|abcdefg                                                                         
+03|XXXX                                                                            
+04|hijklmn                                                                         
+05|~                                                                               
+06|~                                                                               
+07|~                                                                               
+08|~                                                                               
+09|~                                                                               
+10|~                                                                               
+11|~                                                                               
+12|~                                                                               
+13|~                                                                               
+14|~                                                                               
+15|~                                                                               
+16|~                                                                               
+17|~                                                                               
+18|~                                                                               
+19|~                                                                               
+20|~                                                                               
+21|~                                                                               
+22|~                                                                               
+23|[No Name] [+]                                                 1,1            All
+24|                                                                                
+
+--|---------|---------|---------|---------|---------|---------|---------|---------|
+01|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+02|11111110000000000000000000000000000000000000000000000000000000000000000000000000
+03|22220000000000000000000000000000000000000000000000000000000000000000000000000000
+04|00000000000000000000000000000000000000000000000000000000000000000000000000000000
+05|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+06|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+07|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+08|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+09|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+10|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+11|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+12|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+13|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+14|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+15|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+16|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+17|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+18|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+19|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+20|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+21|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+22|33333333333333333333333333333333333333333333333333333333333333333333333333333333
+23|44444444444444444444444444444444444444444444444444444444444444444444444444444444
+24|00000000000000000000000000000000000000000000000000000000000000000000000000000000


Reviews:
user: login: tris203
body: if we have removed the UI tests, then we need to also remove the screenshots from the folder
state: DISMISSED
author_association: COLLABORATOR
submitted_at: 2025-05-07T16:16:11Z
user: login: Xuyuanp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T02:09:36Z
user: login: tris203
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-15T12:17:18Z

Review comments:
diff_hunk: @@ -14,108 +14,159 @@ function M.clear_suggestion(bufnr, ns_id)
         vim.b[bufnr].nes_jump = false
         return
     end
-    vim.api.nvim_buf_clear_namespace(bufnr, ns_id, 0, -1)
+    _dismiss_suggestion(bufnr, ns_id)
     ---@type copilotlsp.InlineEdit
     local state = vim.b[bufnr].nes_state
     if not state then
         return
     end
 
-    _dismiss_suggestion(bufnr, ns_id)
     vim.b[bufnr].nes_state = nil
 end
 
-local function trim_end(s)
-    return s:gsub("%s+$", "")
-end
-
 ---@private
----@param suggestion copilotlsp.InlineEdit
----@return copilotlsp.nes.LineCalculationResult
-function M._calculate_lines(suggestion)
-    local deleted_lines_count = suggestion.range["end"].line - suggestion.range.start.line
-    local added_lines = vim.split(trim_end(suggestion.newText), "\n")
-    local added_lines_count = suggestion.newText == "" and 0 or #added_lines
-    local same_line = 0
-
-    if deleted_lines_count == 0 and added_lines_count == 1 then
-        ---changing within line
-        deleted_lines_count = 1
-        same_line = 1
+---@param bufnr integer
+---@param edit lsp.TextEdit
+---@return copilotlsp.nes.InlineEditPreview
+function M._caculate_preview(bufnr, edit)
path: lua/copilot-lsp/nes/ui.lua
user: login: tris203
body: ```suggestion
function M._calculate_preview(bufnr, edit)
```
created_at: 2025-05-07T16:13:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,261 @@
+local ref = MiniTest.expect.reference_screenshot
+local eq = MiniTest.expect.equality
+
+local child = MiniTest.new_child_neovim()
+
+local T = MiniTest.new_set()
+T["ui_preview"] = MiniTest.new_set({
+    hooks = {
+        pre_case = function()
+            child.restart({ "-u", "scripts/minimal_init.lua" })
+            child.bo.filetype = "txt"
+        end,
+        post_once = child.stop,
+    },
+})
+
+local cases = {
+    ["inline insertion"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 2,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 2,
+                },
+            },
+            newText = "XYZ",
+        },
+        preview = {
+            inline_insertion = {
+                text = "XYZ",
+                line = 1,
+                character = 2,
+            },
+        },
+        final = "123456\nabXYZcdefg\nhijklmn",
+    },
+    ["inline deletion"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 2,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 5,
+                },
+            },
+            newText = "",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    start = {
+                        line = 1,
+                        character = 2,
+                    },
+                    ["end"] = {
+                        line = 1,
+                        character = 5,
+                    },
+                },
+            },
+        },
+        final = "123456\nabfg\nhijklmn",
+    },
+    ["insert lines below"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 7,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 7,
+                },
+            },
+            newText = "\nXXXX\nYYY",
+        },
+        preview = {
+            lines_insertion = {
+                text = "XXXX\nYYY",
+                line = 1,
+            },
+        },
+        final = "123456\nabcdefg\nXXXX\nYYY\nhijklmn",
+    },
+    ["insert lines above"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 0,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 0,
+                },
+            },
+            newText = "XXXX\nYYY\n",
+        },
+        preview = {
+            lines_insertion = {
+                text = "XXXX\nYYY",
+                line = 1,
+                above = true,
+            },
+        },
+        final = "123456\nXXXX\nYYY\nabcdefg\nhijklmn",
+    },
+    ["inline replacement"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 0,
+                    character = 3,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 4,
+                },
+            },
+            newText = "XXXX\nYYY",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    ["end"] = {
+                        character = 7,
+                        line = 1,
+                    },
+                    start = {
+                        character = 0,
+                        line = 0,
+                    },
+                },
+            },
+            lines_insertion = {
+                line = 1,
+                text = "123XXXX\nYYYefg",
+            },
+        },
+        final = "123XXXX\nYYYefg\nhijklmn",
+    },
+    ["single line replacement"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 0,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 8,
+                },
+            },
+            newText = "XXXX",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    ["end"] = {
+                        character = 7,
+                        line = 1,
+                    },
+                    start = {
+                        character = 0,
+                        line = 1,
+                    },
+                },
+            },
+            lines_insertion = {
+                line = 1,
+                text = "XXXX",
+            },
+        },
+        final = "123456\nXXXX\nhijklmn",
+    },
+    ["delete lines"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 0,
+                    character = 0,
+                },
+                ["end"] = {
+                    line = 2,
+                    character = 0,
+                },
+            },
+            newText = "",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    ["end"] = {
+                        character = 0,
+                        line = 2,
+                    },
+                    start = {
+                        character = 0,
+                        line = 0,
+                    },
+                },
+            },
+        },
+        final = "hijklmn",
+    },
+}
+
+local function set_content(content)
+    child.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(content, "\n", { plain = true }))
+end
+
+local function get_content()
+    return table.concat(child.api.nvim_buf_get_lines(0, 0, -1, false), "\n")
+end
+
+do
+    for name, case in pairs(cases) do
+        T["ui_preview"][name] = function()
path: tests/nes/test_ui_preview.lua
user: login: tris203
body: Do you think it would be nicer to use parameterization rather than a loop?
created_at: 2025-05-07T16:15:37Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,261 @@
+local ref = MiniTest.expect.reference_screenshot
+local eq = MiniTest.expect.equality
+
+local child = MiniTest.new_child_neovim()
+
+local T = MiniTest.new_set()
+T["ui_preview"] = MiniTest.new_set({
+    hooks = {
+        pre_case = function()
+            child.restart({ "-u", "scripts/minimal_init.lua" })
+            child.bo.filetype = "txt"
+        end,
+        post_once = child.stop,
+    },
+})
+
+local cases = {
+    ["inline insertion"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 2,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 2,
+                },
+            },
+            newText = "XYZ",
+        },
+        preview = {
+            inline_insertion = {
+                text = "XYZ",
+                line = 1,
+                character = 2,
+            },
+        },
+        final = "123456\nabXYZcdefg\nhijklmn",
+    },
+    ["inline deletion"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 2,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 5,
+                },
+            },
+            newText = "",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    start = {
+                        line = 1,
+                        character = 2,
+                    },
+                    ["end"] = {
+                        line = 1,
+                        character = 5,
+                    },
+                },
+            },
+        },
+        final = "123456\nabfg\nhijklmn",
+    },
+    ["insert lines below"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 7,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 7,
+                },
+            },
+            newText = "\nXXXX\nYYY",
+        },
+        preview = {
+            lines_insertion = {
+                text = "XXXX\nYYY",
+                line = 1,
+            },
+        },
+        final = "123456\nabcdefg\nXXXX\nYYY\nhijklmn",
+    },
+    ["insert lines above"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 0,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 0,
+                },
+            },
+            newText = "XXXX\nYYY\n",
+        },
+        preview = {
+            lines_insertion = {
+                text = "XXXX\nYYY",
+                line = 1,
+                above = true,
+            },
+        },
+        final = "123456\nXXXX\nYYY\nabcdefg\nhijklmn",
+    },
+    ["inline replacement"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 0,
+                    character = 3,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 4,
+                },
+            },
+            newText = "XXXX\nYYY",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    ["end"] = {
+                        character = 7,
+                        line = 1,
+                    },
+                    start = {
+                        character = 0,
+                        line = 0,
+                    },
+                },
+            },
+            lines_insertion = {
+                line = 1,
+                text = "123XXXX\nYYYefg",
+            },
+        },
+        final = "123XXXX\nYYYefg\nhijklmn",
+    },
+    ["single line replacement"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 1,
+                    character = 0,
+                },
+                ["end"] = {
+                    line = 1,
+                    character = 8,
+                },
+            },
+            newText = "XXXX",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    ["end"] = {
+                        character = 7,
+                        line = 1,
+                    },
+                    start = {
+                        character = 0,
+                        line = 1,
+                    },
+                },
+            },
+            lines_insertion = {
+                line = 1,
+                text = "XXXX",
+            },
+        },
+        final = "123456\nXXXX\nhijklmn",
+    },
+    ["delete lines"] = {
+        content = "123456\nabcdefg\nhijklmn",
+        edit = {
+            range = {
+                start = {
+                    line = 0,
+                    character = 0,
+                },
+                ["end"] = {
+                    line = 2,
+                    character = 0,
+                },
+            },
+            newText = "",
+        },
+        preview = {
+            deletion = {
+                range = {
+                    ["end"] = {
+                        character = 0,
+                        line = 2,
+                    },
+                    start = {
+                        character = 0,
+                        line = 0,
+                    },
+                },
+            },
+        },
+        final = "hijklmn",
+    },
+}
+
+local function set_content(content)
+    child.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(content, "\n", { plain = true }))
+end
+
+local function get_content()
+    return table.concat(child.api.nvim_buf_get_lines(0, 0, -1, false), "\n")
+end
+
+do
+    for name, case in pairs(cases) do
+        T["ui_preview"][name] = function()
path: tests/nes/test_ui_preview.lua
user: login: Xuyuanp
body: I tried to use parameterization, It is a bit difficult to tell which case is failed from the failure message. imo parameterization is more suitable for simple basic type parameters
created_at: 2025-05-08T02:09:36Z
author_association: CONTRIBUTOR

PR comments:
user: login: tris203
created_at: 2025-05-04T18:34:08Z
body: ![image](https://github.com/user-attachments/assets/81a846b5-5ab8-48bc-b06f-43c0f3c90b15)
![image](https://github.com/user-attachments/assets/1e1e7099-7980-40b5-8127-c4991b6a0c99)

i seem to still be getting larger diffs on this branch, would you not expect this diff to be more minimal?
author_association: COLLABORATOR
user: login: Xuyuanp
created_at: 2025-05-06T02:20:01Z
body: From what I've seen, Copilot currently seems to only return whole-line edits (like insert, delete, replace), not the real inline edits. But the structure returned by `copilotInlineEdit` itself can support inline edits. It's possible that the copilot will start send inline edits in the future. This PR handles it. What I am not sure about is whether we need to convert the single-line editing to inline editing.

At the same time, I am also refactoring my plugin (nes.nvim) to implement the `copilotInlineEdit` method and support inline edits
author_association: CONTRIBUTOR