feat(editor): F4.6b the command line on a computer's desktop
A new oracle, TerminalWindowRun, types into Java's own command line window: the window writes each line after its prompt, takes a blank line, cls, reset and exit itself, keeps the lines for the arrow keys, and keeps its text, history and working directory over a stop and a start. The room now holds a command line window per computer for everyone (TerminalWindow), kept over stops; the protocol carries its lines and the one way to read them (terminalScreen); the core goes on in the working directory of the run before (continueIn). The desktop opens programs in Java's frame, and the command line works with keyboard and finger: grey on black, the prompt hidden while a command runs, history, chips for the commands, Ctrl+C. The room's failure is now tested in the browser. Fixed: the room handed the engine the wall clock with fractions of a millisecond, and a ping hung after its first timeout. The engine and the room count whole milliseconds, as Java's clock does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// Public surface of the wire protocol.
|
||||
export * from './host.js';
|
||||
export * from './sim.js';
|
||||
export * from './terminal.js';
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// A command line's window as the room keeps it and every client shows it
|
||||
// (plan §7.3): its lines, in order, and how a client reads them, after
|
||||
// GUIApplicationTerminalWindow (measured with tools/java-oracle's
|
||||
// TerminalWindowRun). The window, not the program, puts the start screen
|
||||
// up, writes each entered line after its prompt, takes a blank line, cls,
|
||||
// reset and exit itself, hides the prompt while a command runs and keeps the
|
||||
// lines entered for the arrow keys.
|
||||
|
||||
/** A line of a command line's window. */
|
||||
export type TerminalLine =
|
||||
/** What the program or the window wrote: the start screen, a command's output, a blank line's " \n". */
|
||||
| { readonly kind: 'text'; readonly text: string }
|
||||
/** A line entered after its prompt; `command` when the program runs it (not cls, reset or exit). */
|
||||
| { readonly kind: 'input'; readonly prompt: string; readonly line: string; readonly command: boolean }
|
||||
/** cls or reset: the window starts again (the start screen follows). */
|
||||
| { readonly kind: 'clear' }
|
||||
/** A command that runs on (ping …) began or ended (Java's Boolean to the window). */
|
||||
| { readonly kind: 'busy'; readonly busy: boolean }
|
||||
/** The prompt after a command, when it changed (the working directory). */
|
||||
| { readonly kind: 'prompt'; readonly prompt: string }
|
||||
/** exit: the window closes; its text stays. */
|
||||
| { readonly kind: 'exit' };
|
||||
|
||||
export interface TerminalScreen {
|
||||
/** What the window shows, from its last cls on. */
|
||||
readonly text: string;
|
||||
readonly prompt: string;
|
||||
/** Java hides the prompt from a command's start until its end. */
|
||||
readonly promptShown: boolean;
|
||||
/** Every line entered, the oldest first (blank lines not), for the arrow keys. */
|
||||
readonly history: readonly string[];
|
||||
}
|
||||
|
||||
/** The window as Java shows it after these lines. */
|
||||
export function terminalScreen(lines: readonly TerminalLine[]): TerminalScreen {
|
||||
let text = '';
|
||||
let prompt = '';
|
||||
let promptShown = true;
|
||||
let busy = false;
|
||||
const history: string[] = [];
|
||||
for (const line of lines) {
|
||||
switch (line.kind) {
|
||||
case 'text':
|
||||
text += line.text;
|
||||
if (!busy) promptShown = true;
|
||||
break;
|
||||
case 'input':
|
||||
text += `\n${line.prompt}${line.line}\n`;
|
||||
history.push(line.line);
|
||||
if (line.command) promptShown = false;
|
||||
break;
|
||||
case 'clear':
|
||||
text = '';
|
||||
break;
|
||||
case 'busy':
|
||||
busy = line.busy;
|
||||
promptShown = !busy;
|
||||
break;
|
||||
case 'prompt':
|
||||
prompt = line.prompt;
|
||||
break;
|
||||
case 'exit':
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { text, prompt, promptShown, history };
|
||||
}
|
||||
|
||||
/**
|
||||
* The arrow keys in the history (Java's commandHistoryPointer): -1 is the
|
||||
* empty line below the newest, 0 the newest, and so on; up goes back, down
|
||||
* forward, neither beyond the ends.
|
||||
*/
|
||||
export function historyStep(pointer: number, step: 'up' | 'down', length: number): number {
|
||||
const next = pointer + (step === 'up' ? 1 : -1);
|
||||
return Math.max(-1, Math.min(length - 1, next));
|
||||
}
|
||||
|
||||
/** The line the history shows at a pointer: empty below the newest. */
|
||||
export function historyLine(history: readonly string[], pointer: number): string {
|
||||
return pointer < 0 ? '' : (history[history.length - 1 - pointer] ?? '');
|
||||
}
|
||||
Reference in New Issue
Block a user