Module: TTY::Screen

Defined in:
lib/tty/screen.rb,
lib/tty/screen/version.rb

Overview

Used for detecting screen properties

Constant Summary collapse

DEFAULT_SIZE =

Default terminal size

[27, 80].freeze
STDOUT_HANDLE =
0xFFFFFFF5
TIOCGWINSZ =

linux

0x5413
TIOCGWINSZ_PPC =

macos, freedbsd, netbsd, openbsd

0x40087468
TIOCGWINSZ_SOL =

solaris

0x5468
VERSION =
"0.7.1"

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.cached_size_methodObject

Stores the current size method


40
41
42
# File 'lib/tty/screen.rb', line 40

def cached_size_method
  @cached_size_method
end

.envObject

Holds the environment variables


44
45
46
# File 'lib/tty/screen.rb', line 44

def env
  @env
end

.outputObject

Specifies an output stream


48
49
50
# File 'lib/tty/screen.rb', line 48

def output
  @output
end

Class Method Details

.colsObject


95
96
97
# File 'lib/tty/screen.rb', line 95

def width
  size[1]
end

.columnsObject


94
95
96
# File 'lib/tty/screen.rb', line 94

def width
  size[1]
end

.heightObject


99
100
101
# File 'lib/tty/screen.rb', line 99

def height
  size[0]
end

.ioctl?(control, buf) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if ioctl can be called and any of the streams is attached to a terminal.

Returns:

  • (Boolean)

    True if any of the streams is attached to a terminal, false otherwise.


230
231
232
233
234
235
236
# File 'lib/tty/screen.rb', line 230

def ioctl?(control, buf)
  ($stdout.ioctl(control, buf) >= 0) ||
  ($stdin.ioctl(control, buf) >= 0) ||
  ($stderr.ioctl(control, buf) >= 0)
rescue SystemCallError
  false
end

.linesObject


105
106
107
# File 'lib/tty/screen.rb', line 105

def height
  size[0]
end

.load_dep(name, message, verbose: false) ⇒ Object

Helper to load dependency


22
23
24
25
26
# File 'lib/tty/screen.rb', line 22

def self.load_dep(name, message, verbose: false)
  require(name)
rescue LoadError
  warn(message) if verbose
end

.private_module_function(name) ⇒ Object

Helper to define private functions


16
17
18
19
# File 'lib/tty/screen.rb', line 16

def self.private_module_function(name)
  module_function(name)
  private_class_method(name)
end

.rowsObject


104
105
106
# File 'lib/tty/screen.rb', line 104

def height
  size[0]
end

.sizeArray[Integer, Integer]

Get terminal rows and columns

Returns:

  • (Array[Integer, Integer])

    return rows and columns


57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/tty/screen.rb', line 57

def size
  return cached_size_method.() unless cached_size_method.nil?

  check_size(:size_from_java) ||
  check_size(:size_from_win_api) ||
  check_size(:size_from_ioctl) ||
  check_size(:size_from_io_console) ||
  check_size(:size_from_readline) ||
  check_size(:size_from_tput) ||
  check_size(:size_from_stty) ||
  check_size(:size_from_env) ||
  check_size(:size_from_ansicon) ||
  check_size(:size_from_default)
end

.size_from_ansiconObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Detect terminal size from Windows ANSICON


299
300
301
302
303
304
# File 'lib/tty/screen.rb', line 299

def size_from_ansicon
  return unless @env["ANSICON"] =~ /\((.*)x(.*)\)/

  size = [$2, $1].map(&:to_i)
  size if nonzero_column?(size[1])
end

.size_from_defaultArray[Integer, Integer]

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Default size for the terminal

Returns:

  • (Array[Integer, Integer])

114
115
116
# File 'lib/tty/screen.rb', line 114

def size_from_default
  DEFAULT_SIZE
end

.size_from_envnil, Array[Integer, Integer]

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Detect terminal size from environment

After executing Ruby code if the user changes terminal dimensions during code runtime, the code won't be notified, and hence won't see the new dimensions reflected in its copy of LINES and COLUMNS environment variables.

Returns:

  • (nil, Array[Integer, Integer])

288
289
290
291
292
293
# File 'lib/tty/screen.rb', line 288

def size_from_env
  return unless @env["COLUMNS"] =~ /^\d+$/

  size = [(@env["LINES"] || @env["ROWS"]).to_i, @env["COLUMNS"].to_i]
  size if nonzero_column?(size[1])
end

.size_from_io_console(verbose: nil) ⇒ nil, Array[Integer, Integer]

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Detect screen size by loading io/console lib

On Windows io_console falls back to reading environment variables. This means any user changes to the terminal size won't be reflected in the runtime of the Ruby app.

Returns:

  • (nil, Array[Integer, Integer])

181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/tty/screen.rb', line 181

def size_from_io_console(verbose: nil)
  return if jruby?

  require "io/console"

  if @output.tty? && IO.method_defined?(:winsize)
    size = @output.winsize
    size if nonzero_column?(size[1])
  end
