Fix context_stack race in KeyContextView (#29324)

cc @notpeter

Before this change we used our own copy of `cx.key_context()` when
matching.
This led to races where the context queried could be either before (or
after) the
context used in dispatching.

To avoid the race, gpui now passes out the context stack actually used
instead.

Release Notes:

- Fixed a bug where the Key Context View could show the incorrect
context,
  causing confusing results.
This commit is contained in:
Conrad Irwin 2025-04-23 23:34:39 -06:00 committed by GitHub
parent 9d10489607
commit c0f8e0f605
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 52 additions and 23 deletions

View file

@ -1154,6 +1154,7 @@ impl Window {
&mut self,
event: &dyn Any,
action: Option<Box<dyn Action>>,
context_stack: Vec<KeyContext>,
cx: &mut App,
) {
let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
@ -1165,6 +1166,7 @@ impl Window {
&KeystrokeEvent {
keystroke: key_down_event.keystroke.clone(),
action: action.as_ref().map(|action| action.boxed_clone()),
context_stack: context_stack.clone(),
},
self,
cx,
@ -3275,7 +3277,7 @@ impl Window {
}
let Some(keystroke) = keystroke else {
self.finish_dispatch_key_event(event, dispatch_path, cx);
self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
return;
};
@ -3329,13 +3331,18 @@ impl Window {
for binding in match_result.bindings {
self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
if !cx.propagate_event {
self.dispatch_keystroke_observers(event, Some(binding.action), cx);
self.dispatch_keystroke_observers(
event,
Some(binding.action),
match_result.context_stack.clone(),
cx,
);
self.pending_input_changed(cx);
return;
}
}
self.finish_dispatch_key_event(event, dispatch_path, cx);
self.finish_dispatch_key_event(event, dispatch_path, match_result.context_stack, cx);
self.pending_input_changed(cx);
}
@ -3343,6 +3350,7 @@ impl Window {
&mut self,
event: &dyn Any,
dispatch_path: SmallVec<[DispatchNodeId; 32]>,
context_stack: Vec<KeyContext>,
cx: &mut App,
) {
self.dispatch_key_down_up_event(event, &dispatch_path, cx);
@ -3355,7 +3363,7 @@ impl Window {
return;
}
self.dispatch_keystroke_observers(event, None, cx);
self.dispatch_keystroke_observers(event, None, context_stack, cx);
}
fn pending_input_changed(&mut self, cx: &mut App) {
@ -3453,7 +3461,12 @@ impl Window {
for binding in replay.bindings {
self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
if !cx.propagate_event {
self.dispatch_keystroke_observers(&event, Some(binding.action), cx);
self.dispatch_keystroke_observers(
&event,
Some(binding.action),
Vec::default(),
cx,
);
continue 'replay;
}
}