Module: Terminal

Defined in:
lib/terminal.rb,
lib/terminal/ansi.rb,
lib/terminal/text.rb,
lib/terminal/input.rb,
lib/terminal/detect.rb,
lib/terminal/version.rb,
lib/terminal/input/key_event.rb,
lib/terminal/text/char_width.rb,
lib/terminal/ansi/named_colors.rb

Overview

Terminal access with support for ANSI control codes and BBCode-like embedded text attribute syntax (see Ansi.bbcode).

It automagically detects whether your terminal supports ANSI features, like coloring (see Terminal.colors) or the CSIu protocol support (see Terminal.read_key_event and Terminal.input_mode). It calculates the display width for Unicode chars (see Text.width) and help you to display text with line formatting (see Text.each_line).

Defined Under Namespace

Modules: Ansi, Text Classes: KeyEvent

Constant Summary collapse

VERSION =

The version number of the gem.

'0.13.0'

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.ansi?Boolean (readonly)

Return true if the current terminal supports ANSI control codes. When the terminal does not support it, colors will return 2 and all output methods (<<, print, puts) will not forward ANSI control codes to the terminal, read_key_event will not support CSIu.

Returns:

  • (Boolean)

    whether ANSI control codes are supported



27
# File 'lib/terminal.rb', line 27

def ansi? = @ansi

.applicationSymbol? (readonly)

Terminal application identifier.

The detection supports a wide range of terminal emulators but may return nil if an unsupported terminal was found. These are the supported application IDs:

  • :alacritty,
  • :amiga,
  • :code_edit,
  • :dg_unix,
  • :fluent,
  • :ghostty,
  • :hpterm,
  • :hyper,
  • :iterm,
  • :macos,
  • :mintty,
  • :ms_terminal,
  • :ncr260,
  • :nsterm,
  • :rio,
  • :tabby,
  • :terminator,
  • :terminology,
  • :terminus,
  • :termite,
  • :tmux,
  • :vscode,
  • :vt100,
  • :warp,
  • :wezterm,
  • :wyse,
  • :xnuppc

Returns:

  • (Symbol, nil)

    the application identifier



65
# File 'lib/terminal.rb', line 65

def application = (@application ||= Detect.application)

.colorsInteger (readonly)

Number of supported colors. The detection checks various conditions to find the correct value. The most common values are

  • 16_777_216 for 24-bit encoding (true_color? return true)
  • 256 for 8-Bit encoding
  • 52 for some Unix terminals with an extended color palette
  • 8 for 3-/4-bit encoding
  • 2 if ANSI is not supported in general (ansi? return false)

Returns:

  • (Integer)

    number of supported colors



79
# File 'lib/terminal.rb', line 79

def colors = (@colors ||= ansi? ? Detect.colors : 2)

.columnsInteger

Screen column count. See size for support and detection details.

Returns:

  • (Integer)

    number of available columns



86
# File 'lib/terminal.rb', line 86

def columns = size[1]

.input_mode:csi_u, ... (readonly)

Supported input mode.

Returns:

  • (:csi_u)

    when CSIu protocol supported

  • (:legacy)

    for standard terminal

  • (:dumb)

    for non-interactive input (pipes etc.)

  • (:error)

    when input device is closed



20
21
22
# File 'lib/terminal/input.rb', line 20

def input_mode
  @input_mode ||= find_input_mode
end

.pos[Integer, Integer]?

Current cursor position. This is only available when ANSI is supported (ansi? return true).

Returns:

  • ([Integer, Integer])

    cursor position as rows and columns

  • (nil)

    for incompatible terminals



99
100
101
102
103
# File 'lib/terminal.rb', line 99

def pos
  @con&.cursor
rescue IOError
  @con = nil
end

.rowsInteger

Screen row count. See size for support and detection details.

Returns:

  • (Integer)

    number of available rows



117
# File 'lib/terminal.rb', line 117

def rows = size[0]

.size[Integer, Integer]

Screen size as a tuple of rows and columns.

If the terminal does not support the report of it's dimension or ANSI is not supported in general then environment variables COLUMNS and LINES will be used. If this failed [25, 80] will be returned as default.

Setting the terminal size is not widely supported.

Returns:

  • ([Integer, Integer])

    available screen size as rows and columns

See Also:



138
139
140
141
142
143
# File 'lib/terminal.rb', line 138

