add name when loading quote without a portfolio
This commit is contained in:
parent
8e0288d437
commit
128085eefc
2 changed files with 75 additions and 0 deletions
|
|
@ -447,6 +447,33 @@ pub fn invalidateClassificationMap(self: *PortfolioData) void {
|
||||||
self.classification_map_future = self.io.async(classificationMapWorker, .{ self, @as(usize, 0) });
|
self.classification_map_future = self.io.async(classificationMapWorker, .{ self, @as(usize, 0) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prime ONLY the `metadata.srf` classification map for `paths_in`,
|
||||||
|
/// without the full `load()` (no price fetch, no summary, no
|
||||||
|
/// candle/dividend/account workers). Spawns the same
|
||||||
|
/// `classificationMapWorker` that `load()` uses, so a subsequent
|
||||||
|
/// `classificationMap()` resolves curated security names identically.
|
||||||
|
///
|
||||||
|
/// Used by the TUI's explicit-symbol launch (`zfin AAPL`), which skips
|
||||||
|
/// the portfolio load entirely but still wants the quote tab (and the
|
||||||
|
/// 'K' overlay) to show the `metadata.srf` security name the way the CLI
|
||||||
|
/// `quote` command does. No-op when `paths_in` is empty or a portfolio
|
||||||
|
/// is already loaded (a full `load()` populates the map itself).
|
||||||
|
pub fn primeClassificationMap(self: *PortfolioData, paths_in: []const []const u8) void {
|
||||||
|
if (paths_in.len == 0 or self.paths.len != 0) return;
|
||||||
|
|
||||||
|
// Dupe the anchor paths into the per-load arena so `anchorPath()`
|
||||||
|
// (and the worker's metadata.srf derivation) outlive `paths_in`.
|
||||||
|
const arena_alloc = self.allocator();
|
||||||
|
const paths_dup = arena_alloc.alloc([]const u8, paths_in.len) catch return;
|
||||||
|
for (paths_in, 0..) |p, i| {
|
||||||
|
paths_dup[i] = arena_alloc.dupe(u8, p) catch return;
|
||||||
|
}
|
||||||
|
self.paths = paths_dup;
|
||||||
|
|
||||||
|
if (self.classification_map_future) |*f| _ = f.cancel(self.io);
|
||||||
|
self.classification_map_future = self.io.async(classificationMapWorker, .{ self, @as(usize, 0) });
|
||||||
|
}
|
||||||
|
|
||||||
/// Drain a worker future. Idempotent (Future.await is itself
|
/// Drain a worker future. Idempotent (Future.await is itself
|
||||||
/// idempotent); safe to call every time.
|
/// idempotent); safe to call every time.
|
||||||
fn awaitWorker(self: *PortfolioData, fut: *?std.Io.Future(void)) void {
|
fn awaitWorker(self: *PortfolioData, fut: *?std.Io.Future(void)) void {
|
||||||
|
|
@ -984,6 +1011,43 @@ test "PortfolioData.cancelLoad: idempotent on idle state" {
|
||||||
try testing.expect(pd.classification_map_data == null);
|
try testing.expect(pd.classification_map_data == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "PortfolioData.primeClassificationMap: spawns the classification worker without a full load" {
|
||||||
|
var svc: DataService = .{
|
||||||
|
.allocator = testing.allocator,
|
||||||
|
.io = testing.io,
|
||||||
|
.config = .{ .cache_dir = "./.tmp/zfin-pd-prime-cache" },
|
||||||
|
};
|
||||||
|
var pd = PortfolioData.init(.{ .gpa = testing.allocator, .io = testing.io, .svc = &svc });
|
||||||
|
defer pd.deinit();
|
||||||
|
|
||||||
|
// Explicit-symbol launch shape: nothing loaded yet, so the map is
|
||||||
|
// null - exactly the state that left the TUI quote tab nameless.
|
||||||
|
try testing.expectEqual(@as(usize, 0), pd.paths.len);
|
||||||
|
try testing.expect(pd.classification_map_future == null);
|
||||||
|
try testing.expect(pd.classificationMap() == null);
|
||||||
|
|
||||||
|
// Empty paths: no-op (still nothing loaded).
|
||||||
|
pd.primeClassificationMap(&.{});
|
||||||
|
try testing.expectEqual(@as(usize, 0), pd.paths.len);
|
||||||
|
try testing.expect(pd.classification_map_future == null);
|
||||||
|
|
||||||
|
// A real anchor sets the path and spawns the SAME worker `load()`
|
||||||
|
// uses, so a later `classificationMap()` reads metadata.srf and
|
||||||
|
// resolves the curated name the way the CLI does.
|
||||||
|
pd.primeClassificationMap(&.{"./.tmp/zfin-pd-prime-test/portfolio.srf"});
|
||||||
|
try testing.expectEqual(@as(usize, 1), pd.paths.len);
|
||||||
|
try testing.expect(pd.classification_map_future != null);
|
||||||
|
try testing.expectEqualStrings("./.tmp/zfin-pd-prime-test/portfolio.srf", pd.anchorPath().?);
|
||||||
|
|
||||||
|
// Already primed: a second call must not clobber the loaded paths.
|
||||||
|
pd.primeClassificationMap(&.{"./.tmp/other/portfolio.srf"});
|
||||||
|
try testing.expectEqual(@as(usize, 1), pd.paths.len);
|
||||||
|
try testing.expectEqualStrings("./.tmp/zfin-pd-prime-test/portfolio.srf", pd.anchorPath().?);
|
||||||
|
|
||||||
|
// Drain the spawned worker so teardown leaves no dangling future.
|
||||||
|
_ = pd.classificationMap();
|
||||||
|
}
|
||||||
|
|
||||||
test "PortfolioData.candles: returns null after cancelLoad with no data" {
|
test "PortfolioData.candles: returns null after cancelLoad with no data" {
|
||||||
var svc: DataService = .{
|
var svc: DataService = .{
|
||||||
.allocator = testing.allocator,
|
.allocator = testing.allocator,
|
||||||
|
|
|
||||||
11
src/tui.zig
11
src/tui.zig
|
|
@ -2556,6 +2556,17 @@ pub fn run(
|
||||||
if (framework.resolvePatterns(io, allocator, config, portfolio_patterns)) |rp| {
|
if (framework.resolvePatterns(io, allocator, config, portfolio_patterns)) |rp| {
|
||||||
resolved_pf_paths = rp;
|
resolved_pf_paths = rp;
|
||||||
} else |_| {}
|
} else |_| {}
|
||||||
|
} else {
|
||||||
|
// Explicit-symbol launch (e.g. `zfin AAPL`) skips the full
|
||||||
|
// portfolio load below, but the quote tab (and the 'K' overlay)
|
||||||
|
// still want the curated security name from metadata.srf - same
|
||||||
|
// as the CLI `quote` command. Prime just the classification map
|
||||||
|
// (no price fetch) so classificationMap() resolves the name.
|
||||||
|
if (framework.resolvePatterns(io, allocator, config, portfolio_patterns)) |rp| {
|
||||||
|
var rp_owned = rp;
|
||||||
|
defer rp_owned.deinit();
|
||||||
|
app_inst.portfolio.primeClassificationMap(rp_owned.paths);
|
||||||
|
} else |_| {}
|
||||||
}
|
}
|
||||||
|
|
||||||
var resolved_wl: ?zfin.Config.ResolvedPath = null;
|
var resolved_wl: ?zfin.Config.ResolvedPath = null;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue