|
| 1 | +# reader-message-actions |
| 2 | + |
| 3 | +## Purpose |
| 4 | + |
| 5 | +Message-level actions available from the reader scope: replying to the sender, |
| 6 | +replying to all participants, forwarding, yanking the body (with or without headers) |
| 7 | +to the clipboard, and toggling the headers menu. The keyboard bindings that trigger |
| 8 | +these actions are declared in the `ui-hotkeys` capability; this capability defines the |
| 9 | +behavior of each action. |
| 10 | + |
| 11 | +--- |
| 12 | +## Requirements |
| 13 | +### Requirement: Reply to sender |
| 14 | +The reader SHALL provide an `r` action that opens the compose screen prefilled as a |
| 15 | +reply to the open message's sender. The `To` field SHALL be set to the original |
| 16 | +message's `From` address. The `Subject` SHALL be the original subject prefixed with |
| 17 | +`Re: `, not duplicated if the subject already begins with `Re:` (case-insensitive). The |
| 18 | +compose body SHALL contain the original message body quoted, with each line prefixed by |
| 19 | +`> ` (greater-than then a single space). `r` SHALL be active only when the reader is the |
| 20 | +active scope and focus is not in a text input. |
| 21 | + |
| 22 | +#### Scenario: r opens compose addressed to the sender |
| 23 | +- **WHEN** the reader is open on a message and the user presses `r` |
| 24 | +- **THEN** the compose screen opens with the `To` field set to the original message's `From` address |
| 25 | + |
| 26 | +#### Scenario: Original body is quoted with "> " prefix |
| 27 | +- **WHEN** the user presses `r` in the reader |
| 28 | +- **THEN** the compose body contains the original message text with each line prefixed by `> ` |
| 29 | + |
| 30 | +#### Scenario: Subject gets a single Re: prefix |
| 31 | +- **WHEN** the user replies to a message whose subject is `Hello` |
| 32 | +- **THEN** the compose subject is `Re: Hello` |
| 33 | + |
| 34 | +#### Scenario: Re: is not duplicated |
| 35 | +- **WHEN** the user replies to a message whose subject is already `Re: Hello` |
| 36 | +- **THEN** the compose subject remains `Re: Hello` (no `Re: Re:`) |
| 37 | + |
| 38 | +#### Scenario: r suppressed while typing |
| 39 | +- **WHEN** focus is in an `input` or `textarea` and the user presses `r` |
| 40 | +- **THEN** the character is typed normally and no reply is started |
| 41 | + |
| 42 | +### Requirement: Reply to all |
| 43 | +The reader SHALL provide an `R` (Shift+r) action that opens the compose screen as a |
| 44 | +reply to every participant of the open message. The `To` field SHALL contain the |
| 45 | +original `From` address; the `Cc` field SHALL contain the union of the original `To` |
| 46 | +and `Cc` recipients. The active account's own address SHALL be excluded from both |
| 47 | +fields. Subject prefixing and body quoting SHALL follow the same rules as `r`. |
| 48 | + |
| 49 | +#### Scenario: R populates To and Cc from all participants |
| 50 | +- **WHEN** the reader is open on a message with multiple recipients and the user presses `R` |
| 51 | +- **THEN** the compose `To` is the original `From` and the `Cc` contains the other original `To`/`Cc` recipients |
| 52 | + |
| 53 | +#### Scenario: Own address excluded from reply-all |
| 54 | +- **WHEN** the user presses `R` on a message that also listed the active account's own address as a recipient |
| 55 | +- **THEN** the active account's address does not appear in the `To` or `Cc` fields |
| 56 | + |
| 57 | +#### Scenario: Reply-all quotes the original body |
| 58 | +- **WHEN** the user presses `R` in the reader |
| 59 | +- **THEN** the compose body contains the original message text with each line prefixed by `> ` |
| 60 | + |
| 61 | +### Requirement: Forward message |
| 62 | +The reader SHALL provide an `F` (Shift+f) action that opens the compose screen to |
| 63 | +forward the open message. The `To` field SHALL be empty, the `Subject` SHALL be the |
| 64 | +original subject prefixed with `Fwd: ` (not duplicated), and the body SHALL contain the |
| 65 | +forwarded original message including its `From`, `To`, `Subject`, and `Date` headers |
| 66 | +followed by the original body. `F` SHALL NOT interfere with `f`, which remains hint mode. |
| 67 | + |
| 68 | +#### Scenario: F opens compose to forward |
| 69 | +- **WHEN** the reader is open and the user presses `F` |
| 70 | +- **THEN** the compose screen opens with an empty `To` and the subject prefixed with `Fwd: ` |
| 71 | + |
| 72 | +#### Scenario: Forwarded body includes original headers |
| 73 | +- **WHEN** the user presses `F` in the reader |
| 74 | +- **THEN** the compose body includes the original message's `From`, `To`, `Subject`, and `Date` followed by the original body |
| 75 | + |
| 76 | +#### Scenario: f still activates hint mode |
| 77 | +- **WHEN** the reader is open (text/simple mode) and the user presses `f` |
| 78 | +- **THEN** hint mode activates and no forward is started |
| 79 | + |
| 80 | +### Requirement: Yank message body |
| 81 | +The reader SHALL provide a `y` action that copies the open message's plain-text body to |
| 82 | +the system clipboard. The copied content SHALL be the body only, without headers. |
| 83 | + |
| 84 | +#### Scenario: y copies the body to the clipboard |
| 85 | +- **WHEN** the reader is open and the user presses `y` |
| 86 | +- **THEN** the system clipboard contains the message's plain-text body and no headers |
| 87 | + |
| 88 | +### Requirement: Yank message with headers |
| 89 | +The reader SHALL provide a `Y` (Shift+y) action that copies the open message's common |
| 90 | +headers followed by its body to the system clipboard. The headers SHALL include at |
| 91 | +least `From`, `To`, and `Subject`, plus `Date` and `Cc` when present, each on its own |
| 92 | +line, followed by a blank line and then the plain-text body. |
| 93 | + |
| 94 | +#### Scenario: Y copies headers and body |
| 95 | +- **WHEN** the reader is open and the user presses `Y` |
| 96 | +- **THEN** the system clipboard contains `From`, `To`, and `Subject` lines (and `Date`/`Cc` when present) followed by a blank line and the message body |
| 97 | + |
| 98 | +### Requirement: Yank clipboard feedback |
| 99 | +After a successful yank, the reader SHALL show a transient toast notification confirming |
| 100 | +the copy. `y` SHALL show `Message text copied to clipboard`; `Y` SHALL show |
| 101 | +`Message text with headers copied to clipboard`. The toast SHALL dismiss itself after a |
| 102 | +short delay. No toast SHALL be shown if the clipboard write fails (e.g. insecure context |
| 103 | +or denied permission). |
| 104 | + |
| 105 | +#### Scenario: y shows a body-copied toast |
| 106 | +- **WHEN** the reader is open and the user presses `y` |
| 107 | +- **THEN** a toast reading `Message text copied to clipboard` appears and then auto-dismisses |
| 108 | + |
| 109 | +#### Scenario: Y shows a headers-copied toast |
| 110 | +- **WHEN** the reader is open and the user presses `Y` |
| 111 | +- **THEN** a toast reading `Message text with headers copied to clipboard` appears and then auto-dismisses |
| 112 | + |
| 113 | +### Requirement: Headers menu toggle |
| 114 | +The reader SHALL provide a `g h` leader sequence that toggles the headers menu (the |
| 115 | +`HeadersPopover`) showing the message's full header set. Pressing `g h` again or |
| 116 | +`Escape` SHALL close it. |
| 117 | + |
| 118 | +#### Scenario: g h opens the headers menu |
| 119 | +- **WHEN** the reader is open and the user presses `g` then `h` within the leader timeout |
| 120 | +- **THEN** the headers menu opens showing the message's full headers |
| 121 | + |
| 122 | +#### Scenario: g h closes an open headers menu |
| 123 | +- **WHEN** the headers menu is open and the user presses `g` then `h` |
| 124 | +- **THEN** the headers menu closes |
0 commit comments