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.

See Also:



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

def attributes = ATTRIBUTES_S.keys

.colorsArray<Symbol> (readonly)

Supported 3/4-bit 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.

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]

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.



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"

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



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.



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.



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.



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

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

.cursor_hideString

Hide cursor.



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.



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.



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.



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

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

.cursor_restore_posString

Restore saved cursor position.



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

def cursor_restore_pos = +CURSOR_POS_RESTORE

.cursor_save_posString

Save current cursor position.



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

def cursor_save_pos = +CURSOR_POS_SAVE

.cursor_showString

Show cursor.



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

def cursor_show = +CURSOR_SHOW

.cursor_up(lines = 1) ⇒ String

Move cursor given lines up.



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"

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.



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

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.



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

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

.plain(str) ⇒ String

Remove any BBCode-like and/or ANSI attributes.

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|
      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? { 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.



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).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)


524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
# File 'lib/terminal/ansi.rb', line 524

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.



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

def screen_alternate = +SCREEN_ALTERNATE

.screen_alternate_offString

Do not longer use alternative screen buffer.



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

def screen_alternate_off = +SCREEN_ALTERNATE_OFF

.screen_erase(part = :all) ⇒ String

Erase screen part.



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

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.



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

def screen_restore = +SCREEN_RESTORE

.screen_saveString

Safe current screen.



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

def screen_save = +SCREEN_SAVE

.screen_scroll_down(lines = 1) ⇒ String

Scroll window given lines down.



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

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

.screen_scroll_up(lines = 1) ⇒ String

Scroll window given lines up.



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

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

.tab_title(title) ⇒ String

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



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

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

.title(title) ⇒ String

Set window title. This is not widely supported.



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

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

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"

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|
    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? { 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!"

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.

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