Module: TTY::Screen

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

Overview

Responsible for detecting terminal screen size

Constant Summary collapse

DEFAULT_SIZE =

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

The default terminal screen size

Returns:

  • (Array(Integer, Integer))
[27, 80].freeze
STDOUT_HANDLE =

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

The standard output handle

Returns:

  • (Integer)
0xFFFFFFF5
TIOCGWINSZ =

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

The get window size control code for Linux

Returns:

  • (Integer)
0x5413
TIOCGWINSZ_PPC =

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

The get window size control code for FreeBSD and macOS

Returns:

  • (Integer)
0x40087468
TIOCGWINSZ_SOL =

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

The get window size control code for Solaris

Returns:

  • (Integer)
0x5468
VERSION =
"0.8.2"

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.envEnumerable

The environment variables

Examples:

TTY::Screen.env
TTY::Screen.env = {"ROWS" => "51", "COLUMNS" => "211"}

Returns:

  • (Enumerable)


81
82
83
# File 'lib/tty/screen.rb', line 81

def env
  @env
end

.outputIO

The output stream with standard error as default

Examples:

TTY::Screen.output
TTY::Screen.output = $stdout

Returns:

  • (IO)


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

def output
  @output
end

Class Method Details

.colsInteger

Detect terminal screen width

Examples:

TTY::Screen.width # => 211

Returns:

  • (Integer)


134
135
136
# File 'lib/tty/screen.rb', line 134

def width
  size[1]
end

.columnsInteger

Detect terminal screen width

Examples:

TTY::Screen.width # => 211

Returns:

  • (Integer)


133
134
135
# File 'lib/tty/screen.rb', line 133

def width
  size[1]
end

.heightInteger

Detect terminal screen height

Examples:

TTY::Screen.height # => 51

Returns:

  • (Integer)


146
147
148
# File 'lib/tty/screen.rb', line 146

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 the ioctl call gets window size on any standard stream

Parameters:

  • control (Integer)

    the control code

  • buf (String)

    the window size buffer

Returns:

  • (Boolean)

    true if the ioctl call gets window size, false otherwise



331
332
333
334
335
336
337
# File 'lib/tty/screen.rb', line 331

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

.jruby?Object

.linesInteger

Detect terminal screen height

Examples:

TTY::Screen.height # => 51

Returns:

  • (Integer)


152
153
154
# File 'lib/tty/screen.rb', line 152

def height
  size[0]
end

.private_module_function(name) ⇒ void

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.

This method returns an undefined value.

Define module method as private



28
29
30
31
# File 'lib/tty/screen.rb', line 28

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

.rowsInteger

Detect terminal screen height

Examples:

TTY::Screen.height # => 51

Returns:

  • (Integer)


151
152
153
# File 'lib/tty/screen.rb', line 151

def height
  size[0]
end

.size(verbose: false) ⇒ Array(Integer, Integer)

Detect terminal screen size

Examples:

TTY::Screen.size # => [51, 211]

Returns:

  • (Array(Integer, Integer))

    the terminal screen size



106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/tty/screen.rb', line 106

def size(verbose: false)
  size_from_java(verbose: verbose) ||
  size_from_win_api(verbose: verbose) ||
  size_from_ioctl ||
  size_from_io_console(verbose: verbose) ||
  size_from_readline(verbose: verbose) ||
  size_from_tput ||
  size_from_stty ||
  size_from_env ||
  size_from_ansicon ||
  size_from_default
end

