Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions doc/api/tty.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,18 @@

<!-- YAML
added: v0.7.7
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/REPLACEME

Check warning on line 74 in doc/api/tty.md

View workflow job for this annotation

GitHub Actions / lint-pr-url

pr-url doesn't match the URL of the current PR.
description: The `mode` argument supports `'raw-vt'` and `'io'`.
-->

* `mode` {boolean} If `true`, configures the `tty.ReadStream` to operate as a
raw device. If `false`, configures the `tty.ReadStream` to operate in its
default mode. The `readStream.isRaw` property will be set to the resulting
mode.
* `mode` {boolean|string} If `true` or `'raw-vt'`, configures the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not use 'raw-vt' as a name and instead just use 'raw'. UV_TTY_MODE_RAW_VT is what UV_TTY_MODE_RAW should probably have been all along – the only reason they aren't merged (yet) into a single constant is backwards compatibility expectations in libuv.

`tty.ReadStream` to operate as a raw device. If `'io'`, configures the
`tty.ReadStream` to operate in binary-safe I/O mode. If `false`, configures
the `tty.ReadStream` to operate in its default mode. The `readStream.isRaw`
property will be set to whether the stream is in raw mode, and the
`readStream.rawMode` property will be set to the resulting mode.
* Returns: {this} The read stream instance.

Allows configuration of `tty.ReadStream` so that it operates as a raw device.
Expand All @@ -86,6 +92,22 @@
in this mode. This mode does not affect terminal output processing, such as
newline translation on Unix terminals.

When in binary-safe I/O mode, terminal output processing is also disabled.
This corresponds to libuv's `UV_TTY_MODE_IO` mode and is not supported on
Windows.

### `readStream.rawMode`

<!-- YAML
added: REPLACEME
-->

* {boolean|string}

The current raw mode for the `tty.ReadStream`. This is `false` when the stream
is in its default mode, `'raw-vt'` when raw input mode is enabled, and `'io'`
when binary-safe I/O mode is enabled.

## Class: `tty.WriteStream`

<!-- YAML
Expand Down
24 changes: 19 additions & 5 deletions lib/tty.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ const {
} = primordials;

const net = require('net');
const { TTY, isTTY } = internalBinding('tty_wrap');
const {
TTY,
UV_TTY_MODE_IO,
UV_TTY_MODE_NORMAL,
UV_TTY_MODE_RAW_VT,
isTTY,
} = internalBinding('tty_wrap');
const {
ErrnoException,
codes: {
Expand Down Expand Up @@ -68,20 +74,28 @@ function ReadStream(fd, options) {
});

this.isRaw = false;
this.rawMode = false;
this.isTTY = true;
}

ObjectSetPrototypeOf(ReadStream.prototype, net.Socket.prototype);
ObjectSetPrototypeOf(ReadStream, net.Socket);

ReadStream.prototype.setRawMode = function(flag) {
flag = !!flag;
const err = this._handle?.setRawMode(flag);
ReadStream.prototype.setRawMode = function(mode) {
const rawMode = mode === 'io' ? 'io' : (mode ? 'raw-vt' : false);
let ttyMode = UV_TTY_MODE_NORMAL;
if (rawMode === 'io') {
ttyMode = UV_TTY_MODE_IO;
} else if (rawMode === 'raw-vt') {
ttyMode = UV_TTY_MODE_RAW_VT;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we reject invalid/unrecognized values here?

const err = this._handle?.setRawMode(ttyMode);
if (err) {
this.emit('error', new ErrnoException(err, 'setRawMode'));
return this;
}
this.isRaw = flag;
this.isRaw = rawMode !== false;
this.rawMode = rawMode;
return this;
};

Expand Down
10 changes: 7 additions & 3 deletions src/tty_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ void TTYWrap::Initialize(Local<Object> target,
SetProtoMethod(isolate, t, "setRawMode", SetRawMode);

SetMethodNoSideEffect(context, target, "isTTY", IsTTY);
NODE_DEFINE_CONSTANT(target, UV_TTY_MODE_NORMAL);
NODE_DEFINE_CONSTANT(target, UV_TTY_MODE_IO);
NODE_DEFINE_CONSTANT(target, UV_TTY_MODE_RAW_VT);

Local<Value> func;
if (t->GetFunction(context).ToLocal(&func) &&
Expand Down Expand Up @@ -124,9 +127,10 @@ void TTYWrap::SetRawMode(const FunctionCallbackInfo<Value>& args) {
// sequences at all on Windows, such as bracketed paste mode.
// The Node.js readline implementation handles differences between
// these modes.
int err = uv_tty_set_mode(
&wrap->handle_,
args[0]->IsTrue() ? UV_TTY_MODE_RAW_VT : UV_TTY_MODE_NORMAL);
Environment* env = Environment::GetCurrent(args);
int mode;
if (!args[0]->Int32Value(env->context()).To(&mode)) return;
int err = uv_tty_set_mode(&wrap->handle_, static_cast<uv_tty_mode_t>(mode));
args.GetReturnValue().Set(err);
}

Expand Down
36 changes: 36 additions & 0 deletions test/pseudo-tty/test-set-raw-mode-modes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';
require('../common');
const assert = require('assert');
const { spawnSync } = require('child_process');

function isOnlcrEnabled() {
const { stdout, status } = spawnSync('stty', ['-a'], {
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'inherit'],
});

assert.strictEqual(status, 0);
return /(?:^|[\s;])onlcr(?:[\s;]|$)/.test(stdout);
}

process.stdin.setRawMode(true);
console.log(`raw=${isOnlcrEnabled()}`);
assert.strictEqual(process.stdin.isRaw, true);
assert.strictEqual(process.stdin.rawMode, 'raw-vt');

process.stdin.setRawMode(false);
console.log(`normal=${process.stdin.isRaw}`);
assert.strictEqual(process.stdin.rawMode, false);

process.stdin.setRawMode('raw-vt');
console.log(`raw-vt=${isOnlcrEnabled()}`);
assert.strictEqual(process.stdin.isRaw, true);
assert.strictEqual(process.stdin.rawMode, 'raw-vt');

process.stdin.setRawMode(false);
process.stdin.setRawMode('io');
console.log(`io=${isOnlcrEnabled()}`);
assert.strictEqual(process.stdin.isRaw, true);
assert.strictEqual(process.stdin.rawMode, 'io');

process.stdin.setRawMode(false);
4 changes: 4 additions & 0 deletions test/pseudo-tty/test-set-raw-mode-modes.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
raw=true
normal=false
raw-vt=true
io=false
Loading