Module: RubyTUI

Defined in:
lib/rubytui.rb,
lib/rubytui/app.rb,
lib/rubytui/cell.rb,
lib/rubytui/rect.rb,
lib/rubytui/color.rb,
lib/rubytui/event.rb,
lib/rubytui/frame.rb,
lib/rubytui/style.rb,
lib/rubytui/buffer.rb,
lib/rubytui/errors.rb,
lib/rubytui/widget.rb,
lib/rubytui/backend.rb,
lib/rubytui/symbols.rb,
lib/rubytui/unicode.rb,
lib/rubytui/version.rb,
lib/rubytui/modifier.rb,
lib/rubytui/terminal.rb,
lib/rubytui/input/key.rb,
lib/rubytui/text/line.rb,
lib/rubytui/text/span.rb,
lib/rubytui/text/text.rb,
lib/rubytui/color_mode.rb,
lib/rubytui/layout/flex.rb,
lib/rubytui/input/parser.rb,
lib/rubytui/input/reader.rb,
lib/rubytui/widgets/list.rb,
lib/rubytui/widgets/tabs.rb,
lib/rubytui/layout/layout.rb,
lib/rubytui/widgets/block.rb,
lib/rubytui/widgets/chart.rb,
lib/rubytui/widgets/gauge.rb,
lib/rubytui/widgets/image.rb,
lib/rubytui/widgets/popup.rb,
lib/rubytui/widgets/table.rb,
lib/rubytui/widgets/canvas.rb,
lib/rubytui/stateful_widget.rb,
lib/rubytui/layout/constraint.rb,
lib/rubytui/widgets/paragraph.rb,
lib/rubytui/widgets/scrollbar.rb,
lib/rubytui/widgets/sparkline.rb,
lib/rubytui/widgets/async_image.rb,
lib/rubytui/widgets/input_field.rb,
lib/rubytui/backends/ansi_backend.rb,
lib/rubytui/backends/test_backend.rb

Overview

A pure Ruby terminal user interface library.

RubyTUI provides immediate-mode rendering with double buffering, constraint-based layouts, and a duck-typed widget protocol.

Examples:

Interactive TUI application

RubyTUI.run do |terminal, reader|
  loop do
    terminal.draw do |frame|
      frame.buffer.set_string(0, 0, "Hello!", Style.new.fg(Color::GREEN))
    end
    event = reader.poll(timeout_ms: 50)
    break if event.is_a?(RubyTUI::KeyEvent) && event.char == 'q'
  end
end

One-shot styled output (no event loop)

RubyTUI.render_once(width: 80) do |frame|
  block = RubyTUI::Widgets::Block.new(title: " Info ", borders: :all)
  frame.render_widget(block, frame.area)
end

Quick table print

RubyTUI.print_table(
  header: ["Name", "Value"],
  rows: [["Alice", "100"], ["Bob", "200"]],
  title: " Data "
)

Defined Under Namespace

Modules: App, Backend, ColorMode, Input, Layout, Modifier, StatefulWidget, Symbols, Unicode, Widget, Widgets Classes: AnsiBackend, Buffer, Cell, Color, Error, Event, Frame, KeyEvent, LayoutError, Line, MouseEvent, Rect, ResizeEvent, Span, Style, Terminal, TerminalError, TestBackend, Text, UnsupportedImageFormat

Constant Summary collapse

Constraint =

Convenience alias for Layout::Constraint

Layout::Constraint
VERSION =

Gem version string.

"1.2.3"

Class Method Summary collapse

Class Method Details

.init(output: $stdout, input: $stdin, mouse: false, alternate_screen: true) ⇒ Array(Terminal, Input::Reader)

Initialize a terminal with ANSI backend.

Enables raw mode, hides the cursor, and optionally enters alternate screen. Use restore to undo these changes, or prefer run for automatic cleanup.

