chore: release v0.1.4 with npm packaging and shared helpers #7
+53
-11
@@ -1,29 +1,39 @@
|
|||||||
// Terminal styling utilities.
|
// Terminal styling and rendering utilities.
|
||||||
// Respects NO_COLOR convention, --no-color flag, and TTY detection.
|
// Respects NO_COLOR convention, --no-color flag, and TTY detection.
|
||||||
|
|
||||||
import { isStdoutTTY } from "./tty";
|
import { isStdoutTTY } from "./tty";
|
||||||
|
|
||||||
|
// ── Color support ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
let _enabled: boolean | null = null;
|
let _enabled: boolean | null = null;
|
||||||
|
|
||||||
export function setColorEnabled(enabled: boolean): void {
|
export function setColorEnabled(enabled: boolean): void {
|
||||||
_enabled = enabled;
|
_enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isColorEnabled(): boolean {
|
export function isColorEnabled(): boolean {
|
||||||
if (_enabled !== null) return _enabled;
|
if (_enabled !== null) return _enabled;
|
||||||
|
|
||||||
// Respect NO_COLOR: https://no-color.org/
|
// Respect NO_COLOR: https://no-color.org/
|
||||||
if (process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== "") {
|
if (process.env.NO_COLOR !== undefined && process.env.NO_COLOR !== "") {
|
||||||
return false;
|
_enabled = false;
|
||||||
}
|
return false;
|
||||||
if (!isStdoutTTY()) return false;
|
}
|
||||||
if (process.env.FORCE_COLOR && process.env.FORCE_COLOR !== "0") return true;
|
if (!isStdoutTTY()) {
|
||||||
|
_enabled = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (process.env.FORCE_COLOR && process.env.FORCE_COLOR !== "0") {
|
||||||
|
_enabled = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
_enabled = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function s(code: string): string {
|
function s(code: string): string {
|
||||||
return isColorEnabled() ? code : "";
|
return isColorEnabled() ? code : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BOLD = () => s("\x1b[1m");
|
export const BOLD = () => s("\x1b[1m");
|
||||||
@@ -33,3 +43,35 @@ export const YELLOW = () => s("\x1b[33m");
|
|||||||
export const CYAN = () => s("\x1b[36m");
|
export const CYAN = () => s("\x1b[36m");
|
||||||
export const RED = () => s("\x1b[31m");
|
export const RED = () => s("\x1b[31m");
|
||||||
export const RESET = () => s("\x1b[0m");
|
export const RESET = () => s("\x1b[0m");
|
||||||
|
|
||||||
|
// ── Terminal rendering helpers ───────────────────────────────────────
|
||||||
|
|
||||||
|
export function hideCursor(): void {
|
||||||
|
process.stdout.write("\x1b[?25l");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showCursor(): void {
|
||||||
|
process.stdout.write("\x1b[?25h");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearLine(): void {
|
||||||
|
process.stdout.write("\r\x1b[2K");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moveUp(lines: number): void {
|
||||||
|
if (lines > 0) process.stdout.write(`\x1b[${lines}A`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearScreen(): void {
|
||||||
|
process.stdout.write("\x1b[2J\x1b[H");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calculate visible length of a string, stripping ANSI escape codes. */
|
||||||
|
export function visibleLength(value: string): number {
|
||||||
|
return value.replace(/\x1b\[[0-9;]*m/g, "").length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Pad a string to the given visible width (accounting for ANSI codes). */
|
||||||
|
export function padRight(value: string, width: number): string {
|
||||||
|
return value + " ".repeat(Math.max(0, width - visibleLength(value)));
|
||||||
|
}
|
||||||
Reference in new issue
Block a user