1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
# system_extensions.rb
#
# Created by James Edward Gray II on 2006-06-14.
# Copyright 2006 Gray Productions. All rights reserved.
#
# This is Free Software. See LICENSE and COPYING for details.
require "highline/compatibility"
class HighLine
module SystemExtensions
module_function
JRUBY = defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
#
# This section builds character reading and terminal size functions
# to suit the proper platform we're running on. Be warned: Here be
# dragons!
#
begin
# Cygwin will look like Windows, but we want to treat it like a Posix OS:
raise LoadError, "Cygwin is a Posix OS." if RUBY_PLATFORM =~ /\bcygwin\b/i
require "Win32API" # See if we're on Windows.
CHARACTER_MODE = "Win32API" # For Debugging purposes only.
#
# Windows savvy getc().
#
# *WARNING*: This method ignores <tt>input</tt> and reads one
# character from +STDIN+!
#
def get_character( input = STDIN )
Win32API.new("msvcrt", "_getch", [ ], "L").Call
rescue Exception
Win32API.new("crtdll", "_getch", [ ], "L").Call
end
# A Windows savvy method to fetch the console columns, and rows.
def terminal_size
m_GetStdHandle = Win32API.new( 'kernel32',
'GetStdHandle',
['L'],
'L' )
m_GetConsoleScreenBufferInfo = Win32API.new(
'kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L'
)
format = 'SSSSSssssSS'
buf = ([0] * format.size).pack(format)
stdout_handle = m_GetStdHandle.call(0xFFFFFFF5)
m_GetConsoleScreenBufferInfo.call(stdout_handle, buf)
_, _, _, _, _,
left, top, right, bottom, _, _ = buf.unpack(format)
return right - left + 1, bottom - top + 1
end
rescue LoadError # If we're not on Windows try...
begin
require "termios" # Unix, first choice termios.
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
new_settings.c_lflag &= ~(Termios::ECHO | Termios::ICANON)
new_settings.c_cc[Termios::VMIN] = 1
begin
Termios.setattr(input, Termios::TCSANOW, new_settings)
input.getbyte
ensure
Termios.setattr(input, Termios::TCSANOW, old_settings)
end
end
rescue LoadError # If our first choice fails, try using ffi-ncurses.
begin
require 'ffi-ncurses' # The ffi gem is builtin to JRUBY and because stty does not
# work correctly in JRuby manually installing the ffi-ncurses
# gem is the only way to get highline to operate correctly in
# JRuby. The ncurses library is only present on unix platforms
# so this is not a solution for using highline in JRuby on
# windows.
CHARACTER_MODE = "ncurses" # For Debugging purposes only.
#
# ncurses savvy getc().
#
def get_character( input = STDIN )
FFI::NCurses.initscr
FFI::NCurses.cbreak
begin
FFI::NCurses.curs_set 0
input.getbyte
ensure
FFI::NCurses.endwin
end
end
rescue LoadError # If the ffi-ncurses choice fails, try using stty
CHARACTER_MODE = "stty" # For Debugging purposes only.
#
# Unix savvy getc(). (Second choice.)
#
# *WARNING*: This method requires the external "stty" program!
#
def get_character( input = STDIN )
raw_no_echo_mode
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 CHARACTER_MODE == 'ncurses'
#
# A ncurses savvy method to fetch the console columns, and rows.
#
def terminal_size
size = [80, 40]
FFI::NCurses.initscr
begin
size = FFI::NCurses.getmaxyx(stdscr).reverse
ensure
FFI::NCurses.endwin
end
size
end
elsif JRUBY
# JRuby running on Unix can fetch the number of columns and rows from the builtin Jline library
require 'java'
java_import 'jline.Terminal'
def terminal_size
java_terminal = @java_terminal || Terminal.getTerminal
[ java_terminal.getTerminalWidth, java_terminal.getTerminalHeight ]
end
else
# A Unix savvy method using stty that 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
end
end
|