diff --git a/src/buffered_io.ts b/src/buffered_io.ts index 301318c..2e8000a 100644 --- a/src/buffered_io.ts +++ b/src/buffered_io.ts @@ -1,5 +1,5 @@ import { IOutputCallback } from './callback'; -import { OutputFlag, Termios } from './termios'; +import { InputFlag, LocalFlag, OutputFlag, Termios } from './termios'; /** * Classes to deal with buffered IO between main worker and web worker. Both have access to the same @@ -280,13 +280,15 @@ export class WorkerBufferedIO extends BufferedIO { read(): number[] { Atomics.wait(this._readArray, READ_MAIN, this._readCount); - const ret = this._loadFromSharedArrayBuffer(); + const read = this._loadFromSharedArrayBuffer(); this._readCount++; // Notify main worker that character has been read and a new one can be stored. Atomics.store(this._readArray, READ_WORKER, this._readCount); Atomics.notify(this._readArray, READ_WORKER, 1); + const ret = this._processReadChars(read); + this._maybeEchoToOutput(ret); return ret; } @@ -318,6 +320,66 @@ export class WorkerBufferedIO extends BufferedIO { } } + _maybeEchoToOutput(chars: number[]): void { + const NL = 10; // Linefeed \n + const echo = (this.termios.c_lflag & LocalFlag.ECHO) > 0; + const echoNL = (this.termios.c_lflag & LocalFlag.ECHONL) > 0; + if (!echo && !echoNL) { + return; + } + + const ret: number[] = []; + for (const char of chars) { + switch (char) { + case NL: + ret.push(NL); + break; + case 4: + break; + default: + if (echo) { + ret.push(char); + } + break; + } + } + + if (ret.length > 0) { + this.write(ret); + } + } + + private _processReadChars(chars: number[]): number[] { + const NL = 10; // Linefeed \n + const CR = 13; // Carriage return \r + + const ret: number[] = []; + for (const char of chars) { + switch (char) { + case CR: + if ((this.termios.c_iflag & InputFlag.IGNCR) === 0) { + if ((this.termios.c_iflag & InputFlag.ICRNL) > 0) { + ret.push(NL); + } else { + ret.push(CR); + } + } + break; + case NL: + if ((this.termios.c_iflag & InputFlag.INLCR) > 0) { + ret.push(CR); + } else { + ret.push(NL); + } + break; + default: + ret.push(char); + break; + } + } + return ret; + } + private _processWriteChars(chars: Int8Array | number[]): number[] { const NL = 10; // Linefeed \n const CR = 13; // Carriage return \r diff --git a/src/commands/wasm_command_runner.ts b/src/commands/wasm_command_runner.ts index 75b2560..ee5d603 100644 --- a/src/commands/wasm_command_runner.ts +++ b/src/commands/wasm_command_runner.ts @@ -32,16 +32,6 @@ export abstract class WasmCommandRunner implements ICommandRunner { _getCharBuffer = utf16codes.slice(1); } - if (stdin.isTerminal()) { - if (utf16 === 10) { - context.stdout.write('\n'); - context.stdout.flush(); - } else if (utf16 > 31 && utf16 !== 127) { - context.stdout.write(String.fromCharCode(...utf16codes)); - context.stdout.flush(); - } - } - // What to do with length other than 1? if (utf16 === 4) { // EOT diff --git a/test/tests/shell.test.ts b/test/tests/shell.test.ts index c02547e..d433e4f 100644 --- a/test/tests/shell.test.ts +++ b/test/tests/shell.test.ts @@ -90,7 +90,7 @@ test.describe('Shell', () => { ]); return output.text; }); - expect(output).toMatch(/^wc\r\nab {6}0 {7}1 {7}5\r\n/); + expect(output).toMatch('wc\r\na\x1B[Bb 0 1 5\r\n'); }); test('should support terminal stdin more than once', async ({ page }) => {