Module: Terminal::Ansi

Defined in:
lib/terminal/ansi.rb,
lib/terminal/ansi/named_colors.rb

Overview

Fast ANSI control code and BBCode processing.

Class Attribute Summary collapse

ANSI control code generator functions collapse

BBcode related functions collapse

Other tool functions collapse

Cursor manipulation collapse

Screen manipulation collapse

Other ANSI control functions collapse

Class Attribute Details

.attributesArray<Symbol> (readonly)

Supported attribute names.

Returns:

  • (Array<Symbol>)

    all attribute names

See Also:



15
# File 'lib/terminal/ansi.rb', line 15

def attributes = @attributes.dup

.colorsArray<Symbol> (readonly)

Supported 3/4-bit color names.

Returns:

  • (Array<Symbol>)

    all color names

See Also:



23
# File 'lib/terminal/ansi.rb', line 23

def colors = @colors.dup

.named_colorsArray<Symbol> (readonly)

Supported basic 24-bit (Kitty compatible) color names.

Returns:

  • (Array<Symbol>)

    all basic named_colors names

See Also:



31
# File 'lib/terminal/ansi.rb', line 31

def named_colors = NAMED_COLORS.keys.map!(&:to_sym)

Class Method Details

.[](*attributes) ⇒ String

Combine given ANSI attributes, colors, named_colors and color codes.

Colors can specified by their name for ANSI 3-bit and 4-bit colors. For 8-bit ANSI colors use 2-digit hexadecimal values 00...ff.

To use RGB ANSI colors (24-bit colors) specify 3-digit or 6-digit hexadecimal values 000...fff or 000000...ffffff. This represent the RRGGBB values (or RGB for short version) like you may known from CSS color notation.

To use a color as background color prefix the color attribute with bg_ or on_. To use a color as underline color prefix the color attribute with ul_. To clarify that a color attribute have to be used as foreground color use the prefix fg_.

Examples:

Valid Foreground Color Attributes

Terminal::Ansi[:yellow]
Terminal::Ansi[:fg_fab]
Terminal::Ansi[:fg_00aa00]
Terminal::Ansi[:af]
Terminal::Ansi[:fg_af]
Terminal::Ansi['#fab']
Terminal::Ansi['#00aa00']
Terminal::Ansi['lightblue']

Valid Background Color Attributes

Terminal::Ansi[:bg_yellow]
Terminal::Ansi[:bg_fab]
Terminal::Ansi[:bg_00aa00]
Terminal::Ansi[:bg_af]
Terminal::Ansi['bg#00aa00']
Terminal::Ansi['bg_lightblue']

Terminal::Ansi[:on_yellow]
Terminal::Ansi[:on_fab]
Terminal::Ansi[:on_00aa00]
Terminal::Ansi[:on_af]
Terminal::Ansi['on#00aa00']
Terminal::Ansi['on_lightblue']

Valid Underline Color Attributes

Terminal::Ansi[:underline, :ul_yellow]
Terminal::Ansi[:underline, :ul_fab]
Terminal::Ansi[:underline, :ul_00aa00]
Terminal::Ansi[:underline, :ul_fa]
Terminal::Ansi[:underline, :ul_bright_yellow]
Terminal::Ansi[:underline, 'ul#00aa00']
Terminal::Ansi['underline', 'ul_lightblue']

Combined attributes:

Terminal::Ansi[:bold, :italic, :bright_white, :on_0000cc]

Parameters:

  • attributes (Array<Symbol, String>)

    attribute names to be used

Returns:

  • (String)

    combined ANSI attributes

See Also:



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/terminal/ansi.rb', line 95

def [](*attributes)
  return +'' if attributes.empty?
  "\e[#{
    attributes
      .map do |arg|
        case arg
        when String
          @attr_map[arg] || _invalid(arg)
        when Symbol
          @attrs_map[arg] || _invalid(arg)
        when (0..255)
          "38;5;#{arg}"
        when (256..511)
          "48;5;#{arg - 256}"
        when (512..767)
          "58;5;#{arg - 512}"
        else
          _invalid(arg)
        end
      end
      .join(';')
  }m"
