Repository: JEG2/highline (ruby)

Issue:
Ctrl-C improperly handled when q.echo = false
Hi,

Just noticed something a little odd with the handling of a ctrl-c while in an `ask` with echo set to false.

```
#!/usr/bin/env ruby

require 'highline'

cli = HighLine.new
cli.ask("Password?") {|q| q.echo = false}
cli.ask("Anything else?")
```

```
$ ./highline_test.rb 
Password?
<hit ctrl-c>
Anything else?
<hit enter>

```

Two things happened here:
1. the ctrl-c did not interrupt the script (it does if `q.echo` is not set to false)
2. after this, and every time I run a new command (ls, ps etc), an empty line will be printed before the output of the command (see example below)

```
$ ls

file1
file2
```

I'm using highline-2.0.0.gem, and `zsh` in the standard terminal app in OSX.


Discussion:
I'll be having a look at it as soon as possible.
HighLine dates from a time where all the hard work should be done by it.
This is probably an issue related to the fact that HighLine is handling all cases related to special characters like backspace and others.
If you come up with a PR, feel free to open it, I would be thankful!
If not possible, just wait some time and I will surely try to fix it.

Thanks for reporting the issue! 👍 
Hi,

No worries, this isn't in any way a blocking/problematic bug, so don't feel pressed to fix this :) I might look into it on the train sometime, but no promises here :)
I've just run into this as well - we can work around it for now, and if I have time for a PR I'll raise one, but also subscribing for notifications if you happen to fix it before I do. Cheers!
io/console #getpass handles ctrl-C correctly
Just a thought, you could always throw the exit in with the character checks in HighLine#get_line_raw_no_echo_mode, this would "catch" (I say that because `trap` doesn't seem to catch anything in the method, or anywhere for that matter). This worked for me. I am not sure off hand if \u0003 is going to be cross platform but it seems to work in POSIX environments, tested on macOS:

```
diff --git a/lib/highline.rb b/lib/highline.rb
index 3e60cd3..e33e13a 100755
--- a/lib/highline.rb
+++ b/lib/highline.rb
@@ -538,6 +538,7 @@ class HighLine
     terminal.raw_no_echo_mode_exec do
       loop do
         character = terminal.get_character
+        exit 130 if character == "\u0003"
         break unless character
         break if ["\n", "\r"].include? character
```

Patch:
diff --git a/lib/highline.rb b/lib/highline.rb
--- a/lib/highline.rb
+++ b/lib/highline.rb
@@ -538,6 +538,7 @@ def get_line_raw_no_echo_mode(question)
     terminal.raw_no_echo_mode_exec do
       loop do
         character = terminal.get_character
+        raise Interrupt if character == "\u0003"
         break unless character
         break if ["\n", "\r"].include? character
 
diff --git a/lib/highline/io_console_compatible.rb b/lib/highline/io_console_compatible.rb
--- a/lib/highline/io_console_compatible.rb
+++ b/lib/highline/io_console_compatible.rb
@@ -13,7 +13,7 @@
 #
 
 module IOConsoleCompatible
-  def getch
+  def getch(min:nil, time:nil, intr: nil)
     getc
   end
 
diff --git a/lib/highline/terminal/io_console.rb b/lib/highline/terminal/io_console.rb
--- a/lib/highline/terminal/io_console.rb
+++ b/lib/highline/terminal/io_console.rb
@@ -27,7 +27,7 @@ def restore_mode
 
       # (see Terminal#get_character)
       def get_character
-        input.getch # from ruby io/console
+        input.getch(intr: true) # from ruby io/console
       rescue Errno::ENOTTY
         input.getc
       end


Test patch:
diff --git a/test/test_highline.rb b/test/test_highline.rb
--- a/test/test_highline.rb
+++ b/test/test_highline.rb
@@ -1300,6 +1300,20 @@ def test_echoing_with_utf8_when_echo_is_star
     assert_equal("maçã", answer)
   end
 
+  def test_echo_false_with_ctrl_c_interrupts
+    @input << "String with a ctrl-c at the end \u0003 \n"
+    @input.rewind
+    @answer = nil
+
+    assert_raises(Interrupt) do
+      @answer = @terminal.ask("Type:  ") do |q|
+        q.echo = false
+      end
+    end
+
+    assert_nil @answer
+  end
+
   def test_range_requirements
     @input << "112\n-541\n28\n"
     @input.rewind