Skip to content

Commit a916d3a

Browse files
committed
refactor(ui): share keymap spec helper between popup and stack view
Introduce ui/keymap_spec.lua as a thin helper that wraps vim.keymap.set with the buffer/nowait/silent defaults the popup and stack view keymaps both used. ui/keymaps.lua and ui/stack_view/keymaps.lua now describe their bindings as PeekstackKeymapSpec lists and apply them through the helper, removing duplicated registration boilerplate.
1 parent 36d7bb9 commit a916d3a

3 files changed

Lines changed: 327 additions & 245 deletions

File tree

lua/peekstack/ui/keymap_spec.lua

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
local M = {}
2+
3+
---@class PeekstackKeymapSpec
4+
---@field lhs string
5+
---@field rhs string|function
6+
---@field desc? string
7+
---@field mode? string|string[]
8+
---@field expr? boolean
9+
---@field nowait? boolean
10+
---@field silent? boolean
11+
---@field remap? boolean
12+
13+
---@param spec PeekstackKeymapSpec
14+
---@param bufnr integer
15+
---@return table
16+
local function build_opts(spec, bufnr)
17+
return {
18+
buffer = bufnr,
19+
nowait = spec.nowait ~= false,
20+
silent = spec.silent ~= false,
21+
desc = spec.desc,
22+
expr = spec.expr,
23+
remap = spec.remap,
24+
}
25+
end
26+
27+
---Set a single buffer-local keymap from a spec.
28+
---Skips empty/nil `lhs` entries so callers can pass user-configurable keys directly.
29+
---@param bufnr integer
30+
---@param spec PeekstackKeymapSpec
31+
function M.set(bufnr, spec)
32+
if not spec.lhs or spec.lhs == "" then
33+
return
34+
end
35+
vim.keymap.set(spec.mode or "n", spec.lhs, spec.rhs, build_opts(spec, bufnr))
36+
end
37+
38+
---Apply multiple specs on a buffer.
39+
---@param bufnr integer
40+
---@param specs PeekstackKeymapSpec[]
41+
function M.apply(bufnr, specs)
42+
for _, spec in ipairs(specs) do
43+
M.set(bufnr, spec)
44+
end
45+
end
46+
47+
---Drop specs with empty `lhs` and de-dup by `lhs`, keeping the last occurrence.
48+
---Useful when user config produces overlapping shortcuts.
49+
---@param specs PeekstackKeymapSpec[]
50+
---@return PeekstackKeymapSpec[]
51+
function M.normalize(specs)
52+
---@type table<string, PeekstackKeymapSpec>
53+
local by_lhs = {}
54+
---@type string[]
55+
local order = {}
56+
for _, spec in ipairs(specs) do
57+
if spec.lhs and spec.lhs ~= "" then
58+
if not by_lhs[spec.lhs] then
59+
order[#order + 1] = spec.lhs
60+
end
61+
by_lhs[spec.lhs] = spec
62+
end
63+
end
64+
65+
local out = {}
66+
for _, lhs in ipairs(order) do
67+
out[#out + 1] = by_lhs[lhs]
68+
end
69+
return out
70+
end
71+
72+
return M

lua/peekstack/ui/keymaps.lua

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
local config = require("peekstack.config")
22
local promote = require("peekstack.core.promote")
33
local stack_view = require("peekstack.ui.stack_view")
4+
local keymap_spec = require("peekstack.ui.keymap_spec")
45

56
local M = {}
67

@@ -16,17 +17,6 @@ local M = {}
1617
---@type PeekstackSourcePopupMapState?
1718
local active_source_maps = nil
1819

19-
---@param bufnr integer
20-
---@param lhs string?
21-
---@param rhs string|function
22-
---@param desc string
23-
local function map(bufnr, lhs, rhs, desc)
24-
if not lhs or lhs == "" then
25-
return
26-
end
27-
vim.keymap.set("n", lhs, rhs, { buffer = bufnr, nowait = true, silent = true, desc = desc })
28-
end
29-
3020
--- Navigate from a popup to an adjacent split window.
3121
--- Moves focus back to the root (non-floating) window first, then executes
3222
--- wincmd in the given direction.
@@ -52,10 +42,10 @@ local function resolve_current_popup()
5242
return popup
5343
end
5444

55-
---@return { lhs: string, rhs: function, desc: string }[]
45+
---@return PeekstackKeymapSpec[]
5646
local function mapping_specs()
5747
local keys = config.get().ui.keys
58-
---@type { lhs: string, rhs: function, desc: string }[]
48+
---@type PeekstackKeymapSpec[]
5949
local raw = {
6050
{
6151
lhs = keys.close,
@@ -173,25 +163,7 @@ local function mapping_specs()
173163
},
174164
}
175165

176-
---@type table<string, { lhs: string, rhs: function, desc: string }>
177-
local by_lhs = {}
178-
---@type string[]
179-
local order = {}
180-
for _, spec in ipairs(raw) do
181-
if spec.lhs and spec.lhs ~= "" then
182-
if not by_lhs[spec.lhs] then
183-
order[#order + 1] = spec.lhs
184-
end
185-
by_lhs[spec.lhs] = spec
186-
end
187-
end
188-
189-
---@type { lhs: string, rhs: function, desc: string }[]
190-
local specs = {}
191-
for _, lhs in ipairs(order) do
192-
specs[#specs + 1] = by_lhs[lhs]
193-
end
194-
return specs
166+
return keymap_spec.normalize(raw)
195167
end
196168

197169
---@param bufnr integer
@@ -269,7 +241,7 @@ local function activate_source_popup(popup)
269241

270242
for _, spec in ipairs(specs) do
271243
original[spec.lhs] = get_buffer_map(popup.bufnr, spec.lhs)
272-
map(popup.bufnr, spec.lhs, spec.rhs, spec.desc)
244+
keymap_spec.set(popup.bufnr, spec)
273245
lhs_list[#lhs_list + 1] = spec.lhs
274246
end
275247

@@ -288,9 +260,7 @@ function M.apply_popup(popup)
288260
return
289261
end
290262

291-
for _, spec in ipairs(mapping_specs()) do
292-
map(popup.bufnr, spec.lhs, spec.rhs, spec.desc)
293-
end
263+
keymap_spec.apply(popup.bufnr, mapping_specs())
294264
end
295265

296266
---@param target integer|PeekstackPopupModel

0 commit comments

Comments
 (0)