pub mod cli;
pub mod color;
pub mod completion;
pub mod config;
pub mod executor;
pub mod parser;
pub mod plugin;
pub mod prompt;
pub mod shell;
pub mod theme;
pub mod zsh;
use std::time::Duration;
pub const MAX_STARTUP_MS: u64 = 10;
pub const MAX_PROMPT_MS: u64 = 2;
pub const MAX_PARSER_MS: u64 = 2;
pub const MAX_EXECUTOR_MS: u64 = 2;
#[derive(Debug, thiserror::Error)]
pub enum PzshError {
#[error("startup exceeded {0}ms budget (took {1}ms)")]
StartupBudgetExceeded(u64, u64),
#[error("parser exceeded {0}ms budget (took {1}ms)")]
ParserBudgetExceeded(u64, u64),
#[error("executor exceeded {0}ms budget (took {1}ms)")]
ExecutorBudgetExceeded(u64, u64),
#[error("prompt exceeded {0}ms budget (took {1}ms)")]
PromptBudgetExceeded(u64, u64),
#[error("config error: {0}")]
Config(#[from] config::ConfigError),
#[error("forbidden pattern detected: {0}")]
ForbiddenPattern(String),
}
pub type Result<T> = std::result::Result<T, PzshError>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ShellType {
#[default]
Zsh,
Bash,
}
#[derive(Debug)]
#[allow(dead_code)] pub struct Pzsh {
config: config::CompiledConfig,
parser: parser::Parser,
executor: executor::Executor,
prompt: prompt::Prompt,
shell_type: ShellType,
}
impl Pzsh {
pub fn new(config: config::CompiledConfig) -> Result<Self> {
let start = std::time::Instant::now();
let shell_type = config.shell_type;
let parser = parser::Parser::new(&config);
let executor = executor::Executor::new(&config);
let prompt = prompt::Prompt::new(&config);
let elapsed = start.elapsed();
if elapsed > Duration::from_millis(MAX_STARTUP_MS) {
return Err(PzshError::StartupBudgetExceeded(
MAX_STARTUP_MS,
elapsed.as_millis() as u64,
));
}
Ok(Self {
config,
parser,
executor,
prompt,
shell_type,
})
}
#[must_use]
pub fn measure_startup(&self) -> Duration {
let start = std::time::Instant::now();
let config = config::CompiledConfig::default();
let _ = parser::Parser::new(&config);
let _ = executor::Executor::new(&config);
let _ = prompt::Prompt::new(&config);
start.elapsed()
}
#[must_use]
pub const fn shell_type(&self) -> ShellType {
self.shell_type
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Instant;
#[test]
fn test_startup_under_10ms() {
let config = config::CompiledConfig::default();
let start = Instant::now();
let result = Pzsh::new(config);
let elapsed = start.elapsed();
assert!(result.is_ok(), "Pzsh initialization failed");
assert!(
elapsed < Duration::from_millis(MAX_STARTUP_MS),
"ANDON: Startup exceeded 10ms budget: {:?}",
elapsed
);
}
#[test]
fn test_startup_is_deterministic() {
let mut times = Vec::with_capacity(100);
for _ in 0..100 {
let config = config::CompiledConfig::default();
let start = Instant::now();
let _ = Pzsh::new(config);
times.push(start.elapsed());
}
let mean: Duration = times.iter().sum::<Duration>() / times.len() as u32;
let variance: f64 = times
.iter()
.map(|t| {
let diff = t.as_nanos() as f64 - mean.as_nanos() as f64;
diff * diff
})
.sum::<f64>()
/ times.len() as f64;
let std_dev = variance.sqrt();
assert!(
std_dev < 1_000_000.0,
"Startup time variance too high: std_dev = {std_dev}ns"
);
}
#[test]
fn test_shell_type_default_is_zsh() {
let config = config::CompiledConfig::default();
let pzsh = Pzsh::new(config).unwrap();
assert_eq!(pzsh.shell_type(), ShellType::Zsh);
}
#[test]
fn test_shell_type_bash() {
let mut config = config::CompiledConfig::default();
config.shell_type = ShellType::Bash;
let pzsh = Pzsh::new(config).unwrap();
assert_eq!(pzsh.shell_type(), ShellType::Bash);
}
#[test]
fn test_measure_startup() {
let config = config::CompiledConfig::default();
let pzsh = Pzsh::new(config).unwrap();
let duration = pzsh.measure_startup();
assert!(
duration < Duration::from_millis(MAX_STARTUP_MS),
"measure_startup took too long: {:?}",
duration
);
}
#[test]
fn test_error_display() {
let err = PzshError::StartupBudgetExceeded(10, 15);
assert!(err.to_string().contains("startup exceeded"));
let err = PzshError::ParserBudgetExceeded(2, 5);
assert!(err.to_string().contains("parser exceeded"));
let err = PzshError::ExecutorBudgetExceeded(2, 4);
assert!(err.to_string().contains("executor exceeded"));
let err = PzshError::PromptBudgetExceeded(2, 3);
assert!(err.to_string().contains("prompt exceeded"));
let err = PzshError::ForbiddenPattern("test pattern".to_string());
assert!(err.to_string().contains("forbidden pattern"));
}
#[test]
fn test_shell_type_default() {
let shell = ShellType::default();
assert_eq!(shell, ShellType::Zsh);
}
}