Skip to content

Commit

Permalink
Factor out the terminal state setting code.
Browse files Browse the repository at this point in the history
It does not look like we need to set and reset state on every character, so
allow the higher level code to handle when to do that.

The JRuby special casing has been removed and has been integrated into the
system_extensions.rb file, adding a new CHARACTER_MODE = "jline"

jline, stty and ncurses modes have been tested, but termios needs testing.

Windows code was not touched.

The Question::character = :getc option does not make sense anymore.
  • Loading branch information
mnzaki committed Jul 18, 2012
1 parent 107e385 commit 2abb2c7
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 97 deletions.
22 changes: 4 additions & 18 deletions lib/highline.rb
Expand Up @@ -823,12 +823,7 @@ def get_response( )
if @question.echo == true and @question.limit.nil?
get_line
else
if JRUBY
echoChar = @java_console.getEchoCharacter
@java_console.setEchoCharacter 0
elsif stty
raw_no_echo_mode
end
raw_no_echo_mode

line = ""
backspace_limit = 0
Expand Down Expand Up @@ -867,11 +862,7 @@ def get_response( )
break if @question.limit and line.size == @question.limit
end
ensure
if JRUBY
@java_console.setEchoCharacter echoChar
elsif stty
restore_mode
end
restore_mode
end
if @question.overwrite
@output.print("\r#{HighLine.Style(:erase_line).code}")
Expand All @@ -883,10 +874,7 @@ def get_response( )
@question.change_case(@question.remove_whitespace(line))
end
else
if JRUBY
echoChar = @java_console.getEchoCharacter
@java_console.setEchoCharacter 0
end
raw_no_echo_mode
begin
if @question.character == :getc
response = @input.getbyte.chr
Expand All @@ -907,9 +895,7 @@ def get_response( )
end
end
ensure
if JRUBY
@java_console.setEchoCharacter echoChar
end
restore_mode
end
@question.change_case(response)
end
Expand Down
138 changes: 59 additions & 79 deletions lib/highline/system_extensions.rb
Expand Up @@ -13,6 +13,10 @@ module SystemExtensions

JRUBY = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'

def get_character( input = STDIN )
input.getbyte
end

#
# This section builds character reading and terminal size functions
# to suit the proper platform we're running on. Be warned: Here be
Expand All @@ -38,6 +42,13 @@ def get_character( input = STDIN )
Win32API.new("crtdll", "_getch", [ ], "L").Call
end

# We do not define a raw_no_echo_mode for Windows as _getch turns off echo
def raw_no_echo_mode
end

def restore_mode
end

# A Windows savvy method to fetch the console columns, and rows.
def terminal_size
m_GetStdHandle = Win32API.new( 'kernel32',
Expand All @@ -63,26 +74,16 @@ def terminal_size

CHARACTER_MODE = "termios" # For Debugging purposes only.

#
# Unix savvy getc(). (First choice.)
#
# *WARNING*: This method requires the "termios" library!
#
def get_character( input = STDIN )
return input.getbyte if input.is_a? StringIO

old_settings = Termios.getattr(input)

new_settings = old_settings.dup
def raw_no_echo_mode
@state = Termios.getattr(input)
new_settings = @state.dup
new_settings.c_lflag &= ~(Termios::ECHO | Termios::ICANON)
new_settings.c_cc[Termios::VMIN] = 1
Termios.setattr(input, Termios::TCSANOW, new_settings)
end

begin
Termios.setattr(input, Termios::TCSANOW, new_settings)
input.getbyte
ensure
Termios.setattr(input, Termios::TCSANOW, old_settings)
end
def restore_mode
Termios.setattr(input, Termios::TCSANOW, @state)
end
rescue LoadError # If our first choice fails, try using ffi-ncurses.
begin
Expand All @@ -95,18 +96,13 @@ def get_character( input = STDIN )

CHARACTER_MODE = "ncurses" # For Debugging purposes only.

#
# ncurses savvy getc().
#
def get_character( input = STDIN )
def raw_no_echo_mode
FFI::NCurses.initscr
FFI::NCurses.cbreak
begin
FFI::NCurses.curs_set 0
input.getbyte
ensure
FFI::NCurses.endwin
end
end

def restore_mode
FFI::NCurses.endwin
end

#
Expand All @@ -122,69 +118,53 @@ def terminal_size
end
size
end
rescue LoadError # If the ffi-ncurses choice fails, try using stty
CHARACTER_MODE = "stty" # For Debugging purposes only.
rescue LoadError
if JRUBY # If the ffi-ncurses choice fails, use Jline
require 'java' # if we are on JRuby

#
# Unix savvy getc(). (Second choice.)
#
# *WARNING*: This method requires the external "stty" program!
#
def get_character( input = STDIN )
raw_no_echo_mode
CHARACTER_MODE = "jline" # For Debugging purposes only.

begin
input.getbyte
ensure
restore_mode
end
end

#
# Switched the input mode to raw and disables echo.
#
# *WARNING*: This method requires the external "stty" program!
#
def raw_no_echo_mode
@state = `stty -g`
system "stty raw -echo -icanon isig"
end

#
# Restores a previously saved input mode.
#
# *WARNING*: This method requires the external "stty" program!
#
def restore_mode
system "stty #{@state}"
end
end
end

if not defined?(terminal_size)
if JRUBY
# JRuby running on Unix can fetch the number of columns and rows from the builtin Jline library
require 'java'
def terminal_size
java_terminal = @java_console.getTerminal
[ java_terminal.getTerminalWidth, java_terminal.getTerminalHeight ]
end
else
# A Unix savvy method using stty to fetch the console columns, and rows.
# ... stty does not work in JRuby
def terminal_size
if /solaris/ =~ RUBY_PLATFORM and
`stty` =~ /\brows = (\d+).*\bcolumns = (\d+)/
[$2, $1].map { |c| x.to_i }
else
`stty size`.split.map { |x| x.to_i }.reverse

def raw_no_echo_mode
@state = @java_console.getEchoCharacter
@java_console.setEchoCharacter 0
end

def restore_mode
@java_console.setEchoCharacter @state
end
else # As a final choice, use stty
# *WARNING*: This method requires the external "stty" program!
CHARACTER_MODE = "stty" # For Debugging purposes only.

def raw_no_echo_mode
@state = `stty -g`
system "stty raw -echo -icanon isig"
end

def restore_mode
system "stty #{@state}"
end
end
end
end
if (JRUBY and CHARACTER_MODE == "stty") or not defined?(get_character)
def get_character( input = STDIN )
input.getbyte

# For termios and stty
if not defined?(terminal_size)
# A Unix savvy method using stty to fetch the console columns, and rows.
# ... stty does not work in JRuby
def terminal_size
if /solaris/ =~ RUBY_PLATFORM and
`stty` =~ /\brows = (\d+).*\bcolumns = (\d+)/
[$2, $1].map { |c| x.to_i }
else
`stty size`.split.map { |x| x.to_i }.reverse
end
end
end
end
Expand Down

0 comments on commit 2abb2c7

Please sign in to comment.