cleanup of _mod imports
This commit is contained in:
parent
b3ebc3f986
commit
58c20a4de9
10 changed files with 93 additions and 91 deletions
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
const std = @import("std");
|
||||
const srf = @import("srf");
|
||||
const snapshot_mod = @import("models/snapshot.zig");
|
||||
const snapshot = @import("models/snapshot.zig");
|
||||
const Date = @import("models/date.zig").Date;
|
||||
const timeline = @import("analytics/timeline.zig");
|
||||
|
||||
|
|
@ -58,21 +58,21 @@ pub const snapshot_suffix = "-portfolio.srf";
|
|||
pub fn parseSnapshotBytes(
|
||||
allocator: std.mem.Allocator,
|
||||
bytes: []const u8,
|
||||
) Error!snapshot_mod.Snapshot {
|
||||
) Error!snapshot.Snapshot {
|
||||
var reader = std.Io.Reader.fixed(bytes);
|
||||
// `alloc_strings = false` tells srf to return string values as
|
||||
// slices into `bytes` rather than duping into its own arena.
|
||||
var it = srf.iterator(&reader, allocator, .{ .alloc_strings = false }) catch return error.InvalidSrf;
|
||||
defer it.deinit();
|
||||
|
||||
var meta_opt: ?snapshot_mod.MetaRow = null;
|
||||
var totals: std.ArrayList(snapshot_mod.TotalRow) = .empty;
|
||||
var meta_opt: ?snapshot.MetaRow = null;
|
||||
var totals: std.ArrayList(snapshot.TotalRow) = .empty;
|
||||
errdefer totals.deinit(allocator);
|
||||
var taxes: std.ArrayList(snapshot_mod.TaxTypeRow) = .empty;
|
||||
var taxes: std.ArrayList(snapshot.TaxTypeRow) = .empty;
|
||||
errdefer taxes.deinit(allocator);
|
||||
var accounts: std.ArrayList(snapshot_mod.AccountRow) = .empty;
|
||||
var accounts: std.ArrayList(snapshot.AccountRow) = .empty;
|
||||
errdefer accounts.deinit(allocator);
|
||||
var lots: std.ArrayList(snapshot_mod.LotRow) = .empty;
|
||||
var lots: std.ArrayList(snapshot.LotRow) = .empty;
|
||||
errdefer lots.deinit(allocator);
|
||||
|
||||
while (it.next() catch return error.InvalidSrf) |field_it| {
|
||||
|
|
@ -115,11 +115,11 @@ pub fn parseSnapshotBytes(
|
|||
/// coerces remaining fields into the matching variant struct. Variant
|
||||
/// names here MUST match the wire-format `kind` values literally.
|
||||
const SnapshotRecord = union(enum) {
|
||||
meta: snapshot_mod.MetaRow,
|
||||
total: snapshot_mod.TotalRow,
|
||||
tax_type: snapshot_mod.TaxTypeRow,
|
||||
account: snapshot_mod.AccountRow,
|
||||
lot: snapshot_mod.LotRow,
|
||||
meta: snapshot.MetaRow,
|
||||
total: snapshot.TotalRow,
|
||||
tax_type: snapshot.TaxTypeRow,
|
||||
account: snapshot.AccountRow,
|
||||
lot: snapshot.LotRow,
|
||||
|
||||
pub const srf_tag_field = "kind";
|
||||
};
|
||||
|
|
@ -133,7 +133,7 @@ const SnapshotRecord = union(enum) {
|
|||
/// because each snapshot borrows strings from its corresponding buffer.
|
||||
/// `deinit` frees both in the right order.
|
||||
pub const LoadedHistory = struct {
|
||||
snapshots: []snapshot_mod.Snapshot,
|
||||
snapshots: []snapshot.Snapshot,
|
||||
/// Per-snapshot backing buffers, parallel to `snapshots`. Empty
|
||||
/// slice when `snapshots` is empty.
|
||||
buffers: [][]u8,
|
||||
|
|
@ -169,7 +169,7 @@ pub fn loadHistoryDir(
|
|||
};
|
||||
defer dir.close();
|
||||
|
||||
var snapshots: std.ArrayList(snapshot_mod.Snapshot) = .empty;
|
||||
var snapshots: std.ArrayList(snapshot.Snapshot) = .empty;
|
||||
var buffers: std.ArrayList([]u8) = .empty;
|
||||
errdefer {
|
||||
for (snapshots.items) |*s| s.deinit(allocator);
|
||||
|
|
@ -283,7 +283,7 @@ const testing = std.testing;
|
|||
/// it. Returns the snapshot AND the owned bytes so the test can free
|
||||
/// both in the correct order (snapshot first, then bytes).
|
||||
const ParsedLiteral = struct {
|
||||
snap: snapshot_mod.Snapshot,
|
||||
snap: snapshot.Snapshot,
|
||||
bytes: []u8,
|
||||
|
||||
fn deinit(self: *ParsedLiteral) void {
|
||||
|
|
|
|||
94
src/tui.zig
94
src/tui.zig
|
|
@ -5,8 +5,8 @@ const fmt = @import("format.zig");
|
|||
const views = @import("views/portfolio_sections.zig");
|
||||
const cli = @import("commands/common.zig");
|
||||
const keybinds = @import("tui/keybinds.zig");
|
||||
const theme_mod = @import("tui/theme.zig");
|
||||
const chart_mod = @import("tui/chart.zig");
|
||||
const theme = @import("tui/theme.zig");
|
||||
const chart = @import("tui/chart.zig");
|
||||
const portfolio_tab = @import("tui/portfolio_tab.zig");
|
||||
const quote_tab = @import("tui/quote_tab.zig");
|
||||
const perf_tab = @import("tui/perf_tab.zig");
|
||||
|
|
@ -15,7 +15,7 @@ const earnings_tab = @import("tui/earnings_tab.zig");
|
|||
const analysis_tab = @import("tui/analysis_tab.zig");
|
||||
const history_tab = @import("tui/history_tab.zig");
|
||||
const history_io = @import("history.zig");
|
||||
const timeline_mod = @import("analytics/timeline.zig");
|
||||
const timeline = @import("analytics/timeline.zig");
|
||||
|
||||
/// Comptime-generated table of single-character grapheme slices with static lifetime.
|
||||
/// This avoids dangling pointers from stack-allocated temporaries in draw functions.
|
||||
|
|
@ -208,14 +208,14 @@ pub const OptionsRow = struct {
|
|||
};
|
||||
|
||||
pub const ChartState = struct {
|
||||
config: chart_mod.ChartConfig = .{},
|
||||
timeframe: chart_mod.Timeframe = .@"1Y",
|
||||
config: chart.ChartConfig = .{},
|
||||
timeframe: chart.Timeframe = .@"1Y",
|
||||
image_id: ?u32 = null, // currently transmitted Kitty image ID
|
||||
image_width: u16 = 0, // image width in cells
|
||||
image_height: u16 = 0, // image height in cells
|
||||
symbol: [16]u8 = undefined, // symbol the chart was rendered for
|
||||
symbol_len: usize = 0,
|
||||
timeframe_rendered: ?chart_mod.Timeframe = null, // timeframe the chart was rendered for
|
||||
timeframe_rendered: ?chart.Timeframe = null, // timeframe the chart was rendered for
|
||||
timeframe_row: ?usize = null, // screen row of the timeframe selector (for mouse clicks)
|
||||
dirty: bool = true, // needs re-render
|
||||
price_min: f64 = 0,
|
||||
|
|
@ -223,9 +223,9 @@ pub const ChartState = struct {
|
|||
rsi_latest: ?f64 = null,
|
||||
|
||||
// Cached indicator data (persists across frames to avoid recomputation)
|
||||
cached_indicators: ?chart_mod.CachedIndicators = null,
|
||||
cached_indicators: ?chart.CachedIndicators = null,
|
||||
cache_candle_count: usize = 0, // candle count when cache was computed
|
||||
cache_timeframe: ?chart_mod.Timeframe = null, // timeframe when cache was computed
|
||||
cache_timeframe: ?chart.Timeframe = null, // timeframe when cache was computed
|
||||
cache_last_close: f64 = 0, // last candle's close when cache was computed
|
||||
|
||||
/// Free cached indicator memory.
|
||||
|
|
@ -240,7 +240,7 @@ pub const ChartState = struct {
|
|||
}
|
||||
|
||||
/// Check if cache is valid for the given candle data and timeframe.
|
||||
pub fn isCacheValid(self: *const ChartState, candles: []const zfin.Candle, timeframe: chart_mod.Timeframe) bool {
|
||||
pub fn isCacheValid(self: *const ChartState, candles: []const zfin.Candle, timeframe: chart.Timeframe) bool {
|
||||
if (self.cached_indicators == null) return false;
|
||||
if (self.cache_timeframe == null or self.cache_timeframe.? != timeframe) return false;
|
||||
|
||||
|
|
@ -275,7 +275,7 @@ pub const App = struct {
|
|||
config: zfin.Config,
|
||||
svc: *zfin.DataService,
|
||||
keymap: keybinds.KeyMap,
|
||||
theme: theme_mod.Theme,
|
||||
theme: theme.Theme,
|
||||
active_tab: Tab = .portfolio,
|
||||
symbol: []const u8 = "",
|
||||
symbol_buf: [16]u8 = undefined,
|
||||
|
|
@ -381,7 +381,7 @@ pub const App = struct {
|
|||
// Default to `.liquid` — that's the metric most worth watching
|
||||
// day-to-day. Illiquid barely changes, net_worth is dominated by
|
||||
// liquid anyway, so "show me liquid" is the headline view.
|
||||
history_metric: timeline_mod.Metric = .liquid,
|
||||
history_metric: timeline.Metric = .liquid,
|
||||
|
||||
// Mouse wheel debounce for cursor-based tabs (portfolio, options).
|
||||
// Terminals often send multiple wheel events per physical tick.
|
||||
|
|
@ -551,7 +551,7 @@ pub const App = struct {
|
|||
const col = @as(usize, @intCast(mouse.col));
|
||||
const prefix_len: usize = 9; // " Chart: "
|
||||
if (col >= prefix_len) {
|
||||
const timeframes = [_]chart_mod.Timeframe{ .@"6M", .ytd, .@"1Y", .@"3Y", .@"5Y" };
|
||||
const timeframes = [_]chart.Timeframe{ .@"6M", .ytd, .@"1Y", .@"3Y", .@"5Y" };
|
||||
var x: usize = prefix_len;
|
||||
for (timeframes) |tf| {
|
||||
const lbl_len = tf.label().len;
|
||||
|
|
@ -1599,8 +1599,8 @@ pub const App = struct {
|
|||
if (width > sym_label.len + col) {
|
||||
const sym_start = width - sym_label.len;
|
||||
const sym_style: vaxis.Style = .{
|
||||
.fg = theme_mod.Theme.vcolor(if (is_selected) th.warning else th.info),
|
||||
.bg = theme_mod.Theme.vcolor(th.tab_bg),
|
||||
.fg = theme.Theme.vcolor(if (is_selected) th.warning else th.info),
|
||||
.bg = theme.Theme.vcolor(th.tab_bg),
|
||||
.bold = is_selected,
|
||||
};
|
||||
for (0..sym_label.len) |i| {
|
||||
|
|
@ -1892,52 +1892,54 @@ pub const App = struct {
|
|||
|
||||
// ── Utility functions ────────────────────────────────────────
|
||||
|
||||
pub fn renderBrailleToStyledLines(arena: std.mem.Allocator, lines: *std.ArrayList(StyledLine), data: []const zfin.Candle, th: theme_mod.Theme) !void {
|
||||
var chart = fmt.computeBrailleChart(arena, data, 60, 10, th.positive, th.negative) catch return;
|
||||
pub fn renderBrailleToStyledLines(arena: std.mem.Allocator, lines: *std.ArrayList(StyledLine), data: []const zfin.Candle, th: theme.Theme) !void {
|
||||
// Local shadows the `chart` module import; use a shorter name for
|
||||
// the local BrailleChart handle.
|
||||
var br = fmt.computeBrailleChart(arena, data, 60, 10, th.positive, th.negative) catch return;
|
||||
// No deinit needed: arena handles cleanup
|
||||
|
||||
const bg = th.bg;
|
||||
for (0..chart.chart_height) |row| {
|
||||
const graphemes = try arena.alloc([]const u8, chart.n_cols + 12); // chart + padding + label
|
||||
const styles = try arena.alloc(vaxis.Style, chart.n_cols + 12);
|
||||
for (0..br.chart_height) |row| {
|
||||
const graphemes = try arena.alloc([]const u8, br.n_cols + 12); // chart + padding + label
|
||||
const styles = try arena.alloc(vaxis.Style, br.n_cols + 12);
|
||||
var gpos: usize = 0;
|
||||
|
||||
// 2 leading spaces
|
||||
graphemes[gpos] = " ";
|
||||
styles[gpos] = .{ .fg = theme_mod.Theme.vcolor(th.text_muted), .bg = theme_mod.Theme.vcolor(bg) };
|
||||
styles[gpos] = .{ .fg = theme.Theme.vcolor(th.text_muted), .bg = theme.Theme.vcolor(bg) };
|
||||
gpos += 1;
|
||||
graphemes[gpos] = " ";
|
||||
styles[gpos] = styles[0];
|
||||
gpos += 1;
|
||||
|
||||
// Chart columns
|
||||
for (0..chart.n_cols) |col| {
|
||||
const pattern = chart.pattern(row, col);
|
||||
for (0..br.n_cols) |col| {
|
||||
const pattern = br.pattern(row, col);
|
||||
graphemes[gpos] = fmt.brailleGlyph(pattern);
|
||||
if (pattern != 0) {
|
||||
styles[gpos] = .{ .fg = theme_mod.Theme.vcolor(chart.col_colors[col]), .bg = theme_mod.Theme.vcolor(bg) };
|
||||
styles[gpos] = .{ .fg = theme.Theme.vcolor(br.col_colors[col]), .bg = theme.Theme.vcolor(bg) };
|
||||
} else {
|
||||
styles[gpos] = .{ .fg = theme_mod.Theme.vcolor(bg), .bg = theme_mod.Theme.vcolor(bg) };
|
||||
styles[gpos] = .{ .fg = theme.Theme.vcolor(bg), .bg = theme.Theme.vcolor(bg) };
|
||||
}
|
||||
gpos += 1;
|
||||
}
|
||||
|
||||
// Right-side price labels
|
||||
if (row == 0) {
|
||||
const lbl = try std.fmt.allocPrint(arena, " {s}", .{chart.maxLabel()});
|
||||
const lbl = try std.fmt.allocPrint(arena, " {s}", .{br.maxLabel()});
|
||||
for (lbl) |ch| {
|
||||
if (gpos < graphemes.len) {
|
||||
graphemes[gpos] = glyph(ch);
|
||||
styles[gpos] = .{ .fg = theme_mod.Theme.vcolor(th.text_muted), .bg = theme_mod.Theme.vcolor(bg) };
|
||||
styles[gpos] = .{ .fg = theme.Theme.vcolor(th.text_muted), .bg = theme.Theme.vcolor(bg) };
|
||||
gpos += 1;
|
||||
}
|
||||
}
|
||||
} else if (row == chart.chart_height - 1) {
|
||||
const lbl = try std.fmt.allocPrint(arena, " {s}", .{chart.minLabel()});
|
||||
} else if (row == br.chart_height - 1) {
|
||||
const lbl = try std.fmt.allocPrint(arena, " {s}", .{br.minLabel()});
|
||||
for (lbl) |ch| {
|
||||
if (gpos < graphemes.len) {
|
||||
graphemes[gpos] = glyph(ch);
|
||||
styles[gpos] = .{ .fg = theme_mod.Theme.vcolor(th.text_muted), .bg = theme_mod.Theme.vcolor(bg) };
|
||||
styles[gpos] = .{ .fg = theme.Theme.vcolor(th.text_muted), .bg = theme.Theme.vcolor(bg) };
|
||||
gpos += 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1945,7 +1947,7 @@ pub fn renderBrailleToStyledLines(arena: std.mem.Allocator, lines: *std.ArrayLis
|
|||
|
||||
try lines.append(arena, .{
|
||||
.text = "",
|
||||
.style = .{ .fg = theme_mod.Theme.vcolor(th.text), .bg = theme_mod.Theme.vcolor(bg) },
|
||||
.style = .{ .fg = theme.Theme.vcolor(th.text), .bg = theme.Theme.vcolor(bg) },
|
||||
.graphemes = graphemes[0..gpos],
|
||||
.cell_styles = styles[0..gpos],
|
||||
});
|
||||
|
|
@ -1955,12 +1957,12 @@ pub fn renderBrailleToStyledLines(arena: std.mem.Allocator, lines: *std.ArrayLis
|
|||
{
|
||||
var start_buf: [7]u8 = undefined;
|
||||
var end_buf: [7]u8 = undefined;
|
||||
const start_label = fmt.BrailleChart.fmtShortDate(chart.start_date, &start_buf);
|
||||
const end_label = fmt.BrailleChart.fmtShortDate(chart.end_date, &end_buf);
|
||||
const muted_style = vaxis.Style{ .fg = theme_mod.Theme.vcolor(th.text_muted), .bg = theme_mod.Theme.vcolor(bg) };
|
||||
const start_label = fmt.BrailleChart.fmtShortDate(br.start_date, &start_buf);
|
||||
const end_label = fmt.BrailleChart.fmtShortDate(br.end_date, &end_buf);
|
||||
const muted_style = vaxis.Style{ .fg = theme.Theme.vcolor(th.text_muted), .bg = theme.Theme.vcolor(bg) };
|
||||
|
||||
const date_graphemes = try arena.alloc([]const u8, chart.n_cols + 12);
|
||||
const date_styles = try arena.alloc(vaxis.Style, chart.n_cols + 12);
|
||||
const date_graphemes = try arena.alloc([]const u8, br.n_cols + 12);
|
||||
const date_styles = try arena.alloc(vaxis.Style, br.n_cols + 12);
|
||||
var dpos: usize = 0;
|
||||
|
||||
// 2 leading spaces
|
||||
|
|
@ -1981,7 +1983,7 @@ pub fn renderBrailleToStyledLines(arena: std.mem.Allocator, lines: *std.ArrayLis
|
|||
}
|
||||
|
||||
// Gap between labels
|
||||
const total_width = chart.n_cols;
|
||||
const total_width = br.n_cols;
|
||||
if (total_width > start_label.len + end_label.len) {
|
||||
const gap = total_width - start_label.len - end_label.len;
|
||||
for (0..gap) |_| {
|
||||
|
|
@ -2004,7 +2006,7 @@ pub fn renderBrailleToStyledLines(arena: std.mem.Allocator, lines: *std.ArrayLis
|
|||
|
||||
try lines.append(arena, .{
|
||||
.text = "",
|
||||
.style = .{ .fg = theme_mod.Theme.vcolor(th.text), .bg = theme_mod.Theme.vcolor(bg) },
|
||||
.style = .{ .fg = theme.Theme.vcolor(th.text), .bg = theme.Theme.vcolor(bg) },
|
||||
.graphemes = date_graphemes[0..dpos],
|
||||
.cell_styles = date_styles[0..dpos],
|
||||
});
|
||||
|
|
@ -2017,7 +2019,7 @@ pub const freeWatchlist = cli.freeWatchlist;
|
|||
// Force test discovery for imported TUI sub-modules
|
||||
comptime {
|
||||
_ = keybinds;
|
||||
_ = theme_mod;
|
||||
_ = theme;
|
||||
_ = portfolio_tab;
|
||||
_ = quote_tab;
|
||||
_ = perf_tab;
|
||||
|
|
@ -2042,14 +2044,14 @@ pub fn run(
|
|||
var symbol_upper_buf: [32]u8 = undefined;
|
||||
var has_explicit_symbol = false;
|
||||
var skip_watchlist = false;
|
||||
var chart_config: chart_mod.ChartConfig = .{};
|
||||
var chart_config: chart.ChartConfig = .{};
|
||||
var i: usize = 0;
|
||||
while (i < args.len) : (i += 1) {
|
||||
if (std.mem.eql(u8, args[i], "--default-keys")) {
|
||||
try keybinds.printDefaults();
|
||||
return;
|
||||
} else if (std.mem.eql(u8, args[i], "--default-theme")) {
|
||||
try theme_mod.printDefaults();
|
||||
try theme.printDefaults();
|
||||
return;
|
||||
} else if (std.mem.eql(u8, args[i], "--symbol") or std.mem.eql(u8, args[i], "-s")) {
|
||||
if (i + 1 < args.len) {
|
||||
|
|
@ -2063,7 +2065,7 @@ pub fn run(
|
|||
} else if (std.mem.eql(u8, args[i], "--chart")) {
|
||||
if (i + 1 < args.len) {
|
||||
i += 1;
|
||||
if (chart_mod.ChartConfig.parse(args[i])) |cc| {
|
||||
if (chart.ChartConfig.parse(args[i])) |cc| {
|
||||
chart_config = cc;
|
||||
}
|
||||
}
|
||||
|
|
@ -2094,13 +2096,13 @@ pub fn run(
|
|||
};
|
||||
defer keymap.deinit();
|
||||
|
||||
const theme = blk: {
|
||||
const home = std.process.getEnvVarOwned(allocator, "HOME") catch break :blk theme_mod.default_theme;
|
||||
const loaded_theme = blk: {
|
||||
const home = std.process.getEnvVarOwned(allocator, "HOME") catch break :blk theme.default_theme;
|
||||
defer allocator.free(home);
|
||||
const theme_path = std.fs.path.join(allocator, &.{ home, ".config", "zfin", "theme.srf" }) catch
|
||||
break :blk theme_mod.default_theme;
|
||||
break :blk theme.default_theme;
|
||||
defer allocator.free(theme_path);
|
||||
break :blk theme_mod.loadFromFile(allocator, theme_path) orelse theme_mod.default_theme;
|
||||
break :blk theme.loadFromFile(allocator, theme_path) orelse theme.default_theme;
|
||||
};
|
||||
|
||||
var svc = try allocator.create(zfin.DataService);
|
||||
|
|
@ -2115,7 +2117,7 @@ pub fn run(
|
|||
.config = config,
|
||||
.svc = svc,
|
||||
.keymap = keymap,
|
||||
.theme = theme,
|
||||
.theme = loaded_theme,
|
||||
.portfolio_path = portfolio_path,
|
||||
.symbol = symbol,
|
||||
.has_explicit_symbol = has_explicit_symbol,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
const vaxis = @import("vaxis");
|
||||
const zfin = @import("../root.zig");
|
||||
const fmt = @import("../format.zig");
|
||||
const theme_mod = @import("theme.zig");
|
||||
const theme = @import("theme.zig");
|
||||
const tui = @import("../tui.zig");
|
||||
const App = tui.App;
|
||||
const StyledLine = tui.StyledLine;
|
||||
|
|
@ -76,7 +76,7 @@ pub fn buildStyledLines(app: *App, arena: std.mem.Allocator) ![]const StyledLine
|
|||
/// Render analysis tab content. Pure function — no App dependency.
|
||||
pub fn renderAnalysisLines(
|
||||
arena: std.mem.Allocator,
|
||||
th: theme_mod.Theme,
|
||||
th: theme.Theme,
|
||||
analysis_result: ?zfin.analysis.AnalysisResult,
|
||||
) ![]const StyledLine {
|
||||
var lines: std.ArrayList(StyledLine) = .empty;
|
||||
|
|
@ -198,7 +198,7 @@ test "renderAnalysisLines with data" {
|
|||
var arena_state = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena_state.deinit();
|
||||
const arena = arena_state.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
var asset_class = [_]zfin.analysis.BreakdownItem{
|
||||
.{ .label = "US Stock", .weight = 0.60, .value = 120000 },
|
||||
|
|
@ -234,7 +234,7 @@ test "renderAnalysisLines no data" {
|
|||
var arena_state = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena_state.deinit();
|
||||
const arena = arena_state.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
const lines = try renderAnalysisLines(arena, th, null);
|
||||
try testing.expectEqual(@as(usize, 5), lines.len);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
const std = @import("std");
|
||||
const z2d = @import("z2d");
|
||||
const zfin = @import("../root.zig");
|
||||
const theme_mod = @import("theme.zig");
|
||||
const theme = @import("theme.zig");
|
||||
|
||||
const Surface = z2d.Surface;
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ pub fn renderChart(
|
|||
timeframe: Timeframe,
|
||||
width_px: u32,
|
||||
height_px: u32,
|
||||
th: theme_mod.Theme,
|
||||
th: theme.Theme,
|
||||
cached: ?*const CachedIndicators,
|
||||
) !ChartResult {
|
||||
if (candles.len < 20) return error.InsufficientData;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
const vaxis = @import("vaxis");
|
||||
const zfin = @import("../root.zig");
|
||||
const fmt = @import("../format.zig");
|
||||
const theme_mod = @import("theme.zig");
|
||||
const theme = @import("theme.zig");
|
||||
const tui = @import("../tui.zig");
|
||||
const App = tui.App;
|
||||
const StyledLine = tui.StyledLine;
|
||||
|
|
@ -60,7 +60,7 @@ pub fn buildStyledLines(app: *App, arena: std.mem.Allocator) ![]const StyledLine
|
|||
/// Render earnings tab content. Pure function — no App dependency.
|
||||
pub fn renderEarningsLines(
|
||||
arena: std.mem.Allocator,
|
||||
th: theme_mod.Theme,
|
||||
th: theme.Theme,
|
||||
symbol: []const u8,
|
||||
earnings_disabled: bool,
|
||||
earnings_data: ?[]const zfin.EarningsEvent,
|
||||
|
|
@ -130,7 +130,7 @@ test "renderEarningsLines with earnings data" {
|
|||
var arena_state = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena_state.deinit();
|
||||
const arena = arena_state.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
const events = [_]zfin.EarningsEvent{.{
|
||||
.symbol = "AAPL",
|
||||
|
|
@ -152,7 +152,7 @@ test "renderEarningsLines no symbol" {
|
|||
var arena_state = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena_state.deinit();
|
||||
const arena = arena_state.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
const lines = try renderEarningsLines(arena, th, "", false, null, 0, null);
|
||||
try testing.expectEqual(@as(usize, 2), lines.len);
|
||||
|
|
@ -163,7 +163,7 @@ test "renderEarningsLines disabled" {
|
|||
var arena_state = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena_state.deinit();
|
||||
const arena = arena_state.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
const lines = try renderEarningsLines(arena, th, "VTI", true, null, 0, null);
|
||||
try testing.expectEqual(@as(usize, 2), lines.len);
|
||||
|
|
@ -174,7 +174,7 @@ test "renderEarningsLines no data" {
|
|||
var arena_state = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena_state.deinit();
|
||||
const arena = arena_state.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
const lines = try renderEarningsLines(arena, th, "AAPL", false, null, 0, null);
|
||||
try testing.expectEqual(@as(usize, 4), lines.len);
|
||||
|
|
@ -185,7 +185,7 @@ test "renderEarningsLines with error message" {
|
|||
var arena_state = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena_state.deinit();
|
||||
const arena = arena_state.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
const lines = try renderEarningsLines(arena, th, "AAPL", false, null, 0, "No API key. Set FINNHUB_API_KEY");
|
||||
try testing.expectEqual(@as(usize, 4), lines.len);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const std = @import("std");
|
|||
const vaxis = @import("vaxis");
|
||||
const zfin = @import("../root.zig");
|
||||
const fmt = @import("../format.zig");
|
||||
const theme_mod = @import("theme.zig");
|
||||
const theme = @import("theme.zig");
|
||||
const tui = @import("../tui.zig");
|
||||
const history_io = @import("../history.zig");
|
||||
const timeline = @import("../analytics/timeline.zig");
|
||||
|
|
@ -85,7 +85,7 @@ pub fn buildStyledLines(app: *App, arena: std.mem.Allocator) ![]const StyledLine
|
|||
/// timeline series and the currently-selected metric.
|
||||
pub fn renderHistoryLines(
|
||||
arena: std.mem.Allocator,
|
||||
th: theme_mod.Theme,
|
||||
th: theme.Theme,
|
||||
series_opt: ?timeline.TimelineSeries,
|
||||
metric: timeline.Metric,
|
||||
) ![]const StyledLine {
|
||||
|
|
@ -176,7 +176,7 @@ pub fn renderHistoryLines(
|
|||
fn appendSummaryLine(
|
||||
arena: std.mem.Allocator,
|
||||
lines: *std.ArrayList(StyledLine),
|
||||
th: theme_mod.Theme,
|
||||
th: theme.Theme,
|
||||
label: []const u8,
|
||||
points: []const timeline.TimelinePoint,
|
||||
metric: timeline.Metric,
|
||||
|
|
@ -242,7 +242,7 @@ test "renderHistoryLines: no series shows no-data message" {
|
|||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const a = arena.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
const lines = try renderHistoryLines(a, th, null, .net_worth);
|
||||
var saw_no_data = false;
|
||||
|
|
@ -256,7 +256,7 @@ test "renderHistoryLines: renders summary + chart + table" {
|
|||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const a = arena.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
// Build a tiny timeline by hand (bypasses buildSeries + its snapshot
|
||||
// input). Two points: day1 and day2.
|
||||
|
|
@ -304,7 +304,7 @@ test "renderHistoryLines: metric switching changes chart label" {
|
|||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const a = arena.allocator();
|
||||
const th = theme_mod.default_theme;
|
||||
const th = theme.default_theme;
|
||||
|
||||
const pts = try a.alloc(timeline.TimelinePoint, 1);
|
||||
pts[0] = .{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
const vaxis = @import("vaxis");
|
||||
const zfin = @import("../root.zig");
|
||||
const fmt = @import("../format.zig");
|
||||
const theme_mod = @import("theme.zig");
|
||||
const theme = @import("theme.zig");
|
||||
const tui = @import("../tui.zig");
|
||||
|
||||
const App = tui.App;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||
const vaxis = @import("vaxis");
|
||||
const zfin = @import("../root.zig");
|
||||
const fmt = @import("../format.zig");
|
||||
const theme_mod = @import("theme.zig");
|
||||
const theme = @import("theme.zig");
|
||||
const tui = @import("../tui.zig");
|
||||
|
||||
const App = tui.App;
|
||||
|
|
@ -167,7 +167,7 @@ fn appendStyledReturnsTable(
|
|||
lines: *std.ArrayList(StyledLine),
|
||||
price: zfin.performance.TrailingReturns,
|
||||
total: ?zfin.performance.TrailingReturns,
|
||||
th: theme_mod.Theme,
|
||||
th: theme.Theme,
|
||||
) !void {
|
||||
const has_total = total != null;
|
||||
if (has_total) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const zfin = @import("../root.zig");
|
|||
const fmt = @import("../format.zig");
|
||||
const views = @import("../views/portfolio_sections.zig");
|
||||
const cli = @import("../commands/common.zig");
|
||||
const theme_mod = @import("theme.zig");
|
||||
const theme = @import("theme.zig");
|
||||
const tui = @import("../tui.zig");
|
||||
|
||||
const App = tui.App;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ const std = @import("std");
|
|||
const vaxis = @import("vaxis");
|
||||
const zfin = @import("../root.zig");
|
||||
const fmt = @import("../format.zig");
|
||||
const theme_mod = @import("theme.zig");
|
||||
const chart_mod = @import("chart.zig");
|
||||
const theme = @import("theme.zig");
|
||||
const chart = @import("chart.zig");
|
||||
const tui = @import("../tui.zig");
|
||||
|
||||
const App = tui.App;
|
||||
|
|
@ -77,7 +77,7 @@ fn drawWithKittyChart(app: *App, ctx: vaxis.vxfw.DrawContext, buf: []vaxis.Cell,
|
|||
const prefix = " Chart: ";
|
||||
@memcpy(tf_buf[tf_pos..][0..prefix.len], prefix);
|
||||
tf_pos += prefix.len;
|
||||
const timeframes = [_]chart_mod.Timeframe{ .@"6M", .ytd, .@"1Y", .@"3Y", .@"5Y" };
|
||||
const timeframes = [_]chart.Timeframe{ .@"6M", .ytd, .@"1Y", .@"3Y", .@"5Y" };
|
||||
for (timeframes) |tf| {
|
||||
const lbl = tf.label();
|
||||
if (tf == app.chart.timeframe) {
|
||||
|
|
@ -160,7 +160,7 @@ fn drawWithKittyChart(app: *App, ctx: vaxis.vxfw.DrawContext, buf: []vaxis.Cell,
|
|||
app.chart.freeCache(app.allocator);
|
||||
|
||||
// Compute and cache new indicators
|
||||
const new_cache = chart_mod.computeIndicators(
|
||||
const new_cache = chart.computeIndicators(
|
||||
app.allocator,
|
||||
c,
|
||||
app.chart.timeframe,
|
||||
|
|
@ -186,9 +186,9 @@ fn drawWithKittyChart(app: *App, ctx: vaxis.vxfw.DrawContext, buf: []vaxis.Cell,
|
|||
// because z2d allocates large pixel buffers that would bloat the arena.
|
||||
if (app.vx_app) |va| {
|
||||
// Pass cached indicators to avoid recomputation during rendering
|
||||
const cached_ptr: ?*const chart_mod.CachedIndicators = if (app.chart.cached_indicators) |*ci| ci else null;
|
||||
const cached_ptr: ?*const chart.CachedIndicators = if (app.chart.cached_indicators) |*ci| ci else null;
|
||||
|
||||
const chart_result = chart_mod.renderChart(
|
||||
const chart_result = chart.renderChart(
|
||||
app.allocator,
|
||||
c,
|
||||
app.chart.timeframe,
|
||||
|
|
@ -536,7 +536,7 @@ fn buildDetailColumns(
|
|||
|
||||
// Merge all columns into grapheme-based StyledLines
|
||||
const gap: usize = 3;
|
||||
const bg_style = vaxis.Style{ .fg = theme_mod.Theme.vcolor(th.text), .bg = theme_mod.Theme.vcolor(th.bg) };
|
||||
const bg_style = vaxis.Style{ .fg = theme.Theme.vcolor(th.text), .bg = theme.Theme.vcolor(th.bg) };
|
||||
const cols = [_]*const Column{ &col1, &col2, &col3, &col4 };
|
||||
var max_rows: usize = 0;
|
||||
for (cols) |col| max_rows = @max(max_rows, col.len());
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue