Search code examples
keyboard-eventsinteractioncrystal-lang

Interaction with a running process


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

Solution

  • 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.