43d88fd
Branches > main > 43d88fd > files
Nvim - Stop parinfer edits from flickering highlights
Commit: 43d88fd615f1b54529377b3cdba984eacfd0d0f5
Parent: 7e90c32
1 changed file:
nvim/lua/parinfer/plugin.lua view file
@@ -7,7 +7,6 @@ vim.g.parinfer_comment_chars = {";"} local api = vim.api-local diff = vim.text.diff or vim.diff local parinfer = require("parinfer.parinfer") local modes = {indent = parinfer.indentMode, paren = parinfer.parenMode,@@ -39,13 +38,8 @@ end end ---- Collapses everything that happened since the last run into one change.---- Linewise edits (V>, Vd + p, :m, ...) used to be passed as several on_bytes changes, each in the---- coordinates of a buffer that had been changed again since. Smart mode then shifted the---- indentation of the wrong lines (or the same lines more than once) and mangled the forms.-local function get_change(old, new)- if old == nil or old == new then return nil end-+--- Returns how many bytes 'old' and 'new' have in common at the start, and then at the end+local function common_ends(old, new) local max = math.min(#old, #new) local prefix = 0 while prefix < max and old:byte(prefix + 1) == new:byte(prefix + 1) do@@ -55,7 +49,17 @@ while suffix < max - prefix and old:byte(#old - suffix) == new:byte(#new - suffix) do suffix = suffix + 1 end+ return prefix, suffix+end +--- Collapses everything that happened since the last run into one change.+--- Linewise edits (V>, Vd + p, :m, ...) used to be passed as several on_bytes changes, each in the+--- coordinates of a buffer that had been changed again since. Smart mode then shifted the+--- indentation of the wrong lines (or the same lines more than once) and mangled the forms.+local function get_change(old, new)+ if old == nil or old == new then return nil end++ local prefix, suffix = common_ends(old, new) local before = old:sub(1, prefix) local _, line_breaks = before:gsub("\n", "") local line_start = before:find("[^\n]*$")@@ -65,18 +69,25 @@ newText = new:sub(prefix + 1, #new - suffix)} end +--- Only replaces the bytes parinfer changed. Replacing whole lines deletes the extmarks on them, so+--- the LSP semantic token highlights of every fixed line blinked off until the server sent new ones. local function update_buffer(bufnr, old_text, new_text)+ local old_lines = vim.split(old_text, "\n", {plain = true}) local new_lines = vim.split(new_text, "\n", {plain = true})- local hunks = diff(old_text .. "\n", new_text .. "\n", {result_type = "indices"}) vim.cmd("silent! undojoin")- --- Bottom up, so applying a hunk doesn't move the lines of the ones after it- for i = #hunks, 1, -1 do- local start_a, count_a, start_b, count_b = unpack(hunks[i])- --- A pure insertion goes after start_a- if count_a == 0 then start_a = start_a + 1 end- api.nvim_buf_set_lines(bufnr, start_a - 1, start_a - 1 + count_a, false,- {unpack(new_lines, start_b, start_b + count_b - 1)})+ --- Parinfer only moves parens and indentation, it shouldn't ever add or remove lines+ if #old_lines ~= #new_lines then+ api.nvim_buf_set_lines(bufnr, 0, -1, false, new_lines)+ return+ end+ for i, old in ipairs(old_lines) do+ local new = new_lines[i]+ if old ~= new then+ local prefix, suffix = common_ends(old, new)+ api.nvim_buf_set_text(bufnr, i - 1, prefix, i - 1, #old - suffix,+ {new:sub(prefix + 1, #new - suffix)})+ end end end