detached 12f4382

refactor(core): pass lane span validity to laneWidth

commit
12f4382b95d57852235a69f997e163e146c47620
author
brice · · 2026-10-21 08:21 UTC
parent
faf772d
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +6 -10
M internal/core/border.go +1 -0
@@ -133,6 +133,7 @@ func (w *Workspace) setBorder(b border, pos int) bool {
133133 }
134134 stamped := !w.validSpans(first, last)
135135 if stamped {
136+ // Mutates spans, so it must not cache validity across this loop.
136137 w.spanSeq++
137138 used := 0
138139 for i := first; i <= last; i++ {
@@ -133,6 +133,7 @@ func (w *Workspace) setBorder(b border, pos int) bool {
133 }133 }
134 stamped := !w.validSpans(first, last)134 stamped := !w.validSpans(first, last)
135 if stamped {135 if stamped {
136+ // Mutates spans, so it must not cache validity across this loop.
136 w.spanSeq++137 w.spanSeq++
137 used := 0138 used := 0
138 for i := first; i <= last; i++ {139 for i := first; i <= last; i++ {
M internal/core/cascade.go +5 -10
@@ -82,7 +82,7 @@ func (w *Workspace) cellX(i int) int {
8282 x := w.gap()
8383 valid := w.validSpans(first, last)
8484 for j := first; j < i; j++ {
85- x += w.laneWidthWith(j, first, last, S, u, sum, valid) + w.gap()
85+ x += w.laneWidth(j, first, last, S, u, sum, valid) + w.gap()
8686 }
8787 return x
8888 }
@@ -99,7 +99,7 @@ func (w *Workspace) cascadeBands() (n, spacing int) {
9999 func (w *Workspace) cellWidth(i int) int {
100100 first, last := w.laneBounds(w.laneOf(i))
101101 S, u, sum := w.laneStats(first, last)
102- return w.laneWidth(i, first, last, S, u, sum)
102+ return w.laneWidth(i, first, last, S, u, sum, w.validSpans(first, last))
103103 }
104104
105105 // laneStats measures the lane first..last: S is the sum of the cells of
@@ -143,13 +143,8 @@ func (w *Workspace) laneWeight(i, S, u int) int {
143143 // laneWidth is the width of column i of the lane first..last with the
144144 // stats of laneStats: the usable width after gaps, split by weight. The
145145 // last column receives the pixel remainder, just as for stamped spans.
146-func (w *Workspace) laneWidth(i, first, last, S, u, sum int) int {
147- return w.laneWidthWith(i, first, last, S, u, sum, w.validSpans(first, last))
148-}
149-
150-// laneWidthWith is laneWidth with the lane's validSpans given, so a loop
151-// over the lane checks it once.
152-func (w *Workspace) laneWidthWith(i, first, last, S, u, sum int, spansValid bool) int {
146+// The caller passes the lane's validSpans so a loop over the lane checks it once.
147+func (w *Workspace) laneWidth(i, first, last, S, u, sum int, spansValid bool) int {
153148 if spansValid {
154149 avail := max(w.Usable.W-w.gap()*(last-first+2), 0)
155150 if i == last {
@@ -214,7 +209,7 @@ func (w *Workspace) cascadeRectsAt(dst []Rect, ignoreFullWidth bool, shift int)
214209 x := g
215210 valid := w.validSpans(first, last)
216211 for i := first; i <= last; i++ {
217- cw := w.laneWidthWith(i, first, last, S, u, sum, valid)
212+ cw := w.laneWidth(i, first, last, S, u, sum, valid)
218213 r := Rect{X: w.Usable.X + x, Y: w.Usable.Y + g + lane*w.Usable.H - view, W: cw, H: max(w.Usable.H-2*g, 0)}
219214 if w.Columns[i].FullWidth && !ignoreFullWidth {
220215 r.X = w.Usable.X + g
@@ -82,7 +82,7 @@ func (w *Workspace) cellX(i int) int {
82 x := w.gap()82 x := w.gap()
83 valid := w.validSpans(first, last)83 valid := w.validSpans(first, last)
84 for j := first; j < i; j++ {84 for j := first; j < i; j++ {
85- x += w.laneWidthWith(j, first, last, S, u, sum, valid) + w.gap()85+ x += w.laneWidth(j, first, last, S, u, sum, valid) + w.gap()
86 }86 }
87 return x87 return x
88 }88 }
@@ -99,7 +99,7 @@ func (w *Workspace) cascadeBands() (n, spacing int) {
99 func (w *Workspace) cellWidth(i int) int {99 func (w *Workspace) cellWidth(i int) int {
100 first, last := w.laneBounds(w.laneOf(i))100 first, last := w.laneBounds(w.laneOf(i))
101 S, u, sum := w.laneStats(first, last)101 S, u, sum := w.laneStats(first, last)
102- return w.laneWidth(i, first, last, S, u, sum)102+ return w.laneWidth(i, first, last, S, u, sum, w.validSpans(first, last))
103 }103 }
104 104
105 // laneStats measures the lane first..last: S is the sum of the cells of105 // laneStats measures the lane first..last: S is the sum of the cells of
@@ -143,13 +143,8 @@ func (w *Workspace) laneWeight(i, S, u int) int {
143 // laneWidth is the width of column i of the lane first..last with the143 // laneWidth is the width of column i of the lane first..last with the
144 // stats of laneStats: the usable width after gaps, split by weight. The144 // stats of laneStats: the usable width after gaps, split by weight. The
145 // last column receives the pixel remainder, just as for stamped spans.145 // last column receives the pixel remainder, just as for stamped spans.
146-func (w *Workspace) laneWidth(i, first, last, S, u, sum int) int {146+// The caller passes the lane's validSpans so a loop over the lane checks it once.
147- return w.laneWidthWith(i, first, last, S, u, sum, w.validSpans(first, last))147+func (w *Workspace) laneWidth(i, first, last, S, u, sum int, spansValid bool) int {
148-}
149-
150-// laneWidthWith is laneWidth with the lane's validSpans given, so a loop
151-// over the lane checks it once.
152-func (w *Workspace) laneWidthWith(i, first, last, S, u, sum int, spansValid bool) int {
153 if spansValid {148 if spansValid {
154 avail := max(w.Usable.W-w.gap()*(last-first+2), 0)149 avail := max(w.Usable.W-w.gap()*(last-first+2), 0)
155 if i == last {150 if i == last {
@@ -214,7 +209,7 @@ func (w *Workspace) cascadeRectsAt(dst []Rect, ignoreFullWidth bool, shift int)
214 x := g209 x := g
215 valid := w.validSpans(first, last)210 valid := w.validSpans(first, last)
216 for i := first; i <= last; i++ {211 for i := first; i <= last; i++ {
217- cw := w.laneWidthWith(i, first, last, S, u, sum, valid)212+ cw := w.laneWidth(i, first, last, S, u, sum, valid)
218 r := Rect{X: w.Usable.X + x, Y: w.Usable.Y + g + lane*w.Usable.H - view, W: cw, H: max(w.Usable.H-2*g, 0)}213 r := Rect{X: w.Usable.X + x, Y: w.Usable.Y + g + lane*w.Usable.H - view, W: cw, H: max(w.Usable.H-2*g, 0)}
219 if w.Columns[i].FullWidth && !ignoreFullWidth {214 if w.Columns[i].FullWidth && !ignoreFullWidth {
220 r.X = w.Usable.X + g215 r.X = w.Usable.X + g

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 26

Tags 10

↑↓ moveenter openesc close