|
| 1 | +## MODIFIED Requirements |
| 2 | + |
| 3 | +### Requirement: Named-action surface |
| 4 | + |
| 5 | +The view module SHALL expose `view.action(name, handler)` and |
| 6 | +`view.dispatch(name, ctx)`. The following actions MUST be |
| 7 | +registered by the view at module setup: |
| 8 | + |
| 9 | +- `expand` — expand the expandable row at the cursor (watch |
| 10 | + or child variable). |
| 11 | +- `collapse` — collapse the row at the cursor. |
| 12 | +- `expand-all-children` — expand the row at the cursor and |
| 13 | + all its already-fetched children. |
| 14 | +- `collapse-all-children` — collapse the row and its |
| 15 | + descendants. |
| 16 | +- `jump-to-source` — open the source location for the child |
| 17 | + variable row at the cursor (watch top-level rows |
| 18 | + notify-and-no-op). |
| 19 | +- `retry` — re-issue the failed request associated with the |
| 20 | + row at the cursor. |
| 21 | +- `load-more` — issue the next page for the load-more row at |
| 22 | + the cursor. |
| 23 | +- `add-watch` — prompt via `vim.ui.input` (optionally |
| 24 | + pre-filled via `ctx.prefill`) for a new expression and |
| 25 | + append it to the list. |
| 26 | +- `remove-watch` — remove the top-level watch at the cursor, |
| 27 | + or remove `ctx.index` when an explicit index is supplied. |
| 28 | + The action MUST no-op when the cursor row is not a |
| 29 | + top-level watch row. |
| 30 | +- `edit-watch-expression` — prompt via `vim.ui.input` |
| 31 | + pre-filled with the current expression; replace on submit; |
| 32 | + no-op on cancel. |
| 33 | + |
| 34 | +The view MUST NOT install any keymaps for these actions. |
| 35 | +Invoking `view.dispatch(name)` for an unregistered name MUST |
| 36 | +raise a clear error naming the missing action. |
| 37 | + |
| 38 | +The three list-mutation actions are human tools per |
| 39 | +`project.md` §3.2. They MUST NOT show a confirmation prompt; |
| 40 | +the `vim.ui.input` prompt for `add-watch` and |
| 41 | +`edit-watch-expression` is used only to collect the |
| 42 | +expression text, not to confirm the action. Empty submits for |
| 43 | +`add-watch` and `edit-watch-expression` are no-ops; cancel is |
| 44 | +a no-op. |
| 45 | + |
| 46 | +#### Scenario: Module setup registers the ten actions |
| 47 | +- **WHEN** the view module is loaded and `setup({})` is |
| 48 | + invoked |
| 49 | +- **THEN** `view.list_actions()` returns a table containing |
| 50 | + exactly the names `"expand"`, `"collapse"`, |
| 51 | + `"expand-all-children"`, `"collapse-all-children"`, |
| 52 | + `"jump-to-source"`, `"retry"`, `"load-more"`, |
| 53 | + `"add-watch"`, `"remove-watch"`, |
| 54 | + `"edit-watch-expression"` |
| 55 | + |
| 56 | +#### Scenario: View installs no keymaps |
| 57 | +- **WHEN** the view is mounted and `on_focus` returns |
| 58 | +- **THEN** the view's buffer has no buffer-local keymaps |
| 59 | + installed by the view module |
| 60 | + |
| 61 | +#### Scenario: Dispatch on unknown action raises |
| 62 | +- **WHEN** `view.dispatch("nope", ctx)` is invoked |
| 63 | +- **THEN** the call raises an error identifying the unknown |
| 64 | + action |
| 65 | + |
| 66 | +#### Scenario: List-mutation actions show no confirmation prompt |
| 67 | +- **WHEN** the user invokes `remove-watch` on a row |
| 68 | +- **THEN** the view does not call `vim.ui.select` or any |
| 69 | + other confirmation surface before removing the watch |
| 70 | +- **AND** the action is identified in the spec as a *human* |
| 71 | + side-effecting tool per `project.md` §3.2 |
| 72 | + |
| 73 | +#### Scenario: add-watch with empty submit is a no-op |
| 74 | +- **WHEN** the user invokes `add-watch` and submits an empty |
| 75 | + string at the `vim.ui.input` prompt |
| 76 | +- **THEN** the in-memory list is unchanged |
| 77 | +- **AND** the on-disk file is not rewritten |
| 78 | + |
| 79 | +#### Scenario: add-watch with cancel is a no-op |
| 80 | +- **WHEN** the user invokes `add-watch` and cancels the |
| 81 | + `vim.ui.input` prompt |
| 82 | +- **THEN** the in-memory list is unchanged |
| 83 | +- **AND** the on-disk file is not rewritten |
| 84 | + |
| 85 | +#### Scenario: add-watch with non-empty submit appends and re-evaluates |
| 86 | +- **WHEN** the user invokes `add-watch` with expression `e` |
| 87 | + and a session is paused |
| 88 | +- **THEN** `e` is appended to the in-memory list |
| 89 | +- **AND** the on-disk file is rewritten atomically |
| 90 | +- **AND** exactly one `evaluate` request is issued for `e` |
| 91 | + with `context = "watch"` and `frameId = current_frame()` |
| 92 | + captured at issue time (not at response time) |
| 93 | +- **AND** the generation counter is bumped before the request |
| 94 | + is issued (so a subsequent step that arrives between issue |
| 95 | + and response advances the generation and the response is |
| 96 | + dropped per the stale-response rule) |
| 97 | + |
| 98 | +#### Scenario: edit-watch-expression replaces and re-evaluates |
| 99 | +- **WHEN** the user invokes `edit-watch-expression` on the |
| 100 | + watch at index 1, submits a new expression `e2`, and a |
| 101 | + session is paused |
| 102 | +- **THEN** the watch at index 1 becomes `e2` |
| 103 | +- **AND** any prior child-tree state for that index is |
| 104 | + discarded |
| 105 | +- **AND** exactly one `evaluate` request is issued for `e2` |
| 106 | + |
| 107 | +#### Scenario: remove-watch removes and persists by explicit index |
| 108 | +- **WHEN** the user invokes `remove-watch` with `ctx.index` |
| 109 | + set to watch index 2 (out of three) |
| 110 | +- **THEN** the in-memory list has two entries |
| 111 | +- **AND** the on-disk file is rewritten atomically |
| 112 | +- **AND** no DAP request is issued |
| 113 | + |
| 114 | +#### Scenario: remove-watch removes and persists from cursor watch row |
| 115 | +- **WHEN** the watches view has three watches and the cursor |
| 116 | + is on the second top-level watch row |
| 117 | +- **AND** the user invokes `remove-watch` through the view |
| 118 | + keymap dispatch path with only `ctx.win` |
| 119 | +- **THEN** the second watch is removed from the in-memory list |
| 120 | +- **AND** the on-disk file is rewritten atomically |
| 121 | +- **AND** no DAP request is issued |
| 122 | + |
| 123 | +#### Scenario: remove-watch no-ops on child variable row |
| 124 | +- **WHEN** the cursor is on a child variable row inside an |
| 125 | + expanded watch |
| 126 | +- **AND** the user invokes `remove-watch` through the view |
| 127 | + keymap dispatch path with only `ctx.win` |
| 128 | +- **THEN** the in-memory watch list is unchanged |
| 129 | +- **AND** the on-disk file is not rewritten |
| 130 | +- **AND** no DAP request is issued |
0 commit comments