Skip to content

Commit

Permalink
Merge pull request #28 from jupyterlite/stderr
Browse files Browse the repository at this point in the history
Use separate TerminalOutput for stderr
  • Loading branch information
ianthomas23 authored Jul 25, 2024
2 parents 752700b + 69fcfaf commit 974fc10
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 19 deletions.
12 changes: 7 additions & 5 deletions src/commands/builtin_command_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class BuiltinCommandRunner implements ICommandRunner {
await this._alias(context);
break;
case 'cd':
this._cd(context);
await this._cd(context);
break;
case 'history':
await this._history(context);
Expand All @@ -28,20 +28,22 @@ export class BuiltinCommandRunner implements ICommandRunner {
}
}

private _cd(context: Context) {
const { args } = context;
private async _cd(context: Context) {
const { args, stderr } = context;
if (args.length < 1) {
// Do nothing.
return;
} else if (args.length > 1) {
throw new Error('cd: too many arguments');
await stderr.write('cd: too many arguments\r\n');
return;
}

let path = args[0];
if (path === '-') {
const oldPwd = context.environment.get('OLDPWD');
if (oldPwd === undefined) {
throw new Error('cd: OLDPWD not set');
await stderr.write('cd: OLDPWD not set\r\n');
return;
}
path = oldPwd;
}
Expand Down
4 changes: 2 additions & 2 deletions src/commands/wasm_command_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export abstract class WasmCommandRunner implements ICommandRunner {
abstract names(): string[];

async run(cmdName: string, context: Context): Promise<void> {
const { args, fileSystem, mountpoint, stdin, stdout } = context;
const { args, fileSystem, mountpoint, stdin, stdout, stderr } = context;

const start = Date.now();
if (!this._wasmModule) {
Expand Down Expand Up @@ -36,7 +36,7 @@ export abstract class WasmCommandRunner implements ICommandRunner {
thisProgram: cmdName,
noInitialRun: true,
print: (text: string) => stdout.write(`${text}\n`),
printErr: (text: string) => stdout.write(`${text}\n`), // Should be stderr
printErr: (text: string) => stderr.write(`${text}\n`),
preRun: (module: any) => {
if (Object.prototype.hasOwnProperty.call(module, 'FS')) {
// Use PROXYFS so that command sees the shared FS.
Expand Down
4 changes: 3 additions & 1 deletion src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ export class Context {
readonly environment: Environment,
readonly history: History,
readonly stdin: IInput,
readonly stdout: IOutput
readonly stdout: IOutput,
readonly stderr: IOutput
) {}

async flush(): Promise<void> {
await this.stderr.flush();
await this.stdout.flush();
}
}
17 changes: 12 additions & 5 deletions src/io/terminal_output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,29 @@ import { IOutputCallback } from '../callback';
export class TerminalOutput extends BufferedOutput {
// Needs to know if supports terminal escape codes.

constructor(outputCallback: IOutputCallback) {
constructor(
readonly outputCallback: IOutputCallback,
readonly prefix: string | null = null,
readonly suffix: string | null = null
) {
super();
this._outputCallback = outputCallback;
}

override async flush(): Promise<void> {
this.data.forEach(async line => await this._outputCallback(line));
this.data.forEach(async line => await this.outputCallback(line));
this.clear();
}

override async write(text: string): Promise<void> {
if (text.endsWith('\n')) {
text = text.slice(0, -1) + '\r\n';
}
if (this.prefix !== null) {
text = this.prefix + text;
}
if (this.suffix !== null) {
text = text + this.suffix;
}
await super.write(text);
}

private _outputCallback: IOutputCallback;
}
14 changes: 8 additions & 6 deletions src/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,29 +150,29 @@ export class Shell {

const stdin = new TerminalInput(this._stdinCallback);
const stdout = new TerminalOutput(this._outputCallback);
const stderr = new TerminalOutput(this._outputCallback, '\x1b[1;31m!', '\x1b[1;0m');
try {
const nodes = parse(cmdText, true, this._aliases);

for (const node of nodes) {
if (node instanceof CommandNode) {
await this._runCommand(node, stdin, stdout);
await this._runCommand(node, stdin, stdout, stderr);
} else if (node instanceof PipeNode) {
const { commands } = node;
const n = commands.length;
let prevPipe: Pipe;
for (let i = 0; i < n; i++) {
const input = i === 0 ? stdin : prevPipe!.input;
const output = i < n - 1 ? (prevPipe = new Pipe()) : stdout;
await this._runCommand(commands[i], input, output);
await this._runCommand(commands[i], input, output, stderr);
}
} else {
// This should not occur.
throw new Error(`Expected CommandNode or PipeNode not ${node}`);
}
}
} catch (error: any) {
// Send result via output?????? With color. Should be to stderr.
stdout.write('\x1b[1;31m' + error + '\x1b[1;0m\r\n');
stderr.write(error + '\r\n');
await stdout.flush();
} finally {
if (this._enableBufferedStdinCallback) {
Expand All @@ -184,7 +184,8 @@ export class Shell {
private async _runCommand(
commandNode: CommandNode,
input: IInput,
output: IOutput
output: IOutput,
error: IOutput
): Promise<void> {
const name = commandNode.name.value;
const runner = CommandRegistry.instance().get(name);
Expand Down Expand Up @@ -219,7 +220,8 @@ export class Shell {
this._environment,
this._history,
input,
output
output,
error
);
await runner.run(name, context);

Expand Down

0 comments on commit 974fc10

Please sign in to comment.