Module: Terminal::Ansi

Defined in:
lib/terminal/ansi.rb,
lib/terminal/ansi/attributes.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_S.keys

.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_S.keys

.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
118
# File 'lib/terminal/ansi.rb', line 95

def [](*attributes)
  return +'' if attributes.empty?
  "\e[#{
    attributes
      .map do |arg|
        case arg
        when String
          ATTRIBUTES[arg] || COLORS[arg] || _color(arg) || _invalid(arg)
        when Symbol
          ATTRIBUTES_S[arg] || COLORS_S[arg] || _color(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



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

def ansi?(str) = 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:



225
226
227
228
229
230
231
232
233
# File 'lib/terminal/ansi.rb', line 225

def bbcode(str)
  str = str.to_s
  return str.dup unless str.index('[')
  str.gsub(BBCODE) do |match_str|
    next match_str if (match = Regexp.last_match[1]).empty?
    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



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

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



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

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



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

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



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

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

.cursor_hideString

Hide cursor.

Returns:

  • (String)

    ANSI control code



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

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



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

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



360
361
362
363
# File 'lib/terminal/ansi.rb', line 360

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



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

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

.cursor_restore_posString

Restore saved cursor position.

Returns:

  • (String)

    ANSI control code



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

def cursor_restore_pos = +CURSOR_POS_RESTORE

.cursor_save_posString

Save current cursor position.

Returns:

  • (String)

    ANSI control code



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

def cursor_save_pos = +CURSOR_POS_SAVE

.cursor_showString

Show cursor.

Returns:

  • (String)

    ANSI control code



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

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



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

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:



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

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.

Returns:

  • (String)

    ANSI control code



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

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.

Parameters:

  • url (#to_s)

    URL to link to

  • text (#to_s)

    text to display for the link

Returns:

  • (String)

    ANSI control code



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

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:



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/terminal/ansi.rb', line 270

def plain(str)
  str = str.to_s
  unless str.index('[')
    return str.index("\e") ? str.gsub(TEST, '') : str.dup
  end
  str =
    str.gsub(BBCODE) do |match_str|
      next match_str if (match = Regexp.last_match[1]).empty?
      next "[#{match[1..]}]" if match[0] == '\\'
      next match_str if (match = match.split).empty?
      next if match.all? { ATTRIBUTES[_1] || COLORS[_1] || _color(_1) }
      match_str
    end
  str.index("\e") ? str.gsub!(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



293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/terminal/ansi.rb', line 293

def rainbow(str, frequency: 0.3, spread: 0.8, seed: 1.1)
  pos = -1
  str
    .to_s
    .chars
    .map! do |char|
      i = (seed + ((pos += 1) / spread)) * frequency
      "\e[38;2;#{(Math.sin(i) * 255).abs.to_i};" \
        "#{(Math.sin(i + PI2_THIRD) * 255).abs.to_i};" \
        "#{(Math.sin(i + PI4_THIRD) * 255).abs.to_i}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.

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



510
511
512
513
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
# File 'lib/terminal/ansi.rb', line 510

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, :center
      opts << 'v=2'
    end
    case horizontal
    when 0, :left
      opts << 'h=0'
    when 1, :right
      opts << 'h=1'
    when 2, :centered, :center
      opts << 'h=2'
    end
  end
  "\e]66;#{opts.join(':')};#{text}\a"
end

.screen_alternateString

Use alternative screen buffer.

Returns:

  • (String)

    ANSI control code



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

def screen_alternate = +SCREEN_ALTERNATE

.screen_alternate_offString

Do not longer use alternative screen buffer.

Returns:

  • (String)

    ANSI control code



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

def screen_alternate_off = +SCREEN_ALTERNATE_OFF

.screen_erase(part = :all) ⇒ String

Erase screen part.

Returns:

  • (String)

    ANSI control code



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

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



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

def screen_restore = +SCREEN_RESTORE

.screen_saveString

Safe current screen.

Returns:

  • (String)

    ANSI control code



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

def screen_save = +SCREEN_SAVE

.screen_scroll_down(lines = 1) ⇒ String

Scroll window given lines down.

Returns:

  • (String)

    ANSI control code



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

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



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

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

.tab_title(title) ⇒ String

Set tab title. This is not widely supported.

Parameters:

  • title (#to_s)

    text

Returns:

  • (String)

    ANSI control code



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

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

.title(title) ⇒ String

Set window title. This is not widely supported.

Parameters:

  • title (#to_s)

    text

Returns:

  • (String)

    ANSI control code



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

def title(title) = "\e]2;#{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:



179
180
181
182
183
184
185
186
187
# File 'lib/terminal/ansi.rb', line 179

def try_convert(attributes, separator: ' ')
  return unless attributes
  return if (attributes = attributes.to_s.split(separator)).empty?
  "\e[#{
    attributes
      .map! { ATTRIBUTES[_1] || COLORS[_1] || _color(_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:



245
246
247
248
249
250
251
252
253
254
255
# File 'lib/terminal/ansi.rb', line 245

def unbbcode(str)
  str = str.to_s
  return str.dup unless str.index('[')
  str.gsub(BBCODE) do |match_str|
    next match_str if (match = Regexp.last_match[1]).empty?
    next "[#{match[1..]}]" if match[0] == '\\'
    next match_str if (match = match.split).empty?
    next if match.all? { ATTRIBUTES[_1] || COLORS[_1] || _color(_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:



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

def undecorate(str)
  str = str.to_s
  str.index("\e") ? str.gsub(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:



195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/terminal/ansi.rb', line 195

def valid?(*attributes)
  attributes.all? do |arg|
    case arg
    when String
      ATTRIBUTES[arg] || COLORS[arg] || _color(arg)
    when Symbol
      ATTRIBUTES_S[arg] || COLORS_S[arg] || _color(arg)
    when (0..767)
      true
    end
  end
end