pmacs-gpu: forward chorded deletion keys (C-BS word delete)
Backspace/Delete with modifiers were withheld by the chord filter, so C-BS / C-DEL / M-BS — word-level deletes in the default keymap — silently did nothing in the GPU while C-<left> word motion worked. Deletion keys now forward with their modifiers exactly like motion keys; an unbound chord is a harmless no-op at the daemon keymap, and chorded deletes never apply optimistically (optimistic_delete_range requires empty modifiers), so they always round-trip into their bound commands. Acceptance test drives C-BS / C-DEL through the real dispatch path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
21671cc590
commit
2339a10b03
|
|
@ -2649,26 +2649,31 @@ fn is_motion_key(key: ProtocolKey) -> bool {
|
|||
}
|
||||
|
||||
/// Whether to forward a translated key to the daemon (session B2).
|
||||
/// Motion keys go through with any modifiers. Plain text-editing keys
|
||||
/// (`Char` / `Backspace` / `Enter` / `Delete` / `Tab`) go through only
|
||||
/// *without* a Ctrl/Alt/Meta chord modifier: a bare key edits text,
|
||||
/// but a chord drives commands and minibuffer flows the GUI can't
|
||||
/// render or interact with yet (deferred to a later session). Shift is
|
||||
/// not a chord modifier — `Shift`+a already arrives as `Char('A')`.
|
||||
/// Motion keys go through with any modifiers (C-<left> is word
|
||||
/// motion). Deletion keys do too: C-BS / C-DEL / M-BS are word-level
|
||||
/// deletes in the default keymap — the same editing-command family as
|
||||
/// chorded motion, and an unbound chord is a harmless no-op at the
|
||||
/// daemon keymap. (Chorded deletes never apply optimistically:
|
||||
/// `optimistic_delete_range` requires empty modifiers, so they always
|
||||
/// round-trip into their bound commands.) The remaining text keys
|
||||
/// (`Char` / `Enter` / `Tab`) go through only *without* a
|
||||
/// Ctrl/Alt/Meta chord modifier: a bare key edits text, but those
|
||||
/// chords drive commands and minibuffer flows the GUI can't render or
|
||||
/// interact with yet (deferred to a later session). Shift is not a
|
||||
/// chord modifier — `Shift`+a already arrives as `Char('A')`.
|
||||
fn should_forward_key(key: ProtocolKey, mods: Modifiers) -> bool {
|
||||
if is_motion_key(key) {
|
||||
return true;
|
||||
}
|
||||
if matches!(key, ProtocolKey::Backspace | ProtocolKey::Delete) {
|
||||
return true;
|
||||
}
|
||||
if !is_plain_text_modifiers(mods) {
|
||||
return false;
|
||||
}
|
||||
matches!(
|
||||
key,
|
||||
ProtocolKey::Char(_)
|
||||
| ProtocolKey::Backspace
|
||||
| ProtocolKey::Enter
|
||||
| ProtocolKey::Delete
|
||||
| ProtocolKey::Tab
|
||||
ProtocolKey::Char(_) | ProtocolKey::Enter | ProtocolKey::Tab
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -3600,6 +3605,13 @@ mod tests {
|
|||
assert!(should_forward_key(ProtocolKey::Left, ctrl));
|
||||
assert!(should_forward_key(ProtocolKey::Down, shift));
|
||||
assert!(should_forward_key(ProtocolKey::PageUp, none));
|
||||
|
||||
// Deletion keys forward regardless of modifiers too — C-BS /
|
||||
// C-DEL / M-BS are word-level deletes in the default keymap,
|
||||
// the same editing-command family as chorded motion.
|
||||
assert!(should_forward_key(ProtocolKey::Backspace, ctrl));
|
||||
assert!(should_forward_key(ProtocolKey::Delete, ctrl));
|
||||
assert!(should_forward_key(ProtocolKey::Backspace, Modifiers::ALT));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -74,6 +74,32 @@ fn backspace_deletes_the_shift_selected_region() {
|
|||
assert_eq!(cursor, 1);
|
||||
}
|
||||
|
||||
/// C-Backspace deletes the previous word (and C-Delete the next),
|
||||
/// mirroring C-arrow word motion. The pmacs-gpu frontend forwards
|
||||
/// chorded deletion keys to this same dispatch path.
|
||||
#[test]
|
||||
fn ctrl_backspace_deletes_the_previous_word() {
|
||||
let mut s = EditorState::new();
|
||||
type_str(&mut s, "alpha beta");
|
||||
|
||||
s.dispatch_key(
|
||||
FrontendId::LOCAL,
|
||||
key(KeyCode::Backspace, KeyModifiers::CONTROL),
|
||||
);
|
||||
let (text, _, cursor) = probe(&s);
|
||||
assert_eq!(text, "alpha ", "C-BS deletes back through the previous word");
|
||||
assert_eq!(cursor, 6);
|
||||
|
||||
s.dispatch_key(FrontendId::LOCAL, key(KeyCode::Left, KeyModifiers::CONTROL));
|
||||
s.dispatch_key(
|
||||
FrontendId::LOCAL,
|
||||
key(KeyCode::Delete, KeyModifiers::CONTROL),
|
||||
);
|
||||
let (text, _, cursor) = probe(&s);
|
||||
assert_eq!(text, " ", "C-DEL deletes forward through the next word");
|
||||
assert_eq!(cursor, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typing_replaces_the_shift_selected_region() {
|
||||
let mut s = EditorState::new();
|
||||
|
|
|
|||
Loading…
Reference in New Issue