Skip to content

Commit 5831aec

Browse files
tty: add raw-vt and io raw modes
1 parent 74567b2 commit 5831aec

5 files changed

Lines changed: 92 additions & 12 deletions

File tree

doc/api/tty.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,18 @@ A `boolean` that is always `true` for `tty.ReadStream` instances.
6969

7070
<!-- YAML
7171
added: v0.7.7
72+
changes:
73+
- version: REPLACEME
74+
pr-url: https://github.com/nodejs/node/pull/REPLACEME
75+
description: The `mode` argument supports `'raw-vt'` and `'io'`.
7276
-->
7377

74-
* `mode` {boolean} If `true`, configures the `tty.ReadStream` to operate as a
75-
raw device. If `false`, configures the `tty.ReadStream` to operate in its
76-
default mode. The `readStream.isRaw` property will be set to the resulting
77-
mode.
78+
* `mode` {boolean|string} If `true` or `'raw-vt'`, configures the
79+
`tty.ReadStream` to operate as a raw device. If `'io'`, configures the
80+
`tty.ReadStream` to operate in binary-safe I/O mode. If `false`, configures
81+
the `tty.ReadStream` to operate in its default mode. The `readStream.isRaw`
82+
property will be set to whether the stream is in raw mode, and the
83+
`readStream.rawMode` property will be set to the resulting mode.
7884
* Returns: {this} The read stream instance.
7985

8086
Allows configuration of `tty.ReadStream` so that it operates as a raw device.
@@ -86,6 +92,22 @@ characters. <kbd>Ctrl</kbd>+<kbd>C</kbd> will no longer cause a `SIGINT` when
8692
in this mode. This mode does not affect terminal output processing, such as
8793
newline translation on Unix terminals.
8894

95+
When in binary-safe I/O mode, terminal output processing is also disabled.
96+
This corresponds to libuv's `UV_TTY_MODE_IO` mode and is not supported on
97+
Windows.
98+
99+
### `readStream.rawMode`
100+
101+
<!-- YAML
102+
added: REPLACEME
103+
-->
104+
105+
* {boolean|string}
106+
107+
The current raw mode for the `tty.ReadStream`. This is `false` when the stream
108+
is in its default mode, `'raw-vt'` when raw input mode is enabled, and `'io'`
109+
when binary-safe I/O mode is enabled.
110+
89111
## Class: `tty.WriteStream`
90112

91113
<!-- YAML

lib/tty.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ const {
2727
} = primordials;
2828

2929
const net = require('net');
30-
const { TTY, isTTY } = internalBinding('tty_wrap');
30+
const {
31+
TTY,
32+
UV_TTY_MODE_IO,
33+
UV_TTY_MODE_NORMAL,
34+
UV_TTY_MODE_RAW_VT,
35+
isTTY,
36+
} = internalBinding('tty_wrap');
3137
const {
3238
ErrnoException,
3339
codes: {
@@ -68,20 +74,28 @@ function ReadStream(fd, options) {
6874
});
6975

7076
this.isRaw = false;
77+
this.rawMode = false;
7178
this.isTTY = true;
7279
}
7380

7481
ObjectSetPrototypeOf(ReadStream.prototype, net.Socket.prototype);
7582
ObjectSetPrototypeOf(ReadStream, net.Socket);
7683

77-
ReadStream.prototype.setRawMode = function(flag) {
78-
flag = !!flag;
79-
const err = this._handle?.setRawMode(flag);
84+
ReadStream.prototype.setRawMode = function(mode) {
85+
const rawMode = mode === 'io' ? 'io' : (mode ? 'raw-vt' : false);
86+
let ttyMode = UV_TTY_MODE_NORMAL;
87+
if (rawMode === 'io') {
88+
ttyMode = UV_TTY_MODE_IO;
89+
} else if (rawMode === 'raw-vt') {
90+
ttyMode = UV_TTY_MODE_RAW_VT;
91+
}
92+
const err = this._handle?.setRawMode(ttyMode);
8093
if (err) {
8194
this.emit('error', new ErrnoException(err, 'setRawMode'));
8295
return this;
8396
}
84-
this.isRaw = flag;
97+
this.isRaw = rawMode !== false;
98+
this.rawMode = rawMode;
8599
return this;
86100
};
87101

src/tty_wrap.cc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ void TTYWrap::Initialize(Local<Object> target,
6868
SetProtoMethod(isolate, t, "setRawMode", SetRawMode);
6969

7070
SetMethodNoSideEffect(context, target, "isTTY", IsTTY);
71+
NODE_DEFINE_CONSTANT(target, UV_TTY_MODE_NORMAL);
72+
NODE_DEFINE_CONSTANT(target, UV_TTY_MODE_IO);
73+
NODE_DEFINE_CONSTANT(target, UV_TTY_MODE_RAW_VT);
7174

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use strict';
2+
require('../common');
3+
const assert = require('assert');
4+
const { spawnSync } = require('child_process');
5+
6+
function isOnlcrEnabled() {
7+
const { stdout, status } = spawnSync('stty', ['-a'], {
8+
encoding: 'utf8',
9+
stdio: ['inherit', 'pipe', 'inherit'],
10+
});
11+
12+
assert.strictEqual(status, 0);
13+
return /(?:^|[\s;])onlcr(?:[\s;]|$)/.test(stdout);
14+
}
15+
16+
process.stdin.setRawMode(true);
17+
console.log(`raw=${isOnlcrEnabled()}`);
18+
assert.strictEqual(process.stdin.isRaw, true);
19+
assert.strictEqual(process.stdin.rawMode, 'raw-vt');
20+
21+
process.stdin.setRawMode(false);
22+
console.log(`normal=${process.stdin.isRaw}`);
23+
assert.strictEqual(process.stdin.rawMode, false);
24+
25+
process.stdin.setRawMode('raw-vt');
26+
console.log(`raw-vt=${isOnlcrEnabled()}`);
27+
assert.strictEqual(process.stdin.isRaw, true);
28+
assert.strictEqual(process.stdin.rawMode, 'raw-vt');
29+
30+
process.stdin.setRawMode(false);
31+
process.stdin.setRawMode('io');
32+
console.log(`io=${isOnlcrEnabled()}`);
33+
assert.strictEqual(process.stdin.isRaw, true);
34+
assert.strictEqual(process.stdin.rawMode, 'io');
35+
36+
process.stdin.setRawMode(false);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
raw=true
2+
normal=false
3+
raw-vt=true
4+
io=false

0 commit comments

Comments
 (0)