Skip to content

feat(context_bar): reveal text as the bar fills - #207

Open
AlexS-scale wants to merge 3 commits into
stephenleo:mainfrom
AlexS-scale:AlexS/context-bar-filled-text
Open

AlexS-scale wants to merge 3 commits into
stephenleo:mainfrom
AlexS-scale:AlexS/context-bar-filled-text

Conversation

@AlexS-scale

@AlexS-scale AlexS-scale commented Sep 25, 2026 •

Copy link
Copy Markdown

Adds four optional [cship.context_bar] fields:

  • filled_text: fills the bar with successive characters of a string instead of repeating filled_char, so the bar can spell out a word as the context window fills (CONTEXT░░░░░░░ 50%).
  • full_at: the percentage at which the bar is drawn full (default 100). Claude Code auto-compacts before the window reaches 100%, so a bar scaled to 100% never completes.
  • filled_style / track_style: style the filled slots and the track separately. Text on a track needs different styles for the letters and the track; today one style covers the whole bar and the percentage.

With none of the fields set, output is unchanged: every existing test fixture renders byte-identically to main. Docs, FAQ, CHANGELOG and schema are updated.

Fill levels:
01-filling-up

Before/after:
02-before-after

Animation:
03-filling-up

Add `filled_text`, which fills the bar with successive characters of a
string instead of repeating `filled_char`, so the bar can spell out a
word or phrase as the context window fills. The bar is as wide as the
text, so `width` is ignored.

  [cship.context_bar]
  filled_text = "CONTEXT WINDOW"   # CONTEXT░░░░░░░ 50%

Each slot is one visible character: zero-width characters such as
combining accents join the character before them, and the track takes
the hidden text's display width, so wide characters don't make the bar
grow as it fills. A `filled_text` with no visible characters is ignored with a warn-once
diagnostic, like `family_style`'s empty key.
Add `full_at`, the percentage at which the bar is drawn full (default
100). Claude Code auto-compacts before the context window reaches 100%,
so a bar scaled to 100% never completes; setting `full_at` to your
auto-compact point fills it in time.
Thresholds still compare the real percentage, and a `full_at` at or
below 0 is ignored with a warn-once diagnostic.
Add `filled_style` and `track_style`, which style the filled slots and
the empty slots (the track) on their own instead of sharing one style
with the percentage. The threshold style then covers only the
percentage, and each unset part style falls back to it, so a bar can
keep a fixed look while its percentage still escalates:

  [cship.context_bar]
  filled_text  = "CONTEXT WINDOW"
  filled_style = "bold fg:#FFFFFF bg:#4C4C4C"
  track_style  = "fg:#929292 bg:#000000"

The painted parts are never wrapped in an outer style, because an outer
style's attributes such as bold would otherwise leak into parts that
don't reset them: a `format` string's `$style` is left empty for them,
and the bar starts from a reset, so a style written directly in `format`
doesn't reach it (documented). With neither field set, the existing
format and default paths run unchanged. `empty_style` still covers the
no-data state. An empty part (the text at 0%, the track at 100%) is left
out rather than painted as bare escape codes. Adds a FAQ entry and an
end-to-end CLI test with a TOML fixture.
@AlexS-scale
AlexS-scale force-pushed the AlexS/context-bar-filled-text branch from 6f72c01 to 765cc49 Compare September 25, 2026 15:35
@AlexS-scale
AlexS-scale force-pushed the AlexS/context-bar-filled-text branch from 765cc49 to 46f27b7 Compare October 20, 2026 18:04
@AlexS-scale
AlexS-scale marked this pull request as ready for review October 20, 2026 18:13
@AlexS-scale

Copy link
Copy Markdown
Author

@stephenleo could you please review? Happy to add/change anything if needed.

@stephenleo

Copy link
Copy Markdown
Owner

@AlexS-scale thanks for the PR! A code review turned up a few things in src/modules/context_bar.rs:

Bugs

  1. Control chars leak (~L196): text_slots keeps escape/control characters as slots, so filled_text = "\x1b[31mCONTEXT" can emit a lone ESC / ESC[ at low fill, and \n breaks the line. Suggest running it through ansi::sanitize_control first.
  2. Leading zero-width char (~L197): "\u{301}AB" gives 3 slots for 2 visible columns; one fill step shows nothing.
  3. Wide empty_char (~L86): with empty_char = "⬜" the bar is 14 cols at 0% but 7 at 100%, so the status line jumps. Repeat track_width / display_width(empty_char) times.
  4. full_at validation (~L56): inf is accepted silently (bar never fills); nan hits the "must be above 0" warning. Use pct.is_finite() && pct > 0.0.
  5. Format span style dropped (~L147): with track_style set, [ $value ](bg:blue) loses bg:blue after the bar because of the per-part resets, which breaks powerline-style formats.
  6. $style silently empty (~L128): once filled_style/track_style is set, [CTX $symbol$value]($style) loses the threshold colour on CTX with no warning.

Cleanups
7. Warn-once duplication (~L38): the AtomicBool warn-once block is now in 3 places (incl. model.rs:35); a small helper would cover all of them.
8. Duplicated dispatch (~L117): the part-style branch repeats the resolve_threshold_style call and the format/no-format dispatch.
9. Allocation (~L86): slots[filled..].concat() allocates only to measure width; summing display_width over the slots avoids it.

🤖 Generated with Claude Code

This branch has not been deployed

No deployments
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.

2 participants