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();
|
||||
```
|
||||
|
||||
* 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
|
||||
var readlineSync = require('readline-sync');
|
||||
|
|
|
@ -53,7 +53,7 @@ var
|
|||
|
||||
if (!options.noEchoBack && !options.keyIn) {
|
||||
if (options.display !== '') { writeTTY(options.display); }
|
||||
input = readByCS();
|
||||
input = readByFSO();
|
||||
} else if (options.noEchoBack && !options.keyIn && options.mask === '*') {
|
||||
if (options.display !== '') { writeTTY(options.display); }
|
||||
input = readByPW();
|
||||
|
@ -77,7 +77,7 @@ function writeTTY(text) {
|
|||
}
|
||||
}
|
||||
|
||||
function readByCS() {
|
||||
function readByFSO() {
|
||||
var text;
|
||||
try {
|
||||
text = getFso().OpenTextFile('CONIN$', FSO_ForReading).ReadLine();
|
||||
|
|
|
@ -33,7 +33,7 @@ if ($options.encoded) {
|
|||
|
||||
[string] $inputTTY = ''
|
||||
[bool] $isInputLine = $False
|
||||
[bool] $isEditable = (-not $options.noEchoBack) -and (-not $options.keyIn)
|
||||
[bool] $isCooked = (-not $options.noEchoBack) -and (-not $options.keyIn)
|
||||
|
||||
function writeTTY ($text) {
|
||||
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 }
|
||||
else { $reqSize = 1024 } # dummy
|
||||
|
||||
while ($True) {
|
||||
if ($isEditable) {
|
||||
if ($isCooked) {
|
||||
$chunk = execWithTTY 'Read-Host' $True
|
||||
$chunk += "`n"
|
||||
} else { # raw
|
||||
|
@ -82,7 +81,7 @@ while ($True) {
|
|||
$chunk = $chunk -replace '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', ''
|
||||
if ($chunk -eq '') { continue }
|
||||
|
||||
if (-not $isEditable) {
|
||||
if (-not $isCooked) {
|
||||
$displayTmp = $chunk -replace '[\r\n]', ''
|
||||
if ($displayTmp -ne '') {
|
||||
if ($options.noEchoBack) {
|
||||
|
@ -98,7 +97,7 @@ while ($True) {
|
|||
($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
|
||||
|
||||
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)
|
||||
while [ $# -ge 1 ]; do
|
||||
case "$1" in
|
||||
"--noechoback") noechoback=1;;
|
||||
"--keyin") keyin=1;;
|
||||
"--display") shift; display=$1;;
|
||||
arg="$(printf '%s' "$1" | grep -E '^-+[^-]+$' | tr '[A-Z]' '[a-z]' | tr -d '-')"
|
||||
case "$arg" in
|
||||
'display') shift; options_display="$1";;
|
||||
'noechoback') options_noEchoBack='true';;
|
||||
'mask') shift; options_mask="$1";;
|
||||
'keyin') options_keyIn='true';;
|
||||
'encoded') options_encoded='true';;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ -n "$display" ]; then
|
||||
printf '%s' "$display" >/dev/tty
|
||||
reset_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
|
||||
|
||||
if [ "$noechoback" = "1" ]; then
|
||||
# Try `-s` option. *ksh have it that not `--silent`. Therefore, don't try it.
|
||||
if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then
|
||||
IFS= read -rs input </dev/tty 2>/dev/null && printf '\n' >/dev/tty || read_s
|
||||
else
|
||||
read_s
|
||||
fi
|
||||
if [ -n "$is_cooked" ]; then
|
||||
stty --file=/dev/tty cooked 2>/dev/null || \
|
||||
stty -F /dev/tty cooked 2>/dev/null || \
|
||||
stty -f /dev/tty cooked || exit $?
|
||||
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
|
||||
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
|
||||
|
|
|
@ -114,8 +114,8 @@ function readlineSync(options) {
|
|||
{ print(options.display, encoding); }
|
||||
|
||||
(function() { // try read
|
||||
var buffer, reqSize, readSize, chunk, isInputLine = false,
|
||||
isEditable = !options.noEchoBack && !options.keyIn;
|
||||
var buffer, reqSize, readSize, chunk, isEol, isInputLine = false, line,
|
||||
isCooked = !options.noEchoBack && !options.keyIn;
|
||||
|
||||
function writeTTY(text) {
|
||||
fs.writeSync(fdW, text);
|
||||
|
@ -131,7 +131,7 @@ function readlineSync(options) {
|
|||
}
|
||||
|
||||
if (useExt || !ttyR ||
|
||||
typeof fdW !== 'number' && (options.display !== '' || !isEditable)) {
|
||||
typeof fdW !== 'number' && (options.display !== '' || !isCooked)) {
|
||||
input = tryExt();
|
||||
return;
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ function readlineSync(options) {
|
|||
options.display = '';
|
||||
}
|
||||
|
||||
if (!setRawMode(!isEditable)) {
|
||||
if (!setRawMode(!isCooked)) {
|
||||
input = tryExt();
|
||||
return;
|
||||
}
|
||||
|
@ -149,36 +149,41 @@ function readlineSync(options) {
|
|||
|
||||
while (true) {
|
||||
readSize = 0;
|
||||
|
||||
try {
|
||||
readSize = fs.readSync(fdR, buffer, 0, reqSize);
|
||||
} catch (e) {
|
||||
if (e.code === 'EOF') { break; }
|
||||
if (e.code !== 'EOF') {
|
||||
setRawMode(false);
|
||||
input += tryExt();
|
||||
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;
|
||||
if (/[\r\n]$/.test(input) ||
|
||||
options.keyIn && input.length >= reqSize) { break; }
|
||||
if (isEol || options.keyIn && input.length >= reqSize) { break; }
|
||||
}
|
||||
|
||||
if (!isEditable && !(options.keyIn && !isInputLine)) { writeTTY('\n'); }
|
||||
if (!isCooked && !(options.keyIn && !isInputLine)) { writeTTY('\n'); }
|
||||
setRawMode(false);
|
||||
})();
|
||||
|
||||
|
|
Loading…
Reference in a new issue