summaryrefslogtreecommitdiff
path: root/helix-term/src/compositor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src/compositor.rs')
-rw-r--r--helix-term/src/compositor.rs36
1 files changed, 32 insertions, 4 deletions
diff --git a/helix-term/src/compositor.rs b/helix-term/src/compositor.rs
index 3a644750..dd7ebe1d 100644
--- a/helix-term/src/compositor.rs
+++ b/helix-term/src/compositor.rs
@@ -7,7 +7,7 @@ use helix_view::graphics::{CursorKind, Rect};
use crossterm::event::Event;
use tui::buffer::Buffer as Surface;
-pub type Callback = Box<dyn FnOnce(&mut Compositor)>;
+pub type Callback = Box<dyn FnOnce(&mut Compositor, &mut Context)>;
// --> EventResult should have a callback that takes a context with methods like .popup(),
// .prompt() etc. That way we can abstract it from the renderer.
@@ -55,15 +55,20 @@ pub trait Component: Any + AnyComponent {
/// May be used by the parent component to compute the child area.
/// viewport is the maximum allowed area, and the child should stay within those bounds.
+ ///
+ /// The returned size might be larger than the viewport if the child is too big to fit.
+ /// In this case the parent can use the values to calculate scroll.
fn required_size(&mut self, _viewport: (u16, u16)) -> Option<(u16, u16)> {
- // TODO: for scrolling, the scroll wrapper should place a size + offset on the Context
- // that way render can use it
None
}
fn type_name(&self) -> &'static str {
std::any::type_name::<Self>()
}
+
+ fn id(&self) -> Option<&'static str> {
+ None
+ }
}
use anyhow::Error;
@@ -121,17 +126,32 @@ impl Compositor {
self.layers.push(layer);
}
+ /// Replace a component that has the given `id` with the new layer and if
+ /// no component is found, push the layer normally.
+ pub fn replace_or_push(&mut self, id: &'static str, layer: Box<dyn Component>) {
+ if let Some(component) = self.find_id(id) {
+ *component = layer;
+ } else {
+ self.push(layer)
+ }
+ }
+
pub fn pop(&mut self) -> Option<Box<dyn Component>> {
self.layers.pop()
}
pub fn handle_event(&mut self, event: Event, cx: &mut Context) -> bool {
+ // If it is a key event and a macro is being recorded, push the key event to the recording.
+ if let (Event::Key(key), Some((_, keys))) = (event, &mut cx.editor.macro_recording) {
+ keys.push(key.into());
+ }
+
// propagate events through the layers until we either find a layer that consumes it or we
// run out of layers (event bubbling)
for layer in self.layers.iter_mut().rev() {
match layer.handle_event(event, cx) {
EventResult::Consumed(Some(callback)) => {
- callback(self);
+ callback(self, cx);
return true;
}
EventResult::Consumed(None) => return true,
@@ -184,6 +204,14 @@ impl Compositor {
.find(|component| component.type_name() == type_name)
.and_then(|component| component.as_any_mut().downcast_mut())
}
+
+ pub fn find_id<T: 'static>(&mut self, id: &'static str) -> Option<&mut T> {
+ let type_name = std::any::type_name::<T>();
+ self.layers
+ .iter_mut()
+ .find(|component| component.type_name() == type_name && component.id() == Some(id))
+ .and_then(|component| component.as_any_mut().downcast_mut())
+ }
}
// View casting, taken straight from Cursive