diff --git a/src/main.rs b/src/main.rs index 7fc3334..388002d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,22 +34,70 @@ use ui::import_wizard_ui::ImportWizardWidget; use ui::tile_bar::TileBar; use ui::view_panel::ViewPanel; +fn main() -> Result<()> { + let args: Vec = std::env::args().collect(); + let arg_config = parse_args(args); + arg_config.run() +} + +trait Runnable { + fn run(self: Box) -> Result<()>; +} + struct CmdLineArgs { file_path: Option, import_path: Option, } -enum ArgConfig { - Help, - Headless { - file_path: Option, - commands: Vec, - script: Option, - }, - Default(CmdLineArgs), +impl Runnable for CmdLineArgs { + fn run(self: Box) -> Result<()> { + // Load or create model + let model = get_initial_model(&self.file_path)?; + + // Pre-TUI import: parse JSON and open wizard + let import_json = if let Some(ref path) = self.import_path { + match std::fs::read_to_string(path) { + Err(e) => { + eprintln!("Cannot read '{}': {e}", path.display()); + return Ok(()); + } + Ok(content) => match serde_json::from_str::(&content) { + Err(e) => { + eprintln!("JSON parse error: {e}"); + return Ok(()); + } + Ok(json) => Some(json), + }, + } + } else { + None + }; + + run_tui(model, self.file_path, import_json) + } } -fn parse_args(args: Vec) -> ArgConfig { +struct HeadlessArgs { + file_path: Option, + commands: Vec, + script: Option, +} + +impl Runnable for HeadlessArgs { + fn run(self: Box) -> Result<()> { + run_headless(self.file_path, self.commands, self.script) + } +} + +struct HelpArgs {} + +impl Runnable for HelpArgs { + fn run(self: Box) -> Result<()> { + print_usage() + } +} + +fn parse_args(args: Vec) -> Box { let mut file_path: Option = None; let mut headless_cmds: Vec = Vec::new(); let mut headless_script: Option = None; @@ -73,7 +121,7 @@ fn parse_args(args: Vec) -> ArgConfig { import_path = args.get(i).map(PathBuf::from); } "--help" | "-h" => { - return ArgConfig::Help; + return Box::new(HelpArgs {}); } arg if !arg.starts_with('-') => { file_path = Some(PathBuf::from(arg)); @@ -84,14 +132,14 @@ fn parse_args(args: Vec) -> ArgConfig { } if !headless_cmds.is_empty() || headless_script.is_some() { - return ArgConfig::Headless { + return Box::new(HeadlessArgs { file_path, commands: headless_cmds, script: headless_script, - }; + }); } - return ArgConfig::Default(CmdLineArgs { + return Box::new(CmdLineArgs { file_path, import_path, }); @@ -117,58 +165,12 @@ fn get_initial_model(file_path: &Option) -> Result { }; } -fn main() -> Result<()> { - let args: Vec = std::env::args().collect(); - - let arg_config = parse_args(args); - - match arg_config { - ArgConfig::Default(cmd_line_args) => { - // Load or create model - let model = get_initial_model(&cmd_line_args.file_path)?; - - // Pre-TUI import: parse JSON and open wizard - let import_json = if let Some(ref path) = cmd_line_args.import_path { - match std::fs::read_to_string(path) { - Err(e) => { - eprintln!("Cannot read '{}': {e}", path.display()); - return Ok(()); - } - Ok(content) => match serde_json::from_str::(&content) { - Err(e) => { - eprintln!("JSON parse error: {e}"); - return Ok(()); - } - Ok(json) => Some(json), - }, - } - } else { - None - }; - - run_tui(model, cmd_line_args.file_path, import_json) - } - ArgConfig::Headless { - file_path, - commands, - script, - } => { - let mut model = get_initial_model(&file_path)?; - return run_headless(&mut model, file_path, commands, script); - } - ArgConfig::Help => { - print_usage(); - Ok(()) - } - } -} - fn run_headless( - model: &mut Model, file_path: Option, inline_cmds: Vec, script: Option, ) -> Result<()> { + let mut model = get_initial_model(&file_path)?; let mut cmds: Vec = inline_cmds; if let Some(script_path) = script { let content = std::fs::read_to_string(&script_path)?; @@ -191,7 +193,7 @@ fn run_headless( continue; } }; - let result = command::dispatch(model, &parsed); + let result = command::dispatch(&mut model, &parsed); if !result.ok { exit_code = 1; } @@ -199,7 +201,7 @@ fn run_headless( } if let Some(path) = file_path { - persistence::save(model, &path)?; + persistence::save(&mut model, &path)?; } std::process::exit(exit_code); @@ -560,7 +562,7 @@ fn draw_welcome(f: &mut Frame, area: Rect, _app: &App) { // ── Usage ───────────────────────────────────────────────────────────────────── -fn print_usage() { +fn print_usage() -> Result<()> { println!("improvise — multi-dimensional data modeling TUI\n"); println!("USAGE:"); println!(" improvise [file.improv] Open or create a model"); @@ -583,4 +585,5 @@ fn print_usage() { println!(" F C V Toggle Formulas / Categories / Views panel"); println!(" ZZ Save and quit"); println!(" ? Help"); + Ok(()) }