Repository navigation
fix: draw the text cursor as a bar so trailing spaces show - #710
Merged
Merged
Conversation
The label editor quotes the label so a trailing space stays visible, but
the cursor was a highlighted block: over a character, or a highlighted
space after the text when at the end. So a label ending in a space with
the cursor on it ("Weekly:" + block) looked the same as a label with no
space and the cursor past the end ("7d" + block), and "7d" read as "7d ".
Draw the cursor as a bar between characters instead. It never covers a
character, so a trailing space shows as a gap before it, and the end of
the text adds nothing that looks like a space. Custom Text shares the
cursor, so it gets the bar too.
Owner
|
I'm not a huge fan of it. To fix the root issue I've just modified the TUI to realtime update the statusline preview as the labels are being edited, so it's obvious if a space is missing or not. I also added a blink to the cursor to make it more 'cursor-like'. But without moving to controlling the terminal native cursor throughout the app, I think this is the best fit. I wasn't a fan of how the line cursor shifted letters around it as you moved it. |
axisrow
added a commit
to axisrow/ccstatusline
that referenced
this pull request
Oct 15, 2026
…rs (#64) * chore(deps-dev): bump vitest from 4.1.11 to 5.0.0 (sirmalloc#723) Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.11 to 5.0.0. - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.0/packages/vitest) --- updated-dependencies: - dependency-name: vitest dependency-version: 5.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump react-devtools-core from 7.0.1 to 8.0.0 (sirmalloc#722) Bumps [react-devtools-core](https://github.com/react/react/tree/HEAD/packages/react-devtools-core) from 7.0.1 to 8.0.0. - [Release notes](https://github.com/react/react/releases) - [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/react/react/commits/[email protected]/packages/react-devtools-core) --- updated-dependencies: - dependency-name: react-devtools-core dependency-version: 8.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump actions/setup-node from 7.0.0 to 7.1.0 (sirmalloc#720) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 7.0.0 to 7.1.0. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](actions/setup-node@8207627...949feb2) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: 7.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps-dev): bump the dev-dependencies group across 1 directory with 6 updates (sirmalloc#733) Bumps the dev-dependencies group with 6 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@remotion/cli](https://github.com/remotion-dev/remotion) | `4.0.532` | `4.0.534` | | [eslint](https://github.com/eslint/eslint) | `10.11.0` | `10.12.0` | | [globals](https://github.com/sindresorhus/globals) | `17.12.0` | `17.13.0` | | [remotion](https://github.com/remotion-dev/remotion) | `4.0.532` | `4.0.534` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.70.1` | `8.71.1` | | [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `5.0.0` | `5.0.3` | Updates `@remotion/cli` from 4.0.532 to 4.0.534 - [Release notes](https://github.com/remotion-dev/remotion/releases) - [Commits](remotion-dev/remotion@v4.0.532...v4.0.534) Updates `eslint` from 10.11.0 to 10.12.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](eslint/eslint@v10.11.0...v10.12.0) Updates `globals` from 17.12.0 to 17.13.0 - [Release notes](https://github.com/sindresorhus/globals/releases) - [Commits](sindresorhus/globals@v17.12.0...v17.13.0) Updates `remotion` from 4.0.532 to 4.0.534 - [Release notes](https://github.com/remotion-dev/remotion/releases) - [Commits](remotion-dev/remotion@v4.0.532...v4.0.534) Updates `typescript-eslint` from 8.70.1 to 8.71.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.71.1/packages/typescript-eslint) Updates `vitest` from 5.0.0 to 5.0.3 - [Release notes](https://github.com/vitest-dev/vitest/releases) - [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md) - [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.3/packages/vitest) --- updated-dependencies: - dependency-name: "@remotion/cli" dependency-version: 4.0.534 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: eslint dependency-version: 10.12.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: globals dependency-version: 17.13.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: remotion dependency-version: 4.0.534 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: typescript-eslint dependency-version: 8.71.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: vitest dependency-version: 5.0.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(usage): add Spend Limit Usage and Spend Limit Amount widgets (sirmalloc#695) Claude Code 2.1.251 added rate_limits.spend_limit to the status line payload for developers behind a Claude apps gateway. Parse it and show it with two widgets that read the payload only and never call the usage API. Closes sirmalloc#572 Co-authored-by: Matthew Breedlove <[email protected]> * fix: draw the text cursor as a bar so trailing spaces show (sirmalloc#710) * fix: draw the text cursor as a bar so trailing spaces show The label editor quotes the label so a trailing space stays visible, but the cursor was a highlighted block: over a character, or a highlighted space after the text when at the end. So a label ending in a space with the cursor on it ("Weekly:" + block) looked the same as a label with no space and the cursor past the end ("7d" + block), and "7d" read as "7d ". Draw the cursor as a bar between characters instead. It never covers a character, so a trailing space shows as a gap before it, and the end of the text adds nothing that looks like a space. Custom Text shares the cursor, so it gets the bar too. * feat(tui): preview label edits live and blink editor cursors --------- Co-authored-by: Matthew Breedlove <[email protected]> * fix(usage): call Session Usage Block Usage, ending its "Session:" label clash (sirmalloc#708) * fix(usage): call Session Usage Block Usage, ending its "Session:" label clash Three widgets printed the label "Session: " and meant two different things by it. Session Clock and Session Name mean the Claude Code conversation; Session Usage meant the 5-hour usage window. On one line, "Session: 42% | Session: 1hr 5m" reads as two facts about the same session when they aren't. The 5-hour window already has a name here: Block Timer and Block Reset Timer call it the block. Session Usage becomes Block Usage, labeled "Block: ", with the description "Shows the current 5-hour block's usage percentage". Its type stays session-usage, so saved configs keep working, and anyone who prefers the old label can set "Session: " back with the label editor (e). The docs follow; past release notes keep the name they shipped with. * fix(usage): label Block Usage "5h: " rather than "Block: " "Block: " is already Block Timer's label, for the block's elapsed time ("Block: 3hr 45m"), so Block Usage beside it would print two "Block:" figures. Label it "5h: " instead, which says which window the percent is of and pairs with Weekly Usage's "Weekly: ". The name stays Block Usage, and a "Session: " override still sets the old label back. --------- Co-authored-by: Matthew Breedlove <[email protected]> * fix: keep 8-bit color codes, strip them, and drop other 8-bit sequences whole (sirmalloc#704) * fix(ansi): strip 8-bit color codes as well as ESC [ ones The ANSI parser reads the 8-bit CSI (0x9b) as an escape sequence, but stripSgrCodes only matched color codes written with ESC [. Text colored with \x9b31m kept its colors where they should go: a global foreground override left a preserveColors widget's own colors in place, and a Custom Command cut by its max width never got its closing reset, so its color ran into the separators and widgets after it. Match both introducers. restoreBackgroundAfterResets shares the pattern, so an 8-bit reset now gets the background re-applied after it too; its parameter parsing skips a one-character introducer for those. * fix(sanitize): keep 8-bit color codes and drop other 8-bit sequences whole The terminal sanitizer dropped 8-bit C1 controls one character at a time. For a sequence started by one, that removed only the introducer and left the rest as text: a command printing \x9b31mred\x9b39m showed "31mred39m", and an 8-bit hyperlink or title string showed its URL or payload. Read each 8-bit introducer as the ESC sequence it stands for: CSI (0x9b) as ESC [, OSC (0x9d) as ESC ], and DCS, SOS, PM and APC likewise, with ST (0x9c) ending strings. Color codes and safe hyperlinks are kept, in their 7-bit form, which every terminal reads and the rest of the renderer parses; any other sequence is dropped whole. Lone 8-bit controls that start no sequence, such as NEL or a stray ST, are still dropped. * feat(claude-status): optionally link the widget to the status page (sirmalloc#701) * feat(claude-status): optionally link the widget to the status page Claude Status shows "minor" or "major" when something's wrong, but the details are on status.claude.com, which you have to look up. Git Branch and Git Root Dir can already link to the repo or IDE. Press `l` on Claude Status to make the whole widget an OSC 8 hyperlink to https://status.claude.com, the site it reads the status from: label, status and the history strip, and an unknown "?" too, when the page is most worth a look. It's off by default, like the other links, and the editor row shows "status link". Terminals without OSC 8 support show the text as before. * fix(preview): preserve enabled widget hyperlinks --------- Co-authored-by: Matthew Breedlove <[email protected]> * fix(powerline): detect Nerd Fonts v3 names and fonts in font subfolders checkPowerlineFonts() scanned only the top level of the font folders and required a spaced "nerd font" pattern, so common layouts were reported as missing: Nerd Fonts v3 file names have no spaces ("JetBrainsMonoNerdFont-Regular.ttf"), the short "NF" form exists ("JetBrainsMonoNF-Regular.ttf"), and font managers nest fonts in subfolders ("NerdFonts/", "TTF/", Debian's /usr/share/fonts/opentype/PowerlineSymbols.otf). Match "nerd ?font" and an "NF" token, and scan the font folders recursively with a depth cap. Co-Authored-By: Claude Code <[email protected]> * chore: retrigger CI after merge * chore: probe CI trigger * chore: probe CI trigger after actions re-enable * chore: probe CI trigger after fork workflows re-enable * fix: align tests and compact labels with merged upstream changes Three merge fallouts after merging origin/main into the PR branch: - upstream-terminal-sanitize: upstream c08a59d drops an 8-bit C1 CSI sequence whole (terminals consume it as one unit), so \x9b2J no longer leaves 2J as text; expect 'okx'. - usage-prefetch: the fork's async providers pass a cache handle in every fetchUsageData call; the upstream spend-limit test now uses the same anyCacheMatcher() as the neighboring assertions. - compact labels: upstream 6e148cb renamed the session usage label from "Session:" to "5h:", so the compact-label probe dropped the widget; add the '5h: ' preset. Co-Authored-By: Claude Code <[email protected]> --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mert Kaya <[email protected]> Co-authored-by: Matthew Breedlove <[email protected]> Co-authored-by: eric-engberg <[email protected]> Co-authored-by: axisrow <[email protected]> Co-authored-by: Claude Code <[email protected]>
axisrow
added a commit
to axisrow/ccstatusline
that referenced
this pull request
Oct 20, 2026
…sirmalloc#704/sirmalloc#708/sirmalloc#710, dep bumps) Upstream cursor-bar fix (sirmalloc#710) ported into fork lazy editors in src/widgets/editors/. Fork compaction-counter no-space glyph and usage-prefetch cache matcher kept. Co-Authored-By: Claude Code <[email protected]>
axisrow
added a commit
to axisrow/ccstatusline
that referenced
this pull request
Oct 20, 2026
BlinkingCursor replaces the inverse-space caret in Link/CustomCommand/CustomSymbol/Skills/CurrentWorkingDir/MaxWidth/SpeedWindow/SymbolSlots editors. Co-Authored-By: Claude Code <[email protected]>
pcvelz
added a commit
to pcvelz/ccstatusline-usage
that referenced
this pull request
Oct 21, 2026
Upstream: - Spend Limit Usage and Spend Limit Amount widgets (sirmalloc#695) - Session Usage renamed to Block Usage, ending its Session label clash (sirmalloc#708) - keep 8-bit color codes, strip them, drop other 8-bit sequences whole (sirmalloc#704) - text cursor drawn as a bar so trailing spaces show (sirmalloc#710) - Claude Status widget optionally links to the status page (sirmalloc#701) - dependency bumps: vitest major (sirmalloc#723), react-devtools-core major (sirmalloc#722), actions/setup-node (sirmalloc#720), dev-dependencies group (sirmalloc#733) Conflict resolutions: - .github/workflows/publish.yml, docs/DEVELOPMENT.md, docs/USAGE.md: kept deleted (.fork-keep-deleted) - src/types/RenderContext.ts, src/utils/usage-types.ts: fork weeklyFableUsage fields kept, upstream spendLimit fields added; upstream fableUsage fields dropped (their FableWeeklyUsage widget is fork-deleted) - src/utils/widget-manifest.ts, src/widgets/index.ts: spend-limit widgets added; upstream fable-weekly-usage dropped (fork-deleted), fork keeps its own reset-timer entry - src/widgets/shared/usage-percent-widget.ts: fork fable-weekly kind kept, upstream spend-limit kind added - src/utils/usage-prefetch.ts: fork per-item requirements and API-sourced weekly kept, upstream spend-limit extraction added - src/utils/__tests__/usage-prefetch.test.ts: upstream test for weekly usage from rate_limits stays retired (docs/test-retirements.md, a56a58e); upstream spend-limit tests added Hand edits outside conflicts: - src/utils/__tests__/usage-prefetch.test.ts: compat fix - upstream spend-limit tests reference mockFetchUsageData, the fork's mock is mockFetchUsage - docs/test-retirements.md: ledger entries for two tests upstream replaced (sirmalloc#704 8-bit sequences, sirmalloc#701 OSC links in the preview)
This was referenced Oct 31, 2026
Closed
Closed
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.
@sirmalloc I'd like your opinion on this before it merges. It changes the text cursor in the label editor and Custom Text from a block to a bar. If you don't like the bar, do you have ideas for something else?
What
In the label editor (
e) and the Custom Text editor, the text cursor is now a bar between characters instead of a highlighted block:"Weekly: │"with the cursor at the end, and"Weekly:│ "one step left."7d │"versus"7d│".Keys and editing work as before.
Why
The label editor from #601 quotes the label so that a trailing space, which usually separates the label from the value, stays visible. But the block cursor made two different labels look the same:
Weekly:"Weekly:█"7d"7d█"Past the end, the cursor is an extra highlighted space inside the quotes. So replacing
Weekly:with7dlooked like"7d ", yet the label saved as7d, and the status line read7d80.0%with no gap. Moving left made the "space" disappear and moving right brought it back: it was the cursor's cell, not part of the label.How
renderTextWithCursor(src/widgets/shared/text-cursor.ts) puts a bold cyan│at the cursor's index, instead of inverting the character under it or adding an inverted space at the end. The cursor always sits on a grapheme boundary, so the bar never splits an emoji.Text, so a wide emoji isn't overwritten.Demo
The label editor on Weekly Usage:
e, ← then →, delete the label, type7d, Space, Backspace, Enter. Before, the cursor after7dlooks like a trailing space. After, there's a gap only while the label has one. The usage figure is the TUI's preview data.Powerline, before
Powerline, after
Plain, before
Plain, after
Testing
text-cursor.test.ts:abwith the cursor on the space renders differently fromabwith the cursor at the end. Before, both rendered asabplus a highlighted space.ItemsEditor.test.ts: the joined-emoji label test now expects"👩💻 │". The label editor tests passed 10 runs out of 10.bun test: 3113 pass, 0 fail.bun run lintpasses. Under Node (Vitest), the two changed test files pass 21 of 21.main(the change is in the TUI only);"Weekly: │","Weekly:│ "and"7d│", and Custom Text showsab │andab│.