| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- /**
- * Glyph selection for CLI output.
- *
- * On Windows, console output is interpreted via the active output
- * codepage. PowerShell 5.1 and cmd.exe in legacy conhost default to
- * OEM codepages (CP437, CP936, ...), so UTF-8 bytes written to the
- * console render as mojibake (see #168). The shimmer worker is hit
- * hardest because it uses `fs.writeSync(1, ...)` (raw bytes, no
- * TTY-aware encoding conversion) to keep animation smooth while the
- * main thread is blocked in SQLite. To stay readable everywhere, we
- * fall back to ASCII glyphs whenever the terminal is not known to
- * handle UTF-8.
- *
- * The Windows branch must agree with @clack/prompts (which bundles
- * `is-unicode-supported`): clack draws the outer `┌ │ └` frame around
- * init/index/sync output, and if it decides Unicode while we decide
- * ASCII, one block mixes `│` and `|` rails (#398). The terminals the
- * list recognizes (Windows Terminal, VS Code, ConEmu/Cmder, Alacritty,
- * JetBrains, Terminus, CI log viewers) all run with a UTF-8-capable
- * output path, so the raw-byte shimmer writes render correctly there
- * too; unrecognized Windows consoles keep the safe ASCII fallback —
- * and clack falls back to ASCII in those as well, so output stays
- * consistent in both directions.
- *
- * Detection:
- * - `CODEGRAPH_ASCII=1` -> ASCII (escape hatch for any terminal)
- * - `CODEGRAPH_UNICODE=1` -> Unicode (opt-in on any terminal)
- * - Windows -> mirror is-unicode-supported (see above)
- * - Linux kernel console (`TERM=linux`) -> ASCII
- * - Everything else -> Unicode
- */
- export function supportsUnicode(): boolean {
- if (process.env.CODEGRAPH_ASCII === '1') return false;
- if (process.env.CODEGRAPH_UNICODE === '1') return true;
- if (process.platform === 'win32') {
- const env = process.env;
- return Boolean(
- env.CI ||
- env.WT_SESSION || // Windows Terminal
- env.TERMINUS_SUBLIME ||
- env.ConEmuTask === '{cmd::Cmder}' || // ConEmu and cmder
- env.TERM_PROGRAM === 'Terminus-Sublime' ||
- env.TERM_PROGRAM === 'vscode' ||
- env.TERM === 'xterm-256color' ||
- env.TERM === 'alacritty' ||
- env.TERMINAL_EMULATOR === 'JetBrains-JediTerm'
- );
- }
- return process.env.TERM !== 'linux';
- }
- export interface Glyphs {
- ok: string;
- err: string;
- info: string;
- warn: string;
- spinner: string[];
- barFilled: string;
- barEmpty: string;
- rail: string;
- phaseDone: string;
- dash: string;
- hLine: string;
- treeBranch: string;
- treeLast: string;
- treePipe: string;
- }
- export const UNICODE_GLYPHS: Glyphs = {
- ok: '✓',
- err: '✗',
- info: 'ℹ',
- warn: '⚠',
- spinner: ['·', '✢', '✳', '✶', '✻', '✽'],
- barFilled: '█',
- barEmpty: '░',
- rail: '│',
- phaseDone: '◆',
- dash: '—',
- hLine: '─',
- treeBranch: '├── ',
- treeLast: '└── ',
- treePipe: '│ ',
- };
- export const ASCII_GLYPHS: Glyphs = {
- ok: '[OK]',
- err: '[ERR]',
- info: '[i]',
- warn: '[!]',
- spinner: ['.', '*', '+', 'x', 'o', 'O'],
- barFilled: '#',
- barEmpty: '-',
- rail: '|',
- phaseDone: '*',
- dash: '-',
- hLine: '-',
- treeBranch: '|-- ',
- treeLast: '`-- ',
- treePipe: '| ',
- };
- let cached: Glyphs | null = null;
- export function getGlyphs(): Glyphs {
- if (cached === null) {
- cached = supportsUnicode() ? UNICODE_GLYPHS : ASCII_GLYPHS;
- }
- return cached;
- }
- /**
- * Unicode support for the RAW console write path — `fs.writeSync(1, ...)`,
- * used only by the shimmer worker's transient animation frames. Raw bytes
- * bypass Node's TTY-aware conversion and get decoded by the ACTIVE CONSOLE
- * CODEPAGE on Windows; OEM codepages (CP437, CP936, ...) mojibake UTF-8
- * there even inside Windows Terminal, whose ConPTY still decodes app output
- * with the session codepage (#168). So the raw path stays ASCII on every
- * Windows terminal unless the user opts in via CODEGRAPH_UNICODE=1 —
- * independent of `supportsUnicode()`, which governs the codepage-immune
- * main-thread writes (`process.stdout` uses the wide-char console API).
- */
- export function supportsUnicodeRawWrites(): boolean {
- if (process.env.CODEGRAPH_ASCII === '1') return false;
- if (process.env.CODEGRAPH_UNICODE === '1') return true;
- if (process.platform === 'win32') return false;
- return process.env.TERM !== 'linux';
- }
- export function getRawWriteGlyphs(): Glyphs {
- return supportsUnicodeRawWrites() ? UNICODE_GLYPHS : ASCII_GLYPHS;
- }
- /** Reset the cached glyph set. Test-only; production code should call `getGlyphs()`. */
- export function _resetGlyphsCache(): void {
- cached = null;
- }
|