Hidden
Prompt::Hidden
prompt with a :hidden adverb ā a password typed at a terminal that the
terminal never shows.
Why it exists
Raku has prompt, and it echoes. Reading a password means reaching past it:
Terminal::Getpass shells out to stty, and everyone else writes the same
half-dozen lines again. None of that is prompt, so a program that wants one
visible field and one hidden one uses two different calls with two different
signatures.
This module makes the hidden read an adverb on the call you already write:
use Prompt::Hidden;
my $user = prompt "Username: ";
my $pass = prompt "Password: ", :hidden;
prompt without :hidden is CORE::<&prompt>, forwarded capture and all ā
same message, same allomorph return, same Nil at end of input. Only
:hidden is new.
What it runs on
The same program runs everywhere. What differs is who suppresses the echo.
On Raku++, the engine can read a line without echoing it and the module finds that by probing for the
rakupp-prompt-hiddenprimitive. The adverb is still this module's element. Coreprompttakes no named arguments on any engine, soprompt("pw: ", :hidden)without this module is an error everywhere, which is what keeps the spelling portable. The terminal is put back by aSIGINThandler as well as by scope exit, so ^C at the password prompt leaves the shell working.On any other Raku, the module does it itself:
stty -gto save,stty -echofor the duration, and the saved settings restored in aLEAVE.On Windows without the engine primitive,
_getchfrommsvcrt, which reads a key without echoing it. That half lives inPrompt::Hidden::Win32and is loaded only on Windows;use NativeCallcosts about 70 ms on Rakudo, and no Unix program should pay it for a branch it cannot take.
A secret comes back a Str, and that is deliberate
prompt returns an allomorph: type 1234 and you get an IntStr, which is
an Int as much as it is a Str. For a PIN that is a trap, and not a
theoretical one ā measured on Rakudo v2026.08 and Raku++ 3.26.0 alike:
my $pin = prompt "PIN: "; # user types 01234
say to-json({ pin => $pin }); # {"pin": 1234}
The leading zero is gone and the secret has been retyped as a number. So
prompt(:hidden) returns a plain Str, always. prompt without
:hidden keeps the allomorph, because that is what prompt does.
Not a terminal is not an error
A pipe, a file, a here-doc, a CI harness: there is no echo to suppress, so the
line is read plainly and returned. That is what makes :hidden testable, and
it is why this distribution's own suite can assert the return type without a
pseudo-terminal.
Prompt::Hidden::prompt-backend
Says which of the three is live ā 'core', 'stty' or 'msvcrt' ā so a
program (or a bug report) can tell them apart:
say Prompt::Hidden::prompt-backend; # 'core' on Raku++, 'stty' elsewhere
Exports
&prompt, and only that. Prompt::Hidden::prompt-backend is spelled in
full rather than exported.
There is no import list: with one export there is nothing to select, and a list is refused rather than accepted and ignored ā the one thing an import list must never do is swallow a typo written beside it.
AUTHOR
Andrew Shitov
COPYRIGHT AND LICENSE
Copyright 2026 Andrew Shitov
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.