rehash eval_xy and implement a few more modifiers
Some checks failed
/ build (push) Has been cancelled

This commit is contained in:
facile pop culture reference 2026-07-15 19:56:50 +03:00
parent aa0dd37d88
commit e398541b7e
2 changed files with 139 additions and 89 deletions

View file

@ -1,52 +1,6 @@
use crate::{*, lang::*};
use ratatui::style::Color;
/// Some layout operations exist in XY, X, and Y variants that take 3 or 2 arguments.
/// Their handling in [eval_view] is uniform and goes like this:
macro_rules! eval_xy ((
$name:expr, $expr:expr, $head:expr, $output:ident, $state:ident,
$variant:expr, $arg0: ident, $arg1: ident, $arg2: ident,
$xy:ident, $x:ident, $y:ident
) => {{
let variant = $variant;
let cb = thunk(move|output: &mut O|$state.interpret(output, &match variant {
Some("x") | Some("y") => $arg1,
Some("xy") | None => $arg2,
_ => panic!("{}: unsupported axis {variant:?}; try /x, /y, /xy", $name)
}));
match variant {
// XY variant (can be omitted)
Some("xy") | None => cb.push_xy(
$state.namespace($arg0?)?,
$state.namespace($arg1?)?,
).draw($output),
// X variant
Some("x") => cb.push_x(
$state.namespace($arg0?)?,
).draw($output),
// Y variant
Some("y") => cb.push_y(
$state.namespace($arg0?)?,
).draw($output),
// Other namespace members are invalid
frag => {
let name = $name;
let expr = $expr;
let head = $head;
unimplemented!(
"{name}/{frag:?} ({expr:?}) ({head:?}) ({:?})",
head.src()?.unwrap_or_default().split("/").next()
)
}
}
}});
/// Some layout operations exist in multiple variants that take a single argument.
/// Their handling in [eval_view] is uniform and goes like this:
macro_rules! eval_enum ((
@ -60,6 +14,75 @@ macro_rules! eval_enum ((
}
}});
/// Some layout operations exist in XY, X, and Y variants that take 3 or 2 arguments.
/// Their handling in [eval_view] is uniform and goes like this:
macro_rules! eval_xy (
// Valueless variant:
// (fill/x ...)
// (fill/y ...)
// (fill/xy ...)
(
$name:expr => $expr:expr, $head:expr, $output:ident, $state:ident,
$variant:expr, $xy:ident, $x:ident, $y:ident, $arg: ident,
) => {{
// frags.next(): 2nd slash-delimited fragment: /x, /y, /xy
let variant = $variant;
let thunk = thunk(move|screen|$state.interpret(screen, &$arg));
match variant {
// X variant
Some("x") => thunk.$x().draw($output),
// Y variant
Some("y") => thunk.$y().draw($output),
// XY variant (can be omitted)
Some("xy") | None => thunk.$xy().draw($output),
// Other namespace members are invalid
frag => invalid_variant($name, frag, $expr, $head)
}
}};
// Variadic variant:
// (push/x n ...)
// (push/y n ...)
// (push/xy n m ...)
(
$name:expr => $expr:expr, $head:expr, $output:ident, $state:ident,
$variant:expr, $xy:ident, $x:ident, $y:ident, $arg0: ident, $arg1: ident, $arg2: ident,
) => {{
// frags.next(): 2nd slash-delimited fragment: /x, /y, /xy
let variant = $variant;
let thunk = thunk(move|screen|$state.interpret(screen, &match variant {
Some("x") | Some("y") => $arg1,
Some("xy") | None => $arg2,
_ => panic!("{}: unsupported axis {variant:?}; try /x, /y, /xy", $name)
}));
match variant {
// X variant
Some("x") => thunk.$x($state.namespace($arg0?)?)
.draw($output),
// Y variant
Some("y") => thunk.$y($state.namespace($arg0?)?)
.draw($output),
// XY variant (can be omitted)
Some("xy") | None => thunk.$xy($state.namespace($arg0?)?, $state.namespace($arg1?)?)
.draw($output),
// Other namespace members are invalid
frag => invalid_variant($name, frag, $expr, $head)
}
}};
);
fn invalid_variant <T> (
name: &str,
frag: impl Language,
expr: impl Language,
head: impl Language,
) -> Usually<T> {
unimplemented!(
"{name}/{frag:?} ({expr:?}) ({head:?}) ({:?})",
head.src()?.unwrap_or_default().split("/").next()
)
}
/// Interpret layout operation.
///
/// ```
@ -103,67 +126,46 @@ pub fn eval_view <'a, O: Screen + 'a, S> (
let arg1 = tail0.head();
let tail1 = tail0.tail();
let arg2 = tail1.head();
// First `frags.next()` calls returns the namespace.
match frags.next() {
Some("when") => when(
state.namespace(arg0?)?.unwrap(),
thunk(move|output: &mut O|{state.interpret(output, &arg1)})
).draw(output),
Some("either") => either(
state.namespace(arg0?)?.unwrap(),
thunk(move|output: &mut O|{state.interpret(output, &arg1)}),
thunk(move|output: &mut O|{state.interpret(output, &arg2)}),
).draw(output),
// Second `frags.next()` calls returns the namespace member.
Some("bsp") => eval_enum!("bsp", output, state, frags.next(), arg0, Split {
"n" => North,
"s" => South,
"e" => East,
"w" => West,
"a" => Above,
"b" => Below
"n" => North, "s" => South, "e" => East, "w" => West, "a" => Above, "b" => Below
}).half(
thunk(move|output: &mut O|{state.interpret(output, &arg0)}),
thunk(move|output: &mut O|{state.interpret(output, &arg1)}),
).draw(output),
Some("align") => {
let content = thunk(move|output: &mut O|{state.interpret(output, &arg0)});
content.align(eval_enum!("align", output, state, frags.next(), arg0, Azimuth {
"c" => C,
"n" => N,
"s" => S,
"e" => E,
"w" => W,
"x" => X,
"y" => Y
})).draw(output)
},
Some("align") => thunk(move|output: &mut O|{
state.interpret(output, &arg0)
}).align(eval_enum!("align", output, state, frags.next(), arg0, Azimuth {
"c" => C, "n" => N, "s" => S, "e" => E, "w" => W, "x" => X, "y" => Y
})).draw(output),
Some("exact") => eval_xy!(
"exact", expr, head, output, state, frags.next(),
arg0, arg1, arg2, wh_exact, w_exact, h_exact
"exact" => expr, head, output, state, frags.next(), exact_wh, exact_w, exact_h, arg0, arg1, arg2,
),
Some("fixed") => eval_xy!(
"fixed" => expr, head, output, state, frags.next(), exact_wh, exact_w, exact_h, arg0, arg1, arg2,
),
Some("min") => eval_xy!(
"min", expr, head, output, state, frags.next(),
arg0, arg1, arg2, wh_min, w_min, h_min
"min" => expr, head, output, state, frags.next(), min_wh, min_w, min_h, arg0, arg1, arg2,
),
Some("max") => eval_xy!(
"max", expr, head, output, state, frags.next(),
arg0, arg1, arg2, wh_max, w_max, h_max
"max" => expr, head, output, state, frags.next(), max_wh, max_w, max_h, arg0, arg1, arg2,
),
Some("push") => eval_xy!(
"push", expr, head, output, state, frags.next(),
arg0, arg1, arg2, xy_push, x_push, y_push
"push" => expr, head, output, state, frags.next(), push_xy, push_x, push_y, arg0, arg1, arg2,
),
Some("fill") => eval_xy!(
"fill" => expr, head, output, state, frags.next(), full_wh, full_w, full_h, arg0,
),
_ => return Ok(None)
}