diff options
Diffstat (limited to 'helix-term/src/compositor.rs')
-rw-r--r-- | helix-term/src/compositor.rs | 86 |
1 files changed, 85 insertions, 1 deletions
diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs index 4869032b..6e81cc81 100644 --- a/helix-term/src/compositor.rs +++ b/helix-term/src/compositor.rs @@ -34,7 +34,7 @@ pub struct Context<'a> { pub callbacks: &'a mut LspCallbacks, } -pub trait Component { +pub trait Component: Any + AnyComponent { /// Process input events, return true if handled. fn handle_event(&mut self, event: Event, ctx: &mut Context) -> EventResult { EventResult::Ignored @@ -60,6 +60,10 @@ pub trait Component { // that way render can use it None } + + fn type_name(&self) -> &'static str { + std::any::type_name::<Self>() + } } use anyhow::Error; @@ -142,4 +146,84 @@ impl Compositor { } None } + + pub fn find(&mut self, type_name: &str) -> Option<&mut dyn Component> { + self.layers + .iter_mut() + .find(|component| component.type_name() == type_name) + .map(|component| component.as_mut()) + } +} + +// View casting, taken straight from Cursive + +use std::any::Any; + +/// A view that can be downcasted to its concrete type. +/// +/// This trait is automatically implemented for any `T: Component`. +pub trait AnyComponent { + /// Downcast self to a `Any`. + fn as_any(&self) -> &dyn Any; + + /// Downcast self to a mutable `Any`. + fn as_any_mut(&mut self) -> &mut dyn Any; + + /// Returns a boxed any from a boxed self. + /// + /// Can be used before `Box::downcast()`. + /// + /// # Examples + /// + /// ```rust + /// # use cursive_core::views::TextComponent; + /// # use cursive_core::view::Component; + /// let boxed: Box<Component> = Box::new(TextComponent::new("text")); + /// let text: Box<TextComponent> = boxed.as_boxed_any().downcast().unwrap(); + /// ``` + fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>; +} + +impl<T: Component> AnyComponent for T { + /// Downcast self to a `Any`. + fn as_any(&self) -> &dyn Any { + self + } + + /// Downcast self to a mutable `Any`. + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn as_boxed_any(self: Box<Self>) -> Box<dyn Any> { + self + } +} + +impl dyn AnyComponent { + /// Attempts to downcast `self` to a concrete type. + pub fn downcast_ref<T: Any>(&self) -> Option<&T> { + self.as_any().downcast_ref() + } + + /// Attempts to downcast `self` to a concrete type. + pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { + self.as_any_mut().downcast_mut() + } + + /// Attempts to downcast `Box<Self>` to a concrete type. + pub fn downcast<T: Any>(self: Box<Self>) -> Result<Box<T>, Box<Self>> { + // Do the check here + unwrap, so the error + // value is `Self` and not `dyn Any`. + if self.as_any().is::<T>() { + Ok(self.as_boxed_any().downcast().unwrap()) + } else { + Err(self) + } + } + + /// Checks if this view is of type `T`. + pub fn is<T: Any>(&mut self) -> bool { + self.as_any().is::<T>() + } } |