fix(palette): integrate wrap-up findings
- commit
- 8f95b0e103b06a470df04b5d02e2620d9a888006
- author
- brice · · 2026-07-15 07:20 UTC
- committer
- brice · · 2026-07-15 07:49 UTC
- parent
- 77cef84
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +27 -22
M internal/usecase/daemon/config_test.go +4 -5
| @@ -8,7 +8,6 @@ import ( | |||
| 8 | 8 | "github.com/bnema/vev/internal/domain" | |
| 9 | 9 | "github.com/bnema/vev/internal/ports" | |
| 10 | 10 | "github.com/bnema/vev/internal/usecase/keys" | |
| 11 | - | "github.com/bnema/vev/internal/usecase/palette" | |
| 12 | 11 | ) | |
| 13 | 12 | ||
| 14 | 13 | type captureKeyHandler struct { | |
| @@ -98,12 +97,12 @@ func TestApplyConfigRepaintsActivePaletteWithoutReplacingModel(t *testing.T) { | |||
| 98 | 97 | require.Equal(t, query, ac.overlays.palette.Query()) | |
| 99 | 98 | selectedAfter, ok := ac.overlays.palette.Selected() | |
| 100 | 99 | require.True(t, ok) | |
| 101 | - | selectedCommand, ok := selected.(palette.CommandResult) | |
| 100 | + | selectedCommand, ok := selected.Command() | |
| 102 | 101 | require.True(t, ok) | |
| 103 | - | selectedAfterCommand, ok := selectedAfter.(palette.CommandResult) | |
| 102 | + | selectedAfterCommand, ok := selectedAfter.Command() | |
| 104 | 103 | require.True(t, ok) | |
| 105 | - | require.Equal(t, selectedCommand.Command().Slug, selectedAfterCommand.Command().Slug) | |
| 106 | - | require.Equal(t, selectedCommand.Command().Code, selectedAfterCommand.Command().Code) | |
| 104 | + | require.Equal(t, selectedCommand.Slug, selectedAfterCommand.Slug) | |
| 105 | + | require.Equal(t, selectedCommand.Code, selectedAfterCommand.Code) | |
| 107 | 106 | } | |
| 108 | 107 | ||
| 109 | 108 | func TestApplyConfigPublishesImmutableFloatingSnapshot(t *testing.T) { | |
| @@ -8,7 +8,6 @@ import ( | |||||
| 8 | "github.com/bnema/vev/internal/domain" | 8 | "github.com/bnema/vev/internal/domain" | ||
| 9 | "github.com/bnema/vev/internal/ports" | 9 | "github.com/bnema/vev/internal/ports" | ||
| 10 | "github.com/bnema/vev/internal/usecase/keys" | 10 | "github.com/bnema/vev/internal/usecase/keys" | ||
| 11 | - | "github.com/bnema/vev/internal/usecase/palette" | |||
| 12 | ) | 11 | ) | ||
| 13 | 12 | ||||
| 14 | type captureKeyHandler struct { | 13 | type captureKeyHandler struct { | ||
| @@ -98,12 +97,12 @@ func TestApplyConfigRepaintsActivePaletteWithoutReplacingModel(t *testing.T) { | |||||
| 98 | require.Equal(t, query, ac.overlays.palette.Query()) | 97 | require.Equal(t, query, ac.overlays.palette.Query()) | ||
| 99 | selectedAfter, ok := ac.overlays.palette.Selected() | 98 | selectedAfter, ok := ac.overlays.palette.Selected() | ||
| 100 | require.True(t, ok) | 99 | require.True(t, ok) | ||
| 101 | - | selectedCommand, ok := selected.(palette.CommandResult) | 100 | + | selectedCommand, ok := selected.Command() |
| 102 | require.True(t, ok) | 101 | require.True(t, ok) | ||
| 103 | - | selectedAfterCommand, ok := selectedAfter.(palette.CommandResult) | 102 | + | selectedAfterCommand, ok := selectedAfter.Command() |
| 104 | require.True(t, ok) | 103 | require.True(t, ok) | ||
| 105 | - | require.Equal(t, selectedCommand.Command().Slug, selectedAfterCommand.Command().Slug) | 104 | + | require.Equal(t, selectedCommand.Slug, selectedAfterCommand.Slug) |
| 106 | - | require.Equal(t, selectedCommand.Command().Code, selectedAfterCommand.Command().Code) | 105 | + | require.Equal(t, selectedCommand.Code, selectedAfterCommand.Code) |
| 107 | } | 106 | } | ||
| 108 | 107 | ||||
| 109 | func TestApplyConfigPublishesImmutableFloatingSnapshot(t *testing.T) { | 108 | func TestApplyConfigPublishesImmutableFloatingSnapshot(t *testing.T) { | ||
M internal/usecase/daemon/palette.go +14 -8
| @@ -67,7 +67,7 @@ func (d *Daemon) paletteResults(current *session, commands []command.Command) [] | |||
| 67 | 67 | for _, cmd := range commands { | |
| 68 | 68 | results = append(results, palette.NewCommandResult(cmd)) | |
| 69 | 69 | } | |
| 70 | - | active := make([]palette.SessionResult, 0, len(sessions)) | |
| 70 | + | active := make([]palette.Result, 0, len(sessions)) | |
| 71 | 71 | for _, candidate := range sessions { | |
| 72 | 72 | if candidate == current { | |
| 73 | 73 | continue | |
| @@ -80,7 +80,11 @@ func (d *Daemon) paletteResults(current *session, commands []command.Command) [] | |||
| 80 | 80 | active = append(active, palette.NewActiveSessionResult(name, time.Unix(0, createdAt), id)) | |
| 81 | 81 | } | |
| 82 | 82 | } | |
| 83 | - | sort.Slice(active, func(i, j int) bool { return active[i].Name() < active[j].Name() }) | |
| 83 | + | sort.Slice(active, func(i, j int) bool { | |
| 84 | + | left, _ := active[i].SessionName() | |
| 85 | + | right, _ := active[j].SessionName() | |
| 86 | + | return left < right | |
| 87 | + | }) | |
| 84 | 88 | sort.Slice(stopped, func(i, j int) bool { return stopped[i].name < stopped[j].name }) | |
| 85 | 89 | for _, candidate := range active { | |
| 86 | 90 | results = append(results, candidate) | |
| @@ -150,7 +154,7 @@ func (d *Daemon) handlePaletteInput(ac *attachedClient, data []byte) { | |||
| 150 | 154 | return | |
| 151 | 155 | } | |
| 152 | 156 | var cmd command.Command | |
| 153 | - | var sessionTarget palette.SessionResult | |
| 157 | + | var sessionTarget palette.Result | |
| 154 | 158 | var hasSessionTarget bool | |
| 155 | 159 | var args []string | |
| 156 | 160 | var recent []recentSession | |
| @@ -209,7 +213,7 @@ func (d *Daemon) handlePaletteInput(ac *attachedClient, data []byte) { | |||
| 209 | 213 | return | |
| 210 | 214 | } | |
| 211 | 215 | rawQuery = ac.overlays.palette.Query() | |
| 212 | - | if selectedCommand, ok := selected.CommandInfo(); ok { | |
| 216 | + | if selectedCommand, ok := selected.Command(); ok { | |
| 213 | 217 | cmd = selectedCommand | |
| 214 | 218 | // JRS is contextual: fuzzy selection cannot turn an unrelated | |
| 215 | 219 | // query into a jump. | |
| @@ -222,8 +226,8 @@ func (d *Daemon) handlePaletteInput(ac *attachedClient, data []byte) { | |||
| 222 | 226 | args = action.Args | |
| 223 | 227 | recent = append([]recentSession(nil), ac.overlays.paletteRecent...) | |
| 224 | 228 | } | |
| 225 | - | } else if selectedSession, ok := selected.Session(); ok { | |
| 226 | - | sessionTarget = selectedSession | |
| 229 | + | } else if _, ok := selected.SessionName(); ok { | |
| 230 | + | sessionTarget = selected | |
| 227 | 231 | hasSessionTarget = true | |
| 228 | 232 | } else { | |
| 229 | 233 | changed = true | |
| @@ -258,8 +262,10 @@ func (d *Daemon) handlePaletteInput(ac *attachedClient, data []byte) { | |||
| 258 | 262 | } | |
| 259 | 263 | ||
| 260 | 264 | if hasSessionTarget { | |
| 261 | - | createdAt := sessionTarget.CreatedAt().UnixNano() | |
| 262 | - | target := picker.Target{Name: sessionTarget.Name(), TabIndex: -1, ExpectedCreatedAt: &createdAt} | |
| 265 | + | createdAt, _ := sessionTarget.SessionCreatedAt() | |
| 266 | + | expectedCreatedAt := createdAt.UnixNano() | |
| 267 | + | name, _ := sessionTarget.SessionName() | |
| 268 | + | target := picker.Target{Name: name, TabIndex: -1, ExpectedCreatedAt: &expectedCreatedAt} | |
| 263 | 269 | if id, active := sessionTarget.SessionID(); active { | |
| 264 | 270 | target.Session = id | |
| 265 | 271 | } else { | |
| @@ -67,7 +67,7 @@ func (d *Daemon) paletteResults(current *session, commands []command.Command) [] | |||||
| 67 | for _, cmd := range commands { | 67 | for _, cmd := range commands { | ||
| 68 | results = append(results, palette.NewCommandResult(cmd)) | 68 | results = append(results, palette.NewCommandResult(cmd)) | ||
| 69 | } | 69 | } | ||
| 70 | - | active := make([]palette.SessionResult, 0, len(sessions)) | 70 | + | active := make([]palette.Result, 0, len(sessions)) |
| 71 | for _, candidate := range sessions { | 71 | for _, candidate := range sessions { | ||
| 72 | if candidate == current { | 72 | if candidate == current { | ||
| 73 | continue | 73 | continue | ||
| @@ -80,7 +80,11 @@ func (d *Daemon) paletteResults(current *session, commands []command.Command) [] | |||||
| 80 | active = append(active, palette.NewActiveSessionResult(name, time.Unix(0, createdAt), id)) | 80 | active = append(active, palette.NewActiveSessionResult(name, time.Unix(0, createdAt), id)) | ||
| 81 | } | 81 | } | ||
| 82 | } | 82 | } | ||
| 83 | - | sort.Slice(active, func(i, j int) bool { return active[i].Name() < active[j].Name() }) | 83 | + | sort.Slice(active, func(i, j int) bool { |
| 84 | + | left, _ := active[i].SessionName() | |||
| 85 | + | right, _ := active[j].SessionName() | |||
| 86 | + | return left < right | |||
| 87 | + | }) | |||
| 84 | sort.Slice(stopped, func(i, j int) bool { return stopped[i].name < stopped[j].name }) | 88 | sort.Slice(stopped, func(i, j int) bool { return stopped[i].name < stopped[j].name }) | ||
| 85 | for _, candidate := range active { | 89 | for _, candidate := range active { | ||
| 86 | results = append(results, candidate) | 90 | results = append(results, candidate) | ||
| @@ -150,7 +154,7 @@ func (d *Daemon) handlePaletteInput(ac *attachedClient, data []byte) { | |||||
| 150 | return | 154 | return | ||
| 151 | } | 155 | } | ||
| 152 | var cmd command.Command | 156 | var cmd command.Command | ||
| 153 | - | var sessionTarget palette.SessionResult | 157 | + | var sessionTarget palette.Result |
| 154 | var hasSessionTarget bool | 158 | var hasSessionTarget bool | ||
| 155 | var args []string | 159 | var args []string | ||
| 156 | var recent []recentSession | 160 | var recent []recentSession | ||
| @@ -209,7 +213,7 @@ func (d *Daemon) handlePaletteInput(ac *attachedClient, data []byte) { | |||||
| 209 | return | 213 | return | ||
| 210 | } | 214 | } | ||
| 211 | rawQuery = ac.overlays.palette.Query() | 215 | rawQuery = ac.overlays.palette.Query() | ||
| 212 | - | if selectedCommand, ok := selected.CommandInfo(); ok { | 216 | + | if selectedCommand, ok := selected.Command(); ok { |
| 213 | cmd = selectedCommand | 217 | cmd = selectedCommand | ||
| 214 | // JRS is contextual: fuzzy selection cannot turn an unrelated | 218 | // JRS is contextual: fuzzy selection cannot turn an unrelated | ||
| 215 | // query into a jump. | 219 | // query into a jump. | ||
| @@ -222,8 +226,8 @@ func (d *Daemon) handlePaletteInput(ac *attachedClient, data []byte) { | |||||
| 222 | args = action.Args | 226 | args = action.Args | ||
| 223 | recent = append([]recentSession(nil), ac.overlays.paletteRecent...) | 227 | recent = append([]recentSession(nil), ac.overlays.paletteRecent...) | ||
| 224 | } | 228 | } | ||
| 225 | - | } else if selectedSession, ok := selected.Session(); ok { | 229 | + | } else if _, ok := selected.SessionName(); ok { |
| 226 | - | sessionTarget = selectedSession | 230 | + | sessionTarget = selected |
| 227 | hasSessionTarget = true | 231 | hasSessionTarget = true | ||
| 228 | } else { | 232 | } else { | ||
| 229 | changed = true | 233 | changed = true | ||
| @@ -258,8 +262,10 @@ func (d *Daemon) handlePaletteInput(ac *attachedClient, data []byte) { | |||||
| 258 | } | 262 | } | ||
| 259 | 263 | ||||
| 260 | if hasSessionTarget { | 264 | if hasSessionTarget { | ||
| 261 | - | createdAt := sessionTarget.CreatedAt().UnixNano() | 265 | + | createdAt, _ := sessionTarget.SessionCreatedAt() |
| 262 | - | target := picker.Target{Name: sessionTarget.Name(), TabIndex: -1, ExpectedCreatedAt: &createdAt} | 266 | + | expectedCreatedAt := createdAt.UnixNano() |
| 267 | + | name, _ := sessionTarget.SessionName() | |||
| 268 | + | target := picker.Target{Name: name, TabIndex: -1, ExpectedCreatedAt: &expectedCreatedAt} | |||
| 263 | if id, active := sessionTarget.SessionID(); active { | 269 | if id, active := sessionTarget.SessionID(); active { | ||
| 264 | target.Session = id | 270 | target.Session = id | ||
| 265 | } else { | 271 | } else { | ||
M internal/usecase/daemon/palette_test.go +9 -9
| @@ -63,8 +63,8 @@ func TestPaletteEntryPublishesEligibleNamedSessionResults(t *testing.T) { | |||
| 63 | 63 | ||
| 64 | 64 | got := map[string]palette.ResultKind{} | |
| 65 | 65 | for _, match := range ac.overlays.palette.Matches() { | |
| 66 | - | if result, ok := match.Result.(palette.SessionResult); ok { | |
| 67 | - | got[result.Name()] = result.Kind() | |
| 66 | + | if name, ok := match.Result.SessionName(); ok { | |
| 67 | + | got[name] = match.Result.Kind() | |
| 68 | 68 | } | |
| 69 | 69 | } | |
| 70 | 70 | require.Equal(t, map[string]palette.ResultKind{ | |
| @@ -85,7 +85,7 @@ func TestPaletteSessionFailureFeedbackClearsOnQueryChange(t *testing.T) { | |||
| 85 | 85 | ac.overlays.paletteMu.Lock() | |
| 86 | 86 | selected, ok := ac.overlays.palette.Selected() | |
| 87 | 87 | ac.overlays.paletteMu.Unlock() | |
| 88 | - | _, isSession := selected.(palette.SessionResult) | |
| 88 | + | _, isSession := selected.SessionName() | |
| 89 | 89 | require.True(t, ok) | |
| 90 | 90 | require.True(t, isSession) | |
| 91 | 91 | d.mu.Lock() | |
| @@ -455,9 +455,9 @@ func TestPaletteReopensWithSuccessfulCommandFirst(t *testing.T) { | |||
| 455 | 455 | awaitFrame(t, sends, ports.MsgOutput) | |
| 456 | 456 | result, ok := ac.overlays.palette.Selected() | |
| 457 | 457 | require.True(t, ok) | |
| 458 | - | cmd, ok := result.(palette.CommandResult) | |
| 458 | + | cmd, ok := result.Command() | |
| 459 | 459 | require.True(t, ok) | |
| 460 | - | require.Equal(t, "NXT", cmd.Command().Code) | |
| 460 | + | require.Equal(t, "NXT", cmd.Code) | |
| 461 | 461 | } | |
| 462 | 462 | ||
| 463 | 463 | func TestPaletteRecentCommandsNewestFirstThenRegistryOrder(t *testing.T) { | |
| @@ -568,17 +568,17 @@ func TestPaletteCtrlNAndCtrlPNavigate(t *testing.T) { | |||
| 568 | 568 | awaitFrame(t, sends, ports.MsgOutput) | |
| 569 | 569 | result, ok := ac.overlays.palette.Selected() | |
| 570 | 570 | require.True(t, ok) | |
| 571 | - | cmd, ok := result.(palette.CommandResult) | |
| 571 | + | cmd, ok := result.Command() | |
| 572 | 572 | require.True(t, ok) | |
| 573 | - | require.Equal(t, "CNS", cmd.Command().Code) | |
| 573 | + | require.Equal(t, "CNS", cmd.Code) | |
| 574 | 574 | ||
| 575 | 575 | d.handlePaletteInput(ac, []byte{0x10}) | |
| 576 | 576 | awaitFrame(t, sends, ports.MsgOutput) | |
| 577 | 577 | result, ok = ac.overlays.palette.Selected() | |
| 578 | 578 | require.True(t, ok) | |
| 579 | - | cmd, ok = result.(palette.CommandResult) | |
| 579 | + | cmd, ok = result.Command() | |
| 580 | 580 | require.True(t, ok) | |
| 581 | - | require.Equal(t, "CNT", cmd.Command().Code) | |
| 581 | + | require.Equal(t, "CNT", cmd.Code) | |
| 582 | 582 | } | |
| 583 | 583 | ||
| 584 | 584 | func TestPaletteModalGeometry(t *testing.T) { | |
| @@ -63,8 +63,8 @@ func TestPaletteEntryPublishesEligibleNamedSessionResults(t *testing.T) { | |||||
| 63 | 63 | ||||
| 64 | got := map[string]palette.ResultKind{} | 64 | got := map[string]palette.ResultKind{} | ||
| 65 | for _, match := range ac.overlays.palette.Matches() { | 65 | for _, match := range ac.overlays.palette.Matches() { | ||
| 66 | - | if result, ok := match.Result.(palette.SessionResult); ok { | 66 | + | if name, ok := match.Result.SessionName(); ok { |
| 67 | - | got[result.Name()] = result.Kind() | 67 | + | got[name] = match.Result.Kind() |
| 68 | } | 68 | } | ||
| 69 | } | 69 | } | ||
| 70 | require.Equal(t, map[string]palette.ResultKind{ | 70 | require.Equal(t, map[string]palette.ResultKind{ | ||
| @@ -85,7 +85,7 @@ func TestPaletteSessionFailureFeedbackClearsOnQueryChange(t *testing.T) { | |||||
| 85 | ac.overlays.paletteMu.Lock() | 85 | ac.overlays.paletteMu.Lock() | ||
| 86 | selected, ok := ac.overlays.palette.Selected() | 86 | selected, ok := ac.overlays.palette.Selected() | ||
| 87 | ac.overlays.paletteMu.Unlock() | 87 | ac.overlays.paletteMu.Unlock() | ||
| 88 | - | _, isSession := selected.(palette.SessionResult) | 88 | + | _, isSession := selected.SessionName() |
| 89 | require.True(t, ok) | 89 | require.True(t, ok) | ||
| 90 | require.True(t, isSession) | 90 | require.True(t, isSession) | ||
| 91 | d.mu.Lock() | 91 | d.mu.Lock() | ||
| @@ -455,9 +455,9 @@ func TestPaletteReopensWithSuccessfulCommandFirst(t *testing.T) { | |||||
| 455 | awaitFrame(t, sends, ports.MsgOutput) | 455 | awaitFrame(t, sends, ports.MsgOutput) | ||
| 456 | result, ok := ac.overlays.palette.Selected() | 456 | result, ok := ac.overlays.palette.Selected() | ||
| 457 | require.True(t, ok) | 457 | require.True(t, ok) | ||
| 458 | - | cmd, ok := result.(palette.CommandResult) | 458 | + | cmd, ok := result.Command() |
| 459 | require.True(t, ok) | 459 | require.True(t, ok) | ||
| 460 | - | require.Equal(t, "NXT", cmd.Command().Code) | 460 | + | require.Equal(t, "NXT", cmd.Code) |
| 461 | } | 461 | } | ||
| 462 | 462 | ||||
| 463 | func TestPaletteRecentCommandsNewestFirstThenRegistryOrder(t *testing.T) { | 463 | func TestPaletteRecentCommandsNewestFirstThenRegistryOrder(t *testing.T) { | ||
| @@ -568,17 +568,17 @@ func TestPaletteCtrlNAndCtrlPNavigate(t *testing.T) { | |||||
| 568 | awaitFrame(t, sends, ports.MsgOutput) | 568 | awaitFrame(t, sends, ports.MsgOutput) | ||
| 569 | result, ok := ac.overlays.palette.Selected() | 569 | result, ok := ac.overlays.palette.Selected() | ||
| 570 | require.True(t, ok) | 570 | require.True(t, ok) | ||
| 571 | - | cmd, ok := result.(palette.CommandResult) | 571 | + | cmd, ok := result.Command() |
| 572 | require.True(t, ok) | 572 | require.True(t, ok) | ||
| 573 | - | require.Equal(t, "CNS", cmd.Command().Code) | 573 | + | require.Equal(t, "CNS", cmd.Code) |
| 574 | 574 | ||||
| 575 | d.handlePaletteInput(ac, []byte{0x10}) | 575 | d.handlePaletteInput(ac, []byte{0x10}) | ||
| 576 | awaitFrame(t, sends, ports.MsgOutput) | 576 | awaitFrame(t, sends, ports.MsgOutput) | ||
| 577 | result, ok = ac.overlays.palette.Selected() | 577 | result, ok = ac.overlays.palette.Selected() | ||
| 578 | require.True(t, ok) | 578 | require.True(t, ok) | ||
| 579 | - | cmd, ok = result.(palette.CommandResult) | 579 | + | cmd, ok = result.Command() |
| 580 | require.True(t, ok) | 580 | require.True(t, ok) | ||
| 581 | - | require.Equal(t, "CNT", cmd.Command().Code) | 581 | + | require.Equal(t, "CNT", cmd.Code) |
| 582 | } | 582 | } | ||
| 583 | 583 | ||||
| 584 | func TestPaletteModalGeometry(t *testing.T) { | 584 | func TestPaletteModalGeometry(t *testing.T) { | ||