io-console 0.9.1-java → 0.9.3-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/{lib/ffi/io/console/native_console.rb → jruby/lib/io/console/backend/ffi/termios.rb} +112 -12
- data/{lib/ffi/io/console/windows_console.rb → jruby/lib/io/console/backend/ffi/windows.rb} +21 -9
- data/jruby/lib/io/console/backend/stty.rb +213 -0
- data/{lib/ffi/io/console/stub_console.rb → jruby/lib/io/console/backend/stub.rb} +12 -0
- data/{lib/ffi → jruby/lib}/io/console/common.rb +26 -10
- data/{lib/ffi/io/console/bsd_console.rb → jruby/lib/io/console/constants/bsd.rb} +11 -64
- data/{lib/ffi/io/console/linux_console.rb → jruby/lib/io/console/constants/linux.rb} +4 -47
- data/{lib/ffi/io/console/windows_constants.rb → jruby/lib/io/console/constants/windows.rb} +7 -0
- data/{lib/ffi → jruby/lib}/io/console/version.rb +1 -1
- data/{lib/ffi → jruby/lib}/io/console.rb +16 -14
- data/lib/io/console/size.rb +4 -2
- metadata +13 -13
- data/lib/ffi/io/console/stty_console.rb +0 -110
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 81030a79e741f9fbea14484f4849da9e6efc1daf0784d6d9b7fc067cc3a95357
|
|
4
|
+
data.tar.gz: f3c862f8495b89a129d0547177530875456cb44fcdf4f7b76d9ddb81c110b08b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6441ea13e62add5a11937381834077352406e0fd96a4cd7ded00e6fbcdc08a4c0e1376aa9b42ec35a3aba9b68ca7a6e5b0b8eddd4086cec960cabc1d6a1565f4
|
|
7
|
+
data.tar.gz: 28f42664fef6544ae6cffcf2ebc09e921155c302c8cf8da85e3ff584697d5a98bf1893bccddf76cfe68fa391a3b7f86ebb97ffb2ab6eb6dd299ecdf19b055c3b
|
|
@@ -1,8 +1,72 @@
|
|
|
1
|
+
require 'ffi'
|
|
2
|
+
|
|
3
|
+
case RbConfig::CONFIG['host_os']
|
|
4
|
+
when /darwin/i
|
|
5
|
+
tested_platforms = /i386|x86_64|aarch64/
|
|
6
|
+
unless tested_platforms.match?(FFI::Platform::ARCH)
|
|
7
|
+
raise LoadError, "native console on MacOS only supported on #{tested_platforms.source.gsub('|', ', ')}"
|
|
8
|
+
end
|
|
9
|
+
when /linux/i
|
|
10
|
+
tested_platforms = /i386|x86_64|powerpc64|aarch64|s390x/
|
|
11
|
+
unless tested_platforms.match?(FFI::Platform::ARCH)
|
|
12
|
+
warn "native console only tested on #{tested_platforms.source.gsub('|', ', ')}"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module IO::Console::LibC
|
|
17
|
+
include IO::Console::Constants
|
|
18
|
+
extend FFI::Library
|
|
19
|
+
ffi_lib FFI::Library::LIBC
|
|
20
|
+
|
|
21
|
+
typedef TCFLAG_TYPE, :tcflag_t
|
|
22
|
+
typedef SPEED_TYPE, :speed_t
|
|
23
|
+
|
|
24
|
+
class Termios < FFI::Struct
|
|
25
|
+
constants = IO::Console::Constants
|
|
26
|
+
fields = [
|
|
27
|
+
:c_iflag, :tcflag_t,
|
|
28
|
+
:c_oflag, :tcflag_t,
|
|
29
|
+
:c_cflag, :tcflag_t,
|
|
30
|
+
:c_lflag, :tcflag_t,
|
|
31
|
+
]
|
|
32
|
+
fields.concat([:c_line, :uchar]) if constants::TERMIOS_HAS_LINE
|
|
33
|
+
fields.concat([
|
|
34
|
+
:c_cc, [:uchar, constants::NCCS],
|
|
35
|
+
:c_ispeed, :speed_t,
|
|
36
|
+
:c_ospeed, :speed_t,
|
|
37
|
+
])
|
|
38
|
+
layout(*fields)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class Winsize < FFI::Struct
|
|
42
|
+
layout \
|
|
43
|
+
:ws_row, :ushort,
|
|
44
|
+
:ws_col, :ushort,
|
|
45
|
+
:ws_xpixel, :ushort,
|
|
46
|
+
:ws_ypixel, :ushort
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
attach_function :tcsetattr, [:int, :int, :pointer], :int
|
|
50
|
+
attach_function :tcgetattr, [:int, :pointer], :int
|
|
51
|
+
attach_function :cfgetispeed, [:pointer], :speed_t
|
|
52
|
+
attach_function :cfgetospeed, [:pointer], :speed_t
|
|
53
|
+
attach_function :cfsetispeed, [:pointer, :speed_t], :int
|
|
54
|
+
attach_function :cfsetospeed, [:pointer, :speed_t], :int
|
|
55
|
+
attach_function :cfmakeraw, [:pointer], :void
|
|
56
|
+
attach_function :tcflush, [:int, :int], :int
|
|
57
|
+
attach_function :ioctl, [:int, :ulong, :varargs], :int
|
|
58
|
+
end
|
|
59
|
+
|
|
1
60
|
# Common logic that uses native calls for console
|
|
2
61
|
module IO::Console
|
|
3
62
|
def ttymode
|
|
4
63
|
termios = LibC::Termios.new
|
|
5
|
-
if LibC.
|
|
64
|
+
result = if LibC.const_defined?(:TIOCGETA)
|
|
65
|
+
LibC.ioctl(fileno, LibC::TIOCGETA, :pointer, termios.pointer)
|
|
66
|
+
else
|
|
67
|
+
LibC.tcgetattr(fileno, termios.pointer)
|
|
68
|
+
end
|
|
69
|
+
if result != 0
|
|
6
70
|
raise SystemCallError.new(respond_to?(:path) ? path : "tcgetattr", FFI.errno)
|
|
7
71
|
end
|
|
8
72
|
|
|
@@ -15,7 +79,12 @@ module IO::Console
|
|
|
15
79
|
private :ttymode
|
|
16
80
|
|
|
17
81
|
def ttymode_set(termios)
|
|
18
|
-
if LibC.
|
|
82
|
+
result = if LibC.const_defined?(:TIOCSETA)
|
|
83
|
+
LibC.ioctl(fileno, LibC::TIOCSETA, :pointer, termios.pointer)
|
|
84
|
+
else
|
|
85
|
+
LibC.tcsetattr(fileno, LibC::TCSANOW, termios.pointer)
|
|
86
|
+
end
|
|
87
|
+
if result != 0
|
|
19
88
|
raise SystemCallError.new(respond_to?(:path) ? path : "tcsetattr(TCSANOW)", FFI.errno)
|
|
20
89
|
end
|
|
21
90
|
end
|
|
@@ -33,13 +102,19 @@ module IO::Console
|
|
|
33
102
|
end
|
|
34
103
|
private :ttymode_yield
|
|
35
104
|
|
|
36
|
-
|
|
37
|
-
LibC.
|
|
105
|
+
TTY_SET_MIN = Proc.new do |t, min|
|
|
106
|
+
t[:c_cc][LibC::VMIN] = min ? min.to_i.clamp(0, 255) : 1
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
TTY_SET_TIME = Proc.new do |t, time|
|
|
110
|
+
t[:c_cc][LibC::VTIME] = time ? (time * 10).to_i.clamp(0, 255) : 0
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
TTY_RAW = Proc.new do |t, min: nil, time: nil, intr: nil|
|
|
114
|
+
LibC.cfmakeraw(t.pointer)
|
|
38
115
|
t[:c_lflag] &= ~(LibC::ECHOE|LibC::ECHOK)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
end
|
|
42
|
-
t[:c_cc][LibC::VTIME] = (time&.to_i || 0) * 10
|
|
116
|
+
TTY_SET_MIN[t, min]
|
|
117
|
+
TTY_SET_TIME[t, time]
|
|
43
118
|
if intr
|
|
44
119
|
t[:c_iflag] |= LibC::BRKINT
|
|
45
120
|
t[:c_lflag] |= LibC::ISIG
|
|
@@ -47,18 +122,19 @@ module IO::Console
|
|
|
47
122
|
end
|
|
48
123
|
end
|
|
49
124
|
|
|
50
|
-
def raw(*, min:
|
|
125
|
+
def raw(*, min: nil, time: nil, intr: nil, &block)
|
|
51
126
|
ttymode_yield(block, min:, time:, intr:, &TTY_RAW)
|
|
52
127
|
end
|
|
53
128
|
|
|
54
|
-
def raw!(
|
|
55
|
-
ttymode(
|
|
129
|
+
def raw!(*, min: 1, time: nil, intr: nil)
|
|
130
|
+
ttymode { |t| TTY_RAW.call(t, min:, time:, intr:) }
|
|
131
|
+
self
|
|
56
132
|
end
|
|
57
133
|
|
|
58
134
|
TTY_COOKED = Proc.new do |t|
|
|
59
135
|
t[:c_iflag] |= (LibC::BRKINT|LibC::ISTRIP|LibC::ICRNL|LibC::IXON)
|
|
60
136
|
t[:c_oflag] |= LibC::OPOST
|
|
61
|
-
t[:c_lflag] |= (
|
|
137
|
+
t[:c_lflag] |= (TTY_ECHO|LibC::ICANON|LibC::ISIG|LibC::IEXTEN)
|
|
62
138
|
end
|
|
63
139
|
|
|
64
140
|
def cooked(*, &block)
|
|
@@ -88,6 +164,8 @@ module IO::Console
|
|
|
88
164
|
ttymode_yield(block) { |t| t[:c_lflag] &= ~(TTY_ECHO) }
|
|
89
165
|
end
|
|
90
166
|
|
|
167
|
+
private_constant :TTY_SET_TIME, :TTY_SET_MIN, :TTY_RAW, :TTY_COOKED, :TTY_ECHO
|
|
168
|
+
|
|
91
169
|
class Mode
|
|
92
170
|
attr_reader :termios
|
|
93
171
|
|
|
@@ -99,6 +177,11 @@ module IO::Console
|
|
|
99
177
|
@termios = m.termios.dup
|
|
100
178
|
end
|
|
101
179
|
|
|
180
|
+
def echo?
|
|
181
|
+
!(@termios[:c_lflag] & TTY_ECHO).zero?
|
|
182
|
+
end
|
|
183
|
+
alias echo echo?
|
|
184
|
+
|
|
102
185
|
def echo=(echo)
|
|
103
186
|
if echo
|
|
104
187
|
@termios[:c_lflag] |= TTY_ECHO
|
|
@@ -117,6 +200,22 @@ module IO::Console
|
|
|
117
200
|
TTY_RAW[new_mode.termios, min:, time:, intr:]
|
|
118
201
|
new_mode
|
|
119
202
|
end
|
|
203
|
+
|
|
204
|
+
def min
|
|
205
|
+
@termios[:c_cc][LibC::VMIN]
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def min=(min)
|
|
209
|
+
TTY_SET_MIN[@termios, min]
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def time
|
|
213
|
+
@termios[:c_cc][LibC::VTIME].quo(10)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def time=(time)
|
|
217
|
+
TTY_SET_TIME[@termios, time]
|
|
218
|
+
end
|
|
120
219
|
end
|
|
121
220
|
|
|
122
221
|
def console_mode
|
|
@@ -176,4 +275,5 @@ end
|
|
|
176
275
|
|
|
177
276
|
class IO
|
|
178
277
|
include Console
|
|
278
|
+
prepend PlatformTty if instance_method(:tty?).arity == 0
|
|
179
279
|
end
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
require 'ffi'
|
|
2
2
|
|
|
3
3
|
module IO::Console::Windows
|
|
4
|
-
STD_INPUT_HANDLE = -10
|
|
5
|
-
STD_OUTPUT_HANDLE = -11
|
|
6
|
-
WAIT_OBJECT_0 = 0
|
|
7
|
-
WAIT_TIMEOUT = 258
|
|
8
|
-
ENABLE_WRAP_AT_EOL_OUTPUT = 2
|
|
9
|
-
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
|
|
10
|
-
|
|
11
4
|
module Native
|
|
12
5
|
extend FFI::Library
|
|
13
6
|
ffi_convention :stdcall
|
|
@@ -125,11 +118,30 @@ end
|
|
|
125
118
|
|
|
126
119
|
IO.prepend(IO::Console::Windows::TTY)
|
|
127
120
|
|
|
128
|
-
class IO::
|
|
121
|
+
class IO::Console::Mode
|
|
129
122
|
def initialize(mode)
|
|
130
123
|
@mode = mode
|
|
131
124
|
end
|
|
132
125
|
|
|
126
|
+
def echo?
|
|
127
|
+
end
|
|
128
|
+
alias echo echo?
|
|
129
|
+
|
|
130
|
+
def echo=(echo)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def min
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def min=(min)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def time
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def time=(time)
|
|
143
|
+
end
|
|
144
|
+
|
|
133
145
|
def virtual_terminal_processing?
|
|
134
146
|
@mode & IO::Console::Windows::ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0
|
|
135
147
|
end
|
|
@@ -158,7 +170,7 @@ end
|
|
|
158
170
|
|
|
159
171
|
class IO
|
|
160
172
|
def console_mode
|
|
161
|
-
IO::
|
|
173
|
+
IO::Console::Mode.new(IO::Console::Windows.console_mode(self))
|
|
162
174
|
end
|
|
163
175
|
|
|
164
176
|
def console_mode=(mode)
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# attempt to call stty; if failure, raise error
|
|
2
|
+
module IO::Console
|
|
3
|
+
STTY = %w[/usr/bin/stty /bin/stty].find {|path| File.executable?(path)}
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
raise LoadError, "stty command not found" unless IO::Console::STTY
|
|
7
|
+
|
|
8
|
+
warn "io/console on JRuby shells out to stty for most operations" if $VERBOSE
|
|
9
|
+
|
|
10
|
+
class IO::Console::Mode
|
|
11
|
+
STTY_PATTERNS = /
|
|
12
|
+
(?<a>[a-z]\w*)\s(?:=\s(?:(?<n>\d+)|(?<c>\^.|.)|<undef>)|(?<n>\d+)(?:\s+\w+)?); |
|
|
13
|
+
(?<n>\d+)\s+(?<a>[a-z]\w*); |
|
|
14
|
+
(?<f>-)?(?<a>[a-z]\w*)(?=\s|$)
|
|
15
|
+
/x
|
|
16
|
+
private_constant :STTY_PATTERNS
|
|
17
|
+
|
|
18
|
+
def initialize(saved, attrs)
|
|
19
|
+
@saved = saved.chomp
|
|
20
|
+
@attrs = {}
|
|
21
|
+
attrs.scan(STTY_PATTERNS) do
|
|
22
|
+
m = $~
|
|
23
|
+
case attr = m[:a]
|
|
24
|
+
when "echo"
|
|
25
|
+
@attrs[attr.to_sym] = !m[:f]
|
|
26
|
+
when "min", "time"
|
|
27
|
+
@attrs[attr.to_sym] = m[:n]&.to_i
|
|
28
|
+
when *%w[brkint icanon isig opost]
|
|
29
|
+
@attrs[attr.to_sym] = !m[:f]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
@args = []
|
|
33
|
+
@changes = {}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def initialize_copy(mode)
|
|
37
|
+
super
|
|
38
|
+
@attrs = @attrs.dup
|
|
39
|
+
@saved = @saved.dup
|
|
40
|
+
@args = @args.dup
|
|
41
|
+
@changes = @changes.dup
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def arguments
|
|
45
|
+
[
|
|
46
|
+
@saved,
|
|
47
|
+
*@args,
|
|
48
|
+
*@changes.flat_map {|a, v|
|
|
49
|
+
case v
|
|
50
|
+
when true
|
|
51
|
+
a.to_s
|
|
52
|
+
when false
|
|
53
|
+
"-#{a}"
|
|
54
|
+
when nil
|
|
55
|
+
else
|
|
56
|
+
[a.to_s, v.to_s]
|
|
57
|
+
end
|
|
58
|
+
},
|
|
59
|
+
]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def echo?
|
|
63
|
+
@changes.fetch(:echo) {@attrs[:echo]}
|
|
64
|
+
end
|
|
65
|
+
alias echo echo?
|
|
66
|
+
|
|
67
|
+
def echo=(echo)
|
|
68
|
+
@changes[:echo] = echo
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def raw(min: nil, time: nil, intr: nil)
|
|
72
|
+
dup.raw!(min:, time:, intr:)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def raw!(min: nil, time: nil, intr: nil)
|
|
76
|
+
@args << 'raw'
|
|
77
|
+
self.min = min
|
|
78
|
+
self.time = time
|
|
79
|
+
%i[brkint isig opost].each {|a| @changes[a] = true} if intr
|
|
80
|
+
self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def min
|
|
84
|
+
@changes.fetch(:min) {@attrs[:min]}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def min=(min)
|
|
88
|
+
@changes[:min] = (min || 1).to_i.clamp(0, 255)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def time
|
|
92
|
+
@changes.fetch(:time) {@attrs[:time]}&.quo(10)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def time=(time)
|
|
96
|
+
@changes[:time] = ((time || 0) * 10).to_i.clamp(0, 255)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
attr_reader :attrs, :saved, :args, :changes
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Non-Windows assumes stty command is available
|
|
105
|
+
class IO
|
|
106
|
+
private def _io_console_stty(*args)
|
|
107
|
+
# pre-check to catch non-tty filenos we can't stty against anyway
|
|
108
|
+
raise Errno::ENOTTY, inspect if !tty?
|
|
109
|
+
|
|
110
|
+
IO.pipe do |re, we|
|
|
111
|
+
input = dup # workaround for JRuby
|
|
112
|
+
IO.popen([Console::STTY, *args, in: input, err: we], &:read)
|
|
113
|
+
ensure
|
|
114
|
+
input&.close
|
|
115
|
+
unless $?.success?
|
|
116
|
+
we.close
|
|
117
|
+
error = re.read
|
|
118
|
+
case error
|
|
119
|
+
when /Inappropriate ioctl for device/
|
|
120
|
+
raise Errno::ENOTTY, inspect
|
|
121
|
+
end
|
|
122
|
+
raise "stty command failed: #{error.chomp}"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def raw(*, min: 1, time: nil, intr: nil)
|
|
128
|
+
saved = console_mode
|
|
129
|
+
self.console_mode = saved.raw(min:, time:, intr:)
|
|
130
|
+
yield self
|
|
131
|
+
ensure
|
|
132
|
+
self.console_mode = saved if saved
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def raw!(*, min: 1, time: nil, intr: nil)
|
|
136
|
+
self.console_mode = console_mode.raw(min:, time:, intr:)
|
|
137
|
+
self
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def cooked(*)
|
|
141
|
+
saved = _io_console_stty('-g')
|
|
142
|
+
_io_console_stty('-raw')
|
|
143
|
+
yield self
|
|
144
|
+
ensure
|
|
145
|
+
_io_console_stty(saved) if saved
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def cooked!(*)
|
|
149
|
+
_io_console_stty('-raw')
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def echo=(echo)
|
|
153
|
+
_io_console_stty(echo ? 'echo' : '-echo')
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def echo?
|
|
157
|
+
(_io_console_stty('-a') =~ / -echo /) ? false : true
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def noecho
|
|
161
|
+
saved = _io_console_stty('-g')
|
|
162
|
+
_io_console_stty('-echo')
|
|
163
|
+
yield self
|
|
164
|
+
ensure
|
|
165
|
+
_io_console_stty(saved) if saved
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def console_mode
|
|
169
|
+
Console::Mode.new(_io_console_stty('-g'), _io_console_stty('-a'))
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def console_mode=(mode)
|
|
173
|
+
_io_console_stty(*mode.arguments)
|
|
174
|
+
mode
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def winsize
|
|
178
|
+
# Pattern for rows/columns; all systems may not return in these formats.
|
|
179
|
+
match = /
|
|
180
|
+
(?<rows>\d+)\s+rows;\s*(?<columns>\d+)\s+columns |
|
|
181
|
+
rows\s+(?<rows>\d+);\s*columns\s+(?<columns>\d+)
|
|
182
|
+
/x.match(_io_console_stty('-a'))
|
|
183
|
+
[match[:rows].to_i, match[:columns].to_i]
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def winsize=(size)
|
|
187
|
+
size = size.to_ary unless size.kind_of?(Array)
|
|
188
|
+
sizelen = size.size
|
|
189
|
+
|
|
190
|
+
if sizelen != 2 && sizelen != 4
|
|
191
|
+
raise ArgumentError, "wrong number of arguments (given #{sizelen}, expected 2 or 4)"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
if sizelen == 4
|
|
195
|
+
warn "stty io/console does not support pixel winsize"
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
row, col, _, _ = size
|
|
199
|
+
|
|
200
|
+
_io_console_stty('rows', row.to_s, 'cols', col.to_s)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def iflush
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def oflush
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def ioflush
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
prepend PlatformTty
|
|
213
|
+
end
|
|
@@ -6,7 +6,7 @@ end
|
|
|
6
6
|
|
|
7
7
|
class IO
|
|
8
8
|
# TODO: Windows version uses "conin$" and "conout$" instead of /dev/tty
|
|
9
|
-
def self.console(sym = nil, *args)
|
|
9
|
+
def self.console(sym = nil, *args, **opts)
|
|
10
10
|
raise TypeError, "expected Symbol, got #{sym.class}" unless sym.nil? || sym.kind_of?(Symbol)
|
|
11
11
|
|
|
12
12
|
# klass = self == IO ? File : self
|
|
@@ -43,7 +43,8 @@ class IO
|
|
|
43
43
|
@console = con
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
return
|
|
46
|
+
return nil unless con
|
|
47
|
+
return con.send(sym, *args, **opts) if sym
|
|
47
48
|
return con
|
|
48
49
|
end
|
|
49
50
|
|
|
@@ -57,14 +58,11 @@ class IO
|
|
|
57
58
|
wio = self == $stdin ? $stderr : self
|
|
58
59
|
wio.write(prompt) if prompt
|
|
59
60
|
begin
|
|
60
|
-
str =
|
|
61
|
-
noecho do
|
|
62
|
-
str = gets
|
|
63
|
-
end
|
|
61
|
+
str = noecho {gets("\n")}
|
|
64
62
|
ensure
|
|
65
|
-
puts
|
|
63
|
+
puts
|
|
66
64
|
end
|
|
67
|
-
str
|
|
65
|
+
str&.chomp("\n")
|
|
68
66
|
end
|
|
69
67
|
|
|
70
68
|
def input_pending?
|
|
@@ -108,6 +106,7 @@ class IO
|
|
|
108
106
|
end
|
|
109
107
|
end
|
|
110
108
|
|
|
109
|
+
return nil unless b && result.length == 2
|
|
111
110
|
result.map(&:pred)
|
|
112
111
|
end
|
|
113
112
|
end
|
|
@@ -162,9 +161,26 @@ class IO
|
|
|
162
161
|
|
|
163
162
|
def getpass(prompt = nil)
|
|
164
163
|
write(prompt) if prompt
|
|
165
|
-
str = gets
|
|
166
|
-
puts
|
|
164
|
+
str = gets("\n")&.chomp("\n")
|
|
165
|
+
puts
|
|
167
166
|
str
|
|
168
167
|
end
|
|
169
168
|
end
|
|
169
|
+
|
|
170
|
+
module PlatformTty # :nodoc:
|
|
171
|
+
def tty?(*modes)
|
|
172
|
+
modes.each do |mode|
|
|
173
|
+
case mode
|
|
174
|
+
when nil
|
|
175
|
+
when :any
|
|
176
|
+
when Symbol
|
|
177
|
+
raise ArgumentError, "unknown tty type: #{mode.inspect}"
|
|
178
|
+
else
|
|
179
|
+
raise TypeError, "wrong argument type #{mode.class} (expected Symbol)"
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
super()
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
private_constant :PlatformTty
|
|
170
186
|
end
|
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
module IO::Console::LibC
|
|
10
|
-
extend FFI::Library
|
|
11
|
-
ffi_lib FFI::Library::LIBC
|
|
12
|
-
|
|
13
|
-
if RbConfig::CONFIG['host_os'].downcase =~ /darwin/
|
|
14
|
-
typedef :ulong, :tcflag_t
|
|
15
|
-
typedef :ulong, :speed_t
|
|
1
|
+
module IO::Console::Constants
|
|
2
|
+
if /darwin/i.match?(RbConfig::CONFIG['host_os'])
|
|
3
|
+
TCFLAG_TYPE = :ulong
|
|
4
|
+
SPEED_TYPE = :ulong
|
|
5
|
+
TIOCGETA = 0x40487413
|
|
6
|
+
TIOCSETA = 0x80487414
|
|
16
7
|
else
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
TCFLAG_TYPE = :uint
|
|
9
|
+
SPEED_TYPE = :uint
|
|
19
10
|
end
|
|
11
|
+
TERMIOS_HAS_LINE = false
|
|
20
12
|
|
|
21
13
|
# Special Control Characters
|
|
22
14
|
VEOF = 0 # ICANON
|
|
@@ -124,51 +116,6 @@ module IO::Console::LibC
|
|
|
124
116
|
IOCPARM_MASK = 0x1fff
|
|
125
117
|
IOC_OUT = 0x40000000
|
|
126
118
|
IOC_IN = 0x80000000
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
inout | ((len & IOCPARM_MASK) << 16) | ((group.ord << 8) | num)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def self._IOR(g,n,t)
|
|
133
|
-
self._IOC(IOC_OUT, g, n, find_type(t).size)
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def self._IOW(g,n,t)
|
|
137
|
-
self._IOC(IOC_IN, g, n, find_type(t).size)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
class Termios < FFI::Struct
|
|
142
|
-
layout \
|
|
143
|
-
:c_iflag, :tcflag_t,
|
|
144
|
-
:c_oflag, :tcflag_t,
|
|
145
|
-
:c_cflag, :tcflag_t,
|
|
146
|
-
:c_lflag, :tcflag_t,
|
|
147
|
-
:c_cc, [ :uchar, NCCS ],
|
|
148
|
-
:c_ispeed, :speed_t,
|
|
149
|
-
:c_ospeed, :speed_t
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
class Winsize < FFI::Struct
|
|
153
|
-
layout \
|
|
154
|
-
:ws_row, :ushort,
|
|
155
|
-
:ws_col, :ushort,
|
|
156
|
-
:ws_xpixel, :ushort,
|
|
157
|
-
:ws_ypixel, :ushort
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
TIOCGWINSZ = _IOR('t', 104, Winsize) # get window size
|
|
161
|
-
TIOCSWINSZ = _IOW('t', 103, Winsize) # set window size
|
|
162
|
-
|
|
163
|
-
attach_function :tcsetattr, [ :int, :int, Termios ], :int
|
|
164
|
-
attach_function :tcgetattr, [ :int, Termios ], :int
|
|
165
|
-
attach_function :cfgetispeed, [ Termios ], :speed_t
|
|
166
|
-
attach_function :cfgetospeed, [ Termios ], :speed_t
|
|
167
|
-
attach_function :cfsetispeed, [ Termios, :speed_t ], :int
|
|
168
|
-
attach_function :cfsetospeed, [ Termios, :speed_t ], :int
|
|
169
|
-
attach_function :cfmakeraw, [ Termios ], :int
|
|
170
|
-
attach_function :tcflush, [ :int, :int ], :int
|
|
171
|
-
attach_function :ioctl, [ :int, :ulong, :varargs ], :int
|
|
119
|
+
TIOCGWINSZ = 0x40087468
|
|
120
|
+
TIOCSWINSZ = 0x80087467
|
|
172
121
|
end
|
|
173
|
-
|
|
174
|
-
require_relative 'native_console'
|
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
unless FFI::Platform::ARCH =~ /#{tested_platforms.join('|')}/
|
|
6
|
-
warn "native console only tested on #{tested_platforms.join(', ')}"
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
module IO::Console::LibC
|
|
10
|
-
extend FFI::Library
|
|
11
|
-
ffi_lib FFI::Library::LIBC
|
|
12
|
-
|
|
13
|
-
typedef :uint, :tcflag_t
|
|
14
|
-
typedef :uint, :speed_t
|
|
1
|
+
module IO::Console::Constants
|
|
2
|
+
TCFLAG_TYPE = :uint
|
|
3
|
+
SPEED_TYPE = :uint
|
|
4
|
+
TERMIOS_HAS_LINE = true
|
|
15
5
|
|
|
16
6
|
VINTR = 0
|
|
17
7
|
VQUIT = 1
|
|
@@ -168,39 +158,6 @@ module IO::Console::LibC
|
|
|
168
158
|
TCSADRAIN = 1
|
|
169
159
|
TCSAFLUSH = 2
|
|
170
160
|
NCCS = 32
|
|
171
|
-
class Termios < FFI::Struct
|
|
172
|
-
layout \
|
|
173
|
-
:c_iflag, :tcflag_t,
|
|
174
|
-
:c_oflag, :tcflag_t,
|
|
175
|
-
:c_cflag, :tcflag_t,
|
|
176
|
-
:c_lflag, :tcflag_t,
|
|
177
|
-
:c_line, :uchar,
|
|
178
|
-
:c_cc, [ :uchar, NCCS ],
|
|
179
|
-
:c_ispeed, :speed_t,
|
|
180
|
-
:c_ospeed, :speed_t
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
class Winsize < FFI::Struct
|
|
184
|
-
layout \
|
|
185
|
-
:ws_row, :ushort,
|
|
186
|
-
:ws_col, :ushort,
|
|
187
|
-
:ws_xpixel, :ushort,
|
|
188
|
-
:ws_ypixel, :ushort
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
|
|
192
161
|
TIOCGWINSZ = 0x5413
|
|
193
162
|
TIOCSWINSZ = 0x5414
|
|
194
|
-
|
|
195
|
-
attach_function :tcsetattr, [ :int, :int, Termios ], :int
|
|
196
|
-
attach_function :tcgetattr, [ :int, Termios ], :int
|
|
197
|
-
attach_function :cfgetispeed, [ Termios ], :speed_t
|
|
198
|
-
attach_function :cfgetospeed, [ Termios ], :speed_t
|
|
199
|
-
attach_function :cfsetispeed, [ Termios, :speed_t ], :int
|
|
200
|
-
attach_function :cfsetospeed, [ Termios, :speed_t ], :int
|
|
201
|
-
attach_function :cfmakeraw, [ Termios ], :int
|
|
202
|
-
attach_function :tcflush, [ :int, :int ], :int
|
|
203
|
-
attach_function :ioctl, [ :int, :ulong, :varargs ], :int
|
|
204
163
|
end
|
|
205
|
-
|
|
206
|
-
require_relative 'native_console'
|
|
@@ -36,28 +36,30 @@ class IO
|
|
|
36
36
|
deprecate_constant :ConsoleMode
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
backends = []
|
|
40
|
+
ENV["IO_CONSOLE_BACKEND"]&.then do |be|
|
|
41
|
+
backends.concat(be.split(",").map {|b| b.split(":")})
|
|
42
|
+
end&.first ||
|
|
40
43
|
# If Linux or BSD, try to load the native version
|
|
41
|
-
case RbConfig::CONFIG['host_os']
|
|
42
|
-
when /darwin|openbsd|freebsd|netbsd/
|
|
43
|
-
|
|
44
|
-
when /linux/
|
|
45
|
-
|
|
44
|
+
case RbConfig::CONFIG['host_os']
|
|
45
|
+
when /darwin|openbsd|freebsd|netbsd/i
|
|
46
|
+
backends << %w[ffi/termios bsd] << %w[stty]
|
|
47
|
+
when /linux/i
|
|
48
|
+
backends << %w[ffi/termios linux] << %w[stty]
|
|
46
49
|
when /mswin|win32|ming/i
|
|
47
|
-
|
|
48
|
-
require_relative 'console/windows_console'
|
|
49
|
-
return
|
|
50
|
+
backends << %w[ffi/windows windows]
|
|
50
51
|
else
|
|
51
|
-
|
|
52
|
+
backends << %w[stty]
|
|
52
53
|
end
|
|
53
54
|
|
|
54
|
-
return if
|
|
55
|
-
require_relative "console/#{
|
|
55
|
+
return if backends.any? do |backend, constants|
|
|
56
|
+
require_relative "console/constants/#{constants}" if constants
|
|
57
|
+
require_relative "console/backend/#{backend}"
|
|
56
58
|
rescue Exception => ex
|
|
57
|
-
warn "failed to load #{
|
|
59
|
+
warn "failed to load #{backend.split('/', 2).first} console support: #{ex}" if $VERBOSE
|
|
58
60
|
else
|
|
59
61
|
true
|
|
60
62
|
end
|
|
61
63
|
|
|
62
64
|
# If still not ready, just use stubbed version
|
|
63
|
-
require_relative
|
|
65
|
+
require_relative 'console/backend/stub'
|
data/lib/io/console/size.rb
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: false
|
|
2
2
|
# fallback to console window size
|
|
3
3
|
def IO.default_console_size
|
|
4
|
+
lines = ENV["LINES"].to_i
|
|
5
|
+
columns = ENV["COLUMNS"].to_i
|
|
4
6
|
[
|
|
5
|
-
|
|
6
|
-
|
|
7
|
+
lines.positive? ? lines : 25,
|
|
8
|
+
columns.positive? ? columns : 80,
|
|
7
9
|
]
|
|
8
10
|
end
|
|
9
11
|
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: io-console
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.3
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Nobu Nakada
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-09-14 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: add console capabilities to IO instances.
|
|
13
13
|
email: nobu@ruby-lang.org
|
|
@@ -19,16 +19,16 @@ files:
|
|
|
19
19
|
- BSDL
|
|
20
20
|
- COPYING
|
|
21
21
|
- README.md
|
|
22
|
-
- lib/
|
|
23
|
-
- lib/
|
|
24
|
-
- lib/
|
|
25
|
-
- lib/
|
|
26
|
-
- lib/
|
|
27
|
-
- lib/
|
|
28
|
-
- lib/
|
|
29
|
-
- lib/
|
|
30
|
-
- lib/
|
|
31
|
-
- lib/
|
|
22
|
+
- jruby/lib/io/console.rb
|
|
23
|
+
- jruby/lib/io/console/backend/ffi/termios.rb
|
|
24
|
+
- jruby/lib/io/console/backend/ffi/windows.rb
|
|
25
|
+
- jruby/lib/io/console/backend/stty.rb
|
|
26
|
+
- jruby/lib/io/console/backend/stub.rb
|
|
27
|
+
- jruby/lib/io/console/common.rb
|
|
28
|
+
- jruby/lib/io/console/constants/bsd.rb
|
|
29
|
+
- jruby/lib/io/console/constants/linux.rb
|
|
30
|
+
- jruby/lib/io/console/constants/windows.rb
|
|
31
|
+
- jruby/lib/io/console/version.rb
|
|
32
32
|
- lib/io/console/size.rb
|
|
33
33
|
homepage: https://github.com/ruby/io-console
|
|
34
34
|
licenses:
|
|
@@ -39,7 +39,7 @@ metadata:
|
|
|
39
39
|
changelog_uri: https://github.com/ruby/io-console/releases
|
|
40
40
|
rdoc_options: []
|
|
41
41
|
require_paths:
|
|
42
|
-
- lib
|
|
42
|
+
- jruby/lib
|
|
43
43
|
- lib
|
|
44
44
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
45
45
|
requirements:
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
# attempt to call stty; if failure, raise error
|
|
2
|
-
module IO::Console
|
|
3
|
-
STTY = %w[/usr/bin/stty /bin/stty].find {|path| File.executable?(path)}
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
unless IO::Console::STTY &&
|
|
7
|
-
system(IO::Console::STTY, out: File::NULL, err: %i[child out])
|
|
8
|
-
raise "stty command returned nonzero exit status"
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
warn "io/console on JRuby shells out to stty for most operations" if $VERBOSE
|
|
12
|
-
|
|
13
|
-
# Non-Windows assumes stty command is available
|
|
14
|
-
class IO
|
|
15
|
-
private def _io_console_stty(*args)
|
|
16
|
-
# pre-check to catch non-tty filenos we can't stty against anyway
|
|
17
|
-
raise Errno::ENOTTY, inspect if !tty?
|
|
18
|
-
|
|
19
|
-
IO.pipe do |re, we|
|
|
20
|
-
input = dup # workaround for JRuby
|
|
21
|
-
IO.popen([Console::STTY, *args, in: input, err: we], &:read)
|
|
22
|
-
ensure
|
|
23
|
-
input&.close
|
|
24
|
-
unless $?.success?
|
|
25
|
-
we.close
|
|
26
|
-
error = re.read
|
|
27
|
-
case error
|
|
28
|
-
when /Inappropriate ioctl for device/
|
|
29
|
-
raise Errno::ENOTTY, inspect
|
|
30
|
-
end
|
|
31
|
-
raise "stty command failed: #{error.chomp}"
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def raw(*, min: 1, time: nil, intr: nil)
|
|
37
|
-
saved = _io_console_stty('-g')
|
|
38
|
-
_io_console_stty('raw')
|
|
39
|
-
yield self
|
|
40
|
-
ensure
|
|
41
|
-
_io_console_stty(saved) if saved
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def raw!(*)
|
|
45
|
-
_io_console_stty('raw')
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def cooked(*)
|
|
49
|
-
saved = _io_console_stty('-g')
|
|
50
|
-
_io_console_stty('-raw')
|
|
51
|
-
yield self
|
|
52
|
-
ensure
|
|
53
|
-
_io_console_stty(saved) if saved
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def cooked!(*)
|
|
57
|
-
_io_console_stty('-raw')
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def echo=(echo)
|
|
61
|
-
_io_console_stty(echo ? 'echo' : '-echo')
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def echo?
|
|
65
|
-
(_io_console_stty('-a') =~ / -echo /) ? false : true
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def noecho
|
|
69
|
-
saved = _io_console_stty('-g')
|
|
70
|
-
_io_console_stty('-echo')
|
|
71
|
-
yield self
|
|
72
|
-
ensure
|
|
73
|
-
_io_console_stty(saved) if saved
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# Not all systems return same format of stty -a output
|
|
77
|
-
IEEE_STD_1003_2 = '(?<rows>\d+) rows; (?<columns>\d+) columns'
|
|
78
|
-
UBUNTU = 'rows (?<rows>\d+); columns (?<columns>\d+)'
|
|
79
|
-
|
|
80
|
-
def winsize
|
|
81
|
-
match = _io_console_stty('-a').match(/#{IEEE_STD_1003_2}|#{UBUNTU}/o)
|
|
82
|
-
[match[:rows].to_i, match[:columns].to_i]
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def winsize=(size)
|
|
86
|
-
size = size.to_ary unless size.kind_of?(Array)
|
|
87
|
-
sizelen = size.size
|
|
88
|
-
|
|
89
|
-
if sizelen != 2 && sizelen != 4
|
|
90
|
-
raise ArgumentError.new("wrong number of arguments (given #{sizelen}, expected 2 or 4)")
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
if sizelen == 4
|
|
94
|
-
warn "stty io/console does not support pixel winsize"
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
row, col, _, _ = size
|
|
98
|
-
|
|
99
|
-
_io_console_stty("rows #{row} cols #{col}")
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def iflush
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def oflush
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def ioflush
|
|
109
|
-
end
|
|
110
|
-
end
|