end

.ansi?(str) ⇒ true, false

Test if given String contains ANSI control codes.

Parameters:

  • str (#to_s)

    object to be tested

Returns:

  • (true, false)

    whether if attributes are found



123
# File 'lib/terminal/ansi.rb', line 123

def ansi?(str) = @re_test.match?(str.to_s)

.bbcode(str) ⇒ String

Replace embedded BBCode-like attributes with ANSI control codes.

Examples:

Terminal::Ansi.bbcode "[b]Bold[/b] Text"
# => "\e[1mBold\e[22m Text"

Parameters:

  • str (#to_s)

    string to be modified

Returns:

  • (String)

    string with ANSI attributes

See Also:



220
221
222
223
224
225
226
227
228
# File 'lib/terminal/ansi.rb', line 220

def bbcode(str)
  str = str.to_s
  return str.dup unless str.index('[')
  str.gsub(@re_bbcode) do |match_str|
    match = Regexp.last_match(1) or next match_str
    next "[#{match[1..]}]" if match[0] == '\\'
    try_convert(match) || match_str
  end
end

.cursor_back(columns = 1) ⇒ String

Move cursor given columns back.

Returns:

  • (String)

    ANSI control code



332
# File 'lib/terminal/ansi.rb', line 332

def cursor_back(columns = 1) = "\e[#{columns}D"

.cursor_column(column = 1) ⇒ String

Move cursor to given column in the current row.

Parameters:

  • column (Integer) (defaults to: 1)

    column index

Returns:

  • (String)

    ANSI control code



350
# File 'lib/terminal/ansi.rb', line 350

def cursor_column(column = 1) = "\e[#{column}G"

.cursor_down(lines = 1) ⇒ String

Move cursor given lines down.

Parameters:

  • lines (Integer) (defaults to: 1)

    number of lines to move

Returns:

  • (String)

    ANSI control code



320
# File 'lib/terminal/ansi.rb', line 320

def cursor_down(lines = 1) = "\e[#{lines}B"

.cursor_forward(columns = 1) ⇒ String

Move cursor given columns forward.

Parameters:

  • columns (Integer) (defaults to: 1)

    number of columns to move

Returns:

  • (String)

    ANSI control code



326
# File 'lib/terminal/ansi.rb', line 326

def cursor_forward(columns = 1) = "\e[#{columns}C"

.cursor_hideString

Hide cursor.

Returns:

  • (String)

    ANSI control code



370
# File 'lib/terminal/ansi.rb', line 370

def cursor_hide = +CURSOR_HIDE

.cursor_next_line(lines = 1) ⇒ String

Move cursor to the beginning of the given next line.

Returns:

  • (String)

    ANSI control code



338
# File 'lib/terminal/ansi.rb', line 338

def cursor_next_line(lines = 1) = "\e[#{lines}E"

.cursor_pos(row, column = nil) ⇒ String

Move to given row and column.

Parameters:

  • row (Integer)

    row index

  • column (Integer) (defaults to: nil)

    column index

Returns:

  • (String)

    ANSI control code



357
358
359
360
# File 'lib/terminal/ansi.rb', line 357

def cursor_pos(row, column = nil)
  return column ? "\e[;#{column}H" : "\e[H" unless row
  column ? "\e[#{row};#{column}H" : "\e[#{row}H"
end

.cursor_prev_line(lines = 1) ⇒ String

Move cursor to the beginning of the given previous line.

Returns:

  • (String)

    ANSI control code



344
# File 'lib/terminal/ansi.rb', line 344

def cursor_prev_line(lines = 1) = "\e[#{lines}F"

.cursor_restore_posString

Restore saved cursor position.

Returns:

  • (String)

    ANSI control code



380
# File 'lib/terminal/ansi.rb', line 380

def cursor_restore_pos = +CURSOR_POS_RESTORE

.cursor_save_posString

Save current cursor position.

Returns:

  • (String)

    ANSI control code



375
# File 'lib/terminal/ansi.rb', line 375

def cursor_save_pos = +CURSOR_POS_SAVE

.cursor_showString

Show cursor.

Returns:

  • (String)

    ANSI control code



365
# File 'lib/terminal/ansi.rb', line 365

def cursor_show = +CURSOR_SHOW

.cursor_up(lines = 1) ⇒ String

Move cursor given lines up.

Parameters:

  • lines (Integer) (defaults to: 1)

    number of lines to move

Returns:

  • (String)

    ANSI control code



314
# File 'lib/terminal/ansi.rb', line 314

def cursor_up(lines = 1) = "\e[#{lines}A"

.decorate(str, *attributes, reset: true) ⇒ String

Decorate given argument with ANSI attributes and colors.

Examples:

Terminal::Ansi.decorate(
  'Hello World!',
  :bold, :italic, :bright_white, :on_00c
)
# => "\e[1;3;97;48;2;0;0;204mHello World!\e[m"

Parameters:

  • str (#to_s)

    object to be decorated

  • attributes (Array<Symbol, String>)

    attribute names to be used

  • reset (true, false) (defaults to: true)

    whether to include reset code for ANSI attributes

Returns:

  • (String)

    str converted and decorated with the ANSI attributes

See Also:



141
142
143
144
# File 'lib/terminal/ansi.rb', line 141

def decorate(str, *attributes, reset: true)
  attributes = self[*attributes]
  attributes.empty? ? "#{str}" : "#{attributes}#{str}#{"\e[m" if reset}"
end

.line_erase(part = :all) ⇒ String

Erase part of line.

Parameters:

  • part (:to_end, :to_start, :all) (defaults to: :all)

    line part to erase

Returns:

  • (String)

    ANSI control code



449
450
451
452
453
454
455
456
457
458
459
460
# File 'lib/terminal/ansi.rb', line 449

def line_erase(part = :all)
  "\e[#{
    case part
    when :to_end
      # nop
    when :to_start
      '1'
    else # :all
      '2'
    end
  }K"
end

Create a hyperlink. This is not widely supported; works for Ghosty, iTerm2, Kitty, Rio, Tabby, WezTerm.

Parameters:

  • url (#to_s)

    URL to link to

  • text (#to_s)

    text to display for the link

Returns:

  • (String)

    ANSI control code



487
# File 'lib/terminal/ansi.rb', line 487

def link(url, text) = "\e]8;;#{url}\a#{text}\e]8;;\a"

.plain(str) ⇒ String

Remove any BBCode-like and/or ANSI attributes.

Parameters:

  • str (#to_s)

    string to be modified

Returns:

  • (String)

    string without BBCode and ANSI control codes.

See Also:



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/terminal/ansi.rb', line 265

def plain(str)
  str = str.to_s
  unless str.index('[')
    return str.index("\e") ? str.gsub(@re_test, '') : str.dup
  end
  str =
    str.gsub(@re_bbcode) do |match_str|
      match = Regexp.last_match(1) or next match_str
      next "[#{match[1..]}]" if match[0] == '\\'
      next match_str if (match = match.split).empty?
      next if match.all? { @attr_map[_1] }
      match_str
    end
  str.index("\e") ? str.gsub!(@re_test, '') : str
end

.rainbow(str, frequency: 0.3, spread: 0.8, seed: 1.1) ⇒ String

Create nice colored text.

Parameters:

  • str (#to_s)

    string to enrich with color

  • frequency (Float) (defaults to: 0.3)

    color change frequency

  • spread (Float) (defaults to: 0.8)

    number of chars with same color

  • seed (Float) (defaults to: 1.1)

    start index on sinus curve

Returns:

  • (String)

    fancy text



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/terminal/ansi.rb', line 288

def rainbow(str, frequency: 0.3, spread: 0.8, seed: 1.1)
  pos = -1
  @pi2_third ||= 2.0 * Math::PI / 3.0
  @pi4_third ||= 4.0 * Math::PI / 3.0
  str
    .to_s
    .chars
    .map! do |char|
      i = (seed + ((pos += 1) / spread)) * frequency
      "\e[38;2;#{(Math.sin(i) * 255).to_i.abs};" \
        "#{(Math.sin(i + @pi2_third) * 255).to_i.abs};" \
        "#{(Math.sin(i + @pi4_third) * 255).to_i.abs}m#{char}"
    end
    .join << RESET
end

.scale(text, scale: nil, width: nil, fracn: nil, fracd: nil, vertical: nil, horizontal: nil) ⇒ String

Create scaled text. It uses the text sizing protocol. This is not widely supported; works for Kitty.

Examples:

Double-height Greeting

Terminal::Ansi.scale('Hello Ruby!', scale: 2)

Half-height Greeting

Terminal::Ansi.scale('Hello Ruby!', fracn: 1, fracd: 2, vertical: :centered)

Parameters:

  • text (#to_s)

    text to scale

  • scale (Integer, nil) (defaults to: nil)

    overall scale size, range 1..7

  • width (Integer, nil) (defaults to: nil)

    with in cells, range 0..7

  • fracn (Integer, nil) (defaults to: nil)

    numerator for the fractional scale, range: 0..15

  • fracd (Integer, nil) (defaults to: nil)

    denominator for the fractional scale, range: 0..15, > fracn

  • vertical (:top, :bottom, :centered, nil) (defaults to: nil)

    vertical alignment to use for fractionally scaled text

  • horizontal (:left, :right, :centered, nil) (defaults to: nil)

    horizontal alignment to use for fractionally scaled text

Returns:

  • (String)

    ANSI control code



514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
# File 'lib/terminal/ansi.rb', line 514

def scale(
  text,
  scale: nil,
  width: nil,
  fracn: nil,
  fracd: nil,
  vertical: nil,
  horizontal: nil
)
  opts = scale ? ["s=#{scale.clamp(1, 7)}"] : []
  opts << "w=#{width.clamp(0, 7)}" if width
  if fracn
    opts << "n=#{fracn = fracn.clamp(0, 15)}"
    opts << "d=#{fracd.clamp(fracn + 1, 15)}" if fracd
    case vertical
    when 0, :top
      opts << 'v=0'
    when 1, :bottom
      opts << 'v=1'
    when 2, :centered
      opts << 'v=2'
    end
    case horizontal
    when 0, :left
      opts << 'h=0'
    when 1, :right
      opts << 'h=1'
    when 2, :centered
      opts << 'h=2'
    end
  end
  "\e]66;#{opts.join(':')};#{text}\a"
end

.screen_alternateString

Use alternative screen buffer.

Returns:

  • (String)

    ANSI control code



420
# File 'lib/terminal/ansi.rb', line 420

def screen_alternate = +SCREEN_ALTERNATE

.screen_alternate_offString

Do not longer use alternative screen buffer.

Returns:

  • (String)

    ANSI control code



425
# File 'lib/terminal/ansi.rb', line 425

def screen_alternate_off = +SCREEN_ALTERNATE_OFF

.screen_erase(part = :all) ⇒ String

Erase screen part.

Parameters:

  • part (:below, :above, :all, :scrollback) (defaults to: :all)

    screen part to erase

Returns:

  • (String)

    ANSI control code



392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/terminal/ansi.rb', line 392

def screen_erase(part = :all)
  "\e[#{
    case part
    when :below
      # nop
    when :above
      '1'
    when :scrollback
      '3'
    else # all
      '2'
    end
  }J"
end

.screen_restoreString

Restore current screen.

Returns:

  • (String)

    ANSI control code



415
# File 'lib/terminal/ansi.rb', line 415

def screen_restore = +SCREEN_RESTORE

.screen_saveString

Safe current screen.

Returns:

  • (String)

    ANSI control code



410
# File 'lib/terminal/ansi.rb', line 410

def screen_save = +SCREEN_SAVE

.screen_scroll_down(lines = 1) ⇒ String

Scroll window given lines down.

Returns:

  • (String)

    ANSI control code



437
# File 'lib/terminal/ansi.rb', line 437

def screen_scroll_down(lines = 1) = "\e[#{lines}T"

.screen_scroll_up(lines = 1) ⇒ String

Scroll window given lines up.

Parameters:

  • lines (Integer) (defaults to: 1)

    number of lines to scroll

Returns:

  • (String)

    ANSI control code



431
# File 'lib/terminal/ansi.rb', line 431

def screen_scroll_up(lines = 1) = "\e[#{lines}S"

.title(title) ⇒ String

Set (tab) title. This is not widely supported; works for Hyper, iTerm2, Kitty, MacOS Terminal, Tabby, WezTerm.

Parameters:

  • title (#to_s)

    text

Returns:

  • (String)

    ANSI control code



473
# File 'lib/terminal/ansi.rb', line 473

def title(title) = "\e]0;#{title}\a"

.try_convert(attributes, separator: ' ') ⇒ String?

Try to combine given ANSI attributes and colors. The attributes and colors have to be separated by given separator`.

Examples:

Valid Attribute String

Terminal::Ansi.try_convert('bold italic blink red on#00ff00')
# => "\e[1;3;5;31;48;2;0;255;0m"

Invalid Attribute String

Terminal::Ansi.try_convert('cool bold on green')
# => nil

Parameters:

  • attributes (#to_s)

    attributes separated by given separator

  • separator (String) (defaults to: ' ')

    attribute separator char

Returns:

  • (String)

    combined ANSI attributes

  • (nil)

    when string does not contain valid attributes

See Also:



178
179
180
181
182
# File 'lib/terminal/ansi.rb', line 178

def try_convert(attributes, separator: ' ')
  return unless attributes
  return if (attributes = attributes.to_s.split(separator)).empty?
  "\e[#{attributes.map! { @attr_map[_1] || return }.join(';')}m"
end

.unbbcode(str) ⇒ String

Remove embedded BBCode-like attributes.

Examples:

Terminal::Ansi.unbbcode "[b]Bold[/b] Text"
# => "Bold Text"

Parameters:

  • str (#to_s)

    string to be modified

Returns:

  • (String)

    string without BBCode

See Also:



240
241
242
243
244
245
246
247
248
249
250
# File 'lib/terminal/ansi.rb', line 240

def unbbcode(str)
  str = str.to_s
  return str.dup unless str.index('[')
  str.gsub(@re_bbcode) do |match_str|
    match = Regexp.last_match(1) or next match_str
    next "[#{match[1..]}]" if match[0] == '\\'
    next match_str if (match = match.split).empty?
    next if match.all? { @attr_map[_1] }
    match_str
  end
end

.undecorate(str) ⇒ String

Remove ANSI functions, attributes and colors from given string.

Examples:

Terminal::Ansi.undecorate("\e[1;3;97;48;2;0;0;204mHello World!\e[m")
# => "Hello World!"

Parameters:

  • str (#to_s)

    string to be modified

Returns:

  • (String)

    string without ANSI attributes

See Also:



156
157
158
159
# File 'lib/terminal/ansi.rb', line 156

def undecorate(str)
  str = str.to_s
  str.index("\e") ? str.gsub(@re_test, '') : str.dup
end

.valid?(*attributes) ⇒ true, false

Test if all given attributes are valid.

Parameters:

  • attributes (Array<Symbol, String>)

    attribute names to be used

Returns:

  • (true, false)

    whether if all given attributes are valid

See Also:



190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/terminal/ansi.rb', line 190

def valid?(*attributes)
  attributes.all? do |arg|
    case arg
    when String
      @attr_map[arg]
    when Symbol
      @attrs_map[arg]
    when (0..767)
      true
    end
  end
end