session_inventory.go RawHistoryFolder

1package daemon
2
3import (
4	"time"
5)
6
7// inventoriedLiveSession pairs a live session pointer with its immutable
8// snapshot view. The pointer preserves exact current-session identity while
9// the view carries all display/policy facts, so projections never re-lock
10// the registry to re-read the same session.
11type inventoriedLiveSession struct {
12	sess *session
13	view sessionView
14}
15
16// localSessionInventory is the remote-free capture consumed by the prepared
17// local projections: the local catalogue export, the local navigation source
18// group, and the local picker/control projection. It copies active and
19// inactive records of this daemon only.
20//
21// d.mu is released before any per-session snapshot, preserving the
22// established lock ordering. Copied values are coherent per exact target,
23// not a distributed atomic transaction; callers revalidate at selection.
24type localSessionInventory struct {
25	live    []inventoriedLiveSession
26	stopped []inactiveSession
27	now     time.Time
28}
29
30// sessionInventory is the daemon-owned common capture consumed by the
31// palette, picker, and catalog export projections. The daemon observes only
32// its own sessions: other daemons reach the palette through the client's
33// route snapshot.
34type sessionInventory struct {
35	localSessionInventory
36}
37
38// captureLocalSessionInventory copies registry pointers and inactive records
39// under d.mu, then snapshots each live session without holding that lock. When
40// refreshTitles is true the focused-title refresh runs per session after the
41// registry lock is released, matching the historical picker/catalog cost;
42// palette passes false to avoid rich tab-title work it never displays. It
43// performs no remote-directory read.
44func (d *Daemon) captureLocalSessionInventory(opts viewOptions, refreshTitles bool) localSessionInventory {
45	var sessions []*session
46	var stopped []inactiveSession
47	if d != nil {
48		d.mu.Lock()
49		sessions = d.sessionsSnapshotLocked()
50		stopped = make([]inactiveSession, 0, len(d.inactive))
51		for _, entry := range d.inactive {
52			stopped = append(stopped, entry)
53		}
54		d.mu.Unlock()
55	}
56	if refreshTitles && d != nil {
57		for _, sess := range sessions {
58			d.refreshSessionFocusedTitles(sess)
59		}
60	}
61	live := make([]inventoriedLiveSession, 0, len(sessions))
62	for _, sess := range sessions {
63		if sess == nil {
64			continue
65		}
66		live = append(live, inventoriedLiveSession{sess: sess, view: sess.snapshotView(opts)})
67	}
68	return localSessionInventory{live: live, stopped: stopped, now: d.daemonNow()}
69}
70
71// captureSessionInventory is the palette, picker, and catalog capture.
72func (d *Daemon) captureSessionInventory(opts viewOptions, refreshTitles bool) sessionInventory {
73	return sessionInventory{localSessionInventory: d.captureLocalSessionInventory(opts, refreshTitles)}
74}
75
76// resumableStopped returns stopped sessions eligible for resume display,
77// preserving the palette's historical canResume projection.
78func (inv localSessionInventory) resumableStopped() []inactiveSession {
79	out := make([]inactiveSession, 0, len(inv.stopped))
80	for _, entry := range inv.stopped {
81		if entry.canResume() {
82			out = append(out, entry)
83		}
84	}
85	return out
86}
87
88// visibleStopped returns non-purging stopped sessions, preserving the
89// picker and catalog export projections.
90func (inv localSessionInventory) visibleStopped() []inactiveSession {
91	out := make([]inactiveSession, 0, len(inv.stopped))
92	for _, entry := range inv.stopped {
93		if entry.visible() {
94			out = append(out, entry)
95		}
96	}
97	return out
98}

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 12

Tags 11

↑↓ moveenter openesc close