import * as ansiEscapes from "./ansi_escapes.ts";import type { Chain } from "./chain.ts";import { Cursor, getCursorPosition } from "./cursor_position.ts";import type { ReaderSync, WriterSync } from "./deps.ts";
export interface TtyOptions { writer?: WriterSync; reader?: ReaderSync & { setRaw(mode: boolean, options?: Deno.SetRawOptions): void; isTerminal(): boolean; };}
type Executor = (this: TtyChain, ...args: Args) => string;type Args = Array<unknown>;type Property = string | Executor;type PropertyNames = keyof Chain<TtyChain>;
export interface TtyChain extends Exclude<Chain<TtyChain>, "cursorPosition"> { (): void; getCursorPosition(): Cursor;}
export type TtyFactory = (options?: TtyOptions) => Tty;
export type Tty = TtyFactory & TtyChain;
export const tty: Tty = factory();
const encoder = new TextEncoder();
function factory(options?: TtyOptions): Tty { let result = ""; let stack: Array<[Property, Args]> = []; const writer = options?.writer ?? Deno.stdout; const reader = options?.reader ?? Deno.stdin;
const tty: Tty = function ( this: TtyChain | undefined, ...args: Args | [TtyOptions] ): TtyChain { if (this) { update(args); writer.writeSync(encoder.encode(result)); return this; } return factory(args[0] as TtyOptions ?? options); } as Tty;
tty.text = function (text: string): TtyChain { stack.push([text, []]); update(); writer.writeSync(encoder.encode(result)); return this; };
tty.getCursorPosition = (): Cursor => getCursorPosition({ writer, reader });
const methodList: Array<[PropertyNames, Property]> = Object.entries( ansiEscapes, ) as Array<[PropertyNames, Property]>;
for (const [name, method] of methodList) { if (name === "cursorPosition") { continue; } Object.defineProperty(tty, name, { get(this: TtyChain) { stack.push([method, []]); return this; }, }); }
return tty;
function update(args?: Args) { if (!stack.length) { return; } if (args) { stack[stack.length - 1][1] = args; } result = stack.reduce( (prev: string, [cur, args]: [Property, Args]) => prev + (typeof cur === "string" ? cur : cur.call(tty, ...args)), "", ); stack = []; }}