Something went wrong. Try again.
jujutsu file annotations for neovim (like blame)
Something went wrong. Try again.
5.8 kB · 159 lines
Lua
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160---@class jjannotate.Config---@field view jjannotate.Config.View---@field mappings jjannotate.Config.Mappings
---@class jjannotate.Config.View---@field collapse_repeating_lines boolean Whether to collapse repeating lines into a single line---@field highlight_changed_lines boolean Whether to highlight all lines changed by cursor's change id---@field highlight_current_change "none" | "bold" How to highlight lines related to current change---@field palette jjannotate.Config.Palette Controls the view's color palette---@field loading_delay number? Delay in ms before showing a "Loading..." placeholder while annotating
---@class jjannotate.Config.Mappings---@field close string | boolean Close the annotate window---@field show string | boolean Show revision under the cursor in a new tab---@field follow string | boolean Follow revision under the cursor and re-run annotate in a new tab---@field prev_change string | boolean Jump to the previous change---@field next_change string | boolean Jump to the next change
---@alias jjannotate.Config.Palette "auto" | jjannotate.Config.PaletteAuto | jjannotate.Config.ResolvedPalette--- * `auto`: Pick palette based on vim.o.background--- * `PaletteAuto`: Pick palette based on vim.o.background, with a color multiplier--- * `ResolvedPalette`: Manually specify the palette
---@class jjannotate.Config.PaletteAuto---@field auto boolean Pick palette based on vim.o.background---@field multiplier jjannotate.Config.Palette.Color Color multiplier applied to the auto-selected palette
---@class jjannotate.Config.ResolvedPalette---@field fg jjannotate.Config.Palette.Color---@field fg_bold jjannotate.Config.Palette.Color---@field bg jjannotate.Config.Palette.Color
---@class jjannotate.Config.Palette.Color---@field sat number---@field light number
local M = {}
local Window = require("jjannotate.window")local backend = require("jjannotate.backend")local cache = require("jjannotate.cache")local util = require("jjannotate.util")
---@param buf integer---@return jjannotate.RevisionRef?local function buf_revision(buf) local bufname = vim.api.nvim_buf_get_name(buf) return util.parse_uri("annotate", bufname)end
---@param info jjannotate.RepoInfo---@param revset string?---@return string?local function resolve_revision_sync(info, revset) if revset then return info.backend.resolve_revision(info.repo, revset) end local revision = buf_revision(0) return revision and revision.change_id or info.backend.resolve_revision(info.repo)end
--- Open an annotate window for `path` (or the current buffer).--- If already open, update and focus it.---@param path? string defaults to current buffer---@param revset? string defaults to "@"function M.open(path, revset) local info = path and backend.path_info(path) or backend.buf_info(0) if not info then local display_path = path or vim.api.nvim_buf_get_name(0) if display_path ~= "" then display_path = vim.fs.relpath(vim.uv.cwd(), display_path) or display_path end util.notify( string.format("`%s` is not in a jj or git repo", display_path), vim.log.levels.ERROR ) return end
info.backend.resolve_revision(info.repo, revset, function(change_id) vim.schedule(function() ---@type jjannotate.Revision local revision = vim.tbl_extend("force", info, { change_id = change_id }) local existing = cache:get_by_revision(revision) if existing then vim.api.nvim_create_autocmd("User", { pattern = "JjAnnotateUpdate:" .. existing.id, once = true, callback = function(args) local w = cache:get_by_id(args.data.id) if w then vim.api.nvim_set_current_win(w.annotate.win) end end, }) existing:update() return end
Window.open(revision) end) end)end
--- Check if any annotate window is open---@param path? string if provided, check if path's annotate window is open---@param revset? string defaults to "@", only used if `path` is provided---@return booleanfunction M.is_open(path, revset) if path then local info = backend.path_info(path) if not info then return false end local change_id = resolve_revision_sync(info, revset) if not change_id then return false end local w = cache:get_by_revision({ repo = info.repo, path = info.path, change_id = change_id }) return w and w:is_open() or false end
return vim.iter(vim.tbl_values(cache.wins)):any(function(w) return w:is_open() end)end
--- Close annotate window---@param path? string defaults to current buffer---@param revset? string defaults to "@"---@return boolean whether any window(s) closedfunction M.close(path, revset) local info = path and backend.path_info(path) or backend.buf_info(0) if not info then return false end local change_id = resolve_revision_sync(info, revset) if not change_id then return false end local w = cache:get_by_revision({ repo = info.repo, path = info.path, change_id = change_id }) if w then return w:close() end return falseend
--- Close all annotate windows---@return number number of windows closedfunction M.close_all() local count = 0 for _, w in pairs(cache.wins) do if w:close() then count = count + 1 end end return countend
--- Toggle annotate window---@param path? string defaults to current buffer---@param revset? string defaults to "@"function M.toggle(path, revset) if not M.close(path, revset) then M.open(path, revset) endend
---@param win_id integer---@return jjannotate.Window?function M.get_by_id(win_id) return cache:get_by_id(win_id) end
---@param revision jjannotate.RevisionRef---@return jjannotate.Window?function M.get_by_revision(revision) return cache:get_by_revision(revision) end
require("jjannotate.attach").setup()
return M