fix(picker): Reformat the file history picker (#127)

This commit is contained in:
Nicolas GB
2026-06-18 20:24:29 +02:00
committed by GitHub
parent 30d740024d
commit cffc74128a
2 changed files with 32 additions and 79 deletions
+24 -43
View File
@@ -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
+8 -36
View File
@@ -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