.size_from_ansiconArray(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 screen size from the ANSICON environment variable

Returns:

  • (Array(Integer, Integer), nil)

    the terminal screen size or nil



426
427
428
429
430
431
# File 'lib/tty/screen.rb', line 426

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

  size = [::Regexp.last_match(2).to_i, ::Regexp.last_match(1).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.

Detect terminal screen size from default

Returns:

  • (Array(Integer, Integer))


161
162
163
# File 'lib/tty/screen.rb', line 161

def size_from_default
  DEFAULT_SIZE
end

.size_from_envArray(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 screen size from environment variables

After executing Ruby code, when the user changes terminal screen size during code runtime, the code will not be notified, and hence will not see the new size reflected in its copy of LINES and COLUMNS environment variables.

Returns:

  • (Array(Integer, Integer), nil)

    the terminal screen size or nil



412
413
414
415
416
417
# File 'lib/tty/screen.rb', line 412

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: false) ⇒ 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 screen size from io-console

On Windows, the io-console falls back to reading environment variables. This means any user changes to the terminal screen size will not be reflected in the runtime of the Ruby application.

Parameters:

  • verbose (Boolean) (defaults to: false)

    the verbose mode, by default false

Returns:

  • (Array(Integer, Integer), nil)

    the terminal screen size or nil



249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/tty/screen.rb', line 249

def size_from_io_console(verbose: false)
  return unless output.tty?

  require "io/console" unless IO.method_defined?(:winsize)
  return unless output.respond_to?(:winsize)

  size = output.winsize
  size if nonzero_column?(size[1])
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_ioctlArray(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 screen size from ioctl

Returns:

  • (Array(Integer, Integer), nil)

    the terminal screen size or nil



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

def size_from_ioctl
  buffer = Array.new(TIOCGWINSZ_BUF_LEN, 0).pack(TIOCGWINSZ_BUF_FMT)

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

    rows, cols, = buffer.unpack(TIOCGWINSZ_BUF_FMT)
    [rows, cols] if nonzero_column?(cols)
  end
end

.size_from_java(verbose: false) ⇒ 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 screen size from Java

Parameters:

  • verbose (Boolean) (defaults to: false)

    the verbose mode, by default false

Returns:

  • (Array(Integer, Integer), nil)

    the terminal screen size or nil



221
222
223
224
225
226
227
228
229
230
# File 'lib/tty/screen.rb', line 221

def size_from_java(verbose: false)
  require "java"

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

.size_from_readline(verbose: false) ⇒ 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 screen size from readline

Parameters:

  • verbose (Boolean) (defaults to: false)

    the verbose mode, by default false

Returns:

  • (Array(Integer, Integer), nil)

    the terminal screen size or nil



353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/tty/screen.rb', line 353

def size_from_readline(verbose: false)
  return unless output.tty?

  require "readline" unless defined?(::Readline)
  return unless ::Readline.respond_to?(:get_screen_size)

  size = ::Readline.get_screen_size
  size if nonzero_column?(size[1])
rescue LoadError
  warn "no readline gem" if verbose
rescue NotImplementedError
end

.size_from_sttyArray(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 screen size from stty

Returns:

  • (Array(Integer, Integer), nil)

    the terminal screen size or nil



390
391
392
393
394
395
396
397
398
# File 'lib/tty/screen.rb', line 390

def size_from_stty
  return unless output.tty? && command_exist?("stty")

  out = run_command("stty", "size")
  return unless out

  size = out.split.map(&:to_i)
  size if nonzero_column?(size[1])
end

.size_from_tputArray(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 screen size from tput

Returns:

  • (Array(Integer, Integer), nil)

    the terminal screen size or nil



373
374
375
376
377
378
379
380
381
# File 'lib/tty/screen.rb', line 373

def size_from_tput
  return unless output.tty? && command_exist?("tput")

  lines = run_command("tput", "lines")
  return unless lines

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

.size_from_win_api(verbose: false) ⇒ 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 screen size from Windows API

Parameters:

  • verbose (Boolean) (defaults to: false)

    the verbose mode, by default false

Returns:

  • (Array(Integer, Integer), nil)

    the terminal screen size or nil



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/tty/screen.rb', line 183

def size_from_win_api(verbose: false)
  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]
  size if nonzero_column?(size[1] - 1)
rescue LoadError
  warn "no native fiddle module found" if verbose
rescue Fiddle::DLError
  # non windows platform or no kernel32 lib
end

.widthInteger

Detect terminal screen width

Examples:

TTY::Screen.width # => 211

Returns:

  • (Integer)


128
129
130
# File 'lib/tty/screen.rb', line 128

def width
  size[1]
end

.windows?Object

Instance Method Details

#command_exist?(command) ⇒ 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 a command exists

Parameters:

  • command (String)

    the command to check

Returns:

  • (Boolean)


442
443
444
445
446
447
448
449
# File 'lib/tty/screen.rb', line 442

def command_exist?(command)
  exts = env.fetch("PATHEXT", "").split(::File::PATH_SEPARATOR)
  env.fetch("PATH", "").split(::File::PATH_SEPARATOR).any? do |dir|
    file = ::File.join(dir, command)
    ::File.exist?(file) ||
      exts.any? { |ext| ::File.exist?("#{file}#{ext}") }
  end
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 a number is non-zero

Parameters:

  • column (Integer, String)

    the column to check

Returns:

  • (Boolean)


476
477
478
# File 'lib/tty/screen.rb', line 476

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

#run_command(*args) ⇒ String?

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.

Run command capturing the standard output

Parameters:

  • args (Array<String>)

    the command arguments

Returns:

  • (String, nil)

    the command output or nil



461
462
463
464
465
# File 'lib/tty/screen.rb', line 461

def run_command(*args)
  %x(#{args.join(" ")})
rescue IOError, SystemCallError
  nil
end