tty-screen 0.5.1 → 0.6.0
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/CHANGELOG.md +16 -0
- data/README.md +12 -8
- data/lib/tty/screen.rb +241 -35
- data/lib/tty/version.rb +5 -0
- data/lib/tty-screen.rb +1 -1
- data/spec/unit/height_width_spec.rb +31 -0
- data/spec/unit/size_spec.rb +124 -53
- data/tasks/console.rake +1 -0
- data/tty-screen.gemspec +3 -1
- metadata +6 -7
- data/lib/tty/screen/size.rb +0 -155
- data/lib/tty/screen/version.rb +0 -5
- data/spec/unit/new_spec.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dae2d40de8e2675bc91d26ec698d333bce317169
|
4
|
+
data.tar.gz: 2b26bc3794b5a6b05ff230b9202a11b59c60a8f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d16dba65921f31a54f1c5528e89597ab223c6aecc1dccec83d3c588ae6e7b341b643f98746be1236e5135513752a07fad79c2eccda26218fce8585742430d5d4
|
7
|
+
data.tar.gz: 4083a1c8b373ff2dbb64fb2856f8ab5c8c9bcab29974194666ab5db02cd206876027e44a80473625bdad4827fe6571134fe1cee15ad1953c7fe7ab75f076f40e
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.6.0] - 2017-10-29
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add #size_from_ioctl check for reading terminal size with Unix ioctl
|
7
|
+
* Add #size_from_java check for reading terminal size from Java on JRuby
|
8
|
+
* Add #size_from_win_api check for reading terminal size from Windows C API
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
* Change TTY::Screen to a module without any state
|
12
|
+
* Change to prefix all checks with `size` keyword
|
13
|
+
* Change gemspec to require ruby >= 2.0.0
|
14
|
+
* Remove #try_io_console and inline with io-console check
|
15
|
+
* Remove #default_size and replace with constant
|
16
|
+
* Remove TTY::Screen::Size class
|
17
|
+
|
3
18
|
## [v0.5.1] - 2017-10-26
|
4
19
|
|
5
20
|
### Changed
|
@@ -56,6 +71,7 @@
|
|
56
71
|
### Fixed
|
57
72
|
* Fix bug with screen detection from_io_console by @luxflux
|
58
73
|
|
74
|
+
[v0.6.0]: https://github.com/peter-murach/tty-screen/compare/v0.5.1...v0.6.0
|
59
75
|
[v0.5.1]: https://github.com/peter-murach/tty-screen/compare/v0.5.0...v0.5.1
|
60
76
|
[v0.5.0]: https://github.com/peter-murach/tty-screen/compare/v0.4.3...v0.5.0
|
61
77
|
[v0.4.3]: https://github.com/peter-murach/tty-screen/compare/v0.4.2...v0.4.3
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
|
18
18
|
> Terminal screen size detection which works on Linux, OS X and Windows/Cygwin platforms and supports MRI, JRuby and Rubinius interpreters.
|
19
19
|
|
20
|
-
**TTY::Screen** provides independent screen size detection component for [TTY](https://github.com/piotrmurach/tty) toolkit.
|
20
|
+
**TTY::Screen** provides independent terminal screen size detection component for [TTY](https://github.com/piotrmurach/tty) toolkit.
|
21
21
|
|
22
22
|
## Installation
|
23
23
|
|
@@ -40,19 +40,23 @@ Or install it yourself as:
|
|
40
40
|
**TTY::Screen** allows you to detect terminal screen size by calling `size` method which returns [height, width] tuple.
|
41
41
|
|
42
42
|
```ruby
|
43
|
-
|
44
|
-
|
45
|
-
screen.size # => [51, 280]
|
46
|
-
screen.width # => 280
|
47
|
-
screen.height # => 51
|
43
|
+
TTY::Screen.size # => [51, 280]
|
48
44
|
```
|
49
45
|
|
50
|
-
|
46
|
+
To read terminal width do:
|
51
47
|
|
52
48
|
```ruby
|
53
|
-
TTY::Screen.size # => [51, 280]
|
54
49
|
TTY::Screen.width # => 280
|
50
|
+
TTY::Screen.columns # => 280
|
51
|
+
TTY::Screen.cols # => 280
|
52
|
+
```
|
53
|
+
|
54
|
+
Similarly, to read terminal height do:
|
55
|
+
|
56
|
+
```ruby
|
55
57
|
TTY::Screen.height # => 51
|
58
|
+
TTY::Screen.rows # => 51
|
59
|
+
TTY::Screen.lines # => 51
|
56
60
|
```
|
57
61
|
|
58
62
|
## Contributing
|
data/lib/tty/screen.rb
CHANGED
@@ -1,66 +1,272 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# fronzen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'version'
|
3
4
|
|
4
5
|
module TTY
|
5
6
|
# Used for detecting screen properties
|
6
7
|
#
|
7
8
|
# @api public
|
8
|
-
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
module Screen
|
10
|
+
# Helper to define private functions
|
11
|
+
def self.private_module_function(name)
|
12
|
+
module_function(name)
|
13
|
+
private_class_method(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Default terminal size
|
14
17
|
#
|
15
18
|
# @api public
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
DEFAULT_SIZE = [27, 80].freeze
|
20
|
+
|
21
|
+
@env = ENV
|
22
|
+
@output = $stderr
|
23
|
+
|
24
|
+
class << self
|
25
|
+
attr_accessor :env
|
26
|
+
|
27
|
+
# Specifies an output stream
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
attr_accessor :output
|
20
31
|
end
|
21
32
|
|
33
|
+
# Get terminal rows and columns
|
34
|
+
#
|
35
|
+
# @return [Array[Integer, Integer]]
|
36
|
+
# return rows & columns
|
37
|
+
#
|
22
38
|
# @api public
|
23
|
-
def
|
24
|
-
|
39
|
+
def size
|
40
|
+
size = size_from_java
|
41
|
+
size ||= size_from_win_api
|
42
|
+
size ||= size_from_ioctl
|
43
|
+
size ||= size_from_io_console
|
44
|
+
size ||= size_from_readline
|
45
|
+
size ||= size_from_tput
|
46
|
+
size ||= size_from_stty
|
47
|
+
size ||= size_from_env
|
48
|
+
size ||= size_from_ansicon
|
49
|
+
size || DEFAULT_SIZE
|
25
50
|
end
|
51
|
+
module_function :size
|
26
52
|
|
27
|
-
|
28
|
-
def self.width
|
53
|
+
def width
|
29
54
|
size[1]
|
30
55
|
end
|
56
|
+
module_function :width
|
31
57
|
|
32
|
-
|
33
|
-
|
58
|
+
alias columns width
|
59
|
+
alias cols width
|
60
|
+
module_function :columns
|
61
|
+
module_function :cols
|
62
|
+
|
63
|
+
def height
|
34
64
|
size[0]
|
35
65
|
end
|
66
|
+
module_function :height
|
67
|
+
|
68
|
+
alias rows height
|
69
|
+
alias lines height
|
70
|
+
module_function :rows
|
71
|
+
module_function :lines
|
36
72
|
|
37
|
-
|
73
|
+
STDOUT_HANDLE = 0xFFFFFFF5
|
74
|
+
|
75
|
+
# Determine terminal size with a Windows native API
|
38
76
|
#
|
39
|
-
# @return [Array[Integer]]
|
77
|
+
# @return [nil, Array[Integer, Integer]]
|
40
78
|
#
|
41
|
-
# @api
|
42
|
-
def
|
43
|
-
|
79
|
+
# @api private
|
80
|
+
def size_from_win_api(verbose: nil)
|
81
|
+
require 'fiddle'
|
82
|
+
|
83
|
+
kernel32 = Fiddle::Handle.new('kernel32')
|
84
|
+
get_std_handle = Fiddle::Function.new(kernel32['GetStdHandle'],
|
85
|
+
[-Fiddle::TYPE_INT], Fiddle::TYPE_INT)
|
86
|
+
get_console_buffer_info = Fiddle::Function.new(
|
87
|
+
kernel32['GetConsoleScreenBufferInfo'],
|
88
|
+
[Fiddle::TYPE_LONG, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)
|
89
|
+
|
90
|
+
format = 'SSSSSssssSS'
|
91
|
+
buffer = ([0] * format.size).pack(format)
|
92
|
+
stdout_handle = get_std_handle.(STDOUT_HANDLE)
|
93
|
+
|
94
|
+
get_console_buffer_info.(stdout_handle, buffer)
|
95
|
+
_, _, _, _, _, left, top, right, bottom, = buffer.unpack(format)
|
96
|
+
[bottom - top + 1, right - left + 1]
|
97
|
+
rescue LoadError
|
98
|
+
warn 'no native fiddle module found' if verbose
|
99
|
+
rescue Fiddle::DLError
|
100
|
+
# non windows platform or no kernel32 lib
|
44
101
|
end
|
102
|
+
module_function :size_from_win_api
|
45
103
|
|
46
|
-
#
|
104
|
+
# Determine terminal size on jruby using native Java libs
|
47
105
|
#
|
48
|
-
# @return [Integer]
|
106
|
+
# @return [nil, Array[Integer, Integer]]
|
49
107
|
#
|
50
|
-
# @api
|
51
|
-
def
|
52
|
-
|
108
|
+
# @api private
|
109
|
+
def size_from_java(verbose: nil)
|
110
|
+
return unless jruby?
|
111
|
+
require 'java'
|
112
|
+
java_import 'jline.TerminalFactory'
|
113
|
+
terminal = TerminalFactory.get
|
114
|
+
[terminal.get_height, terminal.get_width]
|
115
|
+
rescue
|
116
|
+
warn 'failed to import java terminal package' if verbose
|
53
117
|
end
|
54
|
-
|
118
|
+
module_function :size_from_java
|
55
119
|
|
56
|
-
#
|
120
|
+
# Detect screen size by loading io/console lib
|
57
121
|
#
|
58
|
-
#
|
122
|
+
# On Windows io_console falls back to reading environment
|
123
|
+
# variables. This means any user changes to the terminal
|
124
|
+
# size won't be reflected in the runtime of the Ruby app.
|
59
125
|
#
|
60
|
-
# @
|
61
|
-
|
62
|
-
|
126
|
+
# @return [nil, Array[Integer, Integer]]
|
127
|
+
#
|
128
|
+
# @api private
|
129
|
+
def size_from_io_console(verbose: nil)
|
130
|
+
return if jruby?
|
131
|
+
require 'io/console'
|
132
|
+
|
133
|
+
begin
|
134
|
+
if @output.tty? && IO.method_defined?(:winsize)
|
135
|
+
size = @output.winsize
|
136
|
+
size if nonzero_column?(size[1])
|
137
|
+
end
|
138
|
+
rescue Errno::EOPNOTSUPP
|
139
|
+
# no support for winsize on output
|
140
|
+
end
|
141
|
+
rescue LoadError
|
142
|
+
warn 'no native io/console support or io-console gem' if verbose
|
143
|
+
end
|
144
|
+
module_function :size_from_io_console
|
145
|
+
|
146
|
+
TIOCGWINSZ = 0x5413
|
147
|
+
TIOCGWINSZ_PPC = 0x40087468
|
148
|
+
|
149
|
+
# Read terminal size from Unix ioctl
|
150
|
+
#
|
151
|
+
# @return [nil, Array[Integer, Integer]]
|
152
|
+
#
|
153
|
+
# @api private
|
154
|
+
def size_from_ioctl
|
155
|
+
return if jruby?
|
156
|
+
return unless @output.respond_to?(:ioctl)
|
157
|
+
|
158
|
+
format = 'SSSS'
|
159
|
+
buffer = ([0] * format.size).pack(format)
|
160
|
+
if ioctl?(TIOCGWINSZ, buffer) || ioctl?(TIOCGWINSZ_PPC, buffer)
|
161
|
+
rows, cols, = buffer.unpack(format)[0..1]
|
162
|
+
return [rows, cols]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
module_function :size_from_ioctl
|
166
|
+
|
167
|
+
def ioctl?(control, buf)
|
168
|
+
@output.ioctl(control, buf) >= 0
|
169
|
+
rescue Errno::ENOTTY
|
170
|
+
# wrong processor architecture
|
171
|
+
false
|
172
|
+
rescue Errno::EINVAL
|
173
|
+
# ioctl failed to recognise processor type(not Intel)
|
174
|
+
false
|
175
|
+
end
|
176
|
+
module_function :ioctl?
|
177
|
+
|
178
|
+
# Detect screen size using Readline
|
179
|
+
#
|
180
|
+
# @api private
|
181
|
+
def size_from_readline
|
182
|
+
if defined?(Readline) && Readline.respond_to?(:get_screen_size)
|
183
|
+
size = Readline.get_screen_size
|
184
|
+
size if nonzero_column?(size[1])
|
185
|
+
end
|
186
|
+
rescue NotImplementedError
|
187
|
+
end
|
188
|
+
module_function :size_from_readline
|
189
|
+
|
190
|
+
# Detect terminal size from tput utility
|
191
|
+
#
|
192
|
+
# @api private
|
193
|
+
def size_from_tput
|
194
|
+
return unless @output.tty?
|
195
|
+
lines = run_command('tput', 'lines').to_i
|
196
|
+
cols = run_command('tput', 'cols').to_i
|
197
|
+
[lines, cols] if nonzero_column?(lines)
|
198
|
+
rescue Errno::ENOENT
|
199
|
+
end
|
200
|
+
module_function :size_from_tput
|
201
|
+
|
202
|
+
# Detect terminal size from stty utility
|
203
|
+
#
|
204
|
+
# @api private
|
205
|
+
def size_from_stty
|
206
|
+
return unless @output.tty?
|
207
|
+
out = run_command('stty', 'size')
|
208
|
+
return unless out
|
209
|
+
size = out.split.map(&:to_i)
|
210
|
+
size if nonzero_column?(size[1])
|
211
|
+
rescue Errno::ENOENT
|
212
|
+
end
|
213
|
+
module_function :size_from_stty
|
214
|
+
|
215
|
+
# Detect terminal size from environment
|
216
|
+
#
|
217
|
+
# After executing Ruby code if the user changes terminal
|
218
|
+
# dimensions during code runtime, the code won't be notified,
|
219
|
+
# and hence won't see the new dimensions reflected in its copy
|
220
|
+
# of LINES and COLUMNS environment variables.
|
221
|
+
#
|
222
|
+
# @return [nil, Array[Integer, Integer]]
|
223
|
+
#
|
224
|
+
# @api private
|
225
|
+
def size_from_env
|
226
|
+
return unless @env['COLUMNS'] =~ /^\d+$/
|
227
|
+
size = [(@env['LINES'] || @env['ROWS']).to_i, @env['COLUMNS'].to_i]
|
228
|
+
size if nonzero_column?(size[1])
|
229
|
+
end
|
230
|
+
module_function :size_from_env
|
231
|
+
|
232
|
+
# Detect terminal size from Windows ANSICON
|
233
|
+
#
|
234
|
+
# @api private
|
235
|
+
def size_from_ansicon
|
236
|
+
return unless @env['ANSICON'] =~ /\((.*)x(.*)\)/
|
237
|
+
size = [$2, $1].map(&:to_i)
|
238
|
+
size if nonzero_column?(size[1])
|
239
|
+
end
|
240
|
+
module_function :size_from_ansicon
|
241
|
+
|
242
|
+
# Runs command silently capturing the output
|
243
|
+
#
|
244
|
+
# @api private
|
245
|
+
def run_command(*args)
|
246
|
+
require 'tempfile'
|
247
|
+
out = Tempfile.new('tty-screen')
|
248
|
+
result = system(*args, out: out.path)
|
249
|
+
return if result.nil?
|
250
|
+
out.rewind
|
251
|
+
out.read
|
252
|
+
ensure
|
253
|
+
out.close if out
|
254
|
+
end
|
255
|
+
private_module_function :run_command
|
256
|
+
|
257
|
+
# Check if number is non zero
|
258
|
+
#
|
259
|
+
# return [Boolean]
|
260
|
+
#
|
261
|
+
# @api private
|
262
|
+
def nonzero_column?(column)
|
263
|
+
column.to_i > 0
|
264
|
+
end
|
265
|
+
private_module_function :nonzero_column?
|
266
|
+
|
267
|
+
def jruby?
|
268
|
+
RbConfig::CONFIG['ruby_install_name'] == 'jruby'
|
63
269
|
end
|
64
|
-
|
270
|
+
private_module_function :jruby?
|
65
271
|
end # Screen
|
66
272
|
end # TTY
|
data/lib/tty/version.rb
ADDED
data/lib/tty-screen.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
require_relative 'tty/screen'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
RSpec.describe TTY::Screen, '#height,#width' do
|
2
|
+
it "calcualtes screen width" do
|
3
|
+
allow(TTY::Screen).to receive(:size).and_return([51, 280])
|
4
|
+
expect(TTY::Screen.width).to eq(280)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "aliases width to columns" do
|
8
|
+
allow(TTY::Screen).to receive(:size).and_return([51, 280])
|
9
|
+
expect(TTY::Screen.columns).to eq(280)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "aliases width to cols" do
|
13
|
+
allow(TTY::Screen).to receive(:size).and_return([51, 280])
|
14
|
+
expect(TTY::Screen.cols).to eq(280)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "calcualtes screen height" do
|
18
|
+
allow(TTY::Screen).to receive(:size).and_return([51, 280])
|
19
|
+
expect(TTY::Screen.height).to eq(51)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "aliases width to rows" do
|
23
|
+
allow(TTY::Screen).to receive(:size).and_return([51, 280])
|
24
|
+
expect(TTY::Screen.rows).to eq(51)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "aliases width to lines" do
|
28
|
+
allow(TTY::Screen).to receive(:size).and_return([51, 280])
|
29
|
+
expect(TTY::Screen.lines).to eq(51)
|
30
|
+
end
|
31
|
+
end
|
data/spec/unit/size_spec.rb
CHANGED
@@ -1,34 +1,77 @@
|
|
1
1
|
require 'delegate'
|
2
2
|
|
3
|
-
RSpec.describe TTY::Screen
|
3
|
+
RSpec.describe TTY::Screen, '#size' do
|
4
4
|
class Output < SimpleDelegator
|
5
5
|
def winsize
|
6
6
|
[100, 200]
|
7
7
|
end
|
8
|
+
|
9
|
+
def ioctl(control, buf)
|
10
|
+
buf.replace("3\x00\xD3\x00\xF2\x04\xCA\x02\x00")
|
11
|
+
0
|
12
|
+
end
|
8
13
|
end
|
9
14
|
|
10
15
|
let(:output) { Output.new(StringIO.new('', 'w+')) }
|
11
16
|
|
12
17
|
context 'size' do
|
13
18
|
it "correctly falls through choices" do
|
14
|
-
screen =
|
15
|
-
|
16
|
-
|
19
|
+
screen = TTY::Screen
|
20
|
+
old_output = screen.output
|
21
|
+
screen.output = output
|
22
|
+
|
23
|
+
allow(screen).to receive(:size_from_java).and_return(nil)
|
24
|
+
allow(screen).to receive(:size_from_win_api).and_return(nil)
|
25
|
+
allow(screen).to receive(:size_from_ioctl).and_return(nil)
|
26
|
+
allow(screen).to receive(:size_from_io_console).and_return([51, 280])
|
27
|
+
allow(screen).to receive(:size_from_readline).and_return(nil)
|
17
28
|
|
18
29
|
expect(screen.size).to eq([51, 280])
|
19
|
-
expect(screen).
|
30
|
+
expect(screen).to have_received(:size_from_java)
|
31
|
+
expect(screen).to have_received(:size_from_win_api)
|
32
|
+
expect(screen).to have_received(:size_from_ioctl)
|
33
|
+
expect(screen).to_not have_received(:size_from_readline)
|
34
|
+
|
35
|
+
screen.output = old_output
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "size from java" do
|
40
|
+
it "doesn't import java on non-jruby platform" do
|
41
|
+
screen = TTY::Screen
|
42
|
+
allow(screen).to receive(:jruby?).and_return(false)
|
43
|
+
expect(screen.size_from_java).to eq(nil)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "imports java library on jruby" do
|
47
|
+
screen = TTY::Screen
|
48
|
+
class << screen
|
49
|
+
def java_import(*args); end
|
50
|
+
end
|
51
|
+
terminal = double(:terminal, get_height: 51, get_width: 211)
|
52
|
+
factory = double(:factory, get: terminal)
|
53
|
+
stub_const("TTY::Screen::TerminalFactory", factory)
|
54
|
+
|
55
|
+
allow(screen).to receive(:jruby?).and_return(true)
|
56
|
+
allow(screen).to receive(:require).with('java').and_return(true)
|
57
|
+
allow(screen).to receive(:java_import)
|
58
|
+
|
59
|
+
expect(screen.size_from_java).to eq([51, 211])
|
20
60
|
end
|
21
61
|
end
|
22
62
|
|
23
63
|
context 'from io console' do
|
24
64
|
it "doesn't calculate size if jruby " do
|
25
|
-
screen =
|
65
|
+
screen = TTY::Screen
|
26
66
|
allow(screen).to receive(:jruby?).and_return(true)
|
27
|
-
expect(screen.
|
67
|
+
expect(screen.size_from_io_console).to eq(nil)
|
28
68
|
end
|
29
69
|
|
30
70
|
it "calcualtes the size" do
|
31
|
-
screen =
|
71
|
+
screen = TTY::Screen
|
72
|
+
old_output = screen.output
|
73
|
+
screen.output = output
|
74
|
+
|
32
75
|
allow(screen).to receive(:jruby?).and_return(false)
|
33
76
|
allow(screen).to receive(:require).with('io/console').
|
34
77
|
and_return(true)
|
@@ -36,118 +79,146 @@ RSpec.describe TTY::Screen::Size, '#size' do
|
|
36
79
|
allow(IO).to receive(:method_defined?).with(:winsize).and_return(true)
|
37
80
|
allow(output).to receive(:winsize).and_return([100, 200])
|
38
81
|
|
39
|
-
expect(screen.
|
82
|
+
expect(screen.size_from_io_console).to eq([100, 200])
|
40
83
|
expect(output).to have_received(:winsize)
|
84
|
+
|
85
|
+
screen.output = old_output
|
41
86
|
end
|
42
87
|
|
43
88
|
it "doesn't calculate size if io/console not available" do
|
44
|
-
screen =
|
89
|
+
screen = TTY::Screen
|
45
90
|
allow(screen).to receive(:jruby?).and_return(false)
|
46
91
|
allow(screen).to receive(:require).with('io/console').
|
47
92
|
and_raise(LoadError)
|
48
|
-
expect(screen.
|
93
|
+
expect(screen.size_from_io_console).to eq(nil)
|
49
94
|
end
|
50
95
|
|
51
96
|
it "doesn't calculate size if it is run without a console" do
|
52
|
-
screen =
|
97
|
+
screen = TTY::Screen
|
53
98
|
allow(screen).to receive(:jruby?).and_return(false)
|
54
99
|
allow(screen).to receive(:require).with('io/console').
|
55
100
|
and_return(true)
|
56
|
-
allow(output).to receive(:tty?).and_return(true)
|
101
|
+
allow(screen.output).to receive(:tty?).and_return(true)
|
57
102
|
allow(IO).to receive(:method_defined?).with(:winsize).and_return(false)
|
58
|
-
expect(screen.
|
103
|
+
expect(screen.size_from_io_console).to eq(nil)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "from ioctl" do
|
108
|
+
it "reads terminal size" do
|
109
|
+
screen = TTY::Screen
|
110
|
+
old_output = screen.output
|
111
|
+
screen.output = output
|
112
|
+
allow(screen).to receive(:jruby?).and_return(false)
|
113
|
+
expect(screen.size_from_ioctl).to eq([51, 211])
|
114
|
+
screen.output = old_output
|
115
|
+
end
|
116
|
+
|
117
|
+
it "skips reading on jruby" do
|
118
|
+
allow(TTY::Screen).to receive(:jruby?).and_return(true)
|
119
|
+
expect(TTY::Screen.size_from_ioctl).to eq(nil)
|
59
120
|
end
|
60
121
|
end
|
61
122
|
|
62
123
|
context 'from tput' do
|
63
124
|
it "doesn't run command if outside of terminal" do
|
64
|
-
|
65
|
-
|
66
|
-
expect(screen.from_tput).to eq(nil)
|
125
|
+
allow(TTY::Screen.output).to receive(:tty?).and_return(false)
|
126
|
+
expect(TTY::Screen.size_from_tput).to eq(nil)
|
67
127
|
end
|
68
128
|
|
69
129
|
it "runs tput commands" do
|
70
|
-
screen =
|
71
|
-
allow(output).to receive(:tty?).and_return(true)
|
130
|
+
screen = TTY::Screen
|
131
|
+
allow(screen.output).to receive(:tty?).and_return(true)
|
72
132
|
allow(screen).to receive(:run_command).with('tput', 'lines').and_return(51)
|
73
133
|
allow(screen).to receive(:run_command).with('tput', 'cols').and_return(280)
|
74
|
-
expect(screen.
|
134
|
+
expect(screen.size_from_tput).to eq([51, 280])
|
75
135
|
end
|
76
136
|
|
77
137
|
it "doesn't return zero size" do
|
78
|
-
screen =
|
79
|
-
allow(output).to receive(:tty?).and_return(true)
|
138
|
+
screen = TTY::Screen
|
139
|
+
allow(screen.output).to receive(:tty?).and_return(true)
|
80
140
|
allow(screen).to receive(:run_command).with('tput', 'lines').and_return(0)
|
81
141
|
allow(screen).to receive(:run_command).with('tput', 'cols').and_return(0)
|
82
|
-
expect(screen.
|
142
|
+
expect(screen.size_from_tput).to eq(nil)
|
83
143
|
end
|
84
144
|
end
|
85
145
|
|
86
|
-
context 'from stty' do
|
146
|
+
context 'size from stty' do
|
87
147
|
it "doesn't run command if outside of terminal" do
|
88
|
-
|
89
|
-
|
90
|
-
expect(screen.from_stty).to eq(nil)
|
148
|
+
allow(TTY::Screen.output).to receive(:tty?).and_return(false)
|
149
|
+
expect(TTY::Screen.size_from_stty).to eq(nil)
|
91
150
|
end
|
92
151
|
|
93
152
|
it "runs stty commands" do
|
94
|
-
screen =
|
95
|
-
allow(output).to receive(:tty?).and_return(true)
|
153
|
+
screen = TTY::Screen
|
154
|
+
allow(screen.output).to receive(:tty?).and_return(true)
|
96
155
|
allow(screen).to receive(:run_command).with('stty', 'size').and_return("51 280")
|
97
|
-
expect(screen.
|
156
|
+
expect(screen.size_from_stty).to eq([51, 280])
|
98
157
|
end
|
99
158
|
|
100
159
|
it "doesn't return zero size" do
|
101
|
-
screen =
|
102
|
-
allow(output).to receive(:tty?).and_return(true)
|
160
|
+
screen = TTY::Screen
|
161
|
+
allow(screen.output).to receive(:tty?).and_return(true)
|
103
162
|
allow(screen).to receive(:run_command).with('stty', 'size').and_return("0 0")
|
104
|
-
expect(screen.
|
163
|
+
expect(screen.size_from_stty).to eq(nil)
|
105
164
|
end
|
106
165
|
end
|
107
166
|
|
108
|
-
context 'from env' do
|
167
|
+
context 'size from env' do
|
109
168
|
it "doesn't calculate size without COLUMNS key" do
|
110
|
-
screen =
|
111
|
-
|
169
|
+
screen = TTY::Screen
|
170
|
+
old_env = screen.env
|
171
|
+
screen.env = {'COLUMNS' => nil}
|
172
|
+
expect(screen.size_from_env).to eq(nil)
|
173
|
+
screen.env = old_env
|
112
174
|
end
|
113
175
|
|
114
176
|
it "extracts lines and columns from environment" do
|
115
|
-
screen =
|
116
|
-
|
177
|
+
screen = TTY::Screen
|
178
|
+
old_env = screen.env
|
179
|
+
screen.env = {'COLUMNS' => '280', 'LINES' => '51'}
|
180
|
+
expect(screen.size_from_env).to eq([51, 280])
|
181
|
+
screen.env = old_env
|
117
182
|
end
|
118
183
|
|
119
184
|
it "doesn't return zero size" do
|
120
|
-
screen =
|
121
|
-
|
185
|
+
screen = TTY::Screen
|
186
|
+
old_env = screen.env
|
187
|
+
screen.env = {'COLUMNS' => '0', 'LINES' => '0'}
|
188
|
+
expect(screen.size_from_env).to eq(nil)
|
189
|
+
screen.env = old_env
|
122
190
|
end
|
123
191
|
end
|
124
192
|
|
125
193
|
context 'from ansicon' do
|
126
194
|
it "doesn't calculate size without ANSICON key" do
|
127
|
-
screen =
|
128
|
-
|
195
|
+
screen = TTY::Screen
|
196
|
+
old_env = screen.env
|
197
|
+
screen.env = {'ANSICON' => nil}
|
198
|
+
expect(screen.size_from_ansicon).to eq(nil)
|
199
|
+
screen.env = old_env
|
129
200
|
end
|
130
201
|
|
131
202
|
it "extracts lines and columns from environment" do
|
132
|
-
screen =
|
133
|
-
|
203
|
+
screen = TTY::Screen
|
204
|
+
old_env = screen.env
|
205
|
+
screen.env = {'ANSICON' => '(280x51)'}
|
206
|
+
expect(screen.size_from_ansicon).to eq([51, 280])
|
207
|
+
screen.env = old_env
|
134
208
|
end
|
135
209
|
|
136
210
|
it "doesn't return zero size" do
|
137
|
-
screen =
|
138
|
-
|
211
|
+
screen = TTY::Screen
|
212
|
+
old_env = screen.env
|
213
|
+
screen.env = {'ANSICON' => '(0x0)'}
|
214
|
+
expect(screen.size_from_ansicon).to eq(nil)
|
215
|
+
screen.env = old_env
|
139
216
|
end
|
140
217
|
end
|
141
218
|
|
142
219
|
context 'default size' do
|
143
220
|
it "suggests default terminal size" do
|
144
|
-
|
145
|
-
expect(screen.default_size).to eq([27, 80])
|
146
|
-
end
|
147
|
-
|
148
|
-
it "attempts to get default terminal size from environment" do
|
149
|
-
screen = described_class.new({'LINES' => 52, 'COLUMNS' => 200})
|
150
|
-
expect(screen.default_size).to eq([52, 200])
|
221
|
+
expect(TTY::Screen::DEFAULT_SIZE).to eq([27, 80])
|
151
222
|
end
|
152
223
|
end
|
153
224
|
end
|
data/tasks/console.rake
CHANGED
data/tty-screen.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'tty/
|
4
|
+
require 'tty/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'tty-screen'
|
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(spec)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.required_ruby_version = '>= 2.0.0'
|
22
|
+
|
21
23
|
spec.add_development_dependency 'bundler', '>= 1.5.0', '< 2.0'
|
22
24
|
spec.add_development_dependency 'rake', '~> 10.0'
|
23
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tty-screen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -64,10 +64,9 @@ files:
|
|
64
64
|
- appveyor.yml
|
65
65
|
- lib/tty-screen.rb
|
66
66
|
- lib/tty/screen.rb
|
67
|
-
- lib/tty/
|
68
|
-
- lib/tty/screen/version.rb
|
67
|
+
- lib/tty/version.rb
|
69
68
|
- spec/spec_helper.rb
|
70
|
-
- spec/unit/
|
69
|
+
- spec/unit/height_width_spec.rb
|
71
70
|
- spec/unit/size_spec.rb
|
72
71
|
- tasks/console.rake
|
73
72
|
- tasks/coverage.rake
|
@@ -85,7 +84,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
84
|
requirements:
|
86
85
|
- - ">="
|
87
86
|
- !ruby/object:Gem::Version
|
88
|
-
version:
|
87
|
+
version: 2.0.0
|
89
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
89
|
requirements:
|
91
90
|
- - ">="
|
@@ -100,5 +99,5 @@ summary: Terminal screen size detection which works on Linux, OS X and Windows/C
|
|
100
99
|
platforms and supports MRI, JRuby and Rubinius interpreters.
|
101
100
|
test_files:
|
102
101
|
- spec/spec_helper.rb
|
103
|
-
- spec/unit/
|
102
|
+
- spec/unit/height_width_spec.rb
|
104
103
|
- spec/unit/size_spec.rb
|
data/lib/tty/screen/size.rb
DELETED
@@ -1,155 +0,0 @@
|
|
1
|
-
module TTY
|
2
|
-
class Screen
|
3
|
-
class Size
|
4
|
-
# Initialize terminal size detection
|
5
|
-
#
|
6
|
-
# @api public
|
7
|
-
def initialize(env, options = {})
|
8
|
-
@env = env
|
9
|
-
@output = options.fetch(:output) { $stderr }
|
10
|
-
@verbose = options.fetch(:verbose) { false }
|
11
|
-
end
|
12
|
-
|
13
|
-
# Get terminal rows and columns
|
14
|
-
#
|
15
|
-
# @return [Array[Integer, Integer]]
|
16
|
-
# return rows & columns
|
17
|
-
#
|
18
|
-
# @api public
|
19
|
-
def size
|
20
|
-
size = from_io_console
|
21
|
-
size ||= from_readline
|
22
|
-
size ||= from_tput
|
23
|
-
size ||= from_stty
|
24
|
-
size ||= from_env
|
25
|
-
size ||= from_ansicon
|
26
|
-
size || default_size
|
27
|
-
end
|
28
|
-
|
29
|
-
# Detect screen size by loading io/console lib
|
30
|
-
#
|
31
|
-
# @return [Array[Integer, Integer]]
|
32
|
-
#
|
33
|
-
# @api private
|
34
|
-
def from_io_console
|
35
|
-
return if jruby?
|
36
|
-
try_io_console { |size| size if nonzero_column?(size[1]) }
|
37
|
-
end
|
38
|
-
|
39
|
-
# Attempts to load native console extension
|
40
|
-
#
|
41
|
-
# @return [Boolean, Array]
|
42
|
-
#
|
43
|
-
# @api private
|
44
|
-
def try_io_console
|
45
|
-
require 'io/console'
|
46
|
-
|
47
|
-
begin
|
48
|
-
if output.tty? && IO.method_defined?(:winsize)
|
49
|
-
yield output.winsize
|
50
|
-
end
|
51
|
-
rescue Errno::EOPNOTSUPP
|
52
|
-
# no support for winsize on output
|
53
|
-
end
|
54
|
-
rescue LoadError
|
55
|
-
warn 'no native io/console support or io-console gem' if @verbose
|
56
|
-
end
|
57
|
-
|
58
|
-
# Detect screen size using Readline
|
59
|
-
#
|
60
|
-
# @api private
|
61
|
-
def from_readline
|
62
|
-
if defined?(Readline) && Readline.respond_to?(:get_screen_size)
|
63
|
-
size = Readline.get_screen_size
|
64
|
-
size if nonzero_column?(size[1])
|
65
|
-
end
|
66
|
-
rescue NotImplementedError
|
67
|
-
end
|
68
|
-
|
69
|
-
# Detect terminal size from tput utility
|
70
|
-
#
|
71
|
-
# @api private
|
72
|
-
def from_tput
|
73
|
-
return unless output.tty?
|
74
|
-
lines = run_command('tput', 'lines').to_i
|
75
|
-
cols = run_command('tput', 'cols').to_i
|
76
|
-
[lines, cols] if nonzero_column?(lines)
|
77
|
-
rescue Errno::ENOENT
|
78
|
-
end
|
79
|
-
|
80
|
-
# Detect terminal size from stty utility
|
81
|
-
#
|
82
|
-
# @api private
|
83
|
-
def from_stty
|
84
|
-
return unless output.tty?
|
85
|
-
out = run_command('stty', 'size')
|
86
|
-
return unless out
|
87
|
-
size = out.split.map(&:to_i)
|
88
|
-
size if nonzero_column?(size[1])
|
89
|
-
rescue Errno::ENOENT
|
90
|
-
end
|
91
|
-
|
92
|
-
# Detect terminal size from environment
|
93
|
-
#
|
94
|
-
# @api private
|
95
|
-
def from_env
|
96
|
-
return unless @env['COLUMNS'] =~ /^\d+$/
|
97
|
-
size = [(@env['LINES'] || @env['ROWS']).to_i, @env['COLUMNS'].to_i]
|
98
|
-
size if nonzero_column?(size[1])
|
99
|
-
end
|
100
|
-
|
101
|
-
# Detect terminal size on windows
|
102
|
-
#
|
103
|
-
# @api private
|
104
|
-
def from_ansicon
|
105
|
-
return unless @env['ANSICON'] =~ /\((.*)x(.*)\)/
|
106
|
-
size = [$2, $1].map(&:to_i)
|
107
|
-
size if nonzero_column?(size[1])
|
108
|
-
end
|
109
|
-
|
110
|
-
# Default terminal size
|
111
|
-
#
|
112
|
-
# @api public
|
113
|
-
def default_size
|
114
|
-
[
|
115
|
-
@env['LINES'].to_i.nonzero? || 27,
|
116
|
-
@env['COLUMNS'].to_i.nonzero? || 80
|
117
|
-
]
|
118
|
-
end
|
119
|
-
|
120
|
-
# Specifies an output stream object
|
121
|
-
#
|
122
|
-
# @api public
|
123
|
-
attr_reader :output
|
124
|
-
|
125
|
-
private
|
126
|
-
|
127
|
-
# Runs command silently capturing the output
|
128
|
-
#
|
129
|
-
# @api private
|
130
|
-
def run_command(*args)
|
131
|
-
require 'tempfile'
|
132
|
-
out = Tempfile.new('tty-screen')
|
133
|
-
result = system(*args, out: out.path)
|
134
|
-
return if result.nil?
|
135
|
-
out.rewind
|
136
|
-
out.read
|
137
|
-
ensure
|
138
|
-
out.close if out
|
139
|
-
end
|
140
|
-
|
141
|
-
# Check if number is non zero
|
142
|
-
#
|
143
|
-
# return [Boolean]
|
144
|
-
#
|
145
|
-
# @api private
|
146
|
-
def nonzero_column?(column)
|
147
|
-
column.to_i > 0
|
148
|
-
end
|
149
|
-
|
150
|
-
def jruby?
|
151
|
-
RbConfig::CONFIG['ruby_install_name'] == 'jruby'
|
152
|
-
end
|
153
|
-
end # Size
|
154
|
-
end # Screen
|
155
|
-
end # TTY
|
data/lib/tty/screen/version.rb
DELETED
data/spec/unit/new_spec.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
RSpec.describe TTY::Screen, '.new' do
|
2
|
-
|
3
|
-
it "initializses size with defaults" do
|
4
|
-
allow(TTY::Screen::Size).to receive(:new)
|
5
|
-
TTY::Screen.new
|
6
|
-
expect(TTY::Screen::Size).to have_received(:new).
|
7
|
-
with(ENV, {output: $stderr, verbose: false})
|
8
|
-
end
|
9
|
-
|
10
|
-
it "initializes size with values" do
|
11
|
-
allow(TTY::Screen::Size).to receive(:new)
|
12
|
-
|
13
|
-
TTY::Screen.new(output: :output, verbose: true)
|
14
|
-
|
15
|
-
expect(TTY::Screen::Size).to have_received(:new).
|
16
|
-
with(ENV, output: :output, verbose: true)
|
17
|
-
end
|
18
|
-
|
19
|
-
it "delegates size call" do
|
20
|
-
size_instance = spy(:size)
|
21
|
-
allow(TTY::Screen::Size).to receive(:new).and_return(size_instance)
|
22
|
-
|
23
|
-
screen = described_class.new
|
24
|
-
screen.size
|
25
|
-
|
26
|
-
expect(size_instance).to have_received(:size)
|
27
|
-
end
|
28
|
-
|
29
|
-
it "calls size" do
|
30
|
-
size_instance = double(:size, size: [51, 280])
|
31
|
-
allow(TTY::Screen::Size).to receive(:new).and_return(size_instance)
|
32
|
-
|
33
|
-
expect(TTY::Screen.size).to eq([51, 280])
|
34
|
-
expect(TTY::Screen::Size).to have_received(:new).once
|
35
|
-
end
|
36
|
-
|
37
|
-
it "calls width" do
|
38
|
-
size_instance = double(:size, size: [51, 280])
|
39
|
-
allow(TTY::Screen::Size).to receive(:new).and_return(size_instance)
|
40
|
-
|
41
|
-
expect(TTY::Screen.width).to eq(280)
|
42
|
-
expect(TTY::Screen::Size).to have_received(:new).once
|
43
|
-
end
|
44
|
-
|
45
|
-
it "calls height" do
|
46
|
-
size_instance = double(:size, size: [51, 280])
|
47
|
-
allow(TTY::Screen::Size).to receive(:new).and_return(size_instance)
|
48
|
-
expect(TTY::Screen.height).to eq(51)
|
49
|
-
end
|
50
|
-
end
|