detached eb19005

refactor(core): always snapshot overview keys and scrolls and release unplugged shots

commit
eb19005f6ba45e00a5de6d48c5eb68bf0e8c5a08
author
brice · · 2026-10-05 08:28 UTC
parent
8747466
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +7 -20
M internal/core/input.go +4 -7
@@ -143,13 +143,10 @@ func (c *Core) handleInput(ctx context.Context, ev ports.InputEvent) error {
143143 c.scrollStop(v)
144144 // In the overview, scrolling moves the selection.
145145 if c.cur().mon.ov.open && !c.overviewKeyboardTaken() {
146- // Only a scroll that can step needs the shot (not the end of
147- // one, nor the rest of a finger scroll that stepped).
146+ // overviewScroll owns which scrolls step; the shot costs no
147+ // allocation once warm.
148148 now := c.now()
149- var shots []viewShot
150- if m := c.cur().mon; !v.Vertical.Stop && !v.Horizontal.Stop && !(v.Source == ports.AxisFinger && m.ov.scrolled) {
151- shots = c.snapshot(now)
152- }
149+ shots := c.snapshot(now)
153150 if c.cur().mon.overviewScroll(v) {
154151 c.transition(shots, now)
155152 if err := c.workspaceVisible(ctx, true); err != nil {
@@ -202,7 +199,7 @@ func (c *Core) handleInput(ctx context.Context, ev ports.InputEvent) error {
202199 if mon := c.cur().mon; mon.ov.open && !c.overviewKeyboardTaken() {
203200 now := c.now()
204201 var shots []viewShot
205- if key.Pressed && overviewKeyNamed(key) {
202+ if key.Pressed {
206203 shots = c.snapshot(now)
207204 }
208205 if key.Pressed && mon.overviewKey(key) {
@@ -143,13 +143,10 @@ func (c *Core) handleInput(ctx context.Context, ev ports.InputEvent) error {
143 c.scrollStop(v)143 c.scrollStop(v)
144 // In the overview, scrolling moves the selection.144 // In the overview, scrolling moves the selection.
145 if c.cur().mon.ov.open && !c.overviewKeyboardTaken() {145 if c.cur().mon.ov.open && !c.overviewKeyboardTaken() {
146- // Only a scroll that can step needs the shot (not the end of146+ // overviewScroll owns which scrolls step; the shot costs no
147- // one, nor the rest of a finger scroll that stepped).147+ // allocation once warm.
148 now := c.now()148 now := c.now()
149- var shots []viewShot149+ shots := c.snapshot(now)
150- if m := c.cur().mon; !v.Vertical.Stop && !v.Horizontal.Stop && !(v.Source == ports.AxisFinger && m.ov.scrolled) {
151- shots = c.snapshot(now)
152- }
153 if c.cur().mon.overviewScroll(v) {150 if c.cur().mon.overviewScroll(v) {
154 c.transition(shots, now)151 c.transition(shots, now)
155 if err := c.workspaceVisible(ctx, true); err != nil {152 if err := c.workspaceVisible(ctx, true); err != nil {
@@ -202,7 +199,7 @@ func (c *Core) handleInput(ctx context.Context, ev ports.InputEvent) error {
202 if mon := c.cur().mon; mon.ov.open && !c.overviewKeyboardTaken() {199 if mon := c.cur().mon; mon.ov.open && !c.overviewKeyboardTaken() {
203 now := c.now()200 now := c.now()
204 var shots []viewShot201 var shots []viewShot
205- if key.Pressed && overviewKeyNamed(key) {202+ if key.Pressed {
206 shots = c.snapshot(now)203 shots = c.snapshot(now)
207 }204 }
208 if key.Pressed && mon.overviewKey(key) {205 if key.Pressed && mon.overviewKey(key) {
M internal/core/overview.go +0 -13
@@ -1015,19 +1015,6 @@ func (c *Core) overviewKeyboardTaken() bool {
10151015 return layer || c.popups[id] != nil
10161016 }
10171017
1018-// overviewKeyNamed reports whether key is one overviewKey handles (a bare key); it
1019-// lets input snapshot only for those.
1020-func overviewKeyNamed(key ports.KeyEvent) bool {
1021- if key.Mods != 0 {
1022- return false
1023- }
1024- switch keyName(key.Keysym) {
1025- case "h", "Left", "l", "Right", "k", "Up", "j", "Down", "Return", "KP_Enter", "Escape":
1026- return true
1027- }
1028- return false
1029-}
1030-
10311018 // overviewKey runs an overview key: true when the key was one.
10321019 func (m *Monitor) overviewKey(key ports.KeyEvent) bool {
10331020 if key.Mods != 0 {
@@ -1015,19 +1015,6 @@ func (c *Core) overviewKeyboardTaken() bool {
1015 return layer || c.popups[id] != nil1015 return layer || c.popups[id] != nil
1016 }1016 }
1017 1017
1018-// overviewKeyNamed reports whether key is one overviewKey handles (a bare key); it
1019-// lets input snapshot only for those.
1020-func overviewKeyNamed(key ports.KeyEvent) bool {
1021- if key.Mods != 0 {
1022- return false
1023- }
1024- switch keyName(key.Keysym) {
1025- case "h", "Left", "l", "Right", "k", "Up", "j", "Down", "Return", "KP_Enter", "Escape":
1026- return true
1027- }
1028- return false
1029-}
1030-
1031 // overviewKey runs an overview key: true when the key was one.1018 // overviewKey runs an overview key: true when the key was one.
1032 func (m *Monitor) overviewKey(key ports.KeyEvent) bool {1019 func (m *Monitor) overviewKey(key ports.KeyEvent) bool {
1033 if key.Mods != 0 {1020 if key.Mods != 0 {
M internal/core/transition.go +3 -0
@@ -657,7 +657,10 @@ func (c *Core) snapshot(now time.Time) []viewShot {
657657 out = append(out, s)
658658 }
659659 for i := len(out); i < len(full); i++ {
660+ // Shots of unplugged screens keep nothing of them alive.
660661 full[i].sc, full[i].ws = nil, nil
662+ clear(full[i].list[:cap(full[i].list)])
663+ full[i].list = full[i].list[:0]
661664 }
662665 c.shots = out
663666 return out
@@ -657,7 +657,10 @@ func (c *Core) snapshot(now time.Time) []viewShot {
657 out = append(out, s)657 out = append(out, s)
658 }658 }
659 for i := len(out); i < len(full); i++ {659 for i := len(out); i < len(full); i++ {
660+ // Shots of unplugged screens keep nothing of them alive.
660 full[i].sc, full[i].ws = nil, nil661 full[i].sc, full[i].ws = nil, nil
662+ clear(full[i].list[:cap(full[i].list)])
663+ full[i].list = full[i].list[:0]
661 }664 }
662 c.shots = out665 c.shots = out
663 return out666 return out

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