Skip to content

feat: configurable numeric precision (per-widget, type-aware, optional global) #455

Description

@zachthedev

Problem

The numeric formatters render a fixed decimal count, so whole values carry a
trailing .0: 1.0M, 512.0k, 100.0%, 50.0 t/s. Blanket-stripping it
(the original #456) was rejected: the fixed width stops the field from snapping
as a value crosses a whole unit (1M -> 1.1M -> ...), which Claude Code
itself preserves (6.0k). The fix is to make precision configurable, not to
change the default.

Proposal

A per-widget number-format setting, type-aware, with an optional global.
Default output is unchanged.

Format: numberFormat = { style?, decimals? }

  • style: precise (keep trailing zeros, today: 1.0M) | compact (drop
    trailing zeros, keep real fractions: 1M, 1.1M) | whole (no decimals: 1M)
  • decimals: max places before style applies (precise + 2 -> 1.00M)

Type-aware defaults

Each numeric widget has a number kind with its own default, so one setting
does the right thing per type:

kind widgets default
token tokens in/out/cached/total, context length, context-bar count, compaction reclaimed, cache read/write precise, 1 (1.0M)
speed input/output/total speed precise, 1 (50.0 t/s)
percent context %, cache hit %, usage/utilization/reset sliders precise, 1 (84.5%)
memory free memory current (G: 1, M/K: 0)
cost session cost precise, 2 ($1.20)

So tokens can be xxx.x while money stays xxx.xx: cost defaults to 2 and a
token-oriented change won't pull it to 1.

Precedence

effective = global[kind] (if set) -> widget.numberFormat (if set) -> kind default

Per-widget is the primary control. The global is optional and off by default;
when set it wins, the same way overrideForegroundColor / globalBold already
do. With nothing set, every widget renders exactly as today.

Scope

formatTokens + consumers, formatSpeed, FreeMemory, the toFixed(1)%
percentage sites, SessionCost.

Implementation notes

  • numberFormat is an optional top-level WidgetItem field (parallel to
    dim/bold); global is an optional per-kind Settings field. Optional, so
    no settings-version migration; absent = current behavior.
  • One resolveNumberFormat(kind, item, settings) choke point; pure formatters
    take the resolved { style, decimals }; shared helpers take it as a param.
    Precision is resolved at render time (it can't be a post-render pass like
    color/bold).
  • TUI: per-widget affordance in the editor (like (d) for dim) + a global
    entry in the overrides menu.

Non-goals

  • No change to default output. Cost stays 2-decimal by default.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions