refactor(daemon): clarify floating geometry boundaries
- commit
- 883aaa92363de677cd1414bd616d952fe358821e
- author
- brice · · 2026-07-11 06:00 UTC
- parent
- 9dd5126
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +10 -6
M internal/usecase/daemon/floating_render.go +4 -2
| @@ -8,8 +8,10 @@ import ( | |||
| 8 | 8 | ) | |
| 9 | 9 | ||
| 10 | 10 | // floatingGeometry describes a popup's outer frame and terminal content area. | |
| 11 | - | // Committed geometry is tab-content-relative and origin-zero; Bounds and Inner | |
| 12 | - | // are both relative to tab content. | |
| 11 | + | // Bounds and Inner always share the same coordinate space. Committed pane | |
| 12 | + | // geometry is origin-zero and tab-content-relative; composeFloatingFrame | |
| 13 | + | // translates both fields and returns/caches frame-absolute geometry. Callers | |
| 14 | + | // must not translate a composed or cached value again. | |
| 13 | 15 | type floatingGeometry struct { | |
| 14 | 16 | Bounds domain.Rect | |
| 15 | 17 | Inner domain.Rect | |
| @@ -8,8 +8,10 @@ import ( | |||||
| 8 | ) | 8 | ) | ||
| 9 | 9 | ||||
| 10 | // floatingGeometry describes a popup's outer frame and terminal content area. | 10 | // floatingGeometry describes a popup's outer frame and terminal content area. | ||
| 11 | - | // Committed geometry is tab-content-relative and origin-zero; Bounds and Inner | 11 | + | // Bounds and Inner always share the same coordinate space. Committed pane |
| 12 | - | // are both relative to tab content. | 12 | + | // geometry is origin-zero and tab-content-relative; composeFloatingFrame |
| 13 | + | // translates both fields and returns/caches frame-absolute geometry. Callers | |||
| 14 | + | // must not translate a composed or cached value again. | |||
| 13 | type floatingGeometry struct { | 15 | type floatingGeometry struct { | ||
| 14 | Bounds domain.Rect | 16 | Bounds domain.Rect | ||
| 15 | Inner domain.Rect | 17 | Inner domain.Rect | ||
M internal/usecase/daemon/floating_render_test.go +6 -4
| @@ -309,14 +309,15 @@ func BenchmarkComposeFloatingFrameCached(b *testing.B) { | |||
| 309 | 309 | base := renderer.NewFrame(80, 24) | |
| 310 | 310 | content := domain.Rect{Y: 1, Width: 80, Height: 22} | |
| 311 | 311 | cfg := domain.FloatingConfig{Width: 80, Height: 80} | |
| 312 | + | desired := calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg) | |
| 312 | 313 | cache := &composedFrameCache{} | |
| 313 | - | composeFloatingFrame(base, nil, p, 1, content, calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg), tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | |
| 314 | + | composeFloatingFrame(base, nil, p, 1, content, desired, tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | |
| 314 | 315 | p.screen.ClearDamage() | |
| 315 | 316 | ||
| 316 | 317 | b.ReportAllocs() | |
| 317 | 318 | b.ResetTimer() | |
| 318 | 319 | for b.Loop() { | |
| 319 | - | composeFloatingFrame(base, nil, p, 1, content, calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg), tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | |
| 320 | + | composeFloatingFrame(base, nil, p, 1, content, desired, tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | |
| 320 | 321 | } | |
| 321 | 322 | } | |
| 322 | 323 | ||
| @@ -326,12 +327,13 @@ func TestComposeFloatingFrameCachedDoesNotAllocate(t *testing.T) { | |||
| 326 | 327 | base := renderer.NewFrame(80, 24) | |
| 327 | 328 | content := domain.Rect{Y: 1, Width: 80, Height: 22} | |
| 328 | 329 | cfg := domain.FloatingConfig{Width: 80, Height: 80} | |
| 330 | + | desired := calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg) | |
| 329 | 331 | cache := &composedFrameCache{} | |
| 330 | - | composeFloatingFrame(base, nil, p, 1, content, calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg), tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | |
| 332 | + | composeFloatingFrame(base, nil, p, 1, content, desired, tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | |
| 331 | 333 | p.screen.ClearDamage() | |
| 332 | 334 | ||
| 333 | 335 | allocs := testing.AllocsPerRun(100, func() { | |
| 334 | - | composeFloatingFrame(base, nil, p, 1, content, calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg), tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | |
| 336 | + | composeFloatingFrame(base, nil, p, 1, content, desired, tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | |
| 335 | 337 | }) | |
| 336 | 338 | require.Zero(t, allocs, "cached floating composition must not allocate without damage or title changes") | |
| 337 | 339 | } | |
| @@ -309,14 +309,15 @@ func BenchmarkComposeFloatingFrameCached(b *testing.B) { | |||||
| 309 | base := renderer.NewFrame(80, 24) | 309 | base := renderer.NewFrame(80, 24) | ||
| 310 | content := domain.Rect{Y: 1, Width: 80, Height: 22} | 310 | content := domain.Rect{Y: 1, Width: 80, Height: 22} | ||
| 311 | cfg := domain.FloatingConfig{Width: 80, Height: 80} | 311 | cfg := domain.FloatingConfig{Width: 80, Height: 80} | ||
| 312 | + | desired := calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg) | |||
| 312 | cache := &composedFrameCache{} | 313 | cache := &composedFrameCache{} | ||
| 313 | - | composeFloatingFrame(base, nil, p, 1, content, calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg), tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | 314 | + | composeFloatingFrame(base, nil, p, 1, content, desired, tabLayoutSnapshot{}, themeui.Theme{}, cache, false) |
| 314 | p.screen.ClearDamage() | 315 | p.screen.ClearDamage() | ||
| 315 | 316 | ||||
| 316 | b.ReportAllocs() | 317 | b.ReportAllocs() | ||
| 317 | b.ResetTimer() | 318 | b.ResetTimer() | ||
| 318 | for b.Loop() { | 319 | for b.Loop() { | ||
| 319 | - | composeFloatingFrame(base, nil, p, 1, content, calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg), tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | 320 | + | composeFloatingFrame(base, nil, p, 1, content, desired, tabLayoutSnapshot{}, themeui.Theme{}, cache, false) |
| 320 | } | 321 | } | ||
| 321 | } | 322 | } | ||
| 322 | 323 | ||||
| @@ -326,12 +327,13 @@ func TestComposeFloatingFrameCachedDoesNotAllocate(t *testing.T) { | |||||
| 326 | base := renderer.NewFrame(80, 24) | 327 | base := renderer.NewFrame(80, 24) | ||
| 327 | content := domain.Rect{Y: 1, Width: 80, Height: 22} | 328 | content := domain.Rect{Y: 1, Width: 80, Height: 22} | ||
| 328 | cfg := domain.FloatingConfig{Width: 80, Height: 80} | 329 | cfg := domain.FloatingConfig{Width: 80, Height: 80} | ||
| 330 | + | desired := calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg) | |||
| 329 | cache := &composedFrameCache{} | 331 | cache := &composedFrameCache{} | ||
| 330 | - | composeFloatingFrame(base, nil, p, 1, content, calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg), tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | 332 | + | composeFloatingFrame(base, nil, p, 1, content, desired, tabLayoutSnapshot{}, themeui.Theme{}, cache, false) |
| 331 | p.screen.ClearDamage() | 333 | p.screen.ClearDamage() | ||
| 332 | 334 | ||||
| 333 | allocs := testing.AllocsPerRun(100, func() { | 335 | allocs := testing.AllocsPerRun(100, func() { | ||
| 334 | - | composeFloatingFrame(base, nil, p, 1, content, calculateContentFloatingGeometry(domain.Size{Cols: content.Width, Rows: content.Height}, cfg), tabLayoutSnapshot{}, themeui.Theme{}, cache, false) | 336 | + | composeFloatingFrame(base, nil, p, 1, content, desired, tabLayoutSnapshot{}, themeui.Theme{}, cache, false) |
| 335 | }) | 337 | }) | ||
| 336 | require.Zero(t, allocs, "cached floating composition must not allocate without damage or title changes") | 338 | require.Zero(t, allocs, "cached floating composition must not allocate without damage or title changes") | ||
| 337 | } | 339 | } | ||