From 31d8285089447949d9a7421b1f2fc3b2ec46ae13 Mon Sep 17 00:00:00 2001 From: Ruben Garcia Date: Sat, 21 Feb 2026 21:32:58 +0100 Subject: [PATCH 1/5] refactor: extract common buffer load/cleanup logic into utils.with_buf Suppress autocommands during temporary buffer loads to prevent LSP clients from attaching to every scanned file. Extract the repeated pattern (bufadd, bufload, filetype set, cleanup) from ts.lua, usages.lua, and rename.lua into a shared utils.with_buf() helper. --- lua/pytrize/rename.lua | 42 ++++++++++++++++++------------------------ lua/pytrize/ts.lua | 27 +++++++++++---------------- lua/pytrize/usages.lua | 39 ++++++++++++++------------------------- lua/pytrize/utils.lua | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 65 deletions(-) diff --git a/lua/pytrize/rename.lua b/lua/pytrize/rename.lua index 9a51455..48ff212 100644 --- a/lua/pytrize/rename.lua +++ b/lua/pytrize/rename.lua @@ -4,6 +4,7 @@ local ts = vim.treesitter local warn = require("pytrize.warn").warn local paths = require("pytrize.paths") local ts_utils = require("pytrize.ts") +local utils = require("pytrize.utils") local function hrtime() return (vim.uv or vim.loop).hrtime() @@ -256,34 +257,27 @@ local function rename(old_name, new_name) local files_changed = 0 for _, filepath in ipairs(files_to_process) do - local existing_bufnr = vim.fn.bufnr(filepath) - local was_loaded = existing_bufnr ~= -1 and vim.fn.bufloaded(existing_bufnr) == 1 - - local bufnr = vim.fn.bufadd(filepath) - if not was_loaded then - vim.fn.bufload(bufnr) - end + local abort = false + utils.with_buf(filepath, function(bufnr) + local positions = find_rename_positions(bufnr, old_name) + if positions == nil then + abort = true + return + end - vim.api.nvim_set_option_value("filetype", "python", { buf = bufnr }) + if #positions > 0 then + local count = apply_renames(bufnr, positions, new_name) + total_replacements = total_replacements + count + files_changed = files_changed + 1 - local positions = find_rename_positions(bufnr, old_name) - if positions == nil then + vim.api.nvim_buf_call(bufnr, function() + vim.cmd("write") + end) + end + end) + if abort then return end - - if #positions > 0 then - local count = apply_renames(bufnr, positions, new_name) - total_replacements = total_replacements + count - files_changed = files_changed + 1 - - vim.api.nvim_buf_call(bufnr, function() - vim.cmd("write") - end) - end - - if not was_loaded then - vim.api.nvim_buf_delete(bufnr, { force = false }) - end end local t_end = hrtime() diff --git a/lua/pytrize/ts.lua b/lua/pytrize/ts.lua index ab76012..84a15fc 100644 --- a/lua/pytrize/ts.lua +++ b/lua/pytrize/ts.lua @@ -1,6 +1,7 @@ local M = {} local ts = vim.treesitter +local utils = require("pytrize.utils") M.walk = function(node, callback) callback(node) @@ -88,26 +89,20 @@ M.scan_fixtures = function(filepath) return scan_cache[filepath] end - local existing_bufnr = vim.fn.bufnr(filepath) - local was_loaded = existing_bufnr ~= -1 and vim.fn.bufloaded(existing_bufnr) == 1 - - local bufnr = vim.fn.bufadd(filepath) - if not was_loaded then - vim.fn.bufload(bufnr) - end - - vim.api.nvim_set_option_value("filetype", "python", { buf = bufnr }) - - local ok, defs = pcall(M.get_fixture_defs, bufnr) - - if not was_loaded then - vim.api.nvim_buf_delete(bufnr, { force = true }) - end + local result = utils.with_buf(filepath, function(bufnr) + local ok, defs = pcall(M.get_fixture_defs, bufnr) + if not ok then + return nil + end + return defs + end, { force_delete = true }) - if not ok then + if result == nil then return {} end + local defs = result + local fixtures = {} for _, def in ipairs(defs) do local row, col = def.func_node:start() diff --git a/lua/pytrize/usages.lua b/lua/pytrize/usages.lua index 6442401..af1ca69 100644 --- a/lua/pytrize/usages.lua +++ b/lua/pytrize/usages.lua @@ -4,6 +4,7 @@ local ts = vim.treesitter local warn = require("pytrize.warn").warn local paths = require("pytrize.paths") local ts_utils = require("pytrize.ts") +local utils = require("pytrize.utils") local function find_python_files(root_dir, name) return vim.fn.systemlist(string.format('grep -rl --include="*.py" "%s" "%s"', vim.fn.escape(name, '"\\'), root_dir)) @@ -167,31 +168,19 @@ local find_all_usages = function(fixture_name, root_dir) local items = {} for _, filepath in ipairs(py_files) do - local existing_bufnr = vim.fn.bufnr(filepath) - local was_loaded = existing_bufnr ~= -1 and vim.fn.bufloaded(existing_bufnr) == 1 - - local bufnr = vim.fn.bufadd(filepath) - if not was_loaded then - vim.fn.bufload(bufnr) - end - - vim.api.nvim_set_option_value("filetype", "python", { buf = bufnr }) - - local positions = find_usage_positions(bufnr, fixture_name) - local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) - - for _, pos in ipairs(positions) do - table.insert(items, { - filename = filepath, - lnum = pos.row + 1, - col = pos.col_start + 1, - text = lines[pos.row + 1] or "", - }) - end - - if not was_loaded then - vim.api.nvim_buf_delete(bufnr, { force = false }) - end + utils.with_buf(filepath, function(bufnr) + local positions = find_usage_positions(bufnr, fixture_name) + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false) + + for _, pos in ipairs(positions) do + table.insert(items, { + filename = filepath, + lnum = pos.row + 1, + col = pos.col_start + 1, + text = lines[pos.row + 1] or "", + }) + end + end) end return items diff --git a/lua/pytrize/utils.lua b/lua/pytrize/utils.lua index 4d02fea..8780fed 100644 --- a/lua/pytrize/utils.lua +++ b/lua/pytrize/utils.lua @@ -16,4 +16,36 @@ M.max = function(a, b) end end +--- Temporarily load a Python buffer for `filepath`, call `fn(bufnr)`, then +--- clean up if the buffer was not already loaded. Autocommands are suppressed +--- during the load so that LSP clients (and other plugins) do not attach to +--- ephemeral buffers. +--- +--- @param filepath string Absolute path to a Python file. +--- @param fn fun(bufnr: integer): any Callback that receives the buffer number. +--- @param opts? { force_delete?: boolean } Options for cleanup (default: force_delete = false). +--- @return any The return value of `fn`. +M.with_buf = function(filepath, fn, opts) + opts = opts or {} + local existing_bufnr = vim.fn.bufnr(filepath) + local was_loaded = existing_bufnr ~= -1 and vim.fn.bufloaded(existing_bufnr) == 1 + + local bufnr = vim.fn.bufadd(filepath) + if not was_loaded then + local saved_eventignore = vim.o.eventignore + vim.o.eventignore = "all" + vim.fn.bufload(bufnr) + vim.api.nvim_set_option_value("filetype", "python", { buf = bufnr }) + vim.o.eventignore = saved_eventignore + end + + local result = fn(bufnr) + + if not was_loaded then + vim.api.nvim_buf_delete(bufnr, { force = opts.force_delete or false }) + end + + return result +end + return M From a024c7e97ea91942654252690faf75c53f53309d Mon Sep 17 00:00:00 2001 From: Ruben Garcia Date: Sat, 21 Feb 2026 21:36:06 +0100 Subject: [PATCH 2/5] fix: suppress file path echo when jumping to fixture definition ':edit' prints the file info message (path, line count, bytes) on every jump. Use ':silent edit' to suppress it. --- lua/pytrize/jump/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/pytrize/jump/util.lua b/lua/pytrize/jump/util.lua index 3a36ca2..c3862f5 100644 --- a/lua/pytrize/jump/util.lua +++ b/lua/pytrize/jump/util.lua @@ -1,7 +1,7 @@ local M = {} M.open_file = function(file) - vim.cmd("edit " .. file) + vim.cmd("silent edit " .. file) end return M From bcdbc0f02e855792beb9ef9d260cccfa030823d3 Mon Sep 17 00:00:00 2001 From: Ruben Garcia Date: Sat, 21 Feb 2026 21:43:17 +0100 Subject: [PATCH 3/5] fix: suppress file info message when jumping to a file ':silent edit' only suppresses Vimscript-level messages. Neovim's file info message ("file.py" 42L, 1234B) is printed by Neovim's internals and is controlled by the 'F' flag in 'shortmess'. Temporarily append it around ':edit' and restore the original value afterward. --- lua/pytrize/jump/util.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/pytrize/jump/util.lua b/lua/pytrize/jump/util.lua index c3862f5..ec8532f 100644 --- a/lua/pytrize/jump/util.lua +++ b/lua/pytrize/jump/util.lua @@ -1,7 +1,10 @@ local M = {} M.open_file = function(file) - vim.cmd("silent edit " .. file) + local saved = vim.o.shortmess + vim.opt.shortmess:append("F") + vim.cmd("edit " .. file) + vim.o.shortmess = saved end return M From 926b685612ee71bb55d05669f8ee03d34d9d434f Mon Sep 17 00:00:00 2001 From: Ruben Garcia Date: Sat, 21 Feb 2026 21:54:29 +0100 Subject: [PATCH 4/5] fix: use vim.fn.execute() to suppress file info on jump Both ':silent edit' and temporarily setting shortmess+=F failed because Neovim's C-level fileinfo message can be displayed after the Lua frame completes, by which point shortmess has been restored and :silent no longer applies. vim.fn.execute() is backed by :redir, which captures all output at the channel level before it reaches the command line. This gives reliable suppression regardless of message timing. Also adds fnameescape() for correct handling of paths with special characters. --- lua/pytrize/jump/util.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lua/pytrize/jump/util.lua b/lua/pytrize/jump/util.lua index ec8532f..b96780a 100644 --- a/lua/pytrize/jump/util.lua +++ b/lua/pytrize/jump/util.lua @@ -1,10 +1,7 @@ local M = {} M.open_file = function(file) - local saved = vim.o.shortmess - vim.opt.shortmess:append("F") - vim.cmd("edit " .. file) - vim.o.shortmess = saved + vim.fn.execute("edit " .. vim.fn.fnameescape(file)) end return M From e9812fe9421d02db3d4917ceb5decd0b27147464 Mon Sep 17 00:00:00 2001 From: Ruben Garcia Date: Sat, 21 Feb 2026 22:10:55 +0100 Subject: [PATCH 5/5] fix: suppress file info message printed by bufload during scanning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit eventignore = 'all' only suppresses autocommands. It does not suppress the C-level file-reading message ('path/to/file' NL, NB) that bufload() emits via open_buffer() → readfile(). Wrap the bufload call in vim.fn.execute() which uses :redir internally to capture all output at the channel level before it reaches the command line. --- lua/pytrize/utils.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/pytrize/utils.lua b/lua/pytrize/utils.lua index 8780fed..42a572d 100644 --- a/lua/pytrize/utils.lua +++ b/lua/pytrize/utils.lua @@ -34,7 +34,7 @@ M.with_buf = function(filepath, fn, opts) if not was_loaded then local saved_eventignore = vim.o.eventignore vim.o.eventignore = "all" - vim.fn.bufload(bufnr) + vim.fn.execute("call bufload(" .. bufnr .. ")") vim.api.nvim_set_option_value("filetype", "python", { buf = bufnr }) vim.o.eventignore = saved_eventignore end