43d88fd

Branches > main > 43d88fd > files

Nvim - Stop parinfer edits from flickering highlights

Grahp, 2026-10-25

Commit: 43d88fd615f1b54529377b3cdba984eacfd0d0f5
Parent: 7e90c32

1 changed file:

nvim/lua/parinfer/plugin.lua modified (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