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-hidden primitive. The adverb is still this module's element. Core prompt takes no named arguments on any engine, so prompt("pw: ", :hidden) without this module is an error everywhere, which is what keeps the spelling portable. The terminal is put back by a SIGINT handler 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 -g to save, stty -echo for the duration, and the saved settings restored in a LEAVE.

  • On Windows without the engine primitive, _getch from msvcrt, which reads a key without echoing it. That half lives in Prompt::Hidden::Win32 and is loaded only on Windows; use NativeCall costs 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.

Prompt::Hidden v0.0.3

prompt with a :hidden adverb — a password the terminal never echoes, native on Raku++ and stty everywhere else

Authors

  • Andrew Shitov

License

Artistic-2.0

Dependencies

Test Dependencies

Provides

  • Prompt::Hidden
  • Prompt::Hidden::Win32

Documentation

The Camelia image is copyright 2009 by Larry Wall. "Raku" is a trademark of the Yet Another Society. All rights reserved.

Built with Podlite — the markup and publishing tools behind this site.