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.
256 |
# File 'lib/terminal/ansi.rb', line 256 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 |
# File 'lib/terminal/ansi.rb', line 186 def bbcode(str) return str.dup unless (str = str.to_s).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.
443 |
# File 'lib/terminal/ansi.rb', line 443 def char_repeat(count = 1) = "\e[#{count}b" |
.cursor_back(columns = 1) ⇒ String
Move cursor left.
322 |
# File 'lib/terminal/ansi.rb', line 322 def cursor_back(columns = 1) = "\e[#{columns}D" |
.cursor_column(column = 1) ⇒ String
Move cursor to absolute column.
340 |
# File 'lib/terminal/ansi.rb', line 340 def cursor_column(column = 1) = "\e[#{column}G" |
.cursor_column_rel(column = 1) ⇒ String
Move cursor right by relative columns.
346 |
# File 'lib/terminal/ansi.rb', line 346 def cursor_column_rel(column = 1) = "\e[#{column}a" |
.cursor_down(lines = 1) ⇒ String
Move cursor down.
310 |
# File 'lib/terminal/ansi.rb', line 310 def cursor_down(lines = 1) = "\e[#{lines}B" |
.cursor_forward(columns = 1) ⇒ String
Move cursor right.
316 |
# File 'lib/terminal/ansi.rb', line 316 def cursor_forward(columns = 1) = "\e[#{columns}C" |
.cursor_hide ⇒ String
Hide cursor.
376 |
# File 'lib/terminal/ansi.rb', line 376 def cursor_hide = +CURSOR_HIDE |
.cursor_next_line(lines = 1) ⇒ String
Move cursor to beginning of line, N lines down.
328 |
# File 'lib/terminal/ansi.rb', line 328 def cursor_next_line(lines = 1) = "\e[#{lines}E" |
.cursor_pos(row, column = nil) ⇒ String
Move cursor to absolute position.
363 364 365 366 |
# File 'lib/terminal/ansi.rb', line 363 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.
334 |
# File 'lib/terminal/ansi.rb', line 334 def cursor_prev_line(lines = 1) = "\e[#{lines}F" |
.cursor_restore_pos ⇒ String
Restore previously saved cursor position.
390 |
# File 'lib/terminal/ansi.rb', line 390 def cursor_restore_pos = +CURSOR_POS_RESTORE |
.cursor_row_rel(row = 1) ⇒ String
Move cursor down by relative rows.
352 |
# File 'lib/terminal/ansi.rb', line 352 def cursor_row_rel(row = 1) = "\e[#{row}e" |
.cursor_save_pos ⇒ String
Save current cursor position.
383 |
# File 'lib/terminal/ansi.rb', line 383 def cursor_save_pos = +CURSOR_POS_SAVE |
.cursor_show ⇒ String
Show cursor.
371 |
# File 'lib/terminal/ansi.rb', line 371 def cursor_show = +CURSOR_SHOW |
.cursor_up(lines = 1) ⇒ String
Move cursor up.
304 |
# File 'lib/terminal/ansi.rb', line 304 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.
230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/terminal/ansi.rb', line 230 def escape_bbcode(str) return str.dup unless (str = str.to_s).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.
450 |
# File 'lib/terminal/ansi.rb', line 450 def line_erase(part = :all) = "\e[#{@line_erase[part]}K" |
.link(url, text, **params) ⇒ String
Create a complete hyperlink (OSC 8).
495 496 497 |
# File 'lib/terminal/ansi.rb', line 495 def link(url, text, **params) "#{link_start(url, **params)}#{text}#{LINK_END}" end |
.link_end ⇒ String
End a hyperlink.
482 |
# File 'lib/terminal/ansi.rb', line 482 def link_end = +LINK_END |
.link_start(url, **params) ⇒ String
Supported by Ghostty, iTerm2, Kitty, Rio, Tabby, WezTerm.
Start a hyperlink (OSC 8).
473 474 475 |
# File 'lib/terminal/ansi.rb', line 473 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.
507 |
# File 'lib/terminal/ansi.rb', line 507 def notify(text) = "\e]9;#{text}\a" |
.plain(str) ⇒ String
Remove both BBCode tags and ANSI escape codes, returning plain text.
289 290 291 292 |
# File 'lib/terminal/ansi.rb', line 289 def plain(str) str.gsub!(@re_test, '') if (str = unbbcode(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.
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
# File 'lib/terminal/ansi.rb', line 526 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.
566 567 568 569 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 |
# File 'lib/terminal/ansi.rb', line 566 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.
418 |
# File 'lib/terminal/ansi.rb', line 418 def screen_alternate = +SCREEN_ALTERNATE |
.screen_alternate_off ⇒ String
Switch back from the alternate screen buffer.
425 |
# File 'lib/terminal/ansi.rb', line 425 def screen_alternate_off = +SCREEN_ALTERNATE_OFF |
.screen_erase(part = :all) ⇒ String
Erase part of the screen.
397 |
# File 'lib/terminal/ansi.rb', line 397 def screen_erase(part = :all) = "\e[#{@screen_erase[part]}J" |
.screen_restore ⇒ String
Restore previously saved screen state.
411 |
# File 'lib/terminal/ansi.rb', line 411 def screen_restore = +SCREEN_RESTORE |
.screen_save ⇒ String
Save screen state.
404 |
# File 'lib/terminal/ansi.rb', line 404 def screen_save = +SCREEN_SAVE |
.screen_scroll_down(lines = 1) ⇒ String
Scroll the screen down.
437 |
# File 'lib/terminal/ansi.rb', line 437 def screen_scroll_down(lines = 1) = "\e[#{lines}T" |
.screen_scroll_up(lines = 1) ⇒ String
Scroll the screen up.
431 |
# File 'lib/terminal/ansi.rb', line 431 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.
461 |
# File 'lib/terminal/ansi.rb', line 461 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.
205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/terminal/ansi.rb', line 205 def unbbcode(str) return str.dup unless (str = str.to_s).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.
267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/terminal/ansi.rb', line 267 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 |