Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lua/gitlad/ui/hl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ local highlight_groups = {
GitladPopupHeading = { link = "Title" },
GitladPopupSwitchKey = { link = "Special" },
GitladPopupSwitchEnabled = { link = "DiagnosticOk" },
GitladPopupSwitchPersistent = { link = "DiagnosticHint" },
GitladPopupOptionKey = { link = "Keyword" },
GitladPopupActionKey = { link = "Keyword" },
GitladPopupDescription = { link = "Normal" },
Expand Down
14 changes: 11 additions & 3 deletions lua/gitlad/ui/hl_status.lua
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ function M.apply_popup_highlights(
-- Build lookup for switch keys
local switch_keys = {}
for _, sw in ipairs(switches) do
switch_keys[sw.key] = sw.enabled
switch_keys[sw.key] = { enabled = sw.enabled, persistent = sw.persist_key ~= nil }
end

-- Build lookup for option keys
Expand Down Expand Up @@ -834,7 +834,7 @@ function M.apply_popup_highlights(
-- Switch line: " -a description (--flag)"
local switch_key = line:match("^%s%s%-(%S)")
if switch_key and switch_keys[switch_key] ~= nil then
local is_enabled = switch_keys[switch_key]
local sw_info = switch_keys[switch_key]
-- Highlight the -key part
local key_start = line:find("%-")
if key_start then
Expand All @@ -848,11 +848,19 @@ function M.apply_popup_highlights(
)
end
-- Highlight the flag text inside parens (not the parens themselves)
-- Persistent+enabled switches use a distinct color from transient+enabled
local cli_start = line:find("%(%-")
if cli_start then
local cli_end = line:find("%)", cli_start)
if cli_end then
local hl_group = is_enabled and "GitladPopupSwitchEnabled" or "Comment"
local hl_group
if sw_info.enabled and sw_info.persistent then
hl_group = "GitladPopupSwitchPersistent"
elseif sw_info.enabled then
hl_group = "GitladPopupSwitchEnabled"
else
hl_group = "Comment"
end
hl_module.set(bufnr, ns_popup, line_idx, cli_start, cli_end - 1, hl_group)
end
end
Expand Down
22 changes: 21 additions & 1 deletion lua/gitlad/ui/popup/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ local git = require("gitlad.git")
---@field enabled boolean Current state
---@field cli_prefix string Prefix for CLI flag (default "--")
---@field exclusive_with? string[] CLI names of switches that are mutually exclusive
---@field persist_key? string If set, enabled state is saved/loaded across popup invocations

---@class PopupOption
---@field key string Single character key binding
Expand Down Expand Up @@ -126,7 +127,7 @@ end
---@param key string Single character key
---@param cli string CLI flag name (without --)
---@param description string User-facing description
---@param opts? { enabled?: boolean, cli_prefix?: string, exclusive_with?: string[] }
---@param opts? { enabled?: boolean, cli_prefix?: string, exclusive_with?: string[], persist_key?: string }
---@return PopupBuilder
function PopupBuilder:switch(key, cli, description, opts)
opts = opts or {}
Expand All @@ -137,6 +138,7 @@ function PopupBuilder:switch(key, cli, description, opts)
enabled = opts.enabled or false,
cli_prefix = opts.cli_prefix or "--",
exclusive_with = opts.exclusive_with,
persist_key = opts.persist_key,
})
return self
end
Expand Down Expand Up @@ -292,6 +294,17 @@ function PopupBuilder:build()
local data = setmetatable({}, PopupData)
data.name = self._name
data.switches = vim.deepcopy(self._switches)

-- Apply persisted enabled states for sticky switches
local persist = require("gitlad.utils.persist")
for _, sw in ipairs(data.switches) do
if sw.persist_key then
local saved = persist.get(sw.persist_key)
if saved ~= nil then
sw.enabled = saved
end
end
end
data.options = vim.deepcopy(self._options)
data.actions = vim.deepcopy(self._actions)
data.branch_scope = self._branch_scope
Expand Down Expand Up @@ -372,6 +385,7 @@ end
--- Toggle a switch by key
---@param key string Switch key
function PopupData:toggle_switch(key)
local persist = require("gitlad.utils.persist")
for _, sw in ipairs(self.switches) do
if sw.key == key then
sw.enabled = not sw.enabled
Expand All @@ -381,10 +395,16 @@ function PopupData:toggle_switch(key)
for _, excl_cli in ipairs(sw.exclusive_with) do
if other.cli == excl_cli then
other.enabled = false
if other.persist_key then
persist.set(other.persist_key, false)
end
end
end
end
end
if sw.persist_key then
persist.set(sw.persist_key, sw.enabled)
end
return
end
end
Expand Down
1 change: 1 addition & 0 deletions lua/gitlad/utils/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ local M = {}
M.errors = require("gitlad.utils.errors")
M.keymap = require("gitlad.utils.keymap")
M.path = require("gitlad.utils.path")
M.persist = require("gitlad.utils.persist")
M.prompt = require("gitlad.utils.prompt")
M.remote = require("gitlad.utils.remote")

Expand Down
75 changes: 75 additions & 0 deletions lua/gitlad/utils/persist.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---@mod gitlad.utils.persist Lightweight key-value persistence
---@brief [[
--- Simple persistent store for popup switch states and similar small values.
--- Data is stored as JSON in stdpath("data")/gitlad/popup_switches.json.
---
--- Override M._override_path in tests to avoid touching the real data directory.
---@brief ]]

local M = {}

--- Override storage path (for tests)
---@type string|nil
M._override_path = nil

---@return string
local function data_file()
return M._override_path or (vim.fn.stdpath("data") .. "/gitlad/popup_switches.json")
end

---@type table<string, any>|nil
local _cache = nil

--- Reset the in-memory cache (call after changing _override_path in tests)
function M._reset_cache()
_cache = nil
end

---@return table<string, any>
local function load()
if _cache then
return _cache
end
local path = data_file()
local f = io.open(path, "r")
if not f then
_cache = {}
return _cache
end
local content = f:read("*a")
f:close()
local ok, data = pcall(vim.json.decode, content)
_cache = (ok and type(data) == "table") and data or {}
return _cache
end

---@param data table<string, any>
local function save(data)
local path = data_file()
local dir = vim.fn.fnamemodify(path, ":h")
vim.fn.mkdir(dir, "p")
local f = io.open(path, "w")
if not f then
return
end
f:write(vim.json.encode(data))
f:close()
end

--- Get a persisted value by key
---@param key string
---@return any
function M.get(key)
return load()[key]
end

--- Set a persisted value by key
---@param key string
---@param value any
function M.set(key, value)
local data = load()
data[key] = value
save(data)
end

return M
Loading
Loading