Fix prompt in deno, but break in bun :(
This commit is contained in:
parent
4d54d4bf8a
commit
8ee17f4eef
@ -16,8 +16,10 @@ const BunTerminalIO: ITerminal = {
|
||||
argv: (Bun.argv.length > 2) ? Bun.argv.slice(2) : [],
|
||||
inputLoop: async function* inputLoop() {
|
||||
for await (const chunk of Bun.stdin.stream()) {
|
||||
yield readKey(chunk);
|
||||
yield chunk;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
getTerminalSize: async function getTerminalSize(): Promise<ITerminalSize> {
|
||||
const encoder = new TextEncoder();
|
||||
@ -33,28 +35,32 @@ const BunTerminalIO: ITerminal = {
|
||||
|
||||
// Get the first chunk from stdin
|
||||
// The response is \x1b[(rows);(cols)R..
|
||||
for await (const chunk of Bun.stdin.stream()) {
|
||||
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;
|
||||
|
||||
// Clear the screen
|
||||
await write(Ansi.ClearScreen + Ansi.ResetCursor);
|
||||
|
||||
return {
|
||||
rows,
|
||||
cols,
|
||||
};
|
||||
const chunk = await BunTerminalIO.readStdinRaw();
|
||||
if (chunk === null) {
|
||||
return defaultTerminalSize;
|
||||
}
|
||||
|
||||
return defaultTerminalSize;
|
||||
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;
|
||||
|
||||
// Clear the screen
|
||||
await write(Ansi.ClearScreen + Ansi.ResetCursor);
|
||||
|
||||
return {
|
||||
rows,
|
||||
cols,
|
||||
};
|
||||
},
|
||||
readStdin: async function (): Promise<string> {
|
||||
const gen = BunTerminalIO.inputLoop();
|
||||
const chunk = await gen.next();
|
||||
return chunk.value!;
|
||||
readStdin: async function (): Promise<string | null> {
|
||||
const raw = await BunTerminalIO.readStdinRaw();
|
||||
return readKey(raw ?? new Uint8Array(0));
|
||||
},
|
||||
readStdinRaw: async function (): Promise<Uint8Array | null> {
|
||||
const chunk = await BunTerminalIO.inputLoop().next();
|
||||
return chunk.value ?? null;
|
||||
},
|
||||
writeStdout: async function write(s: string): Promise<void> {
|
||||
const buffer = new TextEncoder().encode(s);
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
ITerminalSize,
|
||||
logToFile,
|
||||
Position,
|
||||
readKey,
|
||||
SCROLL_QUIT_TIMES,
|
||||
SCROLL_VERSION,
|
||||
} from './mod.ts';
|
||||
@ -229,23 +230,35 @@ class Editor {
|
||||
|
||||
let res = '';
|
||||
|
||||
while (true) {
|
||||
outer: while (true) {
|
||||
this.setStatusMessage(`${p}${res}`);
|
||||
await this.refreshScreen();
|
||||
const char = await term.readStdin();
|
||||
// End the prompt
|
||||
if (char === KeyCommand.Enter) {
|
||||
this.setStatusMessage('');
|
||||
if (res.length === 0) {
|
||||
return null;
|
||||
for await (const chunk of term.inputLoop()) {
|
||||
const char = readKey(chunk);
|
||||
if (char === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
// End the prompt
|
||||
if (char === KeyCommand.Enter) {
|
||||
this.setStatusMessage('');
|
||||
if (res.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add to the prompt result
|
||||
if (!isControl(char)) {
|
||||
res += char;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Allow backspacing
|
||||
if (char === KeyCommand.Backspace || char === KeyCommand.Delete) {
|
||||
res = truncate(res, res.length - 1);
|
||||
continue outer;
|
||||
}
|
||||
|
||||
// Add to the prompt result
|
||||
if (!isControl(char!)) {
|
||||
res += char;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getRuntime } from './runtime.ts';
|
||||
import { getRuntime, readKey } from './runtime.ts';
|
||||
import { getTermios } from './termios.ts';
|
||||
import Editor from './editor.ts';
|
||||
|
||||
@ -37,16 +37,21 @@ export async function main() {
|
||||
// Clear the screen
|
||||
await editor.refreshScreen();
|
||||
|
||||
for await (const char of term.inputLoop()) {
|
||||
// Process input
|
||||
const shouldLoop = await editor.processKeyPress(char);
|
||||
if (!shouldLoop) {
|
||||
return 0;
|
||||
while (true) {
|
||||
for await (const char of term.inputLoop()) {
|
||||
const parsed = readKey(char);
|
||||
if (char.length === 0 || parsed.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process input
|
||||
const shouldLoop = await editor.processKeyPress(parsed);
|
||||
if (!shouldLoop) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Render output
|
||||
await editor.refreshScreen();
|
||||
}
|
||||
|
||||
// Render output
|
||||
await editor.refreshScreen();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -64,14 +64,22 @@ export interface ITerminal {
|
||||
/**
|
||||
* The generator function returning chunks of input from the stdin stream
|
||||
*/
|
||||
inputLoop(): AsyncGenerator<string, void>;
|
||||
inputLoop(): AsyncGenerator<Uint8Array, null>;
|
||||
|
||||
/**
|
||||
* Get the size of the terminal
|
||||
*/
|
||||
getTerminalSize(): Promise<ITerminalSize>;
|
||||
|
||||
readStdin(): Promise<string>;
|
||||
/**
|
||||
* Get the current chunk of input, if it exists
|
||||
*/
|
||||
readStdin(): Promise<string | null>;
|
||||
|
||||
/**
|
||||
* Get the raw chunk of input
|
||||
*/
|
||||
readStdinRaw(): Promise<Uint8Array | null>;
|
||||
|
||||
/**
|
||||
* Pipe a string to stdout
|
||||
@ -147,6 +155,9 @@ let scrollRuntime: IRuntime | null = null;
|
||||
* @param raw - the raw chunk of input
|
||||
*/
|
||||
export function readKey(raw: Uint8Array): string {
|
||||
if (raw.length === 0) {
|
||||
return '';
|
||||
}
|
||||
const parsed = decoder.decode(raw);
|
||||
|
||||
// Return the input if it's unambiguous
|
||||
|
@ -2,13 +2,10 @@ import { ITerminal, ITerminalSize, readKey } from '../common/runtime.ts';
|
||||
|
||||
const DenoTerminalIO: ITerminal = {
|
||||
argv: Deno.args,
|
||||
/**
|
||||
* Wrap the runtime-specific hook into stdin
|
||||
*/
|
||||
inputLoop: async function* inputLoop() {
|
||||
for await (const chunk of Deno.stdin.readable) {
|
||||
yield readKey(chunk);
|
||||
}
|
||||
inputLoop: async function* (): AsyncGenerator<Uint8Array, null> {
|
||||
yield await DenoTerminalIO.readStdinRaw() ?? new Uint8Array(0);
|
||||
|
||||
return null;
|
||||
},
|
||||
getTerminalSize: function getSize(): Promise<ITerminalSize> {
|
||||
const size: { rows: number; columns: number } = Deno.consoleSize();
|
||||
@ -18,10 +15,16 @@ const DenoTerminalIO: ITerminal = {
|
||||
cols: size.columns,
|
||||
});
|
||||
},
|
||||
readStdin: async function (): Promise<string> {
|
||||
const gen = DenoTerminalIO.inputLoop();
|
||||
const chunk = await gen.next();
|
||||
return chunk.value!;
|
||||
readStdin: async function (): Promise<string | null> {
|
||||
const raw = await DenoTerminalIO.readStdinRaw();
|
||||
return readKey(raw ?? new Uint8Array(0));
|
||||
},
|
||||
readStdinRaw: async function (): Promise<Uint8Array | null> {
|
||||
const reader = Deno.stdin.readable.getReader();
|
||||
const chunk = await reader.read();
|
||||
const res = chunk?.value;
|
||||
reader.releaseLock();
|
||||
return res ?? null;
|
||||
},
|
||||
writeStdout: async function write(s: string): Promise<void> {
|
||||
const buffer: Uint8Array = new TextEncoder().encode(s);
|
||||
|
Loading…
Reference in New Issue
Block a user