use crate::AppModel;
use crate::actions::DraftKey;
use crate::boundary::{Action, Gesture, help, line, reply::Reply, reply::encode};
use crate::cli_outbound::Cli;
use std::path::PathBuf;
use super::ShellState;
const RUN_HINT: &str = "Run this slash command — the same gesture the buttons and keys fire, typed \
instead of clicked. Its answer, or the reason it was refused, appears below. \
Enter runs it without leaving the box.";
pub(super) fn run(
model: &mut AppModel,
state: &mut ShellState,
lernie: &Cli,
bl: &Cli,
key: &DraftKey,
typed: &str,
) -> bool {
let ctx = line::Context {
prepared: state.start.pending.clone(),
..model.line_context()
};
match line::parse(typed, &ctx) {
Err(reason) => {
state.slash = Some(reason);
false
}
Ok(Gesture::Ask(query)) => {
let deps = model.boundary_deps(lernie, bl);
let answer = model.answer(&deps, &query, super::now_unix());
note(state, answer)
}
Ok(Gesture::Act(action)) => {
act(model, state, key, &seeded(state, action));
false
}
}
}
fn seeded(state: &ShellState, action: Action) -> Action {
match action {
Action::Prompt { prepared, goal, .. } => Action::Prompt {
prepared,
goal,
seed: Some(state.start.mint_seed),
},
other => other,
}
}
fn act(model: &mut AppModel, state: &mut ShellState, key: &DraftKey, action: &Action) {
let ws = action.workspace().map_or_else(PathBuf::new, |name| {
model
.snap
.ws_path(&name)
.unwrap_or_else(|_| model.new_workspace_inputs(&name).workspace)
});
super::acting::line(model, state, key, &ws, action);
}
pub(super) fn note(state: &mut ShellState, result: Result<Reply, String>) -> bool {
match result {
Ok(Reply::Help(rows)) => {
state.slash = Some(help::render(&rows));
true
}
Ok(Reply::Search(_)) => {
state.slash = None;
super::focus::center(state, crate::keymap::CenterTab::Search);
true
}
Ok(reply) => {
state.slash = Some(
serde_json::to_string_pretty(&encode(&reply))
.unwrap_or_else(|e| format!("unreadable reply: {e}")),
);
true
}
Err(reason) => {
state.slash = Some(reason);
false
}
}
}
pub(super) fn seat(
ui: &mut egui::Ui,
model: &mut AppModel,
state: &mut ShellState,
lernie: &Cli,
bl: &Cli,
ctx: &super::verb_row::VerbCtx,
) -> bool {
if !line::is_command(&ctx.text) {
return false;
}
let clicked = ui
.horizontal(|ui| ui.button("Run").on_hover_text(RUN_HINT).clicked())
.inner;
if clicked || ctx.entered {
super::focus::request(state);
if run(model, state, lernie, bl, &ctx.key, &ctx.text) {
state.actions.drafts.set(ctx.key.clone(), String::new());
}
}
true
}
pub(super) fn note_ui(ui: &mut egui::Ui, state: &ShellState) {
let Some(note) = state.slash.clone() else {
return;
};
egui::ScrollArea::both()
.id_salt("slash-note")
.max_height(160.0)
.show(ui, |ui| {
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
ui.label(egui::RichText::new(note).monospace());
});
}