Parameters:

  • output (IO) (defaults to: $stdout) —

    output stream (default: $stdout)

  • input (IO) (defaults to: $stdin) —

    input stream (default: $stdin)

  • mouse (Boolean) (defaults to: false) —

    enable mouse event reporting (default: false)

  • alternate_screen (Boolean) (defaults to: true) —

    enter alternate screen buffer (default: true)

Returns:

See Also:



109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/rubytui.rb', line 109

def init(output: $stdout, input: $stdin, mouse: false, alternate_screen: true)
  backend = AnsiBackend.new(output: output, input: input)
  terminal = Terminal.new(backend: backend)
  reader = Input::Reader.new(input: input)

  backend.enable_raw_mode
  backend.hide_cursor
  terminal.enter_alternate_screen if alternate_screen
  backend.enable_mouse if mouse
  backend.flush

  [terminal, reader]
end

This method returns an undefined value.

Print a styled box with text content to stdout. No event loop needed.

Renders a RubyTUI::Widgets::Paragraph inside a RubyTUI::Widgets::Block with borders, then prints the ANSI output directly.

Examples:

RubyTUI.print_box(
  title: " Summary ",
  content: "Total: $1,234\nProfit: +5.2%",
  border_style: Style.new.fg(Color::YELLOW)
)

Parameters:

  • title (String, nil) (defaults to: nil) —

    box title rendered on the top border

  • content (String, Array<String>) (defaults to: "") —

    text content (newlines or array of lines)

  • border (Symbol, Symbols::BorderSet) (defaults to: :rounded) —

    border style — :rounded, :double, :thick, :light, :plain, or a RubyTUI::Symbols::BorderSet (default: :rounded)

  • border_style (Style) (defaults to: Style::DEFAULT) —

    style for the border characters (default: RubyTUI::Style::DEFAULT)

  • style (Style) (defaults to: Style::DEFAULT) —

    background style for the box area (default: RubyTUI::Style::DEFAULT)

  • text_style (Style) (defaults to: Style::DEFAULT) —

    style for the text content (default: RubyTUI::Style::DEFAULT)

  • alignment (Symbol) (defaults to: :left) —

    text alignment — :left, :center, :right (default: :left)

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

    total width in columns (default: auto-detect)

  • output (IO) (defaults to: $stdout) —

    output stream (default: $stdout)



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/rubytui.rb', line 284

def print_box(title: nil, content: "", border: :rounded,
              border_style: Style::DEFAULT, style: Style::DEFAULT,
              text_style: Style::DEFAULT, alignment: :left,
              width: nil, output: $stdout)
  border_set = resolve_border_set(border)
  block_widget = Widgets::Block.new(
    title: title, borders: :all, border_set: border_set,
    border_style: border_style, style: style
  )

  text = case content
         when String then Text.from(content)
         when Array  then Text.from(content.join("\n"))
         else content
         end

  para = Widgets::Paragraph.new(
    text: text, style: text_style, alignment: alignment,
    block: block_widget
  )

  w = width || terminal_width(output)
  line_count = case content
               when String then content.count("\n") + 1
               when Array  then content.length
               else 1
               end
  h = line_count + 2  # +2 for borders

  area = Rect.new(0, 0, w, h)
  buf = Buffer.new(area)
  para.render(area, buf)
  output.write(buf.to_ansi)
  output.write("\n")
end

This method returns an undefined value.

Print a styled gauge/progress bar to stdout. No event loop needed.

Renders a RubyTUI::Widgets::Gauge with optional title block, then prints the ANSI output directly.

Examples:

RubyTUI.print_gauge(ratio: 0.75, title: " Progress ", width: 40)

