Implement methods to get current console size
This commit is contained in:
parent
9cca55b101
commit
d99656de66
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Wrap the runtime-specific hook into stdin
|
* Wrap the runtime-specific hook into stdin
|
||||||
*/
|
*/
|
||||||
import { ITerminalIO } from '../common/mod.ts';
|
import { ITerminalIO, ITerminalSize } from '../common/mod.ts';
|
||||||
|
|
||||||
export async function* inputLoop() {
|
export async function* inputLoop() {
|
||||||
for await (const chunk of Bun.stdin.stream()) {
|
for await (const chunk of Bun.stdin.stream()) {
|
||||||
@ -15,8 +15,20 @@ export async function write(s: string): Promise<void> {
|
|||||||
await Bun.write(Bun.stdout, buffer);
|
await Bun.write(Bun.stdout, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSize(): ITerminalSize {
|
||||||
|
// @TODO implement
|
||||||
|
// Check for tput
|
||||||
|
// If has tput, use it to get terminal size
|
||||||
|
// If not, try FFI fallback
|
||||||
|
// Otherwise, return 80x25 as a last resort
|
||||||
|
const fallback: ITerminalSize = { rows: 25, cols: 80 };
|
||||||
|
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
const BunTerminalIO: ITerminalIO = {
|
const BunTerminalIO: ITerminalIO = {
|
||||||
inputLoop,
|
inputLoop,
|
||||||
|
getSize,
|
||||||
write,
|
write,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
function escape(suffix: string): string {
|
function esc(pieces: TemplateStringsArray): string {
|
||||||
return `\x1b[${suffix}`;
|
return '\x1b[' + pieces[0];
|
||||||
}
|
|
||||||
|
|
||||||
function moveCursor(row: number, col: number): string {
|
|
||||||
return escape(`${row};${col}H`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Ansi = {
|
export const Ansi = {
|
||||||
ClearScreen: escape('2J'),
|
ClearScreen: esc`2J`,
|
||||||
ResetCursor: escape('H'),
|
ResetCursor: esc`H`,
|
||||||
moveCursor,
|
moveCursor: function moveCursor(row: number, col: number): string {
|
||||||
|
return `\x1b${row};${col}H`;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Ansi;
|
export default Ansi;
|
||||||
|
@ -12,6 +12,10 @@ class Buffer {
|
|||||||
this.#b += s;
|
this.#b += s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appendLine(s: string): void {
|
||||||
|
this.#b += s + '\r\n';
|
||||||
|
}
|
||||||
|
|
||||||
clear(): void {
|
clear(): void {
|
||||||
this.#b = '';
|
this.#b = '';
|
||||||
}
|
}
|
||||||
@ -49,10 +53,18 @@ export class Editor {
|
|||||||
const { write } = await importForRuntime('terminal_io');
|
const { write } = await importForRuntime('terminal_io');
|
||||||
|
|
||||||
this.clearScreen();
|
this.clearScreen();
|
||||||
|
this.drawRows();
|
||||||
|
|
||||||
await write(this.#buffer.getBuffer());
|
await write(this.#buffer.getBuffer());
|
||||||
this.#buffer.clear();
|
this.#buffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private drawRows(): void {
|
||||||
|
for (let y = 0; y <= 24; y++) {
|
||||||
|
this.#buffer.appendLine('~');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private clearScreen(): void {
|
private clearScreen(): void {
|
||||||
this.#buffer.append(Ansi.ClearScreen);
|
this.#buffer.append(Ansi.ClearScreen);
|
||||||
this.#buffer.append(Ansi.ResetCursor);
|
this.#buffer.append(Ansi.ResetCursor);
|
||||||
|
@ -1,41 +1,3 @@
|
|||||||
import { importForRuntime } from './runtime.ts';
|
|
||||||
import { Editor } from './editor.ts';
|
|
||||||
import { getTermios } from './termios.ts';
|
|
||||||
|
|
||||||
export * from './runtime.ts';
|
export * from './runtime.ts';
|
||||||
export * from './strings.ts';
|
export * from './strings.ts';
|
||||||
export type * from './types.ts';
|
export type * from './types.ts';
|
||||||
|
|
||||||
const decoder = new TextDecoder();
|
|
||||||
|
|
||||||
export async function main() {
|
|
||||||
const { inputLoop, onExit } = await importForRuntime('mod.ts');
|
|
||||||
|
|
||||||
// Setup raw mode, and tear down on error or normal exit
|
|
||||||
const t = await getTermios();
|
|
||||||
t.enableRawMode();
|
|
||||||
onExit(() => {
|
|
||||||
console.info('Exit handler called, disabling raw mode');
|
|
||||||
t.disableRawMode();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create the editor itself
|
|
||||||
const editor = new Editor();
|
|
||||||
|
|
||||||
// The main event loop
|
|
||||||
for await (const chunk of inputLoop()) {
|
|
||||||
const char = String(decoder.decode(chunk));
|
|
||||||
|
|
||||||
// Clear the screen for output
|
|
||||||
await editor.refreshScreen();
|
|
||||||
|
|
||||||
// Process input
|
|
||||||
const shouldLoop = editor.processKeyPress(char);
|
|
||||||
|
|
||||||
if (!shouldLoop) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
@ -37,6 +37,11 @@ export interface IFFI {
|
|||||||
getPointer(ta: any): unknown;
|
getPointer(ta: any): unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ITerminalSize {
|
||||||
|
rows: number;
|
||||||
|
cols: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runtime-specific IO streams
|
* Runtime-specific IO streams
|
||||||
*/
|
*/
|
||||||
@ -46,6 +51,11 @@ export interface ITerminalIO {
|
|||||||
*/
|
*/
|
||||||
inputLoop(): AsyncGenerator<Uint8Array, void, unknown>;
|
inputLoop(): AsyncGenerator<Uint8Array, void, unknown>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the terminal
|
||||||
|
*/
|
||||||
|
getSize(): ITerminalSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pipe a string to stdout
|
* Pipe a string to stdout
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ITerminalIO } from '../common/types.ts';
|
import { ITerminalIO, ITerminalSize } from '../common/types.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap the runtime-specific hook into stdin
|
* Wrap the runtime-specific hook into stdin
|
||||||
@ -17,8 +17,18 @@ export async function write(s: string): Promise<void> {
|
|||||||
stdout.releaseLock();
|
stdout.releaseLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSize(): ITerminalSize {
|
||||||
|
const size: { rows: number; columns: number } = Deno.consoleSize();
|
||||||
|
|
||||||
|
return {
|
||||||
|
rows: size.rows,
|
||||||
|
cols: size.columns,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const DenoTerminalIO: ITerminalIO = {
|
const DenoTerminalIO: ITerminalIO = {
|
||||||
inputLoop,
|
inputLoop,
|
||||||
|
getSize,
|
||||||
write,
|
write,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,43 @@
|
|||||||
/**
|
/**
|
||||||
* The starting point for running scroll
|
* The starting point for running scroll
|
||||||
*/
|
*/
|
||||||
import { main } from './common/mod.ts';
|
import { importForRuntime } from './common/mod.ts';
|
||||||
|
import { getTermios } from './common/termios.ts';
|
||||||
|
import { Editor } from './common/editor.ts';
|
||||||
|
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
|
export async function main() {
|
||||||
|
const { inputLoop, onExit } = await importForRuntime('mod.ts');
|
||||||
|
|
||||||
|
// Setup raw mode, and tear down on error or normal exit
|
||||||
|
const t = await getTermios();
|
||||||
|
t.enableRawMode();
|
||||||
|
onExit(() => {
|
||||||
|
console.info('Exit handler called, disabling raw mode');
|
||||||
|
t.disableRawMode();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create the editor itself
|
||||||
|
const editor = new Editor();
|
||||||
|
|
||||||
|
// The main event loop
|
||||||
|
for await (const chunk of inputLoop()) {
|
||||||
|
const char = String(decoder.decode(chunk));
|
||||||
|
|
||||||
|
// Clear the screen for output
|
||||||
|
await editor.refreshScreen();
|
||||||
|
|
||||||
|
// Process input
|
||||||
|
const shouldLoop = editor.processKeyPress(char);
|
||||||
|
|
||||||
|
if (!shouldLoop) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the event loop
|
* Start the event loop
|
||||||
|
Loading…
Reference in New Issue
Block a user