first pass of merging in warp (doesn't build)
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
# Enter on empty input sends the top queued prompt
|
||||
|
||||
Linear: [APP-4717](https://linear.app/warpdotdev/issue/APP-4717/change-it-so-hitting-enter-w-an-empty-buffer-and-queued-prompts-auto)
|
||||
|
||||
## Summary
|
||||
|
||||
When the queued prompts panel is showing and the terminal input is empty, pressing Enter sends the top queued row immediately — exactly as if the user clicked that row's Send-now button. The panel header advertises this with a "⏎ to send" hint that appears only when Enter would actually send.
|
||||
|
||||
Figma: none provided. Reference is Cursor's queue UI, which shows an Enter-to-send hint next to its "N Queued" header label; we copy that placement in our panel header.
|
||||
|
||||
## Behavior
|
||||
|
||||
1. With the queued prompts panel visible, the input buffer completely empty, and the top queued row sendable (see 5), pressing Enter in the terminal input sends the top row immediately. This is identical to clicking that row's Send-now button:
|
||||
- An agent prompt row is submitted to the same target Send-now would use (running conversation follow-up, cloud follow-up, shared-session viewer send, or full-terminal-use agent when one is in control), carrying the row's own queued attachments.
|
||||
- A command row (`!` prefix) executes as a shell command.
|
||||
- The row is removed from the queue after dispatch; remaining rows shift up.
|
||||
2. This applies regardless of the input's mode. In shell mode, an empty-buffer Enter that previously produced a fresh prompt line instead sends the top queued row while the panel is showing a sendable top row.
|
||||
3. Enter sends exactly one row per press. Pressing Enter again re-evaluates: if the new top row is sendable and the buffer is still empty, it sends that row next.
|
||||
4. The behavior works the same whether the panel body is expanded or collapsed (the header is visible either way).
|
||||
5. Enter mirrors Send-now availability for the top row. While the top row's Send-now is disabled — the locked initial cloud-mode prompt while cloud environment setup is in progress — Enter does nothing and the hint is hidden.
|
||||
- The same applies whenever prompt sending is unavailable for the pane as a whole, e.g. the user is a read-only (non-executor) viewer in a shared session. In that state the rows' Send-now buttons are also disabled (with a tooltip explaining why), Enter does nothing, and the hint is hidden — button and Enter availability are bundled and may not disagree.
|
||||
- Pane-level unavailability only affects sending: it does not disable a row's edit/delete buttons, and it does not stop new prompts from being queued.
|
||||
- Enter-only conditions (non-empty buffer, CLI-agent rich input open) hide the hint and suppress Enter but do not disable the Send-now buttons.
|
||||
6. If the buffer contains any content (including whitespace-only content), Enter behaves exactly as it does today and the hint is hidden.
|
||||
7. Header hint:
|
||||
- The panel header shows an ⏎ keycap followed by "to send" next to the "N queued" label, matching the look and spacing of Warp's existing keystroke hints (e.g. "? for help"). The "to send" text uses the same color as the "N queued" label; the keycap glyph is dimmer (disabled-text styling) so it reads as a secondary affordance.
|
||||
- The hint is visible exactly when an empty-buffer Enter would send the top row, and hidden otherwise (non-empty buffer, no sendable top row, sending unavailable per 5, panel hidden, or any case in 8–10). The hint and the Enter behavior must never disagree.
|
||||
8. Whenever the panel is not rendered (no queue, inline menu like slash commands or the model selector is open, feature flag off), Enter keeps its existing behavior and no hint is shown.
|
||||
9. While a queued row is in inline edit mode, Enter commits that edit as today (focus is in the row's editor, not the input). The header hint is hidden during an inline edit.
|
||||
10. When the CLI-agent rich input is open, Enter keeps its existing submit-to-CLI-agent behavior and the hint is hidden. (The `submit_on_ctrl_enter` setting only affects the CLI-agent rich input, so it never changes which key sends a queued row.)
|
||||
11. Sending via Enter does not touch the input buffer, its pending attachments, or focus: the buffer stays empty, attachments staged in the input are not consumed (the queued row carries its own), and focus remains in the input afterward. One pre-existing exception, shared with the Send-now button: on the shared-session viewer path an empty input temporarily shows the standard "<prompt> ◌" loading affordance until the sharer acknowledges the send.
|
||||
12. When the last queued row is sent, the panel disappears (existing behavior); a subsequent Enter behaves as it did before this feature.
|
||||
13. Sending a queued row records telemetry distinguishing the trigger: Send-now button click vs. Enter on empty input.
|
||||
@@ -0,0 +1,41 @@
|
||||
# APP-4717 — Enter on empty input sends the top queued prompt
|
||||
|
||||
See `specs/APP-4717/PRODUCT.md` for behavior. Researched at commit `e367c9de8b9629600885e40b029c10c8915f9ec8`.
|
||||
|
||||
## Context
|
||||
|
||||
- [`app/src/terminal/input.rs:12808 @ e367c9de`](https://github.com/warpdotdev/warp/blob/e367c9de8b9629600885e40b029c10c8915f9ec8/app/src/terminal/input.rs#L12808) — `Input::input_enter`. CLI-agent rich input returns early at the top (L12809-12867), so the queue-send path never applies there (PRODUCT §10). The else-if chain at L12984-12988 (`maybe_launch_cloud_handoff_request` / `maybe_queue_input_for_in_progress_conversation` / …) is where the new empty-buffer check slots in; all existing branches in that chain require a non-empty buffer, so ordering is conflict-free.
|
||||
- [`app/src/terminal/input.rs:3755-3793 @ e367c9de`](https://github.com/warpdotdev/warp/blob/e367c9de8b9629600885e40b029c10c8915f9ec8/app/src/terminal/input.rs#L3755-L3793) — `handle_queued_prompts_panel_event`: the existing Send-now dispatch (command vs prompt, `remove_fired_row`, refocus). This is the logic Enter must reuse.
|
||||
- [`app/src/terminal/view/queued_prompts_panel.rs:580-620 @ e367c9de`](https://github.com/warpdotdev/warp/blob/e367c9de8b9629600885e40b029c10c8915f9ec8/app/src/terminal/view/queued_prompts_panel.rs#L580-L620) — `SendNow` action handler; skips rows where `row.is_locked()` (the initial cloud-mode prompt), which is exactly the head-row sendability condition (`update_send_now_availability`, L285-324, disables the head only when it is the locked initial cloud-mode row).
|
||||
- [`app/src/terminal/view/queued_prompts_panel.rs:853-903 @ e367c9de`](https://github.com/warpdotdev/warp/blob/e367c9de8b9629600885e40b029c10c8915f9ec8/app/src/terminal/view/queued_prompts_panel.rs#L853-L903) — `render_header` ("N queued" label) where the "⏎ to send" hint goes. `should_render` (L548-563) already gates on flag, inline menus, and queue presence.
|
||||
- [`app/src/terminal/input.rs:9756-9763 @ e367c9de`](https://github.com/warpdotdev/warp/blob/e367c9de8b9629600885e40b029c10c8915f9ec8/app/src/terminal/input.rs#L9756-L9763) — `Input` already detects empty↔non-empty buffer transitions on every `Edited` event (`is_editor_empty_on_last_edit`); the panel can be driven from here.
|
||||
- [`app/src/server/telemetry/events.rs:2945-2963 @ e367c9de`](https://github.com/warpdotdev/warp/blob/e367c9de8b9629600885e40b029c10c8915f9ec8/app/src/server/telemetry/events.rs#L2945-L2963) — existing `QueuedPrompt*` telemetry events to extend.
|
||||
|
||||
## Proposed changes
|
||||
|
||||
1. Shared dispatch helper on `Input` (`app/src/terminal/input.rs`): extract the body of the `QueuedPromptsPanelEvent::SendNow` arm into `fn send_queued_row_immediately(&mut self, conversation_id, query_id, text, is_command, trigger, ctx)`. Both the panel-event arm and the Enter path call it. It emits the new telemetry event (below) on dispatch.
|
||||
2. Panel send state (`app/src/terminal/view/queued_prompts_panel.rs`):
|
||||
- `can_send_prompt: bool` (host-pushed via the change-detecting `set_can_send_prompt` setter) — whether the terminal can send prompts at all (false for read-only shared-session viewers, via the existing `SharedSessionStatus::is_reader()` helper). Gates the Send-now buttons (re-runs `update_send_now_availability`, with a "Read-only viewers cannot send prompts." tooltip), empty-Enter sends, and the hint. Edit/delete buttons are unaffected.
|
||||
- Host-input emptiness is *not* pushed: the panel holds the host editor's `ViewHandle` (passed at construction) and reads `is_empty` live at decision time, so the Enter decision cannot trail same-update buffer changes. A subscription to the host editor's `Edited`/`BufferReplaced` events re-renders the panel on empty↔non-empty transitions (a cached `host_editor_was_empty` flag only damps these notifications), mirroring the `CLIAgentSessionsModel` pattern below.
|
||||
The panel observes the CLI-agent rich input itself (a `CLIAgentSessionsModel` subscription plus a live `is_input_open` read — Enter submits to the CLI agent while it is open) and exposes `enter_sends_queued_prompt(ctx)` = `should_render` + `can_send_prompt` + live editor emptiness + rich input closed. The hint shows when that holds, no row is in inline edit mode, and the head row is sendable (`!is_locked()`), so the hint can never advertise an Enter that wouldn't fire.
|
||||
3. Enter path: inlined in `input_enter`'s dispatch chain (before `maybe_launch_cloud_handoff_request`): when `panel.enter_sends_queued_prompt(ctx)` holds, look up the head row of the active conversation's queue (`BlocklistAIHistoryModel::active_conversation_id` + `QueuedQueryModel::queue(...).first()`, skipping a locked head) and dispatch it via `send_queued_row_immediately`; a locked head means Enter does nothing.
|
||||
4. Push sites: `Input` seeds `can_send_prompt` at panel construction (`is_reader`) and passes the editor handle in; `TerminalView::on_self_role_updated` pushes `set_can_send_prompt(role.can_execute())` when the shared-session role changes (panel reached via the `Input::queued_prompts_panel()` accessor).
|
||||
5. Header hint rendering: `render_header` appends an enter keycap chip (`render_keystroke_with_color_overrides`, the same component the "? for help" message-bar hints use) followed by "to send" text. The text uses the header's `sub_text_color`; the keycap glyph uses `internal_colors::text_disabled` so it is dimmer. Spacing follows the message-bar hint rules (`render_message_bar_items`): 8px label→keycap, 4px keycap→text.
|
||||
6. Telemetry (`app/src/server/telemetry/events.rs`): new event `QueuedPromptSentNow { origin: TelemetryQueuedQueryOrigin, trigger: QueuedPromptSendNowTrigger }` with `QueuedPromptSendNowTrigger { SendNowButton, EnterOnEmptyInput }`, payload + descriptions following the adjacent `QueuedPrompt*` events. Emitted from the shared helper in (1). (Send-now currently has no telemetry; this adds it for both triggers.)
|
||||
|
||||
No new feature flag: the behavior ships under the existing `QueueSlashCommand` gate the panel already requires.
|
||||
|
||||
## Testing and validation
|
||||
|
||||
- Unit tests in `app/src/terminal/input_tests.rs` next to the existing queued-panel host tests (L1277+), driving `input_enter`:
|
||||
- empty buffer + queued prompt row → head row dispatched, removed from queue, buffer untouched (PRODUCT §1, §11); a second Enter sends the next row (§3).
|
||||
- empty buffer + queued command row, default shell mode → command executed instead of an empty shell submission (§1, §2).
|
||||
- non-empty buffer → no queue send (§6).
|
||||
- locked initial cloud-mode head row → no send (§5) — the `!is_locked` filter in the Enter path is the only guard on this path.
|
||||
Send-permission gating (read-only viewer) and the flag-off case are intentionally not host-tested: the former is a pushed flag whose effects are covered by the panel tests below, and with the flag off the panel (and hook target) doesn't exist.
|
||||
- Panel tests in `app/src/terminal/view/queued_prompts_tests.rs`: hint hidden during inline edit and for a locked head (§7, §9); Send-now buttons disabled when `can_send_prompt` is false (via `send_now_button_disabled_for_test`) but not merely because the input is non-empty (§5). Panel tests reuse the host input's own panel when the flag is on — a second panel on the same terminal view would fight over edit-editor focus and commit edits on blur.
|
||||
- `cargo check` + `./script/format`; manual smoke: queue two prompts during a running conversation, hit Enter twice with an empty input.
|
||||
|
||||
## Parallelization
|
||||
|
||||
Not beneficial: the change is small and tightly coupled (one host file + one panel file share the dispatch helper and the empty-state plumbing). A single agent implements it on this branch (`harry/app-4717-change-it-so-hitting-enter-w-an-empty-buffer-and-queued`).
|
||||
Reference in New Issue
Block a user