main bcc9a45

arena.go RawHistoryFolder

1package ui
2
3// elementArena hands out the elements of one frame from reusable chunks, so a
4// steady frame allocates no elements and keeps each element's slice capacity.
5// Chunks never move, so *element pointers stay valid until reset. The runtime
6// alternates two arenas: one holds the committed tree, which the next frame
7// reads as its previous tree, while the other is being rebuilt.
8type elementArena struct {
9	chunks [][]element
10	n      int // elements handed out since the last reset
11}
12
13const (
14	arenaChunk     = 32  // elements per chunk
15	arenaMaxChunks = 64  // retained chunks per arena (2048 elements)
16	elementMaxKeep = 256 // retained capacity of a per-element slice
17)
18
19func (a *elementArena) slot(i int) *element { return &a.chunks[i/arenaChunk][i%arenaChunk] }
20
21// newElement returns a zeroed element that is valid until the next reset.
22func (a *elementArena) newElement() *element {
23	if a == nil { // an arena-less frame, such as a hand-built test Frame
24		return &element{}
25	}
26	if a.n/arenaChunk == len(a.chunks) {
27		a.chunks = append(a.chunks, make([]element, arenaChunk))
28	}
29	e := a.slot(a.n)
30	a.n++
31	return e
32}
33
34// reset recycles every element handed out. It drops references so the old
35// tree can be collected, keeps modest slice capacity and releases chunks
36// beyond twice what the last frame needed, or the retention cap.
37func (a *elementArena) reset() {
38	for i := 0; i < a.n; i++ {
39		e := a.slot(i)
40		children, events, classes, nodes := e.children, e.events, e.classes, e.ln.Children
41		clear(children)
42		clear(events)
43		clear(classes)
44		clear(nodes)
45		*e = element{children: keep(children), events: keep(events), classes: keep(classes)}
46		e.ln.Children = keep(nodes)
47	}
48	needed := (a.n + arenaChunk - 1) / arenaChunk
49	if limit := min(2*needed+1, arenaMaxChunks); len(a.chunks) > limit {
50		clear(a.chunks[limit:])
51		a.chunks = a.chunks[:limit]
52	}
53	a.n = 0
54}
55
56func keep[T any](s []T) []T {
57	if cap(s) > elementMaxKeep {
58		return nil
59	}
60	return s[:0]
61}

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 1

Tags 12

↑↓ moveenter openesc close