add sub-bar usage widget extension with opencode-go support

This commit is contained in:
2026-03-12 12:30:09 +00:00
parent 9ad10a016c
commit 3fd3fb5916
70 changed files with 14776 additions and 6 deletions
@@ -0,0 +1,937 @@
/**
* UI formatting utilities for the sub-bar extension
*/
import type { Theme } from "@mariozechner/pi-coding-agent";
import { truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
import type { RateWindow, UsageSnapshot, ProviderStatus, ModelInfo } from "./types.js";
import type {
BaseTextColor,
BarStyle,
BarType,
BarCharacter,
BarWidth,
ColorScheme,
DividerBlanks,
ResetTimerContainment,
Settings,
} from "./settings-types.js";
import { isBackgroundColor, resolveBaseTextColor, resolveDividerColor } from "./settings-types.js";
import { formatErrorForDisplay, isExpectedMissingData } from "./errors.js";
import { getStatusIcon, getStatusLabel } from "./status.js";
import { shouldShowWindow } from "./providers/windows.js";
import { getUsageExtras } from "./providers/extras.js";
import { normalizeTokens } from "./utils.js";
export interface UsageWindowParts {
label: string;
bar: string;
pct: string;
reset: string;
}
/**
* Context window usage info from the pi framework
*/
export interface ContextInfo {
tokens: number;
contextWindow: number;
percent: number;
}
type ModelInput = ModelInfo | string | undefined;
function resolveModelInfo(model?: ModelInput): ModelInfo | undefined {
if (!model) return undefined;
return typeof model === "string" ? { id: model } : model;
}
function isCodexSparkModel(model?: ModelInput): boolean {
const tokens = normalizeTokens(typeof model === "string" ? model : model?.id ?? "");
return tokens.includes("codex") && tokens.includes("spark");
}
function isCodexSparkWindow(window: RateWindow): boolean {
const tokens = normalizeTokens(window.label ?? "");
return tokens.includes("codex") && tokens.includes("spark");
}
function getDisplayWindowLabel(window: RateWindow, model?: ModelInput): string {
if (!isCodexSparkWindow(window)) return window.label;
if (!isCodexSparkModel(model)) return window.label;
const parts = window.label.trim().split(/\s+/);
const suffix = parts.at(-1) ?? "";
if (/^\d+h$/i.test(suffix) || /^day$/i.test(suffix) || /^week$/i.test(suffix)) {
return suffix;
}
return window.label;
}
/**
* Get the characters to use for progress bars
*/
function getBarCharacters(barCharacter: BarCharacter): { filled: string; empty: string } {
let filled = "━";
let empty = "━";
switch (barCharacter) {
case "light":
filled = "─";
empty = "─";
break;
case "heavy":
filled = "━";
empty = "━";
break;
case "double":
filled = "═";
empty = "═";
break;
case "block":
filled = "█";
empty = "█";
break;
default: {
const raw = String(barCharacter);
const trimmed = raw.trim();
if (!trimmed) return { filled, empty };
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
const segments = Array.from(segmenter.segment(raw), (entry) => entry.segment);
const first = segments[0] ?? trimmed[0] ?? "━";
const second = segments[1];
filled = first;
empty = second ?? first;
break;
}
}
return { filled, empty };
}
/**
* Get color based on percentage and color scheme
*/
function getUsageColor(
percent: number,
isRemaining: boolean,
colorScheme: ColorScheme,
errorThreshold: number = 25,
warningThreshold: number = 50,
successThreshold: number = 75
): "error" | "warning" | "base" | "success" {
if (colorScheme === "monochrome") {
return "base";
}
// For remaining percentage (Codex style), invert the logic
const effectivePercent = isRemaining ? percent : 100 - percent;
if (colorScheme === "success-base-warning-error") {
// >75%: success, >50%: base, >25%: warning, <=25%: error
if (effectivePercent < errorThreshold) return "error";
if (effectivePercent < warningThreshold) return "warning";
if (effectivePercent < successThreshold) return "base";
return "success";
}
// base-warning-error (default)
// >50%: base, >25%: warning, <=25%: error
if (effectivePercent < errorThreshold) return "error";
if (effectivePercent < warningThreshold) return "warning";
return "base";
}
function clampPercent(value: number): number {
return Math.max(0, Math.min(100, value));
}
function getStatusColor(
indicator: NonNullable<UsageSnapshot["status"]>["indicator"],
colorScheme: ColorScheme
): "error" | "warning" | "success" | "base" {
if (colorScheme === "monochrome") {
return "base";
}
if (indicator === "minor" || indicator === "maintenance") {
return "warning";
}
if (indicator === "major" || indicator === "critical") {
return "error";
}
if (indicator === "none") {
return colorScheme === "success-base-warning-error" ? "success" : "base";
}
return "base";
}
function resolveStatusTintColor(
color: "error" | "warning" | "success" | "base",
baseTextColor: BaseTextColor
): BaseTextColor {
return color === "base" ? baseTextColor : color;
}
function fgFromBgAnsi(ansi: string): string {
return ansi.replace(/\x1b\[48;/g, "\x1b[38;").replace(/\x1b\[49m/g, "\x1b[39m");
}
function applyBaseTextColor(theme: Theme, color: BaseTextColor, text: string): string {
if (isBackgroundColor(color)) {
const fgAnsi = fgFromBgAnsi(theme.getBgAnsi(color as Parameters<Theme["getBgAnsi"]>[0]));
return `${fgAnsi}${text}\x1b[39m`;
}
return theme.fg(resolveDividerColor(color), text);
}
function resolveUsageColorTargets(settings?: Settings): {
title: boolean;
timer: boolean;
bar: boolean;
usageLabel: boolean;
status: boolean;
} {
const targets = settings?.display.usageColorTargets;
return {
title: targets?.title ?? true,
timer: targets?.timer ?? true,
bar: targets?.bar ?? true,
usageLabel: targets?.usageLabel ?? true,
status: targets?.status ?? true,
};
}
function formatElapsedSince(timestamp: number): string {
const diffMs = Date.now() - timestamp;
if (diffMs < 60000) {
const seconds = Math.max(1, Math.floor(diffMs / 1000));
return `${seconds}s`;
}
const diffMins = Math.floor(diffMs / 60000);
if (diffMins < 60) return `${diffMins}m`;
const hours = Math.floor(diffMins / 60);
const mins = diffMins % 60;
if (hours < 24) return mins > 0 ? `${hours}h${mins}m` : `${hours}h`;
const days = Math.floor(hours / 24);
const remHours = hours % 24;
return remHours > 0 ? `${days}d${remHours}h` : `${days}d`;
}
const RESET_CONTAINMENT_SEGMENTER = new Intl.Segmenter(undefined, { granularity: "grapheme" });
function wrapResetContainment(text: string, containment: ResetTimerContainment): { wrapped: string; attachWithSpace: boolean } {
switch (containment) {
case "none":
return { wrapped: text, attachWithSpace: true };
case "blank":
return { wrapped: text, attachWithSpace: true };
case "[]":
return { wrapped: `[${text}]`, attachWithSpace: true };
case "<>":
return { wrapped: `<${text}>`, attachWithSpace: true };
case "()":
return { wrapped: `(${text})`, attachWithSpace: true };
default: {
const trimmed = String(containment).trim();
if (!trimmed) return { wrapped: `(${text})`, attachWithSpace: true };
const segments = Array.from(RESET_CONTAINMENT_SEGMENTER.segment(trimmed), (entry) => entry.segment)
.map((segment) => segment.trim())
.filter(Boolean);
if (segments.length === 0) return { wrapped: `(${text})`, attachWithSpace: true };
const left = segments[0];
const right = segments[1] ?? left;
return { wrapped: `${left}${text}${right}`, attachWithSpace: true };
}
}
}
function formatResetDateTime(resetAt: string): string {
const date = new Date(resetAt);
if (Number.isNaN(date.getTime())) return resetAt;
return new Intl.DateTimeFormat(undefined, {
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
}).format(date);
}
function getBarTypeLevels(barType: BarType): string[] | null {
switch (barType) {
case "horizontal-single":
return ["▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"];
case "vertical":
return ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
case "braille":
return ["⡀", "⡄", "⣄", "⣆", "⣇", "⣧", "⣷", "⣿"];
case "shade":
return ["░", "▒", "▓", "█"];
default:
return null;
}
}
function renderBarSegments(
percent: number,
width: number,
levels: string[],
options?: { allowMinimum?: boolean; emptyChar?: string }
): { segments: Array<{ char: string; filled: boolean }>; minimal: boolean } {
const totalUnits = Math.max(1, width) * levels.length;
let filledUnits = Math.round((percent / 100) * totalUnits);
let minimal = false;
if (options?.allowMinimum && percent > 0 && filledUnits === 0) {
filledUnits = 1;
minimal = true;
}
const emptyChar = options?.emptyChar ?? " ";
const segments: Array<{ char: string; filled: boolean }> = [];
for (let i = 0; i < Math.max(1, width); i++) {
if (filledUnits >= levels.length) {
segments.push({ char: levels[levels.length - 1], filled: true });
filledUnits -= levels.length;
continue;
}
if (filledUnits > 0) {
segments.push({ char: levels[Math.min(levels.length - 1, filledUnits - 1)], filled: true });
filledUnits = 0;
continue;
}
segments.push({ char: emptyChar, filled: false });
}
return { segments, minimal };
}
function formatProviderLabel(theme: Theme, usage: UsageSnapshot, settings?: Settings, model?: ModelInput): string {
const showProviderName = settings?.display.showProviderName ?? true;
const showStatus = settings?.providers[usage.provider]?.showStatus ?? true;
const error = usage.error;
const fetchError = Boolean(error && !isExpectedMissingData(error));
const baseStatus = showStatus ? usage.status : undefined;
const lastSuccessAt = usage.lastSuccessAt;
const elapsed = lastSuccessAt ? formatElapsedSince(lastSuccessAt) : undefined;
const fetchDescription = elapsed
? (elapsed === "just now" ? "Last upd.: just now" : `Last upd.: ${elapsed} ago`)
: "Fetch failed";
const fetchStatus: ProviderStatus | undefined = fetchError
? { indicator: "minor", description: fetchDescription }
: undefined;
const status = showStatus ? (fetchStatus ?? baseStatus) : undefined;
const statusDismissOk = settings?.display.statusDismissOk ?? true;
const statusModeRaw = settings?.display.statusIndicatorMode ?? "icon";
const statusMode = statusModeRaw === "icon" || statusModeRaw === "text" || statusModeRaw === "icon+text"
? statusModeRaw
: "icon";
const statusIconPack = settings?.display.statusIconPack ?? "emoji";
const statusIconCustom = settings?.display.statusIconCustom;
const providerLabelSetting = settings?.display.providerLabel ?? "none";
const showColon = settings?.display.providerLabelColon ?? true;
const boldProviderLabel = settings?.display.providerLabelBold ?? false;
const baseTextColor = resolveBaseTextColor(settings?.display.baseTextColor);
const usageTargets = resolveUsageColorTargets(settings);
const statusActive = Boolean(status && (!statusDismissOk || status.indicator !== "none"));
const showIcon = statusActive && (statusMode === "icon" || statusMode === "icon+text");
const showText = statusActive && (statusMode === "text" || statusMode === "icon+text");
const labelSuffix = providerLabelSetting === "plan"
? "Plan"
: providerLabelSetting === "subscription"
? "Subscription"
: providerLabelSetting === "sub"
? "Sub."
: providerLabelSetting === "none"
? ""
: String(providerLabelSetting);
const rawName = usage.displayName?.trim() ?? "";
const baseName = rawName.replace(/\s+(plan|subscription|sub\.?)[\s]*$/i, "").trim();
const resolvedProviderName = baseName || rawName;
const isSpark = usage.provider === "codex" && isCodexSparkModel(model);
const providerName = isSpark ? `${resolvedProviderName} (Spark)` : resolvedProviderName;
const providerLabel = showProviderName
? [providerName, labelSuffix].filter(Boolean).join(" ")
: "";
const providerLabelWithColon = providerLabel && showColon ? `${providerLabel}:` : providerLabel;
const icon = showIcon && status ? getStatusIcon(status, statusIconPack, statusIconCustom) : "";
const statusText = showText && status ? getStatusLabel(status) : "";
const rawStatusColor = status
? getStatusColor(status.indicator, settings?.display.colorScheme ?? "base-warning-error")
: "base";
const statusTint = usageTargets.status
? resolveStatusTintColor(rawStatusColor, baseTextColor)
: baseTextColor;
const statusColor = statusTint;
const dividerEnabled = settings?.display.statusProviderDivider ?? false;
const dividerChar = settings?.display.dividerCharacter ?? "│";
const dividerColor = resolveDividerColor(settings?.display.dividerColor);
const dividerGlyph = dividerChar === "none"
? ""
: dividerChar === "blank"
? " "
: dividerChar;
const statusParts: string[] = [];
if (icon) statusParts.push(applyBaseTextColor(theme, statusColor, icon));
if (statusText) statusParts.push(applyBaseTextColor(theme, statusColor, statusText));
const parts: string[] = [];
if (statusParts.length > 0) {
parts.push(statusParts.join(" "));
}
if (providerLabelWithColon) {
if (statusParts.length > 0 && dividerEnabled && dividerGlyph) {
parts.push(theme.fg(dividerColor, dividerGlyph));
}
const colored = applyBaseTextColor(theme, baseTextColor, providerLabelWithColon);
parts.push(boldProviderLabel ? theme.bold(colored) : colored);
}
if (parts.length === 0) return "";
return parts.join(" ");
}
/**
* Format a single usage window as a styled string
*/
export function formatUsageWindow(
theme: Theme,
window: RateWindow,
isCodex: boolean,
settings?: Settings,
usage?: UsageSnapshot,
options?: { useNormalColors?: boolean; barWidthOverride?: number },
model?: ModelInput
): string {
const parts = formatUsageWindowParts(theme, window, isCodex, settings, usage, options, model);
const baseTextColor = resolveBaseTextColor(settings?.display.baseTextColor);
const usageTargets = resolveUsageColorTargets(settings);
// Special handling for Extra usage label
if (window.label.startsWith("Extra [")) {
const match = window.label.match(/^(Extra \[)(on|active)(\] .*)$/);
if (match) {
const [, prefix, status, suffix] = match;
const styledLabel =
status === "active"
? applyBaseTextColor(theme, baseTextColor, prefix)
+ theme.fg("text", status)
+ applyBaseTextColor(theme, baseTextColor, suffix)
: applyBaseTextColor(theme, baseTextColor, window.label);
const extraParts = [styledLabel, parts.bar, parts.pct].filter(Boolean);
return extraParts.join(" ");
}
if (!usageTargets.title) {
const extraParts = [applyBaseTextColor(theme, baseTextColor, window.label), parts.bar, parts.pct].filter(Boolean);
return extraParts.join(" ");
}
const extraColor = getUsageColor(window.usedPercent, false, settings?.display.colorScheme ?? "base-warning-error");
const extraTextColor = (options?.useNormalColors && extraColor === "base")
? "text"
: extraColor === "base"
? baseTextColor
: extraColor;
const extraParts = [applyBaseTextColor(theme, extraTextColor, window.label), parts.bar, parts.pct].filter(Boolean);
return extraParts.join(" ");
}
const joinedParts = [parts.label, parts.bar, parts.pct, parts.reset].filter(Boolean);
return joinedParts.join(" ");
}
export function formatUsageWindowParts(
theme: Theme,
window: RateWindow,
isCodex: boolean,
settings?: Settings,
usage?: UsageSnapshot,
options?: { useNormalColors?: boolean; barWidthOverride?: number },
model?: ModelInput
): UsageWindowParts {
const barStyle: BarStyle = settings?.display.barStyle ?? "both";
const barWidthSetting = settings?.display.barWidth;
const containBar = settings?.display.containBar ?? false;
const barWidth = options?.barWidthOverride ?? (typeof barWidthSetting === "number" ? barWidthSetting : 6);
const barType: BarType = settings?.display.barType ?? "horizontal-bar";
const brailleFillEmpty = settings?.display.brailleFillEmpty ?? false;
const brailleFullBlocks = settings?.display.brailleFullBlocks ?? false;
const barCharacter: BarCharacter = settings?.display.barCharacter ?? "heavy";
const colorScheme: ColorScheme = settings?.display.colorScheme ?? "base-warning-error";
const resetTimePosition = settings?.display.resetTimePosition ?? "front";
const resetTimeFormat = settings?.display.resetTimeFormat ?? "relative";
const showUsageLabels = settings?.display.showUsageLabels ?? true;
const showWindowTitle = settings?.display.showWindowTitle ?? true;
const boldWindowTitle = settings?.display.boldWindowTitle ?? false;
const baseTextColor = resolveBaseTextColor(settings?.display.baseTextColor);
const errorThreshold = settings?.display.errorThreshold ?? 25;
const warningThreshold = settings?.display.warningThreshold ?? 50;
const successThreshold = settings?.display.successThreshold ?? 75;
const rawUsedPct = Math.round(window.usedPercent);
const usedPct = clampPercent(rawUsedPct);
const displayPct = isCodex ? clampPercent(100 - usedPct) : usedPct;
const isRemaining = isCodex;
const barPercent = clampPercent(displayPct);
const filled = Math.round((barPercent / 100) * barWidth);
const empty = Math.max(0, barWidth - filled);
const baseColor = getUsageColor(displayPct, isRemaining, colorScheme, errorThreshold, warningThreshold, successThreshold);
const usageTargets = resolveUsageColorTargets(settings);
const usageTextColor = (options?.useNormalColors && baseColor === "base")
? "text"
: baseColor === "base"
? baseTextColor
: baseColor;
const neutralTextColor = options?.useNormalColors ? "text" : baseTextColor;
const titleColor = usageTargets.title ? usageTextColor : neutralTextColor;
const timerColor = usageTargets.timer ? usageTextColor : neutralTextColor;
const usageLabelColor = usageTargets.usageLabel ? usageTextColor : neutralTextColor;
const barUsageColor = (options?.useNormalColors && baseColor === "base") ? "text" : baseColor === "base" ? "muted" : baseColor;
const neutralBarColor = baseTextColor === "dim" ? "dim" : "muted";
const barColor = usageTargets.bar ? barUsageColor : neutralBarColor;
const { filled: filledChar, empty: emptyChar } = getBarCharacters(barCharacter);
const emptyColor = "dim";
let barStr = "";
if ((barStyle === "bar" || barStyle === "both") && barWidth > 0) {
let levels = getBarTypeLevels(barType);
if (barType === "braille" && brailleFullBlocks) {
levels = ["⣿"];
}
if (!levels || barType === "horizontal-bar") {
const filledCharWidth = Math.max(1, visibleWidth(filledChar));
const emptyCharWidth = Math.max(1, visibleWidth(emptyChar));
const segmentCount = barWidth > 0 ? Math.floor(barWidth / filledCharWidth) : 0;
const filledSegments = segmentCount > 0 ? Math.round((barPercent / 100) * segmentCount) : 0;
const filledStr = filledChar.repeat(filledSegments);
const filledWidth = filledSegments * filledCharWidth;
const remainingWidth = Math.max(0, barWidth - filledWidth);
const emptySegments = emptyCharWidth > 0 ? Math.floor(remainingWidth / emptyCharWidth) : 0;
const emptyStr = emptyChar.repeat(emptySegments);
const emptyRendered = emptyChar === " " ? emptyStr : theme.fg(emptyColor, emptyStr);
barStr = theme.fg(barColor as Parameters<typeof theme.fg>[0], filledStr) + emptyRendered;
const barVisualWidth = visibleWidth(barStr);
if (barVisualWidth < barWidth) {
barStr += " ".repeat(barWidth - barVisualWidth);
}
} else {
const emptyChar = barType === "braille" && brailleFillEmpty && barWidth > 1 ? "⣿" : " ";
const { segments, minimal } = renderBarSegments(barPercent, barWidth, levels, {
allowMinimum: true,
emptyChar,
});
const filledColor = minimal ? "dim" : barColor;
barStr = segments
.map((segment) => {
if (segment.filled) {
return theme.fg(filledColor as Parameters<typeof theme.fg>[0], segment.char);
}
if (segment.char === " ") {
return segment.char;
}
return theme.fg("dim", segment.char);
})
.join("");
}
if (settings?.display.containBar && barStr) {
const leftCap = theme.fg(barColor as Parameters<typeof theme.fg>[0], "▕");
const rightCap = theme.fg(barColor as Parameters<typeof theme.fg>[0], "▏");
barStr = leftCap + barStr + rightCap;
}
}
let pctStr = "";
if (barStyle === "percentage" || barStyle === "both") {
// Special handling for Copilot Month window - can show percentage or requests
if (window.label === "Month" && usage?.provider === "copilot") {
const quotaDisplay = settings?.providers.copilot.quotaDisplay ?? "percentage";
if (quotaDisplay === "requests" && usage.requestsRemaining !== undefined && usage.requestsEntitlement !== undefined) {
const used = usage.requestsEntitlement - usage.requestsRemaining;
const suffix = showUsageLabels ? " used" : "";
pctStr = applyBaseTextColor(theme, usageLabelColor, `${used}/${usage.requestsEntitlement}${suffix}`);
} else {
const suffix = showUsageLabels ? " used" : "";
pctStr = applyBaseTextColor(theme, usageLabelColor, `${usedPct}%${suffix}`);
}
} else if (isCodex) {
const suffix = showUsageLabels ? " rem." : "";
pctStr = applyBaseTextColor(theme, usageLabelColor, `${displayPct}%${suffix}`);
} else {
const suffix = showUsageLabels ? " used" : "";
pctStr = applyBaseTextColor(theme, usageLabelColor, `${usedPct}%${suffix}`);
}
}
const isActiveReset = window.resetDescription === "__ACTIVE__";
const resetText = isActiveReset
? undefined
: resetTimeFormat === "datetime"
? (window.resetAt ? formatResetDateTime(window.resetAt) : window.resetDescription)
: window.resetDescription;
const resetContainment = settings?.display.resetTimeContainment ?? "()";
const leftSuffix = resetText && resetTimeFormat === "relative" && showUsageLabels ? " left" : "";
const displayLabel = getDisplayWindowLabel(window, model);
const coloredTitle = applyBaseTextColor(theme, titleColor, displayLabel);
const titlePart = showWindowTitle ? (boldWindowTitle ? theme.bold(coloredTitle) : coloredTitle) : "";
let labelPart = titlePart;
if (resetText) {
const resetBody = `${resetText}${leftSuffix}`;
const { wrapped, attachWithSpace } = wrapResetContainment(resetBody, resetContainment);
const coloredReset = applyBaseTextColor(theme, timerColor, wrapped);
if (resetTimePosition === "front") {
if (!titlePart) {
labelPart = coloredReset;
} else {
labelPart = attachWithSpace ? `${titlePart} ${coloredReset}` : `${titlePart}${coloredReset}`;
}
} else if (resetTimePosition === "integrated") {
labelPart = titlePart ? `${applyBaseTextColor(theme, timerColor, `${wrapped}/`)}${titlePart}` : coloredReset;
} else if (resetTimePosition === "back") {
labelPart = titlePart;
}
} else if (!titlePart) {
labelPart = "";
}
const resetPart =
resetTimePosition === "back" && resetText
? applyBaseTextColor(theme, timerColor, wrapResetContainment(`${resetText}${leftSuffix}`, resetContainment).wrapped)
: "";
return {
label: labelPart,
bar: barStr,
pct: pctStr,
reset: resetPart,
};
}
/**
* Format context window usage as a progress bar
*/
export function formatContextBar(
theme: Theme,
context: ContextInfo,
settings?: Settings,
options?: { barWidthOverride?: number }
): string {
// Create a pseudo-RateWindow for context display
const contextWindow: RateWindow = {
label: "Ctx",
usedPercent: context.percent,
// No reset description for context
};
// Format using the same window formatting logic, but with "used" semantics (not inverted)
return formatUsageWindow(theme, contextWindow, false, settings, undefined, options);
}
/**
* Format a complete usage snapshot as a usage line
*/
export function formatUsageStatus(
theme: Theme,
usage: UsageSnapshot,
model?: ModelInput,
settings?: Settings,
context?: ContextInfo
): string | undefined {
const baseTextColor = resolveBaseTextColor(settings?.display.baseTextColor);
const modelInfo = resolveModelInfo(model);
const label = formatProviderLabel(theme, usage, settings, modelInfo);
// If no windows, just show the provider name with error
if (usage.windows.length === 0) {
const errorMsg = usage.error
? applyBaseTextColor(theme, baseTextColor, `(${formatErrorForDisplay(usage.error)})`)
: "";
if (!label) {
return errorMsg;
}
return errorMsg ? `${label} ${errorMsg}` : label;
}
// Build usage bars
const parts: string[] = [];
const isCodex = usage.provider === "codex";
const invertUsage = isCodex && (settings?.providers.codex.invertUsage ?? false);
const modelId = modelInfo?.id;
// Add context bar as leftmost element if enabled
const showContextBar = settings?.display.showContextBar ?? false;
if (showContextBar && context && context.contextWindow > 0) {
parts.push(formatContextBar(theme, context, settings));
}
for (const w of usage.windows) {
// Skip windows that are disabled in settings
if (!shouldShowWindow(usage, w, settings, modelInfo)) {
continue;
}
parts.push(formatUsageWindow(theme, w, invertUsage, settings, usage, undefined, modelInfo));
}
// Add extra usage lines (extra usage off, copilot multiplier, etc.)
const extras = getUsageExtras(usage, settings, modelId);
for (const extra of extras) {
parts.push(applyBaseTextColor(theme, baseTextColor, extra.label));
}
// Build divider from settings
const dividerChar = settings?.display.dividerCharacter ?? "•";
const dividerColor = resolveDividerColor(settings?.display.dividerColor);
const blanksSetting = settings?.display.dividerBlanks ?? 1;
const showProviderDivider = settings?.display.showProviderDivider ?? false;
const blanksPerSide = typeof blanksSetting === "number" ? blanksSetting : 1;
const spacing = " ".repeat(blanksPerSide);
const charToDisplay = dividerChar === "blank" ? " " : dividerChar === "none" ? "" : dividerChar;
const divider = charToDisplay ? spacing + theme.fg(dividerColor, charToDisplay) + spacing : spacing + spacing;
const labelGap = label && parts.length > 0
? showProviderDivider && charToDisplay !== ""
? divider
: spacing
: "";
return label + labelGap + parts.join(divider);
}
export function formatUsageStatusWithWidth(
theme: Theme,
usage: UsageSnapshot,
width: number,
model?: ModelInput,
settings?: Settings,
options?: { labelGapFill?: boolean },
context?: ContextInfo
): string | undefined {
const labelGapFill = options?.labelGapFill ?? false;
const baseTextColor = resolveBaseTextColor(settings?.display.baseTextColor);
const modelInfo = resolveModelInfo(model);
const label = formatProviderLabel(theme, usage, settings, modelInfo);
const showContextBar = settings?.display.showContextBar ?? false;
const hasContext = showContextBar && context && context.contextWindow > 0;
// If no windows, just show the provider name with error
if (usage.windows.length === 0) {
const errorMsg = usage.error
? applyBaseTextColor(theme, baseTextColor, `(${formatErrorForDisplay(usage.error)})`)
: "";
if (!label) {
return errorMsg;
}
return errorMsg ? `${label} ${errorMsg}` : label;
}
const barStyle: BarStyle = settings?.display.barStyle ?? "both";
const hasBar = barStyle === "bar" || barStyle === "both";
const barWidthSetting = settings?.display.barWidth ?? 6;
const dividerBlanksSetting = settings?.display.dividerBlanks ?? 1;
const dividerColor = resolveDividerColor(settings?.display.dividerColor);
const showProviderDivider = settings?.display.showProviderDivider ?? false;
const containBar = settings?.display.containBar ?? false;
const barFill = barWidthSetting === "fill";
const barBaseWidth = typeof barWidthSetting === "number" ? barWidthSetting : (hasBar ? 1 : 0);
const barContainerExtra = containBar && hasBar ? 2 : 0;
const barBaseContentWidth = barFill ? 0 : barBaseWidth;
const barBaseWidthCalc = barFill ? 0 : barBaseContentWidth + barContainerExtra;
const barTotalBaseWidth = barBaseWidthCalc;
const baseDividerBlanks = typeof dividerBlanksSetting === "number" ? dividerBlanksSetting : 1;
const dividerFill = dividerBlanksSetting === "fill";
// Build usage windows
const windows: RateWindow[] = [];
const isCodex = usage.provider === "codex";
const invertUsage = isCodex && (settings?.providers.codex.invertUsage ?? false);
const modelId = modelInfo?.id;
// Add context window as first entry if enabled
let contextWindowIndex = -1;
if (hasContext) {
contextWindowIndex = windows.length;
windows.push({
label: "Ctx",
usedPercent: context!.percent,
});
}
for (const w of usage.windows) {
if (!shouldShowWindow(usage, w, settings, modelInfo)) {
continue;
}
windows.push(w);
}
const barEligibleCount = hasBar ? windows.length : 0;
const extras = getUsageExtras(usage, settings, modelId);
const extraParts = extras.map((extra) => applyBaseTextColor(theme, baseTextColor, extra.label));
const barSpacerWidth = hasBar ? 1 : 0;
const baseWindowWidths = windows.map((w, i) => {
// Context window uses false for invertUsage (always show used percentage)
const isContext = i === contextWindowIndex;
return (
visibleWidth(
formatUsageWindow(
theme,
w,
isContext ? false : invertUsage,
settings,
isContext ? undefined : usage,
{ barWidthOverride: 0 },
modelInfo
)
) + barSpacerWidth
);
});
const extraWidths = extraParts.map((part) => visibleWidth(part));
const partCount = windows.length + extraParts.length;
const dividerCount = Math.max(0, partCount - 1);
const dividerChar = settings?.display.dividerCharacter ?? "•";
const charToDisplay = dividerChar === "blank" ? " " : dividerChar === "none" ? "" : dividerChar;
const dividerBaseWidth = (charToDisplay ? 1 : 0) + baseDividerBlanks * 2;
const labelGapEnabled = partCount > 0 && (label !== "" || labelGapFill);
const providerDividerActive = showProviderDivider && charToDisplay !== "" && label !== "";
const labelGapBaseWidth = labelGapEnabled
? providerDividerActive
? dividerBaseWidth
: baseDividerBlanks
: 0;
const labelWidth = visibleWidth(label);
const baseTotalWidth =
labelWidth +
labelGapBaseWidth +
baseWindowWidths.reduce((sum, w) => sum + w, 0) +
extraWidths.reduce((sum, w) => sum + w, 0) +
(barEligibleCount * barTotalBaseWidth) +
(dividerCount * dividerBaseWidth);
let remainingWidth = width - baseTotalWidth;
if (remainingWidth < 0) {
remainingWidth = 0;
}
const useBars = barFill && barEligibleCount > 0;
const labelGapUnits = labelGapEnabled ? (providerDividerActive ? 2 : 1) : 0;
const dividerSlots = dividerCount + (labelGapEnabled ? 1 : 0);
const dividerUnits = dividerCount * 2 + labelGapUnits;
const useDividers = dividerFill && dividerUnits > 0;
let barExtraTotal = 0;
let dividerExtraTotal = 0;
if (remainingWidth > 0 && (useBars || useDividers)) {
const barWeight = useBars ? barEligibleCount : 0;
const dividerWeight = useDividers ? dividerUnits : 0;
const totalWeight = barWeight + dividerWeight;
if (totalWeight > 0) {
barExtraTotal = Math.floor((remainingWidth * barWeight) / totalWeight);
dividerExtraTotal = remainingWidth - barExtraTotal;
}
}
const barWidths: number[] = windows.map(() => barBaseWidthCalc);
if (useBars && barEligibleCount > 0) {
const perBar = Math.floor(barExtraTotal / barEligibleCount);
let remainder = barExtraTotal % barEligibleCount;
for (let i = 0; i < barWidths.length; i++) {
barWidths[i] = barBaseWidthCalc + perBar + (remainder > 0 ? 1 : 0);
if (remainder > 0) remainder -= 1;
}
}
let labelBlanks = labelGapEnabled ? baseDividerBlanks : 0;
const dividerBlanks: number[] = [];
if (dividerUnits > 0) {
const baseUnit = useDividers ? Math.floor(dividerExtraTotal / dividerUnits) : 0;
let remainderUnits = useDividers ? dividerExtraTotal % dividerUnits : 0;
if (labelGapEnabled) {
if (useDividers && providerDividerActive) {
let extraUnits = baseUnit * 2;
if (remainderUnits >= 2) {
extraUnits += 2;
remainderUnits -= 2;
}
labelBlanks = baseDividerBlanks + Math.floor(extraUnits / 2);
} else if (useDividers) {
labelBlanks = baseDividerBlanks + baseUnit + (remainderUnits > 0 ? 1 : 0);
if (remainderUnits > 0) remainderUnits -= 1;
}
}
for (let i = 0; i < dividerCount; i++) {
let extraUnits = baseUnit * 2;
if (remainderUnits >= 2) {
extraUnits += 2;
remainderUnits -= 2;
}
const blanks = baseDividerBlanks + Math.floor(extraUnits / 2);
dividerBlanks.push(blanks);
}
}
const parts: string[] = [];
for (let i = 0; i < windows.length; i++) {
const totalWidth = barWidths[i] ?? barBaseWidthCalc;
const contentWidth = containBar ? Math.max(0, totalWidth - barContainerExtra) : totalWidth;
const isContext = i === contextWindowIndex;
parts.push(
formatUsageWindow(
theme,
windows[i],
isContext ? false : invertUsage,
settings,
isContext ? undefined : usage,
{ barWidthOverride: contentWidth },
modelInfo
)
);
}
for (const extra of extraParts) {
parts.push(extra);
}
let rest = "";
for (let i = 0; i < parts.length; i++) {
rest += parts[i];
if (i < dividerCount) {
const blanks = dividerBlanks[i] ?? baseDividerBlanks;
const spacing = " ".repeat(Math.max(0, blanks));
rest += charToDisplay
? spacing + theme.fg(dividerColor, charToDisplay) + spacing
: spacing + spacing;
}
}
let labelGapExtra = 0;
if (labelGapFill && labelGapEnabled) {
const restWidth = visibleWidth(rest);
const labelGapWidth = providerDividerActive
? (Math.max(0, labelBlanks) * 2) + (charToDisplay ? 1 : 0)
: Math.max(0, labelBlanks);
const totalWidth = visibleWidth(label) + restWidth + labelGapWidth;
labelGapExtra = Math.max(0, width - totalWidth);
}
let output = label;
if (labelGapEnabled) {
if (providerDividerActive) {
const spacing = " ".repeat(Math.max(0, labelBlanks));
output += spacing + theme.fg(dividerColor, charToDisplay) + spacing + " ".repeat(labelGapExtra);
} else {
output += " ".repeat(Math.max(0, labelBlanks + labelGapExtra));
}
}
output += rest;
if (width > 0 && visibleWidth(output) > width) {
return truncateToWidth(output, width, "");
}
return output;
}