Skip to content

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

Open
zachthedev wants to merge 1 commit into
sirmalloc:mainfrom
zachthedev:fix-formattokens-trailing-zeros
Open

feat: configurable numeric precision (per-widget, type-aware, optional global)#456
zachthedev wants to merge 1 commit into
sirmalloc:mainfrom
zachthedev:fix-formattokens-trailing-zeros

Conversation

@zachthedev

@zachthedev zachthedev commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Closes #455

Replaces the rejected "always trim .0" approach (per the discussion here) with
configurable decimal precision for numeric widgets. Default output is unchanged.

Model

  • Per-widget numberFormat: { style?, decimals? } (top-level WidgetItem field,
    alongside dim/bold):
    • style: precise (keep trailing zeros, today's 1.0M) | compact (trim
      them: 1M, 1.1M) | whole (no decimals: 1M).
    • decimals: max places before style applies.
  • Optional per-kind global Settings.numberFormat (token, speed, percent,
    memory, cost). A kind set there wins over the per-widget value, same
    precedence as overrideForegroundColor / globalBold.
  • Type-aware baselines, so a token-oriented change never pulls money off two
    decimals: token/speed/percent default 1, cost 2, memory G:1 / M:0 / K:0.
  • resolveNumberFormat(kind, item, settings) is the single choke point; the
    pure formatters (formatTokens, formatSpeed, formatPercent, formatCost,
    memory) take the resolved format. Optional fields, so no settings migration.

Scope

Every numeric widget: tokens in/out/cached/total, context length/window/bar,
compaction reclaimed, cache read/write/hit, free memory, session cost,
input/output/total speed, context %/usable, the usage sliders (session, weekly,
weekly opus/sonnet, extra-usage), and the block/weekly timers.

TUI

  • Color menu: (n) cycles the highlighted widget's style (default -> compact ->
    whole); reset / clear-all also clear it.
  • Global overrides: (n) opens a per-type submenu to cycle each kind's style.
  • decimals is set per-widget / per-kind in settings.json (the power-user
    axis); the TUI exposes the style.

Tests

bun run lint clean; bun test green (1577). Default output is unchanged
(every existing widget/formatter assertion still passes); added coverage for the
format primitives, resolver precedence, and the TUI style cycle.

@CorticalCode

CorticalCode commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

@zachthedev

Hi, I wanted to advocate for leaving the decimal point in place. At first glance I figured yeah, that trailing zero shouldn't be there. But thinking about it, on a live status line it's actually doing a job: it holds the field width steady as the number climbs. Drop it and the width snaps every time the count crosses a whole unit (1M, then 1.1M, and so on), which ends up more distracting than the .0 it removes.

Claude Code keeps follows this behavior in its token count: past 999 the decimal is preserved through the zeros (e.g. 6.0k, not 6k).

Screenshot 2026-06-15 at 10 01 25 PM

@zachthedev

zachthedev commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

@zachthedev

Hi, I wanted to advocate for leaving the decimal point in place. At first glance I figured yeah, that trailing zero shouldn't be there. But thinking about it, on a live status line it's actually doing a job: it holds the field width steady as the number climbs. Drop it and the width snaps every time the count crosses a whole unit (1M, then 1.1M, and so on), which ends up more distracting than the .0 it removes.

Claude Code keeps it too in its token counter: past 999 the decimal is preservedthrough the zeros (e.g. 6.0k, not 6k).

Screenshot 2026-06-15 at 10 01 25 PM

That is a good point, it should be configurable honestly. I am going to rework it to be a per element or global config to have decimals or not. Instead of chopping off .0.

@sirmalloc

Copy link
Copy Markdown
Owner

@zachthedev i prefer this be a widget specific config, not global.

@zachthedev

Copy link
Copy Markdown
Contributor Author

@zachthedev i prefer this be a widget specific config, not global.

What about widget specific with a global override? If a user didn't want to manually configure every one.
Default would be as it is nowadays.

@zachthedev zachthedev marked this pull request as draft June 16, 2026 03:50
@sirmalloc

Copy link
Copy Markdown
Owner

@zachthedev i prefer this be a widget specific config, not global.

What about widget specific with a global override? If a user didn't want to manually configure every one. Default would be as it is nowadays.

What widgets would it impact? Anything displaying a number? It'll touch more widgets but if it makes sense I'm fine with it if it's done cleanly and doesn't modify existing default behavior.

@zachthedev

Copy link
Copy Markdown
Contributor Author

@zachthedev i prefer this be a widget specific config, not global.

What about widget specific with a global override? If a user didn't want to manually configure every one. Default would be as it is nowadays.

What widgets would it impact? Anything displaying a number? It'll touch more widgets but if it makes sense I'm fine with it if it's done cleanly and doesn't modify existing default behavior.

Yeah anything displaying a number. I marked this as a draft and will mess around with a few ideas.

Add a per-widget `numberFormat` ({ style: precise|compact|whole, decimals })
and an optional per-kind global (Settings.numberFormat), resolved by
resolveNumberFormat(kind, item, settings) with a set global winning over the
per-widget value (matching overrideForegroundColor / globalBold). Every numeric
formatter routes through renderMagnitude with a type-appropriate baseline, so
default output is unchanged: tokens/speed/percent stay 1 decimal, cost 2,
memory G1/M0/K0.

Styles: precise keeps trailing zeros (1.0M, today's default); compact trims
them (1M, 1.1M); whole drops decimals (1M).

Threaded through every numeric widget (tokens, context length/window/bar,
compaction reclaimed, cache read/write/hit, free memory, session cost, speeds,
context %, usage sliders, block/weekly timers). TUI: ColorMenu (n) cycles a
widget's style, Global Overrides has a per-type submenu, and decimals is set in
settings.json. Optional schema fields, so no settings migration.

Co-Authored-By: Claude <noreply@anthropic.com>
@zachthedev zachthedev force-pushed the fix-formattokens-trailing-zeros branch from 6e15df7 to cce85dd Compare June 16, 2026 05:59
@zachthedev zachthedev changed the title fix(format-tokens): drop pointless trailing ".0" from k/M output feat: configurable numeric precision (per-widget, type-aware, optional global) Jun 16, 2026
@zachthedev zachthedev marked this pull request as ready for review June 16, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

3 participants