pub fn dispatch(argv: &[String]) -> Option<i32> {
if let Some(page) = help::answer(argv) {
println!("{page}");
return Some(0);
}
let namespace = Namespace::from_arg(argv.get(1).map(String::as_str)?)?;
Some(namespace.run(argv.get(2..).unwrap_or_default()))
}
fn usage() -> String {
use clap::CommandFactory;
let rows: Vec<&crate::boundary::help::HelpRow> = help::COMMANDS
.iter()
.filter(|row| !row.summary.is_empty())
.collect();
let column = rows.iter().map(|row| row.usage.chars().count()).max();
let listed: Vec<String> = rows
.iter()
.map(|row| {
let gap = " ".repeat(
column
.unwrap_or_default()
.saturating_sub(row.usage.chars().count())
+ 2,
);
format!(" {}{gap}{}", row.usage, row.summary)
})
.collect();
format!(
"{}\nCommands:\n{}\n\nEvery command answers --help. `yog gesture --help` lists every \
gesture; `yog gesture --help <command>` is one command's page.\n",
crate::Args::command().render_help(),
listed.join("\n"),
)
}
const NAMESPACES: &[(&str, Namespace)] = &[
("lernie", Namespace::Lernie),
("bl", Namespace::Bl),
("bz", Namespace::Bz),
("bl-delivery", Namespace::BlDelivery),
("bl-tracker", Namespace::BlTracker),
("gesture", Namespace::Gesture),
(crate::wire::SEAT_SUBCMD, Namespace::Seat),
(crate::wire::HOST_SUBCMD, Namespace::ToolHost),
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Namespace {
Lernie,
Bl,
Bz,
BlDelivery,
BlTracker,
Gesture,
Seat,
ToolHost,
}
impl Namespace {
fn from_arg(arg: &str) -> Option<Self> {
NAMESPACES
.iter()
.find(|(word, _)| *word == arg)
.map(|(_, namespace)| *namespace)
}
fn run(self, args: &[String]) -> i32 {
match self {
Namespace::Lernie => lernie::run(args),
Namespace::Bl => bl::run(args),
Namespace::Bz => bz::run(args),
Namespace::BlDelivery => bl_delivery::run(args),
Namespace::BlTracker => bl_tracker::run(args),
Namespace::Gesture => gesture::run(args),
Namespace::Seat => wire::seat(args),
Namespace::ToolHost => wire::tool_host(args),
}
}
}
mod gesture {
use crate::ui_state::Clock;
use std::time::Duration;
const WAITS: u32 = 1200;
const POLL: Duration = Duration::from_millis(50);
pub(super) fn run(args: &[String]) -> i32 {
let world = crate::world::compose(&crate::xdg::Env::from_env());
let seed = format!(
"{}-{}",
crate::ui_state::SystemClock.stamp(),
std::process::id()
);
crate::boundary::sugar::run(&world.yog_state_root(), args, &seed, WAITS, &mut || {
std::thread::sleep(POLL);
})
}
}
mod wire;
mod lernie;
mod bl;
mod landing;
pub(crate) mod help;
mod bl_delivery {
use std::env;
use std::io;
use std::path::{Path, PathBuf};
pub(super) fn run(args: &[String]) -> i32 {
let home = env::var("HOME").unwrap_or_default();
let env = balls::delivery_bin::Env {
plugin: env::var("BALLS_PLUGIN_NAME").ok(),
xdg: balls::layout::Xdg::with(
Path::new(&home),
env::var("XDG_CONFIG_HOME").ok().as_deref(),
env::var("XDG_STATE_HOME").ok().as_deref(),
),
cwd: env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
};
balls::delivery_bin::run(
args,
&mut io::stdin().lock(),
&mut io::stdout().lock(),
&env,
)
}
}
mod bl_tracker {
use std::env;
use std::io;
use std::path::PathBuf;
pub(super) fn run(args: &[String]) -> i32 {
let home = env::var_os("HOME").map(PathBuf::from).unwrap_or_default();
let xdg = balls::layout::Xdg::with(
&home,
env::var("XDG_CONFIG_HOME").ok().as_deref(),
env::var("XDG_STATE_HOME").ok().as_deref(),
);
let env = balls::tracker::Env::resolve(xdg, env::var("BALLS_PLUGIN_DEPTH").ok());
balls::tracker::run(
args,
&mut io::stdin().lock(),
&mut io::stdout().lock(),
&env,
)
}
}
mod bz {
pub(super) fn run(args: &[String]) -> i32 {
crate::bz_host::run(
args.to_vec(),
&crate::xdg::Env::from_env(),
crate::bz_host::Tty::probe(),
&mut std::io::stdin().lock(),
&mut std::io::stdout().lock(),
&mut std::io::stderr().lock(),
)
}
}
#[cfg(test)]
mod tests;