typr — Terminal UI Toolkit

typr is a Ruby library for building interactive terminal-based user interfaces. It provides data-object based views and keyboard-driven interaction.

Features

Views

  • Grid — sortable, filterable table with formatted columns, colors, and row selection
  • Text — scrollable text viewer with word/line picking, search, and borders
  • Browser — file-system directory browser with MIME type detection
  • Stack, Space — layout containers for composing views
  • Line — interactive prompt/input with colored questions and answers

Frontends

typr supports two rendering backends, selectable via require:

  • Terminal (require 'typr') — raw terminal IO, no dependencies beyond Ruby stdlib
  • Graphical (require 'typr/graphical') — SDL2-based, for desktop GUI windows

All views work identically across frontends.

Keyboard interaction

Navigation uses hint numbers displayed next to selectable items — rows in grids, columns, or other elements. Press the number to select that item directly. When more items are visible than fit in one set of hints (1-9, 0), press Tab to cycle through hint groups. Arrow keys, Page Up/Down, Home/End work as expected. All keys are dispatched through a configurable keymap.

Installation

gem install typr

Or in your Gemfile:

gem 'typr', '~> 1.0'

Usage

Grid (table)

require 'typr'

Typr.init

@grid = Typr::Grid.new(
  input:   [
    ["Alice",   30, "engineer"],
    ["Bob",     25, "designer"],
    ["Carol",   35, "manager"]
  ],
  header:  ["Name", "Age", "Role"],
  format:  [:min, :right, :max],
  colors:  { columns: [:yellow, :cyan, :magenta] }
)

Typr.clear
@grid.draw
key = Typr.read(:key)   # reads a single keypress
@grid.reset               # reset grid to default view
Typr.exit

Text viewer

require 'typr'

Typr.init

@text = Typr::Text.new(
  input:  IO.popen(%w[cat /usr/share/dict/words]),
  header: "Words",
  top:    2, left: 0.1, right: 0.9, bottom: -4,
  border: :round,
  colors: { header: [:yellow, :grey30] }
)

Typr.clear
loop do
  @text.draw
  key = Typr.read(:key)
  case key
  when ?q then break
  else     @text.send(key)  # spacebar scrolls, j/k move up/down, etc.
  end
end
Typr.exit

Browser (file picker)

require 'typr'

Typr.init

@browser = Typr::Browser.new(
  directory: "/tmp",
  right: -1, bottom: -1,
  colors: { hints: [:white, :black] }
)

selected = @browser.pick("/home")   # interactive file picker, returns path
puts "You selected: #{selected}"
Typr.exit

Combined example (Grid + prompt line)

require 'typr'

class MyApp
  include Typr

  def initialize
    Typr.init
    @grid = Typr::Grid.new(
      input: [
        ["Item A", 10, true],
        ["Item B", 5,  false],
        ["Item C", 20, true]
      ],
      header:  ["Name", "Qty", "Active"],
      format:  [:max, :right, :min],
      colors:  { columns: [:yellow, :cyan, :green] }
    )
    @prompt = Typr::Line.new(
      top: -1,
      default: "(s)ort  (f)ilter  [esc] quit"
    )
  end

  def run
    Typr.clear
    loop do
      @grid.draw
      @prompt.draw
      key = Typr.read(:key)
      case key
      when ?s then @grid.sort_by(@prompt.ask("sort column": [@grid, :column]))
      when ?f then @grid.add_filter(*@prompt.ask("filter column": [@grid, :column], with: :line))
      when KEY_ESCAPE then break
      end
    end
  end

  def shutdown; Typr.exit; end
end

app = MyApp.new
begin
  app.run
ensure
  app.shutdown
end

API Reference

Typr.init / Typr.exit

Initialize and tear down the terminal UI. Always call these at the start and end of your program.

Typr.clear([scope])

Clears the full screen or a single line (:line).

Typr.read(type)

Reads input from the terminal. Types:

  • :key — a single keypress (returns KEY_ESCAPE, ?q, etc.)
  • :line — a full line of text input

Layout properties (all views)

  • top, bottom, left, right — placement. Integers for absolute offsets, floats (0-1) for relative sizing. Negative values position from the opposite edge. (bottom: -1 = last row)

Grid options

Option Description
input Array of arrays (data rows)
header Column titles array
format Per-column format: :min, :max, or a number for fixed width
colors { columns: [:yellow, :cyan], header: [:white, :black] } etc.
sorted_by Column index the grid is sorted by (setter)
filters Active filters array (getter)
selected Selected row indices (getter/setter)
.sort_by Sort the grid on a given column
.select_rows / select_columns Multi-select via index picker

Text options

Option Description
input String or IO-like stream to display
header Header bar text
border Border style: :round, " ", etc.

Browser options

Option Description
directory Root directory to start browsing
.pick(start_dir) Interactive file picker, returns the selected path

License

MIT