From 1d10420cad79c62f237d5028f376719fe98ce185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Tue, 11 May 2021 23:20:33 +0200 Subject: [PATCH] Initial structure --- .editorconfig | 9 +++++++++ .gitignore | 3 +++ README.md | 3 +++ ansi.test.ts | 11 +++++++++++ ansi.ts | 23 +++++++++++++++++++++++ common.ts | 13 +++++++++++++ demo.ts | 9 +++++++++ deps.test.ts | 2 ++ deps.ts | 1 + display.ts | 37 +++++++++++++++++++++++++++++++++++++ tsconfig.json | 10 ++++++++++ 11 files changed, 121 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 README.md create mode 100644 ansi.test.ts create mode 100644 ansi.ts create mode 100644 common.ts create mode 100755 demo.ts create mode 100644 deps.test.ts create mode 100644 deps.ts create mode 100644 display.ts create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..83c1115 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*.{ts,json}] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d69a4c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +deno.d.ts +.vscode +.local diff --git a/README.md b/README.md new file mode 100644 index 0000000..c56042c --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# typescript/textui + +[![Build Status](https://thunderk.visualstudio.com/typescript/_apis/build/status/textui?branchName=master)](https://dev.azure.com/thunderk/typescript/_build?pipelineNameFilter=textui) diff --git a/ansi.test.ts b/ansi.test.ts new file mode 100644 index 0000000..8d51b4f --- /dev/null +++ b/ansi.test.ts @@ -0,0 +1,11 @@ +import { AnsiTerminalDisplay } from "./ansi.ts"; +import { Buffer, describe, expect, it } from "./deps.test.ts"; + +describe(AnsiTerminalDisplay, () => { + it("clears the screen", async () => { + const stdout = new Buffer(); + const display = new AnsiTerminalDisplay(stdout); + await display.clear(); + expect(stdout.bytes()).toEqual(new Uint8Array([27, 91, 50, 74])); + }); +}); diff --git a/ansi.ts b/ansi.ts new file mode 100644 index 0000000..0e66c98 --- /dev/null +++ b/ansi.ts @@ -0,0 +1,23 @@ +import { Color, Display } from "./display.ts"; + +/** + * ANSI terminal display + */ +export class AnsiTerminalDisplay implements Display { + constructor(private writer: Deno.Writer = Deno.stdout) { + } + + async setupPalette(colors: readonly Color[]): Promise { + return colors; + } + + async clear(): Promise { + await this.writer.write(CLEAR); + } +} + +function escape(sequence: string): Uint8Array { + return new Uint8Array([0x1B, ...new TextEncoder().encode(sequence)]); +} + +const CLEAR = escape("[2J"); diff --git a/common.ts b/common.ts new file mode 100644 index 0000000..6cfe7b1 --- /dev/null +++ b/common.ts @@ -0,0 +1,13 @@ +import { Display } from "./display.ts"; + +/** + * Common abstraction for a textual UI + */ +export class TextUI { + constructor(private display: Display) { + } + + async init(): Promise { + await this.display.clear(); + } +} diff --git a/demo.ts b/demo.ts new file mode 100755 index 0000000..e18dbca --- /dev/null +++ b/demo.ts @@ -0,0 +1,9 @@ +#!/usr/bin/env -S deno run + +import { AnsiTerminalDisplay } from "./ansi.ts"; +import { TextUI } from "./common.ts"; + +const display = new AnsiTerminalDisplay(); +const ui = new TextUI(display); +await ui.init(); +await new Promise((resolve) => setTimeout(resolve, 3000)); diff --git a/deps.test.ts b/deps.test.ts new file mode 100644 index 0000000..9d35faf --- /dev/null +++ b/deps.test.ts @@ -0,0 +1,2 @@ +export * from "https://code.thunderk.net/typescript/devtools/raw/1.2.2/testing.ts"; +export { Buffer } from "https://deno.land/std@0.96.0/io/buffer.ts"; diff --git a/deps.ts b/deps.ts new file mode 100644 index 0000000..f23b5a8 --- /dev/null +++ b/deps.ts @@ -0,0 +1 @@ +export { Sys } from "https://code.thunderk.net/typescript/devtools/raw/1.2.2/system.ts"; diff --git a/display.ts b/display.ts new file mode 100644 index 0000000..b9cf326 --- /dev/null +++ b/display.ts @@ -0,0 +1,37 @@ +/** + * Color represented by RGB (0.0-1.0) components + */ +export type Color = { + r: number; + g: number; + b: number; +}; + +/** + * Displayable character, with background and foreground color taken from the palette + */ +export type Char = { + ch: string; + bg: number; + fg: number; +}; + +/** + * Display protocol, to allow the UI to draw things on "screen" + */ +export interface Display { + /** + * Setup the palette for color display + * + * If the display supports the whole RGB range, it may return the array as-is. + * If the display only supports a limited palette, it may return only supported colors. + * + * From this call forward, colors will be received by numbered index in the returned array. + */ + setupPalette(colors: readonly Color[]): Promise; + + /** + * Clear the whole screen + */ + clear(): Promise; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e28737f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "module": "esnext", + "target": "ESNext", + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "preserveConstEnums": true + } +}