alignment fixes in contributions
All checks were successful
Generic zig build / build (push) Successful in 5m15s
Generic zig build / publish-macos (push) Successful in 12s
Generic zig build / deploy (push) Successful in 20s

This commit is contained in:
Emil Lerch 2026-09-05 11:43:30 -07:00
parent cee557d55a
commit 23fd4e3b63
Signed by: lobo
GPG key ID: A7B62D657EF764F8

View file

@ -3274,13 +3274,10 @@ fn printReport(out: *std.Io.Writer, report: *const Report, label: []const u8, co
try printSection(out, "Lot edits (same position, key rewritten - not counted)", color, h_color);
for (report.changes) |c| switch (c.kind) {
.lot_edited => {
var buf: [256]u8 = undefined;
const msg = std.fmt.bufPrint(
&buf,
" {s:<14}{s:<30} (strict key broke, shares unchanged)\n",
.{ c.symbol, c.account },
) catch " (lot edit)\n";
try cli.printFg(out, color, mut_color, "{s}", .{msg});
try cli.setFg(out, color, mut_color);
try writeRowPrefix(out, c.symbol, c.account);
try out.writeAll(" (strict key broke, shares unchanged)\n");
try cli.reset(out, color);
},
else => {},
};
@ -3344,10 +3341,10 @@ fn printReport(out: *std.Io.Writer, report: *const Report, label: []const u8, co
total_cd_int += cd_int;
const acct_label = if (acct.len == 0) "(no account)" else acct;
// 30 to match the per-change rows above. `Fidelity Emil 401(k) Roth BL`
// is 28 characters, so 28 left zero gutter and the next field butted
// straight up against the name.
try out.print(" {s:<30}", .{acct_label});
// Same width and the same gutter guarantee as the per-change rows, minus
// the symbol column this section has no use for.
try out.writeAll(" ");
try padTo(out, acct_label, acct_w);
try printSummaryCell(out, " new", t.new_money, color);
try printSummaryCell(out, " drip", t.drip_confirmed, color);
try printSummaryCell(out, " rollup", t.rollup, color);
@ -3432,6 +3429,66 @@ fn printNone(out: *std.Io.Writer, color: bool, muted: [3]u8) !void {
try cli.printFg(out, color, muted, " (none)\n", .{});
}
/// Symbol column. 16 because `Engagement Ring` is 15 - illiquid assets carry
/// free-form names rather than tickers, so the old 14 was sized for a population
/// this report no longer only contains.
const sym_w = 16;
/// Account column. 30 because `Fidelity Emil 401(k) Roth BL` is 28.
const acct_w = 30;
/// Pad `s` into a `w`-wide field, always leaving at least one space behind it.
///
/// The guarantee is the point. `{s:<N}` OVERFLOWS instead of truncating, so a
/// single over-long value both shifted its own row right AND consumed the gutter,
/// welding itself to the next field. And no fixed `N` avoids it here: symbols in
/// this report run from a 3-character ticker to a 24-character option
/// (`AMZN 09/18/2026 280.00 C`), with hand-named illiquid assets in between. So
/// the widths above are chosen for the common case and this keeps the rare long
/// one readable - it loses its alignment, not its whitespace.
fn padTo(out: *std.Io.Writer, s: []const u8, w: usize) !void {
try out.writeAll(s);
try out.splatByteAll(' ', if (s.len >= w) 1 else w - s.len);
}
/// The ` symbol account ` prefix every per-change row opens with.
///
/// One function rather than a format-string literal repeated at fourteen call
/// sites. The literal is how the widths drifted out of step in the first place:
/// twelve rows said `{s:<14}{s:<24}`, the CD continuation said the same with
/// blank arguments, the lot-edit row said `{s: <12} {s: <24}`, and the account
/// summary said `{s:<28}` - four different answers to one question, and each new
/// long value found a different one of them.
///
/// Callers own the single space that follows, so content lands one column past
/// `acct_w`. Keep it: every section has to agree on that column or the report
/// shears between sections instead of within a row, which is harder to spot.
fn writeRowPrefix(out: *std.Io.Writer, symbol: []const u8, account: []const u8) !void {
try out.writeAll(" ");
try padTo(out, symbol, sym_w);
try padTo(out, account, acct_w);
}
test "padTo: pads short values to width and never welds a long one" {
var buf: [128]u8 = undefined;
// Short: padded to the column.
var w1 = std.Io.Writer.fixed(&buf);
try padTo(&w1, "CASH", 16);
try std.testing.expectEqualStrings("CASH ", w1.buffered());
// Exactly one under: still a gutter, and it is the last width that aligns.
var w2 = std.Io.Writer.fixed(&buf);
try padTo(&w2, "Engagement Ring", 16);
try std.testing.expectEqualStrings("Engagement Ring ", w2.buffered());
// Over: alignment is gone, whitespace is not. `{s:<16}` produced no space
// here at all, which ran the value into the next column.
var w3 = std.Io.Writer.fixed(&buf);
try padTo(&w3, "AMZN 09/18/2026 280.00 C", 16);
try std.testing.expectEqualStrings("AMZN 09/18/2026 280.00 C ", w3.buffered());
}
fn printTotalLine(out: *std.Io.Writer, label: []const u8, v: f64, color: bool, hdr: [3]u8) !void {
try cli.printFg(out, color, hdr, " {s}: {f}\n", .{ label, Money.from(v) });
}
@ -3445,7 +3502,7 @@ fn printChangeLine(out: *std.Io.Writer, c: Change, color: bool, pos: [3]u8) !voi
const val_str = std.fmt.bufPrint(&val_buf, "{f}", .{Money.from(c.value())}) catch "$?";
const acct = if (c.account.len == 0) "(no account)" else c.account;
try out.print(" {s:<14}{s:<30}", .{ c.symbol, acct });
try writeRowPrefix(out, c.symbol, acct);
if (c.security_type == .cash) {
try cli.printFg(out, color, pos, " {s}", .{val_str});
} else {
@ -3464,15 +3521,15 @@ fn printCdLine(out: *std.Io.Writer, c: Change, implied_interest: ?f64, color: bo
.cd_removed_early => "removed EARLY",
else => "removed",
};
try out.print(" {s:<14}{s:<30} {s:<16} face {f} maturity {s}\n", .{
c.symbol,
acct,
try writeRowPrefix(out, c.symbol, acct);
try out.print(" {s:<16} face {f} maturity {s}\n", .{
verb,
Money.from(c.face_value),
mat_str,
});
if (implied_interest) |i| {
try cli.printFg(out, color, cli.CLR_POSITIVE, " {s:<14}{s:<30} implied interest: {f}\n", .{ "", "", Money.from(i) });
try writeRowPrefix(out, "", "");
try cli.printFg(out, color, cli.CLR_POSITIVE, " implied interest: {f}\n", .{Money.from(i)});
}
}
@ -3480,7 +3537,8 @@ fn printCashDeltaLine(out: *std.Io.Writer, c: Change, report: *const Report, col
const v = c.value();
const acct = if (c.account.len == 0) "(no account)" else c.account;
const sign = if (v >= 0) "+" else "-";
try out.print(" {s:<14}{s:<30} cash ", .{ c.symbol, acct });
try writeRowPrefix(out, c.symbol, acct);
try out.writeAll(" cash ");
try cli.printGainLoss(out, color, v, "{s}{f}", .{ sign, Money.from(@abs(v)) });
// Hint if a CD matured in the same account.
@ -3495,9 +3553,9 @@ fn printCashDeltaLine(out: *std.Io.Writer, c: Change, report: *const Report, col
fn printPriceOnlyLine(out: *std.Io.Writer, c: Change, color: bool, muted: [3]u8) !void {
const acct = if (c.account.len == 0) "(no account)" else c.account;
try cli.printFg(out, color, muted, " {s:<14}{s:<30} price {f} -> {f}\n", .{
c.symbol,
acct,
try cli.setFg(out, color, muted);
try writeRowPrefix(out, c.symbol, acct);
try out.print(" price {f} -> {f}\n", .{
Money.from(c.old_price),
Money.from(c.new_price),
});
@ -3508,17 +3566,18 @@ fn printFlaggedLine(out: *std.Io.Writer, c: Change, color: bool, warn: [3]u8) !v
try cli.setFg(out, color, warn);
switch (c.kind) {
.flagged => {
try out.print(" {s:<14}{s:<30} {s}", .{ c.symbol, acct, c.detail orelse "edited" });
try writeRowPrefix(out, c.symbol, acct);
try out.print(" {s}", .{c.detail orelse "edited"});
},
.lot_removed => {
try out.print(" {s:<14}{s:<30} {s} lot removed (face {f})", .{
c.symbol, acct, @tagName(c.security_type), Money.from(c.face_value),
try writeRowPrefix(out, c.symbol, acct);
try out.print(" {s} lot removed (face {f})", .{
@tagName(c.security_type), Money.from(c.face_value),
});
},
.drip_negative => {
try out.print(" {s:<14}{s:<30} shares decreased on existing lot ({f})", .{
c.symbol, acct, Money.from(@abs(c.value())),
});
try writeRowPrefix(out, c.symbol, acct);
try out.print(" shares decreased on existing lot ({f})", .{Money.from(@abs(c.value()))});
},
else => {},
}
@ -3637,7 +3696,7 @@ fn printPartialTransferLine(out: *std.Io.Writer, c: Change, color: bool, pos: [3
const lot_value = c.value();
const sym = if (c.symbol.len > 0) c.symbol else "cash";
try out.print(" {s:<14}{s:<30}", .{ sym, acct });
try writeRowPrefix(out, sym, acct);
try cli.printFg(out, color, pos, " {f}", .{Money.from(residual)});
try cli.printFg(
out,
@ -3659,7 +3718,7 @@ fn printCashFundedResidualLine(out: *std.Io.Writer, c: Change, color: bool, pos:
const lot_value = c.value();
const sym = if (c.symbol.len > 0) c.symbol else "cash";
try out.print(" {s:<14}{s:<30}", .{ sym, acct });
try writeRowPrefix(out, sym, acct);
try cli.printFg(out, color, pos, " {f}", .{Money.from(residual)});
try cli.printFg(
out,
@ -3724,9 +3783,11 @@ fn printCollapsedSales(out: *std.Io.Writer, report: *const Report, color: bool,
// current-price proxy, so say which one the reader is looking at.
const basis: []const u8 = if (closed_in_place) "at close" else "at mark";
if (lots == 1) {
try out.print(" {s:<14}{s:<30} sold {s} ({f})", .{ c.symbol, acct, basis, Money.from(proceeds) });
try writeRowPrefix(out, c.symbol, acct);
try out.print(" sold {s} ({f})", .{ basis, Money.from(proceeds) });
} else {
try out.print(" {s:<14}{s:<30} sold {d} lots {s} ({f})", .{ c.symbol, acct, lots, basis, Money.from(proceeds) });
try writeRowPrefix(out, c.symbol, acct);
try out.print(" sold {d} lots {s} ({f})", .{ lots, basis, Money.from(proceeds) });
}
try cli.reset(out, color);
try out.writeAll("\n");
@ -3744,7 +3805,8 @@ fn printInternalPurchaseLine(out: *std.Io.Writer, c: Change, color: bool, muted:
const lot_value = c.value();
try cli.setFg(out, color, muted);
try out.print(" {s:<14}{s:<30} {f} from existing cash", .{ sym, acct, Money.from(c.internal_funded) });
try writeRowPrefix(out, sym, acct);
try out.print(" {f} from existing cash", .{Money.from(c.internal_funded)});
if (c.internal_funded + 0.005 < lot_value) {
try out.print(" (of {f} lot)", .{Money.from(lot_value)});
}