test(app): cover rename prompt integration
- commit
- e59f8774b712ce2a8aae8960ee043f162587d911
- author
- brice · · 2026-07-03 09:29 UTC
- parent
- 26d6300
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +38 -1
M README.md +5 -1
| @@ -53,6 +53,8 @@ Some terminals encode Alt+Space as a non-breaking space instead of `ESC Space`; | |||
| 53 | 53 | ||
| 54 | 54 | Open the palette with Alt+Space, then type a command code or fuzzy-match its label. Use Up/Down or Ctrl-N/Ctrl-P to move through matches, Enter to run the selected command, and Esc to close the palette. | |
| 55 | 55 | ||
| 56 | + | Ephemeral sessions are marked with `*` in the status bar, for example `0*`. Renaming an ephemeral session makes it persistent and removes the marker. | |
| 57 | + | ||
| 56 | 58 | | Code | Action | | |
| 57 | 59 | |---|---| | |
| 58 | 60 | | CNT | create new tab | | |
| @@ -61,9 +63,11 @@ Open the palette with Alt+Space, then type a command code or fuzzy-match its lab | |||
| 61 | 63 | | PVT | switch to previous tab | | |
| 62 | 64 | | SSP | switch session or tab | | |
| 63 | 65 | | CPY | enter scrollback mode | | |
| 64 | - | | RNS | promote session | | |
| 66 | + | | RNS | rename session | | |
| 65 | 67 | | DET | detach | | |
| 66 | 68 | ||
| 69 | + | Rename prompts are prefilled with the current name. Type text, use Backspace to edit, Enter to submit, or Esc/Ctrl-C to cancel. If validation fails, the prompt stays open and shows the error. | |
| 70 | + | ||
| 67 | 71 | ## Scrollback and visual copy | |
| 68 | 72 | ||
| 69 | 73 | Scrollback mode freezes a view over history while the program keeps running underneath. Mouse wheel up enters scrollback mode and shows `[SCROLL]`; scrolling back down to the live bottom exits. When a line selection is active, the selected rows are highlighted and the status bar shows `[VISUAL]`. | |
| @@ -53,6 +53,8 @@ Some terminals encode Alt+Space as a non-breaking space instead of `ESC Space`; | |||||
| 53 | 53 | ||||
| 54 | Open the palette with Alt+Space, then type a command code or fuzzy-match its label. Use Up/Down or Ctrl-N/Ctrl-P to move through matches, Enter to run the selected command, and Esc to close the palette. | 54 | Open the palette with Alt+Space, then type a command code or fuzzy-match its label. Use Up/Down or Ctrl-N/Ctrl-P to move through matches, Enter to run the selected command, and Esc to close the palette. | ||
| 55 | 55 | ||||
| 56 | + | Ephemeral sessions are marked with `*` in the status bar, for example `0*`. Renaming an ephemeral session makes it persistent and removes the marker. | |||
| 57 | + | ||||
| 56 | | Code | Action | | 58 | | Code | Action | | ||
| 57 | |---|---| | 59 | |---|---| | ||
| 58 | | CNT | create new tab | | 60 | | CNT | create new tab | | ||
| @@ -61,9 +63,11 @@ Open the palette with Alt+Space, then type a command code or fuzzy-match its lab | |||||
| 61 | | PVT | switch to previous tab | | 63 | | PVT | switch to previous tab | | ||
| 62 | | SSP | switch session or tab | | 64 | | SSP | switch session or tab | | ||
| 63 | | CPY | enter scrollback mode | | 65 | | CPY | enter scrollback mode | | ||
| 64 | - | | RNS | promote session | | 66 | + | | RNS | rename session | |
| 65 | | DET | detach | | 67 | | DET | detach | | ||
| 66 | 68 | ||||
| 69 | + | Rename prompts are prefilled with the current name. Type text, use Backspace to edit, Enter to submit, or Esc/Ctrl-C to cancel. If validation fails, the prompt stays open and shows the error. | |||
| 70 | + | ||||
| 67 | ## Scrollback and visual copy | 71 | ## Scrollback and visual copy | ||
| 68 | 72 | ||||
| 69 | Scrollback mode freezes a view over history while the program keeps running underneath. Mouse wheel up enters scrollback mode and shows `[SCROLL]`; scrolling back down to the live bottom exits. When a line selection is active, the selected rows are highlighted and the status bar shows `[VISUAL]`. | 73 | Scrollback mode freezes a view over history while the program keeps running underneath. Mouse wheel up enters scrollback mode and shows `[SCROLL]`; scrolling back down to the live bottom exits. When a line selection is active, the selected rows are highlighted and the status bar shows `[VISUAL]`. | ||
M internal/app/daemon_integration_test.go +33 -0
| @@ -190,6 +190,39 @@ func TestIntegration_CommandPaletteCreatesTab(t *testing.T) { | |||
| 190 | 190 | require.Contains(t, text, " 1 2 ") | |
| 191 | 191 | } | |
| 192 | 192 | ||
| 193 | + | func TestIntegration_CommandPaletteRenamesEphemeralSession(t *testing.T) { | |
| 194 | + | sz := domain.Size{Cols: 80, Rows: 24} | |
| 195 | + | dir, _ := startDaemon(t, daemon.WithShell("/bin/sh", []string{"-c", "printf READY; sleep 30"})) | |
| 196 | + | ||
| 197 | + | tr, p := attach(t, dir, ports.IntentEphemeral, "", sz) | |
| 198 | + | defer func() { _ = tr.Close() }() | |
| 199 | + | text := awaitScreenText(t, p, sz, "READY") | |
| 200 | + | require.Contains(t, text, " 0* ") | |
| 201 | + | ||
| 202 | + | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(ports.Input{Data: []byte("\x1b ")})})) | |
| 203 | + | awaitText(t, p, sz, "Commands") | |
| 204 | + | ||
| 205 | + | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(ports.Input{Data: []byte("RNS\r")})})) | |
| 206 | + | awaitText(t, p, sz, "Rename session") | |
| 207 | + | ||
| 208 | + | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(ports.Input{Data: []byte("\x7fwork\r")})})) | |
| 209 | + | text = awaitScreenText(t, p, sz, " work ") | |
| 210 | + | require.NotContains(t, text, "work*") | |
| 211 | + | ||
| 212 | + | listTr, err := ipc.Dial(dir) | |
| 213 | + | require.NoError(t, err) | |
| 214 | + | defer func() { _ = listTr.Close() }() | |
| 215 | + | require.NoError(t, listTr.Send(ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(ports.List{})})) | |
| 216 | + | f, err := listTr.Recv() | |
| 217 | + | require.NoError(t, err) | |
| 218 | + | require.Equal(t, ports.MsgSessions, f.Type) | |
| 219 | + | sessions, err := ports.UnmarshalSessions(f.Payload) | |
| 220 | + | require.NoError(t, err) | |
| 221 | + | require.Len(t, sessions.Sessions, 1) | |
| 222 | + | require.Equal(t, "work", sessions.Sessions[0].Name) | |
| 223 | + | require.False(t, sessions.Sessions[0].Ephemeral) | |
| 224 | + | } | |
| 225 | + | ||
| 193 | 226 | func TestIntegration_AltCWithoutPaletteDoesNotCreateTab(t *testing.T) { | |
| 194 | 227 | sz := domain.Size{Cols: 80, Rows: 24} | |
| 195 | 228 | dir, _ := startDaemon(t, daemon.WithShell("/bin/sh", []string{"-c", "printf READY; sleep 30"})) | |
| @@ -190,6 +190,39 @@ func TestIntegration_CommandPaletteCreatesTab(t *testing.T) { | |||||
| 190 | require.Contains(t, text, " 1 2 ") | 190 | require.Contains(t, text, " 1 2 ") | ||
| 191 | } | 191 | } | ||
| 192 | 192 | ||||
| 193 | + | func TestIntegration_CommandPaletteRenamesEphemeralSession(t *testing.T) { | |||
| 194 | + | sz := domain.Size{Cols: 80, Rows: 24} | |||
| 195 | + | dir, _ := startDaemon(t, daemon.WithShell("/bin/sh", []string{"-c", "printf READY; sleep 30"})) | |||
| 196 | + | ||||
| 197 | + | tr, p := attach(t, dir, ports.IntentEphemeral, "", sz) | |||
| 198 | + | defer func() { _ = tr.Close() }() | |||
| 199 | + | text := awaitScreenText(t, p, sz, "READY") | |||
| 200 | + | require.Contains(t, text, " 0* ") | |||
| 201 | + | ||||
| 202 | + | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(ports.Input{Data: []byte("\x1b ")})})) | |||
| 203 | + | awaitText(t, p, sz, "Commands") | |||
| 204 | + | ||||
| 205 | + | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(ports.Input{Data: []byte("RNS\r")})})) | |||
| 206 | + | awaitText(t, p, sz, "Rename session") | |||
| 207 | + | ||||
| 208 | + | require.NoError(t, tr.Send(ports.Frame{Type: ports.MsgInput, Payload: ports.MarshalInput(ports.Input{Data: []byte("\x7fwork\r")})})) | |||
| 209 | + | text = awaitScreenText(t, p, sz, " work ") | |||
| 210 | + | require.NotContains(t, text, "work*") | |||
| 211 | + | ||||
| 212 | + | listTr, err := ipc.Dial(dir) | |||
| 213 | + | require.NoError(t, err) | |||
| 214 | + | defer func() { _ = listTr.Close() }() | |||
| 215 | + | require.NoError(t, listTr.Send(ports.Frame{Type: ports.MsgList, Payload: ports.MarshalList(ports.List{})})) | |||
| 216 | + | f, err := listTr.Recv() | |||
| 217 | + | require.NoError(t, err) | |||
| 218 | + | require.Equal(t, ports.MsgSessions, f.Type) | |||
| 219 | + | sessions, err := ports.UnmarshalSessions(f.Payload) | |||
| 220 | + | require.NoError(t, err) | |||
| 221 | + | require.Len(t, sessions.Sessions, 1) | |||
| 222 | + | require.Equal(t, "work", sessions.Sessions[0].Name) | |||
| 223 | + | require.False(t, sessions.Sessions[0].Ephemeral) | |||
| 224 | + | } | |||
| 225 | + | ||||
| 193 | func TestIntegration_AltCWithoutPaletteDoesNotCreateTab(t *testing.T) { | 226 | func TestIntegration_AltCWithoutPaletteDoesNotCreateTab(t *testing.T) { | ||
| 194 | sz := domain.Size{Cols: 80, Rows: 24} | 227 | sz := domain.Size{Cols: 80, Rows: 24} | ||
| 195 | dir, _ := startDaemon(t, daemon.WithShell("/bin/sh", []string{"-c", "printf READY; sleep 30"})) | 228 | dir, _ := startDaemon(t, daemon.WithShell("/bin/sh", []string{"-c", "printf READY; sleep 30"})) | ||