detached 7ccd74f

fix(floating): keep zero-inner publication atomic

commit
7ccd74f58cc0448406a4e88fbd5622b022f9f0db
author
brice · · 2026-07-27 17:23 UTC
parent
dae353e
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +32 -0
M internal/usecase/daemon/transactional_resize.go +2 -0
@@ -383,6 +383,8 @@ func (d *Daemon) applyVisibleFloatingLayoutForMember(sess *session, tb *tab, cur
383383 p.mu.Lock()
384384 p.popupGeometry = geometry
385385 p.mu.Unlock()
386+ tb.mu.Unlock()
387+ return nil, true
386388 }
387389 tb.mu.Unlock()
388390 if current != nil && !current() {
@@ -383,6 +383,8 @@ func (d *Daemon) applyVisibleFloatingLayoutForMember(sess *session, tb *tab, cur
383 p.mu.Lock()383 p.mu.Lock()
384 p.popupGeometry = geometry384 p.popupGeometry = geometry
385 p.mu.Unlock()385 p.mu.Unlock()
386+ tb.mu.Unlock()
387+ return nil, true
386 }388 }
387 tb.mu.Unlock()389 tb.mu.Unlock()
388 if current != nil && !current() {390 if current != nil && !current() {
M internal/usecase/daemon/transactional_resize_test.go +30 -0
@@ -617,6 +617,36 @@ func TestApplyVisibleFloatingLayoutPublishesSameSizeGeometryWithoutPTYResize(t *
617617 popup.mu.Unlock()
618618 }
619619
620+func TestZeroInnerFloatingDrawerPublicationDoesNotRecheckCurrent(t *testing.T) {
621+ cfg := domain.FloatingConfig{Width: 100, Height: 100}
622+ committed := calculateContentFloatingGeometry(domain.Size{Cols: 80, Rows: 22}, cfg)
623+ pty := &transactionalResizePTY{}
624+ popup := newPane("floating", pty, rectSize(committed.Inner))
625+ popup.rect = committed.Inner
626+ popup.popupGeometry = committed
627+ tb := newTab(nil, domain.Size{Cols: 79, Rows: 2})
628+ installTestFloating(tb, popup, true)
629+ d := newTestDaemon(t, nil, stubClock{})
630+ d.ApplyConfig(domain.Config{Floating: cfg})
631+ calls := 0
632+
633+ failed, ok := d.applyVisibleFloatingLayout(&session{tabs: []*tab{tb}}, tb, func() bool {
634+ calls++
635+ return calls == 1
636+ })
637+
638+ require.True(t, ok, "a publication accepted while current must not later report stale")
639+ require.Equal(t, 1, calls, "current must not be rechecked after publication")
640+ require.Empty(t, failed)
641+ require.Empty(t, pty.requested())
642+ requested := calculateContentFloatingGeometry(tb.size, cfg)
643+ popup.mu.Lock()
644+ require.Equal(t, requested, popup.popupGeometry)
645+ require.Equal(t, committed.Inner, popup.rect)
646+ require.Equal(t, rectSize(committed.Inner), domain.Size{Cols: popup.screen.Frame.Width, Rows: popup.screen.Frame.Height})
647+ popup.mu.Unlock()
648+}
649+
620650 func TestZeroInnerFloatingDrawerRejectsStaleRequestWithoutPhysicalPublication(t *testing.T) {
621651 cfg := domain.FloatingConfig{Width: 100, Height: 100}
622652 committed := calculateContentFloatingGeometry(domain.Size{Cols: 80, Rows: 22}, cfg)
@@ -617,6 +617,36 @@ func TestApplyVisibleFloatingLayoutPublishesSameSizeGeometryWithoutPTYResize(t *
617 popup.mu.Unlock()617 popup.mu.Unlock()
618 }618 }
619 619
620+func TestZeroInnerFloatingDrawerPublicationDoesNotRecheckCurrent(t *testing.T) {
621+ cfg := domain.FloatingConfig{Width: 100, Height: 100}
622+ committed := calculateContentFloatingGeometry(domain.Size{Cols: 80, Rows: 22}, cfg)
623+ pty := &transactionalResizePTY{}
624+ popup := newPane("floating", pty, rectSize(committed.Inner))
625+ popup.rect = committed.Inner
626+ popup.popupGeometry = committed
627+ tb := newTab(nil, domain.Size{Cols: 79, Rows: 2})
628+ installTestFloating(tb, popup, true)
629+ d := newTestDaemon(t, nil, stubClock{})
630+ d.ApplyConfig(domain.Config{Floating: cfg})
631+ calls := 0
632+
633+ failed, ok := d.applyVisibleFloatingLayout(&session{tabs: []*tab{tb}}, tb, func() bool {
634+ calls++
635+ return calls == 1
636+ })
637+
638+ require.True(t, ok, "a publication accepted while current must not later report stale")
639+ require.Equal(t, 1, calls, "current must not be rechecked after publication")
640+ require.Empty(t, failed)
641+ require.Empty(t, pty.requested())
642+ requested := calculateContentFloatingGeometry(tb.size, cfg)
643+ popup.mu.Lock()
644+ require.Equal(t, requested, popup.popupGeometry)
645+ require.Equal(t, committed.Inner, popup.rect)
646+ require.Equal(t, rectSize(committed.Inner), domain.Size{Cols: popup.screen.Frame.Width, Rows: popup.screen.Frame.Height})
647+ popup.mu.Unlock()
648+}
649+
620 func TestZeroInnerFloatingDrawerRejectsStaleRequestWithoutPhysicalPublication(t *testing.T) {650 func TestZeroInnerFloatingDrawerRejectsStaleRequestWithoutPhysicalPublication(t *testing.T) {
621 cfg := domain.FloatingConfig{Width: 100, Height: 100}651 cfg := domain.FloatingConfig{Width: 100, Height: 100}
622 committed := calculateContentFloatingGeometry(domain.Size{Cols: 80, Rows: 22}, cfg)652 committed := calculateContentFloatingGeometry(domain.Size{Cols: 80, Rows: 22}, cfg)

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