niim
Version:
Node Inspect IMproved
178 lines (166 loc) • 5.88 kB
JavaScript
const process = require('process');
const fs = require('fs');
let leftover = false;
let testObject = { hello: 'world' };
/** Read a line of input from stdin, one character at a time. Standard UNIX terminal line
* discipline is emulated. Input characters may be ASCII or UTF-8.
*
* @param {string} echoChar The charater to echo when a key is pressed. When
* undefined, nothing is echoed. When true, the input
* character is (more or less) echoed back. More or
* less because, rather than typical full-duplex terminal
* emulation that echoes the exact input, in our case
* the input is converted from UTF-8 to UTF-16 for output.
* @param {number} bufSize An optional parameter to specify the buffer size.
* A large (256-byte?) buffer will perform will when reading
* large amounts of data, however the 1-byte default
* will prevent this code from consuming extra data from
* the stdin stream.
* @returns {string} UTF-16 representation of input. Newline is discarded. Invalid
* input could yield unpaired surrogates in the output.
*
* @note Known Bugs - when using echoChar = true, there will be display bugs for
* erase and kill when dealing with codepoints outside of the BMP, as well as
* unpaired surrogates.
*/
function raw_readln(echoChar, bufSize) {
var chBuf = Buffer.alloc(bufSize || 1);
var buf = '';
var utf8Buf;
if (process.stdin.setRawMode)
process.stdin.setRawMode(true);
try {
while(true) {
let ch;
try {
if (!leftover) {
nRead = fs.readSync(process.stdin.fd, chBuf, 0, chBuf.length);
} else {
leftover.copy(chBuf);
nRead = leftover.length;
leftover = false;
}
} catch (e) {
switch(e.code) {
case 'EAGAIN':
nRead = 0
break
case 'EOF':
nRead = -1
break
default:
throw e
}
}
if (nRead < 0)
return null /* input stream is closed */
if (nRead == 0) { /* nothing to read - give up timeslice */
nap();
continue;
}
for (let pos=0; pos < nRead; pos++) {
ch = chBuf[pos];
if (ch >= 0xc2) { /* start of utf-8 sequence */
if (ch >= 0xc2 && ch <= 0xdf)
utf8Buf = Buffer.alloc(2);
if (ch >= 0xe0 && ch <= 0xef)
utf8Buf = Buffer.alloc(3);
if (ch >= 0xf0 && ch <= 0xff)
utf8Buf = Buffer.alloc(4);
utf8Buf[0] = ch;
utf8Pos = 1;
continue;
}
if (ch >= 0x80 && ch <= 0xbf) { /* part of utf-8 sequence */
utf8Buf[utf8Pos++] = ch;
}
if (utf8Buf) {
if (utf8Pos !== utf8Buf.length) {
continue;
} else { /* final byte of utf-8 sequence */
switch(utf8Buf.length) {
case 4:
codepoint = utf8Buf[0] & 0b00011111;
break;
case 3:
codepoint = utf8Buf[0] & 0b00001111;
break;
case 2:
codepoint = utf8Buf[0] & 0b00000111;
break;
}
codepoint = codepoint << ((4 - utf8Buf.length) * 8);
utf8Buf = false;
//XXX console.log(codepoint.toString(16));
}
} else {
codepoint = ch; /* ascii */
}
ch = undefined; /* From here down, we use the Unicode codepoint */
/* Emulate typical UNIX terminal behaviour wrt control codes */
switch(codepoint) {
case 3:
// process.kill(process.pid, 'SIGINT');
console.log('NOT DOING SIGINT');
continue;
case 8: case 127:
buf = buf.slice(0,-1);
if (echoChar)
process.stdout.write(Buffer.from([8,32,32,8,8]));
continue;
case 4:
if (buf.length)
break;
case 10: case 13:
if (nRead - pos != 0) {
leftover = chBuf.slice(pos + 1)
}
return buf;
case 28:
process.kill(process.pid, 'SIGQUIT');
continue;
case 21:
for (let i=0; i < buf.length; i++) {
if (buf.charCodeAt(i) >= 0xd800 && buf.charCodeAt(i) < 0xdc00)
continue;
process.stdout.write(Buffer.from([8,32,8]));
}
buf = '';
continue;
default:
if (codepoint < 32)
continue;
}
buf += String.fromCodePoint(codepoint);
if (echoChar) {
if (echoChar === true)
process.stdout.write(Buffer.from(String.fromCodePoint(codepoint)));
else
process.stdout.write(Buffer.from(echoChar));
}
}
}
}
finally {
if (process.stdin.setRawMode) {
process.stdout.write(Buffer.from([13]));
if (echoChar)
process.stdout.write(Buffer.from([10]));
process.stdin.setRawMode(false);
}
}
}
/** Take a short nap - should cue the scheduler to take what's left of our timeslice.*/
function nap() {
let sab = new SharedArrayBuffer(4);
let int32 = new Int32Array(sab);
Atomics.wait(int32, 0, 0, 125/2); /* 125ms = 100wpm */
}
console.log('The next data will be a prompt with no newline');
process.stdout.write('please type your password: ');
let password = raw_readln('*');
console.log('You typed:', password);
process.stdout.write('please type your password again: ');
password = raw_readln('*');
console.log('You typed:', password);