detached da24396

fix(overview): derive boundary dividers from rendered envelopes

commit
da243964d5cb85d3265b24b87b6190427e6fd1d0
author
brice · · 2026-10-06 14:34 UTC
parent
6ee8ac0
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +41 -1
M internal/core/core.go +1 -1
@@ -627,7 +627,7 @@ func (c *Core) publishFrame(ctx context.Context, only *screen) error {
627627 }
628628 if sc.mon.ov.open {
629629 // Frame the selection and separate numbered and named row groups.
630- _, scene.Separators = sc.mon.overviewRows()
630+ scene.Separators = sc.mon.overviewDividers(layout)
631631 scene.Separators = append(scene.Separators, overviewOutline(layout, max(c.cfg.Border.Width, 2))...)
632632 } else {
633633 // Only the focused output lights the focused window's lines.
@@ -627,7 +627,7 @@ func (c *Core) publishFrame(ctx context.Context, only *screen) error {
627 }627 }
628 if sc.mon.ov.open {628 if sc.mon.ov.open {
629 // Frame the selection and separate numbered and named row groups.629 // Frame the selection and separate numbered and named row groups.
630- _, scene.Separators = sc.mon.overviewRows()630+ scene.Separators = sc.mon.overviewDividers(layout)
631 scene.Separators = append(scene.Separators, overviewOutline(layout, max(c.cfg.Border.Width, 2))...)631 scene.Separators = append(scene.Separators, overviewOutline(layout, max(c.cfg.Border.Width, 2))...)
632 } else {632 } else {
633 // Only the focused output lights the focused window's lines.633 // Only the focused output lights the focused window's lines.
M internal/core/overview.go +40 -0
@@ -625,6 +625,46 @@ func (m *Monitor) overviewLayout(result []Placement) []Placement {
625625 return result
626626 }
627627
628+// overviewDividers uses final placements so rules cannot cross translated cards.
629+func (m *Monitor) overviewDividers(layout []Placement) []ports.Separator {
630+ if m.Current().policy().workspace != horizontalAxis {
631+ _, lines := m.overviewRows()
632+ return lines
633+ }
634+ cur := m.Current()
635+ list := m.overviewWorkspaces()
636+ at := indexOf(list, cur)
637+ bounds := func(w *Workspace) (int, int) {
638+ lo, hi := int(^uint(0)>>1), -int(^uint(0)>>1)
639+ for _, p := range layout {
640+ owner, _ := m.find(p.ID)
641+ if owner == w && !p.Hidden {
642+ lo = min(lo, p.Rect.X)
643+ hi = max(hi, p.Rect.X+p.Rect.W)
644+ }
645+ }
646+ return lo, hi
647+ }
648+ left, right := bounds(cur)
649+ u := cur.overviewArea()
650+ var lines []ports.Separator
651+ for _, i := range []int{at - 1, at + 1} {
652+ if i < 0 || i >= len(list) || m.isHidden(list[i]) == m.isHidden(cur) {
653+ continue
654+ }
655+ lo, hi := bounds(list[i])
656+ if lo > hi {
657+ continue
658+ }
659+ x := (right + lo) / 2
660+ if i < at {
661+ x = (hi + left) / 2
662+ }
663+ lines = append(lines, ports.Separator{Rect: Rect{X: x, Y: u.Y + u.H*4/100, W: 1, H: u.H * 92 / 100}})
664+ }
665+ return lines
666+}
667+
628668 // fan places front and neighboring cards, farthest visible first and front
629669 // last. A card may contain several tiles; omitted cards stay in the layout
630670 // hidden so their clients are not left showing on screen.
@@ -625,6 +625,46 @@ func (m *Monitor) overviewLayout(result []Placement) []Placement {
625 return result625 return result
626 }626 }
627 627
628+// overviewDividers uses final placements so rules cannot cross translated cards.
629+func (m *Monitor) overviewDividers(layout []Placement) []ports.Separator {
630+ if m.Current().policy().workspace != horizontalAxis {
631+ _, lines := m.overviewRows()
632+ return lines
633+ }
634+ cur := m.Current()
635+ list := m.overviewWorkspaces()
636+ at := indexOf(list, cur)
637+ bounds := func(w *Workspace) (int, int) {
638+ lo, hi := int(^uint(0)>>1), -int(^uint(0)>>1)
639+ for _, p := range layout {
640+ owner, _ := m.find(p.ID)
641+ if owner == w && !p.Hidden {
642+ lo = min(lo, p.Rect.X)
643+ hi = max(hi, p.Rect.X+p.Rect.W)
644+ }
645+ }
646+ return lo, hi
647+ }
648+ left, right := bounds(cur)
649+ u := cur.overviewArea()
650+ var lines []ports.Separator
651+ for _, i := range []int{at - 1, at + 1} {
652+ if i < 0 || i >= len(list) || m.isHidden(list[i]) == m.isHidden(cur) {
653+ continue
654+ }
655+ lo, hi := bounds(list[i])
656+ if lo > hi {
657+ continue
658+ }
659+ x := (right + lo) / 2
660+ if i < at {
661+ x = (hi + left) / 2
662+ }
663+ lines = append(lines, ports.Separator{Rect: Rect{X: x, Y: u.Y + u.H*4/100, W: 1, H: u.H * 92 / 100}})
664+ }
665+ return lines
666+}
667+
628 // fan places front and neighboring cards, farthest visible first and front668 // fan places front and neighboring cards, farthest visible first and front
629 // last. A card may contain several tiles; omitted cards stay in the layout669 // last. A card may contain several tiles; omitted cards stay in the layout
630 // hidden so their clients are not left showing on screen.670 // hidden so their clients are not left showing on screen.

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