From 7bf4e53f9fb1fa02bfbc933313dcbb968e22af7e Mon Sep 17 00:00:00 2001 From: Lucas Adelino Date: Sun, 27 Apr 2025 15:47:43 -0400 Subject: [PATCH 01/11] feat(margin): add margin popup --- lua/neogit/buffers/status/actions.lua | 10 ++++ lua/neogit/buffers/status/init.lua | 2 + lua/neogit/buffers/status/ui.lua | 80 ++++++++++++++++++++++++++- lua/neogit/config.lua | 2 + lua/neogit/lib/git/log.lua | 2 + lua/neogit/popups/help/actions.lua | 3 + lua/neogit/popups/margin/actions.lua | 25 +++++++++ lua/neogit/popups/margin/init.lua | 49 ++++++++++++++++ 8 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 lua/neogit/popups/margin/actions.lua create mode 100644 lua/neogit/popups/margin/init.lua diff --git a/lua/neogit/buffers/status/actions.lua b/lua/neogit/buffers/status/actions.lua index 52bfdd76b..ef21db8cb 100644 --- a/lua/neogit/buffers/status/actions.lua +++ b/lua/neogit/buffers/status/actions.lua @@ -445,6 +445,11 @@ M.v_log_popup = function(_self) return popups.open("log") end +---@param _self StatusBuffer +M.v_margin_popup = function(_self) + return popups.open("margin") +end + ---@param _self StatusBuffer M.v_worktree_popup = function(_self) return popups.open("worktree") @@ -1408,6 +1413,11 @@ M.n_log_popup = function(_self) return popups.open("log") end +---@param _self StatusBuffer +M.n_margin_popup = function(_self) + return popups.open("margin") +end + ---@param _self StatusBuffer M.n_worktree_popup = function(_self) return popups.open("worktree") diff --git a/lua/neogit/buffers/status/init.lua b/lua/neogit/buffers/status/init.lua index fbfb97ab7..918fb356b 100644 --- a/lua/neogit/buffers/status/init.lua +++ b/lua/neogit/buffers/status/init.lua @@ -128,6 +128,7 @@ function M:open(kind) [popups.mapping_for("HelpPopup")] = self:_action("v_help_popup"), [popups.mapping_for("IgnorePopup")] = self:_action("v_ignore_popup"), [popups.mapping_for("LogPopup")] = self:_action("v_log_popup"), + [popups.mapping_for("MarginPopup")] = self:_action("v_margin_popup"), [popups.mapping_for("MergePopup")] = self:_action("v_merge_popup"), [popups.mapping_for("PullPopup")] = self:_action("v_pull_popup"), [popups.mapping_for("PushPopup")] = self:_action("v_push_popup"), @@ -182,6 +183,7 @@ function M:open(kind) [popups.mapping_for("HelpPopup")] = self:_action("n_help_popup"), [popups.mapping_for("IgnorePopup")] = self:_action("n_ignore_popup"), [popups.mapping_for("LogPopup")] = self:_action("n_log_popup"), + [popups.mapping_for("MarginPopup")] = self:_action("n_margin_popup"), [popups.mapping_for("MergePopup")] = self:_action("n_merge_popup"), [popups.mapping_for("PullPopup")] = self:_action("n_pull_popup"), [popups.mapping_for("PushPopup")] = self:_action("n_push_popup"), diff --git a/lua/neogit/buffers/status/ui.lua b/lua/neogit/buffers/status/ui.lua index 1efc135f6..724cc11aa 100755 --- a/lua/neogit/buffers/status/ui.lua +++ b/lua/neogit/buffers/status/ui.lua @@ -2,6 +2,7 @@ local Ui = require("neogit.lib.ui") local Component = require("neogit.lib.ui.component") local util = require("neogit.lib.util") local common = require("neogit.buffers.common") +local config = require("neogit.config") local a = require("plenary.async") local col = Ui.col @@ -359,6 +360,78 @@ local SectionItemCommit = Component.new(function(item) end end + -- Render date + if item.commit.rel_date:match(" years?,") then + item.commit.rel_date, _ = item.commit.rel_date:gsub(" years?,", "y") + item.commit.rel_date = item.commit.rel_date .. " " + elseif item.commit.rel_date:match("^%d ") then + item.commit.rel_date = " " .. item.commit.rel_date + end + + -- Render author and date in margin + local state = require("neogit.lib.state") + local visibility = state.get({ "margin", "visibility" }, false) + local margin_date_style = state.get({ "margin", "date_style" }, 1) + local details = state.get({ "margin", "details" }, false) + local date + local author_table = { "" } + local date_table + local date_width = 10 + local clamp_width = 30 -- to avoid having too much space when relative date is short + + if margin_date_style == 1 then -- relative date (short) + local unpacked = vim.split(item.commit.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 + -- 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 = item.commit.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_table = { util.str_min_width(date, date_width), "Special" } + + if details then + author_table = { + util.str_clamp(item.commit.author_name, clamp_width - (#date > date_width and #date or date_width)), + "NeogitGraphAuthor", + } + end + + if visibility then + Virt = { + { " ", "Constant" }, + author_table, + date_table, + } + else + Virt = {} + end + return row( util.merge( { text.highlight("NeogitObjectId")(item.commit.abbreviated_commit) }, @@ -367,7 +440,12 @@ local SectionItemCommit = Component.new(function(item) ref_last, { text(item.commit.subject) } ), - { oid = item.commit.oid, yankable = item.commit.oid, item = item } + { + virtual_text = Virt, + oid = item.commit.oid, + yankable = item.commit.oid, + item = item, + } ) end) diff --git a/lua/neogit/config.lua b/lua/neogit/config.lua index 311274be2..295f9c6b3 100644 --- a/lua/neogit/config.lua +++ b/lua/neogit/config.lua @@ -238,6 +238,7 @@ end ---| "PushPopup" ---| "CommitPopup" ---| "LogPopup" +---| "MarginPopup" ---| "RevertPopup" ---| "StashPopup" ---| "IgnorePopup" @@ -626,6 +627,7 @@ function M.get_default_values() ["c"] = "CommitPopup", ["f"] = "FetchPopup", ["l"] = "LogPopup", + ["L"] = "MarginPopup", ["m"] = "MergePopup", ["p"] = "PullPopup", ["r"] = "RebasePopup", diff --git a/lua/neogit/lib/git/log.lua b/lua/neogit/lib/git/log.lua index b9fef523e..236b4c00c 100644 --- a/lua/neogit/lib/git/log.lua +++ b/lua/neogit/lib/git/log.lua @@ -30,6 +30,7 @@ local commit_header_pat = "([| ]*)(%*?)([| ]*)commit (%w+)" ---@field verification_flag string? ---@field rel_date string ---@field log_date string +---@field unix_date string ---Parses the provided list of lines into a CommitLogEntry ---@param raw string[] @@ -340,6 +341,7 @@ local function format(show_signature) committer_date = "%cD", rel_date = "%cr", log_date = "%cd", + unix_date = "%ct", } if show_signature then diff --git a/lua/neogit/popups/help/actions.lua b/lua/neogit/popups/help/actions.lua index cede6c0c6..28736adfb 100644 --- a/lua/neogit/popups/help/actions.lua +++ b/lua/neogit/popups/help/actions.lua @@ -75,6 +75,9 @@ M.popups = function(env) { "LogPopup", "Log", popups.open("log", function(p) p(env.log) end) }, + { "MarginPopup", "Margin", popups.open("margin", function(p) + p(env.log) + end) }, { "CherryPickPopup", "Cherry Pick", diff --git a/lua/neogit/popups/margin/actions.lua b/lua/neogit/popups/margin/actions.lua new file mode 100644 index 000000000..5c4cba642 --- /dev/null +++ b/lua/neogit/popups/margin/actions.lua @@ -0,0 +1,25 @@ +local M = {} + +local state = require("neogit.lib.state") + +function M.toggle_visibility() + local visibility = state.get({ "margin", "visibility" }, false) + local new_visibility = not visibility + state.set({ "margin", "visibility" }, new_visibility) +end + +function M.cycle_date_style() + local styles = { "relative_short", "relative_long", "local_datetime" } + local current_index = state.get({ "margin", "date_style" }, #styles) + local next_index = (current_index % #styles) + 1 -- wrap around to the first style + + state.set({ "margin", "date_style" }, next_index) +end + +function M.toggle_details() + local details = state.get({ "margin", "details" }, false) + local new_details = not details + state.set({ "margin", "details" }, new_details) +end + +return M diff --git a/lua/neogit/popups/margin/init.lua b/lua/neogit/popups/margin/init.lua new file mode 100644 index 000000000..ef129c564 --- /dev/null +++ b/lua/neogit/popups/margin/init.lua @@ -0,0 +1,49 @@ +local popup = require("neogit.lib.popup") +local config = require("neogit.config") +local actions = require("neogit.popups.margin.actions") + +local M = {} + +function M.create(env) + local p = popup + .builder() + :name("NeogitMarginPopup") + :option("n", "max-count", "256", "Limit number of commits", { default = "256", key_prefix = "-" }) + :switch("o", "topo", "Order commits by", { + cli_suffix = "-order", + options = { + { display = "", value = "" }, + { display = "topo", value = "topo" }, + { display = "author-date", value = "author-date" }, + { display = "date", value = "date" }, + }, + }) + :switch("g", "graph", "Show graph", { + enabled = true, + internal = true, + incompatible = { "reverse" }, + dependent = { "color" }, + }) + :switch_if( + config.values.graph_style == "ascii" or config.values.graph_style == "kitty", + "c", + "color", + "Show graph in color", + { internal = true, incompatible = { "reverse" } } + ) + :switch("d", "decorate", "Show refnames", { enabled = true, internal = true }) + :group_heading("Refresh") + :action("g", "buffer", actions.log_current) + :new_action_group("Margin") + :action("L", "toggle visibility", actions.toggle_visibility) + :action("l", "cycle style", actions.cycle_date_style) + :action("d", "toggle details", actions.toggle_details) + :action("x", "toggle shortstat", actions.log_current) + :build() + + p:show() + + return p +end + +return M From 43d30618640bf45b2e4a738b7115055489afed49 Mon Sep 17 00:00:00 2001 From: Lucas Adelino Date: Wed, 7 May 2025 18:48:28 -0400 Subject: [PATCH 02/11] refactor(margin): fix linting violations --- lua/neogit/buffers/status/ui.lua | 7 ++++--- lua/neogit/popups/margin/init.lua | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lua/neogit/buffers/status/ui.lua b/lua/neogit/buffers/status/ui.lua index 724cc11aa..f693ec844 100755 --- a/lua/neogit/buffers/status/ui.lua +++ b/lua/neogit/buffers/status/ui.lua @@ -422,14 +422,15 @@ local SectionItemCommit = Component.new(function(item) } end + local virt if visibility then - Virt = { + virt = { { " ", "Constant" }, author_table, date_table, } else - Virt = {} + virt = {} end return row( @@ -441,7 +442,7 @@ local SectionItemCommit = Component.new(function(item) { text(item.commit.subject) } ), { - virtual_text = Virt, + virtual_text = virt, oid = item.commit.oid, yankable = item.commit.oid, item = item, diff --git a/lua/neogit/popups/margin/init.lua b/lua/neogit/popups/margin/init.lua index ef129c564..ae1e86645 100644 --- a/lua/neogit/popups/margin/init.lua +++ b/lua/neogit/popups/margin/init.lua @@ -4,7 +4,7 @@ local actions = require("neogit.popups.margin.actions") local M = {} -function M.create(env) +function M.create() local p = popup .builder() :name("NeogitMarginPopup") From 073995d83daaf8fb1c7f7e95dac55fd48a30d927 Mon Sep 17 00:00:00 2001 From: Lucas Adelino Date: Thu, 8 May 2025 11:48:27 -0400 Subject: [PATCH 03/11] fix(margin): env name in help popup action --- lua/neogit/popups/help/actions.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/neogit/popups/help/actions.lua b/lua/neogit/popups/help/actions.lua index 28736adfb..7b03c6f1f 100644 --- a/lua/neogit/popups/help/actions.lua +++ b/lua/neogit/popups/help/actions.lua @@ -76,7 +76,7 @@ M.popups = function(env) p(env.log) end) }, { "MarginPopup", "Margin", popups.open("margin", function(p) - p(env.log) + p(env.margin) end) }, { "CherryPickPopup", From 5276f99ccaee940b837b7912dbca1a92f8067dae Mon Sep 17 00:00:00 2001 From: Lucas Adelino Date: Thu, 8 May 2025 11:51:46 -0400 Subject: [PATCH 04/11] test(margin): add margin popup spec Also had to change the help popup slightly: because columns are calculated dynamically, adding an entry for the margin popup changed the order of some of the existing entries. --- spec/popups/help_popup_spec.rb | 14 +++++++------- spec/popups/margin_popup_spec.rb | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 spec/popups/margin_popup_spec.rb diff --git a/spec/popups/help_popup_spec.rb b/spec/popups/help_popup_spec.rb index 8b3846a4d..1199d28fc 100644 --- a/spec/popups/help_popup_spec.rb +++ b/spec/popups/help_popup_spec.rb @@ -10,17 +10,17 @@ " Commands Applying changes Essential commands ", " $ History M Remote Stage all Refresh ", " A Cherry Pick m Merge K Untrack Go to file ", - " b Branch P Push s Stage Toggle ", - " B Bisect p Pull S Stage unstaged ", + " b Branch p Pull s Stage Toggle ", + " B Bisect P Push S Stage unstaged ", " c Commit Q Command u Unstage ", " d Diff r Rebase U Unstage all ", " f Fetch t Tag x Discard ", - " I Init v Revert ", - " i Ignore w Worktree ", - " l Log X Reset ", - " Z Stash " + " i Ignore v Revert ", + " I Init w Worktree ", + " L Margin X Reset ", + " l Log Z Stash " ] end - %w[$ A b B c d f i I l M m P p r t v w X Z].each { include_examples "interaction", _1 } + %w[$ A b B c d f i I l L M m P p r t v w X Z].each { include_examples "interaction", _1 } end diff --git a/spec/popups/margin_popup_spec.rb b/spec/popups/margin_popup_spec.rb new file mode 100644 index 000000000..66897e0e3 --- /dev/null +++ b/spec/popups/margin_popup_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe "Margin Popup", :git, :nvim, :popup do # rubocop:disable RSpec/EmptyExampleGroup + before { nvim.keys("L") } + + let(:view) do + [ + " Arguments ", + " -n Limit number of commits (--max-count=256) ", + " -o Order commits by (--[topo|author-date|date]-order) ", + " -g Show graph (--graph) ", + " -c Show graph in color (--color) ", + " -d Show refnames (--decorate) ", + " ", + " Refresh Margin ", + " g buffer L toggle visibility ", + " l cycle style ", + " d toggle details ", + " x toggle shortstat " + ] + end + + %w[L l d].each { include_examples "interaction", _1 } +end From a6683afec56e323734f0785d0c2510cddf81ddc8 Mon Sep 17 00:00:00 2001 From: Cameron Date: Wed, 11 Jun 2025 15:43:40 +0200 Subject: [PATCH 05/11] formatting --- lua/neogit/buffers/status/init.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/neogit/buffers/status/init.lua b/lua/neogit/buffers/status/init.lua index 918fb356b..d902de1f0 100644 --- a/lua/neogit/buffers/status/init.lua +++ b/lua/neogit/buffers/status/init.lua @@ -128,7 +128,7 @@ function M:open(kind) [popups.mapping_for("HelpPopup")] = self:_action("v_help_popup"), [popups.mapping_for("IgnorePopup")] = self:_action("v_ignore_popup"), [popups.mapping_for("LogPopup")] = self:_action("v_log_popup"), - [popups.mapping_for("MarginPopup")] = self:_action("v_margin_popup"), + [popups.mapping_for("MarginPopup")] = self:_action("v_margin_popup"), [popups.mapping_for("MergePopup")] = self:_action("v_merge_popup"), [popups.mapping_for("PullPopup")] = self:_action("v_pull_popup"), [popups.mapping_for("PushPopup")] = self:_action("v_push_popup"), @@ -183,7 +183,7 @@ function M:open(kind) [popups.mapping_for("HelpPopup")] = self:_action("n_help_popup"), [popups.mapping_for("IgnorePopup")] = self:_action("n_ignore_popup"), [popups.mapping_for("LogPopup")] = self:_action("n_log_popup"), - [popups.mapping_for("MarginPopup")] = self:_action("n_margin_popup"), + [popups.mapping_for("MarginPopup")] = self:_action("n_margin_popup"), [popups.mapping_for("MergePopup")] = self:_action("n_merge_popup"), [popups.mapping_for("PullPopup")] = self:_action("n_pull_popup"), [popups.mapping_for("PushPopup")] = self:_action("n_push_popup"), From 7e7738898aba5d942784edab12c7ed476c4412be Mon Sep 17 00:00:00 2001 From: Cameron Date: Wed, 11 Jun 2025 15:43:49 +0200 Subject: [PATCH 06/11] Allow actions to suppress closing their popup. --- lua/neogit/lib/popup/init.lua | 7 +++++-- lua/neogit/popups/margin/actions.lua | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lua/neogit/lib/popup/init.lua b/lua/neogit/lib/popup/init.lua index e88bb6dd3..ac4952742 100644 --- a/lua/neogit/lib/popup/init.lua +++ b/lua/neogit/lib/popup/init.lua @@ -371,8 +371,11 @@ function M:mappings() for _, key in ipairs(action.keys) do mappings.n[key] = a.void(function() logger.debug(string.format("[POPUP]: Invoking action %q of %s", key, self.state.name)) - self:close() - action.callback(self) + local persist = action.callback(self) + if not persist then + self:close() + end + Watcher.instance():dispatch_refresh() end) end diff --git a/lua/neogit/popups/margin/actions.lua b/lua/neogit/popups/margin/actions.lua index 5c4cba642..0acd7eb64 100644 --- a/lua/neogit/popups/margin/actions.lua +++ b/lua/neogit/popups/margin/actions.lua @@ -6,6 +6,8 @@ function M.toggle_visibility() local visibility = state.get({ "margin", "visibility" }, false) local new_visibility = not visibility state.set({ "margin", "visibility" }, new_visibility) + + return true end function M.cycle_date_style() @@ -14,12 +16,16 @@ function M.cycle_date_style() local next_index = (current_index % #styles) + 1 -- wrap around to the first style state.set({ "margin", "date_style" }, next_index) + + return true end function M.toggle_details() local details = state.get({ "margin", "details" }, false) local new_details = not details state.set({ "margin", "details" }, new_details) + + return true end return M From f38a8dd9eb6f7ceaefe5be2d579ed446bb541cdb Mon Sep 17 00:00:00 2001 From: Cameron Date: Wed, 11 Jun 2025 15:57:53 +0200 Subject: [PATCH 07/11] Formatting --- lua/neogit/buffers/status/ui.lua | 116 +++++++++++++++---------------- 1 file changed, 57 insertions(+), 59 deletions(-) diff --git a/lua/neogit/buffers/status/ui.lua b/lua/neogit/buffers/status/ui.lua index f693ec844..d942b2cc2 100755 --- a/lua/neogit/buffers/status/ui.lua +++ b/lua/neogit/buffers/status/ui.lua @@ -4,6 +4,7 @@ local util = require("neogit.lib.util") local common = require("neogit.buffers.common") local config = require("neogit.config") local a = require("plenary.async") +local state = require("neogit.lib.state") local col = Ui.col local row = Ui.row @@ -368,69 +369,66 @@ local SectionItemCommit = Component.new(function(item) item.commit.rel_date = " " .. item.commit.rel_date end - -- Render author and date in margin - local state = require("neogit.lib.state") - local visibility = state.get({ "margin", "visibility" }, false) - local margin_date_style = state.get({ "margin", "date_style" }, 1) - local details = state.get({ "margin", "details" }, false) - local date - local author_table = { "" } - local date_table - local date_width = 10 - local clamp_width = 30 -- to avoid having too much space when relative date is short - - if margin_date_style == 1 then -- relative date (short) - local unpacked = vim.split(item.commit.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 - -- 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 = item.commit.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 + local virtual_text - date_table = { util.str_min_width(date, date_width), "Special" } + -- Render author and date in 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) - if details then - author_table = { - util.str_clamp(item.commit.author_name, clamp_width - (#date > date_width and #date or date_width)), - "NeogitGraphAuthor", - } - end + local date + local date_width = 10 + local clamp_width = 30 -- to avoid having too much space when relative date is short - local virt - if visibility then - virt = { - { " ", "Constant" }, + if margin_date_style == 1 then -- relative date (short) + local unpacked = vim.split(item.commit.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 + + -- 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 = item.commit.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 + + 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 + + virtual_text = { + { " ", "Constant" }, author_table, - date_table, + { util.str_min_width(date, date_width), "Special" } } - else - virt = {} end return row( @@ -442,7 +440,7 @@ local SectionItemCommit = Component.new(function(item) { text(item.commit.subject) } ), { - virtual_text = virt, + virtual_text = virtual_text, oid = item.commit.oid, yankable = item.commit.oid, item = item, From b81fbe553d47dc530d2bf9c2e143cf0ab877e93b Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 12 Jun 2025 09:37:30 +0200 Subject: [PATCH 08/11] lint --- lua/neogit/buffers/status/ui.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/neogit/buffers/status/ui.lua b/lua/neogit/buffers/status/ui.lua index d942b2cc2..5821f126d 100755 --- a/lua/neogit/buffers/status/ui.lua +++ b/lua/neogit/buffers/status/ui.lua @@ -378,7 +378,7 @@ local SectionItemCommit = Component.new(function(item) local date local date_width = 10 - local clamp_width = 30 -- to avoid having too much space when relative date is short + local clamp_width = 30 -- to avoid having too much space when relative date is short if margin_date_style == 1 then -- relative date (short) local unpacked = vim.split(item.commit.rel_date, " ") @@ -425,9 +425,9 @@ local SectionItemCommit = Component.new(function(item) end virtual_text = { - { " ", "Constant" }, + { " ", "Constant" }, author_table, - { util.str_min_width(date, date_width), "Special" } + { util.str_min_width(date, date_width), "Special" }, } end From 065301bd111b5a813b5692a5be78e8234af026de Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 12 Jun 2025 10:16:57 +0200 Subject: [PATCH 09/11] Change how we persist popup to not break existing popups. Long running actions need to have the popup closed prior to being invoked, like pushing/fetching. --- lua/neogit/lib/popup/builder.lua | 15 ++++++++++++--- lua/neogit/lib/popup/init.lua | 5 +++-- lua/neogit/popups/margin/actions.lua | 6 ------ lua/neogit/popups/margin/init.lua | 8 ++++---- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/lua/neogit/lib/popup/builder.lua b/lua/neogit/lib/popup/builder.lua index cd2920425..910cd8370 100644 --- a/lua/neogit/lib/popup/builder.lua +++ b/lua/neogit/lib/popup/builder.lua @@ -80,6 +80,10 @@ local M = {} ---@field description string ---@field callback function ---@field heading string? +---@field persist_popup boolean? set to true to prevent closing the popup when invoking + +---@class PopupActionOptions +---@field persist_popup boolean Controls if the action should close the popup (false/nil) or keep it open (true) ---@class PopupSwitchOpts ---@field enabled? boolean Controls if the switch should default to 'on' state @@ -429,8 +433,11 @@ end ---@param keys string|string[] Key or list of keys for the user to press that runs the action ---@param description string Description of action in UI ---@param callback? fun(popup: PopupData) Function that gets run in async context +---@param opts? PopupActionOptions ---@return self -function M:action(keys, description, callback) +function M:action(keys, description, callback, opts) + opts = opts or {} + if type(keys) == "string" then keys = { keys } end @@ -448,6 +455,7 @@ function M:action(keys, description, callback) keys = keys, description = description, callback = callback, + persist_popup = opts.persist_popup or false }) return self @@ -459,10 +467,11 @@ end ---@param keys string|string[] Key or list of keys for the user to press that runs the action ---@param description string Description of action in UI ---@param callback? fun(popup: PopupData) Function that gets run in async context +---@param opts? PopupActionOptions ---@return self -function M:action_if(cond, keys, description, callback) +function M:action_if(cond, keys, description, callback, opts) if cond then - return self:action(keys, description, callback) + return self:action(keys, description, callback, opts) end return self diff --git a/lua/neogit/lib/popup/init.lua b/lua/neogit/lib/popup/init.lua index ac4952742..f4a39e0c2 100644 --- a/lua/neogit/lib/popup/init.lua +++ b/lua/neogit/lib/popup/init.lua @@ -371,11 +371,12 @@ function M:mappings() for _, key in ipairs(action.keys) do mappings.n[key] = a.void(function() logger.debug(string.format("[POPUP]: Invoking action %q of %s", key, self.state.name)) - local persist = action.callback(self) - if not persist then + if not action.persist_popup then + logger.debug("[POPUP]: Closing popup") self:close() end + action.callback(self) Watcher.instance():dispatch_refresh() end) end diff --git a/lua/neogit/popups/margin/actions.lua b/lua/neogit/popups/margin/actions.lua index 0acd7eb64..5c4cba642 100644 --- a/lua/neogit/popups/margin/actions.lua +++ b/lua/neogit/popups/margin/actions.lua @@ -6,8 +6,6 @@ function M.toggle_visibility() local visibility = state.get({ "margin", "visibility" }, false) local new_visibility = not visibility state.set({ "margin", "visibility" }, new_visibility) - - return true end function M.cycle_date_style() @@ -16,16 +14,12 @@ function M.cycle_date_style() local next_index = (current_index % #styles) + 1 -- wrap around to the first style state.set({ "margin", "date_style" }, next_index) - - return true end function M.toggle_details() local details = state.get({ "margin", "details" }, false) local new_details = not details state.set({ "margin", "details" }, new_details) - - return true end return M diff --git a/lua/neogit/popups/margin/init.lua b/lua/neogit/popups/margin/init.lua index ae1e86645..c4e92948d 100644 --- a/lua/neogit/popups/margin/init.lua +++ b/lua/neogit/popups/margin/init.lua @@ -35,10 +35,10 @@ function M.create() :group_heading("Refresh") :action("g", "buffer", actions.log_current) :new_action_group("Margin") - :action("L", "toggle visibility", actions.toggle_visibility) - :action("l", "cycle style", actions.cycle_date_style) - :action("d", "toggle details", actions.toggle_details) - :action("x", "toggle shortstat", actions.log_current) + :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 }) :build() p:show() From 442b1fe43a148a8398a35109ca5f89b0f20f2fa6 Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 12 Jun 2025 10:17:39 +0200 Subject: [PATCH 10/11] Implement refreshing of buffer --- lua/neogit/buffers/status/actions.lua | 16 ++++++++++------ lua/neogit/popups/margin/actions.lua | 7 +++++++ lua/neogit/popups/margin/init.lua | 10 ++++++++-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/lua/neogit/buffers/status/actions.lua b/lua/neogit/buffers/status/actions.lua index ef21db8cb..a6c8871d5 100644 --- a/lua/neogit/buffers/status/actions.lua +++ b/lua/neogit/buffers/status/actions.lua @@ -445,9 +445,11 @@ M.v_log_popup = function(_self) return popups.open("log") end ----@param _self StatusBuffer -M.v_margin_popup = function(_self) - return popups.open("margin") +---@param self StatusBuffer +M.v_margin_popup = function(self) + return popups.open("margin", function(p) + p { buffer = self } + end) end ---@param _self StatusBuffer @@ -1413,9 +1415,11 @@ M.n_log_popup = function(_self) return popups.open("log") end ----@param _self StatusBuffer -M.n_margin_popup = function(_self) - return popups.open("margin") +---@param self StatusBuffer +M.n_margin_popup = function(self) + return popups.open("margin", function(p) + p { buffer = self } + end) end ---@param _self StatusBuffer diff --git a/lua/neogit/popups/margin/actions.lua b/lua/neogit/popups/margin/actions.lua index 5c4cba642..8ab733736 100644 --- a/lua/neogit/popups/margin/actions.lua +++ b/lua/neogit/popups/margin/actions.lua @@ -1,6 +1,13 @@ local M = {} local state = require("neogit.lib.state") +local a = require("plenary.async") + +function M.refresh_buffer(buffer) + return a.void(function() + buffer:dispatch_refresh({ update_diffs = { "*:*" } }, "margin_refresh_buffer") + end) +end function M.toggle_visibility() local visibility = state.get({ "margin", "visibility" }, false) diff --git a/lua/neogit/popups/margin/init.lua b/lua/neogit/popups/margin/init.lua index c4e92948d..e7d5429dc 100644 --- a/lua/neogit/popups/margin/init.lua +++ b/lua/neogit/popups/margin/init.lua @@ -4,7 +4,7 @@ local actions = require("neogit.popups.margin.actions") local M = {} -function M.create() +function M.create(env) local p = popup .builder() :name("NeogitMarginPopup") @@ -33,7 +33,13 @@ function M.create() ) :switch("d", "decorate", "Show refnames", { enabled = true, internal = true }) :group_heading("Refresh") - :action("g", "buffer", actions.log_current) + :action_if( + env.buffer, + "g", + "buffer", + actions.refresh_buffer(env.buffer), + { persist_popup = true } + ) :new_action_group("Margin") :action("L", "toggle visibility", actions.toggle_visibility, { persist_popup = true }) :action("l", "cycle style", actions.cycle_date_style, { persist_popup = true }) From 41cbd258a724f9ea95705d9aab6c7ef39c8a1e6f Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 12 Jun 2025 10:23:50 +0200 Subject: [PATCH 11/11] Modify rel_date so we don't mutate original object --- lua/neogit/buffers/status/ui.lua | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/lua/neogit/buffers/status/ui.lua b/lua/neogit/buffers/status/ui.lua index 5821f126d..0d07d2b2c 100755 --- a/lua/neogit/buffers/status/ui.lua +++ b/lua/neogit/buffers/status/ui.lua @@ -361,14 +361,6 @@ local SectionItemCommit = Component.new(function(item) end end - -- Render date - if item.commit.rel_date:match(" years?,") then - item.commit.rel_date, _ = item.commit.rel_date:gsub(" years?,", "y") - item.commit.rel_date = item.commit.rel_date .. " " - elseif item.commit.rel_date:match("^%d ") then - item.commit.rel_date = " " .. item.commit.rel_date - end - local virtual_text -- Render author and date in margin, if visible @@ -377,11 +369,22 @@ local SectionItemCommit = Component.new(function(item) 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(item.commit.rel_date, " ") + 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 @@ -403,7 +406,7 @@ local SectionItemCommit = Component.new(function(item) date_width = 3 clamp_width = 23 elseif margin_date_style == 2 then -- relative date (long) - date = item.commit.rel_date + date = rel_date date_width = 10 else -- local iso date if config.values.log_date_format == nil then