rewrite read.sh
This commit is contained in:
parent
16db4b4c1c
commit
5f2410132b
5 changed files with 114 additions and 54 deletions
|
@ -101,7 +101,7 @@ readlineSync.setPrompt(chalk.red.bold('> '));
|
||||||
command = readlineSync.prompt();
|
command = readlineSync.prompt();
|
||||||
```
|
```
|
||||||
|
|
||||||
* When you do the redirecting that like `node yourscript.js > foo.log` to record into a file, this is used to output conversation to the file. That is, the conversation isn't outputted to `foo.log` without this code.
|
* When you do the redirecting that like `your-script > foo.log` to record into a file, this is used to output conversation to the file. That is, the conversation isn't outputted to `foo.log` without this code.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var readlineSync = require('readline-sync');
|
var readlineSync = require('readline-sync');
|
||||||
|
|
|
@ -53,7 +53,7 @@ var
|
||||||
|
|
||||||
if (!options.noEchoBack && !options.keyIn) {
|
if (!options.noEchoBack && !options.keyIn) {
|
||||||
if (options.display !== '') { writeTTY(options.display); }
|
if (options.display !== '') { writeTTY(options.display); }
|
||||||
input = readByCS();
|
input = readByFSO();
|
||||||
} else if (options.noEchoBack && !options.keyIn && options.mask === '*') {
|
} else if (options.noEchoBack && !options.keyIn && options.mask === '*') {
|
||||||
if (options.display !== '') { writeTTY(options.display); }
|
if (options.display !== '') { writeTTY(options.display); }
|
||||||
input = readByPW();
|
input = readByPW();
|
||||||
|
@ -77,7 +77,7 @@ function writeTTY(text) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function readByCS() {
|
function readByFSO() {
|
||||||
var text;
|
var text;
|
||||||
try {
|
try {
|
||||||
text = getFso().OpenTextFile('CONIN$', FSO_ForReading).ReadLine();
|
text = getFso().OpenTextFile('CONIN$', FSO_ForReading).ReadLine();
|
||||||
|
|
|
@ -33,7 +33,7 @@ if ($options.encoded) {
|
||||||
|
|
||||||
[string] $inputTTY = ''
|
[string] $inputTTY = ''
|
||||||
[bool] $isInputLine = $False
|
[bool] $isInputLine = $False
|
||||||
[bool] $isEditable = (-not $options.noEchoBack) -and (-not $options.keyIn)
|
[bool] $isCooked = (-not $options.noEchoBack) -and (-not $options.keyIn)
|
||||||
|
|
||||||
function writeTTY ($text) {
|
function writeTTY ($text) {
|
||||||
execWithTTY ('Write-Host ''' + ($text -replace '''', '''''') + ''' -NoNewline')
|
execWithTTY ('Write-Host ''' + ($text -replace '''', '''''') + ''' -NoNewline')
|
||||||
|
@ -67,10 +67,9 @@ if ($options.noEchoBack -and (-not $options.keyIn) -and ($options.mask -eq '*'))
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($options.keyIn) { $reqSize = 1 }
|
if ($options.keyIn) { $reqSize = 1 }
|
||||||
else { $reqSize = 1024 } # dummy
|
|
||||||
|
|
||||||
while ($True) {
|
while ($True) {
|
||||||
if ($isEditable) {
|
if ($isCooked) {
|
||||||
$chunk = execWithTTY 'Read-Host' $True
|
$chunk = execWithTTY 'Read-Host' $True
|
||||||
$chunk += "`n"
|
$chunk += "`n"
|
||||||
} else { # raw
|
} else { # raw
|
||||||
|
@ -82,7 +81,7 @@ while ($True) {
|
||||||
$chunk = $chunk -replace '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', ''
|
$chunk = $chunk -replace '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', ''
|
||||||
if ($chunk -eq '') { continue }
|
if ($chunk -eq '') { continue }
|
||||||
|
|
||||||
if (-not $isEditable) {
|
if (-not $isCooked) {
|
||||||
$displayTmp = $chunk -replace '[\r\n]', ''
|
$displayTmp = $chunk -replace '[\r\n]', ''
|
||||||
if ($displayTmp -ne '') {
|
if ($displayTmp -ne '') {
|
||||||
if ($options.noEchoBack) {
|
if ($options.noEchoBack) {
|
||||||
|
@ -98,7 +97,7 @@ while ($True) {
|
||||||
($options.keyIn -and ($inputTTY.Length -ge $reqSize))) { break }
|
($options.keyIn -and ($inputTTY.Length -ge $reqSize))) { break }
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((-not $isEditable) -and (-not ($options.keyIn -and (-not $isInputLine))))
|
if ((-not $isCooked) -and (-not ($options.keyIn -and (-not $isInputLine))))
|
||||||
{ execWithTTY 'Write-Host ''''' } # new line
|
{ execWithTTY 'Write-Host ''''' } # new line
|
||||||
|
|
||||||
return '''' + $inputTTY + ''''
|
return '''' + $inputTTY + ''''
|
||||||
|
|
106
lib/read.sh
106
lib/read.sh
|
@ -1,38 +1,94 @@
|
||||||
# Silent Read : emulate `read -s` of bash/zsh
|
|
||||||
read_s() {
|
|
||||||
stty --file=/dev/tty -echo echonl 2>/dev/null || \
|
|
||||||
stty -F /dev/tty -echo echonl 2>/dev/null || \
|
|
||||||
stty -f /dev/tty -echo echonl || exit 1
|
|
||||||
IFS= read -r input </dev/tty || exit 1
|
|
||||||
stty --file=/dev/tty echo -echonl 2>/dev/null || \
|
|
||||||
stty -F /dev/tty echo -echonl 2>/dev/null || \
|
|
||||||
stty -f /dev/tty echo -echonl || exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# getopt(s)
|
# getopt(s)
|
||||||
while [ $# -ge 1 ]; do
|
while [ $# -ge 1 ]; do
|
||||||
case "$1" in
|
arg="$(printf '%s' "$1" | grep -E '^-+[^-]+$' | tr '[A-Z]' '[a-z]' | tr -d '-')"
|
||||||
"--noechoback") noechoback=1;;
|
case "$arg" in
|
||||||
"--keyin") keyin=1;;
|
'display') shift; options_display="$1";;
|
||||||
"--display") shift; display=$1;;
|
'noechoback') options_noEchoBack='true';;
|
||||||
|
'mask') shift; options_mask="$1";;
|
||||||
|
'keyin') options_keyIn='true';;
|
||||||
|
'encoded') options_encoded='true';;
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ -n "$display" ]; then
|
reset_tty() {
|
||||||
printf '%s' "$display" >/dev/tty
|
if [ -n "$save_tty" ]; then stty "$save_tty"; fi
|
||||||
|
}
|
||||||
|
trap 'reset_tty' EXIT
|
||||||
|
save_tty="$(stty -g)"
|
||||||
|
|
||||||
|
write_tty() { # 2nd arg: enable escape sequence
|
||||||
|
if [ -n "$2" ]; then
|
||||||
|
printf '%b' "$1" >/dev/tty
|
||||||
|
else
|
||||||
|
printf '%s' "$1" >/dev/tty
|
||||||
|
fi
|
||||||
|
is_inputline='true'
|
||||||
|
}
|
||||||
|
|
||||||
|
replace_allchars() { (
|
||||||
|
text=''
|
||||||
|
for i in $(seq 1 ${#1})
|
||||||
|
do
|
||||||
|
text="$text$2"
|
||||||
|
done
|
||||||
|
printf '%s' "$text"
|
||||||
|
) }
|
||||||
|
|
||||||
|
[ -z "$options_noEchoBack" ] && [ -z "$options_keyIn" ] && is_cooked='true'
|
||||||
|
|
||||||
|
if [ -n "$options_display" ]; then
|
||||||
|
write_tty "$options_display"
|
||||||
|
options_display=''
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$noechoback" = "1" ]; then
|
if [ -n "$is_cooked" ]; then
|
||||||
# Try `-s` option. *ksh have it that not `--silent`. Therefore, don't try it.
|
stty --file=/dev/tty cooked 2>/dev/null || \
|
||||||
if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then
|
stty -F /dev/tty cooked 2>/dev/null || \
|
||||||
IFS= read -rs input </dev/tty 2>/dev/null && printf '\n' >/dev/tty || read_s
|
stty -f /dev/tty cooked || exit $?
|
||||||
else
|
|
||||||
read_s
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
IFS= read -r input </dev/tty || exit 1
|
stty --file=/dev/tty raw -echo 2>/dev/null || \
|
||||||
|
stty -F /dev/tty raw -echo 2>/dev/null || \
|
||||||
|
stty -f /dev/tty raw -echo || exit $?
|
||||||
fi
|
fi
|
||||||
printf '%s' "'$input'"
|
|
||||||
|
[ -n "$options_keyIn" ] && req_size=1
|
||||||
|
|
||||||
|
while :
|
||||||
|
do
|
||||||
|
if [ -z "$is_cooked" ]; then
|
||||||
|
chunk="$(dd if=/dev/tty bs=1 count=1 2>/dev/null)"
|
||||||
|
chunk="$(printf '%s' "$chunk" | tr -d '\r\n')"
|
||||||
|
[ -z "$chunk" ] && is_eol='true' # NL or empty-text was input
|
||||||
|
else
|
||||||
|
IFS= read -r chunk </dev/tty || exit $?
|
||||||
|
chunk="$(printf '%s' "$chunk" | tr -d '\r\n')"
|
||||||
|
is_eol='true'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# other ctrl-chars
|
||||||
|
# chunk="$(printf '%s' "$chunk" | tr -d '\00-\10\13\14\16-\37\177')"
|
||||||
|
# for System V
|
||||||
|
chunk="$(printf '%s' "$chunk" | tr -d '\00\01\02\03\04\05\06\07\10\13\14\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177')"
|
||||||
|
|
||||||
|
if [ -n "$chunk" ] && [ -z "$is_cooked" ]; then
|
||||||
|
if [ -z "$options_noEchoBack" ]; then
|
||||||
|
write_tty "$chunk"
|
||||||
|
elif [ -n "$options_mask" ]; then
|
||||||
|
write_tty "$(replace_allchars "$chunk" "$options_mask")"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
input="$input$chunk"
|
||||||
|
if [ -n "$is_eol" ] || \
|
||||||
|
( [ -n "$options_keyIn" ] && [ ${#input} -ge $req_size ] ); then break; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$is_cooked" ] && ! ( [ -n "$options_keyIn" ] && [ -z "$is_inputline" ] ); then
|
||||||
|
write_tty '\r\n' 'true'
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "'%s'" "$input"
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
@ -114,8 +114,8 @@ function readlineSync(options) {
|
||||||
{ print(options.display, encoding); }
|
{ print(options.display, encoding); }
|
||||||
|
|
||||||
(function() { // try read
|
(function() { // try read
|
||||||
var buffer, reqSize, readSize, chunk, isInputLine = false,
|
var buffer, reqSize, readSize, chunk, isEol, isInputLine = false, line,
|
||||||
isEditable = !options.noEchoBack && !options.keyIn;
|
isCooked = !options.noEchoBack && !options.keyIn;
|
||||||
|
|
||||||
function writeTTY(text) {
|
function writeTTY(text) {
|
||||||
fs.writeSync(fdW, text);
|
fs.writeSync(fdW, text);
|
||||||
|
@ -131,7 +131,7 @@ function readlineSync(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useExt || !ttyR ||
|
if (useExt || !ttyR ||
|
||||||
typeof fdW !== 'number' && (options.display !== '' || !isEditable)) {
|
typeof fdW !== 'number' && (options.display !== '' || !isCooked)) {
|
||||||
input = tryExt();
|
input = tryExt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ function readlineSync(options) {
|
||||||
options.display = '';
|
options.display = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!setRawMode(!isEditable)) {
|
if (!setRawMode(!isCooked)) {
|
||||||
input = tryExt();
|
input = tryExt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -149,36 +149,41 @@ function readlineSync(options) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
readSize = 0;
|
readSize = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
readSize = fs.readSync(fdR, buffer, 0, reqSize);
|
readSize = fs.readSync(fdR, buffer, 0, reqSize);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.code === 'EOF') { break; }
|
if (e.code !== 'EOF') {
|
||||||
setRawMode(false);
|
setRawMode(false);
|
||||||
input += tryExt();
|
input += tryExt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readSize === 0) { break; }
|
|
||||||
chunk = buffer.toString(encoding, 0, readSize);
|
|
||||||
// other ctrl-chars
|
|
||||||
if ((chunk = chunk.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '')) === '')
|
|
||||||
{ continue; }
|
|
||||||
|
|
||||||
if (!isEditable && (displayTmp = chunk.replace(/[\r\n]/g, '')) !== '') {
|
|
||||||
if (options.noEchoBack) {
|
|
||||||
displayTmp = options.mask === '' ? '' :
|
|
||||||
(new Array(displayTmp.length + 1)).join(options.mask);
|
|
||||||
}
|
}
|
||||||
if (displayTmp !== '') { writeTTY(displayTmp); }
|
chunk = readSize > 0 ? buffer.toString(encoding, 0, readSize) : '\n';
|
||||||
|
|
||||||
|
if (!isCooked) {
|
||||||
|
chunk = chunk.replace(/[\r\n]/g, '');
|
||||||
|
if (chunk === '') { isEol = true; } // NL or empty-text was input
|
||||||
|
} else if (typeof(line = (chunk.match(/^(.*?)[\r\n]/) || [])[1]) === 'string') {
|
||||||
|
chunk = line;
|
||||||
|
isEol = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// other ctrl-chars
|
||||||
|
chunk = chunk.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '');
|
||||||
|
|
||||||
|
if (chunk !== '' && !isCooked) {
|
||||||
|
if (!options.noEchoBack) {
|
||||||
|
writeTTY(chunk);
|
||||||
|
} else if (options.mask !== '') {
|
||||||
|
writeTTY((new Array(chunk.length + 1)).join(options.mask));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input += chunk;
|
input += chunk;
|
||||||
if (/[\r\n]$/.test(input) ||
|
if (isEol || options.keyIn && input.length >= reqSize) { break; }
|
||||||
options.keyIn && input.length >= reqSize) { break; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isEditable && !(options.keyIn && !isInputLine)) { writeTTY('\n'); }
|
if (!isCooked && !(options.keyIn && !isInputLine)) { writeTTY('\n'); }
|
||||||
setRawMode(false);
|
setRawMode(false);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue