diff options
Diffstat (limited to 'lib/pure/terminal.nim')
-rw-r--r-- | lib/pure/terminal.nim | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 87e4ab591..4f2f73ba7 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -736,6 +736,56 @@ proc getch*(): char = result = stdin.readChar() discard fd.tcsetattr(TCSADRAIN, addr oldMode) +when defined(windows): + from unicode import toUTF8, Rune, runeLenAt + + proc readPasswordFromStdin*(prompt: string, password: var TaintedString): + bool {.tags: [ReadIOEffect, WriteIOEffect].} = + ## Reads a `password` from stdin without printing it. `password` must not + ## be ``nil``! Returns ``false`` if the end of the file has been reached, + ## ``true`` otherwise. + password.string.setLen(0) + stdout.write(prompt) + while true: + let c = getch() + case c.char + of '\r', chr(0xA): + break + of '\b': + # ensure we delete the whole UTF-8 character: + var i = 0 + var x = 1 + while i < password.len: + x = runeLenAt(password.string, i) + inc i, x + password.string.setLen(max(password.len - x, 0)) + else: + password.string.add(toUTF8(c.Rune)) + stdout.write "\n" + +else: + import termios + + proc readPasswordFromStdin*(prompt: string, password: var TaintedString): + bool {.tags: [ReadIOEffect, WriteIOEffect].} = + password.string.setLen(0) + let fd = stdin.getFileHandle() + var cur, old: Termios + discard fd.tcgetattr(cur.addr) + old = cur + cur.c_lflag = cur.c_lflag and not Cflag(ECHO) + discard fd.tcsetattr(TCSADRAIN, cur.addr) + stdout.write prompt + result = stdin.readLine(password) + stdout.write "\n" + discard fd.tcsetattr(TCSADRAIN, old.addr) + +proc readPasswordFromStdin*(prompt = "password: "): TaintedString = + ## Reads a password from stdin without printing it. + result = TaintedString("") + discard readPasswordFromStdin(prompt, result) + + # Wrappers assuming output to stdout: template hideCursor*() = hideCursor(stdout) template showCursor*() = showCursor(stdout) |