add dynamic component names

pull/8675/merge^2
mattwparas 8 months ago
parent fb81eab093
commit a1b13e570d

8
Cargo.lock generated

@ -2357,7 +2357,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "steel-core" name = "steel-core"
version = "0.6.0" version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#c10339bcda9808c326d5aebda610d920fc436a1f" source = "git+https://github.com/mattwparas/steel.git#c5451eaf7fc8e4ba39eb0536b0ccc9b469c2e50b"
dependencies = [ dependencies = [
"abi_stable", "abi_stable",
"anyhow", "anyhow",
@ -2395,7 +2395,7 @@ dependencies = [
[[package]] [[package]]
name = "steel-derive" name = "steel-derive"
version = "0.5.0" version = "0.5.0"
source = "git+https://github.com/mattwparas/steel.git#c10339bcda9808c326d5aebda610d920fc436a1f" source = "git+https://github.com/mattwparas/steel.git#c5451eaf7fc8e4ba39eb0536b0ccc9b469c2e50b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2405,7 +2405,7 @@ dependencies = [
[[package]] [[package]]
name = "steel-gen" name = "steel-gen"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/mattwparas/steel.git#c10339bcda9808c326d5aebda610d920fc436a1f" source = "git+https://github.com/mattwparas/steel.git#c5451eaf7fc8e4ba39eb0536b0ccc9b469c2e50b"
dependencies = [ dependencies = [
"codegen", "codegen",
"serde", "serde",
@ -2415,7 +2415,7 @@ dependencies = [
[[package]] [[package]]
name = "steel-parser" name = "steel-parser"
version = "0.6.0" version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#c10339bcda9808c326d5aebda610d920fc436a1f" source = "git+https://github.com/mattwparas/steel.git#c5451eaf7fc8e4ba39eb0536b0ccc9b469c2e50b"
dependencies = [ dependencies = [
"fxhash", "fxhash",
"lasso", "lasso",

@ -26,7 +26,6 @@ use crate::{
Context, Context,
}, },
compositor::{self, Component}, compositor::{self, Component},
ctrl, key,
ui::overlay::overlaid, ui::overlay::overlaid,
}; };
@ -40,8 +39,6 @@ struct AsyncReader {
} }
impl AsyncReader { impl AsyncReader {
// TODO: Add &mut references to these async functions
// to avoid the cloning, and to ditch the arc and mutex
async fn read_line(self) -> Option<String> { async fn read_line(self) -> Option<String> {
let mut buf = String::new(); let mut buf = String::new();
@ -53,6 +50,20 @@ impl AsyncReader {
let fut = guard.recv(); let fut = guard.recv();
// If we haven't found any characters, just wait until we have something.
// Otherwise, we give this a 2 ms buffer to check if more things are
// coming through the pipe.
if buf.is_empty() {
let next = fut.await;
match next {
Some(v) => {
buf.push_str(&v);
Some(buf)
}
None => None,
}
} else {
match tokio::time::timeout(std::time::Duration::from_millis(2), fut).await { match tokio::time::timeout(std::time::Duration::from_millis(2), fut).await {
Ok(Some(v)) => { Ok(Some(v)) => {
buf.push_str(&v); buf.push_str(&v);
@ -68,6 +79,7 @@ impl AsyncReader {
Err(_) => Some(buf), Err(_) => Some(buf),
} }
} }
}
} }
impl Custom for AsyncReader {} impl Custom for AsyncReader {}
@ -254,6 +266,12 @@ pub fn helix_component_module() -> BuiltInModule {
"event-result/consume", "event-result/consume",
SteelEventResult::Consumed.into_steelval().unwrap(), SteelEventResult::Consumed.into_steelval().unwrap(),
) )
.register_value(
"event-result/consume-without-rerender",
SteelEventResult::ConsumedWithoutRerender
.into_steelval()
.unwrap(),
)
.register_value( .register_value(
"event-result/ignore", "event-result/ignore",
SteelEventResult::Ignored.into_steelval().unwrap(), SteelEventResult::Ignored.into_steelval().unwrap(),
@ -439,7 +457,7 @@ pub struct SteelDynamicComponent {
// TODO: currently the component id requires using a &'static str, // TODO: currently the component id requires using a &'static str,
// however in a world with dynamic components that might not be // however in a world with dynamic components that might not be
// the case anymore // the case anymore
_name: String, name: String,
// This _should_ be a struct, but in theory can be whatever you want. It will be the first argument // This _should_ be a struct, but in theory can be whatever you want. It will be the first argument
// passed to the functions in the remainder of the struct. // passed to the functions in the remainder of the struct.
state: SteelVal, state: SteelVal,
@ -463,7 +481,7 @@ impl SteelDynamicComponent {
h: HashMap<String, SteelVal>, h: HashMap<String, SteelVal>,
) -> Self { ) -> Self {
Self { Self {
_name: name, name,
state, state,
render, render,
handle_event: h.get("handle_event").cloned(), handle_event: h.get("handle_event").cloned(),
@ -522,11 +540,16 @@ enum SteelEventResult {
Consumed, Consumed,
Ignored, Ignored,
Close, Close,
ConsumedWithoutRerender,
} }
impl Custom for SteelEventResult {} impl Custom for SteelEventResult {}
impl Component for SteelDynamicComponent { impl Component for SteelDynamicComponent {
fn name(&self) -> Option<&str> {
Some(&self.name)
}
fn render( fn render(
&mut self, &mut self,
area: helix_view::graphics::Rect, area: helix_view::graphics::Rect,
@ -646,6 +669,9 @@ impl Component for SteelDynamicComponent {
match value { match value {
Ok(SteelEventResult::Close) => close_fn, Ok(SteelEventResult::Close) => close_fn,
Ok(SteelEventResult::Consumed) => compositor::EventResult::Consumed(None), Ok(SteelEventResult::Consumed) => compositor::EventResult::Consumed(None),
Ok(SteelEventResult::ConsumedWithoutRerender) => {
compositor::EventResult::ConsumedWithoutRerender
}
Ok(SteelEventResult::Ignored) => compositor::EventResult::Ignored(None), Ok(SteelEventResult::Ignored) => compositor::EventResult::Ignored(None),
_ => match event { _ => match event {
// ctrl!('c') | key!(Esc) => close_fn, // ctrl!('c') | key!(Esc) => close_fn,
@ -715,7 +741,7 @@ impl Component for SteelDynamicComponent {
Err(_e) => { Err(_e) => {
log::info!("Error: {:?}", _e); log::info!("Error: {:?}", _e);
(None, CursorKind::Block) (None, CursorKind::Block)
}, }
} }
} else { } else {
(None, helix_view::graphics::CursorKind::Hidden) (None, helix_view::graphics::CursorKind::Hidden)

@ -1527,7 +1527,11 @@ impl Component for BoxDynComponent {
} }
fn id(&self) -> Option<&'static str> { fn id(&self) -> Option<&'static str> {
None Some(self.inner.type_name())
}
fn name(&self) -> Option<&str> {
self.inner.name()
} }
fn render( fn render(
@ -1768,8 +1772,10 @@ fn load_misc_api(engine: &mut Engine, generate_sources: bool) {
// Arity 1 // Arity 1
module.register_fn("hx.custom-insert-newline", custom_insert_newline); module.register_fn("hx.custom-insert-newline", custom_insert_newline);
module.register_fn("push-component!", push_component); module.register_fn("push-component!", push_component);
module.register_fn("pop-last-component!", pop_last_component_by_name);
module.register_fn("enqueue-thread-local-callback", enqueue_command); module.register_fn("enqueue-thread-local-callback", enqueue_command);
template_function_arity_1("pop-last-component!");
template_function_arity_1("hx.custom-insert-newline"); template_function_arity_1("hx.custom-insert-newline");
template_function_arity_1("push-component!"); template_function_arity_1("push-component!");
template_function_arity_1("enqueue-thread-local-callback"); template_function_arity_1("enqueue-thread-local-callback");
@ -2286,10 +2292,12 @@ fn push_component(cx: &mut Context, component: &mut WrappedDynComponent) {
cx.jobs.local_callback(callback); cx.jobs.local_callback(callback);
} }
fn render(cx: &mut Context) { fn pop_last_component_by_name(cx: &mut Context, name: SteelString) {
let callback = async move { let callback = async move {
let call: Box<dyn FnOnce(&mut Editor, &mut Compositor, &mut job::Jobs)> = Box::new( let call: Box<dyn FnOnce(&mut Editor, &mut Compositor, &mut job::Jobs)> = Box::new(
move |_editor: &mut Editor, _compositor: &mut Compositor, _jobs: &mut job::Jobs| {}, move |_editor: &mut Editor, compositor: &mut Compositor, _jobs: &mut job::Jobs| {
compositor.remove_by_dynamic_name(&name);
},
); );
Ok(call) Ok(call)
}; };

@ -13,6 +13,7 @@ pub type SyncCallback = Box<dyn FnOnce(&mut Compositor, &mut Context) + Sync>;
pub enum EventResult { pub enum EventResult {
Ignored(Option<Callback>), Ignored(Option<Callback>),
Consumed(Option<Callback>), Consumed(Option<Callback>),
ConsumedWithoutRerender,
} }
use crate::job::Jobs; use crate::job::Jobs;
@ -73,6 +74,10 @@ pub trait Component: Any + AnyComponent {
fn id(&self) -> Option<&'static str> { fn id(&self) -> Option<&'static str> {
None None
} }
fn name(&self) -> Option<&str> {
None
}
} }
pub struct Compositor { pub struct Compositor {
@ -136,6 +141,14 @@ impl Compositor {
Some(self.layers.remove(idx)) Some(self.layers.remove(idx))
} }
pub fn remove_by_dynamic_name(&mut self, id: &str) -> Option<Box<dyn Component>> {
let idx = self
.layers
.iter()
.position(|layer| layer.name() == Some(id))?;
Some(self.layers.remove(idx))
}
pub fn handle_event(&mut self, event: &Event, cx: &mut Context) -> bool { 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 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) { if let (Event::Key(key), Some((_, keys))) = (event, &mut cx.editor.macro_recording) {
@ -159,6 +172,10 @@ impl Compositor {
consumed = true; consumed = true;
break; break;
} }
// Swallow the event, but don't trigger a re-render
EventResult::ConsumedWithoutRerender => {
break;
}
EventResult::Ignored(Some(callback)) => { EventResult::Ignored(Some(callback)) => {
callbacks.push(callback); callbacks.push(callback);
} }

Loading…
Cancel
Save