statusline 0.23.1

Simple and fast bash PS1 line with useful features
use crate::{Environment, Pretty};
use heck::ToPascalCase as _;
use linkme::distributed_slice;
use std::{collections::HashMap, sync::LazyLock};

mod build_info;
mod elapsed;
mod git;
mod hostuser;
mod jobs;
mod mail;
mod nix_shell;
mod return_code;
mod root_shell;
mod ssh;
mod time;
mod venv;
mod workdir;

pub trait Block: Pretty {
    fn new(environ: &Environment) -> Option<Self>
    where
        Self: Sized;
    fn extend(&mut self) {}
}

type Constructor = fn(&Environment) -> Option<Box<dyn Block>>;
#[distributed_slice]
static BLOCK_KINDS: [(&str, Constructor)];

macro_rules! register_block {
    ($name:ident) => {
        const _: () = {
            #[linkme::distributed_slice($crate::block::BLOCK_KINDS)]
            static _BLOCK_KIND: (&str, $crate::block::Constructor) = (stringify!($name), |env| {
                <$name as $crate::block::Block>::new(env).map(|block| {
                    ::std::boxed::Box::new(block) as ::std::boxed::Box<dyn $crate::block::Block>
                })
            });
        };
    };
}
pub(crate) use register_block;

static BLOCK_KINDS_MAP: LazyLock<HashMap<&str, Constructor>> =
    LazyLock::new(|| BLOCK_KINDS.iter().copied().collect());

pub fn create_blocks(names: &[impl AsRef<str>], environ: &Environment) -> Vec<Box<dyn Block>> {
    names
        .iter()
        .map(|name| name.as_ref().to_pascal_case())
        .map(|name| match BLOCK_KINDS_MAP.get(&*name) {
            Some(block) => block,
            None => panic!("block {name} does not exist"),
        })
        .filter_map(|cons| cons(environ))
        .collect()
}