diff --git a/lua/pytrize/jump/util.lua b/lua/pytrize/jump/util.lua index 3a36ca2..b96780a 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.fn.execute("edit " .. vim.fn.fnameescape(file)) end return M 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..42a572d 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.execute("call 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