Parameters:

  • ratio (Float) (defaults to: 0.0) —

    progress value between 0.0 and 1.0 (default: 0.0)

  • label (String, nil) (defaults to: nil) —

    custom label (default: percentage)

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

    total width in columns (default: auto-detect)

  • gauge_style (Style, nil) (defaults to: nil) —

    style for the filled portion (default: green)

  • title (String, nil) (defaults to: nil) —

    box title rendered on the top border

  • border (Symbol, Symbols::BorderSet) (defaults to: :rounded) —

    border style — :rounded, :double, :thick, :light, :plain, or a RubyTUI::Symbols::BorderSet (default: :rounded)

  • border_style (Style) (defaults to: Style::DEFAULT) —

    style for the border characters (default: RubyTUI::Style::DEFAULT)

  • output (IO) (defaults to: $stdout) —

    output stream (default: $stdout)



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/rubytui.rb', line 338

def print_gauge(ratio: 0.0, label: nil, width: nil,
                gauge_style: nil, title: nil,
                border: :rounded, border_style: Style::DEFAULT,
                output: $stdout)
  block_widget = title ? Widgets::Block.new(
    title: title, borders: :all,
    border_set: resolve_border_set(border),
    border_style: border_style
  ) : nil

  gauge = Widgets::Gauge.new(
    ratio: ratio, label: label, gauge_style: gauge_style,
    block: block_widget
  )

  w = width || terminal_width(output)
  h = title ? 3 : 1

  area = Rect.new(0, 0, w, h)
  buf = Buffer.new(area)
  gauge.render(area, buf)
  output.write(buf.to_ansi)
  output.write("\n")
end

This method returns an undefined value.

Print a styled table to stdout. No event loop needed.

Renders a RubyTUI::Widgets::Table with optional header, borders, and title, then prints the ANSI output directly. Auto-calculates the required height.

Examples:

RubyTUI.print_table(
  header: ["Name", "Price", "Change"],
  rows: [["AAPL", "150.00", "+2.3%"], ["GOOG", "2800", "-1.1%"]],
  border: :rounded,
  title: " Stocks "
)

Parameters:

  • header (Array<String>, nil) (defaults to: nil) —

    column header labels

  • rows (Array<Array<String>>) (defaults to: []) —

    table data rows

  • widths (Array<Integer>) (defaults to: []) —

    column widths (auto-calculated if empty)

  • title (String, nil) (defaults to: nil) —

    box title rendered on the top border

  • border (Symbol, Symbols::BorderSet) (defaults to: :rounded) —

    border style — :rounded, :double, :thick, :light, :plain, or a RubyTUI::Symbols::BorderSet (default: :rounded)

  • border_style (Style) (defaults to: Style::DEFAULT) —

    style for the border characters (default: RubyTUI::Style::DEFAULT)

  • header_style (Style, nil) (defaults to: nil) —

    style for header row (default: cyan bold)

  • style (Style) (defaults to: Style::DEFAULT) —

    base style for data rows (default: RubyTUI::Style::DEFAULT)

  • highlight_symbol (String) (defaults to: " ") —

    prefix for the selected row (default: " ")

  • column_spacing (Integer) (defaults to: 1) —

    gap between columns (default: 1)

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

    total width in columns (default: auto-detect)

  • output (IO) (defaults to: $stdout) —

    output stream (default: $stdout)



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/rubytui.rb', line 232

def print_table(header: nil, rows: [], widths: [], title: nil,
                border: :rounded, border_style: Style::DEFAULT,
                header_style: nil, style: Style::DEFAULT,
                highlight_symbol: "  ", column_spacing: 1,
                width: nil, output: $stdout)
  border_set = resolve_border_set(border)
  block_widget = title ? Widgets::Block.new(
    title: title, borders: :all, border_set: border_set,
    border_style: border_style
  ) : nil

  table = Widgets::Table.new(
    header: header, rows: rows, widths: widths, style: style,
    header_style: header_style, highlight_symbol: highlight_symbol,
    column_spacing: column_spacing, block: block_widget
  )
  state = Widgets::TableState.new(selected: -1)  # No selection for one-shot

  # Calculate height: header(1) + separator(1) + rows + border(2)
  h = rows.length + (header ? 2 : 0) + (title ? 2 : 0)
  w = width || terminal_width(output)

  area = Rect.new(0, 0, w, h)
  buf = Buffer.new(area)
  table.render(area, buf, state)
  output.write(buf.to_ansi)
  output.write("\n")
