Checkpoint

This commit is contained in:
Antonio Scandurra
2023-10-20 11:08:24 +02:00
parent c3a917f8b3
commit b0acaed02f
5 changed files with 55 additions and 31 deletions
+31 -25
View File
@@ -23,6 +23,10 @@ impl DispatchContext {
}
}
pub fn is_empty(&self) -> bool {
self.set.is_empty() && self.map.is_empty()
}
pub fn clear(&mut self) {
self.set.clear();
self.map.clear();
@@ -47,17 +51,17 @@ impl DispatchContext {
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ActionContextPredicate {
pub enum DispatchContextPredicate {
Identifier(SharedString),
Equal(SharedString, SharedString),
NotEqual(SharedString, SharedString),
Child(Box<ActionContextPredicate>, Box<ActionContextPredicate>),
Not(Box<ActionContextPredicate>),
And(Box<ActionContextPredicate>, Box<ActionContextPredicate>),
Or(Box<ActionContextPredicate>, Box<ActionContextPredicate>),
Child(Box<DispatchContextPredicate>, Box<DispatchContextPredicate>),
Not(Box<DispatchContextPredicate>),
And(Box<DispatchContextPredicate>, Box<DispatchContextPredicate>),
Or(Box<DispatchContextPredicate>, Box<DispatchContextPredicate>),
}
impl ActionContextPredicate {
impl DispatchContextPredicate {
pub fn parse(source: &str) -> Result<Self> {
let source = Self::skip_whitespace(source);
let (predicate, rest) = Self::parse_expr(source, 0)?;
@@ -92,8 +96,10 @@ impl ActionContextPredicate {
}
fn parse_expr(mut source: &str, min_precedence: u32) -> anyhow::Result<(Self, &str)> {
type Op =
fn(ActionContextPredicate, ActionContextPredicate) -> Result<ActionContextPredicate>;
type Op = fn(
DispatchContextPredicate,
DispatchContextPredicate,
) -> Result<DispatchContextPredicate>;
let (mut predicate, rest) = Self::parse_primary(source)?;
source = rest;
@@ -139,7 +145,7 @@ impl ActionContextPredicate {
'!' => {
let source = Self::skip_whitespace(&source[1..]);
let (predicate, source) = Self::parse_expr(&source, PRECEDENCE_NOT)?;
Ok((ActionContextPredicate::Not(Box::new(predicate)), source))
Ok((DispatchContextPredicate::Not(Box::new(predicate)), source))
}
_ if next.is_alphanumeric() || next == '_' => {
let len = source
@@ -148,7 +154,7 @@ impl ActionContextPredicate {
let (identifier, rest) = source.split_at(len);
source = Self::skip_whitespace(rest);
Ok((
ActionContextPredicate::Identifier(identifier.to_string().into()),
DispatchContextPredicate::Identifier(identifier.to_string().into()),
source,
))
}
@@ -200,17 +206,17 @@ const PRECEDENCE_NOT: u32 = 5;
#[cfg(test)]
mod tests {
use super::ActionContextPredicate::{self, *};
use super::DispatchContextPredicate::{self, *};
#[test]
fn test_parse_identifiers() {
// Identifiers
assert_eq!(
ActionContextPredicate::parse("abc12").unwrap(),
DispatchContextPredicate::parse("abc12").unwrap(),
Identifier("abc12".into())
);
assert_eq!(
ActionContextPredicate::parse("_1a").unwrap(),
DispatchContextPredicate::parse("_1a").unwrap(),
Identifier("_1a".into())
);
}
@@ -218,11 +224,11 @@ mod tests {
#[test]
fn test_parse_negations() {
assert_eq!(
ActionContextPredicate::parse("!abc").unwrap(),
DispatchContextPredicate::parse("!abc").unwrap(),
Not(Box::new(Identifier("abc".into())))
);
assert_eq!(
ActionContextPredicate::parse(" ! ! abc").unwrap(),
DispatchContextPredicate::parse(" ! ! abc").unwrap(),
Not(Box::new(Not(Box::new(Identifier("abc".into())))))
);
}
@@ -230,15 +236,15 @@ mod tests {
#[test]
fn test_parse_equality_operators() {
assert_eq!(
ActionContextPredicate::parse("a == b").unwrap(),
DispatchContextPredicate::parse("a == b").unwrap(),
Equal("a".into(), "b".into())
);
assert_eq!(
ActionContextPredicate::parse("c!=d").unwrap(),
DispatchContextPredicate::parse("c!=d").unwrap(),
NotEqual("c".into(), "d".into())
);
assert_eq!(
ActionContextPredicate::parse("c == !d")
DispatchContextPredicate::parse("c == !d")
.unwrap_err()
.to_string(),
"operands must be identifiers"
@@ -248,14 +254,14 @@ mod tests {
#[test]
fn test_parse_boolean_operators() {
assert_eq!(
ActionContextPredicate::parse("a || b").unwrap(),
DispatchContextPredicate::parse("a || b").unwrap(),
Or(
Box::new(Identifier("a".into())),
Box::new(Identifier("b".into()))
)
);
assert_eq!(
ActionContextPredicate::parse("a || !b && c").unwrap(),
DispatchContextPredicate::parse("a || !b && c").unwrap(),
Or(
Box::new(Identifier("a".into())),
Box::new(And(
@@ -265,7 +271,7 @@ mod tests {
)
);
assert_eq!(
ActionContextPredicate::parse("a && b || c&&d").unwrap(),
DispatchContextPredicate::parse("a && b || c&&d").unwrap(),
Or(
Box::new(And(
Box::new(Identifier("a".into())),
@@ -278,7 +284,7 @@ mod tests {
)
);
assert_eq!(
ActionContextPredicate::parse("a == b && c || d == e && f").unwrap(),
DispatchContextPredicate::parse("a == b && c || d == e && f").unwrap(),
Or(
Box::new(And(
Box::new(Equal("a".into(), "b".into())),
@@ -291,7 +297,7 @@ mod tests {
)
);
assert_eq!(
ActionContextPredicate::parse("a && b && c && d").unwrap(),
DispatchContextPredicate::parse("a && b && c && d").unwrap(),
And(
Box::new(And(
Box::new(And(
@@ -308,7 +314,7 @@ mod tests {
#[test]
fn test_parse_parenthesized_expressions() {
assert_eq!(
ActionContextPredicate::parse("a && (b == c || d != e)").unwrap(),
DispatchContextPredicate::parse("a && (b == c || d != e)").unwrap(),
And(
Box::new(Identifier("a".into())),
Box::new(Or(
@@ -318,7 +324,7 @@ mod tests {
),
);
assert_eq!(
ActionContextPredicate::parse(" ( a || b ) ").unwrap(),
DispatchContextPredicate::parse(" ( a || b ) ").unwrap(),
Or(
Box::new(Identifier("a".into())),
Box::new(Identifier("b".into())),
+14 -1
View File
@@ -176,6 +176,14 @@ pub trait StatelessInteractive: Element {
self
}
fn context(mut self, context: impl Into<DispatchContext>) -> Self
where
Self: Sized,
{
self.stateless_interactivity().dispatch_context = context.into();
self
}
fn on_action<A: 'static>(
mut self,
listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext<Self::ViewState>)
@@ -320,7 +328,10 @@ pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
result
})
} else {
cx.with_key_listeners(&self.as_stateless().key_listeners, f)
let stateless = self.as_stateless();
cx.with_key_dispatch_context(stateless.dispatch_context.clone(), |cx| {
cx.with_key_listeners(&stateless.key_listeners, f)
})
}
}
@@ -519,6 +530,7 @@ where
}
pub struct StatelessInteraction<V> {
pub dispatch_context: DispatchContext,
pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
@@ -583,6 +595,7 @@ pub struct InteractiveElementState {
impl<V> Default for StatelessInteraction<V> {
fn default() -> Self {
Self {
dispatch_context: DispatchContext::new(),
mouse_down_listeners: SmallVec::new(),
mouse_up_listeners: SmallVec::new(),
mouse_move_listeners: SmallVec::new(),
+3 -3
View File
@@ -1,11 +1,11 @@
use crate::{Action, ActionContextPredicate, DispatchContext, KeyMatch, Keystroke};
use crate::{Action, DispatchContext, DispatchContextPredicate, KeyMatch, Keystroke};
use anyhow::Result;
use smallvec::SmallVec;
pub struct KeyBinding {
action: Box<dyn Action>,
pub(super) keystrokes: SmallVec<[Keystroke; 2]>,
pub(super) context_predicate: Option<ActionContextPredicate>,
pub(super) context_predicate: Option<DispatchContextPredicate>,
}
impl KeyBinding {
@@ -15,7 +15,7 @@ impl KeyBinding {
pub fn load(keystrokes: &str, action: Box<dyn Action>, context: Option<&str>) -> Result<Self> {
let context = if let Some(context) = context {
Some(ActionContextPredicate::parse(context)?)
Some(DispatchContextPredicate::parse(context)?)
} else {
None
};
+3 -2
View File
@@ -1,4 +1,4 @@
use crate::{ActionContextPredicate, KeyBinding, Keystroke};
use crate::{DispatchContextPredicate, KeyBinding, Keystroke};
use collections::HashSet;
use smallvec::SmallVec;
use std::{any::TypeId, collections::HashMap};
@@ -10,7 +10,8 @@ pub struct KeymapVersion(usize);
pub struct Keymap {
bindings: Vec<KeyBinding>,
binding_indices_by_action_id: HashMap<TypeId, SmallVec<[usize; 3]>>,
disabled_keystrokes: HashMap<SmallVec<[Keystroke; 2]>, HashSet<Option<ActionContextPredicate>>>,
disabled_keystrokes:
HashMap<SmallVec<[Keystroke; 2]>, HashSet<Option<DispatchContextPredicate>>>,
version: KeymapVersion,
}
+4
View File
@@ -1388,6 +1388,10 @@ impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
context: DispatchContext,
f: impl FnOnce(&mut Self) -> R,
) -> R {
if context.is_empty() {
return f(self);
}
if !self.window.freeze_key_dispatch_stack {
self.window
.key_dispatch_stack