From 65a06d40d4d6bb67b1f2585a2328934065414d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Fri, 25 Jun 2021 01:09:05 +0200 Subject: [PATCH] Optimize ansi character writing --- ansi.ts | 36 +++++++++++++++++++++++++++++------- mod.ts | 10 +++++++--- ui.ts | 4 ++-- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/ansi.ts b/ansi.ts index ca3db9d..b847a85 100644 --- a/ansi.ts +++ b/ansi.ts @@ -7,6 +7,8 @@ import { Display } from "./display.ts"; export class AnsiTerminalDisplay implements Display { private palette_bg: readonly Uint8Array[] = []; private palette_fg: readonly Uint8Array[] = []; + private width = 1; + private state = { x: -1, y: -1, f: -1, b: -1 }; // current location and color constructor( private writer: Deno.Writer = Deno.stdout, @@ -16,6 +18,7 @@ export class AnsiTerminalDisplay implements Display { async getSize(): Promise { const size = Deno.consoleSize(Deno.stdout.rid); + this.width = size.columns; return { w: size.columns, h: size.rows, @@ -39,13 +42,32 @@ export class AnsiTerminalDisplay implements Display { } async setChar(at: BufferLocation, char: Char): Promise { - // 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}`)); + let { x, y, f, b } = this.state; + + if (f != char.fg) { + f = char.fg; + await this.writer.write(this.palette_fg[f]); + } + + if (b != char.bg) { + b = char.bg; + await this.writer.write(this.palette_bg[b]); + } + + if (x != at.x || y != at.y) { + x = at.x; + y = at.y; + await this.writer.write(escape(`[${at.y};${at.x}H`)); + } + + await this.writer.write(new TextEncoder().encode(char.ch)); + + x += 1; + if (x > this.width) { + x = 0; + y += 1; + } + this.state = { x, y, f, b }; } } diff --git a/mod.ts b/mod.ts index 45f20b6..6fec0bd 100644 --- a/mod.ts +++ b/mod.ts @@ -1,11 +1,15 @@ import { AnsiTerminalDisplay } from "./ansi.ts"; -import { TextUI } from "./ui.ts"; +import { TextUI, UIPalette } from "./ui.ts"; export { TextUI } from "./ui.ts"; -export async function createTextUI(): Promise { +export type UIConfig = { + palette: UIPalette; +}; + +export async function createTextUI(config: UIConfig): Promise { // TODO detect platform var display = new AnsiTerminalDisplay(); var ui = new TextUI(display); - await ui.init(); + await ui.init(config.palette); return ui; } diff --git a/ui.ts b/ui.ts index 31e4bfd..4c94092 100644 --- a/ui.ts +++ b/ui.ts @@ -44,8 +44,8 @@ export class TextUI { async flush(): Promise { // TODO only dirty chars const { w, h } = this.screen.getSize(); - for (let x = 0; x < w; x++) { - for (let y = 0; y < h; y++) { + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { await this.display.setChar({ x, y }, this.screen.get({ x, y })); } }