Skip to content

Commit 4d2da3b

Browse files
committed
Use file descriptor 0 or /dev/tty to read stdin
On Linux, when Node.js (at least, v15.2.0) does a readFileSync of /dev/tty, it hangs. The addition of /dev/tty comes from 9bcf45b, which converts to ESM. It also switches from reading /dev/stdin, to: 1. on Windows, reading file descriptor 0; 2. on other platforms, reading /dev/tty (which presumably works on macOS, but not Linux). However, based on the [Node.js documentation][fd0], reading file descriptor 0 always reads stdin on all platforms, thanks to a compatibility layer in Node.js. Subtly, for Linux specifically, using /dev/stdin instead of the zero file descriptor, enables the following use-case: just enter `commonmark` on the console, causing it to wait for prompt. You can then type text followed by Control-D to have that text be the input. | File | Linux | macOS | Windows | |============|=================|=================|===========| | | Pipe | ✓ | ✓ | ✓ | | 0 |--------|-----------------|-----------------|-----------| | | Prompt | EAGAIN | EAGAIN | TypeError | |~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~|~~~~~~~~~~~| | | ✓ | ✓ | ENOENT | | /dev/stdin |-----------------|-----------------|-----------| | | ✓ | EAGAIN | ENOENT | |~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~|~~~~~~~~~~~| | | (input ignored) | (input ignored) | ENOENT | | /dev/tty |-----------------|-----------------|-----------| | | ✓ | ✓ | ENOENT | Thus we split the decision in a platform-independent way: 1. When in a TTY situation, use /dev/tty. Except on Windows, which does not have a PTY, so we manually read lines until we hit ^Z (which is EOF on Windows). 2. Otherwise, use file descriptor 0, which works across all platforms. [fd0]: https://nodejs.org/api/process.html#process_process_stdin_fd
1 parent 6d80c8e commit 4d2da3b

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

bin/commonmark

+22-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import util from "util";
55
import fs from "fs";
66
import os from "os";
7+
import readline from "readline";
78
import * as commonmark from "../lib/index.js";
89
var version = require('../package.json').version;
910
import parseArgs from "minimist";
@@ -77,11 +78,27 @@ if (format === 'html') {
7778
}
7879

7980
if (files.length === 0) {
80-
if (os.platform() === "win32") {
81-
inps.push(fs.readFileSync(0, 'utf-8'));
82-
} else {
83-
inps.push(fs.readFileSync('/dev/tty', 'utf-8'));
84-
}
81+
if (process.stdin.isTTY) {
82+
if (os.platform() === 'win32') {
83+
// Windows does not have a PTY that Node relies on.
84+
// Instead, we read lines explicitly, tracking ^Z for EOF.
85+
(async () => {
86+
const rl = readline.createInterface({ input: process.stdin });
87+
let inp = '';
88+
for await (const line of rl) {
89+
if (line === '\x1a') { break; }
90+
inp += line;
91+
}
92+
const doc = parser.parse(inp);
93+
const rendered = renderer.render(doc);
94+
if (!options.time) { process.stdout.write(rendered); }
95+
})();
96+
} else {
97+
inps.push(fs.readFileSync('/dev/tty', 'utf-8'));
98+
}
99+
} else {
100+
inps.push(fs.readFileSync(0, 'utf-8'));
101+
}
85102
} else {
86103
for (i = 0; i < files.length; i++) {
87104
var file = files[i];

0 commit comments

Comments
 (0)