instrument proper components module, start documentation

pull/8675/merge^2
Matt Paras 2025-05-17 11:37:23 -07:00
parent 3f062fa3d0
commit 848f2e2e89
4 changed files with 740 additions and 372 deletions

67
Cargo.lock generated
View File

@ -205,6 +205,15 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "1.12.0" version = "1.12.0"
@ -509,6 +518,16 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]] [[package]]
name = "dashmap" name = "dashmap"
version = "6.1.0" version = "6.1.0"
@ -523,6 +542,16 @@ dependencies = [
"parking_lot_core", "parking_lot_core",
] ]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]] [[package]]
name = "displaydoc" name = "displaydoc"
version = "0.2.5" version = "0.2.5"
@ -747,6 +776,16 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.16" version = "0.2.16"
@ -1532,6 +1571,12 @@ dependencies = [
"gix-validate 0.9.4", "gix-validate 0.9.4",
] ]
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]] [[package]]
name = "globset" name = "globset"
version = "0.4.16" version = "0.4.16"
@ -2354,6 +2399,16 @@ dependencies = [
"syn 2.0.101", "syn 2.0.101",
] ]
[[package]]
name = "md-5"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
dependencies = [
"cfg-if",
"digest",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.4" version = "2.7.4"
@ -3082,7 +3137,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#77f8c352f3a140821c078900e1cf3ce4d64cc8c9" source = "git+https://github.com/mattwparas/steel.git#54c703795bf0e960674dce5091ed377fa4e3e1cb"
dependencies = [ dependencies = [
"abi_stable", "abi_stable",
"anyhow", "anyhow",
@ -3101,12 +3156,14 @@ dependencies = [
"futures-util", "futures-util",
"fxhash", "fxhash",
"getrandom 0.3.2", "getrandom 0.3.2",
"glob",
"httparse", "httparse",
"im", "im",
"im-lists", "im-lists",
"im-rc", "im-rc",
"lasso", "lasso",
"log", "log",
"md-5",
"num-bigint", "num-bigint",
"num-integer", "num-integer",
"num-rational", "num-rational",
@ -3132,7 +3189,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#77f8c352f3a140821c078900e1cf3ce4d64cc8c9" source = "git+https://github.com/mattwparas/steel.git#54c703795bf0e960674dce5091ed377fa4e3e1cb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3142,7 +3199,7 @@ dependencies = [
[[package]] [[package]]
name = "steel-doc" name = "steel-doc"
version = "0.6.0" version = "0.6.0"
source = "git+https://github.com/mattwparas/steel.git#77f8c352f3a140821c078900e1cf3ce4d64cc8c9" source = "git+https://github.com/mattwparas/steel.git#54c703795bf0e960674dce5091ed377fa4e3e1cb"
dependencies = [ dependencies = [
"steel-core", "steel-core",
] ]
@ -3150,7 +3207,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#77f8c352f3a140821c078900e1cf3ce4d64cc8c9" source = "git+https://github.com/mattwparas/steel.git#54c703795bf0e960674dce5091ed377fa4e3e1cb"
dependencies = [ dependencies = [
"codegen", "codegen",
"serde", "serde",
@ -3159,7 +3216,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#77f8c352f3a140821c078900e1cf3ce4d64cc8c9" source = "git+https://github.com/mattwparas/steel.git#54c703795bf0e960674dce5091ed377fa4e3e1cb"
dependencies = [ dependencies = [
"compact_str", "compact_str",
"fxhash", "fxhash",

View File

@ -9,7 +9,10 @@ use helix_view::{
Editor, Editor,
}; };
use steel::{ use steel::{
rvals::{as_underlying_type, Custom, FromSteelVal, IntoSteelVal, SteelString}, rvals::{
as_underlying_type, AsRefSteelVal, AsRefSteelValFromRef, Custom, FromSteelVal,
IntoSteelVal, SteelString,
},
steel_vm::{builtin::BuiltInModule, engine::Engine, register_fn::RegisterFn}, steel_vm::{builtin::BuiltInModule, engine::Engine, register_fn::RegisterFn},
SteelVal, SteelVal,
}; };
@ -26,7 +29,9 @@ use crate::{
ui::overlay::overlaid, ui::overlay::overlaid,
}; };
use super::steel::{enter_engine, present_error_inside_engine_context, WrappedDynComponent}; use super::steel::{
enter_engine, format_docstring, present_error_inside_engine_context, WrappedDynComponent,
};
#[derive(Clone)] #[derive(Clone)]
struct AsyncReader { struct AsyncReader {
@ -99,14 +104,100 @@ impl std::io::Write for AsyncWriter {
} }
} }
// TODO: Move the main configuration function to use this instead pub fn helix_component_module(generate_sources: bool) -> BuiltInModule {
pub fn helix_component_module() -> BuiltInModule {
let mut module = BuiltInModule::new("helix/components"); let mut module = BuiltInModule::new("helix/components");
module let mut builtin_components_module = if generate_sources {
.register_fn("async-read-line", AsyncReader::read_line) "(require-builtin helix/components as helix.components.)".to_string()
// TODO: } else {
.register_fn("make-async-reader-writer", || { String::new()
};
macro_rules! register {
(value, $name:expr, $function:expr, $doc:expr) => {
module.register_value($name, $function);
{
let doc = format_docstring($doc);
builtin_components_module.push_str(&format!(
r#"
(provide {})
;;@doc
{}
(define {} helix.components.{})
"#,
$name, doc, $name, $name
));
}
};
(value, $name:expr, $function:expr) => {
module.register_value($name, $function);
{
builtin_components_module.push_str(&format!(
r#"
(provide {})
(define {} helix.components.{})
"#,
$name, $name, $name
));
}
};
($name:expr, $function:expr, $doc:expr) => {
module.register_fn($name, $function);
{
let doc = format_docstring($doc);
builtin_components_module.push_str(&format!(
r#"
(provide {})
;;@doc
{}
(define {} helix.components.{})
"#,
$name, doc, $name, $name
));
}
};
($name:expr, $function:expr) => {
module.register_fn($name, $function);
{
builtin_components_module.push_str(&format!(
r#"
(provide {})
(define {} helix.components.{})
"#,
$name, $name, $name
));
}
};
(ctx, $name:expr, $function:expr, $arity:expr, $doc:expr) => {
module.register_fn($name, $function);
let mut function_expr = Vec::with_capacity($arity);
for arg in 0..$arity {
function_expr.push(format!("arg{}", arg));
}
let formatted = function_expr.join(" ");
{
let doc = format_docstring($doc);
builtin_components_module.push_str(&format!(
r#"
(provide {})
;;@doc
{}
(define ({} {}) (helix.components.{} {}))
"#,
$name, doc, $name, &formatted, $name, &formatted
));
}
};
}
register!("async-read-line", AsyncReader::read_line);
register!("make-async-reader-writer", || {
let (sender, receiver) = tokio::sync::mpsc::unbounded_channel(); let (sender, receiver) = tokio::sync::mpsc::unbounded_channel();
let writer = AsyncWriter { channel: sender }; let writer = AsyncWriter { channel: sender };
@ -118,47 +209,195 @@ pub fn helix_component_module() -> BuiltInModule {
SteelVal::new_dyn_writer_port(writer), SteelVal::new_dyn_writer_port(writer),
reader.into_steelval().unwrap(), reader.into_steelval().unwrap(),
] ]
}) });
// Attempt to pop off a specific component register!(
.register_fn( "theme->bg",
"pop-dynamic-component-by-name", |ctx: &mut Context| { ctx.editor.theme.get("ui.background") },
|ctx: &mut Context, name: SteelString| { "Gets the `Style` associated with the bg for the current theme"
// Removing a component by name here will be important! );
todo!() register!(
"theme->fg",
|ctx: &mut Context| { ctx.editor.theme.get("ui.text") },
"Gets the `style` associated with the fg for the current theme"
);
register!(
ctx,
"theme-scope",
|ctx: &mut Context, scope: SteelString| {
ctx.editor.theme.get(scope.as_str());
}, },
) 1,
.register_fn("theme->bg", |ctx: &mut Context| { "Get the `Style` associated with the given scope from the current theme"
ctx.editor.theme.get("ui.background") );
})
.register_fn("theme->fg", |ctx: &mut Context| { register!(
ctx.editor.theme.get("ui.text") "Position?",
}) |position: SteelVal| { Position::as_ref(&position).is_ok() },
.register_fn("buffer-area", |buffer: &mut Buffer| buffer.area) r#"Check if the given value is a `Position`
.register_fn("frame-set-string!", buffer_set_string)
.register_fn("new-component!", SteelDynamicComponent::new_dyn) (Position? value) -> bool?
.register_fn("position", Position::new)
.register_fn("position-row", |position: &Position| position.row) value : any?
.register_fn("position-col", |position: &Position| position.col)
.register_fn( "#
);
register!(
"Style?",
|style: SteelVal| Style::as_ref(&style).is_ok(),
r#"Check if the given valuie is `Style`
(Style? value) -> bool?
value : any?
"#
);
register!(
"Buffer?",
|value: SteelVal| { Buffer::as_ref_from_ref(&value).is_ok() },
r#"
Checks if the given value is a `Buffer`
(Buffer? value) -> bool?
value : any?
"#
);
register!(
"buffer-area",
|buffer: &mut Buffer| buffer.area,
r#"
Get the `Rect` associated with the given `Buffer`
(buffer-area buffer)
* buffer : Buffer?
"#
);
register!(
"frame-set-string!",
buffer_set_string,
r#"
Set the string at the given `x` and `y` positions for the given `Buffer`, with a provided `Style`.
(frame-set-string! buffer x y string style)
buffer : Buffer?,
x : int?,
y : int?,
string: string?,
style: Style?,
"#
);
register!("new-component!", SteelDynamicComponent::new_dyn);
register!(
"position",
Position::new,
r#"
Construct a new `Position`.
(position row col) -> Position?
row : int?
col : int?
"#
);
register!(
"position-row",
|position: &Position| position.row,
r#"
Get the row associated with the given `Position`.
(position-row pos) -> int?
pos : `Position?`
"#
);
register!(
"position-col",
|position: &Position| position.col,
r#"
Get the col associated with the given `Position`.
(position-col pos) -> int?
pos : `Position?`
"#
);
register!(
"set-position-row!", "set-position-row!",
|position: &mut Position, row: usize| { |position: &mut Position, row: usize| {
position.row = row; position.row = row;
}, },
) r#"Set the row for the given `Position`
.register_fn( (set-position-row! pos row)
pos : Position?
row : int?
"#
);
register!(
"set-position-col!", "set-position-col!",
|position: &mut Position, col: usize| { |position: &mut Position, col: usize| {
position.col = col; position.col = col;
}, },
) r#"Set the col for the given `Position`
.register_fn("area", helix_view::graphics::Rect::new)
.register_fn("area-x", |area: &helix_view::graphics::Rect| area.x) (set-position-col! pos col)
.register_fn("area-y", |area: &helix_view::graphics::Rect| area.y)
.register_fn("area-width", |area: &helix_view::graphics::Rect| area.width) pos : Position?
.register_fn("area-height", |area: &helix_view::graphics::Rect| { col : int?
area.height "#
}) );
.register_fn("overlaid", |component: &mut WrappedDynComponent| {
register!(
"area",
helix_view::graphics::Rect::new,
r#"
Constructs a new `Rect`.
(area x y width height)
* x : int?
* y : int?
* width: int?
* height: int?
# Examples
```scheme
(area 0 0 100 200)
```
"#
);
register!(
"area-x",
|area: &helix_view::graphics::Rect| area.x,
"Get the `x` value of the given `Rect`"
);
register!(
"area-y",
|area: &helix_view::graphics::Rect| area.y,
"Get the `y` value of the given `Rect`"
);
register!(
"area-width",
|area: &helix_view::graphics::Rect| area.width,
"Get the `width` value of the given `Rect`"
);
register!(
"area-height",
|area: &helix_view::graphics::Rect| { area.height },
"Get the `height` value of the given `Rect`"
);
register!("overlaid", |component: &mut WrappedDynComponent| {
let inner: Option<Box<dyn Component + Send + Sync + 'static>> = let inner: Option<Box<dyn Component + Send + Sync + 'static>> =
component.inner.take().map(|x| { component.inner.take().map(|x| {
Box::new(overlaid(BoxDynComponent::new(x))) Box::new(overlaid(BoxDynComponent::new(x)))
@ -166,29 +405,29 @@ pub fn helix_component_module() -> BuiltInModule {
}); });
component.inner = inner; component.inner = inner;
}) });
.register_fn("widget/list", |items: Vec<String>| { register!("widget/list", |items: Vec<String>| {
widgets::List::new( widgets::List::new(
items items
.into_iter() .into_iter()
.map(|x| ListItem::new(Text::from(x))) .map(|x| ListItem::new(Text::from(x)))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
) )
}) });
// Pass references in as well?
.register_fn( register!(
"widget/list/render", "widget/list/render",
|buf: &mut Buffer, area: Rect, list: widgets::List| list.render(area, buf), |buf: &mut Buffer, area: Rect, list: widgets::List| list.render(area, buf)
) );
.register_fn("block", || { register!("block", || {
Block::default() Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
.border_style(Style::default().fg(Color::White)) .border_style(Style::default().fg(Color::White))
.border_type(BorderType::Rounded) .border_type(BorderType::Rounded)
.style(Style::default().bg(Color::Black)) .style(Style::default().bg(Color::Black))
}) });
// TODO: Expose these accordingly
.register_fn( register!(
"make-block", "make-block",
|style: Style, border_style: Style, borders: SteelString, border_type: SteelString| { |style: Style, border_style: Style, borders: SteelString, border_type: SteelString| {
let border_type = match border_type.as_str() { let border_type = match border_type.as_str() {
@ -214,179 +453,273 @@ pub fn helix_component_module() -> BuiltInModule {
.border_type(border_type) .border_type(border_type)
.style(style) .style(style)
}, },
) r#"
.register_fn( Create a `Block` with the provided styling, borders, and border type.
(make-block style border-style borders border_type)
* style : Style?
* border-style : Style?
* borders : string?
* border-type: String?
Valid border-types include:
* "plain"
* "rounded"
* "double"
* "thick"
Valid borders include:
* "top"
* "left"
* "right"
* "bottom"
* "all"
"#
);
register!(
"block/render", "block/render",
|buf: &mut Buffer, area: Rect, block: Block| block.render(area, buf), |buf: &mut Buffer, area: Rect, block: Block| block.render(area, buf)
) );
.register_fn("buffer/clear", Buffer::clear) register!(
.register_fn("buffer/clear-with", Buffer::clear_with) "buffer/clear",
Buffer::clear,
"Clear a `Rect` in the `Buffer`"
);
register!(
"buffer/clear-with",
Buffer::clear_with,
"Clear a `Rect` in the `Buffer` with a default `Style`"
);
// Mutate a color in place, to save some headache. // Mutate a color in place, to save some headache.
.register_fn( register!("set-color-rgb!", |color: &mut Color,
"set-color-rgb!", r: u8,
|color: &mut Color, r: u8, g: u8, b: u8| { g: u8,
b: u8| {
*color = Color::Rgb(r, g, b); *color = Color::Rgb(r, g, b);
}, });
)
.register_fn("set-color-indexed!", |color: &mut Color, index: u8| { register!("set-color-indexed!", |color: &mut Color, index: u8| {
*color = Color::Indexed(index); *color = Color::Indexed(index);
}) });
.register_value("Color/Reset", Color::Reset.into_steelval().unwrap())
.register_value("Color/Black", Color::Black.into_steelval().unwrap()) register!(
.register_value("Color/Red", Color::Red.into_steelval().unwrap()) "Color?",
.register_value("Color/White", Color::White.into_steelval().unwrap()) |color: SteelVal| { Color::as_ref(&color).is_ok() },
.register_value("Color/Green", Color::Green.into_steelval().unwrap()) r#"Check if the given value is a `Color`.
.register_value("Color/Yellow", Color::Yellow.into_steelval().unwrap())
.register_value("Color/Blue", Color::Blue.into_steelval().unwrap()) (Color? value) -> bool?
.register_value("Color/Magenta", Color::Magenta.into_steelval().unwrap())
.register_value("Color/Cyan", Color::Cyan.into_steelval().unwrap()) value : any?
.register_value("Color/Gray", Color::Gray.into_steelval().unwrap())
.register_value("Color/LightRed", Color::LightRed.into_steelval().unwrap()) "#
.register_value( );
register!(value, "Color/Reset", Color::Reset.into_steelval().unwrap());
register!(value, "Color/Black", Color::Black.into_steelval().unwrap());
register!(value, "Color/Red", Color::Red.into_steelval().unwrap());
register!(value, "Color/White", Color::White.into_steelval().unwrap());
register!(value, "Color/Green", Color::Green.into_steelval().unwrap());
register!(
value,
"Color/Yellow",
Color::Yellow.into_steelval().unwrap()
);
register!(value, "Color/Blue", Color::Blue.into_steelval().unwrap());
register!(
value,
"Color/Magenta",
Color::Magenta.into_steelval().unwrap()
);
register!(value, "Color/Cyan", Color::Cyan.into_steelval().unwrap());
register!(value, "Color/Gray", Color::Gray.into_steelval().unwrap());
register!(
value,
"Color/LightRed",
Color::LightRed.into_steelval().unwrap()
);
register!(
value,
"Color/LightGreen", "Color/LightGreen",
Color::LightGreen.into_steelval().unwrap(), Color::LightGreen.into_steelval().unwrap()
) );
.register_value( register!(
value,
"Color/LightYellow", "Color/LightYellow",
Color::LightYellow.into_steelval().unwrap(), Color::LightYellow.into_steelval().unwrap()
) );
.register_value("Color/LightBlue", Color::LightBlue.into_steelval().unwrap()) register!(
.register_value( value,
"Color/LightBlue",
Color::LightBlue.into_steelval().unwrap()
);
register!(
value,
"Color/LightMagenta", "Color/LightMagenta",
Color::LightMagenta.into_steelval().unwrap(), Color::LightMagenta.into_steelval().unwrap()
) );
.register_value("Color/LightCyan", Color::LightCyan.into_steelval().unwrap()) register!(
.register_value("Color/LightGray", Color::LightGray.into_steelval().unwrap()) value,
.register_fn("Color/rgb", Color::Rgb) "Color/LightCyan",
.register_fn("Color-red", Color::red) Color::LightCyan.into_steelval().unwrap()
.register_fn("Color-green", Color::green) );
.register_fn("Color-blue", Color::blue) register!(
.register_fn("Color/Indexed", Color::Indexed) value,
.register_fn("set-style-fg!", |style: &mut Style, color: Color| { "Color/LightGray",
Color::LightGray.into_steelval().unwrap()
);
register!("Color/rgb", Color::Rgb);
register!("Color-red", Color::red);
register!("Color-green", Color::green);
register!("Color-blue", Color::blue);
register!("Color/Indexed", Color::Indexed);
register!("set-style-fg!", |style: &mut Style, color: Color| {
style.fg = Some(color); style.fg = Some(color);
}) });
.register_fn("style-fg", Style::fg) register!("style-fg", Style::fg);
.register_fn("style-bg", Style::bg) register!("style-bg", Style::bg);
.register_fn("style-with-italics", |style: &Style| { register!("style-with-italics", |style: &Style| {
let patch = Style::default().add_modifier(Modifier::ITALIC); let patch = Style::default().add_modifier(Modifier::ITALIC);
style.patch(patch) style.patch(patch)
}) });
.register_fn("style-with-bold", |style: Style| { register!("style-with-bold", |style: Style| {
let patch = Style::default().add_modifier(Modifier::BOLD); let patch = Style::default().add_modifier(Modifier::BOLD);
style.patch(patch) style.patch(patch)
}) });
.register_fn("style-with-dim", |style: &Style| { register!("style-with-dim", |style: &Style| {
let patch = Style::default().add_modifier(Modifier::DIM); let patch = Style::default().add_modifier(Modifier::DIM);
style.patch(patch) style.patch(patch)
}) });
.register_fn("style-with-slow-blink", |style: Style| { register!("style-with-slow-blink", |style: Style| {
let patch = Style::default().add_modifier(Modifier::SLOW_BLINK); let patch = Style::default().add_modifier(Modifier::SLOW_BLINK);
style.patch(patch) style.patch(patch)
}) });
.register_fn("style-with-rapid-blink", |style: Style| { register!("style-with-rapid-blink", |style: Style| {
let patch = Style::default().add_modifier(Modifier::RAPID_BLINK); let patch = Style::default().add_modifier(Modifier::RAPID_BLINK);
style.patch(patch) style.patch(patch)
}) });
.register_fn("style-with-reversed", |style: Style| { register!("style-with-reversed", |style: Style| {
let patch = Style::default().add_modifier(Modifier::REVERSED); let patch = Style::default().add_modifier(Modifier::REVERSED);
style.patch(patch) style.patch(patch)
}) });
.register_fn("style-with-hidden", |style: Style| { register!("style-with-hidden", |style: Style| {
let patch = Style::default().add_modifier(Modifier::HIDDEN); let patch = Style::default().add_modifier(Modifier::HIDDEN);
style.patch(patch) style.patch(patch)
}) });
.register_fn("style-with-crossed-out", |style: Style| { register!("style-with-crossed-out", |style: Style| {
let patch = Style::default().add_modifier(Modifier::CROSSED_OUT); let patch = Style::default().add_modifier(Modifier::CROSSED_OUT);
style.patch(patch) style.patch(patch)
}) });
.register_fn("style->fg", |style: &Style| style.fg) register!("style->fg", |style: &Style| style.fg);
.register_fn("style->bg", |style: &Style| style.bg) register!("style->bg", |style: &Style| style.bg);
.register_fn("set-style-bg!", |style: &mut Style, color: Color| { register!("set-style-bg!", |style: &mut Style, color: Color| {
style.bg = Some(color); style.bg = Some(color);
}) });
.register_fn("style-underline-color", Style::underline_color) register!("style-underline-color", Style::underline_color);
.register_fn("style-underline-style", Style::underline_style) register!("style-underline-style", Style::underline_style);
.register_value(
register!(
value,
"Underline/Reset", "Underline/Reset",
UnderlineStyle::Reset.into_steelval().unwrap(), UnderlineStyle::Reset.into_steelval().unwrap()
) );
.register_value( register!(
value,
"Underline/Line", "Underline/Line",
UnderlineStyle::Line.into_steelval().unwrap(), UnderlineStyle::Line.into_steelval().unwrap()
) );
.register_value( register!(
value,
"Underline/Curl", "Underline/Curl",
UnderlineStyle::Curl.into_steelval().unwrap(), UnderlineStyle::Curl.into_steelval().unwrap()
) );
.register_value( register!(
value,
"Underline/Dotted", "Underline/Dotted",
UnderlineStyle::Dotted.into_steelval().unwrap(), UnderlineStyle::Dotted.into_steelval().unwrap()
) );
.register_value( register!(
value,
"Underline/Dashed", "Underline/Dashed",
UnderlineStyle::Dashed.into_steelval().unwrap(), UnderlineStyle::Dashed.into_steelval().unwrap()
) );
.register_value( register!(
value,
"Underline/DoubleLine", "Underline/DoubleLine",
UnderlineStyle::DoubleLine.into_steelval().unwrap(), UnderlineStyle::DoubleLine.into_steelval().unwrap()
) );
.register_fn("style", || Style::default()) register!(
.register_value( value,
"event-result/consume", "event-result/consume",
SteelEventResult::Consumed.into_steelval().unwrap(), SteelEventResult::Consumed.into_steelval().unwrap()
) );
.register_value( register!(
value,
"event-result/consume-without-rerender", "event-result/consume-without-rerender",
SteelEventResult::ConsumedWithoutRerender SteelEventResult::ConsumedWithoutRerender
.into_steelval() .into_steelval()
.unwrap(), .unwrap()
) );
.register_value( register!(
value,
"event-result/ignore", "event-result/ignore",
SteelEventResult::Ignored.into_steelval().unwrap(), SteelEventResult::Ignored.into_steelval().unwrap()
) );
.register_value( register!(
value,
"event-result/close", "event-result/close",
SteelEventResult::Close.into_steelval().unwrap(), SteelEventResult::Close.into_steelval().unwrap()
) );
// TODO: Use a reference here instead of passing by value. register!("style", || Style::default());
.register_fn("key-event-char", |event: Event| {
register!("key-event-char", |event: Event| {
if let Event::Key(event) = event { if let Event::Key(event) = event {
event.char() event.char()
} else { } else {
None None
} }
}) });
.register_fn("key-event-modifier", |event: Event| { register!("key-event-modifier", |event: Event| {
if let Event::Key(KeyEvent { modifiers, .. }) = event { if let Event::Key(KeyEvent { modifiers, .. }) = event {
Some(modifiers.bits()) Some(modifiers.bits())
} else { } else {
None None
} }
}) });
.register_value(
register!(
value,
"key-modifier-ctrl", "key-modifier-ctrl",
SteelVal::IntV(KeyModifiers::CONTROL.bits() as isize), SteelVal::IntV(KeyModifiers::CONTROL.bits() as isize)
) );
.register_value( register!(
value,
"key-modifier-shift", "key-modifier-shift",
SteelVal::IntV(KeyModifiers::SHIFT.bits() as isize), SteelVal::IntV(KeyModifiers::SHIFT.bits() as isize)
) );
.register_value( register!(
value,
"key-modifier-alt", "key-modifier-alt",
SteelVal::IntV(KeyModifiers::ALT.bits() as isize), SteelVal::IntV(KeyModifiers::ALT.bits() as isize)
) );
.register_fn("key-event-F?", |event: Event, number: u8| match event {
register!("key-event-F?", |event: Event, number: u8| match event {
Event::Key(KeyEvent { Event::Key(KeyEvent {
code: KeyCode::F(x), code: KeyCode::F(x),
.. ..
}) if number == x => true, }) if number == x => true,
_ => false, _ => false,
}) });
.register_fn("mouse-event?", |event: Event| { register!("mouse-event?", |event: Event| {
matches!(event, Event::Mouse(_)) matches!(event, Event::Mouse(_))
}) });
.register_fn("event-mouse-kind", |event: Event| { register!("event-mouse-kind", |event: Event| {
if let Event::Mouse(MouseEvent { kind, .. }) = event { if let Event::Mouse(MouseEvent { kind, .. }) = event {
match kind { match kind {
helix_view::input::MouseEventKind::Down(MouseButton::Left) => 0, helix_view::input::MouseEventKind::Down(MouseButton::Left) => 0,
@ -408,23 +741,23 @@ pub fn helix_component_module() -> BuiltInModule {
} else { } else {
false.into_steelval() false.into_steelval()
} }
}) });
.register_fn("event-mouse-row", |event: Event| { register!("event-mouse-row", |event: Event| {
if let Event::Mouse(MouseEvent { row, .. }) = event { if let Event::Mouse(MouseEvent { row, .. }) = event {
row.into_steelval() row.into_steelval()
} else { } else {
false.into_steelval() false.into_steelval()
} }
}) });
.register_fn("event-mouse-col", |event: Event| { register!("event-mouse-col", |event: Event| {
if let Event::Mouse(MouseEvent { column, .. }) = event { if let Event::Mouse(MouseEvent { column, .. }) = event {
column.into_steelval() column.into_steelval()
} else { } else {
false.into_steelval() false.into_steelval()
} }
}) });
// Is this mouse event within the area provided // Is this mouse event within the area provided
.register_fn("mouse-event-within-area?", |event: Event, area: Rect| { register!("mouse-event-within-area?", |event: Event, area: Rect| {
if let Event::Mouse(MouseEvent { row, column, .. }) = event { if let Event::Mouse(MouseEvent { row, column, .. }) = event {
column > area.x column > area.x
&& column < area.x + area.width && column < area.x + area.width
@ -438,7 +771,7 @@ pub fn helix_component_module() -> BuiltInModule {
macro_rules! register_key_events { macro_rules! register_key_events {
($ ( $name:expr => $key:tt ) , *, ) => { ($ ( $name:expr => $key:tt ) , *, ) => {
$( $(
module.register_fn(concat!("key-event-", $name, "?"), |event: Event| { register!(concat!("key-event-", $name, "?"), |event: Event| {
matches!( matches!(
event, event,
Event::Key( Event::Key(
@ -477,18 +810,20 @@ pub fn helix_component_module() -> BuiltInModule {
"keypad-begin" => KeypadBegin, "keypad-begin" => KeypadBegin,
); );
module if generate_sources {
if let Some(mut target_directory) =
crate::commands::engine::steel::alternative_runtime_search_path()
{
if !target_directory.exists() {
std::fs::create_dir_all(&target_directory).unwrap();
}
target_directory.push("components.scm");
std::fs::write(target_directory, &builtin_components_module).unwrap();
}
} }
// fn buffer_set_string( module
// buffer: &mut tui::buffer::Buffer, }
// x: u16,
// y: u16,
// string: steel::rvals::SteelString,
// style: Style,
// ) {
// buffer.set_string(x, y, string.as_str(), style)
// }
fn buffer_set_string( fn buffer_set_string(
buffer: &mut tui::buffer::Buffer, buffer: &mut tui::buffer::Buffer,
@ -531,7 +866,7 @@ pub struct SteelDynamicComponent {
// passed to the functions in the remainder of the struct. // passed to the functions in the remainder of the struct.
state: SteelVal, state: SteelVal,
handle_event: Option<SteelVal>, handle_event: Option<SteelVal>,
should_update: Option<SteelVal>, _should_update: Option<SteelVal>,
render: SteelVal, render: SteelVal,
cursor: Option<SteelVal>, cursor: Option<SteelVal>,
required_size: Option<SteelVal>, required_size: Option<SteelVal>,
@ -554,7 +889,7 @@ impl SteelDynamicComponent {
state, state,
render, render,
handle_event: h.get("handle_event").cloned(), handle_event: h.get("handle_event").cloned(),
should_update: h.get("should_update").cloned(), _should_update: h.get("should_update").cloned(),
cursor: h.get("cursor").cloned(), cursor: h.get("cursor").cloned(),
required_size: h.get("required_size").cloned(), required_size: h.get("required_size").cloned(),
key_event: None, key_event: None,
@ -574,30 +909,6 @@ impl SteelDynamicComponent {
inner: Some(Box::new(s)), inner: Some(Box::new(s)),
} }
} }
pub fn get_state(&self) -> SteelVal {
self.state.clone()
}
pub fn get_render(&self) -> SteelVal {
self.render.clone()
}
pub fn get_handle_event(&self) -> Option<SteelVal> {
self.handle_event.clone()
}
pub fn get_should_update(&self) -> Option<SteelVal> {
self.should_update.clone()
}
pub fn get_cursor(&self) -> Option<SteelVal> {
self.cursor.clone()
}
pub fn get_required_size(&self) -> Option<SteelVal> {
self.required_size.clone()
}
} }
impl Custom for SteelDynamicComponent {} impl Custom for SteelDynamicComponent {}

View File

@ -199,7 +199,7 @@ pub static REVERSE_BUFFER_MAP: Lazy<SteelVal> =
Lazy::new(|| SteelVal::boxed(SteelVal::empty_hashmap())); Lazy::new(|| SteelVal::boxed(SteelVal::empty_hashmap()));
fn load_component_api(engine: &mut Engine, generate_sources: bool) { fn load_component_api(engine: &mut Engine, generate_sources: bool) {
let module = helix_component_module(); let module = helix_component_module(generate_sources);
if generate_sources { if generate_sources {
configure_lsp_builtins("component", &module); configure_lsp_builtins("component", &module);
@ -234,7 +234,7 @@ fn load_keymap_api(engine: &mut Engine, api: KeyMapApi, generate_sources: bool)
engine.register_module(module); engine.register_module(module);
} }
fn format_docstring(doc: &str) -> String { pub fn format_docstring(doc: &str) -> String {
let mut docstring = doc let mut docstring = doc
.lines() .lines()
.map(|x| { .map(|x| {

2
steel

@ -1 +1 @@
Subproject commit 77f8c352f3a140821c078900e1cf3ce4d64cc8c9 Subproject commit 54c703795bf0e960674dce5091ed377fa4e3e1cb