def size
  @size ||= @inf&.winsize || _default_size
rescue IOError
  @inf = nil
  @size = _default_size
end

.true_color?Boolean (readonly)

Returns whether true colors are supported.

Returns:

  • (Boolean)

    whether true colors are supported

See Also:



155
# File 'lib/terminal.rb', line 155

def true_color? = (colors == 16_777_216)

Class Method Details

.<<(object) ⇒ Terminal

Writes the given object to the terminal. Interprets embedded BBCode.

Parameters:

  • object (#to_s)

    object to write

Returns:



186
187
188
189
190
191
192
# File 'lib/terminal.rb', line 186

def <<(object)
  @out.write(Ansi.bbcode(object)) if @out && object != nil
  self
rescue IOError
  @out = nil
  self
end

.hide_cursorTerminal

Hide the cursor. Will not send the control code if the cursor is already hidden.

When you called hide_cursor n-times you need to call show_cursor n-times to show the cursor again.

Returns:



164
165
166
167
# File 'lib/terminal.rb', line 164

def hide_cursor
  _write(Ansi::CURSOR_HIDE) if ansi? && (@cc += 1) == 1
  self
end

Writes the given objects to the terminal. Optionally interprets embedded BBCode.

Parameters:

  • objects (Array<#to_s>)

    any number of objects to write

  • bbcode (true|false) (defaults to: true)

    whether to interpret embedded BBCode

Returns:

  • (nil)


200
201
202
203
204
205
206
207
# File 'lib/terminal.rb', line 200

def print(*objects, bbcode: true)
  return unless @out
  return @out.print(*objects) unless bbcode
  objects.each { @out.write(Ansi.bbcode(_1)) }
  nil
rescue IOError
  @out = nil
end

.puts(*objects, bbcode: true) ⇒ nil

Writes the given objects to the terminal. Writes a newline after each object that does not already end with a newline sequence in it's String represenation. If called without any arguments, writes a newline only.

Optionally interprets embedded BBCode.

Parameters:

  • objects (Array<#to_s>)

    any number of objects to write

  • bbcode (true|false) (defaults to: true)

    whether to interpret embedded BBCode

Returns:

  • (nil)


218
219
220
221
222
223
224
225
226
# File 'lib/terminal.rb', line 218

def puts(*objects, bbcode: true)
  return unless @out
  return @out.puts if objects.empty?
  return @out.puts(objects) unless bbcode
  objects.flatten!
  objects.empty? ? @out.puts : @out.puts(objects.map! { Ansi.bbcode(_1) })
rescue IOError
  @out = nil
end

.read_key(mode: :named) ⇒ String, ...

Deprecated.

Use rather read_key_event for better input handling.

Read next keyboard input.

The input will be returned as named key codes like "Ctrl+c" by default. This can be changed by mode.

Parameters:

  • mode (:named, :raw, :both) (defaults to: :named)

    modifies the result

Returns:

  • (String)

    key code ("as is") in :raw mode

  • (String)

    key name in :named mode

  • ([String, String])

    key code and key name in :both mode

  • (nil)

    in error case



36
37
38
39
40
41
# File 'lib/terminal/input.rb', line 36

def read_key(mode: :named)
  event = read_key_event or return
  return event.raw if mode == :raw
  key, name = event
  mode == :both ? [key, name] : name || key
end

.read_key_eventKeyEvent?

Read next KeyEvent from standard input.

Returns:

  • (KeyEvent)

    next event

  • (nil)

    in error case



47
48
49
50
51
52
53
54
55
56
57
# File 'lib/terminal/input.rb', line 47

def read_key_event
  case input_mode
  when :dumb
    raw = read_dumb or return
    opts = DUMB_KEYS[raw.ord] if raw.size == 1
    KeyEvent.new(raw, *opts)
  when :csi_u, :legacy
    # raw = with_mouse ? read_tty_with_mouse : read_tty
    KeyEvent[raw] if (raw = read_tty)
  end
end

.show_cursorTerminal

Show the cursor. Will not send the control code if the cursor is not hidden.

When you called hide_cursor n-times you need to call show_cursor n-times to show the cursor again.

Returns:



176
177
178
179
# File 'lib/terminal.rb', line 176

def show_cursor
  _write(Ansi::CURSOR_SHOW) if @cc > 0 && (@cc -= 1).zero?
  self
end