Hi guys, I have a specific request. How when I query the user input with gets, instead of echoing the input, print asterisk ? I would like basically to mask the user input, but print something instead.
It wouldn’t print asterisks, but would be pretty familiar to a Linux user to just use #noecho
.
So I saw this already, but first it’s not exactly the result I would like, I really would like to have the possibility to print asterisk instead.
And the second issue I have is, if the user type straight away something, the echo take a bit to be disabled, is it normal too ?
Here’s my simple attempt:
print "Enter password: "
password = String.build do |str|
loop do
char = STDIN.raw &.read_char
if char == '\r' || char == '\n'
puts
break
end
str << char
print "*"
# STDOUT.flush
end
end
puts "Password is set as #{password}"
Additionally, I found a shard prompt that covers this use case.
Thanks a lot !
Is it normal when I press CTRL+C, I can’t still escape ?
And if I press backspace, I it still print asterisk :x
The following code adds a check to verify if the input characters are printable and handles backspaces.
print "Enter password: "
password = ""
loop do
char = STDIN.raw &.read_char
case char
when '\u0003'
abort "\nInput terminated with Ctrl+C"
when '\r', '\n', '\u0004' # handle Ctrl+D as EOF
puts
break
when '\u007F' # handle Backspace
unless password.empty?
password = password.rchop
print "\b \b"
end
when .try &.printable?
password += char.not_nil!
print "*"
else
# next
print "\r#{" " * (26 + password.size)}\r"
print "Invalid input! Try again: "
STDIN.rewind
password = ""
end
end
puts "Password is set as #{password}"
It should interrupt when detects Ctrl+C
and treats as EOF
when detects Ctrl+D
from STDIN
.
Thank you so much Sunrise
I have one question. In my software, I would like to perform a rescue to ensure if the user press CTRL+C during execution time, I can perform an action before exit. How can I do this ?
It’s my Main.cr of my project:
require "./RequiredLibraries"
Ism = ISM::CommandLine.new
begin
#We check first if the user try to perform right escalating access
tryEscalating = false
if ISM::Core::Security.ranAsSuperUser
tryEscalating = true
ISM::Core::Notification.needToBeRunAsNormalUserNotification
elsif !ISM::Core::Security.ranAsMemberOfGroupIsm
tryEscalating = true
ISM::Core::Notification.needToBeRunAsMemberOfIsmGroupNotification
end
if tryEscalating
ISM::Core.exitProgram
end
ISM::Core.hideTerminalCursor
Ism.start
#We catch any raised error
rescue error
ISM::Core::Error.show( className: "None",
functionName: "None",
errorTitle: "Unexpected error occured",
error: "The program stopped due to an unknown error",
exception: error,
information: "This error occur when #{ISM::Default::CommandLine::Name.upcase} is unable to catch the error",
errorCode: 1)
#We ensure that the program exit securely
ensure
#We ensure that the system is locked even we are facing an issue
if ISM::Core::Security.systemHandleUserAccess
ISM::Core::Security.lockSystemAccess
end
#To finish, we reset the initial terminal title, reset cursor and exit with the error code 1
ISM::Core.showTerminalCursor
ISM::Core.resetTerminalTitle
ISM::Core.exitProgram(code: 1)
end
raise "Terminated with Ctrl+C"
Use raise
instead of abort
so that interrupts caused by Ctrl-C
can be caught with rescue
.
But how I catch this interrupt? It’s this I don’t know how to do
In the case above, since the characters typed into STDIN need to be processed one by one, it is implemented by capturing the character '\u0003'
from pressing Ctrl+C
;
For other more general cases, on_terminate
can be used.