-
Notifications
You must be signed in to change notification settings - Fork 76
[201_85]: Ctrl+G interrupt for ongoing commands #2866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -696,9 +696,10 @@ tree 或 #f | |||||||||
| (let ((u (if (null? args) (master-buffer) (car args))) | ||||||||||
| (raux (if (null? args) (replace-buffer) (cadr args)))) | ||||||||||
| (and-with by (or (by-tree raux) current-replace) | ||||||||||
| (editor-clear-interrupt) | ||||||||||
| (with-buffer u | ||||||||||
| (start-editing) | ||||||||||
| (while (replace-next by) | ||||||||||
| (while (and (not (editor-interrupted?)) (replace-next by)) | ||||||||||
|
||||||||||
| (while (and (not (editor-interrupted?)) (replace-next by)) | |
| (while (and (not (editor-interrupted?)) | |
| (not (gui-interrupted? #t)) | |
| (replace-next by)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # [201_85] Ctrl+G interrupt for ongoing commands | ||
|
|
||
| ## Issue | ||
| #315 — Ctrl+G should interrupt ongoing commands such as find-replace and search. | ||
|
|
||
| ## Problem | ||
| 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. | ||
|
|
||
| ## Solution | ||
| ### 1. C++ interrupt infrastructure | ||
| 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. | ||
|
|
||
| ### 2. Interruptible blocking loops | ||
| Added `gui_interrupted(true)` checks to all unbounded C++ loops: | ||
| - `next_match()` — exits cleanly with "Search interrupted" message | ||
| - Replace-all loop (`a`/`!` key) — stops mid-replace with partial count | ||
| - `search_previous_compound()` / `search_next_compound()` | ||
| - `spell_next()` — ends spell check early with "Spell check interrupted" | ||
|
|
||
| ### 3. Scheme glue | ||
| Exposed `editor-interrupt`, `editor-interrupted?`, `editor-clear-interrupt` to Scheme via `glue_editor.lua`. | ||
|
|
||
| ### 4. Unified `general-cancel` command | ||
| 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. | ||
|
|
||
| ### 5. Consistent Ctrl+G behavior | ||
| - Toolbar search: Changed C-g/C-G from "next match" to `toolbar-search-end` | ||
| - Toolbar replace: Added C-g as cancel alongside escape | ||
| - Scheme replace-all: Made interruptible via `editor-interrupted?` check | ||
| - Emacs/macOS profiles: Updated C-g binding to use `general-cancel` | ||
| - Old-style search: Added missing `escape` handler to `search_keypress` | ||
|
|
||
| ## Changed Files | ||
| - `src/Edit/Interface/edit_interface.hpp` — `editor_interrupted` flag and methods | ||
| - `src/Edit/Interface/edit_interface.cpp` — Initialize flag in constructor | ||
| - `src/Edit/Interface/edit_keyboard.cpp` — Implement interrupt methods, reset in `set_input_normal` | ||
| - `src/Edit/editor.hpp` — Pure virtual declarations | ||
| - `src/Edit/Replace/edit_search.cpp` — Interrupt checks in loops, escape in search_keypress | ||
| - `src/Edit/Replace/edit_spell.cpp` — Interrupt check in `spell_next` | ||
| - `src/Scheme/Glue/glue_editor.lua` — Expose interrupt methods to Scheme | ||
| - `TeXmacs/progs/generic/generic-edit.scm` — `general-cancel` command | ||
| - `TeXmacs/progs/generic/generic-kbd.scm` — C-g bindings use `general-cancel` | ||
| - `TeXmacs/progs/generic/search-widgets.scm` — C-g cancels toolbar search/replace | ||
|
|
||
| ## How to Test | ||
| 1. Open a large document | ||
| 2. Use Ctrl+H (or menu Edit > Replace) to open find-replace | ||
| 3. Enter a common pattern and press Ctrl+Return (replace-all) | ||
| 4. While replacement is running, press Ctrl+G — it should stop | ||
| 5. Verify partial replacements can be undone with Ctrl+Z | ||
| 6. In toolbar search (Ctrl+F), press Ctrl+G — toolbar should close | ||
| 7. In normal mode, press Ctrl+G — selection should be cancelled | ||
|
|
||
| ## 2026/02/26 | ||
| ### What | ||
| Implement Ctrl+G as a universal interrupt/cancel command for ongoing operations. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -58,6 +58,7 @@ class edit_interface_rep : virtual public editor_rep { | |||||
| SI zpixel; // pixel multiplied by zoom factor | ||||||
| rectangles copy_always; // for wiping out cursor | ||||||
| int input_mode; // INPUT_NORMAL, INPUT_SEARCH, INPUT_REPLACE | ||||||
| bool editor_interrupted; // set by Ctrl+G, checked by long-running loops | ||||||
|
||||||
| bool editor_interrupted; // set by Ctrl+G, checked by long-running loops | |
| bool editor_interrupted; // set by Ctrl+G to signal an editor interruption |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
general-canceldoes not appear to signal the new interrupt mechanism (it never callseditor-interrupt). Givensearch-widgets.scmnow relies oneditor-interrupted?to stop toolbar replace-all, it would help to set the interrupt flag here (or otherwise ensure Ctrl+G sets it) so long-running operations can observe the cancel request.