use sim_kernel::Expr;
use sim_lib_intent::{Origin, intent, validate_intent};
use sim_lib_view::palette::{Command, filter_commands, palette_intent};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum KeyInput {
Enter,
Up,
Down,
Left,
Right,
Char(char),
Backspace,
Colon(String),
Escape,
}
pub fn intent_from_key(
key: &KeyInput,
pane: &str,
target: &str,
field: &str,
tick: u64,
) -> Option<Expr> {
let origin = Origin::human(tick);
let target_ref = Expr::String(target.to_owned());
let built = match key {
KeyInput::Enter => intent(
"invoke",
origin,
vec![
("target", target_ref),
("op", sym("activate")),
("args", Expr::List(Vec::new())),
],
),
KeyInput::Up | KeyInput::Down => {
let dir = if matches!(key, KeyInput::Up) {
"up"
} else {
"down"
};
intent(
"select",
origin,
vec![("targets", Expr::List(vec![target_ref])), ("dir", sym(dir))],
)
}
KeyInput::Left | KeyInput::Right => {
let dir = if matches!(key, KeyInput::Left) {
"left"
} else {
"right"
};
intent("move", origin, vec![("node", target_ref), ("at", sym(dir))])
}
KeyInput::Char(typed) => {
if field.is_empty() {
return None;
}
intent(
"edit-field",
origin,
vec![
("target", target_ref),
("path", field_path(field)),
("value", Expr::String(typed.to_string())),
],
)
}
KeyInput::Colon(command) => intent(
"invoke",
origin,
vec![
("target", target_ref),
("op", sym("command")),
("args", Expr::List(vec![Expr::String(command.clone())])),
],
),
KeyInput::Escape => intent(
"cancel",
origin,
vec![("pane", Expr::String(pane.to_owned()))],
),
KeyInput::Backspace => return None,
};
validate_intent(&built).ok().map(|()| built)
}
fn sym(name: &str) -> Expr {
sim_value::build::sym(name)
}
fn field_path(field: &str) -> Expr {
sim_value::path::Path::new()
.key(Expr::String(field.to_owned()))
.to_expr()
}
pub fn palette_intent_from_colon(
commands: &[Command],
command_line: &str,
pane: &str,
tick: u64,
) -> Option<Expr> {
let command = filter_commands(commands, command_line).into_iter().next()?;
palette_intent(command, pane, tick).ok()
}