diff --git a/lua/jj/cmd/init.lua b/lua/jj/cmd/init.lua index 49e7ff9..4bd803c 100644 --- a/lua/jj/cmd/init.lua +++ b/lua/jj/cmd/init.lua @@ -514,6 +514,36 @@ function M.bookmark_delete() end) end +-- Jujutsu delete bookmark +function M.bookmark_track() + if not utils.ensure_jj() then + return + end + + local bookmarks = utils.get_untracked_bookmarks() + if #bookmarks == 0 then + utils.notify("No bookmarks to track") + return + end + + local log_open = terminal.is_log_buffer_open() + + vim.ui.select(bookmarks, { prompt = "Which bookmark do you want to track?" }, function(choice) + if choice then + runner.execute_command_async( + string.format("jj bookmark track %s --quiet", vim.fn.shellescape(choice)), + function() + utils.notify(string.format("Bookmark `%s` is now tracked.", choice)) + if log_open then + M.log() + end + end, + "Could not track bookmark" + ) + end + end) +end + -- Jujutsu undo function M.undo() if not utils.ensure_jj() then @@ -873,6 +903,8 @@ function M.j(args) M.bookmark_move() elseif remaining_args[1] == "delete" or remaining_args[1] == "d" then M.bookmark_delete() + elseif remaining_args[1] == "track" or remaining_args[1] == "t" then + M.bookmark_track() else terminal.run(cmd, M.terminal_keymaps()) end diff --git a/lua/jj/utils.lua b/lua/jj/utils.lua index 36e38a6..ff1f7a9 100644 --- a/lua/jj/utils.lua +++ b/lua/jj/utils.lua @@ -157,6 +157,39 @@ function M.get_all_bookmarks() return bookmarks end +--- Get all bookmarks in the repository, filters out deleted bookmarks +--- @return string[] List of bookmarks, or empty list if none found +function M.get_untracked_bookmarks() + -- Use a custom template to output just the bookmark names, one per line + -- This is more reliable than parsing the default output format + local bookmarks_output, success = runner.execute_command( + [[jj bookmark list -a -T 'if(self.remote() && !self.tracked(), name ++ if(!self.present(), " (deleted)", "") ++ "\n")']], + "Failed to get untracked bookmarks", + nil, + true + ) + + if not success or not bookmarks_output then + return {} + end + + -- Parse bookmarks from template output + local bookmarks = {} + local seen = {} + for line in bookmarks_output:gmatch("[^\n]+") do + local bookmark = vim.trim(line) + if bookmark ~= "" and not seen[bookmark] then + -- Skip bookmarks containing "Hint:" or "(deleted)" + if not bookmark:match("Hint:") and not bookmark:match("%(deleted%)") then + table.insert(bookmarks, bookmark) + seen[bookmark] = true + end + end + end + + return bookmarks +end + --- Get git remotes for the current jj repository --- @return {name: string, url: string}[]|nil A list of remotes with name and URL function M.get_remotes()