diff --git a/src/main.zig b/src/main.zig index f8225d0..0f85ce9 100644 --- a/src/main.zig +++ b/src/main.zig @@ -59,7 +59,7 @@ const usage = \\ ; -pub fn main() !void { +pub fn main() !u8 { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); @@ -73,9 +73,8 @@ pub fn main() !void { const out: *std.Io.Writer = &stdout_writer.interface; if (args.len < 2) { - try out.writeAll(usage); - try out.flush(); - return; + try cli.stderrPrint(usage); + return 1; } // Scan for global --no-color flag @@ -92,36 +91,54 @@ pub fn main() !void { if (std.mem.eql(u8, command, "help") or std.mem.eql(u8, command, "--help") or std.mem.eql(u8, command, "-h")) { try out.writeAll(usage); try out.flush(); - return; + return 0; } // Interactive TUI -- delegates to the TUI module (owns its own DataService) if (std.mem.eql(u8, command, "interactive") or std.mem.eql(u8, command, "i")) { try out.flush(); try tui.run(allocator, config, args); - return; + return 0; } var svc = zfin.DataService.init(allocator, config); defer svc.deinit(); if (std.mem.eql(u8, command, "perf")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'perf' requires a symbol argument\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'perf' requires a symbol argument\n"); + return 1; + } try commands.perf.run(allocator, &svc, args[2], color, out); } else if (std.mem.eql(u8, command, "quote")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'quote' requires a symbol argument\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'quote' requires a symbol argument\n"); + return 1; + } try commands.quote.run(allocator, config, &svc, args[2], color, out); } else if (std.mem.eql(u8, command, "history")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'history' requires a symbol argument\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'history' requires a symbol argument\n"); + return 1; + } try commands.history.run(allocator, &svc, args[2], color, out); } else if (std.mem.eql(u8, command, "divs")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'divs' requires a symbol argument\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'divs' requires a symbol argument\n"); + return 1; + } try commands.divs.run(allocator, &svc, config, args[2], color, out); } else if (std.mem.eql(u8, command, "splits")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'splits' requires a symbol argument\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'splits' requires a symbol argument\n"); + return 1; + } try commands.splits.run(allocator, &svc, args[2], color, out); } else if (std.mem.eql(u8, command, "options")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'options' requires a symbol argument\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'options' requires a symbol argument\n"); + return 1; + } // Parse --ntm flag var ntm: usize = 8; var ai: usize = 3; @@ -133,10 +150,16 @@ pub fn main() !void { } try commands.options.run(allocator, &svc, args[2], ntm, color, out); } else if (std.mem.eql(u8, command, "earnings")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'earnings' requires a symbol argument\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'earnings' requires a symbol argument\n"); + return 1; + } try commands.earnings.run(allocator, &svc, args[2], color, out); } else if (std.mem.eql(u8, command, "etf")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'etf' requires a symbol argument\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'etf' requires a symbol argument\n"); + return 1; + } try commands.etf.run(allocator, &svc, args[2], color, out); } else if (std.mem.eql(u8, command, "portfolio")) { // Parse -w/--watchlist and --refresh flags; file path is first non-flag arg (default: portfolio.srf) @@ -158,13 +181,22 @@ pub fn main() !void { } try commands.portfolio.run(allocator, config, &svc, file_path, watchlist_path, force_refresh, color, out); } else if (std.mem.eql(u8, command, "lookup")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'lookup' requires a CUSIP argument\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'lookup' requires a CUSIP argument\n"); + return 1; + } try commands.lookup.run(allocator, &svc, args[2], color, out); } else if (std.mem.eql(u8, command, "cache")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'cache' requires a subcommand (stats, clear)\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'cache' requires a subcommand (stats, clear)\n"); + return 1; + } try commands.cache.run(allocator, config, args[2], out); } else if (std.mem.eql(u8, command, "enrich")) { - if (args.len < 3) return try cli.stderrPrint("Error: 'enrich' requires a portfolio file path or symbol\n"); + if (args.len < 3) { + try cli.stderrPrint("Error: 'enrich' requires a portfolio file path or symbol\n"); + return 1; + } try commands.enrich.run(allocator, config, args[2], out); } else if (std.mem.eql(u8, command, "analysis")) { // File path is first non-flag arg (default: portfolio.srf) @@ -178,10 +210,12 @@ pub fn main() !void { try commands.analysis.run(allocator, config, &svc, analysis_file, color, out); } else { try cli.stderrPrint("Unknown command. Run 'zfin help' for usage.\n"); + return 1; } // Single flush for all stdout output try out.flush(); + return 0; } // ── Command modules ──────────────────────────────────────────