Module: Terminal::Ansi
- Defined in:
- lib/terminal/ansi.rb,
lib/terminal/ansi/named_colors.rb,
lib/terminal/ansi/screen_viewer.rb
Overview
ANSI escape code generation and BBCode-to-ANSI conversion.
Provides methods for text decoration, color, cursor control, screen manipulation, hyperlinks, notifications, and progress indicators. All methods return ANSI escape sequence strings — they do not write to the terminal directly.
Colors can be specified as named symbols, 256-color indices, hex strings, or CSS/X11 color names.
Defined Under Namespace
Classes: ScreenViewer
Class Attribute Summary collapse
-
.attributes ⇒ Array<Symbol>
readonly
All known text attribute names (bold, italic, underline, etc.).
-
.colors ⇒ Array<Symbol>
readonly
All known basic color names.
-
.named_colors ⇒ Array<Symbol>
readonly
All CSS/X11 named colors.
ANSI Control Code Generation collapse
-
.[](*attributes) ⇒ String
Generate an ANSI escape sequence from attribute names or color indices.
-
.char_repeat(count = 1) ⇒ String
Repeat the last printed character.
-
.cursor_back(columns = 1) ⇒ String
Move cursor left.
-
.cursor_column(column = 1) ⇒ String
Move cursor to absolute column.
-
.cursor_column_rel(column = 1) ⇒ String
Move cursor right by relative columns.
-
.cursor_down(lines = 1) ⇒ String
Move cursor down.
-
.cursor_forward(columns = 1) ⇒ String
Move cursor right.
-
.cursor_hide ⇒ String
Hide cursor.
-
.cursor_next_line(lines = 1) ⇒ String
Move cursor to beginning of line, N lines down.
-
.cursor_pos(row, column = nil) ⇒ String
Move cursor to absolute position.
-
.cursor_prev_line(lines = 1) ⇒ String
Move cursor to beginning of line, N lines up.
-
.cursor_restore_pos ⇒ String
Restore previously saved cursor position.
-
.cursor_row_rel(row = 1) ⇒ String
Move cursor down by relative rows.
-
.cursor_save_pos ⇒ String
Save current cursor position.
-
.cursor_show ⇒ String
Show cursor.
-
.cursor_up(lines = 1) ⇒ String
Move cursor up.
-
.decorate(str, *attributes, reset: true) ⇒ String
Wrap a string with ANSI escape codes.
-
.line_erase(part = :all) ⇒ String
Erase part of the current line.
-
.link(url, text, **params) ⇒ String
Create a complete hyperlink (OSC 8).
-
.link_end ⇒ String
End a hyperlink.
-
.link_start(url, **params) ⇒ String
Start a hyperlink (OSC 8).
-
.notify(text) ⇒ String
Send a desktop notification via the terminal.
-
.progress(state, percent = 0) ⇒ String
Show or update a progress indicator in the terminal tab/title bar.
-
.rainbow(str, frequency: 0.3, spread: 0.8, seed: 1.1) ⇒ String
Generate rainbow-colored text using true color (24-bit) ANSI codes.
-
.scale(text, scale: nil, width: nil, fracn: nil, fracd: nil, vertical: nil, horizontal: nil) ⇒ String
Scale text using the text sizing protocol.
-
.screen_alternate ⇒ String
Switch to the alternate screen buffer.
-
.screen_alternate_off ⇒ String
Switch back from the alternate screen buffer.
-
.screen_erase(part = :all) ⇒ String
Erase part of the screen.
-
.screen_restore ⇒ String
Restore previously saved screen state.
-
.screen_save ⇒ String
Save screen state.
-
.screen_scroll_down(lines = 1) ⇒ String
Scroll the screen down.
-
.screen_scroll_up(lines = 1) ⇒ String
Scroll the screen up.
-
.title(title) ⇒ String
Set the terminal window title.
-
.try_convert(attributes, separator: ' ') ⇒ String?
Try to convert a space-separated attribute string to an ANSI escape sequence.
-
.undecorate(str) ⇒ String
Remove all ANSI escape codes from a string.
BBcode Generation collapse
-
.bbcode(str) ⇒ String
Convert BBCode markup to ANSI escape codes.
-
.escape_bbcode(str) ⇒ String
Escape BBCode tags so they render as literal text after Ansi.bbcode processing.
-
.unbbcode(str) ⇒ String
Remove BBCode tags from a string, keeping the enclosed text.
Tool Functions collapse
-
.ansi?(str) ⇒ true, false
Test whether a string contains ANSI escape codes.
-
.plain(str) ⇒ String
Remove both BBCode tags and ANSI escape codes, returning plain text.
-
.valid?(*attributes) ⇒ true, false
Check whether all given attributes are valid.
Class Attribute Details
.attributes ⇒ Array<Symbol> (readonly)
All known text attribute names (bold, italic, underline, etc.).
27 |
# File 'lib/terminal/ansi.rb', line 27 def attributes = @attributes.dup |
.colors ⇒ Array<Symbol> (readonly)
All known basic color names.
33 |
# File 'lib/terminal/ansi.rb', line 33 def colors = @colors.dup |
.named_colors ⇒ Array<Symbol> (readonly)
All CSS/X11 named colors.
39 |
# File 'lib/terminal/ansi.rb', line 39 def named_colors = NAMED_COLORS.keys.map!(&:to_sym) |
Class Method Details
.[](*attributes) ⇒ String
Generate an ANSI escape sequence from attribute names or color indices.
Accepts symbols (:bold, +:red+), strings ("bold", +"#ff0000"+),
or integers for 256-color palette (0-255 foreground, 256-511
background, 512-767 underline color).
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/terminal/ansi.rb', line 65 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 whether a string contains ANSI escape codes.
259 |
# File 'lib/terminal/ansi.rb', line 259 def ansi?(str) = @re_test.match?(str.to_s) |
.bbcode(str) ⇒ String
Convert BBCode markup to ANSI escape codes.
Tags like +[bold]+ are converted to their ANSI equivalents; +[/bold]+ or +[/]+ resets. Unknown tags are left unchanged. Escape a tag with a backslash: +[\bold]+ renders as +[bold]+.
186 187 188 189 190 191 192 193 194 195 |
# File 'lib/terminal/ansi.rb', line 186 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 try_convert(match) || match_str if match[0] != '\\' match[0] = '' "[#{match}]" end end |
.char_repeat(count = 1) ⇒ String
Repeat the last printed character.
447 |
# File 'lib/terminal/ansi.rb', line 447 def char_repeat(count = 1) = "\e[#{count}b" |
.cursor_back(columns = 1) ⇒ String
Move cursor left.
326 |
# File 'lib/terminal/ansi.rb', line 326 def cursor_back(columns = 1) = "\e[#{columns}D" |
.cursor_column(column = 1) ⇒ String
Move cursor to absolute column.
344 |
# File 'lib/terminal/ansi.rb', line 344 def cursor_column(column = 1) = "\e[#{column}G" |
.cursor_column_rel(column = 1) ⇒ String
Move cursor right by relative columns.
350 |
# File 'lib/terminal/ansi.rb', line 350 def cursor_column_rel(column = 1) = "\e[#{column}a" |
.cursor_down(lines = 1) ⇒ String
Move cursor down.
314 |
# File 'lib/terminal/ansi.rb', line 314 def cursor_down(lines = 1) = "\e[#{lines}B" |
.cursor_forward(columns = 1) ⇒ String
Move cursor right.
320 |
# File 'lib/terminal/ansi.rb', line 320 def cursor_forward(columns = 1) = "\e[#{columns}C" |
.cursor_hide ⇒ String
Hide cursor.
380 |
# File 'lib/terminal/ansi.rb', line 380 def cursor_hide = +CURSOR_HIDE |
.cursor_next_line(lines = 1) ⇒ String
Move cursor to beginning of line, N lines down.
332 |
# File 'lib/terminal/ansi.rb', line 332 def cursor_next_line(lines = 1) = "\e[#{lines}E" |
.cursor_pos(row, column = nil) ⇒ String
Move cursor to absolute position.
367 368 369 370 |
# File 'lib/terminal/ansi.rb', line 367 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 beginning of line, N lines up.
338 |
# File 'lib/terminal/ansi.rb', line 338 def cursor_prev_line(lines = 1) = "\e[#{lines}F" |
.cursor_restore_pos ⇒ String
Restore previously saved cursor position.
394 |
# File 'lib/terminal/ansi.rb', line 394 def cursor_restore_pos = +CURSOR_POS_RESTORE |
.cursor_row_rel(row = 1) ⇒ String
Move cursor down by relative rows.
356 |
# File 'lib/terminal/ansi.rb', line 356 def cursor_row_rel(row = 1) = "\e[#{row}e" |
.cursor_save_pos ⇒ String
Save current cursor position.
387 |
# File 'lib/terminal/ansi.rb', line 387 def cursor_save_pos = +CURSOR_POS_SAVE |
.cursor_show ⇒ String
Show cursor.
375 |
# File 'lib/terminal/ansi.rb', line 375 def cursor_show = +CURSOR_SHOW |
.cursor_up(lines = 1) ⇒ String
Move cursor up.
308 |
# File 'lib/terminal/ansi.rb', line 308 def cursor_up(lines = 1) = "\e[#{lines}A" |
.decorate(str, *attributes, reset: true) ⇒ String
Wrap a string with ANSI escape codes.
103 104 105 106 |
# File 'lib/terminal/ansi.rb', line 103 def decorate(str, *attributes, reset: true) attributes = self[*attributes] attributes.empty? ? "#{str}" : "#{attributes}#{str}#{"\e[m" if reset}" end |
.escape_bbcode(str) ⇒ String
Escape BBCode tags so they render as literal text after bbcode processing.
232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/terminal/ansi.rb', line 232 def escape_bbcode(str) str = str.to_s return str.dup unless str.index('[') str.gsub(@re_bbcode) do |match_str| fc = match_str[1] next match_str if fc == '\\' || fc == ']' match = Regexp.last_match(1) or next match_str next match_str if (parts = match.split).empty? next "[\\#{match}]" if parts.all? { @attr_map[it] } match_str end end |
.line_erase(part = :all) ⇒ String
Erase part of the current line.
454 |
# File 'lib/terminal/ansi.rb', line 454 def line_erase(part = :all) = "\e[#{@line_erase[part]}K" |
.link(url, text, **params) ⇒ String
Create a complete hyperlink (OSC 8).
499 500 501 |
# File 'lib/terminal/ansi.rb', line 499 def link(url, text, **params) "#{link_start(url, **params)}#{text}#{LINK_END}" end |
.link_end ⇒ String
End a hyperlink.
486 |
# File 'lib/terminal/ansi.rb', line 486 def link_end = +LINK_END |
.link_start(url, **params) ⇒ String
Supported by Ghostty, iTerm2, Kitty, Rio, Tabby, WezTerm.
Start a hyperlink (OSC 8).
477 478 479 |
# File 'lib/terminal/ansi.rb', line 477 def link_start(url, **params) "\e]8;#{params.map { it.join('=') }.join(':')};#{url}\a" end |
.notify(text) ⇒ String
Supported by Ghostty, iTerm2, Kitty, WezTerm.
Send a desktop notification via the terminal.
511 |
# File 'lib/terminal/ansi.rb', line 511 def notify(text) = "\e]9;#{text}\a" |
.plain(str) ⇒ String
Remove both BBCode tags and ANSI escape codes, returning plain text.
292 293 294 295 296 |
# File 'lib/terminal/ansi.rb', line 292 def plain(str) str = unbbcode(str) str.gsub!(@re_test, '') if str.index("\e") str end |
.progress(state, percent = 0) ⇒ String
Supported by Ghostty, iTerm2, Kitty.
Show or update a progress indicator in the terminal tab/title bar.
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 |
# File 'lib/terminal/ansi.rb', line 530 def progress(state, percent = 0) case state when :show, true state = 1 when :err, :error state = 2 when :warn, :warning state = 4 when Numeric percent, state = state, 1 when :indeterminate return +PROGRESS_SHOW_INDETERMINATE else return +PROGRESS_HIDE end "\e]9;4;#{state};#{percent.to_i.clamp(0, 100)}\a" end |
.rainbow(str, frequency: 0.3, spread: 0.8, seed: 1.1) ⇒ String
Generate rainbow-colored text using true color (24-bit) ANSI codes.
149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/terminal/ansi.rb', line 149 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).round.abs};#{ (Math.sin(i + @pi2_third) * 255).round.abs };#{(Math.sin(i + @pi4_third) * 255).round.abs}m#{char}" end << RESET_FG ).join end |
.scale(text, scale: nil, width: nil, fracn: nil, fracd: nil, vertical: nil, horizontal: nil) ⇒ String
Only supported by Kitty.
Scale text using the text sizing protocol.
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
# File 'lib/terminal/ansi.rb', line 570 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, :middle opts << 'v=2' end case horizontal when 0, :left opts << 'h=0' when 1, :right opts << 'h=1' when 2, :center opts << 'h=2' end end "\e]66;#{opts.join(':')};#{text}\a" end |
.screen_alternate ⇒ String
Switch to the alternate screen buffer.
422 |
# File 'lib/terminal/ansi.rb', line 422 def screen_alternate = +SCREEN_ALTERNATE |
.screen_alternate_off ⇒ String
Switch back from the alternate screen buffer.
429 |
# File 'lib/terminal/ansi.rb', line 429 def screen_alternate_off = +SCREEN_ALTERNATE_OFF |
.screen_erase(part = :all) ⇒ String
Erase part of the screen.
401 |
# File 'lib/terminal/ansi.rb', line 401 def screen_erase(part = :all) = "\e[#{@screen_erase[part]}J" |
.screen_restore ⇒ String
Restore previously saved screen state.
415 |
# File 'lib/terminal/ansi.rb', line 415 def screen_restore = +SCREEN_RESTORE |
.screen_save ⇒ String
Save screen state.
408 |
# File 'lib/terminal/ansi.rb', line 408 def screen_save = +SCREEN_SAVE |
.screen_scroll_down(lines = 1) ⇒ String
Scroll the screen down.
441 |
# File 'lib/terminal/ansi.rb', line 441 def screen_scroll_down(lines = 1) = "\e[#{lines}T" |
.screen_scroll_up(lines = 1) ⇒ String
Scroll the screen up.
435 |
# File 'lib/terminal/ansi.rb', line 435 def screen_scroll_up(lines = 1) = "\e[#{lines}S" |
.title(title) ⇒ String
Supported by Hyper, iTerm2, Kitty, macOS Terminal, Tabby, WezTerm.
Set the terminal window title.
465 |
# File 'lib/terminal/ansi.rb', line 465 def title(title) = "\e]0;#{title}\a" |
.try_convert(attributes, separator: ' ') ⇒ String?
Try to convert a space-separated attribute string to an ANSI escape sequence.
131 132 133 134 135 136 |
# File 'lib/terminal/ansi.rb', line 131 def try_convert(attributes, separator: ' ') return unless attributes return if (attributes = attributes.to_s.split(separator)).empty? attributes.uniq! "\e[#{attributes.map! { @attr_map[it] || return }.join(';')}m" end |
.unbbcode(str) ⇒ String
Remove BBCode tags from a string, keeping the enclosed text.
206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/terminal/ansi.rb', line 206 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 if match[0] == '\\' match[0] = '' next "[#{match}]" end next match_str if (match = match.split).empty? next if match.all? { @attr_map[it] } match_str end end |
.undecorate(str) ⇒ String
Remove all ANSI escape codes from a string.
116 117 118 |
# File 'lib/terminal/ansi.rb', line 116 def undecorate(str) (str = str.to_s).index("\e") ? str.gsub(@re_test, '') : str.dup end |
.valid?(*attributes) ⇒ true, false
Check whether all given attributes are valid.
270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/terminal/ansi.rb', line 270 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 |