From 621a8db0dfd31095522969c311d4d704473f3acf Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Fri, 20 Mar 2026 08:18:21 -0700 Subject: [PATCH] move loads into tabs --- src/tui.zig | 76 ++--------------------------------------- src/tui/options_tab.zig | 23 +++++++++++++ src/tui/perf_tab.zig | 59 ++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 73 deletions(-) diff --git a/src/tui.zig b/src/tui.zig index e634a30..2534393 100644 --- a/src/tui.zig +++ b/src/tui.zig @@ -860,7 +860,7 @@ pub const App = struct { } } - fn rebuildOptionsRows(self: *App) void { + pub fn rebuildOptionsRows(self: *App) void { self.options_rows.clearRetainingCapacity(); const chains = self.options_data orelse return; const atm_price = if (chains.len > 0) chains[0].underlying_price orelse 0 else @as(f64, 0); @@ -1060,60 +1060,7 @@ pub const App = struct { } pub fn loadPerfData(self: *App) void { - self.perf_loaded = true; - self.freeCandles(); - self.freeDividends(); - self.trailing_price = null; - self.trailing_total = null; - self.trailing_me_price = null; - self.trailing_me_total = null; - self.candle_count = 0; - self.candle_first_date = null; - self.candle_last_date = null; - - const candle_result = self.svc.getCandles(self.symbol) catch |err| { - switch (err) { - zfin.DataError.NoApiKey => self.setStatus("No API key. Set TWELVEDATA_API_KEY"), - zfin.DataError.FetchFailed => self.setStatus("Fetch failed (network error or rate limit)"), - else => self.setStatus("Error loading data"), - } - return; - }; - self.candles = candle_result.data; - self.candle_timestamp = candle_result.timestamp; - - const c = self.candles.?; - if (c.len == 0) { - self.setStatus("No data available for symbol"); - return; - } - self.candle_count = c.len; - self.candle_first_date = c[0].date; - self.candle_last_date = c[c.len - 1].date; - - const today = fmt.todayDate(); - self.trailing_price = zfin.performance.trailingReturns(c); - self.trailing_me_price = zfin.performance.trailingReturnsMonthEnd(c, today); - - if (self.svc.getDividends(self.symbol)) |div_result| { - self.dividends = div_result.data; - self.trailing_total = zfin.performance.trailingReturnsWithDividends(c, div_result.data); - self.trailing_me_total = zfin.performance.trailingReturnsMonthEndWithDividends(c, div_result.data, today); - } else |_| {} - - self.risk_metrics = zfin.risk.trailingRisk(c); - - // Try to load ETF profile (non-fatal, won't show for non-ETFs) - if (!self.etf_loaded) { - self.etf_loaded = true; - if (self.svc.getEtfProfile(self.symbol)) |etf_result| { - if (etf_result.data.isEtf()) { - self.etf_profile = etf_result.data; - } - } else |_| {} - } - - self.setStatus(if (candle_result.source == .cached) "r/F5 to refresh" else "Fetched | r/F5 to refresh"); + perf_tab.loadData(self); } fn loadEarningsData(self: *App) void { @@ -1121,24 +1068,7 @@ pub const App = struct { } fn loadOptionsData(self: *App) void { - self.options_loaded = true; - self.freeOptions(); - - const result = self.svc.getOptions(self.symbol) catch |err| { - switch (err) { - zfin.DataError.FetchFailed => self.setStatus("CBOE fetch failed (network error)"), - else => self.setStatus("Error loading options"), - } - return; - }; - self.options_data = result.data; - self.options_timestamp = result.timestamp; - self.options_cursor = 0; - self.options_expanded = [_]bool{false} ** 64; - self.options_calls_collapsed = [_]bool{false} ** 64; - self.options_puts_collapsed = [_]bool{false} ** 64; - self.rebuildOptionsRows(); - self.setStatus(if (result.source == .cached) "Cached (1hr TTL) | r/F5 to refresh" else "Fetched | r/F5 to refresh"); + options_tab.loadData(self); } pub fn setStatus(self: *App, msg: []const u8) void { diff --git a/src/tui/options_tab.zig b/src/tui/options_tab.zig index 3870924..b127a62 100644 --- a/src/tui/options_tab.zig +++ b/src/tui/options_tab.zig @@ -8,6 +8,29 @@ const tui = @import("../tui.zig"); const App = tui.App; const StyledLine = tui.StyledLine; +// ── Data loading ────────────────────────────────────────────── + +pub fn loadData(self: *App) void { + self.options_loaded = true; + self.freeOptions(); + + const result = self.svc.getOptions(self.symbol) catch |err| { + switch (err) { + zfin.DataError.FetchFailed => self.setStatus("CBOE fetch failed (network error)"), + else => self.setStatus("Error loading options"), + } + return; + }; + self.options_data = result.data; + self.options_timestamp = result.timestamp; + self.options_cursor = 0; + self.options_expanded = [_]bool{false} ** 64; + self.options_calls_collapsed = [_]bool{false} ** 64; + self.options_puts_collapsed = [_]bool{false} ** 64; + self.rebuildOptionsRows(); + self.setStatus(if (result.source == .cached) "Cached (1hr TTL) | r/F5 to refresh" else "Fetched | r/F5 to refresh"); +} + // ── Rendering ───────────────────────────────────────────────── pub fn buildStyledLines(self: *App, arena: std.mem.Allocator) ![]const StyledLine { diff --git a/src/tui/perf_tab.zig b/src/tui/perf_tab.zig index a8f36af..25d2292 100644 --- a/src/tui/perf_tab.zig +++ b/src/tui/perf_tab.zig @@ -8,6 +8,65 @@ const tui = @import("../tui.zig"); const App = tui.App; const StyledLine = tui.StyledLine; +// ── Data loading ────────────────────────────────────────────── + +pub fn loadData(self: *App) void { + self.perf_loaded = true; + self.freeCandles(); + self.freeDividends(); + self.trailing_price = null; + self.trailing_total = null; + self.trailing_me_price = null; + self.trailing_me_total = null; + self.candle_count = 0; + self.candle_first_date = null; + self.candle_last_date = null; + + const candle_result = self.svc.getCandles(self.symbol) catch |err| { + switch (err) { + zfin.DataError.NoApiKey => self.setStatus("No API key. Set TWELVEDATA_API_KEY"), + zfin.DataError.FetchFailed => self.setStatus("Fetch failed (network error or rate limit)"), + else => self.setStatus("Error loading data"), + } + return; + }; + self.candles = candle_result.data; + self.candle_timestamp = candle_result.timestamp; + + const c = self.candles.?; + if (c.len == 0) { + self.setStatus("No data available for symbol"); + return; + } + self.candle_count = c.len; + self.candle_first_date = c[0].date; + self.candle_last_date = c[c.len - 1].date; + + const today = fmt.todayDate(); + self.trailing_price = zfin.performance.trailingReturns(c); + self.trailing_me_price = zfin.performance.trailingReturnsMonthEnd(c, today); + + if (self.svc.getDividends(self.symbol)) |div_result| { + self.dividends = div_result.data; + self.trailing_total = zfin.performance.trailingReturnsWithDividends(c, div_result.data); + self.trailing_me_total = zfin.performance.trailingReturnsMonthEndWithDividends(c, div_result.data, today); + } else |_| {} + + self.risk_metrics = zfin.risk.trailingRisk(c); + + // Try to load ETF profile (non-fatal, won't show for non-ETFs) + if (!self.etf_loaded) { + self.etf_loaded = true; + if (self.svc.getEtfProfile(self.symbol)) |etf_result| { + if (etf_result.data.isEtf()) { + self.etf_profile = etf_result.data; + } + } else |_| {} + } + + self.setStatus(if (candle_result.source == .cached) "r/F5 to refresh" else "Fetched | r/F5 to refresh"); +} + // ── Rendering ───────────────────────────────────────────────── pub fn buildStyledLines(self: *App, arena: std.mem.Allocator) ![]const StyledLine {