pane_owner.go RawHistoryFolder

1package daemon
2
3// paneOwner is an immutable routing snapshot for one published pane. A zero
4// floatingSlotGeneration identifies a tiled pane; installed floating panes
5// carry the tab slot generation that owns them.
6type paneOwner struct {
7	session                *session
8	tab                    *tab
9	generation             uint64
10	floatingSlotGeneration uint64
11}
12
13// paneEffectLease binds an effect to the exact immutable owner generation that
14// existed while the pane was parsed or otherwise inspected under pane.mu.
15type paneEffectLease struct {
16	pane  *pane
17	owner *paneOwner
18}
19
20// Current reports whether the lease still names the published pane owner. For
21// floating panes it also verifies that the same tab slot and slot generation
22// remain installed. Callers must not hold pane.mu or tab.mu.
23func (l paneEffectLease) Current() bool {
24	return l.pane != nil && l.pane.ownerLeaseCurrent(l)
25}
26
27// ownerSnapshot returns the immutable owner visible to lock-free routing
28// readers. Ownership publication itself is serialized under pane.mu.
29func (p *pane) ownerSnapshot() *paneOwner {
30	if p == nil {
31		return nil
32	}
33	return p.owner.Load()
34}
35
36// effectLeaseLocked captures the current owner while pane.mu linearizes VT
37// parsing against transfer. The caller must hold pane.mu.
38func (p *pane) effectLeaseLocked() paneEffectLease {
39	if p == nil {
40		return paneEffectLease{}
41	}
42	return paneEffectLease{pane: p, owner: p.owner.Load()}
43}
44
45// effectLease captures an owner generation outside an existing pane critical
46// section. Callers use effectLeaseLocked when parsing already owns pane.mu.
47func (p *pane) effectLease() paneEffectLease {
48	if p == nil {
49		return paneEffectLease{}
50	}
51	p.mu.Lock()
52	lease := p.effectLeaseLocked()
53	p.mu.Unlock()
54	return lease
55}
56
57// paneEffectSessionName snapshots log metadata only while the lease remains
58// current. Holding session.mu across the final pointer check linearizes the
59// snapshot with owner publication, whose move commit also owns the session.
60func paneEffectSessionName(lease paneEffectLease) (string, bool) {
61	if lease.pane == nil || lease.owner == nil || lease.owner.session == nil || !lease.Current() {
62		return "", false
63	}
64	lease.owner.session.mu.Lock()
65	current := lease.pane.owner.Load() == lease.owner
66	name := lease.owner.session.name
67	lease.owner.session.mu.Unlock()
68	return name, current
69}
70
71// publishOwnerLocked publishes a new immutable owner generation. The caller
72// must hold pane.mu, and must also hold tab.mu when publishing a floating owner.
73func (p *pane) publishOwnerLocked(sess *session, tb *tab, floatingSlotGeneration uint64) (paneEffectLease, paneEffectLease) {
74	if p == nil {
75		return paneEffectLease{}, paneEffectLease{}
76	}
77	old := paneEffectLease{pane: p, owner: p.owner.Load()}
78	p.ownerGeneration++
79	next := &paneOwner{
80		session:                sess,
81		tab:                    tb,
82		generation:             p.ownerGeneration,
83		floatingSlotGeneration: floatingSlotGeneration,
84	}
85	p.owner.Store(next)
86	return old, paneEffectLease{pane: p, owner: next}
87}
88
89// clearOwnerLocked revokes the published owner during terminal teardown. The
90// caller must hold pane.mu. The returned lease identifies the retired owner.
91func (p *pane) clearOwnerLocked() paneEffectLease {
92	if p == nil {
93		return paneEffectLease{}
94	}
95	old := paneEffectLease{pane: p, owner: p.owner.Load()}
96	if old.owner != nil {
97		p.ownerGeneration++
98		p.owner.Store(nil)
99	}
100	return old
101}
102
103func (p *pane) ownerLeaseCurrent(lease paneEffectLease) bool {
104	if p == nil || lease.pane != p || lease.owner == nil || p.owner.Load() != lease.owner {
105		return false
106	}
107	owner := lease.owner
108	if owner.session == nil || owner.tab == nil {
109		return false
110	}
111	if owner.floatingSlotGeneration == 0 {
112		return true
113	}
114	owner.tab.mu.Lock()
115	current := owner.tab.floating.pane == p &&
116		owner.tab.floating.generation == owner.floatingSlotGeneration &&
117		(owner.tab.floating.state == floatingHidden || owner.tab.floating.state == floatingVisible)
118	owner.tab.mu.Unlock()
119	return current && p.owner.Load() == owner
120}
121
122func publishPaneOwner(p *pane, sess *session, tb *tab, floatingSlotGeneration uint64) paneEffectLease {
123	if p == nil {
124		return paneEffectLease{}
125	}
126	p.mu.Lock()
127	_, lease := p.publishOwnerLocked(sess, tb, floatingSlotGeneration)
128	p.mu.Unlock()
129	return lease
130}
131
132// publishTiledPaneOwners initializes every pane in an unpublished tab before
133// that tab is made visible or any reader starts.
134func publishTiledPaneOwners(sess *session, tb *tab) {
135	if sess == nil || tb == nil {
136		return
137	}
138	tb.mu.Lock()
139	for _, p := range tb.panes {
140		publishPaneOwner(p, sess, tb, 0)
141	}
142	tb.mu.Unlock()
143}

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