Something went wrong. Try again.
mini.diff source for jujutsu
Something went wrong. Try again.
3.2 kB · 115 lines
Lua
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116---@class mini.diff.jj.CacheEntry---@field fs_event uv.uv_fs_event_t?---@field timer uv.uv_timer_t?
local MiniDiff = require("mini.diff")
---@overload fun(args: string[], cwd: string): vim.SystemCompleted---@overload fun(args: string[], cwd: string, on_exit: fun(out: vim.SystemCompleted)): vim.SystemObj---@param args string[]---@param cwd string---@param on_exit? fun(out: vim.SystemCompleted)local function jj(args, cwd, on_exit) local obj = vim.system( vim.list_extend({ "jj", "--ignore-working-copy" }, args), { text = true, cwd = cwd }, on_exit ) if on_exit then return obj else return obj:wait() endend
---@type table<number, mini.diff.jj.CacheEntry?>local cache = {}
---@param buf_id integer---@return stringlocal function buf_path(buf_id) return vim.uv.fs_realpath(vim.api.nvim_buf_get_name(buf_id)) or "" end
---@param cwd string---@return string?local function repo_root(cwd) local result = jj({ "root" }, cwd) if result.code == 0 and result.stdout ~= nil then return vim.trim(result.stdout) endend
local function invalidate(buf_id) local entry = cache[buf_id] if entry then if entry.fs_event then entry.fs_event:stop() end if entry.timer then entry.timer:stop() end cache[buf_id] = nil endend
---@param buf_id integer---@param file_path string---@param cwd stringlocal function set_ref_text(buf_id, file_path, cwd) local stat = vim.uv.fs_stat(cwd) if not stat or stat.type ~= "directory" then return end
---@param text string | string[] | nil local function set_text(text) vim.schedule(function() MiniDiff.set_ref_text(buf_id, text) end) end
jj({ "file", "show", "-r", "@-", file_path }, cwd, function(res) if res.code == 0 then return set_text(res.stdout) end
-- Ignore if file is untracked in `@`. jj({ "file", "list", "-r", "@", file_path }, cwd, function(list) local tracked = list.code == 0 and list.stdout ~= nil and vim.trim(list.stdout) ~= "" set_text(tracked and "" or nil) end) end)end
---@param buf_id integer---@param file_path string---@return boolean?local function watch(buf_id, file_path) local cwd = vim.fs.dirname(file_path) local repo = repo_root(cwd) if not repo then return false end
local watch_path = vim.fs.joinpath(repo, ".jj/working_copy") local fs_event = vim.uv.new_fs_event() local timer = vim.uv.new_timer()
local function tick() if not timer then return end timer:stop() timer:start(50, 0, function() set_ref_text(buf_id, file_path, cwd) end) end
local function on_change(_, filename) if filename == "checkout" and timer then tick() end end
if fs_event then fs_event:start(watch_path, {}, on_change) end
invalidate(buf_id) cache[buf_id] = { fs_event = fs_event, timer = timer }
set_ref_text(buf_id, file_path, cwd)
return trueend
---@param buf_id integer---@return boolean?local function attach(buf_id) if cache[buf_id] then return false end local path = buf_path(buf_id) if path == "" then return false end return watch(buf_id, path)end
---@param buf_id integerlocal function detach(buf_id) invalidate(buf_id) end
return { name = "jj", attach = attach, detach = detach }