|
| 1 | +# [201_85] Ctrl+G interrupt for ongoing commands |
| 2 | + |
| 3 | +## Issue |
| 4 | +#315 — Ctrl+G should interrupt ongoing commands such as find-replace and search. |
| 5 | + |
| 6 | +## Problem |
| 7 | +There was no general-purpose mechanism to interrupt long-running editor operations (find, replace-all, spell-check) via Ctrl+G. Several C++ loops (`next_match`, replace-all, `spell_next`) run unbounded `while(true)` with no way to break out once started. Additionally, Ctrl+G behavior was inconsistent: it cancelled selection in normal mode but triggered "next match" in toolbar search. |
| 8 | + |
| 9 | +## Solution |
| 10 | +### 1. C++ interrupt infrastructure |
| 11 | +Added an `editor_interrupted` flag on `edit_interface_rep` with methods `interrupt_editor()`, `is_editor_interrupted()`, and `clear_editor_interrupt()`. The flag is reset when returning to normal input mode. |
| 12 | + |
| 13 | +### 2. Interruptible blocking loops |
| 14 | +Added `gui_interrupted(true)` checks to all unbounded C++ loops: |
| 15 | +- `next_match()` — exits cleanly with "Search interrupted" message |
| 16 | +- Replace-all loop (`a`/`!` key) — stops mid-replace with partial count |
| 17 | +- `search_previous_compound()` / `search_next_compound()` |
| 18 | +- `spell_next()` — ends spell check early with "Spell check interrupted" |
| 19 | + |
| 20 | +### 3. Scheme glue |
| 21 | +Exposed `editor-interrupt`, `editor-interrupted?`, `editor-clear-interrupt` to Scheme via `glue_editor.lua`. |
| 22 | + |
| 23 | +### 4. Unified `general-cancel` command |
| 24 | +Added `general-cancel` in `generic-edit.scm` that dispatches to the right cancel handler based on current mode: toolbar search/replace end, old-style search/replace/spell stop, or `selection-cancel` as fallback. |
| 25 | + |
| 26 | +### 5. Consistent Ctrl+G behavior |
| 27 | +- Toolbar search: Changed C-g/C-G from "next match" to `toolbar-search-end` |
| 28 | +- Toolbar replace: Added C-g as cancel alongside escape |
| 29 | +- Scheme replace-all: Made interruptible via `editor-interrupted?` check |
| 30 | +- Emacs/macOS profiles: Updated C-g binding to use `general-cancel` |
| 31 | +- Old-style search: Added missing `escape` handler to `search_keypress` |
| 32 | + |
| 33 | +## Changed Files |
| 34 | +- `src/Edit/Interface/edit_interface.hpp` — `editor_interrupted` flag and methods |
| 35 | +- `src/Edit/Interface/edit_interface.cpp` — Initialize flag in constructor |
| 36 | +- `src/Edit/Interface/edit_keyboard.cpp` — Implement interrupt methods, reset in `set_input_normal` |
| 37 | +- `src/Edit/editor.hpp` — Pure virtual declarations |
| 38 | +- `src/Edit/Replace/edit_search.cpp` — Interrupt checks in loops, escape in search_keypress |
| 39 | +- `src/Edit/Replace/edit_spell.cpp` — Interrupt check in `spell_next` |
| 40 | +- `src/Scheme/Glue/glue_editor.lua` — Expose interrupt methods to Scheme |
| 41 | +- `TeXmacs/progs/generic/generic-edit.scm` — `general-cancel` command |
| 42 | +- `TeXmacs/progs/generic/generic-kbd.scm` — C-g bindings use `general-cancel` |
| 43 | +- `TeXmacs/progs/generic/search-widgets.scm` — C-g cancels toolbar search/replace |
| 44 | + |
| 45 | +## How to Test |
| 46 | +1. Open a large document |
| 47 | +2. Use Ctrl+H (or menu Edit > Replace) to open find-replace |
| 48 | +3. Enter a common pattern and press Ctrl+Return (replace-all) |
| 49 | +4. While replacement is running, press Ctrl+G — it should stop |
| 50 | +5. Verify partial replacements can be undone with Ctrl+Z |
| 51 | +6. In toolbar search (Ctrl+F), press Ctrl+G — toolbar should close |
| 52 | +7. In normal mode, press Ctrl+G — selection should be cancelled |
| 53 | + |
| 54 | +## 2026/02/26 |
| 55 | +### What |
| 56 | +Implement Ctrl+G as a universal interrupt/cancel command for ongoing operations. |
0 commit comments