feat(01-03): wire complete startup-to-shutdown pipeline in main.rs
- All four modules declared: mod app, config, signals, terminal - Pre-terminal phase: login shell detection, CLI parse, config load - Terminal phase: panic hook installed first, then signals, then terminal init - Event loop: App::new receives is_login_shell and app_config; run_event_loop runs - Shutdown: restore_terminal() called before show_goodbye() in all exit paths - BrokenPipe from event loop exits silently (LIFE-04) - Unexpected I/O errors logged to stderr after terminal restore
This commit is contained in:
+66
-5
@@ -4,10 +4,14 @@ mod signals;
|
||||
mod terminal;
|
||||
|
||||
fn main() {
|
||||
// ── PRE-TERMINAL PHASE ────────────────────────────────────────────────────
|
||||
// Errors here use normal eprintln! — the terminal is not yet in raw mode.
|
||||
|
||||
// 1. Detect login shell BEFORE stripping argv[0]
|
||||
// POSIX: kernel prefixes argv[0] with '-' for login shells.
|
||||
let is_login_shell = config::detect_login_shell();
|
||||
|
||||
// 2. Parse CLI (strips dash from argv[0] internally)
|
||||
// 2. Parse CLI (strips the leading dash from argv[0] before clap sees it)
|
||||
let cli = config::parse_cli();
|
||||
|
||||
// 3. Resolve config path and load config
|
||||
@@ -20,8 +24,65 @@ fn main() {
|
||||
}
|
||||
};
|
||||
|
||||
// Phase 1 placeholder: print loaded config for verification
|
||||
// This will be replaced by terminal init + event loop in Plan 03
|
||||
println!("Config loaded: {:?}", app_config);
|
||||
println!("Login shell: {}", is_login_shell);
|
||||
// ── TERMINAL PHASE ────────────────────────────────────────────────────────
|
||||
// Install safety envelope BEFORE terminal init so panics during init are caught.
|
||||
|
||||
// 4. Install panic hook first — covers panics during terminal init itself
|
||||
terminal::install_panic_hook();
|
||||
|
||||
// 5. Register signal handlers before terminal init — covers early SIGHUP
|
||||
// (e.g. SSH disconnect between login shell launch and first draw)
|
||||
let signal_flags = match signals::register_signals() {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
eprintln!("SYSTEM ERROR: Cannot register signal handlers: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// 6. Initialize terminal (enables raw mode, clears screen, sets Viewport::Fullscreen)
|
||||
let mut term = match terminal::init_terminal() {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
eprintln!("SYSTEM ERROR: Cannot initialize terminal: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// ── EVENT LOOP PHASE ──────────────────────────────────────────────────────
|
||||
|
||||
// 7. Create app state and run the event loop
|
||||
// app_config is stored in App for Phase 2+ use (vault_path, theme).
|
||||
let mut app_state = app::App::new(is_login_shell, app_config);
|
||||
let shutdown_reason = app_state.run_event_loop(&mut term, &signal_flags);
|
||||
|
||||
// ── SHUTDOWN PHASE ────────────────────────────────────────────────────────
|
||||
// Terminal must be restored in EVERY exit path below.
|
||||
|
||||
// 8. Restore terminal — always, regardless of how we got here.
|
||||
// Must happen BEFORE show_goodbye() since goodbye prints to stdout.
|
||||
terminal::restore_terminal();
|
||||
|
||||
// 9. Handle the shutdown reason
|
||||
match shutdown_reason {
|
||||
Ok(app::ShutdownReason::UserQuit) => {
|
||||
// User deliberately exited — show BBS goodbye message
|
||||
app::show_goodbye();
|
||||
}
|
||||
Ok(app::ShutdownReason::Signal) => {
|
||||
// SIGHUP or SIGTERM — SSH disconnect or graceful OS shutdown.
|
||||
// Exit silently: there may be nobody on the other end to see a message.
|
||||
}
|
||||
Err(e) => {
|
||||
// I/O error from the event loop
|
||||
if e.kind() == std::io::ErrorKind::BrokenPipe {
|
||||
// SSH connection closed while we were writing — silent exit (LIFE-04).
|
||||
// Terminal is already restored above; just exit quietly.
|
||||
} else {
|
||||
// Unexpected I/O error — log to stderr after terminal restore
|
||||
eprintln!("SYSTEM ERROR: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user