fix(statusline): make cost formatting locale-independent - #21
Merged
Conversation
Under a comma-decimal locale (LC_NUMERIC=fr_FR.UTF-8) the ledger reported $0.
Two independent defects compound:
1. costs.sh had no locale guard at all, so its awk emitted "19,779682" with a
comma and wrote that into the per-session cache. Downstream arithmetic then
coerced it to 0 -- `costs.sh today` returned 0 and `month` returned "0 0".
2. The render path interpolated the value into the awk PROGRAM TEXT:
LC_NUMERIC=C awk "BEGIN{printf \"%.2f\",19,779682}" -> 19.00
The LC_NUMERIC=C guard was on the wrong side: it fixes output formatting,
but by then the comma is syntax and printf sees two arguments.
Fix:
- export LC_ALL=C at the top of costs.sh and statusline-command.sh so every
awk/printf emits dot decimals regardless of the user's locale.
- fmt_usd (format.sh) and cost_fmt (render.sh) now pass the value via `awk -v`
and normalise a stray comma, so a bad value can never become syntax.
Verified on a fr_FR.UTF-8 host: `costs.sh today` 0 -> 76.543286;
fmt_usd "19,779682" $19.00 -> $19.78; fmt_usd "19.779682" -> $19.78 (unchanged).
Existing caches written with comma decimals must be purged once; they
regenerate with dot decimals on the next refresh.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMNwLEZS6SsrWMLwd1cQ6p
export LC_ALL=C pinned LC_CTYPE as well, and vislen() measures with ${#s}.
Under LC_CTYPE=C that counts UTF-8 bytes instead of columns, so a 3-byte
glyph read as width 3 and a 10-glyph bar as width 30 — 7 fit/vislen tests
failed in CI.
Force LC_NUMERIC=C alone, which is the only category the comma-decimal
defect needs. LC_ALL is unset first because it outranks LC_NUMERIC when
the environment sets it.
Verified: tests/statusline/test_fit_and_pace.sh 53/53 under both
LC_ALL=fr_FR.UTF-8 and LC_ALL=C; costs.sh today emits a dot decimal under
fr_FR; vislen of a 10-glyph bar is 10.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMNwLEZS6SsrWMLwd1cQ6p
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On a host with a comma-decimal locale (
LC_NUMERIC=fr_FR.UTF-8) the statusline cost ledger reported$0. Two independent defects compound.1.
costs.shhad no locale guard (grep -c LC_NUMERIC costs.sh→ 0). Itsawkemitted19,779682and wrote that comma value into the per-session cache; downstream arithmetic coerced it to 0.2. The render path interpolated the value into the awk program text, so
LC_NUMERIC=Cwas applied on the wrong side — by then the comma is syntax, not data:Fix
export LC_ALL=Cat the top ofcosts.shandstatusline-command.sh— everyawk/printfemits dot decimals regardless of the user's locale. Only numeric format specifiers (%Y-%m-%d,%02d) are used elsewhere, so date output is unaffected.fmt_usd(format.sh) andcost_fmt(render.sh) now pass the value viaawk -vand normalise a stray comma, so a malformed value can never become program syntax.Verification
Measured on a
fr_FR.UTF-8host, before → after:costs.sh today076.543286costs.sh month0 076.543286 76.543286fmt_usd 19,779682$19.00$19.78fmt_usd 19.779682$19.78$19.78(unchanged)fmt_usd 1234.5$1.2k$1.2k(unchanged)bash -nclean on all four files.Upgrade note
Caches already written with comma decimals must be purged once — they regenerate with dot decimals on the next refresh:
Regression origin
The previous monolithic
statusline-command.shread.cost.total_cost_usdstraight from the payload — a JSON number, locale-independent. The modular refactor introduced thecosts.shledger layer, which was not locale-safe.🤖 Generated with Claude Code
https://claude.ai/code/session_01JMNwLEZS6SsrWMLwd1cQ6p