local runner = require("jj.core.runner") --- @class jj.utils local M = { executable_cache = {}, dependency_cache = {}, } -- No-op setup, but keep it for API consistency in case we need it later. function M.setup(_) end --- Cache for executable checks to avoid repeated system calls --- Check if an executable exists in PATH --- @param name string The name of the executable to check --- @return boolean True if executable exists, false otherwise function M.has_executable(name) if M.executable_cache[name] ~= nil then return M.executable_cache[name] end local exists = vim.fn.executable(name) == 1 M.executable_cache[name] = exists return exists end --- Check if the dependency is currently installed --- @param module string The dependency module --- @return boolean function M.has_dependency(module) if M.dependency_cache[module] ~= nil then return true end local exists, _ = pcall(require, module) if not exists then M.notify(string.format("Module %s not installed", module), vim.log.levels.ERROR) return false end return true end --- Clear the executable cache (useful for testing or if PATH changes) function M.clear_executable_cache() M.executable_cache = {} end --- Check if jj executable exists, show error if not --- @return boolean True if jj exists, false otherwise function M.ensure_jj() if not M.has_executable("jj") then M.notify("jj command not found", vim.log.levels.ERROR) return false end return true end --- Check if we're in a jj repository --- @return boolean True if in jj repo, false otherwise function M.is_jj_repo() if not M.ensure_jj() then return false end -- We require the runner here to avoid a circular dependency loop at startup local _, success = runner.execute_command("jj status") return success end --- Get jj repository root path --- @return string|nil The repository root path, or nil if not in a repo function M.get_jj_root() if not M.ensure_jj() then return nil end -- We require the runner here to avoid a circular dependency loop at startup local output, success = runner.execute_command("jj root") if success and output then return vim.trim(output) end return nil end --- Get a list of files modified in the current jj repository. --- @return string[] A list of modified file paths function M.get_modified_files() if not M.ensure_jj() then return {} end -- We require the runner here to avoid a circular dependency loop at startup local result, success = runner.execute_command("jj diff --name-only", "Error getting diff") if not success or not result then return {} end local files = {} -- Split the result into lines and add each file to the table for file in result:gmatch("[^\r\n]+") do table.insert(files, file) end return files end ---- Notify function to display messages with a title --- @param message string The message to display --- @param level? number The log level (default: INFO) function M.notify(message, level) level = level or vim.log.levels.INFO vim.notify(message, level, { title = "JJ", timeout = 3000 }) end return M