detached 4b3baff

fix(core): cancel hints when reloading label size

commit
4b3baffa33267a7830a95240b5788347abde75e8
author
brice · · 2026-10-22 20:28 UTC
parent
8f581cc
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +18 -2
M internal/core/core.go +3 -0
@@ -353,6 +353,9 @@ func (c *Core) apply(cfg ports.Config) error {
353353 for _, s := range c.screens {
354354 axes[s.mon] = s.mon.Current().policy()
355355 }
356+ if c.cfg.Hint.Size != cfg.Hint.Size {
357+ c.hintCancel()
358+ }
356359 c.cfg = cfg
357360 c.binds = binds
358361 c.cmdMod = map[string]ports.Mods{"super": ports.ModSuper, "alt": ports.ModAlt, "ctrl": ports.ModCtrl}[cfg.Keyboard.CmdKey]
@@ -353,6 +353,9 @@ func (c *Core) apply(cfg ports.Config) error {
353 for _, s := range c.screens {353 for _, s := range c.screens {
354 axes[s.mon] = s.mon.Current().policy()354 axes[s.mon] = s.mon.Current().policy()
355 }355 }
356+ if c.cfg.Hint.Size != cfg.Hint.Size {
357+ c.hintCancel()
358+ }
356 c.cfg = cfg359 c.cfg = cfg
357 c.binds = binds360 c.binds = binds
358 c.cmdMod = map[string]ports.Mods{"super": ports.ModSuper, "alt": ports.ModAlt, "ctrl": ports.ModCtrl}[cfg.Keyboard.CmdKey]361 c.cmdMod = map[string]ports.Mods{"super": ports.ModSuper, "alt": ports.ModAlt, "ctrl": ports.ModCtrl}[cfg.Keyboard.CmdKey]
M internal/core/hint_test.go +15 -2
@@ -24,7 +24,9 @@ type hintHarness struct {
2424 hints chan ports.HintScanResult
2525 win ports.Rect // window 1, output-local
2626 // state is the security state input is stamped with.
27- state ports.SecurityState
27+ state ports.SecurityState
28+ config chan ports.ConfigChanged
29+ cfg ports.Config
2830 }
2931
3032 // newHint starts a core with one 1000x800 output "OUT-1" and window 1 mapped.
@@ -42,6 +44,8 @@ func newHintConfig(t *testing.T, opts core.Options, edit func(*ports.Config)) *h
4244 cfg.Layout.Gaps = 20
4345 cfg.Binds["Cmd+g"] = "hint"
4446 h := &hintHarness{
47+ config: make(chan ports.ConfigChanged),
48+ cfg: cfg,
4549 t: t,
4650 input: make(chan ports.InputEvent, 32),
4751 client: make(chan ports.ClientEvent, 32),
@@ -52,7 +56,7 @@ func newHintConfig(t *testing.T, opts core.Options, edit func(*ports.Config)) *h
5256 // Unbuffered: a send returns once core took the result.
5357 hints: make(chan ports.HintScanResult),
5458 }
55- ch := core.Channels{Client: h.client, Input: h.input, Output: h.output, Commands: h.commands, Scenes: h.scenes, HintScans: h.scans, Hints: h.hints}
59+ ch := core.Channels{Config: h.config, Client: h.client, Input: h.input, Output: h.output, Commands: h.commands, Scenes: h.scenes, HintScans: h.scans, Hints: h.hints}
5660 c, err := core.New(cfg, ch, opts)
5761 if err != nil {
5862 t.Fatal(err)
@@ -850,3 +854,12 @@ func TestHintOverlappingLabelsDropLowerScore(t *testing.T) {
850854 }
851855 }
852856 }
857+
858+func TestHintSizeReloadCancelsShownHints(t *testing.T) {
859+ h := newHint(t, core.Options{})
860+ h.show(h.inside(0))
861+ cfg := h.cfg
862+ cfg.Hint.Size = 40
863+ h.config <- ports.ConfigChanged{Config: cfg}
864+ h.until(func(s ports.Scene) bool { return s.HintStyle.Size == 40 && len(s.HintLabels) == 0 })
865+}
@@ -24,7 +24,9 @@ type hintHarness struct {
24 hints chan ports.HintScanResult24 hints chan ports.HintScanResult
25 win ports.Rect // window 1, output-local25 win ports.Rect // window 1, output-local
26 // state is the security state input is stamped with.26 // state is the security state input is stamped with.
27- state ports.SecurityState27+ state ports.SecurityState
28+ config chan ports.ConfigChanged
29+ cfg ports.Config
28 }30 }
29 31
30 // newHint starts a core with one 1000x800 output "OUT-1" and window 1 mapped.32 // newHint starts a core with one 1000x800 output "OUT-1" and window 1 mapped.
@@ -42,6 +44,8 @@ func newHintConfig(t *testing.T, opts core.Options, edit func(*ports.Config)) *h
42 cfg.Layout.Gaps = 2044 cfg.Layout.Gaps = 20
43 cfg.Binds["Cmd+g"] = "hint"45 cfg.Binds["Cmd+g"] = "hint"
44 h := &hintHarness{46 h := &hintHarness{
47+ config: make(chan ports.ConfigChanged),
48+ cfg: cfg,
45 t: t,49 t: t,
46 input: make(chan ports.InputEvent, 32),50 input: make(chan ports.InputEvent, 32),
47 client: make(chan ports.ClientEvent, 32),51 client: make(chan ports.ClientEvent, 32),
@@ -52,7 +56,7 @@ func newHintConfig(t *testing.T, opts core.Options, edit func(*ports.Config)) *h
52 // Unbuffered: a send returns once core took the result.56 // Unbuffered: a send returns once core took the result.
53 hints: make(chan ports.HintScanResult),57 hints: make(chan ports.HintScanResult),
54 }58 }
55- ch := core.Channels{Client: h.client, Input: h.input, Output: h.output, Commands: h.commands, Scenes: h.scenes, HintScans: h.scans, Hints: h.hints}59+ ch := core.Channels{Config: h.config, Client: h.client, Input: h.input, Output: h.output, Commands: h.commands, Scenes: h.scenes, HintScans: h.scans, Hints: h.hints}
56 c, err := core.New(cfg, ch, opts)60 c, err := core.New(cfg, ch, opts)
57 if err != nil {61 if err != nil {
58 t.Fatal(err)62 t.Fatal(err)
@@ -850,3 +854,12 @@ func TestHintOverlappingLabelsDropLowerScore(t *testing.T) {
850 }854 }
851 }855 }
852 }856 }
857+
858+func TestHintSizeReloadCancelsShownHints(t *testing.T) {
859+ h := newHint(t, core.Options{})
860+ h.show(h.inside(0))
861+ cfg := h.cfg
862+ cfg.Hint.Size = 40
863+ h.config <- ports.ConfigChanged{Config: cfg}
864+ h.until(func(s ports.Scene) bool { return s.HintStyle.Size == 40 && len(s.HintLabels) == 0 })
865+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 23

Tags 10

↑↓ moveenter openesc close