first pass of merging in warp (doesn't build)

This commit is contained in:
Ryan Ward
2026-07-01 16:08:58 -05:00
parent 2f64909469
commit 4770ac06b5
3662 changed files with 414574 additions and 89772 deletions
+1 -1
View File
@@ -120,5 +120,5 @@ impl ContextPredicate {
}
#[cfg(test)]
#[path = "context_test.rs"]
#[path = "context_tests.rs"]
mod tests;
@@ -1,4 +1,5 @@
use super::{macros::*, *};
use super::macros::*;
use super::*;
#[test]
fn test_context_predicate_eval() -> anyhow::Result<()> {
@@ -0,0 +1,26 @@
use super::macros::*;
use super::*;
#[test]
fn test_context_predicate_eval() -> anyhow::Result<()> {
let predicate = id!("a") & id!("b") | eq!("c", "d");
let mut context = Context::default();
context.set.insert("a");
assert!(!predicate.eval(&context));
context.set.insert("b");
assert!(predicate.eval(&context));
context.set.remove("b");
context.map.insert("c", "x");
assert!(!predicate.eval(&context));
context.map.insert("c", "d");
assert!(predicate.eval(&context));
let predicate = !id!("a");
assert!(predicate.eval(&Context::default()));
Ok(())
}
+9 -6
View File
@@ -1,14 +1,17 @@
use std::sync::Arc;
use itertools::Either;
use super::{
BindingLens, Context, CustomTag, EditableBinding, EditableBindingLens, FixedBinding, Keymap,
Keystroke, Trigger,
};
use crate::{actions::StandardAction, Action, EntityId};
use itertools::Either;
use std::{collections::HashMap, sync::Arc};
use crate::actions::StandardAction;
use crate::{Action, EntityId, EntityIdMap};
#[derive(Default)]
pub struct Matcher {
pending: HashMap<EntityId, Pending>,
pending: EntityIdMap<Pending>,
keymap: Keymap,
/// Default binding validator that should run on every binding (irrespective of the [`Context`]
/// the binding was registered against).
@@ -53,7 +56,7 @@ pub enum MatchResult {
impl Matcher {
pub fn new(keymap: Keymap) -> Self {
Self {
pending: HashMap::new(),
pending: EntityIdMap::default(),
keymap,
default_binding_validator: None,
binding_validators: vec![],
@@ -376,5 +379,5 @@ impl Matcher {
}
#[cfg(test)]
#[path = "matcher_test.rs"]
#[path = "matcher_tests.rs"]
mod tests;
@@ -1,6 +1,5 @@
use crate::keymap::macros::*;
use super::*;
use crate::keymap::macros::*;
#[test]
fn test_matcher() -> anyhow::Result<()> {
@@ -96,7 +95,6 @@ fn test_editable_binding_matching() {
}
let mut keymap = Keymap::default();
use crate::keymap::macros::*;
keymap.register_editable_bindings([
EditableBinding::new("a", "Action for A", Action::A("b"))
.with_key_binding("a")
@@ -0,0 +1,250 @@
use super::*;
use crate::keymap::macros::*;
#[test]
fn test_matcher() -> anyhow::Result<()> {
#[derive(Debug, PartialEq)]
enum Action {
A(String),
B,
AB,
}
let keymap = Keymap::new(vec![
FixedBinding::new("a", Action::A("b".into()), id!("a")),
FixedBinding::new("b", Action::B, id!("a")),
FixedBinding::new("a b", Action::AB, id!("a") | id!("b")),
]);
let mut ctx_a = Context::default();
ctx_a.set.insert("a");
let mut ctx_b = Context::default();
ctx_b.set.insert("b");
let mut matcher = Matcher::new(keymap);
let view_id = EntityId::new();
// Basic match
assert_eq!(
matcher
.test_keystroke("a", view_id, &ctx_a)
.unwrap()
.as_action::<Action>(),
&Action::A("b".into())
);
// Multi-keystroke match
assert!(matcher.test_keystroke("a", view_id, &ctx_b).is_none());
assert_eq!(
matcher
.test_keystroke("b", view_id, &ctx_b)
.unwrap()
.as_action::<Action>(),
&Action::AB
);
// Failed matches don't interfere with matching subsequent keys
assert!(matcher.test_keystroke("x", view_id, &ctx_a).is_none());
assert_eq!(
matcher
.test_keystroke("a", view_id, &ctx_a)
.unwrap()
.as_action::<Action>(),
&Action::A("b".into())
);
// Pending keystrokes are cleared when the context changes
assert!(matcher.test_keystroke("a", view_id, &ctx_b).is_none());
assert_eq!(
matcher
.test_keystroke("b", view_id, &ctx_a)
.unwrap()
.as_action::<Action>(),
&Action::B
);
let mut ctx_c = Context::default();
ctx_c.set.insert("c");
// Pending keystrokes are maintained per-view
let view_id1 = EntityId::new();
let view_id2 = EntityId::new();
assert_ne!(view_id1, view_id2);
assert!(matcher.test_keystroke("a", view_id1, &ctx_b).is_none());
assert!(matcher.test_keystroke("a", view_id2, &ctx_c).is_none());
assert_eq!(
matcher
.test_keystroke("b", view_id1, &ctx_b)
.unwrap()
.as_action::<Action>(),
&Action::AB
);
Ok(())
}
#[test]
fn test_editable_binding_matching() {
#[derive(Debug, PartialEq)]
enum Action {
A(&'static str),
B,
AOrB,
}
let mut keymap = Keymap::default();
keymap.register_editable_bindings([
EditableBinding::new("a", "Action for A", Action::A("b"))
.with_key_binding("a")
.with_context_predicate(id!("a")),
EditableBinding::new("b", "Action for B", Action::B)
.with_key_binding("b")
.with_context_predicate(id!("a")),
EditableBinding::new("a_or_b", "Action for A or B", Action::AOrB)
.with_key_binding("a b")
.with_context_predicate(id!("a") | id!("b")),
]);
let mut ctx_a = Context::default();
ctx_a.set.insert("a");
let mut ctx_b = Context::default();
ctx_b.set.insert("b");
let mut matcher = Matcher::new(keymap);
let view_id = EntityId::new();
// Basic match
assert_eq!(
matcher
.test_keystroke("a", view_id, &ctx_a)
.unwrap()
.as_action::<Action>(),
&Action::A("b"),
);
// Multi-keystroke match
assert!(matcher.test_keystroke("a", view_id, &ctx_b).is_none());
assert_eq!(
matcher
.test_keystroke("b", view_id, &ctx_b)
.unwrap()
.as_action::<Action>(),
&Action::AOrB
);
// Failed matches don't interfere with matching subsequent keys
assert!(matcher.test_keystroke("x", view_id, &ctx_a).is_none());
assert_eq!(
matcher
.test_keystroke("a", view_id, &ctx_a)
.unwrap()
.as_action::<Action>(),
&Action::A("b")
);
// Pending keystrokes are cleared when the context changes
assert!(matcher.test_keystroke("a", view_id, &ctx_b).is_none());
assert_eq!(
matcher
.test_keystroke("b", view_id, &ctx_a)
.unwrap()
.as_action::<Action>(),
&Action::B
);
let mut ctx_c = Context::default();
ctx_c.set.insert("c");
// Pending keystrokes are maintained per-view
let view_id1 = EntityId::new();
let view_id2 = EntityId::new();
assert_ne!(view_id1, view_id2);
assert!(matcher.test_keystroke("a", view_id1, &ctx_b).is_none());
assert!(matcher.test_keystroke("a", view_id2, &ctx_c).is_none());
assert_eq!(
matcher
.test_keystroke("b", view_id1, &ctx_b)
.unwrap()
.as_action::<Action>(),
&Action::AOrB
);
}
#[test]
fn test_bindings_for_context() {
#[derive(Debug)]
enum Action {
A,
B,
C,
}
let keymap = Keymap::new(vec![
FixedBinding::new("a", Action::A, id!("a")),
FixedBinding::new("b", Action::B, id!("b")),
FixedBinding::new("c", Action::C, id!("b")),
]);
let matcher = Matcher::new(keymap);
let mut ctx_a = Context::default();
ctx_a.set.insert("a");
let mut ctx_b = Context::default();
ctx_b.set.insert("b");
// Getting bindings for the 'a' context returns a single result
let ctx_a_bindings = matcher
.bindings_for_context(ctx_a)
.filter_map(|bind| match bind.trigger {
Trigger::Keystrokes(keys) => {
assert_eq!(keys.len(), 1);
Some(keys[0].normalized())
}
_ => None,
})
.collect::<Vec<_>>();
assert_eq!(ctx_a_bindings.len(), 1);
assert_eq!(ctx_a_bindings, vec!["a"]);
// Getting bindings for the 'b' context returns two results, in the reverse order they
// added, so the "c" binding first followed by the "b" binding
let ctx_b_bindings = matcher
.bindings_for_context(ctx_b)
.filter_map(|bind| match bind.trigger {
Trigger::Keystrokes(keys) => {
assert_eq!(keys.len(), 1);
Some(keys[0].normalized())
}
_ => None,
})
.collect::<Vec<_>>();
assert_eq!(ctx_b_bindings, vec!["c", "b"]);
}
impl Matcher {
fn test_keystroke(
&mut self,
keystroke: &str,
view_id: EntityId,
ctx: &Context,
) -> Option<Arc<dyn Action>> {
match self.push_keystroke(Keystroke::parse(keystroke).unwrap(), view_id, ctx) {
MatchResult::Action(action) => Some(action),
_ => None,
}
}
}
trait AsAction {
fn as_action<A: Action>(&self) -> &A;
}
impl AsAction for Arc<dyn Action> {
fn as_action<A: Action>(&self) -> &A {
self.as_ref().as_any().downcast_ref::<A>().unwrap()
}
}