Setup basic terminal output for Deno
This commit is contained in:
parent
e3083b1743
commit
f238b162f6
@ -1,2 +1,15 @@
|
|||||||
export enum Ansi {
|
function escape(suffix: string): string {
|
||||||
|
return `\x1b[${suffix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function moveCursor(row: number, col: number): string {
|
||||||
|
return escape(`${row};${col}H`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Ansi = {
|
||||||
|
ClearScreen: escape('2J'),
|
||||||
|
ResetCursor: escape('H'),
|
||||||
|
moveCursor,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Ansi;
|
||||||
|
@ -1,6 +1,60 @@
|
|||||||
export class Editor {
|
import { Ansi } from './ansi.ts';
|
||||||
|
import { importForRuntime } from './runtime.ts';
|
||||||
|
import { ctrl_key } from './strings.ts';
|
||||||
|
|
||||||
|
class Buffer {
|
||||||
|
#b = '';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
public processKeyPress(): void {
|
|
||||||
|
append(s: string): void {
|
||||||
|
this.#b += s;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(): void {
|
||||||
|
this.#b = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
getBuffer(): string {
|
||||||
|
return this.#b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Editor {
|
||||||
|
#buffer: Buffer;
|
||||||
|
constructor() {
|
||||||
|
this.#buffer = new Buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine what to do based on input
|
||||||
|
* @param input - the decoded chunk of stdin
|
||||||
|
*/
|
||||||
|
public processKeyPress(input: string): boolean {
|
||||||
|
switch (input) {
|
||||||
|
case ctrl_key('q'):
|
||||||
|
this.clearScreen();
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the screen and write out the buffer
|
||||||
|
*/
|
||||||
|
public async refreshScreen(): Promise<void> {
|
||||||
|
const { write } = await importForRuntime('terminal_io');
|
||||||
|
|
||||||
|
this.clearScreen();
|
||||||
|
await write(this.#buffer.getBuffer());
|
||||||
|
this.#buffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearScreen(): void {
|
||||||
|
this.#buffer.append(Ansi.ClearScreen);
|
||||||
|
this.#buffer.append(Ansi.ResetCursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { importForRuntime } from "./runtime";
|
import { importForRuntime } from './runtime.ts';
|
||||||
import { ctrl_key, is_control } from "./strings";
|
import { Editor } from './editor.ts';
|
||||||
|
|
||||||
export * from './runtime.ts';
|
export * from './runtime.ts';
|
||||||
export * from './strings.ts';
|
export * from './strings.ts';
|
||||||
@ -8,32 +8,29 @@ export type { ITestBase } from './test_base.ts';
|
|||||||
|
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
export function readKey(chunk): string {
|
|
||||||
const char = String(decoder.decode(chunk))
|
|
||||||
|
|
||||||
return char;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function main() {
|
export async function main() {
|
||||||
const { inputLoop, init } = await importForRuntime('mod.ts');
|
const { inputLoop, init } = await importForRuntime('mod.ts');
|
||||||
|
|
||||||
// Set up handlers to enable/disable raw mode for each runtime
|
// Set up handlers to enable/disable raw mode for each runtime
|
||||||
await init();
|
await init();
|
||||||
|
|
||||||
|
// Create the editor itself
|
||||||
|
const editor = new Editor();
|
||||||
|
|
||||||
// The main event loop
|
// The main event loop
|
||||||
for await (const chunk of inputLoop()) {
|
for await (const chunk of inputLoop()) {
|
||||||
const char = readKey(chunk);
|
const char = String(decoder.decode(chunk));
|
||||||
|
|
||||||
if (char === ctrl_key('q')) {
|
// Clear the screen for output
|
||||||
|
await editor.refreshScreen();
|
||||||
|
|
||||||
|
// Process input
|
||||||
|
const shouldLoop = editor.processKeyPress(char);
|
||||||
|
|
||||||
|
if (!shouldLoop) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_control(char)) {
|
|
||||||
console.log(char.codePointAt(0) + '\r');
|
|
||||||
} else {
|
|
||||||
console.log(`${char} ('${char.codePointAt(0)}')\r`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* The main entrypoint when using Deno as the runtime
|
* The main entrypoint when using Deno as the runtime
|
||||||
*/
|
*/
|
||||||
import { getTermios } from "../common/mod.ts";
|
import { getTermios } from '../common/mod.ts';
|
||||||
|
|
||||||
export * from './terminal_io.ts';
|
export * from './terminal_io.ts';
|
||||||
|
|
||||||
|
@ -6,3 +6,11 @@ export async function* inputLoop() {
|
|||||||
yield chunk;
|
yield chunk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function write(s: string): Promise<void> {
|
||||||
|
const buffer = new TextEncoder().encode(s);
|
||||||
|
|
||||||
|
const stdout = Deno.stdout.writable.getWriter();
|
||||||
|
await stdout.write(buffer);
|
||||||
|
stdout.releaseLock();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user