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) });
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// idempotent); safe to call every time.
|
||||
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);
|
||||
}
|
||||
|
||||
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" {
|
||||
var svc: DataService = .{
|
||||
.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| {
|
||||
resolved_pf_paths = rp;
|
||||
} 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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue