56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import { BufferLocation, BufferSize, Char, Color } from "./base.ts";
|
|
import { Display } from "./display.ts";
|
|
|
|
/**
|
|
* ANSI terminal display
|
|
*/
|
|
export class AnsiTerminalDisplay implements Display {
|
|
private palette_bg: readonly Uint8Array[] = [];
|
|
private palette_fg: readonly Uint8Array[] = [];
|
|
|
|
constructor(
|
|
private writer: Deno.Writer = Deno.stdout,
|
|
private reader: Deno.Reader = Deno.stdin,
|
|
) {
|
|
}
|
|
|
|
async getSize(): Promise<BufferSize> {
|
|
const size = Deno.consoleSize(Deno.stdout.rid);
|
|
return {
|
|
w: size.columns,
|
|
h: size.rows,
|
|
};
|
|
}
|
|
|
|
async setupPalette(colors: readonly Color[]): Promise<readonly Color[]> {
|
|
// TODO handle not fully rgb compatible terminals
|
|
const cr = (x: number) => Math.round(x * 255);
|
|
this.palette_bg = colors.map((col) =>
|
|
escape(`[48;2;${cr(col.r)};${cr(col.g)};${cr(col.b)}m`)
|
|
);
|
|
this.palette_fg = colors.map((col) =>
|
|
escape(`[38;2;${cr(col.r)};${cr(col.g)};${cr(col.b)}m`)
|
|
);
|
|
return colors;
|
|
}
|
|
|
|
async clear(): Promise<void> {
|
|
await this.writer.write(CLEAR);
|
|
}
|
|
|
|
async setChar(at: BufferLocation, char: Char): Promise<void> {
|
|
// TODO do not move the cursor if already at good location
|
|
// TODO do not change the color if already good
|
|
const fg = this.palette_fg[char.fg];
|
|
const bg = this.palette_bg[char.bg];
|
|
await this.writer.write(fg);
|
|
await this.writer.write(bg);
|
|
await this.writer.write(escape(`[${at.y};${at.x}H${char.ch}`));
|
|
}
|
|
}
|
|
|
|
function escape(sequence: string): Uint8Array {
|
|
return new Uint8Array([0x1B, ...new TextEncoder().encode(sequence)]);
|
|
}
|
|
|
|
const CLEAR = escape("[2J");
|