Fix keys not being sent to terminal (#35979)

Fixes #35057

Release Notes:

- Fix input being sent to editor/terminal when pending keystrokes are
resolved
This commit is contained in:
Conrad Irwin 2025-08-11 16:07:32 +01:00 committed by GitHub
parent 6478e66e7a
commit 12084b6677
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 173 additions and 3 deletions

View file

@ -611,9 +611,17 @@ impl DispatchTree {
#[cfg(test)]
mod tests {
use std::{cell::RefCell, rc::Rc};
use crate::{
self as gpui, Element, ElementId, GlobalElementId, InspectorElementId, LayoutId, Style,
};
use core::panic;
use std::{cell::RefCell, ops::Range, rc::Rc};
use crate::{Action, ActionRegistry, DispatchTree, KeyBinding, KeyContext, Keymap};
use crate::{
Action, ActionRegistry, App, Bounds, Context, DispatchTree, FocusHandle, InputHandler,
IntoElement, KeyBinding, KeyContext, Keymap, Pixels, Point, Render, TestAppContext,
UTF16Selection, Window,
};
#[derive(PartialEq, Eq)]
struct TestAction;
@ -674,4 +682,165 @@ mod tests {
assert!(keybinding[0].action.partial_eq(&TestAction))
}
#[crate::test]
fn test_input_handler_pending(cx: &mut TestAppContext) {
#[derive(Clone)]
struct CustomElement {
focus_handle: FocusHandle,
text: Rc<RefCell<String>>,
}
impl CustomElement {
fn new(cx: &mut Context<Self>) -> Self {
Self {
focus_handle: cx.focus_handle(),
text: Rc::default(),
}
}
}
impl Element for CustomElement {
type RequestLayoutState = ();
type PrepaintState = ();
fn id(&self) -> Option<ElementId> {
Some("custom".into())
}
fn source_location(&self) -> Option<&'static panic::Location<'static>> {
None
}
fn request_layout(
&mut self,
_: Option<&GlobalElementId>,
_: Option<&InspectorElementId>,
window: &mut Window,
cx: &mut App,
) -> (LayoutId, Self::RequestLayoutState) {
(window.request_layout(Style::default(), [], cx), ())
}
fn prepaint(
&mut self,
_: Option<&GlobalElementId>,
_: Option<&InspectorElementId>,
_: Bounds<Pixels>,
_: &mut Self::RequestLayoutState,
window: &mut Window,
cx: &mut App,
) -> Self::PrepaintState {
window.set_focus_handle(&self.focus_handle, cx);
}
fn paint(
&mut self,
_: Option<&GlobalElementId>,
_: Option<&InspectorElementId>,
_: Bounds<Pixels>,
_: &mut Self::RequestLayoutState,
_: &mut Self::PrepaintState,
window: &mut Window,
cx: &mut App,
) {
let mut key_context = KeyContext::default();
key_context.add("Terminal");
window.set_key_context(key_context);
window.handle_input(&self.focus_handle, self.clone(), cx);
window.on_action(std::any::TypeId::of::<TestAction>(), |_, _, _, _| {});
}
}
impl IntoElement for CustomElement {
type Element = Self;
fn into_element(self) -> Self::Element {
self
}
}
impl InputHandler for CustomElement {
fn selected_text_range(
&mut self,
_: bool,
_: &mut Window,
_: &mut App,
) -> Option<UTF16Selection> {
None
}
fn marked_text_range(&mut self, _: &mut Window, _: &mut App) -> Option<Range<usize>> {
None
}
fn text_for_range(
&mut self,
_: Range<usize>,
_: &mut Option<Range<usize>>,
_: &mut Window,
_: &mut App,
) -> Option<String> {
None
}
fn replace_text_in_range(
&mut self,
replacement_range: Option<Range<usize>>,
text: &str,
_: &mut Window,
_: &mut App,
) {
if replacement_range.is_some() {
unimplemented!()
}
self.text.borrow_mut().push_str(text)
}
fn replace_and_mark_text_in_range(
&mut self,
replacement_range: Option<Range<usize>>,
new_text: &str,
_: Option<Range<usize>>,
_: &mut Window,
_: &mut App,
) {
if replacement_range.is_some() {
unimplemented!()
}
self.text.borrow_mut().push_str(new_text)
}
fn unmark_text(&mut self, _: &mut Window, _: &mut App) {}
fn bounds_for_range(
&mut self,
_: Range<usize>,
_: &mut Window,
_: &mut App,
) -> Option<Bounds<Pixels>> {
None
}
fn character_index_for_point(
&mut self,
_: Point<Pixels>,
_: &mut Window,
_: &mut App,
) -> Option<usize> {
None
}
}
impl Render for CustomElement {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
self.clone()
}
}
cx.update(|cx| {
cx.bind_keys([KeyBinding::new("ctrl-b", TestAction, Some("Terminal"))]);
cx.bind_keys([KeyBinding::new("ctrl-b h", TestAction, Some("Terminal"))]);
});
let (test, cx) = cx.add_window_view(|_, cx| CustomElement::new(cx));
cx.update(|window, cx| {
window.focus(&test.read(cx).focus_handle);
window.activate_window();
});
cx.simulate_keystrokes("ctrl-b [");
test.update(cx, |test, _| assert_eq!(test.text.borrow().as_str(), "["))
}
}

View file

@ -3688,7 +3688,8 @@ impl Window {
);
if !match_result.to_replay.is_empty() {
self.replay_pending_input(match_result.to_replay, cx)
self.replay_pending_input(match_result.to_replay, cx);
cx.propagate_event = true;
}
if !match_result.pending.is_empty() {