Skip to content

Instantly share code, notes, and snippets.

@Anselmoo
Last active April 5, 2026 15:13
Show Gist options
  • Select an option

  • Save Anselmoo/64e926bbc168e0dffd2c986ea53675e9 to your computer and use it in GitHub Desktop.

Select an option

Save Anselmoo/64e926bbc168e0dffd2c986ea53675e9 to your computer and use it in GitHub Desktop.
Glyphs and Emoji
/**
* glyphs_emoji.js
* JavaScript port of https://gist.github.com/Anselmoo/64e926bbc168e0dffd2c986ea53675e9
*
* Platform detection: IS_LEGACY_TERMINAL is always false in Node.js / browser
* (only legacy Windows cmd.exe / old PowerShell need ASCII fallbacks).
* Override manually if needed: glyphs_emoji.IS_LEGACY_TERMINAL = true
*/
// ---------------------------------------------------------------------------
// Platform detection
// ---------------------------------------------------------------------------
export let IS_LEGACY_TERMINAL =
typeof process !== "undefined" && process.platform === "win32";
/** Return ASCII fallback on legacy Windows terminals, Unicode elsewhere. */
function _g(windowsAscii, unicodeGlyph) {
return IS_LEGACY_TERMINAL ? windowsAscii : unicodeGlyph;
}
// ---------------------------------------------------------------------------
// Base types
// ---------------------------------------------------------------------------
export class Glyph {
constructor(symbol, name, description = "") {
this.symbol = symbol;
this.name = name;
this.description = description;
Object.freeze(this);
}
toString() { return this.symbol; }
[Symbol.toPrimitive]() { return this.symbol; }
}
export class Emoji {
constructor(symbol, name, description = "") {
this.symbol = symbol;
this.name = name;
this.description = description;
Object.freeze(this);
}
toString() { return this.symbol; }
[Symbol.toPrimitive]() { return this.symbol; }
}
// ===========================================================================
// GLYPH GROUPS
// ===========================================================================
// ---------------------------------------------------------------------------
// Box drawing
// ---------------------------------------------------------------------------
export class BoxGlyphs {
constructor() {
// Single line
this.h = new Glyph(_g("-", "─"), "h");
this.v = new Glyph(_g("|", "│"), "v");
this.tl = new Glyph(_g("+", "┌"), "top_left");
this.tr = new Glyph(_g("+", "┐"), "top_right");
this.bl = new Glyph(_g("+", "└"), "bottom_left");
this.br = new Glyph(_g("+", "┘"), "bottom_right");
this.t = new Glyph(_g("+", "┬"), "t_top");
this.b = new Glyph(_g("+", "┴"), "t_bottom");
this.l = new Glyph(_g("+", "├"), "t_left");
this.r = new Glyph(_g("+", "┤"), "t_right");
this.x = new Glyph(_g("+", "┼"), "cross");
// Double line
this.dh = new Glyph(_g("=", "═"), "double_h");
this.dv = new Glyph(_g("|", "║"), "double_v");
this.dtl = new Glyph(_g("+", "╔"), "double_top_left");
this.dtr = new Glyph(_g("+", "╗"), "double_top_right");
this.dbl = new Glyph(_g("+", "╚"), "double_bottom_left");
this.dbr = new Glyph(_g("+", "╝"), "double_bottom_right");
this.dx = new Glyph(_g("+", "╬"), "double_cross");
}
box(text, padding = 1) {
const pad = " ".repeat(padding);
const inner = `${pad}${text}${pad}`;
const w = inner.length;
const hr = this.h.symbol.repeat(w);
return [
`${this.tl}${hr}${this.tr}`,
`${this.v}${inner}${this.v}`,
`${this.bl}${hr}${this.br}`,
].join("\n");
}
doubleBox(text, padding = 1) {
const pad = " ".repeat(padding);
const inner = `${pad}${text}${pad}`;
const w = inner.length;
const hr = this.dh.symbol.repeat(w);
return [
`${this.dtl}${hr}${this.dtr}`,
`${this.dv}${inner}${this.dv}`,
`${this.dbl}${hr}${this.dbr}`,
].join("\n");
}
table(headers, rows) {
const colW = headers.map((h, i) =>
Math.max(String(h).length, ...rows.map(r => String(r[i]).length)) + 2
);
const rowLine = (cells) =>
this.v + cells.map((c, i) => ` ${String(c).padEnd(colW[i] - 1)}`).join(this.v) + this.v;
const sep = (lft, mid, rgt, fill) =>
lft + colW.map(w => fill.symbol.repeat(w)).join(mid) + rgt;
return [
sep(this.tl, this.t, this.tr, this.h),
rowLine(headers),
sep(this.l, this.x, this.r, this.h),
...rows.map(r => rowLine(r)),
sep(this.bl, this.b, this.br, this.h),
].join("\n");
}
}
// ---------------------------------------------------------------------------
// Tree / filesystem
// ---------------------------------------------------------------------------
export class TreeGlyphs {
constructor() {
this.branch = new Glyph(_g("|--", "├──"), "branch");
this.last = new Glyph(_g("`--", "└──"), "last");
this.pipe = new Glyph(_g("|", "│"), "pipe");
this.blank = new Glyph(" ", " ", "blank");
}
/**
* Render nested entries as a tree.
* entries: Array of [name, isDir, children | null]
*/
render(entries, indent = 0) {
const lines = [];
entries.forEach(([name, isDir, children], i) => {
const isLast = i === entries.length - 1;
const connector = isLast ? this.last.symbol : this.branch.symbol;
const prefix = " ".repeat(indent);
const label = isDir ? `${name}/` : name;
lines.push(`${prefix}${connector} ${label}`);
if (children && children.length) {
const sub = this.render(children, indent + 1);
sub.split("\n").forEach(line => lines.push(line));
}
});
return lines.join("\n");
}
}
// ---------------------------------------------------------------------------
// Arrows
// ---------------------------------------------------------------------------
export class ArrowGlyphs {
constructor() {
this.right = new Glyph(_g("->", "→"), "right");
this.left = new Glyph(_g("<-", "←"), "left");
this.up = new Glyph(_g("^", "↑"), "up");
this.down = new Glyph(_g("v", "↓"), "down");
this.lr = new Glyph(_g("<->", "↔"), "left_right");
this.fatRight = new Glyph(_g("=>", "⇒"), "fat_right");
this.fatLeft = new Glyph(_g("<=", "⇐"), "fat_left");
this.fatLr = new Glyph(_g("<=>", "⇔"), "fat_lr");
this.hookRight = new Glyph(_g("~>", "↪"), "hook_right");
this.hookLeft = new Glyph(_g("<~", "↩"), "hook_left");
this.upRight = new Glyph(_g("/^", "↗"), "up_right");
this.downRight = new Glyph(_g("\\v", "↘"), "down_right");
this.upLeft = new Glyph(_g("^\\", "↖"), "up_left");
this.downLeft = new Glyph(_g("v/", "↙"), "down_left");
this.clockwise = new Glyph(_g("(->)", "↻"), "clockwise");
this.counterCw = new Glyph(_g("(<-)", "↺"), "counter_clockwise");
this.pipeRight = new Glyph(_g("|>", "▷"), "pipe_right");
this.squiggle = new Glyph(_g("~>", "⇝"), "squiggle_right");
this.longRight = new Glyph(_g("-->", "⟶"), "long_right");
this.longLeft = new Glyph(_g("<--", "⟵"), "long_left");
this.mapsTo = new Glyph(_g("|->", "↦"), "maps_to");
}
}
// ---------------------------------------------------------------------------
// Progress / blocks
// ---------------------------------------------------------------------------
const SPINNER_BRAILLE = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];
const SPINNER_ASCII = ["|", "/", "-", "\\"];
const SPINNER_ARROW = ["←","↖","↑","↗","→","↘","↓","↙"];
const SPINNER_BOUNCE = ["▁","▃","▄","▅","▆","▇","█","▇","▆","▅","▄","▃"];
const SPINNER_PULSE = ["·","●","◉","●","·"];
const SPINNER_BAR = ["▏","▎","▍","▌","▋","▊","▉","█","▉","▊","▋","▌","▍","▎"];
export class ProgressGlyphs {
constructor() {
this.full = new Glyph(_g("#", "█"), "full");
this.high = new Glyph(_g("=", "▓"), "high");
this.mid = new Glyph(_g("-", "▒"), "mid");
this.low = new Glyph(_g(".", "░"), "low");
this.empty = new Glyph(_g(".", " "), "empty");
this.barL = new Glyph(_g("[", "▕"), "bar_left");
this.barR = new Glyph(_g("]", "▏"), "bar_right");
}
/** Returns an infinite generator of spinner frames. */
*spinner(style = "braille") {
const map = {
braille: SPINNER_BRAILLE,
ascii: SPINNER_ASCII,
arrow: SPINNER_ARROW,
bounce: SPINNER_BOUNCE,
pulse: SPINNER_PULSE,
bar: SPINNER_BAR,
};
const frames = IS_LEGACY_TERMINAL
? SPINNER_ASCII
: (map[style] ?? SPINNER_BRAILLE);
let i = 0;
while (true) yield frames[i++ % frames.length];
}
renderBar(value, width = 20) {
const filled = Math.round(value * width);
const bar = this.full.symbol.repeat(filled) + this.low.symbol.repeat(width - filled);
return `${this.barL}${bar}${this.barR} ${Math.round(value * 100)}%`;
}
renderSegmented(value, width = 20) {
if (IS_LEGACY_TERMINAL) return this.renderBar(value, width);
const eighths = ["", "▏","▎","▍","▌","▋","▊","▉","█"];
const total = Math.round(value * width * 8);
const full = Math.floor(total / 8);
const rem = total % 8;
const bar = "█".repeat(full) + eighths[rem];
return `▕${bar.padEnd(width)}▏ ${Math.round(value * 100)}%`;
}
}
// ---------------------------------------------------------------------------
// Math / operators
// ---------------------------------------------------------------------------
export class MathGlyphs {
constructor() {
this.approx = new Glyph(_g("~=", "≈"), "approx");
this.notEqual = new Glyph(_g("!=", "≠"), "not_equal");
this.lte = new Glyph(_g("<=", "≤"), "lte");
this.gte = new Glyph(_g(">=", "≥"), "gte");
this.infinity = new Glyph(_g("inf", "∞"), "infinity");
this.sum = new Glyph(_g("SUM", "∑"), "sum");
this.product = new Glyph(_g("PROD", "∏"), "product");
this.sqrt = new Glyph(_g("sqrt", "√"), "sqrt");
this.delta = new Glyph(_g("D", "Δ"), "delta");
this.degree = new Glyph(_g("deg", "°"), "degree");
this.plusMinus = new Glyph(_g("+/-", "±"), "plus_minus");
this.integral = new Glyph(_g("INT", "∫"), "integral");
this.partial = new Glyph(_g("d/", "∂"), "partial");
this.nabla = new Glyph(_g("V", "∇"), "nabla");
this.elementOf = new Glyph(_g("in", "∈"), "element_of");
this.notElement = new Glyph(_g("!in", "∉"), "not_element_of");
this.subset = new Glyph(_g("<C", "⊂"), "subset");
this.superset = new Glyph(_g(">C", "⊃"), "superset");
this.union = new Glyph(_g("U", "∪"), "union");
this.intersect = new Glyph(_g("^", "∩"), "intersection");
this.forAll = new Glyph(_g("forall", "∀"), "for_all");
this.exists = new Glyph(_g("exists", "∃"), "exists");
this.emptySet = new Glyph(_g("{}", "∅"), "empty_set");
this.therefore = new Glyph(_g(":..", "∴"), "therefore");
this.because = new Glyph(_g("..:", "∵"), "because");
this.proportional = new Glyph(_g("oc", "∝"), "proportional");
this.perpendicular = new Glyph(_g("_|_", "⊥"), "perpendicular");
this.parallel = new Glyph(_g("||", "∥"), "parallel");
this.lambda = new Glyph(_g("lam", "λ"), "lambda");
this.mu = new Glyph(_g("mu", "μ"), "mu");
this.sigma = new Glyph(_g("sig", "σ"), "sigma");
this.pi = new Glyph(_g("pi", "π"), "pi");
this.phi = new Glyph(_g("phi", "φ"), "phi");
this.omega = new Glyph(_g("ohm", "Ω"), "omega");
}
}
// ---------------------------------------------------------------------------
// Bullets / markers
// ---------------------------------------------------------------------------
export class BulletGlyphs {
constructor() {
this.dot = new Glyph(_g("*", "•"), "dot");
this.middleDot = new Glyph(_g(".", "·"), "middle_dot");
this.circle = new Glyph(_g("o", "○"), "circle");
this.circleFill = new Glyph(_g("O", "●"), "circle_filled");
this.square = new Glyph(_g("[ ]", "□"), "square");
this.squareFill = new Glyph(_g("[#]", "■"), "square_filled");
this.diamond = new Glyph(_g("<>", "◆"), "diamond");
this.diamondO = new Glyph(_g("<>", "◇"), "diamond_open");
this.triangle = new Glyph(_g(">", "▶"), "triangle");
this.triangleO = new Glyph(_g(">", "▷"), "triangle_open");
this.star = new Glyph(_g("*", "★"), "star");
this.starO = new Glyph(_g("*", "☆"), "star_open");
this.check = new Glyph(_g("[x]", "✔"), "check");
this.cross = new Glyph(_g("[_]", "✘"), "cross");
this.dash = new Glyph(_g("-", "–"), "en_dash");
this.emDash = new Glyph(_g("--", "—"), "em_dash");
this.arrow = new Glyph(_g("->", "➤"), "arrow");
this.lozenge = new Glyph(_g("<>", "◊"), "lozenge");
this.ring = new Glyph(_g("()", "◌"), "ring");
}
}
// ---------------------------------------------------------------------------
// Typography
// ---------------------------------------------------------------------------
export class TypographyGlyphs {
constructor() {
this.ellipsis = new Glyph(_g("...", "…"), "ellipsis");
this.pilcrow = new Glyph(_g("[P]", "¶"), "pilcrow");
this.section = new Glyph(_g("[S]", "§"), "section");
this.dagger = new Glyph(_g("[+]", "†"), "dagger");
this.doubleDag = new Glyph(_g("[++]", "‡"), "double_dagger");
this.trademark = new Glyph(_g("(TM)", "™"), "trademark");
this.registered = new Glyph(_g("(R)", "®"), "registered");
this.copyright = new Glyph(_g("(C)", "©"), "copyright");
this.openDquote = new Glyph(_g('"', "\u201C"), "open_double_quote");
this.closeDquote = new Glyph(_g('"', "\u201D"), "close_double_quote");
this.openSquote = new Glyph(_g("'", "\u2018"), "open_single_quote");
this.closeSquote = new Glyph(_g("'", "\u2019"), "close_single_quote");
this.ndash = new Glyph(_g("-", "–"), "en_dash");
this.mdash = new Glyph(_g("--", "—"), "em_dash");
this.interrobang = new Glyph(_g("?!", "‽"), "interrobang");
this.nbsp = new Glyph(" ", "\u00A0", "non_breaking_space");
}
smartQuote(text) {
return `${this.openDquote}${text}${this.closeDquote}`;
}
}
// ---------------------------------------------------------------------------
// Log levels
// ---------------------------------------------------------------------------
export class LogLevelGlyphs {
constructor() {
this.trace = new Glyph(_g(".", "·"), "trace");
this.debug = new Glyph(_g("o", "○"), "debug");
this.info = new Glyph(_g("*", "●"), "info");
this.notice = new Glyph(_g("<>", "◆"), "notice");
this.warning = new Glyph(_g("/!\\", "▲"), "warning");
this.error = new Glyph(_g("[E]", "✖"), "error");
this.critical = new Glyph(_g("[!!]", "⊘"), "critical");
this.fatal = new Glyph(_g("[XX]", "☠"), "fatal");
this.ok = new Glyph(_g("[OK]", "✔"), "ok");
this.skip = new Glyph(_g("[-]", "⊖"), "skip");
this.sep = new Glyph(_g("---", "─────"), "separator");
this.scopeL = new Glyph(_g("[", "❬"), "scope_left");
this.scopeR = new Glyph(_g("]", "❭"), "scope_right");
this.pipe = new Glyph(_g("|", "│"), "pipe");
this.ellipsis = new Glyph(_g("...", "…"), "ellipsis");
}
label(level, width = 8) {
const map = {
trace: this.trace, debug: this.debug, info: this.info,
notice: this.notice, warning: this.warning, warn: this.warning,
error: this.error, critical: this.critical, fatal: this.fatal,
};
const g = map[level.toLowerCase()] ?? this.info;
const name = level.toUpperCase().padEnd(width);
return `${g} ${name} ${this.pipe}`;
}
formatLine(level, message, scope = "") {
const prefix = this.label(level);
if (scope) return `${prefix} ${this.scopeL}${scope}${this.scopeR} ${message}`;
return `${prefix} ${message}`;
}
}
// ---------------------------------------------------------------------------
// Diff / patch
// ---------------------------------------------------------------------------
export class DiffGlyphs {
constructor() {
this.added = new Glyph("+", "+", "added");
this.removed = new Glyph("-", "─", "removed");
this.modified = new Glyph("~", "~", "modified");
this.unchanged = new Glyph(" ", " ", "unchanged");
this.conflict = new Glyph(_g("!", "≠"), "conflict");
this.moved = new Glyph(_g("->", "→"), "moved");
this.renamed = new Glyph(_g("=>", "⇒"), "renamed");
this.hunk = new Glyph(_g("@@", "⊕⊕"), "hunk");
this.arrowAdd = new Glyph(_g("+>", "┼"), "arrow_add");
this.blockAdd = new Glyph(_g("++", "▌"), "block_add");
this.blockRem = new Glyph(_g("--", "▐"), "block_remove");
}
line(kind, text, lineno = null) {
const map = {
added: this.added, removed: this.removed,
modified: this.modified, unchanged: this.unchanged,
};
const g = map[kind] ?? this.unchanged;
const num = lineno != null ? String(lineno).padStart(4) + " " : "";
return `${num}${g} ${text}`;
}
}
// ---------------------------------------------------------------------------
// Git
// ---------------------------------------------------------------------------
export class GitGlyphs {
constructor() {
// Graph nodes
this.commit = new Glyph(_g("o", "●"), "commit");
this.merge = new Glyph(_g("M", "◎"), "merge_commit");
this.tagNode = new Glyph(_g("#", "◈"), "tag_node");
this.head = new Glyph(_g("H", "◉"), "head");
this.stash = new Glyph(_g("s", "⊙"), "stash");
this.remote = new Glyph(_g("r", "◯"), "remote");
// Graph connectors
this.graphV = new Glyph(_g("|", "│"), "graph_vertical");
this.graphH = new Glyph(_g("-", "─"), "graph_horizontal");
this.graphTl = new Glyph(_g("/", "╮"), "graph_top_left");
this.graphBr = new Glyph(_g("\\", "╯"), "graph_bottom_right");
this.graphBl = new Glyph(_g("\\", "╰"), "graph_bottom_left");
this.graphTr = new Glyph(_g("/", "╭"), "graph_top_right");
this.graphX = new Glyph(_g("*", "┼"), "graph_cross");
// Branch / status indicators
this.branch = new Glyph(_g("br", "⎇"), "branch");
this.ahead = new Glyph(_g("^", "↑"), "ahead");
this.behind = new Glyph(_g("v", "↓"), "behind");
this.diverged = new Glyph(_g("^v", "↕"), "diverged");
this.added = new Glyph("+", "added");
this.removed = new Glyph("-", "removed");
this.modified = new Glyph("~", "modified");
this.untracked= new Glyph("?", "untracked");
this.ignored = new Glyph("!", "ignored");
this.conflict = new Glyph(_g("!=", "≠"), "conflict");
this.clean = new Glyph(_g("OK", "✔"), "clean");
this.dirty = new Glyph(_g("*", "✎"), "dirty");
// Ref decorators
this.refL = new Glyph("(", "(", "ref_left");
this.refR = new Glyph(")", ")", "ref_right");
}
statusLine(branchName, ahead = 0, behind = 0, modified = 0, untracked = 0) {
const parts = [`${this.branch} ${branchName}`];
if (ahead) parts.push(`${this.ahead}${ahead}`);
if (behind) parts.push(`${this.behind}${behind}`);
if (modified) parts.push(`${this.modified}${modified}`);
if (untracked) parts.push(`${this.untracked}${untracked}`);
const status = (modified || untracked) ? this.dirty : this.clean;
parts.push(String(status));
return parts.join(" ");
}
logLine(sha, message, refs = []) {
const refStr = refs.length
? " " + refs.map(r => `${this.refL}${r}${this.refR}`).join(" ")
: "";
return `${this.commit} ${sha.slice(0, 7)}${refStr} ${message}`;
}
}
// ---------------------------------------------------------------------------
// CI/CD pipeline
// ---------------------------------------------------------------------------
export class CICDGlyphs {
constructor() {
// Stage / job states
this.passed = new Glyph(_g("[OK]", "✔"), "passed");
this.failed = new Glyph(_g("[FL]", "✖"), "failed");
this.running = new Glyph(_g("[>>]", "▶"), "running");
this.queued = new Glyph(_g("[Q]", "◷"), "queued");
this.canceled = new Glyph(_g("[CX]", "⊘"), "canceled");
this.skipped = new Glyph(_g("[SK]", "⊖"), "skipped");
this.manual = new Glyph(_g("[M]", "◈"), "manual");
this.blocked = new Glyph(_g("[BL]", "⊗"), "blocked");
this.created = new Glyph(_g("[C]", "○"), "created");
// Stage types
this.build = new Glyph(_g("[B]", "⚙"), "build");
this.test = new Glyph(_g("[T]", "⚗"), "test");
this.lint = new Glyph(_g("[L]", "⌥"), "lint");
this.scan = new Glyph(_g("[SC]", "⌕"), "scan");
this.deploy = new Glyph(_g("[D]", "⬆"), "deploy");
this.release = new Glyph(_g("[R]", "◆"), "release");
this.rollback = new Glyph(_g("[RB]", "↩"), "rollback");
this.artifact = new Glyph(_g("[A]", "⊡"), "artifact");
this.trigger = new Glyph(_g("[TR]", "⇒"), "trigger");
this.notify = new Glyph(_g("[N]", "◎"), "notify");
// Pipeline connectors
this.stageSep = new Glyph(_g("->", "→"), "stage_sep");
this.parallel = new Glyph(_g("||", "⫴"), "parallel");
}
/** stages: Array of [stageType, status] e.g. [["build","passed"],["test","running"]] */
pipeline(stages) {
const typeMap = {
build: this.build, test: this.test, lint: this.lint,
scan: this.scan, deploy: this.deploy, release: this.release,
};
const stateMap = {
passed: this.passed, failed: this.failed, running: this.running,
queued: this.queued, canceled: this.canceled, skipped: this.skipped,
manual: this.manual, blocked: this.blocked,
};
return stages
.map(([type, status]) => `${typeMap[type] ?? this.build}${stateMap[status] ?? this.queued}`)
.join(` ${this.stageSep} `);
}
}
// ---------------------------------------------------------------------------
// Code / programming symbols
// ---------------------------------------------------------------------------
export class CodeGlyphs {
constructor() {
// Code constructs
this.function = new Glyph(_g("fn", "ƒ"), "function");
this.lambda = new Glyph(_g("lam", "λ"), "lambda");
this.class_ = new Glyph(_g("cls", "⊞"), "class");
this.interface = new Glyph(_g("iface", "⊟"), "interface");
this.type = new Glyph(_g("T", "τ"), "type");
this.generic = new Glyph(_g("<T>", "⟨T⟩"), "generic");
this.variable = new Glyph(_g("var", "υ"), "variable");
this.constant = new Glyph(_g("CONST", "κ"), "constant");
this.module = new Glyph(_g("mod", "⊕"), "module");
this.namespace = new Glyph(_g("ns", "⊗"), "namespace");
this.import_ = new Glyph(_g("use", "⇐"), "import");
this.export_ = new Glyph(_g("pub", "⇒"), "export");
// Flow / logic
this.branch = new Glyph(_g("if", "⑂"), "branch");
this.loop = new Glyph(_g("for", "↻"), "loop");
this.recurse = new Glyph(_g("rec", "⟳"), "recurse");
this.async_ = new Glyph(_g("~>", "⇝"), "async");
this.await_ = new Glyph(_g("<~", "⊸"), "await");
this.yield_ = new Glyph(_g("<<", "⟵"), "yield");
this.return_ = new Glyph(_g("<-", "↵"), "return");
this.throw_ = new Glyph(_g("!!!", "↯"), "throw");
// Values / types
this.null_ = new Glyph(_g("null", "∅"), "null");
this.true_ = new Glyph(_g("T", "⊤"), "true");
this.false_ = new Glyph(_g("F", "⊥"), "false");
this.some = new Glyph(_g("Some", "◉"), "some");
this.none = new Glyph(_g("None", "◌"), "none");
this.ok_ = new Glyph(_g("Ok", "✔"), "ok");
this.err_ = new Glyph(_g("Err", "✖"), "err");
// Operators
this.compose = new Glyph(_g(">>", "∘"), "compose");
this.pipeOp = new Glyph(_g("|>", "▷"), "pipe_operator");
this.bind = new Glyph(_g(">>=", "≫="), "bind");
this.mapsTo = new Glyph(_g("|->", "↦"), "maps_to");
this.equiv = new Glyph(_g("===", "≡"), "equivalent");
this.notEquiv = new Glyph(_g("!==", "≢"), "not_equivalent");
// Memory / runtime
this.pointer = new Glyph(_g("*", "⊛"), "pointer");
this.ref = new Glyph("&", "reference");
this.deref = new Glyph(_g("*", "✱"), "dereference");
this.alloc = new Glyph(_g("new", "⊞"), "allocate");
this.free = new Glyph(_g("del", "⊟"), "free");
}
}
// ---------------------------------------------------------------------------
// Analysis / metrics
// ---------------------------------------------------------------------------
const SPARK = [" ","▁","▂","▃","▄","▅","▆","▇","█"];
export class AnalysisGlyphs {
constructor() {
this.trendUp = new Glyph(_g("/^", "↗"), "trend_up");
this.trendDown = new Glyph(_g("\\v", "↘"), "trend_down");
this.trendFlat = new Glyph(_g("->", "→"), "trend_flat");
this.spike = new Glyph(_g("/!\\", "⚡"), "spike");
this.drop = new Glyph(_g("\\!", "⬇"), "drop");
this.scoreFull = new Glyph(_g("[*]", "★"), "score_full");
this.scoreHalf = new Glyph(_g("[/]", "⯨"), "score_half");
this.scoreEmpty = new Glyph(_g("[ ]", "☆"), "score_empty");
this.better = new Glyph(_g(">", "⊳"), "better");
this.worse = new Glyph(_g("<", "⊲"), "worse");
this.same = new Glyph(_g("=", "≈"), "same");
this.p50 = new Glyph(_g("p50", "⊕"), "median");
this.outlier = new Glyph(_g("(!)", "⊛"), "outlier");
}
sparkline(values) {
const mn = Math.min(...values);
const mx = Math.max(...values);
const rng = mx - mn || 1;
if (IS_LEGACY_TERMINAL) {
return values.map(v => String(Math.round((v - mn) / rng * 9)).padStart(2)).join("");
}
return values.map(v => SPARK[Math.round((v - mn) / rng * 8)]).join("");
}
rating(score, maxScore = 5.0, width = 5) {
const ratio = score / maxScore;
const full = Math.floor(ratio * width);
const hasHalf = (ratio * width - full) >= 0.5;
const empty = width - full - (hasHalf ? 1 : 0);
return (
this.scoreFull.symbol.repeat(full) +
(hasHalf ? this.scoreHalf.symbol : "") +
this.scoreEmpty.symbol.repeat(empty) +
` ${score}/${maxScore}`
);
}
delta(oldVal, newVal, unit = "") {
const diff = newVal - oldVal;
const pct = oldVal ? (diff / oldVal * 100) : 0;
const glyph = diff > 0 ? this.trendUp : (diff < 0 ? this.trendDown : this.trendFlat);
const sign = diff >= 0 ? "+" : "";
return `${glyph} ${sign}${diff.toFixed(2)}${unit} (${sign}${pct.toFixed(1)}%)`;
}
}
// ===========================================================================
// EMOJI GROUPS
// ===========================================================================
export class StatusEmojis {
constructor() {
this.success = new Emoji("✅", "success");
this.error = new Emoji("❌", "error");
this.warning = new Emoji("⚠️", "warning");
this.info = new Emoji("ℹ️", "info");
this.pending = new Emoji("⏳", "pending");
this.skipped = new Emoji("⏭️", "skipped");
this.question = new Emoji("❓", "question");
this.debug = new Emoji("🐛", "debug");
this.locked = new Emoji("🔒", "locked");
this.unlocked = new Emoji("🔓", "unlocked");
this.new_ = new Emoji("🆕", "new");
this.hot = new Emoji("🔥", "hot");
this.pinned = new Emoji("📌", "pinned");
this.flag = new Emoji("🚩", "flag");
this.robot = new Emoji("🤖", "robot");
}
}
export class FileEmojis {
constructor() {
this.folder = new Emoji("📁", "folder");
this.folderO = new Emoji("📂", "folder_open");
this.file = new Emoji("📄", "file");
this.link = new Emoji("🔗", "link");
this.image = new Emoji("🖼️", "image");
this.video = new Emoji("🎬", "video");
this.audio = new Emoji("🎵", "audio");
this.archive = new Emoji("🗜️", "archive");
this.config = new Emoji("⚙️", "config");
this.trash = new Emoji("🗑️", "trash");
this.key = new Emoji("🔑", "key");
this.secret = new Emoji("🔐", "secret");
this.database = new Emoji("🗄️", "database");
this.terminal = new Emoji("🖥️", "terminal");
this.package = new Emoji("📦", "package");
}
}
export class DevEmojis {
constructor() {
this.feat = new Emoji("✨", "feature");
this.fix = new Emoji("🐛", "bugfix");
this.hotfix = new Emoji("🚑", "hotfix");
this.refactor = new Emoji("♻️", "refactor");
this.perf = new Emoji("⚡", "performance");
this.test = new Emoji("🧪", "test");
this.docs = new Emoji("📝", "docs");
this.style = new Emoji("🎨", "style");
this.chore = new Emoji("🔧", "chore");
this.revert = new Emoji("⏪", "revert");
this.merge = new Emoji("🔀", "merge");
this.release = new Emoji("🚀", "release");
this.deprecate = new Emoji("🗑️", "deprecate");
this.remove = new Emoji("🔥", "remove");
this.security = new Emoji("🔒", "security");
this.deps = new Emoji("📦", "dependencies");
this.ci = new Emoji("⚙️", "ci");
this.breaking = new Emoji("💥", "breaking_change");
this.wip = new Emoji("🚧", "wip");
this.config = new Emoji("🔧", "config");
}
conventionalCommit(kind, scope, message) {
const map = {
feat: this.feat, fix: this.fix, hotfix: this.hotfix,
refactor: this.refactor, perf: this.perf, test: this.test,
docs: this.docs, style: this.style, chore: this.chore,
revert: this.revert, ci: this.ci, deps: this.deps,
};
const e = map[kind] ?? this.chore;
const scopeStr = scope ? `(${scope})` : "";
return `${e} ${kind}${scopeStr}: ${message}`;
}
}
// ===========================================================================
// REGISTRY
// ===========================================================================
export class GlyphRegistry {
constructor() {
// Glyph groups
this.box = new BoxGlyphs();
this.tree = new TreeGlyphs();
this.arrows = new ArrowGlyphs();
this.progress = new ProgressGlyphs();
this.math = new MathGlyphs();
this.bullets = new BulletGlyphs();
this.typography = new TypographyGlyphs();
this.log = new LogLevelGlyphs();
this.diff = new DiffGlyphs();
this.git = new GitGlyphs();
this.cicd = new CICDGlyphs();
this.code = new CodeGlyphs();
this.analysis = new AnalysisGlyphs();
// Emoji groups
this.statusEmoji = new StatusEmojis();
this.fileEmoji = new FileEmojis();
this.devEmoji = new DevEmojis();
}
}
/** Singleton — mirrors `glyphs = GlyphRegistry()` in the Python original. */
export const glyphs = new GlyphRegistry();
export default glyphs;
// ===========================================================================
// Demo (run with: node glyphs_emoji.js)
// ===========================================================================
if (
typeof process !== "undefined" &&
process.argv[1] &&
process.argv[1].endsWith("glyphs_emoji.js")
) {
const g = glyphs;
const sep = (t) => console.log(`\n── ${t} ${"─".repeat(Math.max(1, 42 - t.length))}`);
console.log(`Platform: ${IS_LEGACY_TERMINAL ? "Legacy Windows" : "Modern terminal"}`);
sep("Log levels");
for (const level of ["trace","debug","info","notice","warning","error","critical","fatal"]) {
console.log(` ${g.log.formatLine(level, `Sample ${level} message`, "auth")}`);
}
sep("Git status");
console.log(` ${g.git.statusLine("feature/my-branch", 3, 1, 5, 2)}`);
console.log(` ${g.git.logLine("abc1234", "feat: add login flow", ["HEAD", "origin/main"])}`);
console.log(` ${g.git.logLine("def5678", "fix: null pointer in parser")}`);
sep("Diff");
for (const [kind, txt, n] of [
["added", "def new_feature():", 10],
["unchanged", " pass", 11],
["removed", "def old_feature():", 12],
["modified", " return result", 13],
]) {
console.log(` ${g.diff.line(kind, txt, n)}`);
}
sep("CI/CD pipeline");
console.log(` ${g.cicd.pipeline([
["lint", "passed"],
["build", "passed"],
["test", "running"],
["scan", "queued"],
["deploy", "blocked"],
])}`);
sep("Code symbols");
const syms = [
g.code.function, g.code.lambda, g.code.class_,
g.code.async_, g.code.await_, g.code.pipeOp,
g.code.compose, g.code.bind, g.code.ok_,
g.code.err_, g.code.null_, g.code.true_,
g.code.false_, g.code.pointer,g.code.throw_,
];
console.log(" " + syms.map(s => `${s}(${s.name})`).join(" "));
sep("Analysis");
const data = [4, 12, 8, 22, 17, 30, 25, 10, 18, 28];
console.log(` Sparkline : ${g.analysis.sparkline(data)}`);
console.log(` Rating : ${g.analysis.rating(3.5)}`);
console.log(` Delta : ${g.analysis.delta(120.0, 145.5, "ms")}`);
console.log(` Delta : ${g.analysis.delta(145.5, 130.0, "ms")}`);
sep("Progress bars");
for (const v of [0.0, 0.33, 0.67, 1.0]) {
console.log(` ${g.progress.renderSegmented(v)}`);
}
sep("Spinner styles (6 frames each)");
for (const style of ["braille","ascii","arrow","bounce","pulse","bar"]) {
const sp = g.progress.spinner(style);
const frames = Array.from({ length: 6 }, () => sp.next().value).join(" ");
console.log(` ${style.padEnd(10)} ${frames}`);
}
sep("Box table");
console.log(g.box.table(
["Level", "Glyph", "Count"],
[
["error", String(g.log.error), "12"],
["warning", String(g.log.warning), "34"],
["info", String(g.log.info), "198"],
]
));
sep("Conventional commits (emoji)");
for (const [kind, scope, msg] of [
["feat", "auth", "add OAuth2 login"],
["fix", "parser", "handle empty input"],
["breaking", "", "rename config keys"],
["ci", "github", "add matrix build"],
]) {
console.log(` ${g.devEmoji.conventionalCommit(kind, scope, msg)}`);
}
sep("Math (extended)");
const row = [
g.math.lambda, g.math.sigma, g.math.pi, g.math.phi, g.math.omega,
g.math.integral, g.math.nabla, g.math.forAll, g.math.exists,
g.math.emptySet, g.math.therefore, g.math.perpendicular,
];
console.log(" " + row.map(String).join(" "));
}