end

.render_once(width: nil, height: nil, output: $stdout) {|frame| ... } ⇒ Frame

Render widgets once and print to stdout.

No event loop, no alternate screen, no raw mode. Output stays in terminal scrollback. Ideal for CLI tools that want styled output using the widget/layout system without a full TUI.

Examples:

Render a block widget

RubyTUI.render_once(width: 60, height: 10) do |frame|
  block = RubyTUI::Widgets::Block.new(title: " Info ", borders: :all)
  frame.render_widget(block, frame.area)
end

Parameters:

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

    output width in columns (default: auto-detect)

  • height (Integer, nil) (defaults to: nil) —

    output height in rows (default: auto-detect)

  • output (IO) (defaults to: $stdout) —

    output stream (default: $stdout)

Yields:

  • (frame) —

    a Frame to render widgets into

Yield Parameters:

Returns:

  • (Frame) —

    the rendered frame



193
194
195
196
197
198
199
200
201
202
203
# File 'lib/rubytui.rb', line 193

def render_once(width: nil, height: nil, output: $stdout)
  w = width || terminal_width(output)
  h = height || terminal_height(output)
  area = Rect.new(0, 0, w, h)
  buf = Buffer.new(area)
  frame = Frame.new(buf, area)
  yield frame
  output.write(buf.to_ansi)
  output.write("\n")
  frame
end

.restore(terminal, alternate_screen: true) ⇒ void

This method returns an undefined value.

Restore terminal to normal state.

Disables mouse, shows cursor, leaves alternate screen, and disables raw mode.

Parameters:

  • terminal (Terminal) —

    the terminal to restore

  • alternate_screen (Boolean) (defaults to: true) —

    whether alternate screen was used (must match init) (default: true)



131
132
133
134
135
136
137
# File 'lib/rubytui.rb', line 131

def restore(terminal, alternate_screen: true)
  terminal.backend.disable_mouse
  terminal.backend.show_cursor
  terminal.leave_alternate_screen if alternate_screen
  terminal.backend.disable_raw_mode
  terminal.backend.flush
end

.run(output: $stdout, input: $stdin, mouse: false, alternate_screen: true) {|terminal, reader| ... } ⇒ void

This method returns an undefined value.

Run a TUI application with automatic setup and teardown.

Sets up the terminal (raw mode, hidden cursor, alternate screen) and yields a terminal and reader. Restores the terminal when the block exits.

Examples:

Basic interactive app

RubyTUI.run do |terminal, reader|
  loop do
    terminal.draw { |frame| frame.buffer.set_string(0, 0, "Hi!") }
    event = reader.poll(timeout_ms: 50)
    break if event.is_a?(RubyTUI::KeyEvent) && event.char == 'q'
  end
end

Non-alternate-screen mode (output persists after exit)

RubyTUI.run(alternate_screen: false) do |terminal, reader|
  terminal.draw { |frame| frame.buffer.set_string(0, 0, "Stays visible") }
end

Parameters:

  • output (IO) (defaults to: $stdout) —

    output stream (default: $stdout)

  • input (IO) (defaults to: $stdin) —

    input stream (default: $stdin)

  • mouse (Boolean) (defaults to: false) —

    enable mouse event reporting (default: false)

  • alternate_screen (Boolean) (defaults to: true) —

    use alternate screen buffer (default: true). Set to false to keep output in terminal scrollback after exit.

Yields:

  • (terminal, reader) —

    the initialized terminal and input reader

Yield Parameters:



167
168
169
170
171
172
173
# File 'lib/rubytui.rb', line 167

def run(output: $stdout, input: $stdin, mouse: false, alternate_screen: true)
  terminal, reader = init(output: output, input: input, mouse: mouse,
                          alternate_screen: alternate_screen)
  yield terminal, reader
ensure
  restore(terminal, alternate_screen: alternate_screen) if terminal
end