2023-11-06 15:36:41 -05:00
|
|
|
/**
|
|
|
|
* Wrap the runtime-specific hook into stdin
|
|
|
|
*/
|
2023-11-24 08:31:51 -05:00
|
|
|
import Ansi from '../common/ansi.ts';
|
2023-11-29 16:09:58 -05:00
|
|
|
import { defaultTerminalSize } from '../common/config.ts';
|
|
|
|
import { readKey } from '../common/fns.ts';
|
|
|
|
import { ITerminal, ITerminalSize } from '../common/types.ts';
|
2023-11-09 10:46:12 -05:00
|
|
|
|
2023-11-13 15:33:56 -05:00
|
|
|
const BunTerminalIO: ITerminal = {
|
2023-11-14 15:53:45 -05:00
|
|
|
// Deno only returns arguments passed to the script, so
|
|
|
|
// remove the bun runtime executable, and entry script arguments
|
|
|
|
// to have consistent argument lists
|
|
|
|
argv: (Bun.argv.length > 2) ? Bun.argv.slice(2) : [],
|
2023-11-08 18:07:34 -05:00
|
|
|
inputLoop: async function* inputLoop() {
|
|
|
|
for await (const chunk of Bun.stdin.stream()) {
|
2023-11-27 15:05:48 -05:00
|
|
|
yield chunk;
|
2023-11-08 18:07:34 -05:00
|
|
|
}
|
2023-11-27 15:05:48 -05:00
|
|
|
|
|
|
|
return null;
|
2023-11-08 18:07:34 -05:00
|
|
|
},
|
2023-11-10 18:22:09 -05:00
|
|
|
getTerminalSize: async function getTerminalSize(): Promise<ITerminalSize> {
|
|
|
|
const encoder = new TextEncoder();
|
|
|
|
const write = (s: string) => Bun.write(Bun.stdout, encoder.encode(s));
|
|
|
|
|
|
|
|
// Tell the cursor to move to Row 999 and Column 999
|
|
|
|
// Since this command specifically doesn't go off the screen
|
|
|
|
// When we ask where the cursor is, we should get the size of the screen
|
|
|
|
await write(Ansi.moveCursorForward(999) + Ansi.moveCursorDown(999));
|
|
|
|
|
|
|
|
// Ask where the cursor is
|
|
|
|
await write(Ansi.GetCursorLocation);
|
|
|
|
|
|
|
|
// Get the first chunk from stdin
|
|
|
|
// The response is \x1b[(rows);(cols)R..
|
2023-11-27 15:05:48 -05:00
|
|
|
const chunk = await BunTerminalIO.readStdinRaw();
|
|
|
|
if (chunk === null) {
|
|
|
|
return defaultTerminalSize;
|
|
|
|
}
|
2023-11-10 18:22:09 -05:00
|
|
|
|
2023-11-27 15:05:48 -05:00
|
|
|
const rawCode = (new TextDecoder()).decode(chunk);
|
|
|
|
const res = rawCode.trim().replace(/^.\[([0-9]+;[0-9]+)R$/, '$1');
|
|
|
|
const [srows, scols] = res.split(';');
|
|
|
|
const rows = parseInt(srows, 10) ?? 24;
|
|
|
|
const cols = parseInt(scols, 10) ?? 80;
|
2023-11-10 18:22:09 -05:00
|
|
|
|
2023-11-27 15:05:48 -05:00
|
|
|
// Clear the screen
|
|
|
|
await write(Ansi.ClearScreen + Ansi.ResetCursor);
|
2023-11-10 18:22:09 -05:00
|
|
|
|
2023-11-27 15:05:48 -05:00
|
|
|
return {
|
|
|
|
rows,
|
|
|
|
cols,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
readStdin: async function (): Promise<string | null> {
|
|
|
|
const raw = await BunTerminalIO.readStdinRaw();
|
|
|
|
return readKey(raw ?? new Uint8Array(0));
|
2023-11-08 18:07:34 -05:00
|
|
|
},
|
2023-11-27 15:05:48 -05:00
|
|
|
readStdinRaw: async function (): Promise<Uint8Array | null> {
|
|
|
|
const chunk = await BunTerminalIO.inputLoop().next();
|
|
|
|
return chunk.value ?? null;
|
2023-11-27 11:07:26 -05:00
|
|
|
},
|
2023-11-13 15:33:56 -05:00
|
|
|
writeStdout: async function write(s: string): Promise<void> {
|
2023-11-08 18:07:34 -05:00
|
|
|
const buffer = new TextEncoder().encode(s);
|
2023-11-08 17:02:59 -05:00
|
|
|
|
2023-11-08 18:07:34 -05:00
|
|
|
await Bun.write(Bun.stdout, buffer);
|
|
|
|
},
|
2023-11-08 15:53:14 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
export default BunTerminalIO;
|