elvish icon indicating copy to clipboard operation
elvish copied to clipboard

Reading user input without echo

Open aka-mj opened this issue 3 years ago • 7 comments

I'm looking if elvish support the bash equivalent read -s password. Currently I have the following but it echos what is typed to the console

var password = (read-line)

If an equivalent doesn't exist maybe something like read-password or read-line &echo=$false?

aka-mj avatar Jan 06 '22 16:01 aka-mj

For what it's worth, here is what I use:

fn prompt {|prompt &tty=/dev/tty| print $prompt >$tty; read-line <$tty }

fn with-stty {|@args cmd~ &tty=/dev/tty|
  var orig = (stty -g <$tty)
  try { stty $@args <$tty; cmd } finally { stty $orig <$tty }
}

Then I can run, say,

with-stty -echo { prompt 'Enter password: ' } | var pw = (one)

I have absolutely no idea if this will work on windows, though. (And to be honest, I have never used the &tty option in either of the two functions above.)

hanche avatar Jan 06 '22 18:01 hanche

I was going to post a solution similar to @hanche's but he beat me to it. Whether this functionality should be builtin depends on how practical it is to implement it in a cross-platform manner.

krader1961 avatar Jan 06 '22 20:01 krader1961

@hanche's solution has another problem. If you ctrl+c out while in the prompt, the tty is never restored and echo remains off.

stephenmw avatar Jan 15 '24 02:01 stephenmw

@hanche's solution has another problem. If you ctrl+c out while in the prompt, the tty is never restored and echo remains off.

I can't reproduce that on macOS. on macOS the try...finally... does restore the stty mode. However, after pressing Ctrl-C I still have to press Enter -- which is probably also a bug as you would expect the Ctrl-C to terminate the read-line command.

krader1961 avatar Jan 15 '24 03:01 krader1961

I am also on macos. I was incorrect. Ctrl-C does indeed not work.

This is kinda awkward and I didn't realize it until you pointed it out. After Ctrl-C didn't work, I immediately did a Ctrl-D out of reflex... every time I tried this. If you do Ctrl-C followed by Ctrl-D you get an exception where the echo is never restored:

$ ./tmp.elv
Password: Exception: interrupted
Traceback:
  /Users/stephenmw/tmp.elv:7:44:
      try { stty $@args <$tty; cmd } finally { stty $orig <$tty }
  /Users/stephenmw/tmp.elv:10:17:
    var password = (with-stty -echo { prompt 'Password: ' })

Code:

#!/usr/bin/env elvish

fn prompt {|prompt &tty=/dev/tty| print $prompt >$tty; read-line <$tty }

fn with-stty {|@args cmd~ &tty=/dev/tty|
  var orig = (stty -g <$tty)
  try { stty $@args <$tty; cmd } finally { stty $orig <$tty }
}

var password = (with-stty -echo { prompt 'Password: ' })
echo
echo Your password is $password

stephenmw avatar Jan 15 '24 05:01 stephenmw

I am also on macos. I was incorrect. Ctrl-C does indeed not work.

I can't parse that. Your original problem statement was that Ctrl-C does not work so I don't understand the "I was incorrect" statement. Whether I put that code in an Elvish script I run from an interactive prompt, or directly in my interactive Elvish shell, a Ctrl-C does result in the stty mode being restored. However, as I stated previously, the Ctrl-C does not immediately terminate the read-line command in either case. I have to press Enter or Ctrl-D. Which is a bug (arguably) but not the bug in your first comment that "echo remains off."

krader1961 avatar Jan 15 '24 05:01 krader1961

I'll also point out that the whole try...finally... to restore the tty modes doesn't do anything useful since the finally block isn't run when Ctrl-C is handled. See https://github.com/elves/elvish/issues/954. The reason the tty modes are restored is due to how Elvish currently handles tty modes. See https://github.com/elves/elvish/issues/732. The tty modes are always "restored" before the next prompt is emitted regardless of any changes done by an stty command.

krader1961 avatar Jan 15 '24 05:01 krader1961