rescue Errno::EOPNOTSUPP  # no support for winsize on output

rescue LoadError
  warn "no native io/console support or io-console gem" if verbose
end

.size_from_ioctlnil, Array[Integer, Integer]

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Read terminal size from Unix ioctl

Returns:

  • (nil, Array[Integer, Integer])

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/tty/screen.rb', line 206

def size_from_ioctl
  return if jruby?
  return unless @output.respond_to?(:ioctl)

  format = "SSSS"
  buffer = ([0] * format.size).pack(format)

  if ioctl?(TIOCGWINSZ, buffer) ||
     ioctl?(TIOCGWINSZ_PPC, buffer) ||
     ioctl?(TIOCGWINSZ_SOL, buffer)

    rows, cols, = buffer.unpack(format)[0..1]
    return [rows, cols] if nonzero_column?(cols)
  end
end

.size_from_java(verbose: nil) ⇒ nil, Array[Integer, Integer]

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Determine terminal size on jruby using native Java libs

Returns:

  • (nil, Array[Integer, Integer])

158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/tty/screen.rb', line 158

def size_from_java(verbose: nil)
  return unless jruby?

  require "java"

  java_import "jline.TerminalFactory"
  terminal = TerminalFactory.get
  size = [terminal.get_height, terminal.get_width]
  return size if nonzero_column?(size[1])
rescue
  warn "failed to import java terminal package" if verbose
end

.size_from_readlineObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Detect screen size using Readline


242
243
244
245
246
247
248
# File 'lib/tty/screen.rb', line 242

def size_from_readline
  if defined?(Readline) && Readline.respond_to?(:get_screen_size)
    size = Readline.get_screen_size
    size if nonzero_column?(size[1])
  end
rescue NotImplementedError
end

.size_from_sttyObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Detect terminal size from stty utility


267
268
269
270
271
272
273
274
275
# File 'lib/tty/screen.rb', line 267

def size_from_stty
  return unless @output.tty?

  out = run_command("stty", "size")
  return unless out
  size = out.split.map(&:to_i)
  size if nonzero_column?(size[1])
rescue IOError, SystemCallError
end

.size_from_tputObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Detect terminal size from tput utility


254
255
256
257
258
259
260
261
# File 'lib/tty/screen.rb', line 254

def size_from_tput
  return unless @output.tty?

  lines = run_command("tput", "lines").to_i
  cols  = run_command("tput", "cols").to_i
  [lines, cols] if nonzero_column?(lines)
rescue IOError, SystemCallError
end

.size_from_win_api(verbose: nil) ⇒ nil, Array[Integer, Integer]

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Determine terminal size with a Windows native API

Returns:

  • (nil, Array[Integer, Integer])

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
# File 'lib/tty/screen.rb', line 126

def size_from_win_api(verbose: nil)
  return unless windows?

  require "fiddle" unless defined?(Fiddle)

  kernel32 = Fiddle::Handle.new("kernel32")
  get_std_handle = Fiddle::Function.new(kernel32["GetStdHandle"],
                    [-Fiddle::TYPE_INT], Fiddle::TYPE_INT)
  get_console_buffer_info = Fiddle::Function.new(
    kernel32["GetConsoleScreenBufferInfo"],
    [Fiddle::TYPE_LONG, Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT)

  format        = "SSSSSssssSS"
  buffer        = ([0] * format.size).pack(format)
  stdout_handle = get_std_handle.(STDOUT_HANDLE)

  get_console_buffer_info.(stdout_handle, buffer)
  _, _, _, _, _, left, top, right, bottom, = buffer.unpack(format)
  size = [bottom - top + 1, right - left + 1]
  return size if nonzero_column?(size[1] - 1)
resuce LoadError
  warn "no native fiddle module found" if verbose
rescue Fiddle::DLError  # non windows platform or no kernel32 lib

end

.widthObject


89
90
91
# File 'lib/tty/screen.rb', line 89

def width
  size[1]
end

Instance Method Details

#check_size(method_name) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if a method returns a correct size and cache it

Parameters:

  • method_name (String)

78
79
80
81
82
83
84
85
86
# File 'lib/tty/screen.rb', line 78

def check_size(method_name)
  size_method = method(method_name.to_sym)
  size = size_method.()

  return if size.nil?

  self.cached_size_method = size_method
  size
end

#nonzero_column?(column) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if number is non zero

return [Boolean]

Returns:

  • (Boolean)

328
329
330
# File 'lib/tty/screen.rb', line 328

def nonzero_column?(column)
  column.to_i > 0
end

#run_command(*args) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Runs command silently capturing the output


310
311
312
313
314
315
316
317
318
319
320
# File 'lib/tty/screen.rb', line 310

def run_command(*args)
  require "tempfile" unless defined?(Tempfile)

  out = Tempfile.new("tty-screen")
  result = system(*args, out: out.path, err: File::NULL)
  return if result.nil?
  out.rewind
  out.read
ensure
  out.close if out
end