Measure line one's branch budget instead of assuming 56 columns

In wrap mode the branch is truncated to whatever the rest of line one leaves,
and "the rest" was a flat 56 columns. It is not flat: the token counts and the
cost figure vary with the session, and with a four-digit cost the real width is
57, so line one came out exactly one column over and the renderer clipped it.
Reachable at COLUMNS 73-81 with padding 2 — a narrow split pane.

Add up the segments that follow the branch instead, from the same values that
render them, and count the ahead/behind markers too, which the constant also
ignored. That needs the cost formatted and the token bar width chosen before
the git segment is built, so both move up; neither depends on anything in
between.

The budget is now exact rather than approximate, so the branch also gets the
columns the old constant was over-reserving when the cost was short.

Tests: the large-cost sweep only used the short branch 'main', where the
overflow cannot show. Repeat it with the long branch, which fails on the old
budget at usable 68, 69, 70 and 75 by exactly one column.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jonny Barnes 2026-08-31 19:01:24 +01:00
commit 417542807b
No known key found for this signature in database
2 changed files with 29 additions and 11 deletions

View file

@ -302,6 +302,10 @@ format_reset_time() {
model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"') model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"')
cwd=$(echo "$input" | jq -r '.cwd // empty') cwd=$(echo "$input" | jq -r '.cwd // empty')
cost_usd=$(echo "$input" | jq -r '.cost.total_cost_usd // empty') cost_usd=$(echo "$input" | jq -r '.cost.total_cost_usd // empty')
# Formatted here rather than where it is rendered: the wrap-mode branch budget
# needs its width, and it is not fixed ("$4.61" vs "$1234.56").
cost_fmt=""
[ -n "$cost_usd" ] && cost_fmt=$(printf '%.2f' "$cost_usd" 2>/dev/null)
size=$(echo "$input" | jq -r '.context_window.context_window_size // 200000') size=$(echo "$input" | jq -r '.context_window.context_window_size // 200000')
[ "$size" -eq 0 ] 2>/dev/null && size=200000 [ "$size" -eq 0 ] 2>/dev/null && size=200000
@ -395,6 +399,11 @@ if [ "$width_tier" = "full" ] && [ -n "$cwd" ]; then
out+="${sep}${dim}$(esc_data "$display_dir")${reset}" out+="${sep}${dim}$(esc_data "$display_dir")${reset}"
fi fi
bar_w="$TOKEN_BAR_WIDTH"
[ "$width_tier" = "wide" ] && bar_w=6
[ "$width_tier" = "split" ] && bar_w=5
[ "$width_tier" = "narrow" ] && bar_w=4
# Git branch + dirty + ahead/behind # Git branch + dirty + ahead/behind
if $SHOW_GIT && [ -n "$cwd" ]; then if $SHOW_GIT && [ -n "$cwd" ]; then
git_info=$(get_git_info "$cwd") git_info=$(get_git_info "$cwd")
@ -406,11 +415,21 @@ if $SHOW_GIT && [ -n "$cwd" ]; then
[ "$width_tier" = "wide" ] && local_max=24 [ "$width_tier" = "wide" ] && local_max=24
[ "$width_tier" = "split" ] && local_max=18 [ "$width_tier" = "split" ] && local_max=18
[ "$width_tier" = "narrow" ] && local_max=12 [ "$width_tier" = "narrow" ] && local_max=12
# In wrap mode line one is model+branch+tokens+thinking+cost; with the # In wrap mode line one is
# shortened model name everything but the branch is ~56 cols, so give # model │ ⎇ branch ✔ ↑1 │ <bar> used/total pct% │ ◇ thinking │ $cost
# the branch whatever is left. # and the branch gets whatever the rest of it leaves. Everything after
# the branch is appended below, so its width is added up here rather
# than assumed: a flat 56 columns was three short of a four-digit cost,
# which pushed line one past the edge to be clipped by the renderer.
if $wrap_mode; then if $wrap_mode; then
local_max=$(( USABLE_WIDTH - 56 )) tail_len=$(( 5 + 2 )) # "│ ⎇ " and the dirty mark
[ "${g_ahead:-0}" -gt 0 ] && tail_len=$(( tail_len + 2 + ${#g_ahead} ))
[ "${g_behind:-0}" -gt 0 ] && tail_len=$(( tail_len + 2 + ${#g_behind} ))
$SHOW_TOKENS && tail_len=$(( tail_len + 3 + bar_w + 1 \
+ ${#used_tokens} + 1 + ${#total_tokens} + 1 + ${#pct_used} + 1 ))
$SHOW_THINKING && tail_len=$(( tail_len + 3 + 10 ))
[ -n "$cost_fmt" ] && tail_len=$(( tail_len + 3 + 1 + ${#cost_fmt} ))
local_max=$(( USABLE_WIDTH - $(vis_len "$out") - tail_len ))
[ "$local_max" -lt 8 ] && local_max=8 [ "$local_max" -lt 8 ] && local_max=8
[ "$local_max" -gt 24 ] && local_max=24 [ "$local_max" -gt 24 ] && local_max=24
fi fi
@ -434,10 +453,6 @@ fi
# Token bar # Token bar
if $SHOW_TOKENS; then if $SHOW_TOKENS; then
bar_w="$TOKEN_BAR_WIDTH"
[ "$width_tier" = "wide" ] && bar_w=6
[ "$width_tier" = "split" ] && bar_w=5
[ "$width_tier" = "narrow" ] && bar_w=4
token_bar=$(build_bar "$pct_used" "$bar_w") token_bar=$(build_bar "$pct_used" "$bar_w")
out+="${sep}${token_bar} ${orange}${used_tokens}${dim}/${reset}${white}${total_tokens}${reset} ${dim}${pct_used}%${reset}" out+="${sep}${token_bar} ${orange}${used_tokens}${dim}/${reset}${white}${total_tokens}${reset} ${dim}${pct_used}%${reset}"
fi fi
@ -458,9 +473,8 @@ if $SHOW_THINKING && [ "$width_tier" != "narrow" ]; then
fi fi
# Session cost — wide/full only # Session cost — wide/full only
if [ -n "$cost_usd" ] && [ "$width_tier" = "wide" -o "$width_tier" = "full" ]; then if [ -n "$cost_fmt" ] && [ "$width_tier" = "wide" -o "$width_tier" = "full" ]; then
cost_fmt=$(printf '%.2f' "$cost_usd" 2>/dev/null) out+="${sep}${dim}\$${cost_fmt}${reset}"
[ -n "$cost_fmt" ] && out+="${sep}${dim}\$${cost_fmt}${reset}"
fi fi
# ===== Rate limits (API, cached 60s) ===== # ===== Rate limits (API, cached 60s) =====

View file

@ -86,5 +86,9 @@ for u in 200 150 116 100 85 68; do check "$u" "$LONG" "$M2" 4.61; done
check 40 "$LONG" "$M2" 4.61 "narrow tier floor ~43 cols with a long branch" check 40 "$LONG" "$M2" 4.61 "narrow tier floor ~43 cols with a long branch"
echo "Large cost figure:" echo "Large cost figure:"
for u in 116 85 68; do check "$u" "$SHORT" "$M1" 1234.56; done for u in 116 85 68; do check "$u" "$SHORT" "$M1" 1234.56; done
# ... and with a long branch, which is what makes the wrap-mode branch budget
# bite: a four-digit cost is three columns wider than the budget assumed.
echo "Large cost figure with a long branch:"
for u in 68 69 70 75 85; do check "$u" "$LONG" "$M1" 1234.56; done
echo; echo "pass=$pass fail=$fail"; [ "$fail" -eq 0 ] echo; echo "pass=$pass fail=$fail"; [ "$fail" -eq 0 ]