Fix cmd-k left
This commit is contained in:
parent
7ec4f22202
commit
c5d7c8e122
4 changed files with 62 additions and 15 deletions
|
@ -34,6 +34,7 @@ use std::{
|
||||||
atomic::{AtomicBool, Ordering::SeqCst},
|
atomic::{AtomicBool, Ordering::SeqCst},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
use unindent::Unindent as _;
|
use unindent::Unindent as _;
|
||||||
|
|
||||||
|
@ -5945,3 +5946,26 @@ async fn test_right_click_menu_behind_collab_panel(cx: &mut TestAppContext) {
|
||||||
});
|
});
|
||||||
assert!(cx.debug_bounds("MENU_ITEM-Close").is_some());
|
assert!(cx.debug_bounds("MENU_ITEM-Close").is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_cmd_k_left(cx: &mut TestAppContext) {
|
||||||
|
let client = TestServer::start1(cx).await;
|
||||||
|
let (workspace, cx) = client.build_test_workspace(cx).await;
|
||||||
|
|
||||||
|
cx.simulate_keystrokes("cmd-n");
|
||||||
|
workspace.update(cx, |workspace, cx| {
|
||||||
|
assert!(workspace.items(cx).collect::<Vec<_>>().len() == 1);
|
||||||
|
});
|
||||||
|
cx.simulate_keystrokes("cmd-k left");
|
||||||
|
workspace.update(cx, |workspace, cx| {
|
||||||
|
assert!(workspace.items(cx).collect::<Vec<_>>().len() == 2);
|
||||||
|
});
|
||||||
|
cx.simulate_keystrokes("cmd-k");
|
||||||
|
// sleep for longer than the timeout in keyboard shortcut handling
|
||||||
|
// to verify that it doesn't fire in this case.
|
||||||
|
cx.executor().advance_clock(Duration::from_secs(2));
|
||||||
|
cx.simulate_keystrokes("left");
|
||||||
|
workspace.update(cx, |workspace, cx| {
|
||||||
|
assert!(workspace.items(cx).collect::<Vec<_>>().len() == 3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -127,6 +127,11 @@ impl TestServer {
|
||||||
(client_a, client_b, channel_id)
|
(client_a, client_b, channel_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn start1<'a>(cx: &'a mut TestAppContext) -> TestClient {
|
||||||
|
let mut server = Self::start(cx.executor().clone()).await;
|
||||||
|
server.create_client(cx, "user_a").await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn reset(&self) {
|
pub async fn reset(&self) {
|
||||||
self.app_state.db.reset();
|
self.app_state.db.reset();
|
||||||
let epoch = self
|
let epoch = self
|
||||||
|
|
|
@ -272,12 +272,17 @@ impl DispatchTree {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dispatch_key pushses the next keystroke into any key binding matchers.
|
||||||
|
// any matching bindings are returned in the order that they should be dispatched:
|
||||||
|
// * First by length of binding (so if you have a binding for "b" and "ab", the "ab" binding fires first)
|
||||||
|
// * Secondly by depth in the tree (so if Editor has a binding for "b" and workspace a
|
||||||
|
// binding for "b", the Editor action fires first).
|
||||||
pub fn dispatch_key(
|
pub fn dispatch_key(
|
||||||
&mut self,
|
&mut self,
|
||||||
keystroke: &Keystroke,
|
keystroke: &Keystroke,
|
||||||
dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
|
dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
|
||||||
) -> KeymatchResult {
|
) -> KeymatchResult {
|
||||||
let mut bindings = SmallVec::new();
|
let mut bindings = SmallVec::<[KeyBinding; 1]>::new();
|
||||||
let mut pending = false;
|
let mut pending = false;
|
||||||
|
|
||||||
let mut context_stack: SmallVec<[KeyContext; 4]> = SmallVec::new();
|
let mut context_stack: SmallVec<[KeyContext; 4]> = SmallVec::new();
|
||||||
|
@ -295,9 +300,19 @@ impl DispatchTree {
|
||||||
.entry(context_stack.clone())
|
.entry(context_stack.clone())
|
||||||
.or_insert_with(|| KeystrokeMatcher::new(self.keymap.clone()));
|
.or_insert_with(|| KeystrokeMatcher::new(self.keymap.clone()));
|
||||||
|
|
||||||
let mut result = keystroke_matcher.match_keystroke(keystroke, &context_stack);
|
let result = keystroke_matcher.match_keystroke(keystroke, &context_stack);
|
||||||
pending = result.pending || pending;
|
pending = result.pending || pending;
|
||||||
bindings.append(&mut result.bindings);
|
for new_binding in result.bindings {
|
||||||
|
match bindings
|
||||||
|
.iter()
|
||||||
|
.position(|el| el.keystrokes.len() < new_binding.keystrokes.len())
|
||||||
|
{
|
||||||
|
Some(idx) => {
|
||||||
|
bindings.insert(idx, new_binding);
|
||||||
|
}
|
||||||
|
None => bindings.push(new_binding),
|
||||||
|
}
|
||||||
|
}
|
||||||
context_stack.pop();
|
context_stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1186,6 +1186,8 @@ impl<'a> WindowContext<'a> {
|
||||||
currently_pending.bindings.push(binding);
|
currently_pending.bindings.push(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for vim compatibility, we also shoul check "is input handler enabled"
|
||||||
|
if !currently_pending.text.is_empty() || !currently_pending.bindings.is_empty() {
|
||||||
currently_pending.timer = Some(self.spawn(|mut cx| async move {
|
currently_pending.timer = Some(self.spawn(|mut cx| async move {
|
||||||
cx.background_executor.timer(Duration::from_secs(1)).await;
|
cx.background_executor.timer(Duration::from_secs(1)).await;
|
||||||
cx.update(move |cx| {
|
cx.update(move |cx| {
|
||||||
|
@ -1198,6 +1200,7 @@ impl<'a> WindowContext<'a> {
|
||||||
.log_err();
|
.log_err();
|
||||||
}));
|
}));
|
||||||
self.window.pending_input = Some(currently_pending);
|
self.window.pending_input = Some(currently_pending);
|
||||||
|
}
|
||||||
|
|
||||||
self.propagate_event = false;
|
self.propagate_event = false;
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue