From cffc74128a80398469085e01ff2e4001e330b800 Mon Sep 17 00:00:00 2001 From: Nicolas GB Date: Thu, 18 Jun 2026 20:24:29 +0200 Subject: [PATCH] fix(picker): Reformat the file history picker (#127) --- lua/jj/picker.lua | 67 ++++++++++++++-------------------------- lua/jj/picker/snacks.lua | 44 +++++--------------------- 2 files changed, 32 insertions(+), 79 deletions(-) diff --git a/lua/jj/picker.lua b/lua/jj/picker.lua index aa989bb..1c57033 100644 --- a/lua/jj/picker.lua +++ b/lua/jj/picker.lua @@ -17,11 +17,9 @@ local parser = require("jj.core.parser") --- @class jj.picker.log_line --- @field text string The text to display in the picker ---- @field symbol string The symbol of the log entry --- @field rev string The revision of the log entry --- @field author string The author of the log entry --- @field time string The time of the log entry ---- @field commit_id string The commit id of the log entry --- @field description string The description of the log entry --- @field preview_cmd string[] The command used to preview the item --- @field confirm_action string The default picker action for the item @@ -160,13 +158,17 @@ function M.status() end end ----Parse jj log oneline +--- Parse file history with a stable no-graph template. ---@param file_path string The path of the file to log ---@return jj.picker.log_line[]|nil A list of log lines or nil if not in a jj repo local function log_history(file_path) - local format = - "jj --no-pager log %s -r 'all()' -T builtin_log_oneline --config 'template-aliases.\"format_timestamp(timestamp)\"=timestamp'" - local output, ok = runner.execute_command(string.format(format, file_path)) + local format = table.concat({ + "jj --no-pager log %s", + "-r 'all() ~ @'", + "--no-graph", + [[ -T 'change_id.shortest() ++ "\t" ++ coalesce(author.name(), "(no author)") ++ "\t" ++ committer.timestamp() ++ "\t" ++ coalesce(description.first_line(), "(no description)") ++ "\n"' ]], + }, " ") + local output, ok = runner.execute_command(string.format(format, vim.fn.shellescape(file_path))) if not ok then return end @@ -179,45 +181,24 @@ local function log_history(file_path) local lines = vim.split(output, "\n", { trimempty = true }) for _, line in ipairs(lines) do - -- Skip root line and elided revisions - local not_empty = line:match("%S") - local root = line:match("root%(%)") - local elided = line:match("~%s*%(elided revisions%)%s*$") + local parts = vim.split(line, "\t", { plain = true }) + if #parts >= 4 then + local rev = parts[1] + local author = parts[2] + local time_part = parts[3] + local description = table.concat(vim.list_slice(parts, 4), "\t") + local short_time = time_part:match("^%d%d%d%d%-%d%d%-%d%d") or time_part - if not_empty and not root and not elided then - -- Pattern: [symbol] [rev] [author] [time] [commit_id] [description] - -- Example: @ w ngou0210 10 seconds ago e (no description set) - -- Split at the first double space which signifies the end of the symbols - local first_spaces = line:find("%s%s") - if not first_spaces then - goto continue - end - -- Split the line into parts - -- The first part is the symbol, the second part is the revision, the third part is the author, - local symbol = line:sub(1, first_spaces - 1) - local rest_of_line = line:sub(first_spaces + 1) - - local rev, author, time_part, commit_id, description = - rest_of_line:match("^%s*(%S+)%s+(%S+)%s+(.-)%s+([%w]+)%s+(.*)$") - - -- It does not make much sense to show the current commit - if symbol and symbol ~= "@" then - if rev and author and commit_id then - table.insert(file_history, { - symbol = symbol or "", - rev = rev, - author = author, - time = time_part or "", - commit_id = commit_id, - description = description or "", - text = line, - preview_cmd = { "jj", "--no-pager", "diff", file_path, "-r", rev, "--stat", "--git" }, - confirm_action = "edit_revision", - }) - end - end + table.insert(file_history, { + rev = rev, + author = author, + time = time_part, + description = description, + text = string.format("%s %s %s %s", rev, author, short_time, description), + preview_cmd = { "jj", "--no-pager", "diff", file_path, "-r", rev, "--stat", "--git" }, + confirm_action = "edit_revision", + }) end - ::continue:: end return file_history diff --git a/lua/jj/picker/snacks.lua b/lua/jj/picker/snacks.lua index def94c4..285a13b 100644 --- a/lua/jj/picker/snacks.lua +++ b/lua/jj/picker/snacks.lua @@ -125,45 +125,17 @@ local function format_jj_log(item) local a = Snacks.picker.util.align local ret = {} ---@type snacks.picker.Highlight[] - -- Add symbol (if available) and revision - if item.symbol and item.symbol ~= "" then - ret[#ret + 1] = { a(item.symbol, 1, { truncate = true }), "SnacksPickerGitMsg" } - else - ret[#ret + 1] = { "?", "SnacksPickerGitMsg" } - end - + local rev = item.rev or "unknown" + ret[#ret + 1] = { a(rev, 12, { truncate = true }), "SnacksPickerGitBreaking" } ret[#ret + 1] = { " " } - local rev = item.rev or "unknown" - -- INFO: This highlight is kind of a nice hack to avoid doing my own highlighs for the moment - --- At some point i'll probably do mines - ret[#ret + 1] = { a(rev, 4, { truncate = true }), "SnacksPickerGitBreaking" } - if #rev >= 4 then - ret[#ret + 1] = { " " } - end + local author = item.author or "(no author)" + ret[#ret + 1] = { a(author, 16, { truncate = true }), "Identifier" } + ret[#ret + 1] = { " " } - if item.author then - ret[#ret + 1] = { a(item.author, 8, { truncate = true }), "Identifier" } - if #item.author >= 8 then - ret[#ret + 1] = { " " } - end - end - - if item.time then - local year, month, day = item.time:match("(%d+)-(%d+)-(%d+)") - local formatted = string.format("%s-%s-%s", year, day, month) - ret[#ret + 1] = { a(formatted, 10), "SnacksPickerGitDate" } - if #formatted >= 10 then - ret[#ret + 1] = { " " } - end - end - - if item.commit_id then - ret[#ret + 1] = { a(item.commit_id, 10, { truncate = true }), "SnacksPickerGitCommit" } - if #item.commit_id >= 4 then - ret[#ret + 1] = { " " } - end - end + local formatted_time = item.time and (item.time:match("^%d%d%d%d%-%d%d%-%d%d") or item.time) or "" + ret[#ret + 1] = { a(formatted_time, 10, { truncate = true }), "SnacksPickerGitDate" } + ret[#ret + 1] = { " " } append_description_hl(ret, item.description) return ret