diff --git a/lua/neogit/buffers/status/ui.lua b/lua/neogit/buffers/status/ui.lua index 0452bdeea..9accb8c10 100755 --- a/lua/neogit/buffers/status/ui.lua +++ b/lua/neogit/buffers/status/ui.lua @@ -363,75 +363,100 @@ local SectionItemCommit = Component.new(function(item) local virtual_text - -- Render author and date in margin, if visible + -- Render margin, if visible if state.get({ "margin", "visibility" }, false) then - local margin_date_style = state.get({ "margin", "date_style" }, 1) - local details = state.get({ "margin", "details" }, false) - - local date - local rel_date - local date_width = 10 - local clamp_width = 30 -- to avoid having too much space when relative date is short - - -- Render date - if item.commit.rel_date:match(" years?,") then - rel_date, _ = item.commit.rel_date:gsub(" years?,", "y") - rel_date = rel_date .. " " - elseif item.commit.rel_date:match("^%d ") then - rel_date = " " .. item.commit.rel_date - else - rel_date = item.commit.rel_date - end + local is_shortstat = state.get({ "margin", "shortstat" }, false) + + if is_shortstat then + local cli_shortstat = item.shortstat + local files_changed + local insertions + local deletions + + files_changed = cli_shortstat:match("^ (%d+) files?") + files_changed = util.str_min_width(files_changed, 3, nil, { mode = "insert" }) + insertions = cli_shortstat:match("(%d+) insertions?") + insertions = util.str_min_width(insertions and insertions .. "+" or " ", 5, nil, { mode = "insert" }) + deletions = cli_shortstat:match("(%d+) deletions?") + deletions = util.str_min_width(deletions and deletions .. "-" or " ", 5, nil, { mode = "insert" }) + + virtual_text = { + { " ", "Constant" }, + { insertions, "NeogitDiffAdditions" }, + { " ", "Constant" }, + { deletions, "NeogitDiffDeletions" }, + { " ", "Constant" }, + { files_changed, "NeogitSubtleText" }, + } + else -- Author & date margin + local margin_date_style = state.get({ "margin", "date_style" }, 1) + local details = state.get({ "margin", "details" }, false) + + local date + local rel_date + local date_width = 10 + local clamp_width = 30 -- to avoid having too much space when relative date is short + + -- Render date + if item.commit.rel_date:match(" years?,") then + rel_date, _ = item.commit.rel_date:gsub(" years?,", "y") + rel_date = rel_date .. " " + elseif item.commit.rel_date:match("^%d ") then + rel_date = " " .. item.commit.rel_date + else + rel_date = item.commit.rel_date + end - if margin_date_style == 1 then -- relative date (short) - local unpacked = vim.split(rel_date, " ") + if margin_date_style == 1 then -- relative date (short) + local unpacked = vim.split(rel_date, " ") - -- above, we added a space if the rel_date started with a single number - -- we get the last two elements to deal with that - local date_number = unpacked[#unpacked - 1] - local date_quantifier = unpacked[#unpacked] - if date_quantifier:match("months?") then - date_quantifier = date_quantifier:gsub("m", "M") -- to distinguish from minutes - end + -- above, we added a space if the rel_date started with a single number + -- we get the last two elements to deal with that + local date_number = unpacked[#unpacked - 1] + local date_quantifier = unpacked[#unpacked] + if date_quantifier:match("months?") then + date_quantifier = date_quantifier:gsub("m", "M") -- to distinguish from minutes + end - -- add back the space if we have a single number - local left_pad - if #unpacked > 2 then - left_pad = " " - else - left_pad = "" + -- add back the space if we have a single number + local left_pad + if #unpacked > 2 then + left_pad = " " + else + left_pad = "" + end + + date = left_pad .. date_number .. date_quantifier:sub(1, 1) + date_width = 3 + clamp_width = 23 + elseif margin_date_style == 2 then -- relative date (long) + date = rel_date + date_width = 10 + else -- local iso date + if config.values.log_date_format == nil then + -- we get the unix date to be able to convert the date to the local timezone + date = os.date("%Y-%m-%d %H:%M", item.commit.unix_date) + date_width = 16 -- TODO: what should the width be here? + else + date = item.commit.log_date + date_width = 16 + end end - date = left_pad .. date_number .. date_quantifier:sub(1, 1) - date_width = 3 - clamp_width = 23 - elseif margin_date_style == 2 then -- relative date (long) - date = rel_date - date_width = 10 - else -- local iso date - if config.values.log_date_format == nil then - -- we get the unix date to be able to convert the date to the local timezone - date = os.date("%Y-%m-%d %H:%M", item.commit.unix_date) - date_width = 16 -- TODO: what should the width be here? - else - date = item.commit.log_date - date_width = 16 + local author_table = { "" } + if details then + author_table = { + util.str_clamp(item.commit.author_name, clamp_width - (#date > date_width and #date or date_width)), + "NeogitGraphAuthor", + } end - end - local author_table = { "" } - if details then - author_table = { - util.str_clamp(item.commit.author_name, clamp_width - (#date > date_width and #date or date_width)), - "NeogitGraphAuthor", + virtual_text = { + { " ", "Constant" }, + author_table, + { util.str_min_width(date, date_width), "Special" }, } end - - virtual_text = { - { " ", "Constant" }, - author_table, - { util.str_min_width(date, date_width), "Special" }, - } end return row( diff --git a/lua/neogit/lib/git/cli.lua b/lua/neogit/lib/git/cli.lua index 315246e41..d65c78960 100644 --- a/lua/neogit/lib/git/cli.lua +++ b/lua/neogit/lib/git/cli.lua @@ -41,6 +41,7 @@ local runner = require("neogit.runner") ---@class GitCommandShow: GitCommandBuilder ---@field stat self +---@field shortstat self ---@field oneline self ---@field no_patch self ---@field format fun(string): self @@ -396,6 +397,7 @@ local configurations = { show = config { flags = { stat = "--stat", + shortstat = "--shortstat", oneline = "--oneline", no_patch = "--no-patch", }, diff --git a/lua/neogit/lib/git/log.lua b/lua/neogit/lib/git/log.lua index 54ac725b7..a6a0e3314 100644 --- a/lua/neogit/lib/git/log.lua +++ b/lua/neogit/lib/git/log.lua @@ -462,11 +462,18 @@ function M.present_commit(commit) return end + local is_shortstat = state.get({ "margin", "shortstat" }, false) + local shortstat + if is_shortstat then + shortstat = git.cli.show.format("").shortstat.args(commit.oid).call().stdout[1] + end + return { name = string.format("%s %s", commit.abbreviated_commit, commit.subject or ""), decoration = M.branch_info(commit.ref_name, git.remote.list()), oid = commit.oid, commit = commit, + shortstat = shortstat, } end diff --git a/lua/neogit/lib/util.lua b/lua/neogit/lib/util.lua index 46c9942f6..02c15dc1b 100644 --- a/lua/neogit/lib/util.lua +++ b/lua/neogit/lib/util.lua @@ -197,13 +197,21 @@ end -- return res -- end -function M.str_min_width(str, len, sep) +---@param opts table? If { mode = 'append' }, adds spaces to the end of `str`. If { mode = 'insert' }, adds spaces to the beginning. +function M.str_min_width(str, len, sep, opts) + local mode = (type(opts) == "table" and opts.mode) or "append" local length = vim.fn.strdisplaywidth(str) if length > len then return str end - return str .. string.rep(sep or " ", len - length) + if mode == "append" then + -- Add spaces to the right of str + return str .. string.rep(sep or " ", len - length) + else + -- Add spaces to the left of str + return string.rep(sep or " ", len - length) .. str + end end function M.slice(tbl, s, e) @@ -255,8 +263,10 @@ function M.str_truncate(str, max_length, trailing) return str end -function M.str_clamp(str, len, sep) - return M.str_min_width(M.str_truncate(str, len - 1, ""), len, sep or " ") +---@param opts table? If { mode = 'append' }, adds spaces to the end of `str`. If { mode = 'insert' }, adds spaces to the beginning. +function M.str_clamp(str, len, sep, opts) + local opts = (type(opts) == "table" and opts.mode) or { mode = "append" } + return M.str_min_width(M.str_truncate(str, len - 1, ""), len, sep or " ", opts) end --- Splits a string every n characters, respecting word boundaries diff --git a/lua/neogit/popups/margin/actions.lua b/lua/neogit/popups/margin/actions.lua index 8ab733736..df2df5079 100644 --- a/lua/neogit/popups/margin/actions.lua +++ b/lua/neogit/popups/margin/actions.lua @@ -29,4 +29,10 @@ function M.toggle_details() state.set({ "margin", "details" }, new_details) end +function M.toggle_shortstat() + local shortstat = state.get({ "margin", "shortstat" }, false) + local new_shortstat = not shortstat + state.set({ "margin", "shortstat" }, new_shortstat) +end + return M diff --git a/lua/neogit/popups/margin/init.lua b/lua/neogit/popups/margin/init.lua index 154d4f6b4..8ac61ed91 100644 --- a/lua/neogit/popups/margin/init.lua +++ b/lua/neogit/popups/margin/init.lua @@ -50,7 +50,7 @@ function M.create(env) :action("L", "toggle visibility", actions.toggle_visibility, { persist_popup = true }) :action("l", "cycle style", actions.cycle_date_style, { persist_popup = true }) :action("d", "toggle details", actions.toggle_details, { persist_popup = true }) - :action("x", "toggle shortstat", actions.log_current, { persist_popup = true }) + :action("x", "toggle shortstat", actions.toggle_shortstat, { persist_popup = true }) :build() p:show()