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).
|
/// Whether to forward a translated key to the daemon (session B2).
|
||||||
/// Motion keys go through with any modifiers. Plain text-editing keys
|
/// Motion keys go through with any modifiers (C-<left> is word
|
||||||
/// (`Char` / `Backspace` / `Enter` / `Delete` / `Tab`) go through only
|
/// motion). Deletion keys do too: C-BS / C-DEL / M-BS are word-level
|
||||||
/// *without* a Ctrl/Alt/Meta chord modifier: a bare key edits text,
|
/// deletes in the default keymap — the same editing-command family as
|
||||||
/// but a chord drives commands and minibuffer flows the GUI can't
|
/// chorded motion, and an unbound chord is a harmless no-op at the
|
||||||
/// render or interact with yet (deferred to a later session). Shift is
|
/// daemon keymap. (Chorded deletes never apply optimistically:
|
||||||
/// not a chord modifier — `Shift`+a already arrives as `Char('A')`.
|
/// `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 {
|
fn should_forward_key(key: ProtocolKey, mods: Modifiers) -> bool {
|
||||||
if is_motion_key(key) {
|
if is_motion_key(key) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if matches!(key, ProtocolKey::Backspace | ProtocolKey::Delete) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if !is_plain_text_modifiers(mods) {
|
if !is_plain_text_modifiers(mods) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
matches!(
|
matches!(
|
||||||
key,
|
key,
|
||||||
ProtocolKey::Char(_)
|
ProtocolKey::Char(_) | ProtocolKey::Enter | ProtocolKey::Tab
|
||||||
| ProtocolKey::Backspace
|
|
||||||
| ProtocolKey::Enter
|
|
||||||
| ProtocolKey::Delete
|
|
||||||
| ProtocolKey::Tab
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3600,6 +3605,13 @@ mod tests {
|
||||||
assert!(should_forward_key(ProtocolKey::Left, ctrl));
|
assert!(should_forward_key(ProtocolKey::Left, ctrl));
|
||||||
assert!(should_forward_key(ProtocolKey::Down, shift));
|
assert!(should_forward_key(ProtocolKey::Down, shift));
|
||||||
assert!(should_forward_key(ProtocolKey::PageUp, none));
|
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]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,32 @@ fn backspace_deletes_the_shift_selected_region() {
|
||||||
assert_eq!(cursor, 1);
|
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]
|
#[test]
|
||||||
fn typing_replaces_the_shift_selected_region() {
|
fn typing_replaces_the_shift_selected_region() {
|
||||||
let mut s = EditorState::new();
|
let mut s = EditorState::new();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue