A new oracle, InstallRun, installs each of Java's programs on new computers, all of them on one, each installed and removed again, and a DNS and an e-mail server installed again after their removal; Java saves the result as a project. A new program is switched off (a computer's firewall is on), makes the folders and files it lacks (the web server's start page in FILIUS' language and its picture, /peer2peer, /mailserver/konten.txt, /dns/hosts), and removing it takes its settings and leaves its files; a server installed again reads its records or accounts from them. Java installs in the order of its list and starts the program at once. The document's setSoftware does the same, checked against Java's saved installation. The core knows what a program makes in the files and installs or removes a program while the simulation runs; the room watches the document's programs and hands changes to the engine, so a new command line works at once. The desktop offers Java's dialog with two lists, arrows, double click and apply changes. Also: Java's file may name a number it rolled by the result of any getter (an idref, here a thread's priority); GetterDefaults now measures the priority of the saved thread classes, which the import read as 0 before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
91 lines
3.1 KiB
TypeScript
91 lines
3.1 KiB
TypeScript
// A computer's command line window in the room (plan §7.3): one for everyone
|
|
// who opens it, as Java has one per computer. It writes the program's lines
|
|
// into the window's lines after the window's own (the start screen, each
|
|
// entered line after its prompt, a blank line, cls, exit), in the order they
|
|
// happened. Like Java's window it outlives a stop and a start: its text, its
|
|
// history and the working directory stay (TerminalWindowRun); each start
|
|
// brings a new program, which goes on where the last one was.
|
|
|
|
import type { Terminal } from '@mdg-filius/core';
|
|
import type { TerminalLine } from '@mdg-filius/protocol';
|
|
|
|
/** StringUtils.isBlank: nothing but whitespace. */
|
|
const blank = (line: string) => line.trim() === '';
|
|
|
|
export class TerminalWindow {
|
|
private readonly linesValue: TerminalLine[] = [];
|
|
private terminal!: Terminal;
|
|
/** How many of the program's lines are in the window. */
|
|
private seen = 0;
|
|
private busy = false;
|
|
private prompt: string | undefined;
|
|
private directory = '/';
|
|
|
|
/** A window on the program of the first start. */
|
|
constructor(terminal: Terminal) {
|
|
this.attach(terminal);
|
|
}
|
|
|
|
get lines(): readonly TerminalLine[] {
|
|
return this.linesValue;
|
|
}
|
|
|
|
/** The program of a start: the first time the window shows its start screen, later it goes on in the working directory it had. */
|
|
attach(terminal: Terminal): void {
|
|
if (this.terminal === terminal) return;
|
|
this.terminal = terminal;
|
|
this.seen = 0;
|
|
terminal.continueIn(this.directory);
|
|
if (this.linesValue.length === 0) this.linesValue.push({ kind: 'text', text: terminal.startScreen });
|
|
if (this.busy) {
|
|
// A command cut off by the stop has ended.
|
|
this.busy = false;
|
|
this.linesValue.push({ kind: 'busy', busy: false });
|
|
}
|
|
this.syncPrompt();
|
|
}
|
|
|
|
/** Takes the program's new lines into the window. */
|
|
pull(): void {
|
|
const terminal = this.terminal;
|
|
for (const entry of terminal.log.all.slice(this.seen)) {
|
|
if (entry.kind === 'text') this.linesValue.push({ kind: 'text', text: entry.text });
|
|
else {
|
|
this.busy = entry.busy;
|
|
this.linesValue.push({ kind: 'busy', busy: entry.busy });
|
|
}
|
|
}
|
|
this.seen = terminal.log.all.length;
|
|
this.directory = terminal.directory;
|
|
if (!this.busy) this.syncPrompt();
|
|
}
|
|
|
|
/** A line entered in the window. */
|
|
enter(line: string): void {
|
|
const terminal = this.terminal;
|
|
this.pull();
|
|
if (blank(line)) {
|
|
this.linesValue.push({ kind: 'text', text: ' \n' });
|
|
return;
|
|
}
|
|
const prompt = this.prompt ?? terminal.prompt;
|
|
const action = terminal.enter(line);
|
|
this.linesValue.push({ kind: 'input', prompt, line, command: action === undefined });
|
|
if (action === 'exit') this.linesValue.push({ kind: 'exit' });
|
|
if (action === 'clear') this.linesValue.push({ kind: 'clear' }, { kind: 'text', text: terminal.startScreen });
|
|
this.pull();
|
|
}
|
|
|
|
/** Ctrl+C in the window. */
|
|
interrupt(): void {
|
|
this.terminal.interrupt();
|
|
}
|
|
|
|
private syncPrompt(): void {
|
|
const prompt = this.terminal.prompt;
|
|
if (prompt === this.prompt) return;
|
|
this.prompt = prompt;
|
|
this.linesValue.push({ kind: 'prompt', prompt });
|
|
}
|
|
}
|