jujutsu file annotations for neovim (like blame)
4

Configure Feed

Select the types of activity you want to include in your feed.

support multiple annotate windows

Signed-off-by: Ron Shavit <me@ronshavit.com>

Ron Shavit (May 27, 2026, 3:48 PM +0300) 0ef2aa0a 05b40728

+51 -18
+1 -1
README.md
··· 30 30 }, 31 31 -- disable any mapping by setting it to `false` 32 32 mappings = { 33 - -- close the annotation window 33 + -- close the annotate window 34 34 close = "q", 35 35 }, 36 36 }
+50 -17
lua/jjannotate.lua
··· 16 16 }, 17 17 -- disable any mapping by setting it to `false` 18 18 mappings = { 19 - -- close the annotation window 19 + -- close the annotate window 20 20 close = "q", 21 21 }, 22 22 } ··· 44 44 ---@field annotate jjannotate.AnnotateResult 45 45 ---@field opts jjannotate.Opts 46 46 47 - local curr ---@type jjannotate.State | nil 47 + ---@type table<string, jjannotate.State?> 48 + local states = {} 48 49 49 50 ---@param path string 50 51 ---@return { win: integer, buf: integer} | nil ··· 218 219 end 219 220 end 220 221 221 - -- TODO: support multiple annotate windows 222 - curr = nil 222 + states[state.path] = nil 223 223 end, 224 224 }) 225 225 end ··· 240 240 opts = opts, 241 241 } 242 242 243 + vim.b[state.buf].jjannotate_path = path 243 244 vim.bo[state.buf].bufhidden = "wipe" 244 245 vim.bo[state.buf].buftype = "nofile" 245 246 vim.bo[state.buf].swapfile = false ··· 285 286 return state 286 287 end 287 288 289 + ---@param state jjannotate.State? 290 + ---@return boolean whether the window was closed 291 + local function close(state) 292 + if state and vim.api.nvim_win_is_valid(state.win) then 293 + vim.api.nvim_win_close(state.win, true) 294 + return true 295 + end 296 + return false 297 + end 298 + 288 299 local M = {} 289 300 290 301 ---@param path? string 291 302 function M.open(path) 292 - -- TODO: support multiple annotate windows 293 - if curr then 294 - update(curr, function() vim.api.nvim_set_current_win(curr.win) end) 303 + path = path or vim.fn.expand("%") 304 + 305 + local state = states[path] 306 + if state then 307 + update(state, function() vim.api.nvim_set_current_win(state.win) end) 295 308 return 296 309 end 297 - 298 - path = path or vim.fn.expand("%") 299 310 300 311 jj.annotate( 301 312 path, 302 313 vim.schedule_wrap(function(annotate) 303 314 local opts = vim.tbl_deep_extend("force", defaults, vim.g.jjannotate_opts or {}) 304 - curr = open(path, annotate, opts) 315 + states[path] = open(path, annotate, opts) 305 316 end) 306 317 ) 307 318 end 308 319 320 + --- Checks if any annotate window is open. If `path` is provided, checks if 321 + --- that path's annotate window is open. 322 + ---@param path? string 309 323 ---@return boolean 310 - function M.is_open() return curr and vim.api.nvim_win_is_valid(curr.win) or false end 324 + function M.is_open(path) 325 + path = path or vim.b.jjannotate_path 326 + if path then 327 + local state = states[path] 328 + return state and vim.api.nvim_win_is_valid(state.win) or false 329 + end 311 330 312 - ---@return boolean whether the window closed 313 - function M.close() 314 - if curr and M.is_open() then 315 - vim.api.nvim_win_close(curr.win, true) 316 - return true 331 + for _, state in pairs(states) do 332 + if vim.api.nvim_win_is_valid(state.win) then return true end 317 333 end 334 + 318 335 return false 319 336 end 320 337 338 + --- Closes all annotate windows. If `path` is provided, closes the annotate 339 + --- window for that path. 340 + ---@param path? string 341 + ---@return boolean whether any window(s) closed 342 + function M.close(path) 343 + path = path or vim.b.jjannotate_path 344 + if path then return close(states[path]) end 345 + 346 + local closed = 0 347 + for _, p in ipairs(vim.tbl_keys(states)) do 348 + if close(states[p]) then closed = closed + 1 end 349 + end 350 + return closed > 0 351 + end 352 + 321 353 ---@param path? string 322 354 function M.toggle(path) 323 - if not M.close() then M.open(path) end 355 + path = path or vim.b.jjannotate_path or vim.fn.expand("%") 356 + if not M.close(path) then M.open(path) end 324 357 end 325 358 326 359 return M