Let's have a simple example:
Process.run("ping", {"google.com"}) do |proc|
proc.output.each_line { |line| puts line }
end
which runs a process, constantly reading its output and printing the output to stdout. Currently, when I press a key, it just appears along with the output of the running process, but I'd like to have some kind of key processing, so I would be able to manage the running process from the keyboard: stop it, or restart it with modified arguments. How to do that?
Or, to narrow the question down, how to make this output-input pair to be non-blocking for each other? Currently it takes one step and then waits for its counterpart to happen.
Process.run("ping", {"google.com"}) do |proc|
until proc.output.closed?
puts proc.output.gets
puts "Got key: #{STDIN.raw &.read_char}"
end
end
Using a terminal for interactive input is not as simple as it might seem. You can try with STDIN.raw &.read_char
. But this is limited and likely won't get you very far.
A tool which is usually used for this is readline
. There are Crystal bindings in the stdlib (see Readline
). They're currently undocumented, but should work. You could also try https://github.com/Papierkorb/fancyline which is a pure Crystal implementation of readline
.