refactor: extracted padding logic into reusable utility function with optimized buffer allocation
- Extracted manual space padding logic into a reusable `padding()` utility function across all UI components and utilities. - Optimized padding operations by introducing a pre-allocated 512-space buffer in the `padding()` function to reduce repeated string allocations. - Updated all imports across 30 files to use the new `padding()` function from pi-tui instead of inline `' '.repeat()` calls. - Renamed local variables from `padding` to `pad`, `padSize`, `indent`, or `linePad` to avoid naming conflicts with the imported `padding()` function. - Exported the `padding()` utility function from the tui package index for public use.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Armin says hi! A fun easter egg with animated XBM art.
|
||||
*/
|
||||
import type { Component, TUI } from "@oh-my-pi/pi-tui";
|
||||
import { type Component, padding, type TUI } from "@oh-my-pi/pi-tui";
|
||||
import { theme } from "../../modes/theme/theme";
|
||||
|
||||
// XBM image: 31x36 pixels, LSB first, 1=background, 0=foreground
|
||||
@@ -87,20 +87,20 @@ export class ArminComponent implements Component {
|
||||
return this.cachedLines;
|
||||
}
|
||||
|
||||
const padding = 1;
|
||||
const availableWidth = width - padding;
|
||||
const indent = 1;
|
||||
const availableWidth = width - indent;
|
||||
|
||||
this.cachedLines = this.currentGrid.map(row => {
|
||||
// Clip row to available width before applying color
|
||||
const clipped = row.slice(0, availableWidth).join("");
|
||||
const padRight = Math.max(0, width - padding - clipped.length);
|
||||
return ` ${theme.fg("accent", clipped)}${" ".repeat(padRight)}`;
|
||||
const padRight = Math.max(0, width - indent - clipped.length);
|
||||
return ` ${theme.fg("accent", clipped)}${padding(padRight)}`;
|
||||
});
|
||||
|
||||
// Add "ARMIN SAYS HI" at the end
|
||||
const message = "ARMIN SAYS HI";
|
||||
const msgPadRight = Math.max(0, width - padding - message.length);
|
||||
this.cachedLines.push(` ${theme.fg("accent", message)}${" ".repeat(msgPadRight)}`);
|
||||
const msgPadRight = Math.max(0, width - indent - message.length);
|
||||
this.cachedLines.push(` ${theme.fg("accent", message)}${padding(msgPadRight)}`);
|
||||
|
||||
this.cachedWidth = width;
|
||||
this.cachedVersion = this.gridVersion;
|
||||
|
||||
@@ -11,7 +11,16 @@
|
||||
* - Space: Toggle selected item (or master switch)
|
||||
* - Esc: Close dashboard (clears search first if active)
|
||||
*/
|
||||
import { type Component, Container, matchesKey, Spacer, Text, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import {
|
||||
type Component,
|
||||
Container,
|
||||
matchesKey,
|
||||
padding,
|
||||
Spacer,
|
||||
Text,
|
||||
truncateToWidth,
|
||||
visibleWidth,
|
||||
} from "@oh-my-pi/pi-tui";
|
||||
import type { SettingsManager } from "../../../config/settings-manager";
|
||||
import { DynamicBorder } from "../../../modes/components/dynamic-border";
|
||||
import { theme } from "../../../modes/theme/theme";
|
||||
@@ -296,7 +305,7 @@ class TwoColumnBody implements Component {
|
||||
|
||||
for (let i = 0; i < numLines; i++) {
|
||||
const left = truncateToWidth(leftLines[i] ?? "", leftWidth);
|
||||
const leftPadded = left + " ".repeat(Math.max(0, leftWidth - visibleWidth(left)));
|
||||
const leftPadded = left + padding(Math.max(0, leftWidth - visibleWidth(left)));
|
||||
const right = truncateToWidth(rightLines[i] ?? "", rightWidth);
|
||||
combined.push(leftPadded + separator + right);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* that toggles the entire provider. All items below are dimmed when the
|
||||
* master switch is off.
|
||||
*/
|
||||
import { type Component, matchesKey, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { type Component, matchesKey, padding, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { isProviderEnabled } from "../../../discovery";
|
||||
import { theme } from "../../../modes/theme/theme";
|
||||
import { applyFilter } from "./state-manager";
|
||||
@@ -272,7 +272,7 @@ export class ExtensionList implements Component {
|
||||
if (width >= targetWidth) {
|
||||
return truncateToWidth(text, targetWidth);
|
||||
}
|
||||
return text + " ".repeat(targetWidth - width);
|
||||
return text + padding(targetWidth - width);
|
||||
}
|
||||
|
||||
private rebuildList(): void {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import type { AssistantMessage } from "@oh-my-pi/pi-ai";
|
||||
import { type Component, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { type Component, padding, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { isEnoent } from "@oh-my-pi/pi-utils";
|
||||
import { theme } from "../../modes/theme/theme";
|
||||
import type { AgentSession } from "../../session/agent-session";
|
||||
@@ -283,8 +283,8 @@ export class FooterComponent implements Component {
|
||||
let statsLine: string;
|
||||
if (totalNeeded <= width) {
|
||||
// Both fit - add padding to right-align model
|
||||
const padding = " ".repeat(width - statsLeftWidth - rightSideWidth);
|
||||
statsLine = statsLeft + padding + rightSide;
|
||||
const pad = padding(width - statsLeftWidth - rightSideWidth);
|
||||
statsLine = statsLeft + pad + rightSide;
|
||||
} else {
|
||||
// Need to truncate right side
|
||||
const availableForRight = width - statsLeftWidth - minPadding;
|
||||
@@ -293,8 +293,8 @@ export class FooterComponent implements Component {
|
||||
const plainRightSide = rightSide.replace(/\x1b\[[0-9;]*m/g, "");
|
||||
const truncatedPlain = plainRightSide.substring(0, availableForRight);
|
||||
// For simplicity, just use plain truncated version (loses color, but fits)
|
||||
const padding = " ".repeat(width - statsLeftWidth - truncatedPlain.length);
|
||||
statsLine = statsLeft + padding + truncatedPlain;
|
||||
const pad = padding(width - statsLeftWidth - truncatedPlain.length);
|
||||
statsLine = statsLeft + pad + truncatedPlain;
|
||||
} else {
|
||||
// Not enough space for right side at all
|
||||
statsLine = statsLeft;
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
Container,
|
||||
Input,
|
||||
matchesKey,
|
||||
padding,
|
||||
Spacer,
|
||||
Text,
|
||||
truncateToWidth,
|
||||
@@ -50,7 +51,7 @@ class HistoryResultsList implements Component {
|
||||
|
||||
const cursorSymbol = `${theme.nav.cursor} `;
|
||||
const cursorWidth = visibleWidth(cursorSymbol);
|
||||
const cursor = isSelected ? theme.fg("accent", cursorSymbol) : " ".repeat(cursorWidth);
|
||||
const cursor = isSelected ? theme.fg("accent", cursorSymbol) : padding(cursorWidth);
|
||||
const maxWidth = width - cursorWidth;
|
||||
|
||||
const normalized = entry.prompt.replace(/\s+/g, " ").trim();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Generic selector component for hooks.
|
||||
* Displays a list of string options with keyboard navigation.
|
||||
*/
|
||||
import { Container, matchesKey, Spacer, Text, type TUI, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { Container, matchesKey, padding, Spacer, Text, type TUI, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { theme } from "../../modes/theme/theme";
|
||||
import { CountdownTimer } from "./countdown-timer";
|
||||
import { DynamicBorder } from "./dynamic-border";
|
||||
@@ -29,7 +29,7 @@ class OutlinedList extends Container {
|
||||
const innerWidth = Math.max(1, width - 2);
|
||||
const content = this.lines.map(line => {
|
||||
const pad = Math.max(0, innerWidth - visibleWidth(line));
|
||||
return `${borderColor(theme.boxSharp.vertical)}${line}${" ".repeat(pad)}${borderColor(theme.boxSharp.vertical)}`;
|
||||
return `${borderColor(theme.boxSharp.vertical)}${line}${padding(pad)}${borderColor(theme.boxSharp.vertical)}`;
|
||||
});
|
||||
return [horizontal, ...content, horizontal];
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
Container,
|
||||
Input,
|
||||
matchesKey,
|
||||
padding,
|
||||
Spacer,
|
||||
Text,
|
||||
truncateToWidth,
|
||||
@@ -122,7 +123,7 @@ class SessionList implements Component {
|
||||
// First line: cursor + title (or first message if no title)
|
||||
const cursorSymbol = `${theme.nav.cursor} `;
|
||||
const cursorWidth = visibleWidth(cursorSymbol);
|
||||
const cursor = isSelected ? theme.fg("accent", cursorSymbol) : " ".repeat(cursorWidth);
|
||||
const cursor = isSelected ? theme.fg("accent", cursorSymbol) : padding(cursorWidth);
|
||||
const maxWidth = width - cursorWidth; // Account for cursor width
|
||||
|
||||
if (session.title) {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* - Shift+J/K: Reorder segment within column
|
||||
* - Live preview shown in the actual status line above
|
||||
*/
|
||||
import { Container, matchesKey } from "@oh-my-pi/pi-tui";
|
||||
import { Container, matchesKey, padding } from "@oh-my-pi/pi-tui";
|
||||
import type { StatusLineSegmentId } from "../../config/settings-manager";
|
||||
import { theme } from "../../modes/theme/theme";
|
||||
import { ALL_SEGMENT_IDS } from "./status-line/segments";
|
||||
@@ -351,7 +351,7 @@ export class StatusLineSegmentEditorComponent extends Container {
|
||||
}
|
||||
|
||||
// Pad to column width (accounting for ANSI codes)
|
||||
const padding = colWidth - label.length - 1;
|
||||
return text + " ".repeat(Math.max(0, padding));
|
||||
const padSize = colWidth - label.length - 1;
|
||||
return text + padding(Math.max(0, padSize));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import type { AssistantMessage } from "@oh-my-pi/pi-ai";
|
||||
import { type Component, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { type Component, padding, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { $ } from "bun";
|
||||
import type { StatusLineSegmentOptions, StatusLineSettings } from "../../config/settings-manager";
|
||||
import { theme } from "../../modes/theme/theme";
|
||||
@@ -378,7 +378,7 @@ export class StatusLineComponent implements Component {
|
||||
leftWidth = groupWidth(left, leftCapWidth, leftSepWidth);
|
||||
rightWidth = groupWidth(right, rightCapWidth, rightSepWidth);
|
||||
const gapWidth = Math.max(1, topFillWidth - leftWidth - rightWidth);
|
||||
return leftGroup + " ".repeat(gapWidth) + rightGroup;
|
||||
return leftGroup + padding(gapWidth) + rightGroup;
|
||||
}
|
||||
|
||||
getTopBorder(width: number): { content: string; width: number } {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type Component, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { type Component, padding, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { APP_NAME } from "../../config";
|
||||
import { theme } from "../../modes/theme/theme";
|
||||
|
||||
@@ -169,7 +169,7 @@ export class WelcomeComponent implements Component {
|
||||
}
|
||||
const leftPad = Math.floor((width - visLen) / 2);
|
||||
const rightPad = width - visLen - leftPad;
|
||||
return " ".repeat(leftPad) + text + " ".repeat(rightPad);
|
||||
return padding(leftPad) + text + padding(rightPad);
|
||||
}
|
||||
|
||||
/** Apply magenta→cyan gradient to a string */
|
||||
@@ -224,6 +224,6 @@ export class WelcomeComponent implements Component {
|
||||
}
|
||||
return `${truncated}${ellipsis}`;
|
||||
}
|
||||
return str + " ".repeat(width - visLen);
|
||||
return str + padding(width - visLen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as fs from "node:fs/promises";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import type { UsageLimit, UsageReport } from "@oh-my-pi/pi-ai";
|
||||
import { Loader, Markdown, Spacer, Text, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { Loader, Markdown, padding, Spacer, Text, visibleWidth } from "@oh-my-pi/pi-tui";
|
||||
import { $ } from "bun";
|
||||
import { nanoid } from "nanoid";
|
||||
import { loadCustomShare } from "../../export/custom-share";
|
||||
@@ -773,7 +773,7 @@ function formatAccountHeader(limit: UsageLimit, report: UsageReport, index: numb
|
||||
function padColumn(text: string, width: number): string {
|
||||
const visible = visibleWidth(text);
|
||||
if (visible >= width) return text;
|
||||
return `${text}${" ".repeat(width - visible)}`;
|
||||
return `${text}${padding(width - visible)}`;
|
||||
}
|
||||
|
||||
function resolveAggregateStatus(limits: UsageLimit[]): UsageLimit["status"] {
|
||||
|
||||
Reference in New Issue
Block a user