refactor(daemon): collapse capture compose emit
- commit
- e178fea86b2918f59bd9132bd23bbbb33e9c2ec1
- author
- brice · · 2026-07-12 04:49 UTC
- parent
- 9819474
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +4 -18
M internal/usecase/daemon/render.go +1 -15
| @@ -61,20 +61,6 @@ func (d *Daemon) paneRenderable(sess *session, tb *tab, p *pane) bool { | |||
| 61 | 61 | return false | |
| 62 | 62 | } | |
| 63 | 63 | ||
| 64 | - | // clearNonRenderablePaneDamage is the single transitional S1 owner for VT | |
| 65 | - | // damage that cannot reach a composition target. S2 replaces this visibility | |
| 66 | - | // decision with pipeline ownership; do not paint or mutate renderer shadows | |
| 67 | - | // here. | |
| 68 | - | func (d *Daemon) clearNonRenderablePaneDamage(sess *session, tb *tab, p *pane) bool { | |
| 69 | - | renderable := d.paneRenderable(sess, tb, p) | |
| 70 | - | if !renderable && p != nil { | |
| 71 | - | p.mu.Lock() | |
| 72 | - | p.screen.ClearDamage() | |
| 73 | - | p.mu.Unlock() | |
| 74 | - | } | |
| 75 | - | return renderable | |
| 76 | - | } | |
| 77 | - | ||
| 78 | 64 | // tabIsPickerPreview reports whether any attached client currently composes | |
| 79 | 65 | // tb as a picker preview. It snapshots daemon ownership before taking overlay | |
| 80 | 66 | // locks, preserving the Daemon -> session -> tab -> pane lock order. | |
| @@ -158,7 +144,7 @@ func (d *Daemon) ptyReader(sess *session, tb *tab, p *pane) { | |||
| 158 | 144 | } | |
| 159 | 145 | } | |
| 160 | 146 | p.mu.Unlock() | |
| 161 | - | renderable := d.clearNonRenderablePaneDamage(sess, tb, p) | |
| 147 | + | renderable := d.paneRenderable(sess, tb, p) | |
| 162 | 148 | markSnapshotDirty(sess) | |
| 163 | 149 | select { | |
| 164 | 150 | case <-attentionCh: | |
| @@ -61,20 +61,6 @@ func (d *Daemon) paneRenderable(sess *session, tb *tab, p *pane) bool { | |||||
| 61 | return false | 61 | return false | ||
| 62 | } | 62 | } | ||
| 63 | 63 | ||||
| 64 | - | // clearNonRenderablePaneDamage is the single transitional S1 owner for VT | |||
| 65 | - | // damage that cannot reach a composition target. S2 replaces this visibility | |||
| 66 | - | // decision with pipeline ownership; do not paint or mutate renderer shadows | |||
| 67 | - | // here. | |||
| 68 | - | func (d *Daemon) clearNonRenderablePaneDamage(sess *session, tb *tab, p *pane) bool { | |||
| 69 | - | renderable := d.paneRenderable(sess, tb, p) | |||
| 70 | - | if !renderable && p != nil { | |||
| 71 | - | p.mu.Lock() | |||
| 72 | - | p.screen.ClearDamage() | |||
| 73 | - | p.mu.Unlock() | |||
| 74 | - | } | |||
| 75 | - | return renderable | |||
| 76 | - | } | |||
| 77 | - | ||||
| 78 | // tabIsPickerPreview reports whether any attached client currently composes | 64 | // tabIsPickerPreview reports whether any attached client currently composes | ||
| 79 | // tb as a picker preview. It snapshots daemon ownership before taking overlay | 65 | // tb as a picker preview. It snapshots daemon ownership before taking overlay | ||
| 80 | // locks, preserving the Daemon -> session -> tab -> pane lock order. | 66 | // locks, preserving the Daemon -> session -> tab -> pane lock order. | ||
| @@ -158,7 +144,7 @@ func (d *Daemon) ptyReader(sess *session, tb *tab, p *pane) { | |||||
| 158 | } | 144 | } | ||
| 159 | } | 145 | } | ||
| 160 | p.mu.Unlock() | 146 | p.mu.Unlock() | ||
| 161 | - | renderable := d.clearNonRenderablePaneDamage(sess, tb, p) | 147 | + | renderable := d.paneRenderable(sess, tb, p) |
| 162 | markSnapshotDirty(sess) | 148 | markSnapshotDirty(sess) | ||
| 163 | select { | 149 | select { | ||
| 164 | case <-attentionCh: | 150 | case <-attentionCh: | ||
M internal/usecase/daemon/render_test.go +3 -3
| @@ -410,7 +410,7 @@ func TestNonRenderablePaneDamageRemainsPendingForCapture(t *testing.T) { | |||
| 410 | 410 | d, sess, tb, p, sends := newFixture(t) | |
| 411 | 411 | tt.setup(d, sess, tb, p) | |
| 412 | 412 | p.screen.Write([]byte("damage")) | |
| 413 | - | d.clearNonRenderablePaneDamage(sess, tb, p) | |
| 413 | + | _ = d.paneRenderable(sess, tb, p) | |
| 414 | 414 | require.NotEmpty(t, p.screen.Damage(), "only render capture may consume VT damage") | |
| 415 | 415 | select { | |
| 416 | 416 | case frame := <-sends: | |
| @@ -424,7 +424,7 @@ func TestNonRenderablePaneDamageRemainsPendingForCapture(t *testing.T) { | |||
| 424 | 424 | t.Run("retains active and picker-preview pane damage", func(t *testing.T) { | |
| 425 | 425 | d, sess, tb, p, _ := newFixture(t) | |
| 426 | 426 | p.screen.Write([]byte("active")) | |
| 427 | - | d.clearNonRenderablePaneDamage(sess, tb, p) | |
| 427 | + | _ = d.paneRenderable(sess, tb, p) | |
| 428 | 428 | require.NotEmpty(t, p.screen.Damage(), "active pane damage belongs to coordinator composition") | |
| 429 | 429 | p.screen.ClearDamage() | |
| 430 | 430 | ||
| @@ -436,7 +436,7 @@ func TestNonRenderablePaneDamageRemainsPendingForCapture(t *testing.T) { | |||
| 436 | 436 | viewer.overlays.pickerMu.Unlock() | |
| 437 | 437 | d.sessions["viewer"] = &session{id: "viewer", client: viewer} | |
| 438 | 438 | p.screen.Write([]byte("preview")) | |
| 439 | - | d.clearNonRenderablePaneDamage(sess, tb, p) | |
| 439 | + | _ = d.paneRenderable(sess, tb, p) | |
| 440 | 440 | require.NotEmpty(t, p.screen.Damage(), "picker preview damage must remain for coordinator composition") | |
| 441 | 441 | }) | |
| 442 | 442 | } | |
| @@ -410,7 +410,7 @@ func TestNonRenderablePaneDamageRemainsPendingForCapture(t *testing.T) { | |||||
| 410 | d, sess, tb, p, sends := newFixture(t) | 410 | d, sess, tb, p, sends := newFixture(t) | ||
| 411 | tt.setup(d, sess, tb, p) | 411 | tt.setup(d, sess, tb, p) | ||
| 412 | p.screen.Write([]byte("damage")) | 412 | p.screen.Write([]byte("damage")) | ||
| 413 | - | d.clearNonRenderablePaneDamage(sess, tb, p) | 413 | + | _ = d.paneRenderable(sess, tb, p) |
| 414 | require.NotEmpty(t, p.screen.Damage(), "only render capture may consume VT damage") | 414 | require.NotEmpty(t, p.screen.Damage(), "only render capture may consume VT damage") | ||
| 415 | select { | 415 | select { | ||
| 416 | case frame := <-sends: | 416 | case frame := <-sends: | ||
| @@ -424,7 +424,7 @@ func TestNonRenderablePaneDamageRemainsPendingForCapture(t *testing.T) { | |||||
| 424 | t.Run("retains active and picker-preview pane damage", func(t *testing.T) { | 424 | t.Run("retains active and picker-preview pane damage", func(t *testing.T) { | ||
| 425 | d, sess, tb, p, _ := newFixture(t) | 425 | d, sess, tb, p, _ := newFixture(t) | ||
| 426 | p.screen.Write([]byte("active")) | 426 | p.screen.Write([]byte("active")) | ||
| 427 | - | d.clearNonRenderablePaneDamage(sess, tb, p) | 427 | + | _ = d.paneRenderable(sess, tb, p) |
| 428 | require.NotEmpty(t, p.screen.Damage(), "active pane damage belongs to coordinator composition") | 428 | require.NotEmpty(t, p.screen.Damage(), "active pane damage belongs to coordinator composition") | ||
| 429 | p.screen.ClearDamage() | 429 | p.screen.ClearDamage() | ||
| 430 | 430 | ||||
| @@ -436,7 +436,7 @@ func TestNonRenderablePaneDamageRemainsPendingForCapture(t *testing.T) { | |||||
| 436 | viewer.overlays.pickerMu.Unlock() | 436 | viewer.overlays.pickerMu.Unlock() | ||
| 437 | d.sessions["viewer"] = &session{id: "viewer", client: viewer} | 437 | d.sessions["viewer"] = &session{id: "viewer", client: viewer} | ||
| 438 | p.screen.Write([]byte("preview")) | 438 | p.screen.Write([]byte("preview")) | ||
| 439 | - | d.clearNonRenderablePaneDamage(sess, tb, p) | 439 | + | _ = d.paneRenderable(sess, tb, p) |
| 440 | require.NotEmpty(t, p.screen.Damage(), "picker preview damage must remain for coordinator composition") | 440 | require.NotEmpty(t, p.screen.Damage(), "picker preview damage must remain for coordinator composition") | ||
| 441 | }) | 441 | }) | ||
| 442 | } | 442 | } | ||