API Reference — glyphs_emoji.py / glyphs-emoji.js

Full symbol listing per group. All glyphs are accessed via glyphs.<group>.<field>.


BoxGlyphs (glyphs.box)

Field Unicode ASCII fallback Description
h - horizontal
v | vertical
tl + top-left corner
tr + top-right corner
bl + bottom-left corner
br + bottom-right corner
t + T-top
b + T-bottom
l + T-left
r + T-right
x + cross
dh = double horizontal
dv | double vertical
dtl + double top-left
dtr + double top-right
dbl + double bottom-left
dbr + double bottom-right
dx + double cross

Methods: box(text, padding=1), double_box(text, padding=1), table(headers, rows)


TreeGlyphs (glyphs.tree)

Field Unicode ASCII
branch ├── |--
last └── `--
pipe |
blank

Methods: render(entries, indent=0) — entries: list[(name, is_dir, children|None)]


ArrowGlyphs (glyphs.arrows)

Field Unicode ASCII
right ->
left <-
up ^
down v
lr <->
fat_right =>
fat_left <=
fat_lr <=>
hook_right ~>
hook_left <~
up_right /^
down_right \v
up_left ^\
down_left v/
clockwise (->)
counter_cw (<-)
pipe_right |>
squiggle ~>
long_right -->
long_left <--
maps_to |->

ProgressGlyphs (glyphs.progress)

Field Unicode ASCII
full #
high =
mid -
low .
empty .
bar_l [
bar_r ]

Spinner tuples (constants): SPINNER_BRAILLE, SPINNER_ASCII, SPINNER_ARROW, SPINNER_BOUNCE, SPINNER_PULSE, SPINNER_BAR

Methods:

  • spinner(style="braille")Iterator[str] (infinite cycle)
  • render_bar(value: float, width=20) → block bar string
  • render_segmented(value: float, width=20) → 1/8-precision bar string

MathGlyphs (glyphs.math)

Field Unicode ASCII
approx ~=
not_equal !=
lte <=
gte >=
infinity inf
sum SUM
product PROD
sqrt sqrt
delta Δ D
degree ° deg
plus_minus ± +/-
integral INT
partial d/
nabla V
element_of in
not_element !in
subset <C
superset >C
union U
intersect ^
for_all forall
exists exists
empty_set {}
therefore :..
because ..:
proportional oc
perpendicular _|_
parallel ||
lambda_ λ lam
mu μ mu
sigma σ sig
pi π pi
phi φ phi
omega Ω ohm

BulletGlyphs (glyphs.bullets)

Field Unicode ASCII
dot *
middle_dot · .
circle o
circle_fill O
square [ ]
square_fill [#]
diamond <>
diamond_o <>
triangle >
triangle_o >
star *
star_o *
check [x]
cross [_]
dash -
em_dash --
arrow ->
lozenge <>
ring ()

TypographyGlyphs (glyphs.typography)

Field Unicode ASCII
ellipsis ...
pilcrow [P]
section § [S]
dagger [+]
double_dag [++]
trademark (TM)
registered ® (R)
copyright © (C)
open_dquote " "
close_dquote " "
open_squote ' '
close_squote ' '
ndash -
mdash --
interrobang ?!
nbsp NBSP

Methods: smart_quote(text)"text"


LogLevelGlyphs (glyphs.log)

Field Unicode ASCII
trace · .
debug o
info *
notice <>
warning /!\
error [E]
critical [!!]
fatal [XX]
ok [OK]
skip [-]
sep ───── ---
scope_l [
scope_r ]
pipe |
ellipsis ...

Methods:

  • label(level, width=8)"● INFO │"
  • format_line(level, message, scope="") → full log line

DiffGlyphs (glyphs.diff)

Field Unicode ASCII
added + +
removed -
modified ~ ~
unchanged
conflict !
moved ->
renamed =>
hunk ⊕⊕ @@
arrow_add +>
block_add ++
block_rem --

Methods: line(kind, text, lineno=None) — kind: added|removed|modified|unchanged


GitGlyphs (glyphs.git)

Field Unicode ASCII
commit o
merge M
tag_node #
head H
stash s
remote r
branch br
ahead ^
behind v
diverged ^v
added + +
removed - -
modified ~ ~
untracked ? ?
ignored ! !
conflict !=
clean OK
dirty *

Methods:

  • status_line(branch_name, ahead=0, behind=0, modified=0, untracked=0)
  • log_line(sha, message, refs=())

CICDGlyphs (glyphs.cicd)

Stage states: passed ✔, failed ✖, running ▶, queued ◷, canceled ⊘, skipped ⊖, manual ◈, blocked ⊗, created ○

Stage types: build ⚙, test ⚗, lint ⌥, scan ⌕, deploy ⬆, release ◆, rollback ↩, artifact ⊡, trigger ⇒, notify ◎

Connectors: stage_sep →, parallel ⫴

Methods: pipeline(stages) — stages: list[(stage_type, status)]


CodeGlyphs (glyphs.code)

Field Unicode ASCII
function ƒ fn
lambda_ λ lam
class_ cls
interface iface
type_ τ T
generic ⟨T⟩ <T>
variable υ var
constant κ CONST
module mod
namespace ns
import_ use
export_ pub
branch if
loop for
recurse rec
async_ ~>
await_ <~
yield_ <<
return_ <-
throw_ !!!
null null
true_ T
false_ F
some Some
none None
ok_ Ok
err_ Err
compose >>
pipe_op |>
bind ≫= >>=
maps_to |->
equiv ===
not_equiv !==
pointer *
ref & &
deref *
alloc new
free del

AnalysisGlyphs (glyphs.analysis)

Field Unicode ASCII
trend_up /^
trend_down \v
trend_flat ->
spike /!\
drop \!
score_full [*]
score_half [/]
score_empty [ ]
better >
worse <
same =
p50 p50
outlier (!)

Spark chars (constant): SPARK = (" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█")

Methods:

  • sparkline(values: list[float]) → unicode sparkline string
  • rating(score, max_score=5.0, width=5) → star rating string
  • delta(old, new, unit="") → trend + diff string

StatusEmojis (glyphs.status_emoji)

Field Emoji
success
error
warning ⚠️
info ℹ️
pending
skipped ⏭️
question
debug 🐛
locked 🔒
unlocked 🔓
new 🆕
hot 🔥
pinned 📌
flag 🚩
robot 🤖

FileEmojis (glyphs.file_emoji)

Field Emoji
folder 📁
folder_o 📂
file 📄
link 🔗
image 🖼️
video 🎬
audio 🎵
archive 🗜️
config ⚙️
trash 🗑️
key 🔑
secret 🔐
database 🗄️
terminal 🖥️
package 📦

DevEmojis (glyphs.dev_emoji)

Field Emoji Commit type
feat feature
fix 🐛 bugfix
hotfix 🚑 hotfix
refactor ♻️ refactor
perf performance
test 🧪 test
docs 📝 docs
style 🎨 style
chore 🔧 chore
revert revert
merge 🔀 merge
release 🚀 release
deprecate 🗑️ deprecate
remove 🔥 remove
security 🔒 security
deps 📦 dependencies
ci ⚙️ ci
breaking 💥 breaking change
wip 🚧 wip
config 🔧 config

Methods: conventional_commit(kind, scope, message)"✨ feat(auth): add OAuth2"

import sys
import itertools
from dataclasses import dataclass, field
from typing import Iterator
# ---------------------------------------------------------------------------
# Platform detection
# _g() is ONLY for Unicode glyphs that may fail on legacy Windows terminals
# (cmd.exe, older PowerShell). Emojis are handled separately — they work
# on both platforms on any modern terminal (Windows Terminal, iTerm2, etc.)
# ---------------------------------------------------------------------------
IS_LEGACY_TERMINAL = sys.platform == "win32"
def _g(windows_ascii: str, unicode_glyph: str) -> str:
"""Return ASCII fallback on legacy Windows terminals, Unicode elsewhere."""
return windows_ascii if IS_LEGACY_TERMINAL else unicode_glyph
# ---------------------------------------------------------------------------
# Base types
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class Glyph:
"""A single platform-aware Unicode symbol (NOT an emoji)."""
symbol: str
name: str
description: str = ""
def __str__(self) -> str:
return self.symbol
def __repr__(self) -> str:
return f"Glyph({self.symbol!r}, name={self.name!r})"
@dataclass(frozen=True)
class Emoji:
"""
A Unicode emoji. Works on both Windows and Unix on modern terminals.
No platform fallback needed — that's the whole point of separating this.
"""
symbol: str
name: str
description: str = ""
def __str__(self) -> str:
return self.symbol
def __repr__(self) -> str:
return f"Emoji({self.symbol!r}, name={self.name!r})"
# ===========================================================================
# GLYPH GROUPS (Unicode symbols — use _g() where Windows may fail)
# ===========================================================================
# ---------------------------------------------------------------------------
# Box drawing
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class BoxGlyphs:
# Single line
h: Glyph = field(default_factory=lambda: Glyph(_g("-", "─"), "h"))
v: Glyph = field(default_factory=lambda: Glyph(_g("|", "│"), "v"))
tl: Glyph = field(default_factory=lambda: Glyph(_g("+", "┌"), "top_left"))
tr: Glyph = field(default_factory=lambda: Glyph(_g("+", "┐"), "top_right"))
bl: Glyph = field(default_factory=lambda: Glyph(_g("+", "└"), "bottom_left"))
br: Glyph = field(default_factory=lambda: Glyph(_g("+", "┘"), "bottom_right"))
t: Glyph = field(default_factory=lambda: Glyph(_g("+", "┬"), "t_top"))
b: Glyph = field(default_factory=lambda: Glyph(_g("+", "┴"), "t_bottom"))
l: Glyph = field(default_factory=lambda: Glyph(_g("+", "├"), "t_left"))
r: Glyph = field(default_factory=lambda: Glyph(_g("+", "┤"), "t_right"))
x: Glyph = field(default_factory=lambda: Glyph(_g("+", "┼"), "cross"))
# Double line
dh: Glyph = field(default_factory=lambda: Glyph(_g("=", "═"), "double_h"))
dv: Glyph = field(default_factory=lambda: Glyph(_g("|", "║"), "double_v"))
dtl: Glyph = field(default_factory=lambda: Glyph(_g("+", "╔"), "double_top_left"))
dtr: Glyph = field(default_factory=lambda: Glyph(_g("+", "╗"), "double_top_right"))
dbl: Glyph = field(default_factory=lambda: Glyph(_g("+", "╚"), "double_bottom_left"))
dbr: Glyph = field(default_factory=lambda: Glyph(_g("+", "╝"), "double_bottom_right"))
dx: Glyph = field(default_factory=lambda: Glyph(_g("+", "╬"), "double_cross"))
def box(self, text: str, padding: int = 1) -> str:
pad = " " * padding
inner = f"{pad}{text}{pad}"
w = len(inner)
return "\n".join([
f"{self.tl}{self.h * w}{self.tr}",
f"{self.v}{inner}{self.v}",
f"{self.bl}{self.h * w}{self.br}",
])
def double_box(self, text: str, padding: int = 1) -> str:
pad = " " * padding
inner = f"{pad}{text}{pad}"
w = len(inner)
return "\n".join([
f"{self.dtl}{self.dh * w}{self.dtr}",
f"{self.dv}{inner}{self.dv}",
f"{self.dbl}{self.dh * w}{self.dbr}",
])
def table(self, headers: list[str], rows: list[list[str]]) -> str:
col_w = [
max(len(str(h)), *(len(str(r[i])) for r in rows)) + 2
for i, h in enumerate(headers)
]
def row_line(cells):
return self.v + self.v.join(
f" {str(c).ljust(w - 1)}" for c, w in zip(cells, col_w)
) + self.v
def sep(lft, mid, rgt, fill):
return lft + mid.join(str(fill) * w for w in col_w) + rgt
return "\n".join([
sep(self.tl, self.t, self.tr, self.h),
row_line(headers),
sep(self.l, self.x, self.r, self.h),
*[row_line(r) for r in rows],
sep(self.bl, self.b, self.br, self.h),
])
# ---------------------------------------------------------------------------
# Tree / filesystem
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class TreeGlyphs:
branch: Glyph = field(default_factory=lambda: Glyph(_g("|--", "├──"), "branch"))
last: Glyph = field(default_factory=lambda: Glyph(_g("`--", "└──"), "last"))
pipe: Glyph = field(default_factory=lambda: Glyph(_g("|", "│"), "pipe"))
blank: Glyph = field(default_factory=lambda: Glyph(" ", " "), "blank")
def render(self, entries: list[tuple[str, bool, list | None]], indent: int = 0) -> str:
"""
Render nested entries as a tree.
entries: list of (name, is_dir, children | None)
children is itself a list of (name, is_dir, children) or None.
"""
lines = []
for i, (name, is_dir, children) in enumerate(entries):
is_last = i == len(entries) - 1
connector = str(self.last) if is_last else str(self.branch)
prefix = " " * indent
label = f"{name}/" if is_dir else name
lines.append(f"{prefix}{connector} {label}")
if children:
child_prefix = " " * (indent + 1)
continuation = " " if is_last else f"{self.pipe} "
sub = self.render(children, indent + 1)
# rewrite prefix to use correct pipe continuation
for line in sub.split("\n"):
lines.append(line)
return "\n".join(lines)
# ---------------------------------------------------------------------------
# Arrows
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class ArrowGlyphs:
right: Glyph = field(default_factory=lambda: Glyph(_g("->", "→"), "right"))
left: Glyph = field(default_factory=lambda: Glyph(_g("<-", "←"), "left"))
up: Glyph = field(default_factory=lambda: Glyph(_g("^", "↑"), "up"))
down: Glyph = field(default_factory=lambda: Glyph(_g("v", "↓"), "down"))
lr: Glyph = field(default_factory=lambda: Glyph(_g("<->", "↔"), "left_right"))
fat_right: Glyph = field(default_factory=lambda: Glyph(_g("=>", "⇒"), "fat_right"))
fat_left: Glyph = field(default_factory=lambda: Glyph(_g("<=", "⇐"), "fat_left"))
fat_lr: Glyph = field(default_factory=lambda: Glyph(_g("<=>", "⇔"), "fat_lr"))
hook_right: Glyph = field(default_factory=lambda: Glyph(_g("~>", "↪"), "hook_right"))
hook_left: Glyph = field(default_factory=lambda: Glyph(_g("<~", "↩"), "hook_left"))
up_right: Glyph = field(default_factory=lambda: Glyph(_g("/^", "↗"), "up_right"))
down_right: Glyph = field(default_factory=lambda: Glyph(_g("\\v", "↘"), "down_right"))
up_left: Glyph = field(default_factory=lambda: Glyph(_g("^\\", "↖"), "up_left"))
down_left: Glyph = field(default_factory=lambda: Glyph(_g("v/", "↙"), "down_left"))
clockwise: Glyph = field(default_factory=lambda: Glyph(_g("(->)", "↻"), "clockwise"))
counter_cw: Glyph = field(default_factory=lambda: Glyph(_g("(<-)", "↺"), "counter_clockwise"))
# Pipeline / flow arrows
pipe_right: Glyph = field(default_factory=lambda: Glyph(_g("|>", "▷"), "pipe_right"))
squiggle: Glyph = field(default_factory=lambda: Glyph(_g("~>", "⇝"), "squiggle_right"))
long_right: Glyph = field(default_factory=lambda: Glyph(_g("-->", "⟶"), "long_right"))
long_left: Glyph = field(default_factory=lambda: Glyph(_g("<--", "⟵"), "long_left"))
maps_to: Glyph = field(default_factory=lambda: Glyph(_g("|->", "↦"), "maps_to"))
# ---------------------------------------------------------------------------
# Progress / blocks
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class ProgressGlyphs:
full: Glyph = field(default_factory=lambda: Glyph(_g("#", "█"), "full"))
high: Glyph = field(default_factory=lambda: Glyph(_g("=", "▓"), "high"))
mid: Glyph = field(default_factory=lambda: Glyph(_g("-", "▒"), "mid"))
low: Glyph = field(default_factory=lambda: Glyph(_g(".", "░"), "low"))
empty: Glyph = field(default_factory=lambda: Glyph(_g(".", " "), "empty"))
bar_l: Glyph = field(default_factory=lambda: Glyph(_g("[", "▕"), "bar_left"))
bar_r: Glyph = field(default_factory=lambda: Glyph(_g("]", "▏"), "bar_right"))
SPINNER_BRAILLE: tuple = ("⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏")
SPINNER_ASCII: tuple = ("|", "/", "-", "\\")
SPINNER_ARROW: tuple = ("←","↖","↑","↗","→","↘","↓","↙")
SPINNER_BOUNCE: tuple = ("▁","▃","▄","▅","▆","▇","█","▇","▆","▅","▄","▃")
SPINNER_PULSE: tuple = ("·","●","◉","●","·")
SPINNER_BAR: tuple = ("▏","▎","▍","▌","▋","▊","▉","█","▉","▊","▋","▌","▍","▎")
def spinner(self, style: str = "braille") -> Iterator[str]:
"""Infinite frame iterator. Styles: braille | ascii | arrow | bounce | pulse | bar"""
frames = {
"braille": self.SPINNER_BRAILLE,
"ascii": self.SPINNER_ASCII,
"arrow": self.SPINNER_ARROW,
"bounce": self.SPINNER_BOUNCE,
"pulse": self.SPINNER_PULSE,
"bar": self.SPINNER_BAR,
}
src = self.SPINNER_ASCII if IS_LEGACY_TERMINAL else frames.get(style, self.SPINNER_BRAILLE)
return itertools.cycle(src)
def render_bar(self, value: float, width: int = 20) -> str:
"""Simple block progress bar."""
filled = round(value * width)
bar = str(self.full) * filled + str(self.low) * (width - filled)
return f"{self.bar_l}{bar}{self.bar_r} {value:.0%}"
def render_segmented(self, value: float, width: int = 20) -> str:
"""Sub-character precision bar using Unicode 1/8 block elements."""
if IS_LEGACY_TERMINAL:
return self.render_bar(value, width)
eighths = ("", "▏","▎","▍","▌","▋","▊","▉","█")
total = round(value * width * 8)
full, rem = divmod(total, 8)
bar = "█" * full + eighths[rem]
return f"▕{bar.ljust(width)}▏ {value:.0%}"
# ---------------------------------------------------------------------------
# Math / operators
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class MathGlyphs:
approx: Glyph = field(default_factory=lambda: Glyph(_g("~=", "≈"), "approx"))
not_equal: Glyph = field(default_factory=lambda: Glyph(_g("!=", "≠"), "not_equal"))
lte: Glyph = field(default_factory=lambda: Glyph(_g("<=", "≤"), "lte"))
gte: Glyph = field(default_factory=lambda: Glyph(_g(">=", "≥"), "gte"))
infinity: Glyph = field(default_factory=lambda: Glyph(_g("inf", "∞"), "infinity"))
sum: Glyph = field(default_factory=lambda: Glyph(_g("SUM", "∑"), "sum"))
product: Glyph = field(default_factory=lambda: Glyph(_g("PROD", "∏"), "product"))
sqrt: Glyph = field(default_factory=lambda: Glyph(_g("sqrt", "√"), "sqrt"))
delta: Glyph = field(default_factory=lambda: Glyph(_g("D", "Δ"), "delta"))
degree: Glyph = field(default_factory=lambda: Glyph(_g("deg", "°"), "degree"))
plus_minus: Glyph = field(default_factory=lambda: Glyph(_g("+/-", "±"), "plus_minus"))
integral: Glyph = field(default_factory=lambda: Glyph(_g("INT", "∫"), "integral"))
partial: Glyph = field(default_factory=lambda: Glyph(_g("d/", "∂"), "partial"))
nabla: Glyph = field(default_factory=lambda: Glyph(_g("V", "∇"), "nabla"))
element_of: Glyph = field(default_factory=lambda: Glyph(_g("in", "∈"), "element_of"))
not_element: Glyph = field(default_factory=lambda: Glyph(_g("!in", "∉"), "not_element_of"))
subset: Glyph = field(default_factory=lambda: Glyph(_g("<C", "⊂"), "subset"))
superset: Glyph = field(default_factory=lambda: Glyph(_g(">C", "⊃"), "superset"))
union: Glyph = field(default_factory=lambda: Glyph(_g("U", "∪"), "union"))
intersect: Glyph = field(default_factory=lambda: Glyph(_g("^", "∩"), "intersection"))
for_all: Glyph = field(default_factory=lambda: Glyph(_g("forall","∀"), "for_all"))
exists: Glyph = field(default_factory=lambda: Glyph(_g("exists","∃"), "exists"))
empty_set: Glyph = field(default_factory=lambda: Glyph(_g("{}", "∅"), "empty_set"))
therefore: Glyph = field(default_factory=lambda: Glyph(_g(":..", "∴"), "therefore"))
because: Glyph = field(default_factory=lambda: Glyph(_g("..:", "∵"), "because"))
proportional: Glyph = field(default_factory=lambda: Glyph(_g("oc", "∝"), "proportional"))
perpendicular:Glyph = field(default_factory=lambda: Glyph(_g("_|_", "⊥"), "perpendicular"))
parallel: Glyph = field(default_factory=lambda: Glyph(_g("||", "∥"), "parallel"))
lambda_: Glyph = field(default_factory=lambda: Glyph(_g("lam", "λ"), "lambda"))
mu: Glyph = field(default_factory=lambda: Glyph(_g("mu", "μ"), "mu"))
sigma: Glyph = field(default_factory=lambda: Glyph(_g("sig", "σ"), "sigma"))
pi: Glyph = field(default_factory=lambda: Glyph(_g("pi", "π"), "pi"))
phi: Glyph = field(default_factory=lambda: Glyph(_g("phi", "φ"), "phi"))
omega: Glyph = field(default_factory=lambda: Glyph(_g("ohm", "Ω"), "omega"))
# ---------------------------------------------------------------------------
# Bullets / markers
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class BulletGlyphs:
dot: Glyph = field(default_factory=lambda: Glyph(_g("*", "•"), "dot"))
middle_dot: Glyph = field(default_factory=lambda: Glyph(_g(".", "·"), "middle_dot"))
circle: Glyph = field(default_factory=lambda: Glyph(_g("o", "○"), "circle"))
circle_fill: Glyph = field(default_factory=lambda: Glyph(_g("O", "●"), "circle_filled"))
square: Glyph = field(default_factory=lambda: Glyph(_g("[ ]", "□"), "square"))
square_fill: Glyph = field(default_factory=lambda: Glyph(_g("[#]", "■"), "square_filled"))
diamond: Glyph = field(default_factory=lambda: Glyph(_g("<>", "◆"), "diamond"))
diamond_o: Glyph = field(default_factory=lambda: Glyph(_g("<>", "◇"), "diamond_open"))
triangle: Glyph = field(default_factory=lambda: Glyph(_g(">", "▶"), "triangle"))
triangle_o: Glyph = field(default_factory=lambda: Glyph(_g(">", "▷"), "triangle_open"))
star: Glyph = field(default_factory=lambda: Glyph(_g("*", "★"), "star"))
star_o: Glyph = field(default_factory=lambda: Glyph(_g("*", "☆"), "star_open"))
check: Glyph = field(default_factory=lambda: Glyph(_g("[x]", "✔"), "check"))
cross: Glyph = field(default_factory=lambda: Glyph(_g("[_]", "✘"), "cross"))
dash: Glyph = field(default_factory=lambda: Glyph(_g("-", "–"), "en_dash"))
em_dash: Glyph = field(default_factory=lambda: Glyph(_g("--", "—"), "em_dash"))
arrow: Glyph = field(default_factory=lambda: Glyph(_g("->", "➤"), "arrow"))
lozenge: Glyph = field(default_factory=lambda: Glyph(_g("<>", "◊"), "lozenge"))
ring: Glyph = field(default_factory=lambda: Glyph(_g("()", "◌"), "ring"))
# ---------------------------------------------------------------------------
# Typography
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class TypographyGlyphs:
ellipsis: Glyph = field(default_factory=lambda: Glyph(_g("...", "…"), "ellipsis"))
pilcrow: Glyph = field(default_factory=lambda: Glyph(_g("[P]", "¶"), "pilcrow"))
section: Glyph = field(default_factory=lambda: Glyph(_g("[S]", "§"), "section"))
dagger: Glyph = field(default_factory=lambda: Glyph(_g("[+]", "†"), "dagger"))
double_dag: Glyph = field(default_factory=lambda: Glyph(_g("[++]", "‡"), "double_dagger"))
trademark: Glyph = field(default_factory=lambda: Glyph(_g("(TM)", "™"), "trademark"))
registered: Glyph = field(default_factory=lambda: Glyph(_g("(R)", "®"), "registered"))
copyright: Glyph = field(default_factory=lambda: Glyph(_g("(C)", "©"), "copyright"))
open_dquote: Glyph = field(default_factory=lambda: Glyph(_g('"', "\u201c"), "open_double_quote"))
close_dquote:Glyph = field(default_factory=lambda: Glyph(_g('"', "\u201d"), "close_double_quote"))
open_squote: Glyph = field(default_factory=lambda: Glyph(_g("'", "\u2018"), "open_single_quote"))
close_squote:Glyph = field(default_factory=lambda: Glyph(_g("'", "\u2019"), "close_single_quote"))
ndash: Glyph = field(default_factory=lambda: Glyph(_g("-", "–"), "en_dash"))
mdash: Glyph = field(default_factory=lambda: Glyph(_g("--", "—"), "em_dash"))
interrobang: Glyph = field(default_factory=lambda: Glyph(_g("?!", "‽"), "interrobang"))
nbsp: Glyph = field(default_factory=lambda: Glyph(" ", "\u00a0"), "non_breaking_space"))
def smart_quote(self, text: str) -> str:
return f"{self.open_dquote}{text}{self.close_dquote}"
# ---------------------------------------------------------------------------
# Log levels *** NEW ***
# Designed for use in log formatters and CLI output.
# These are pure Unicode glyphs — no emoji contamination.
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class LogLevelGlyphs:
trace: Glyph = field(default_factory=lambda: Glyph(_g(".", "·"), "trace"))
debug: Glyph = field(default_factory=lambda: Glyph(_g("o", "○"), "debug"))
info: Glyph = field(default_factory=lambda: Glyph(_g("*", "●"), "info"))
notice: Glyph = field(default_factory=lambda: Glyph(_g("<>", "◆"), "notice"))
warning: Glyph = field(default_factory=lambda: Glyph(_g("/!\\", "▲"), "warning"))
error: Glyph = field(default_factory=lambda: Glyph(_g("[E]", "✖"), "error"))
critical: Glyph = field(default_factory=lambda: Glyph(_g("[!!]", "⊘"), "critical"))
fatal: Glyph = field(default_factory=lambda: Glyph(_g("[XX]", "☠"), "fatal"))
ok: Glyph = field(default_factory=lambda: Glyph(_g("[OK]", "✔"), "ok"))
skip: Glyph = field(default_factory=lambda: Glyph(_g("[-]", "⊖"), "skip"))
# Severity separators / structural
sep: Glyph = field(default_factory=lambda: Glyph(_g("---", "─────"),"separator"))
scope_l: Glyph = field(default_factory=lambda: Glyph(_g("[", "❬"), "scope_left"))
scope_r: Glyph = field(default_factory=lambda: Glyph(_g("]", "❭"), "scope_right"))
pipe: Glyph = field(default_factory=lambda: Glyph(_g("|", "│"), "pipe"))
ellipsis: Glyph = field(default_factory=lambda: Glyph(_g("...", "…"), "ellipsis"))
def label(self, level: str, width: int = 8) -> str:
"""Format a log level label: e.g. '● INFO │'"""
glyph_map = {
"trace": self.trace,
"debug": self.debug,
"info": self.info,
"notice": self.notice,
"warning": self.warning,
"warn": self.warning,
"error": self.error,
"critical": self.critical,
"fatal": self.fatal,
}
g = glyph_map.get(level.lower(), self.info)
name = level.upper().ljust(width)
return f"{g} {name} {self.pipe}"
def format_line(self, level: str, message: str, scope: str = "") -> str:
"""Format a complete log line."""
prefix = self.label(level)
if scope:
return f"{prefix} {self.scope_l}{scope}{self.scope_r} {message}"
return f"{prefix} {message}"
# ---------------------------------------------------------------------------
# Diff / patch *** NEW ***
# For displaying source diffs, patch outputs, file comparisons.
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class DiffGlyphs:
added: Glyph = field(default_factory=lambda: Glyph("+", "+"), "added")
removed: Glyph = field(default_factory=lambda: Glyph("-", "─"), "removed")
modified: Glyph = field(default_factory=lambda: Glyph("~", "~"), "modified")
unchanged: Glyph = field(default_factory=lambda: Glyph(" ", " "), "unchanged")
conflict: Glyph = field(default_factory=lambda: Glyph(_g("!", "≠"), "conflict"))
moved: Glyph = field(default_factory=lambda: Glyph(_g("->","→"), "moved"))
renamed: Glyph = field(default_factory=lambda: Glyph(_g("=>","⇒"), "renamed"))
hunk: Glyph = field(default_factory=lambda: Glyph(_g("@@","⊕⊕"), "hunk"))
arrow_add: Glyph = field(default_factory=lambda: Glyph(_g("+>","┼"), "arrow_add"))
block_add: Glyph = field(default_factory=lambda: Glyph(_g("++","▌"), "block_add"))
block_rem: Glyph = field(default_factory=lambda: Glyph(_g("--","▐"), "block_remove"))
def line(self, kind: str, text: str, lineno: int | None = None) -> str:
"""Render a diff line. kind: added | removed | modified | unchanged"""
glyph_map = {
"added": self.added,
"removed": self.removed,
"modified": self.modified,
"unchanged": self.unchanged,
}
g = glyph_map.get(kind, self.unchanged)
num = f"{lineno:>4} " if lineno is not None else ""
return f"{num}{g} {text}"
# ---------------------------------------------------------------------------
# Git *** NEW ***
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class GitGlyphs:
# Graph nodes
commit: Glyph = field(default_factory=lambda: Glyph(_g("o", "●"), "commit"))
merge: Glyph = field(default_factory=lambda: Glyph(_g("M", "◎"), "merge_commit"))
tag_node: Glyph = field(default_factory=lambda: Glyph(_g("#", "◈"), "tag_node"))
head: Glyph = field(default_factory=lambda: Glyph(_g("H", "◉"), "head"))
stash: Glyph = field(default_factory=lambda: Glyph(_g("s", "⊙"), "stash"))
remote: Glyph = field(default_factory=lambda: Glyph(_g("r", "◯"), "remote"))
# Graph connectors
graph_v: Glyph = field(default_factory=lambda: Glyph(_g("|", "│"), "graph_vertical"))
graph_h: Glyph = field(default_factory=lambda: Glyph(_g("-", "─"), "graph_horizontal"))
graph_tl: Glyph = field(default_factory=lambda: Glyph(_g("/", "╮"), "graph_top_left"))
graph_br: Glyph = field(default_factory=lambda: Glyph(_g("\\", "╯"), "graph_bottom_right"))
graph_bl: Glyph = field(default_factory=lambda: Glyph(_g("\\", "╰"), "graph_bottom_left"))
graph_tr: Glyph = field(default_factory=lambda: Glyph(_g("/", "╭"), "graph_top_right"))
graph_x: Glyph = field(default_factory=lambda: Glyph(_g("*", "┼"), "graph_cross"))
# Branch / status indicators
branch: Glyph = field(default_factory=lambda: Glyph(_g("br", "⎇"), "branch"))
ahead: Glyph = field(default_factory=lambda: Glyph(_g("^", "↑"), "ahead"))
behind: Glyph = field(default_factory=lambda: Glyph(_g("v", "↓"), "behind"))
diverged: Glyph = field(default_factory=lambda: Glyph(_g("^v", "↕"), "diverged"))
added: Glyph = field(default_factory=lambda: Glyph("+", "+"), "added")
removed: Glyph = field(default_factory=lambda: Glyph("-", "-"), "removed")
modified: Glyph = field(default_factory=lambda: Glyph("~", "~"), "modified")
untracked: Glyph = field(default_factory=lambda: Glyph("?", "?"), "untracked")
ignored: Glyph = field(default_factory=lambda: Glyph("!", "!"), "ignored")
conflict: Glyph = field(default_factory=lambda: Glyph(_g("!=", "≠"), "conflict"))
clean: Glyph = field(default_factory=lambda: Glyph(_g("OK", "✔"), "clean"))
dirty: Glyph = field(default_factory=lambda: Glyph(_g("*", "✎"), "dirty"))
# Ref decorators
ref_l: Glyph = field(default_factory=lambda: Glyph("(", "("), "ref_left")
ref_r: Glyph = field(default_factory=lambda: Glyph(")", ")"), "ref_right")
def status_line(self, branch_name: str, ahead: int = 0, behind: int = 0,
modified: int = 0, untracked: int = 0) -> str:
"""Render a compact git status line."""
parts = [f"{self.branch} {branch_name}"]
if ahead: parts.append(f"{self.ahead}{ahead}")
if behind: parts.append(f"{self.behind}{behind}")
if modified: parts.append(f"{self.modified}{modified}")
if untracked: parts.append(f"{self.untracked}{untracked}")
status = self.clean if not (modified or untracked) else self.dirty
parts.append(str(status))
return " ".join(parts)
def log_line(self, sha: str, message: str, refs: list[str] = ()) -> str:
"""Render a single git log line."""
ref_str = ""
if refs:
ref_str = " " + " ".join(
f"{self.ref_l}{r}{self.ref_r}" for r in refs
)
return f"{self.commit} {sha[:7]}{ref_str} {message}"
# ---------------------------------------------------------------------------
# CI/CD pipeline *** NEW ***
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class CICDGlyphs:
# Stage / job states
passed: Glyph = field(default_factory=lambda: Glyph(_g("[OK]", "✔"), "passed"))
failed: Glyph = field(default_factory=lambda: Glyph(_g("[FL]", "✖"), "failed"))
running: Glyph = field(default_factory=lambda: Glyph(_g("[>>]", "▶"), "running"))
queued: Glyph = field(default_factory=lambda: Glyph(_g("[Q]", "◷"), "queued"))
canceled: Glyph = field(default_factory=lambda: Glyph(_g("[CX]", "⊘"), "canceled"))
skipped: Glyph = field(default_factory=lambda: Glyph(_g("[SK]", "⊖"), "skipped"))
manual: Glyph = field(default_factory=lambda: Glyph(_g("[M]", "◈"), "manual"))
blocked: Glyph = field(default_factory=lambda: Glyph(_g("[BL]", "⊗"), "blocked"))
created: Glyph = field(default_factory=lambda: Glyph(_g("[C]", "○"), "created"))
# Stage types
build: Glyph = field(default_factory=lambda: Glyph(_g("[B]", "⚙"), "build"))
test: Glyph = field(default_factory=lambda: Glyph(_g("[T]", "⚗"), "test"))
lint: Glyph = field(default_factory=lambda: Glyph(_g("[L]", "⌥"), "lint"))
scan: Glyph = field(default_factory=lambda: Glyph(_g("[SC]", "⌕"), "scan"))
deploy: Glyph = field(default_factory=lambda: Glyph(_g("[D]", "⬆"), "deploy"))
release: Glyph = field(default_factory=lambda: Glyph(_g("[R]", "◆"), "release"))
rollback: Glyph = field(default_factory=lambda: Glyph(_g("[RB]", "↩"), "rollback"))
artifact: Glyph = field(default_factory=lambda: Glyph(_g("[A]", "⊡"), "artifact"))
trigger: Glyph = field(default_factory=lambda: Glyph(_g("[TR]", "⇒"), "trigger"))
notify: Glyph = field(default_factory=lambda: Glyph(_g("[N]", "◎"), "notify"))
# Pipeline connectors
stage_sep: Glyph = field(default_factory=lambda: Glyph(_g("->", "→"), "stage_sep"))
parallel: Glyph = field(default_factory=lambda: Glyph(_g("||", "⫴"), "parallel"))
def pipeline(self, stages: list[tuple[str, str]]) -> str:
"""
Render a pipeline overview.
stages: list of (stage_type, status) e.g. [("build","passed"), ("test","running")]
"""
type_map = {
"build": self.build, "test": self.test, "lint": self.lint,
"scan": self.scan, "deploy": self.deploy, "release": self.release,
}
state_map = {
"passed": self.passed, "failed": self.failed, "running": self.running,
"queued": self.queued, "canceled": self.canceled, "skipped": self.skipped,
"manual": self.manual, "blocked": self.blocked,
}
parts = []
for stage_type, status in stages:
t = type_map.get(stage_type, self.build)
s = state_map.get(status, self.queued)
parts.append(f"{t}{s}")
return f" {self.stage_sep} ".join(parts)
# ---------------------------------------------------------------------------
# Code / programming symbols *** NEW ***
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class CodeGlyphs:
# Code constructs
function: Glyph = field(default_factory=lambda: Glyph(_g("fn", "ƒ"), "function"))
lambda_: Glyph = field(default_factory=lambda: Glyph(_g("lam", "λ"), "lambda"))
class_: Glyph = field(default_factory=lambda: Glyph(_g("cls", "⊞"), "class"))
interface: Glyph = field(default_factory=lambda: Glyph(_g("iface", "⊟"), "interface"))
type_: Glyph = field(default_factory=lambda: Glyph(_g("T", "τ"), "type"))
generic: Glyph = field(default_factory=lambda: Glyph(_g("<T>", "⟨T⟩"), "generic"))
variable: Glyph = field(default_factory=lambda: Glyph(_g("var", "υ"), "variable"))
constant: Glyph = field(default_factory=lambda: Glyph(_g("CONST", "κ"), "constant"))
module: Glyph = field(default_factory=lambda: Glyph(_g("mod", "⊕"), "module"))
namespace: Glyph = field(default_factory=lambda: Glyph(_g("ns", "⊗"), "namespace"))
import_: Glyph = field(default_factory=lambda: Glyph(_g("use", "⇐"), "import"))
export_: Glyph = field(default_factory=lambda: Glyph(_g("pub", "⇒"), "export"))
# Flow / logic
branch: Glyph = field(default_factory=lambda: Glyph(_g("if", "⑂"), "branch"))
loop: Glyph = field(default_factory=lambda: Glyph(_g("for", "↻"), "loop"))
recurse: Glyph = field(default_factory=lambda: Glyph(_g("rec", "⟳"), "recurse"))
async_: Glyph = field(default_factory=lambda: Glyph(_g("~>", "⇝"), "async"))
await_: Glyph = field(default_factory=lambda: Glyph(_g("<~", "⊸"), "await"))
yield_: Glyph = field(default_factory=lambda: Glyph(_g("<<", "⟵"), "yield"))
return_: Glyph = field(default_factory=lambda: Glyph(_g("<-", "↵"), "return"))
throw_: Glyph = field(default_factory=lambda: Glyph(_g("!!!", "↯"), "throw"))
# Values / types
null: Glyph = field(default_factory=lambda: Glyph(_g("null", "∅"), "null"))
true_: Glyph = field(default_factory=lambda: Glyph(_g("T", "⊤"), "true"))
false_: Glyph = field(default_factory=lambda: Glyph(_g("F", "⊥"), "false"))
some: Glyph = field(default_factory=lambda: Glyph(_g("Some", "◉"), "some"))
none: Glyph = field(default_factory=lambda: Glyph(_g("None", "◌"), "none"))
ok_: Glyph = field(default_factory=lambda: Glyph(_g("Ok", "✔"), "ok"))
err_: Glyph = field(default_factory=lambda: Glyph(_g("Err", "✖"), "err"))
# Operators
compose: Glyph = field(default_factory=lambda: Glyph(_g(">>", "∘"), "compose"))
pipe_op: Glyph = field(default_factory=lambda: Glyph(_g("|>", "▷"), "pipe_operator"))
bind: Glyph = field(default_factory=lambda: Glyph(_g(">>=", "≫="), "bind"))
maps_to: Glyph = field(default_factory=lambda: Glyph(_g("|->", "↦"), "maps_to"))
equiv: Glyph = field(default_factory=lambda: Glyph(_g("===", "≡"), "equivalent"))
not_equiv: Glyph = field(default_factory=lambda: Glyph(_g("!==", "≢"), "not_equivalent"))
# Memory / runtime
pointer: Glyph = field(default_factory=lambda: Glyph(_g("*", "⊛"), "pointer"))
ref: Glyph = field(default_factory=lambda: Glyph(_g("&", "&"), "reference"))
deref: Glyph = field(default_factory=lambda: Glyph(_g("*", "✱"), "dereference"))
alloc: Glyph = field(default_factory=lambda: Glyph(_g("new", "⊞"), "allocate"))
free: Glyph = field(default_factory=lambda: Glyph(_g("del", "⊟"), "free"))
# ---------------------------------------------------------------------------
# Analysis / metrics *** NEW ***
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class AnalysisGlyphs:
# Trend indicators
trend_up: Glyph = field(default_factory=lambda: Glyph(_g("/^", "↗"), "trend_up"))
trend_down: Glyph = field(default_factory=lambda: Glyph(_g("\\v", "↘"), "trend_down"))
trend_flat: Glyph = field(default_factory=lambda: Glyph(_g("->", "→"), "trend_flat"))
spike: Glyph = field(default_factory=lambda: Glyph(_g("/!\\", "⚡"), "spike"))
drop: Glyph = field(default_factory=lambda: Glyph(_g("\\!", "⬇"), "drop"))
# Rating / score
score_full: Glyph = field(default_factory=lambda: Glyph(_g("[*]", "★"), "score_full"))
score_half: Glyph = field(default_factory=lambda: Glyph(_g("[/]", "⯨"), "score_half"))
score_empty: Glyph = field(default_factory=lambda: Glyph(_g("[ ]", "☆"), "score_empty"))
# Comparison
better: Glyph = field(default_factory=lambda: Glyph(_g(">", "⊳"), "better"))
worse: Glyph = field(default_factory=lambda: Glyph(_g("<", "⊲"), "worse"))
same: Glyph = field(default_factory=lambda: Glyph(_g("=", "≈"), "same"))
# Percentile / distribution
p50: Glyph = field(default_factory=lambda: Glyph(_g("p50", "⊕"), "median"))
outlier: Glyph = field(default_factory=lambda: Glyph(_g("(!)", "⊛"), "outlier"))
# Mini sparkline
SPARK: tuple = (" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█")
def sparkline(self, values: list[float]) -> str:
"""Render a unicode sparkline from a list of floats."""
if IS_LEGACY_TERMINAL:
mn, mx = min(values), max(values)
rng = mx - mn or 1
return "".join(
str(round((v - mn) / rng * 9)).rjust(2) for v in values
)
mn, mx = min(values), max(values)
rng = mx - mn or 1
return "".join(
self.SPARK[round((v - mn) / rng * 8)] for v in values
)
def rating(self, score: float, max_score: float = 5.0, width: int = 5) -> str:
"""Render a star rating."""
ratio = score / max_score
full = int(ratio * width)
has_half = (ratio * width - full) >= 0.5
empty = width - full - (1 if has_half else 0)
return (
str(self.score_full) * full
+ (str(self.score_half) if has_half else "")
+ str(self.score_empty) * empty
+ f" {score}/{max_score}"
)
def delta(self, old: float, new: float, unit: str = "") -> str:
"""Show a labelled delta with trend glyph."""
diff = new - old
pct = (diff / old * 100) if old else 0
glyph = self.trend_up if diff > 0 else (self.trend_down if diff < 0 else self.trend_flat)
sign = "+" if diff >= 0 else ""
return f"{glyph} {sign}{diff:.2f}{unit} ({sign}{pct:.1f}%)"
# ===========================================================================
# EMOJI GROUPS (no platform switching — emojis work everywhere modern)
# ===========================================================================
@dataclass(frozen=True)
class StatusEmojis:
success: Emoji = field(default_factory=lambda: Emoji("✅", "success"))
error: Emoji = field(default_factory=lambda: Emoji("❌", "error"))
warning: Emoji = field(default_factory=lambda: Emoji("⚠️", "warning"))
info: Emoji = field(default_factory=lambda: Emoji("ℹ️", "info"))
pending: Emoji = field(default_factory=lambda: Emoji("⏳", "pending"))
skipped: Emoji = field(default_factory=lambda: Emoji("⏭️", "skipped"))
question: Emoji = field(default_factory=lambda: Emoji("❓", "question"))
debug: Emoji = field(default_factory=lambda: Emoji("🐛", "debug"))
locked: Emoji = field(default_factory=lambda: Emoji("🔒", "locked"))
unlocked: Emoji = field(default_factory=lambda: Emoji("🔓", "unlocked"))
new: Emoji = field(default_factory=lambda: Emoji("🆕", "new"))
hot: Emoji = field(default_factory=lambda: Emoji("🔥", "hot"))
pinned: Emoji = field(default_factory=lambda: Emoji("📌", "pinned"))
flag: Emoji = field(default_factory=lambda: Emoji("🚩", "flag"))
robot: Emoji = field(default_factory=lambda: Emoji("🤖", "robot"))
@dataclass(frozen=True)
class FileEmojis:
folder: Emoji = field(default_factory=lambda: Emoji("📁", "folder"))
folder_o: Emoji = field(default_factory=lambda: Emoji("📂", "folder_open"))
file: Emoji = field(default_factory=lambda: Emoji("📄", "file"))
link: Emoji = field(default_factory=lambda: Emoji("🔗", "link"))
image: Emoji = field(default_factory=lambda: Emoji("🖼️", "image"))
video: Emoji = field(default_factory=lambda: Emoji("🎬", "video"))
audio: Emoji = field(default_factory=lambda: Emoji("🎵", "audio"))
archive: Emoji = field(default_factory=lambda: Emoji("🗜️", "archive"))
config: Emoji = field(default_factory=lambda: Emoji("⚙️", "config"))
trash: Emoji = field(default_factory=lambda: Emoji("🗑️", "trash"))
key: Emoji = field(default_factory=lambda: Emoji("🔑", "key"))
secret: Emoji = field(default_factory=lambda: Emoji("🔐", "secret"))
database: Emoji = field(default_factory=lambda: Emoji("🗄️", "database"))
terminal: Emoji = field(default_factory=lambda: Emoji("🖥️", "terminal"))
package: Emoji = field(default_factory=lambda: Emoji("📦", "package"))
@dataclass(frozen=True)
class DevEmojis:
"""Emojis relevant to development workflows — used in PR titles, changelogs, commits."""
feat: Emoji = field(default_factory=lambda: Emoji("✨", "feature"))
fix: Emoji = field(default_factory=lambda: Emoji("🐛", "bugfix"))
hotfix: Emoji = field(default_factory=lambda: Emoji("🚑", "hotfix"))
refactor: Emoji = field(default_factory=lambda: Emoji("♻️", "refactor"))
perf: Emoji = field(default_factory=lambda: Emoji("⚡", "performance"))
test: Emoji = field(default_factory=lambda: Emoji("🧪", "test"))
docs: Emoji = field(default_factory=lambda: Emoji("📝", "docs"))
style: Emoji = field(default_factory=lambda: Emoji("🎨", "style"))
chore: Emoji = field(default_factory=lambda: Emoji("🔧", "chore"))
revert: Emoji = field(default_factory=lambda: Emoji("⏪", "revert"))
merge: Emoji = field(default_factory=lambda: Emoji("🔀", "merge"))
release: Emoji = field(default_factory=lambda: Emoji("🚀", "release"))
deprecate:Emoji = field(default_factory=lambda: Emoji("🗑️", "deprecate"))
remove: Emoji = field(default_factory=lambda: Emoji("🔥", "remove"))
security: Emoji = field(default_factory=lambda: Emoji("🔒", "security"))
deps: Emoji = field(default_factory=lambda: Emoji("📦", "dependencies"))
ci: Emoji = field(default_factory=lambda: Emoji("⚙️", "ci"))
breaking: Emoji = field(default_factory=lambda: Emoji("💥", "breaking_change"))
wip: Emoji = field(default_factory=lambda: Emoji("🚧", "wip"))
config: Emoji = field(default_factory=lambda: Emoji("🔧", "config"))
def conventional_commit(self, kind: str, scope: str, message: str) -> str:
"""Format a conventional commit message with emoji prefix."""
emoji_map = {
"feat": self.feat, "fix": self.fix, "hotfix": self.hotfix,
"refactor": self.refactor, "perf": self.perf, "test": self.test,
"docs": self.docs, "style": self.style, "chore": self.chore,
"revert": self.revert, "ci": self.ci, "deps": self.deps,
}
e = emoji_map.get(kind, self.chore)
scope_str = f"({scope})" if scope else ""
return f"{e} {kind}{scope_str}: {message}"
# ===========================================================================
# REGISTRY
# ===========================================================================
@dataclass(frozen=True)
class GlyphRegistry:
"""
Unified access point.
.glyphs — platform-aware Unicode symbols
.emojis — emoji groups (platform-independent)
"""
# Glyph groups
box: BoxGlyphs = field(default_factory=BoxGlyphs)
tree: TreeGlyphs = field(default_factory=TreeGlyphs)
arrows: ArrowGlyphs = field(default_factory=ArrowGlyphs)
progress: ProgressGlyphs = field(default_factory=ProgressGlyphs)
math: MathGlyphs = field(default_factory=MathGlyphs)
bullets: BulletGlyphs = field(default_factory=BulletGlyphs)
typography: TypographyGlyphs= field(default_factory=TypographyGlyphs)
log: LogLevelGlyphs = field(default_factory=LogLevelGlyphs)
diff: DiffGlyphs = field(default_factory=DiffGlyphs)
git: GitGlyphs = field(default_factory=GitGlyphs)
cicd: CICDGlyphs = field(default_factory=CICDGlyphs)
code: CodeGlyphs = field(default_factory=CodeGlyphs)
analysis: AnalysisGlyphs = field(default_factory=AnalysisGlyphs)
# Emoji groups
status_emoji: StatusEmojis = field(default_factory=StatusEmojis)
file_emoji: FileEmojis = field(default_factory=FileEmojis)
dev_emoji: DevEmojis = field(default_factory=DevEmojis)
glyphs = GlyphRegistry()
# ===========================================================================
# Demo
# ===========================================================================
if __name__ == "__main__":
g = glyphs
sep = lambda t: print(f"\n── {t} {'─' * max(1, 42 - len(t))}")
print(f"Platform: {'Legacy Windows' if IS_LEGACY_TERMINAL else 'Modern terminal'}")
sep("Log levels")
for level in ("trace","debug","info","notice","warning","error","critical","fatal"):
print(f" {g.log.format_line(level, f'Sample {level} message', scope='auth')}")
sep("Git status")
print(f" {g.git.status_line('feature/my-branch', ahead=3, behind=1, modified=5, untracked=2)}")
print(f" {g.git.log_line('abc1234', 'feat: add login flow', refs=['HEAD', 'origin/main'])}")
print(f" {g.git.log_line('def5678', 'fix: null pointer in parser')}")
sep("Diff")
for kind, txt, n in [
("added", "def new_feature():", 10),
("unchanged", " pass", 11),
("removed", "def old_feature():", 12),
("modified", " return result", 13),
]:
print(f" {g.diff.line(kind, txt, n)}")
sep("CI/CD pipeline")
stages = [
("lint", "passed"),
("build", "passed"),
("test", "running"),
("scan", "queued"),
("deploy", "blocked"),
]
print(f" {g.cicd.pipeline(stages)}")
sep("Code symbols")
symbols = [
g.code.function, g.code.lambda_, g.code.class_,
g.code.async_, g.code.await_, g.code.pipe_op,
g.code.compose, g.code.bind, g.code.ok_,
g.code.err_, g.code.null, g.code.true_,
g.code.false_, g.code.pointer, g.code.throw_,
]
print(" " + " ".join(f"{s}({s.name})" for s in symbols))
sep("Analysis")
data = [4, 12, 8, 22, 17, 30, 25, 10, 18, 28]
print(f" Sparkline : {g.analysis.sparkline(data)}")
print(f" Rating : {g.analysis.rating(3.5)}")
print(f" Delta : {g.analysis.delta(120.0, 145.5, 'ms')}")
print(f" Delta : {g.analysis.delta(145.5, 130.0, 'ms')}")
sep("Progress bars")
for v in (0.0, 0.33, 0.67, 1.0):
print(f" {g.progress.render_segmented(v)}")
sep("Spinner styles (5 frames each)")
for style in ("braille","ascii","arrow","bounce","pulse","bar"):
sp = g.progress.spinner(style)
print(f" {style:<10} {' '.join(next(sp) for _ in range(6))}")
sep("Box table")
print(g.box.table(
["Level", "Glyph", "Count"],
[["error", str(g.log.error), "12"],
["warning", str(g.log.warning), "34"],
["info", str(g.log.info), "198"]],
))
sep("Conventional commits (emoji)")
for kind, scope, msg in [
("feat", "auth", "add OAuth2 login"),
("fix", "parser", "handle empty input"),
("breaking", "", "rename config keys"),
("ci", "github", "add matrix build"),
]:
print(f" {g.dev_emoji.conventional_commit(kind, scope, msg)}")
sep("Math (extended)")
row = [g.math.lambda_, g.math.sigma, g.math.pi, g.math.phi, g.math.omega,
g.math.integral, g.math.nabla, g.math.for_all, g.math.exists,
g.math.empty_set, g.math.therefore, g.math.perpendicular]
print(" " + " ".join(str(m) for m in row))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment