detached 5e1cc30

refactor(usecase/daemon): delete dead move-picker, palette identity, and old preview helpers

Daemon.previewTarget and remotePaletteSessionIdentity have no caller left.
The old picker-preview generation cluster (snapshotPickerPreview,
pickerPreviewFromCapturedRender/FromFrame/FromLockedPane) is superseded by
the Phase D remote preview push path (captureRemotePreview), which crops the
pane snapshot directly and never touches VT damage or render state; its
dedicated test assertions about the old path are removed, keeping the
independent captureRenderState receipt-accounting coverage in the same test.

capturePaneRenderStateLocked is a thin wrapper over
capturePaneRenderStateLockedInto (unchanged, still the real production
entry point); its eight test call sites across three files are rewritten to
call capturePaneRenderStateLockedInto directly before the wrapper is
deleted.

ptrSessionAttachTarget is a trivial address-of helper used by six tests
across four files; it moves into a new same-package test helper file rather
than being inlined at every call site.
commit
5e1cc302d839af347f8164a9c2ad6bfb36dfeb5c
author
brice · · 2026-09-23 01:55 UTC
parent
c45bf3b
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
10 files · +21 -134
M internal/usecase/daemon/floating_render_test.go +2 -2
@@ -308,7 +308,7 @@ func TestComposeCapturedFloatingFrameClipsRetainedGeometryAfterFailedShrink(t *t
308308 require.False(t, applyFloatingResizePlanForTest(d, floatingPane, requested))
309309 require.Equal(t, retained, floatingPane.popupGeometry, "failed resize must retain the committed geometry")
310310 floatingPane.mu.Lock()
311- captured := capturePaneRenderStateLocked(floatingPane, retained.Inner)
311+ captured := capturePaneRenderStateLockedInto(floatingPane, retained.Inner, capturedPaneRenderState{})
312312 floatingPane.mu.Unlock()
313313
314314 var frame renderer.Frame
@@ -892,7 +892,7 @@ func TestFailedFloatingResizeKeepsCommittedRenderAndInputGeometry(t *testing.T)
892892 require.Equal(t, oldGeometry, inputGeometry)
893893
894894 p.mu.Lock()
895- captured := capturePaneRenderStateLocked(p, oldGeometry.Inner)
895+ captured := capturePaneRenderStateLockedInto(p, oldGeometry.Inner, capturedPaneRenderState{})
896896 p.mu.Unlock()
897897 base := renderer.NewFrame(newContent.Width, newContent.Height+2)
898898 frame, _ := composeCapturedFloatingFrame(floatingComposeInput{
@@ -308,7 +308,7 @@ func TestComposeCapturedFloatingFrameClipsRetainedGeometryAfterFailedShrink(t *t
308 require.False(t, applyFloatingResizePlanForTest(d, floatingPane, requested))308 require.False(t, applyFloatingResizePlanForTest(d, floatingPane, requested))
309 require.Equal(t, retained, floatingPane.popupGeometry, "failed resize must retain the committed geometry")309 require.Equal(t, retained, floatingPane.popupGeometry, "failed resize must retain the committed geometry")
310 floatingPane.mu.Lock()310 floatingPane.mu.Lock()
311- captured := capturePaneRenderStateLocked(floatingPane, retained.Inner)311+ captured := capturePaneRenderStateLockedInto(floatingPane, retained.Inner, capturedPaneRenderState{})
312 floatingPane.mu.Unlock()312 floatingPane.mu.Unlock()
313 313
314 var frame renderer.Frame314 var frame renderer.Frame
@@ -892,7 +892,7 @@ func TestFailedFloatingResizeKeepsCommittedRenderAndInputGeometry(t *testing.T)
892 require.Equal(t, oldGeometry, inputGeometry)892 require.Equal(t, oldGeometry, inputGeometry)
893 893
894 p.mu.Lock()894 p.mu.Lock()
895- captured := capturePaneRenderStateLocked(p, oldGeometry.Inner)895+ captured := capturePaneRenderStateLockedInto(p, oldGeometry.Inner, capturedPaneRenderState{})
896 p.mu.Unlock()896 p.mu.Unlock()
897 base := renderer.NewFrame(newContent.Width, newContent.Height+2)897 base := renderer.NewFrame(newContent.Width, newContent.Height+2)
898 frame, _ := composeCapturedFloatingFrame(floatingComposeInput{898 frame, _ := composeCapturedFloatingFrame(floatingComposeInput{
M internal/usecase/daemon/graphics_output_test.go +2 -2
@@ -204,9 +204,9 @@ func TestPaneGraphicsCoordinateGeometrySurvivesAttachmentResize(t *testing.T) {
204204 p.mu.Lock()
205205 setScreenGeometry(p.screen, oldGeometry)
206206 writePaneScreenLocked(p, fixture)
207- first := capturePaneRenderStateLocked(p, domain.Rect{Width: 80, Height: 24})
207+ first := capturePaneRenderStateLockedInto(p, domain.Rect{Width: 80, Height: 24}, capturedPaneRenderState{})
208208 setScreenGeometry(p.screen, newGeometry)
209- second := capturePaneRenderStateLocked(p, domain.Rect{Width: 80, Height: 24})
209+ second := capturePaneRenderStateLockedInto(p, domain.Rect{Width: 80, Height: 24}, capturedPaneRenderState{})
210210 p.mu.Unlock()
211211
212212 require.Equal(t, oldGeometry, first.graphicsGeometry)
@@ -204,9 +204,9 @@ func TestPaneGraphicsCoordinateGeometrySurvivesAttachmentResize(t *testing.T) {
204 p.mu.Lock()204 p.mu.Lock()
205 setScreenGeometry(p.screen, oldGeometry)205 setScreenGeometry(p.screen, oldGeometry)
206 writePaneScreenLocked(p, fixture)206 writePaneScreenLocked(p, fixture)
207- first := capturePaneRenderStateLocked(p, domain.Rect{Width: 80, Height: 24})207+ first := capturePaneRenderStateLockedInto(p, domain.Rect{Width: 80, Height: 24}, capturedPaneRenderState{})
208 setScreenGeometry(p.screen, newGeometry)208 setScreenGeometry(p.screen, newGeometry)
209- second := capturePaneRenderStateLocked(p, domain.Rect{Width: 80, Height: 24})209+ second := capturePaneRenderStateLockedInto(p, domain.Rect{Width: 80, Height: 24}, capturedPaneRenderState{})
210 p.mu.Unlock()210 p.mu.Unlock()
211 211
212 require.Equal(t, oldGeometry, first.graphicsGeometry)212 require.Equal(t, oldGeometry, first.graphicsGeometry)
M internal/usecase/daemon/move_picker.go +0 -33
@@ -94,36 +94,3 @@ func (d *Daemon) commitMovePickerSelection(intent protocol.PickerIntent, source
9494 return errMovePaneInvalid
9595 }
9696 }
97-
98-func (d *Daemon) previewTarget(target picker.Target, intent protocol.PickerIntent) (*session, *tab) {
99- d.mu.Lock()
100- sess := d.sessions[target.Session]
101- if sess == nil {
102- d.mu.Unlock()
103- return nil, nil
104- }
105- sess.mu.Lock()
106- d.mu.Unlock()
107- defer sess.mu.Unlock()
108- if sess.incarnation != target.Incarnation || !targetMatchesLifecycle(target, sess.name, sess.createdAt, sess.incarnation) {
109- return nil, nil
110- }
111- if intent == protocol.PickerIntentMoveTab {
112- if len(sess.tabs) == 0 {
113- return nil, nil
114- }
115- return sess, sess.tabs[0]
116- }
117- if target.TabID != "" {
118- for _, tb := range sess.tabs {
119- if domain.TabStableID(tb.stableID) == target.TabID {
120- return sess, tb
121- }
122- }
123- return nil, nil
124- }
125- if target.TabIndex < 0 || target.TabIndex >= len(sess.tabs) {
126- return nil, nil
127- }
128- return sess, sess.tabs[target.TabIndex]
129-}
@@ -94,36 +94,3 @@ func (d *Daemon) commitMovePickerSelection(intent protocol.PickerIntent, source
94 return errMovePaneInvalid94 return errMovePaneInvalid
95 }95 }
96 }96 }
97-
98-func (d *Daemon) previewTarget(target picker.Target, intent protocol.PickerIntent) (*session, *tab) {
99- d.mu.Lock()
100- sess := d.sessions[target.Session]
101- if sess == nil {
102- d.mu.Unlock()
103- return nil, nil
104- }
105- sess.mu.Lock()
106- d.mu.Unlock()
107- defer sess.mu.Unlock()
108- if sess.incarnation != target.Incarnation || !targetMatchesLifecycle(target, sess.name, sess.createdAt, sess.incarnation) {
109- return nil, nil
110- }
111- if intent == protocol.PickerIntentMoveTab {
112- if len(sess.tabs) == 0 {
113- return nil, nil
114- }
115- return sess, sess.tabs[0]
116- }
117- if target.TabID != "" {
118- for _, tb := range sess.tabs {
119- if domain.TabStableID(tb.stableID) == target.TabID {
120- return sess, tb
121- }
122- }
123- return nil, nil
124- }
125- if target.TabIndex < 0 || target.TabIndex >= len(sess.tabs) {
126- return nil, nil
127- }
128- return sess, sess.tabs[target.TabIndex]
129-}
M internal/usecase/daemon/palette.go +0 -4
@@ -77,10 +77,6 @@ func localPaletteSessionIdentity(lifecycle domain.SessionLifecycleID) paletteSes
7777 return paletteSessionIdentity{kind: protocol.RouteKindLocal, endpoint: "local", lifecycle: lifecycle}
7878 }
7979
80-func remotePaletteSessionIdentity(endpoint string, lifecycle domain.SessionLifecycleID) paletteSessionIdentity {
81- return paletteSessionIdentity{kind: protocol.RouteKindRemote, endpoint: endpoint, lifecycle: lifecycle}
82-}
83-
8480 func paletteRemoteDisplayOrigin(hostLabel string) string {
8581 origin := domain.RemoteDisplayOrigin(hostLabel)
8682 if origin == "" {
@@ -77,10 +77,6 @@ func localPaletteSessionIdentity(lifecycle domain.SessionLifecycleID) paletteSes
77 return paletteSessionIdentity{kind: protocol.RouteKindLocal, endpoint: "local", lifecycle: lifecycle}77 return paletteSessionIdentity{kind: protocol.RouteKindLocal, endpoint: "local", lifecycle: lifecycle}
78 }78 }
79 79
80-func remotePaletteSessionIdentity(endpoint string, lifecycle domain.SessionLifecycleID) paletteSessionIdentity {
81- return paletteSessionIdentity{kind: protocol.RouteKindRemote, endpoint: endpoint, lifecycle: lifecycle}
82-}
83-
84 func paletteRemoteDisplayOrigin(hostLabel string) string {80 func paletteRemoteDisplayOrigin(hostLabel string) string {
85 origin := domain.RemoteDisplayOrigin(hostLabel)81 origin := domain.RemoteDisplayOrigin(hostLabel)
86 if origin == "" {82 if origin == "" {
M internal/usecase/daemon/picker.go +0 -72
@@ -9,7 +9,6 @@ import (
99 renderer "github.com/bnema/vev-vt"
1010 "github.com/bnema/vev/internal/domain"
1111 "github.com/bnema/vev/internal/protocol"
12- "github.com/bnema/vev/internal/usecase/layout"
1312 "github.com/bnema/vev/internal/usecase/picker"
1413 "github.com/bnema/vev/internal/usecase/ui"
1514 )
@@ -762,74 +761,3 @@ func (d *Daemon) killPickerTarget(target picker.Target) error {
762761 }
763762 return nil
764763 }
765-
766-func snapshotPickerPreview(tb *tab) picker.Preview {
767- if tb == nil {
768- return picker.Preview{}
769- }
770- tb.mu.Lock()
771- layoutSnap := solveTabLayoutLocked(tb)
772- if !layoutSnap.ok {
773- p := tb.focusedPane()
774- if p == nil {
775- tb.mu.Unlock()
776- return picker.Preview{}
777- }
778- p.mu.Lock()
779- preview := pickerPreviewFromLockedPane(p)
780- p.mu.Unlock()
781- tb.mu.Unlock()
782- return preview
783- }
784- state := capturedRenderState{layout: capturedTabLayout{
785- area: layoutSnap.area, focus: layoutSnap.focus,
786- placements: append([]layout.Placement(nil), layoutSnap.placements...),
787- dividers: append([]layout.Divider(nil), layoutSnap.dividers...),
788- fingerprint: layoutSnap.fingerprint, valid: true,
789- }}
790- for _, placement := range layoutSnap.placements {
791- p := tb.panes[placement.ID]
792- if p == nil {
793- continue
794- }
795- visible := placement.Content
796- if placement.Collapsed {
797- visible = domain.Rect{}
798- }
799- p.mu.Lock()
800- captured := capturePaneRenderStateLocked(p, visible)
801- p.mu.Unlock()
802- captured.placement = placement
803- captured.focused = placement.ID == layoutSnap.focus
804- state.panes = append(state.panes, captured)
805- }
806- tb.mu.Unlock()
807- return pickerPreviewFromCapturedRender(state)
808-}
809-
810-func pickerPreviewFromCapturedRender(state capturedRenderState) picker.Preview {
811- composed := composeFrame(state, composeCacheInput{}, composeCacheInput{}).frame
812- if composed.Height < 2 {
813- return pickerPreviewFromFrame(composed)
814- }
815- rows := make([][]renderer.Cell, composed.Height-2)
816- for y := range rows {
817- rows[y] = append([]renderer.Cell(nil), composed.Row(y+1)...)
818- }
819- return picker.Preview{Rows: rows, Width: composed.Width, Height: len(rows)}
820-}
821-
822-func pickerPreviewFromLockedPane(p *pane) picker.Preview {
823- return pickerPreviewFromFrame(p.screen)
824-}
825-
826-func pickerPreviewFromFrame(frame renderer.CellSource) picker.Preview {
827- rows := make([][]renderer.Cell, frame.Rows())
828- for y := range rows {
829- rows[y] = make([]renderer.Cell, frame.Columns())
830- for x := range rows[y] {
831- rows[y][x] = frame.Cell(x, y)
832- }
833- }
834- return picker.Preview{Rows: rows, Width: frame.Columns(), Height: frame.Rows()}
835-}
@@ -9,7 +9,6 @@ import (
9 renderer "github.com/bnema/vev-vt"9 renderer "github.com/bnema/vev-vt"
10 "github.com/bnema/vev/internal/domain"10 "github.com/bnema/vev/internal/domain"
11 "github.com/bnema/vev/internal/protocol"11 "github.com/bnema/vev/internal/protocol"
12- "github.com/bnema/vev/internal/usecase/layout"
13 "github.com/bnema/vev/internal/usecase/picker"12 "github.com/bnema/vev/internal/usecase/picker"
14 "github.com/bnema/vev/internal/usecase/ui"13 "github.com/bnema/vev/internal/usecase/ui"
15 )14 )
@@ -762,74 +761,3 @@ func (d *Daemon) killPickerTarget(target picker.Target) error {
762 }761 }
763 return nil762 return nil
764 }763 }
765-
766-func snapshotPickerPreview(tb *tab) picker.Preview {
767- if tb == nil {
768- return picker.Preview{}
769- }
770- tb.mu.Lock()
771- layoutSnap := solveTabLayoutLocked(tb)
772- if !layoutSnap.ok {
773- p := tb.focusedPane()
774- if p == nil {
775- tb.mu.Unlock()
776- return picker.Preview{}
777- }
778- p.mu.Lock()
779- preview := pickerPreviewFromLockedPane(p)
780- p.mu.Unlock()
781- tb.mu.Unlock()
782- return preview
783- }
784- state := capturedRenderState{layout: capturedTabLayout{
785- area: layoutSnap.area, focus: layoutSnap.focus,
786- placements: append([]layout.Placement(nil), layoutSnap.placements...),
787- dividers: append([]layout.Divider(nil), layoutSnap.dividers...),
788- fingerprint: layoutSnap.fingerprint, valid: true,
789- }}
790- for _, placement := range layoutSnap.placements {
791- p := tb.panes[placement.ID]
792- if p == nil {
793- continue
794- }
795- visible := placement.Content
796- if placement.Collapsed {
797- visible = domain.Rect{}
798- }
799- p.mu.Lock()
800- captured := capturePaneRenderStateLocked(p, visible)
801- p.mu.Unlock()
802- captured.placement = placement
803- captured.focused = placement.ID == layoutSnap.focus
804- state.panes = append(state.panes, captured)
805- }
806- tb.mu.Unlock()
807- return pickerPreviewFromCapturedRender(state)
808-}
809-
810-func pickerPreviewFromCapturedRender(state capturedRenderState) picker.Preview {
811- composed := composeFrame(state, composeCacheInput{}, composeCacheInput{}).frame
812- if composed.Height < 2 {
813- return pickerPreviewFromFrame(composed)
814- }
815- rows := make([][]renderer.Cell, composed.Height-2)
816- for y := range rows {
817- rows[y] = append([]renderer.Cell(nil), composed.Row(y+1)...)
818- }
819- return picker.Preview{Rows: rows, Width: composed.Width, Height: len(rows)}
820-}
821-
822-func pickerPreviewFromLockedPane(p *pane) picker.Preview {
823- return pickerPreviewFromFrame(p.screen)
824-}
825-
826-func pickerPreviewFromFrame(frame renderer.CellSource) picker.Preview {
827- rows := make([][]renderer.Cell, frame.Rows())
828- for y := range rows {
829- rows[y] = make([]renderer.Cell, frame.Columns())
830- for x := range rows[y] {
831- rows[y][x] = frame.Cell(x, y)
832- }
833- }
834- return picker.Preview{Rows: rows, Width: frame.Columns(), Height: frame.Rows()}
835-}
M internal/usecase/daemon/remote_attach.go +0 -4
@@ -224,7 +224,3 @@ func remoteTargetTabIndexLocked(sess *session, target protocol.SessionAttachTarg
224224 }
225225 return target.ResolveTab(metadata)
226226 }
227-
228-func ptrSessionAttachTarget(target protocol.SessionAttachTarget) *protocol.SessionAttachTarget {
229- return &target
230-}
@@ -224,7 +224,3 @@ func remoteTargetTabIndexLocked(sess *session, target protocol.SessionAttachTarg
224 }224 }
225 return target.ResolveTab(metadata)225 return target.ResolveTab(metadata)
226 }226 }
227-
228-func ptrSessionAttachTarget(target protocol.SessionAttachTarget) *protocol.SessionAttachTarget {
229- return &target
230-}
M internal/usecase/daemon/render_capture.go +3 -7
@@ -179,13 +179,9 @@ func writePaneScreenLocked(p *pane, data []byte) {
179179 }
180180 }
181181
182-// capturePaneRenderStateLocked copies only the visible rectangle required by
183-// composition. It never copies scrollback/history and never lets the mutable
184-// VT frame's Cells or row-offset slices escape pane.mu.
185-func capturePaneRenderStateLocked(p *pane, visible domain.Rect) capturedPaneRenderState {
186- return capturePaneRenderStateLockedInto(p, visible, capturedPaneRenderState{})
187-}
188-
182+// capturePaneRenderStateLockedInto copies only the visible rectangle required
183+// by composition into out. It never copies scrollback/history and never lets
184+// the mutable VT frame's Cells or row-offset slices escape pane.mu.
189185 func capturePaneRenderStateLockedInto(p *pane, visible domain.Rect, out capturedPaneRenderState) capturedPaneRenderState {
190186 out.id, out.stableID, out.title, out.titleGeneration = p.id, domain.PaneStableID(p.stableID), p.displayTitleLocked(), p.title.generation
191187 // GraphicsSnapshot never allocates graphics state for a text-only screen and
@@ -179,13 +179,9 @@ func writePaneScreenLocked(p *pane, data []byte) {
179 }179 }
180 }180 }
181 181
182-// capturePaneRenderStateLocked copies only the visible rectangle required by182+// capturePaneRenderStateLockedInto copies only the visible rectangle required
183-// composition. It never copies scrollback/history and never lets the mutable183+// by composition into out. It never copies scrollback/history and never lets
184-// VT frame's Cells or row-offset slices escape pane.mu.184+// the mutable VT frame's Cells or row-offset slices escape pane.mu.
185-func capturePaneRenderStateLocked(p *pane, visible domain.Rect) capturedPaneRenderState {
186- return capturePaneRenderStateLockedInto(p, visible, capturedPaneRenderState{})
187-}
188-
189 func capturePaneRenderStateLockedInto(p *pane, visible domain.Rect, out capturedPaneRenderState) capturedPaneRenderState {185 func capturePaneRenderStateLockedInto(p *pane, visible domain.Rect, out capturedPaneRenderState) capturedPaneRenderState {
190 out.id, out.stableID, out.title, out.titleGeneration = p.id, domain.PaneStableID(p.stableID), p.displayTitleLocked(), p.title.generation186 out.id, out.stableID, out.title, out.titleGeneration = p.id, domain.PaneStableID(p.stableID), p.displayTitleLocked(), p.title.generation
191 // GraphicsSnapshot never allocates graphics state for a text-only screen and187 // GraphicsSnapshot never allocates graphics state for a text-only screen and
M internal/usecase/daemon/render_damage_receipt_test.go +1 -6
@@ -45,12 +45,7 @@ func TestPrimaryCaptureAloneRecordsDamageReceipts(t *testing.T) {
4545 p.screen.Write([]byte("preview-safe"))
4646 p.mu.Unlock()
4747
48- preview := snapshotPickerPreview(sess.tabs[0])
49- require.NotEmpty(t, preview.Rows)
50- require.Empty(t, ac.renderScratch.receipts, "picker preview must not create primary damage receipts")
51- p.mu.Lock()
52- require.NotEmpty(t, p.screen.Damage(), "picker preview must not acknowledge VT damage")
53- p.mu.Unlock()
48+ require.Empty(t, ac.renderScratch.receipts, "no receipt exists before any capture runs")
5449
5550 ac.sendMu.Lock()
5651 state, ok := captureRenderState(sess, ac, renderCaptureRequest{
@@ -45,12 +45,7 @@ func TestPrimaryCaptureAloneRecordsDamageReceipts(t *testing.T) {
45 p.screen.Write([]byte("preview-safe"))45 p.screen.Write([]byte("preview-safe"))
46 p.mu.Unlock()46 p.mu.Unlock()
47 47
48- preview := snapshotPickerPreview(sess.tabs[0])48+ require.Empty(t, ac.renderScratch.receipts, "no receipt exists before any capture runs")
49- require.NotEmpty(t, preview.Rows)
50- require.Empty(t, ac.renderScratch.receipts, "picker preview must not create primary damage receipts")
51- p.mu.Lock()
52- require.NotEmpty(t, p.screen.Damage(), "picker preview must not acknowledge VT damage")
53- p.mu.Unlock()
54 49
55 ac.sendMu.Lock()50 ac.sendMu.Lock()
56 state, ok := captureRenderState(sess, ac, renderCaptureRequest{51 state, ok := captureRenderState(sess, ac, renderCaptureRequest{
M internal/usecase/daemon/render_pipeline_test.go +4 -4
@@ -70,7 +70,7 @@ func TestCapturePaneRenderStateOwnsVisibleFrameWithoutConsumingDamage(t *testing
7070 p.screen.Write([]byte("old"))
7171
7272 p.mu.Lock()
73- captured := capturePaneRenderStateLocked(p, domain.Rect{Width: 3, Height: 1})
73+ captured := capturePaneRenderStateLockedInto(p, domain.Rect{Width: 3, Height: 1}, capturedPaneRenderState{})
7474 p.mu.Unlock()
7575
7676 require.Equal(t, 3, captured.frame.Width)
@@ -88,7 +88,7 @@ func TestCapturePaneRenderStateIsAlwaysNonDestructive(t *testing.T) {
8888 p.screen.Write([]byte("preview"))
8989
9090 p.mu.Lock()
91- _ = capturePaneRenderStateLocked(p, domain.Rect{Width: 8, Height: 2})
91+ _ = capturePaneRenderStateLockedInto(p, domain.Rect{Width: 8, Height: 2}, capturedPaneRenderState{})
9292 p.mu.Unlock()
9393
9494 require.NotEmpty(t, p.screen.Damage())
@@ -101,7 +101,7 @@ func TestCapturePaneRenderStateMalformedDamageFallsBackToFullRedraw(t *testing.T
101101 p.screen.Damage()[0] = renderer.Damage{Kind: renderer.DamageText, X: -1, Y: 0, Width: 4, Height: 1}
102102
103103 p.mu.Lock()
104- captured := capturePaneRenderStateLocked(p, domain.Rect{Width: 8, Height: 2})
104+ captured := capturePaneRenderStateLockedInto(p, domain.Rect{Width: 8, Height: 2}, capturedPaneRenderState{})
105105 p.mu.Unlock()
106106
107107 require.Equal(t, []renderer.Damage{renderer.FullRedraw()}, captured.damage)
@@ -113,7 +113,7 @@ func TestCapturePaneRenderStateCollapsedRetainsDamage(t *testing.T) {
113113 p.screen.Write([]byte("hidden"))
114114
115115 p.mu.Lock()
116- captured := capturePaneRenderStateLocked(p, domain.Rect{})
116+ captured := capturePaneRenderStateLockedInto(p, domain.Rect{}, capturedPaneRenderState{})
117117 p.mu.Unlock()
118118
119119 require.Zero(t, captured.frame.Width)
@@ -70,7 +70,7 @@ func TestCapturePaneRenderStateOwnsVisibleFrameWithoutConsumingDamage(t *testing
70 p.screen.Write([]byte("old"))70 p.screen.Write([]byte("old"))
71 71
72 p.mu.Lock()72 p.mu.Lock()
73- captured := capturePaneRenderStateLocked(p, domain.Rect{Width: 3, Height: 1})73+ captured := capturePaneRenderStateLockedInto(p, domain.Rect{Width: 3, Height: 1}, capturedPaneRenderState{})
74 p.mu.Unlock()74 p.mu.Unlock()
75 75
76 require.Equal(t, 3, captured.frame.Width)76 require.Equal(t, 3, captured.frame.Width)
@@ -88,7 +88,7 @@ func TestCapturePaneRenderStateIsAlwaysNonDestructive(t *testing.T) {
88 p.screen.Write([]byte("preview"))88 p.screen.Write([]byte("preview"))
89 89
90 p.mu.Lock()90 p.mu.Lock()
91- _ = capturePaneRenderStateLocked(p, domain.Rect{Width: 8, Height: 2})91+ _ = capturePaneRenderStateLockedInto(p, domain.Rect{Width: 8, Height: 2}, capturedPaneRenderState{})
92 p.mu.Unlock()92 p.mu.Unlock()
93 93
94 require.NotEmpty(t, p.screen.Damage())94 require.NotEmpty(t, p.screen.Damage())
@@ -101,7 +101,7 @@ func TestCapturePaneRenderStateMalformedDamageFallsBackToFullRedraw(t *testing.T
101 p.screen.Damage()[0] = renderer.Damage{Kind: renderer.DamageText, X: -1, Y: 0, Width: 4, Height: 1}101 p.screen.Damage()[0] = renderer.Damage{Kind: renderer.DamageText, X: -1, Y: 0, Width: 4, Height: 1}
102 102
103 p.mu.Lock()103 p.mu.Lock()
104- captured := capturePaneRenderStateLocked(p, domain.Rect{Width: 8, Height: 2})104+ captured := capturePaneRenderStateLockedInto(p, domain.Rect{Width: 8, Height: 2}, capturedPaneRenderState{})
105 p.mu.Unlock()105 p.mu.Unlock()
106 106
107 require.Equal(t, []renderer.Damage{renderer.FullRedraw()}, captured.damage)107 require.Equal(t, []renderer.Damage{renderer.FullRedraw()}, captured.damage)
@@ -113,7 +113,7 @@ func TestCapturePaneRenderStateCollapsedRetainsDamage(t *testing.T) {
113 p.screen.Write([]byte("hidden"))113 p.screen.Write([]byte("hidden"))
114 114
115 p.mu.Lock()115 p.mu.Lock()
116- captured := capturePaneRenderStateLocked(p, domain.Rect{})116+ captured := capturePaneRenderStateLockedInto(p, domain.Rect{}, capturedPaneRenderState{})
117 p.mu.Unlock()117 p.mu.Unlock()
118 118
119 require.Zero(t, captured.frame.Width)119 require.Zero(t, captured.frame.Width)
A internal/usecase/daemon/session_attach_target_test_helpers_test.go +9 -0
@@ -0,0 +1,9 @@
1+package daemon
2+
3+import "github.com/bnema/vev/internal/protocol"
4+
5+// ptrSessionAttachTarget builds the pointer form Resume.SessionTarget and
6+// similar fields require from a value literal.
7+func ptrSessionAttachTarget(target protocol.SessionAttachTarget) *protocol.SessionAttachTarget {
8+ return &target
9+}
@@ -0,0 +1,9 @@
1+package daemon
2+
3+import "github.com/bnema/vev/internal/protocol"
4+
5+// ptrSessionAttachTarget builds the pointer form Resume.SessionTarget and
6+// similar fields require from a value literal.
7+func ptrSessionAttachTarget(target protocol.SessionAttachTarget) *protocol.SessionAttachTarget {
8+ return &target
9+}

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