Skip to content

Commit c31a342

Browse files
author
zhangfuxing
committed
add code
1 parent 8defd62 commit c31a342

File tree

3 files changed

+181
-1
lines changed

3 files changed

+181
-1
lines changed

README.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,44 @@
11
# termbox
2-
Termbox is a deno package that provides a cell based view for text terminals.
2+
3+
Termbox is a deno package that provides a cell based view for text terminals.
4+
5+
## Usage
6+
7+
```ts
8+
import TermBox from "https://deno.land/x/termbox@v0.1.0/mod.ts";
9+
10+
const termbox = new TermBox();
11+
12+
termbox.setCell(x, y, "a");
13+
```
14+
15+
## Interface
16+
17+
```ts
18+
class TermBox {
19+
constructor(size?: Size);
20+
flush(): Promise<void>;
21+
size(): Size;
22+
end(): void;
23+
24+
setCell(x: number, y: number, char: string): void;
25+
26+
cursorHide(): Promise<void>;
27+
cursorShow(): Promise<void>;
28+
cursorSave(): Promise<void>;
29+
cursorRestore(): Promise<void>;
30+
cursorTo(x: number, y: number): Promise<void>;
31+
32+
screenClear(): Promise<void>;
33+
screenReset(): Promise<void>;
34+
}
35+
36+
interface Size {
37+
columns: number;
38+
rows: number;
39+
}
40+
```
41+
42+
## example
43+
44+
> https://github.com/deno-library/sl

mod.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import TermBox from "./mod.ts";
2+
import { assertThrows } from "https://deno.land/std@0.186.0/testing/asserts.ts";
3+
4+
Deno.test(`test Hello world`, async () => {
5+
const termbox = new TermBox();
6+
7+
await termbox.hideCursor();
8+
await termbox.clearScreen();
9+
10+
let i = 0;
11+
for (const char of "Hello world!") {
12+
termbox.setCell(i++, 0, char);
13+
}
14+
15+
await termbox.flush();
16+
termbox.cursorTo(0, 0);
17+
await termbox.showCursor();
18+
termbox.end();
19+
});
20+
21+
Deno.test(`Throw error`, () => {
22+
const termbox = new TermBox();
23+
24+
assertThrows((): void => {
25+
termbox.setCell(0, 0, "Hello world!");
26+
});
27+
28+
termbox.end();
29+
});

mod.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
const ESC = "\x1B[";
2+
3+
const SAVE = "\x1B7";
4+
const RESTORE = "\x1B8";
5+
const HIDE = "?25l";
6+
const SHOW = "?25h";
7+
8+
const CLEAR_SCREEN = "2J";
9+
10+
const HOME = "H";
11+
12+
const isTTY = Deno.isatty(Deno.stdout.rid);
13+
14+
interface Size {
15+
columns: number;
16+
rows: number;
17+
}
18+
19+
export default class TermBox {
20+
private encoder = new TextEncoder();
21+
private writer = Deno.stdout.writable.getWriter();
22+
private cells: string[][];
23+
private columns: number;
24+
private rows: number;
25+
26+
constructor(size?: Size) {
27+
const { columns, rows } = size ?? this.size();
28+
this.columns = columns;
29+
this.rows = rows;
30+
this.cells = new Array(rows).fill(null).map(() =>
31+
new Array(columns).fill(null).map(() => " ")
32+
);
33+
}
34+
35+
private cursor(action: string): Promise<void> {
36+
return this.write(ESC + action);
37+
}
38+
39+
private write(msg: string): Promise<void> {
40+
return this.writer.write(this.encoder.encode(msg));
41+
}
42+
43+
flush(): Promise<void> {
44+
this.cursorTo(0, 0);
45+
return this.write(this.cells.map((v) => v.join("")).join("\n"));
46+
}
47+
48+
setCell(x: number, y: number, char: string): void {
49+
if (x >= this.columns || x < 0) return;
50+
if (y >= this.rows || y < 0) return;
51+
if (stripAnsiCode(char).length > 1) {
52+
throw new Error("char length cannot be greater than 1");
53+
}
54+
this.cells[y][x] = char;
55+
}
56+
57+
cursorHide(): Promise<void> {
58+
return this.cursor(HIDE);
59+
}
60+
61+
cursorShow(): Promise<void> {
62+
return this.cursor(SHOW);
63+
}
64+
65+
cursorSave(): Promise<void> {
66+
return this.cursor(SAVE);
67+
}
68+
69+
cursorRestore(): Promise<void> {
70+
return this.cursor(RESTORE);
71+
}
72+
73+
cursorTo(x: number, y: number): Promise<void> {
74+
return this.cursor(`${y};${x}${HOME}`);
75+
}
76+
77+
screenClear(): Promise<void> {
78+
return this.cursor(CLEAR_SCREEN);
79+
}
80+
81+
screenReset(): Promise<void> {
82+
return this.write("\x1b[" + (this.rows - 1) + "A\r\x1b[?0J");
83+
}
84+
85+
size(): Size {
86+
if (!isTTY) return { columns: 100, rows: 50 };
87+
return {
88+
columns: Deno.consoleSize().columns,
89+
rows: Deno.consoleSize().rows,
90+
};
91+
}
92+
93+
end(): void {
94+
this.writer.releaseLock();
95+
}
96+
}
97+
98+
// https://github.com/chalk/ansi-regex/blob/02fa893d619d3da85411acc8fd4e2eea0e95a9d9/index.js
99+
const ANSI_PATTERN = new RegExp(
100+
[
101+
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
102+
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TXZcf-nq-uy=><~]))",
103+
].join("|"),
104+
"g",
105+
);
106+
107+
function stripAnsiCode(string: string): string {
108+
return string.replace(ANSI_PATTERN, "");
109+
}

0 commit comments

Comments
 (0)