Module: NattyUI::Features

Included in:
NattyUI, Element
Defined in:
lib/natty-ui/features.rb

Overview

Mixin that provides all UI methods to NattyUI and every Element.

You never include or extend this module directly. It is already available on NattyUI (via extend) and on every Element subclass (via include). The Kernel#ui helper always returns an object that responds to every method defined here.

Output methods collapse

Section elements collapse

User Interaction collapse

Utilities collapse

Instance Method Details

#await {|temp| ... } ⇒ nil

Waits for the user to press any key.

Examples:

Plain wait

ui.puts 'Press any key to continue…'
ui.await

With temporary prompt

ui.await { ui.puts '[faint]Press any key to continue…' }

Yields:

Yield Parameters:

Returns:

  • (nil)


671
672
673
674
675
676
677
# File 'lib/natty-ui/features.rb', line 671

def await
  yield(temp = temporary) if block_given?
  Terminal.read_key_event
  nil
ensure
  temp&.end
end

#choice(*items, abortable: false, selected: nil) ⇒ Object #choice(abortable: false, selected: nil, **pairs) ⇒ Object

Presents a list of options and returns the one the user selects.

In ANSI mode the user navigates with arrow keys and confirms with Enter. In dumb mode items are numbered and the user types the item number.

Examples:

Positional items

answer = ui.choice 'Yes', 'No', 'Cancel'

Positional items

answer = ui.choice 'Yes', 'No', abortable: true do
  ui.puts 'Overwrite the file?'
end

Keyword pairs

action = ui.choice(overwrite: 'Overwrite', skip: 'Skip') do
  ui.puts 'File already exists.'
end

Overloads:

  • #choice(*items, abortable: false, selected: nil) ⇒ Object

    Items are passed as positional arguments; the selected item itself is returned.

    Parameters:

    • items (#to_s, ...)

      options to choose from

    • abortable (Boolean) (defaults to: false)

      when true the user can press Esc to cancel

    • selected (defaults to: nil)

      pre-selected item value, or nil

  • #choice(abortable: false, selected: nil, **pairs) ⇒ Object

    Items are passed as keyword pairs { return_value => label }; the matching key is returned.

    Parameters:

    • abortable (Boolean) (defaults to: false)

      when true the user can press Esc to cancel

    • selected (defaults to: nil)

      pre-selected return value, or nil

    • pairs (Hash{Object => #to_s})

      map of return values to display labels

Yields:

Yield Parameters:

Returns:

  • (Object)

    the key of the selected pair, or nil if aborted



749
750
751
752
753
754
755
756
757
758
759
# File 'lib/natty-ui/features.rb', line 749

def choice(*items, abortable: false, selected: nil, **pairs)
  return if items.empty? && pairs.empty?
  yield(temp = temporary) if block_given?
  (Terminal.ansi? ? Choice : DumbChoice).new(
    self,
    items + pairs.values,
    Array.new(items.size, &:itself) + pairs.keys
  ).select(abortable, selected)
ensure
  temp&.end
end

#error(title, border: :default) {|section| ... } ⇒ Object, Section

Creates a Section with :error styling.

Parameters:

  • title (#to_s)

    header text

  • border (:default, :rounded, :single, :double, :heavy) (defaults to: :default)

    border style

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Section)

    itself, if no block is specified



555
556
557
# File 'lib/natty-ui/features.rb', line 555

def error(title, border: :default, &)
  section(title, border:, type: :error, &)
end

#fatal(title, border: :default) {|section| ... } ⇒ Object, Section

Creates a Section with :fatal styling.

Parameters:

  • title (#to_s)

    header text

  • border (:default, :rounded, :single, :double, :heavy) (defaults to: :default)

    border style

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Section)

    itself, if no block is specified



565
566
567
# File 'lib/natty-ui/features.rb', line 565

def fatal(title, border: :default, &)
  section(title, border:, type: :fatal, &)
end

#frame(title = nil, border: :default, style: nil) {|frame| ... } ⇒ Object, Frame

Creates a NattyUI::Frame element — a bordered box with an optional title.

Examples:

Manual close

frm = ui.frame 'Preview'
ui.puts 'Content inside the frame.'
frm.end

Block form with title and custom border

ui.frame 'Results', border: :double do
  ui.puts 'All checks passed.'
end

Block form without a title

ui.frame do
  ui.puts 'Framed content.'
end

Parameters:

  • style (Symbol, String, Array<Style>, Array<String>, nil) (defaults to: nil)

    ANSI style applied to the frame

  • title (#to_s, nil) (defaults to: nil)

    optional header text

  • border (:default, :rounded, :single, :double, :heavy) (defaults to: :default)

    border style

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Frame)

    itself, if no block is specified



594
595
596
# File 'lib/natty-ui/features.rb', line 594

def frame(title = nil, border: :default, style: nil, &)
  __with(Frame.new(self, title, border, style), &)
end

#h1(title) ⇒ Features

Prints a level-1 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



212
# File 'lib/natty-ui/features.rb', line 212

def h1(title) = heading(1, title)

#h2(title) ⇒ Features

Prints a level-2 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



218
# File 'lib/natty-ui/features.rb', line 218

def h2(title) = heading(2, title)

#h3(title) ⇒ Features

Prints a level-3 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



224
# File 'lib/natty-ui/features.rb', line 224

def h3(title) = heading(3, title)

#h4(title) ⇒ Features

Prints a level-4 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



230
# File 'lib/natty-ui/features.rb', line 230

def h4(title) = heading(4, title)

#h5(title) ⇒ Features

Prints a level-5 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



236
# File 'lib/natty-ui/features.rb', line 236

def h5(title) = heading(5, title)

#h6(title) ⇒ Features

Prints a level-6 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



242
# File 'lib/natty-ui/features.rb', line 242

def h6(title) = heading(6, title)

#hbars(values, min: nil, max: nil, normalize: false, width: :auto, style: nil, text: true, text_style: nil) ⇒ Features

Prints a horizontal bar chart.

All values must be non-negative.

Examples:

Simple horizontal chart

ui.hbars [3, 7, 2, 9, 5]

Chart without value labels

ui.hbars [10, 40, 25, 60], text: false, normalize: true

Parameters:

  • width (#to_int, Float, :auto) (defaults to: :auto)

    maximum bar width in characters; a Float is a fraction of available width; :auto fills available width

  • text (Boolean) (defaults to: true)

    when true prints the numeric value next to each bar

  • text_style (Symbol, String, Array<Style>, Array<String>, nil) (defaults to: nil)

    ANSI style applied to the value labels

  • values (#each)

    collection of non-negative Numeric values

  • min (Numeric, nil) (defaults to: nil)

    lower bound for scaling; nil uses the data minimum

  • max (Numeric, nil) (defaults to: nil)

    upper bound for scaling; nil uses the data maximum

  • normalize (Boolean) (defaults to: false)

    when true applies min-max normalization; when false scales each bar relative to the maximum value

  • style (Symbol, String, Array<Style>, Array<String>, nil) (defaults to: nil)

    ANSI style applied to the bars

Returns:

Raises:

  • (ArgumentError)


353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'lib/natty-ui/features.rb', line 353

def hbars(
  values,
  min: nil,
  max: nil,
  normalize: false,
  width: :auto,
  style: nil,
  text: true,
  text_style: nil
)
  bars = HBars.new(values, min, max, normalize)
  return self if bars.empty?
  raise(ArgumentError, 'values can not be negative') unless bars.valid?
  bars.with_text(text_style) if text
  puts(*bars.lines(columns, width, style), bbcode: false)
end

#heading(level, title) ⇒ Features

Prints a heading at the given level.

Six heading levels are supported (similarly to HTML <h1><h6>). Use the shorthand helpers #h1#h6 for convenience.

Examples:

Large heading

ui.heading 1, 'Chapter One'

Sub-heading

ui.heading 3, 'Section [i]Overview[/i]'

Parameters:

  • level (#to_int)

    heading level, 1 (largest) to 6 (smallest)

  • title (#to_s)

    heading text

Returns:



206
# File 'lib/natty-ui/features.rb', line 206

def heading(level, title) = Heading.render(self, level, title)

#hr(kind = nil) ⇒ Features

Prints a horizontal rule spanning the available width.

Examples:

Default rule

ui.hr

Named style

ui.hr :double

Repeated string

ui.hr '+-'

Parameters:

  • kind (Symbol, #to_s, nil) (defaults to: nil)
    • nil — default style
    • Symbol — named style: :single, :double, :heavy
    • #to_s — string repeated to fill the available width

Returns:



260
# File 'lib/natty-ui/features.rb', line 260

def hr(kind = nil) = HorizontalRule.render(self, kind)

#information(title, border: :default) {|section| ... } ⇒ Object, Section Also known as: info

Creates a Section with :information styling.

Parameters:

  • title (#to_s)

    header text

  • border (:default, :rounded, :single, :double, :heavy) (defaults to: :default)

    border style

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Section)

    itself, if no block is specified



533
534
535
# File 'lib/natty-ui/features.rb', line 533

def information(title, border: :default, &)
  section(title, border:, type: :information, &)
end

#ls(*items, compact: true, glyph: nil) ⇒ Features

Prints a multi-column list.

Items are arranged in columns to fit the terminal width.

Examples:

Plain list

ui.ls 'Alice', 'Bob', 'Carol'

Hex-numbered list

ui.ls 'red', 'green', 'blue', glyph: :hex

Parameters:

  • items (#to_s, ...)

    items to list; nested arrays are flattened

  • compact (Boolean) (defaults to: true)

    true = ordered in columns, false = ordered left to right per row

  • glyph (defaults to: nil)

    prefix applied to every item:

    • nil / false — no prefix
    • Integer — decimal counter starting at the given number
    • Symbol — alphabetic sequence starting at the given symbol (e.g. :aa, b, c, …)
    • :hex — zero-based hex counter (01, 02, …)
    • a #to_s value matching a hex value — hex counter at the given offset (e.g. "0x0a" starts at 0a)
    • any other #to_s value — used as a literal prefix for every item

Returns:



285
286
287
288
# File 'lib/natty-ui/features.rb', line 285

def ls(*items, compact: true, glyph: nil)
  return self if items.empty?
  puts(*(compact ? CompactLS : LS).lines(columns, items, glyph))
end

#margin(value) ⇒ Object, Margin #margin(vertical = 0, horizontal = 1) ⇒ Object, Margin #margin(top, horizontal, bottom) ⇒ Object, Margin #margin(top, right, bottom, left) ⇒ Object, Margin #margin(top: 0, right: 0, bottom: 0, left: 0) ⇒ Object, Margin

Creates a Margin element that adds horizontal and vertical whitespace.

Examples:

ui.margin 0, 0.25 do
  ui.puts 'This text has 25% width horizontal margin.'
end

Overloads:

  • #margin(value) ⇒ Object, Margin

    Margin for all sides.

    Parameters:

    • value (#to_int, Float)

      margin of all four sides

  • #margin(vertical = 0, horizontal = 1) ⇒ Object, Margin

    Seperate vertical and horizontal margin.

    Parameters:

    • vertical (#to_int) (defaults to: 0)

      top and bottom margin

    • horizontal (#to_int, Float) (defaults to: 1)

      left and right margin

  • #margin(top, horizontal, bottom) ⇒ Object, Margin

    Seperate top, bottom and horizontal margin.

    Parameters:

    • top (#to_int)

      top margin

    • horizontal (#to_int, Float)

      left and right margin

    • bottom (#to_int)

      bottom margin

  • #margin(top, right, bottom, left) ⇒ Object, Margin

    Seperate margins.

    Parameters:

    • top (#to_int)

      top margin

    • right (#to_int, Float)

      right margin

    • bottom (#to_int)

      bottom margin

    • left (#to_int, Float)

      left margin

  • #margin(top: 0, right: 0, bottom: 0, left: 0) ⇒ Object, Margin

    Specific margin.

    Parameters:

    • top (#to_int) (defaults to: 0)

      top margin

    • right (#to_int, Float) (defaults to: 0)

      right margin

    • bottom (#to_int) (defaults to: 0)

      bottom margin

    • left (#to_int, Float) (defaults to: 0)

      left margin

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Margin)

    itself, if no block is specified



481
# File 'lib/natty-ui/features.rb', line 481

def margin(*, &) = __with(Margin.new(self, *), &)

#mark(*text, mark: :default, **popts) ⇒ Features

Prints text with a leading mark symbol.

Examples:

Default mark

ui.mark 'Item one'

Named symbol mark

ui.mark 'Done!', mark: :checkmark

Custom string mark

ui.mark 'Warning', mark: '[bright_red]!'

Parameters:

  • mark (Symbol, #to_s) (defaults to: :default)

    mark to use as prefix:

    • :default — blue bullet •
    • :checkmark — green check mark ✓
    • :item — dim bullet •
    • any other object — converted via #to_s and used as the literal prefix
  • popts (Hash)

    a customizable set of print options, see #puts

  • text (#to_s, ...)

    one or more text values to print

Returns:



150
151
152
# File 'lib/natty-ui/features.rb', line 150

def mark(*text, mark: :default, **popts)
  Mark.render(self, mark, *text, **popts)
end

#message(title, border: :default) {|section| ... } ⇒ Object, Section Also known as: msg

Creates a Section with :message styling.

Parameters:

  • title (#to_s)

    header text

  • border (:default, :rounded, :single, :double, :heavy) (defaults to: :default)

    border style

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Section)

    itself, if no block is specified



522
523
524
# File 'lib/natty-ui/features.rb', line 522

def message(title, border: :default, &)
  section(title, border:, type: :message, &)
end

#ok(*text, **popts) ⇒ Features

Prints text with a green check-mark prefix.

Shorthand for mark(*text, mark: :checkmark, **options).

Examples:

ui.ok 'All tests passed'

Parameters:

  • text (#to_s, ...)

    one or more text values to print

  • popts (Hash)

    a customizable set of print options, see #puts

Returns:



164
# File 'lib/natty-ui/features.rb', line 164

def ok(*text, **popts) = mark(*text, mark: :checkmark, **popts)

#pin(*text, mark: :default, **popts) ⇒ Features

Prints text with a mark that persists after a Temporary element closes.

Identical to #mark but survives when the surrounding Temporary element (see #temporary, #task, #progress) is erased.

Examples:

Pin a success note inside a task

ui.task 'Deploy' do
  do_deploy
  ui.pin 'Deployed to production', mark: :checkmark
end

Parameters:

  • mark (Symbol, #to_s) (defaults to: :default)

    mark to use as prefix:

    • :default — blue bullet •
    • :checkmark — green check mark ✓
    • :item — dim bullet •
    • any other object — converted via #to_s and used as the literal prefix
  • popts (Hash)

    a customizable set of print options, see #puts

  • text (#to_s, ...)

    one or more text values to print

Returns:



179
180
181
# File 'lib/natty-ui/features.rb', line 179

def pin(*text, mark: :default, **popts)
  mark(*text, mark:, pin: true, **popts)
end

#progress(*title, max: nil, **popts) {|progress| ... } ⇒ Object, Progress

Creates a Progress element for tracking incremental work.

When max is given the progress is displayed as a percentage bar. When max is nil an open-ended dot animation is shown instead.

Examples:

Bounded progress

ui.progress 'Processing', max: items.size do |bar|
  items.each { process(it); bar.step }
end

Open-ended progress

ui.progress 'Working…' do |bar|
  loop { bar.step; break if done? }
end

Parameters:

  • max (Numeric, nil) (defaults to: nil)

    maximum value

  • title (#to_s, nil)

    optional header text

  • popts (Hash)

    a customizable set of print options, see #puts

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Progress)

    itself when no block is given



641
642
643
644
645
646
647
648
649
650
651
# File 'lib/natty-ui/features.rb', line 641

def progress(*title, max: nil, **popts, &)
  __with(
    (Terminal.ansi? ? Progress : DumbProgress).new(
      self,
      max,
      *title,
      **popts
    ),
    &
  )
end

#puts(*text, **popts) ⇒ Features

Formats and prints text to the terminal.

Text is word-wrapped to fit the available column width. BBCode-like markup is interpreted by default (e.g. [b]bold[/b], [red]text[/fg]).

Examples:

Simple output with BBCode markup

ui.puts 'Hello, [b]world[/b]!'

Centred text with a prefix

ui.puts 'Step 1 of 3', 'Connect to server',
        align: :center, prefix: '[cyan]→ '

Suppress line breaks and compact spaces

ui.puts <<~TEXT, eol: false, spaces: false
  Line    one
  Line    two     here
TEXT
# => Line one Line two here

Parameters:

  • text (#to_s, ...)

    one or more text values to print

  • popts (Hash)

    a customizable set of print options

Options Hash (**popts):

  • :bbcode (Boolean) — default: true

    interpret BBCode-like markup in the text

  • :eol (Boolean) — default: true

    when false, line breaks inside the text are collapsed to spaces

  • :spaces (Boolean) — default: true

    when false, runs of whitespace are compacted to a single space

  • :align (:left, :center, :right, nil)

    horizontal text alignment within the available width

  • :prefix (#to_s, nil)

    string prepended to the first output line

  • :suffix (#to_s, nil)

    string appended to the last output line

  • :max_width (#to_int, Float, nil)

    maximum line width in characters; nil uses the full terminal width; a negative #to_int value is an offset from the terminal width; a Float in 0.0..1.0 is a fraction of the terminal width

Returns:



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/natty-ui/features.rb', line 53

def puts(*text, **popts)
  return if text.empty?

  popts.delete(:pin) # ignore!

  if popts.empty?
    popts[:bbcode] = true
    popts[:width] = max_width = columns
    return self if max_width < 1
  else
    popts[:bbcode] = true unless popts.key?(:bbcode)
    max_width = __determine_max_width(popts.delete(:max_width))
    return self if max_width < 1

    unless (prefix = popts.delete(:prefix)).nil?
      prefix = StrConst[prefix] unless StrConst === prefix
      return self if (max_width -= prefix.width) < 1
    end

    if (cprefix = popts.delete(:cprefix)).nil?
      cprefix = prefix
    elsif cprefix == true
      prefix, cprefix = StrConst.spacer(prefix.width), prefix if prefix
    else
      cprefix = StrConst[cprefix] unless StrConst === cprefix
      unless prefix
        return self if (max_width -= cprefix.width) < 1
        prefix = StrConst.spacer(cprefix.width)
      end
    end

    unless (suffix = popts.delete(:suffix)).nil?
      suffix = StrConst[suffix] unless StrConst === suffix
      return self if (max_width -= suffix.width) < 1
    end

    if (csuffix = popts.delete(:csuffix)).nil?
      csuffix = suffix
    elsif csuffix == true
      suffix, csuffix = StrConst.spacer(suffix.width), suffix if suffix
    else
      csuffix = StrConst[csuffix] unless StrConst === csuffix
      return self if (max_width -= csuffix.width) < 1
      suffix = StrConst.spacer(csuffix.width)
    end

    popts[:width] = max_width
  end

  popts[:ansi] = Terminal.ansi?
  lines = Text.format(*text, **popts)
  if cprefix || csuffix
    lines.map! do |line|
      line = "#{cprefix}#{line}#{csuffix}"
      cprefix, prefix = prefix, nil if prefix
      csuffix, suffix = suffix, nil if suffix
      line
    end
  end
  Terminal.puts(*lines, bbcode: false)
  @lines_written += lines.size
  self
end

#query(**options) {|temp| ... } ⇒ Object

Waits for a key event and returns information about it.

Key names are strings such as "a", "Enter", "Esc", "Back", "Shift+Alt+F1".

Examples:

answer = ui.query yes: 'y', no: 'n'
ui.puts answer == :yes ? 'Confirmed!' : 'Cancelled.'

With a temporary prompt

answer = ui.query(yes: 'y', no: 'n') do
  ui.puts 'Continue? ([b]y[/b]/[b]n[/b])'
end

Parameters:

  • options (Hash<Object => String, #each>)

    map of return values to key names or enumerables of key names; e.g. { yes: 'y', no: %w[n Esc] }

Yields:

Yield Parameters:

Returns:

  • (Object)

    matched option key



699
700
701
702
703
704
705
706
707
708
709
710
711
712
# File 'lib/natty-ui/features.rb', line 699

def query(**options)
  yield(temp = temporary) if block_given?
  return Terminal.read_key_event.name if options.empty?
  Terminal.on_key_event do |event|
    event = event.name
    found, =
      options.find do |_, value|
        (value.is_a?(Enumerable) && value.include?(event)) || value == event
      end
    break found if found
  end
ensure
  temp&.end
end

#quote(*text) ⇒ Features

Prints text with a left-side quotation border.

Examples:

ui.quote "To be or not to be,\nthat is the question."

Parameters:

  • text (#to_s, ...)

    one or more text values to print

  • popts (Hash)

    a customizable set of print options

Returns:



190
# File 'lib/natty-ui/features.rb', line 190

def quote(*text) = Quote.render(self, *text)

#run(*cmd, env = {}, shell: false, input: nil, max_lines: 10, **spawn_options) ⇒ Array(Process::Status, Array<String>, Array<String>)?

Executes a shell command, captures its output, and returns it.

Stdout and stderr lines are displayed in a scrolling region limited to max_lines. All other arguments are identical to #sh.

Examples:

Capture and inspect output

status, out, err = ui.run 'ls', '-la'
ui.puts "exit #{status.exitstatus}"

Limit displayed lines and pipe input

File.open('data.txt') { |f| ui.run 'wc', '-l', input: f, max_lines: 5 }

Parameters:

  • max_lines (#to_int) (defaults to: 10)

    maximum number of output lines shown at once

Returns:

  • (Array(Process::Status, Array<String>, Array<String>))

    three-element array of exit status, stdout lines, and stderr lines

  • (nil)

    when the command could not be started



865
866
867
868
869
870
871
872
# File 'lib/natty-ui/features.rb', line 865

def run(*, max_lines: 10, **)
  (Terminal.ansi? ? ShellRunner : DumbShellRunner).render(
    self,
    max_lines,
    *,
    **
  )
end

#section(title = nil, type: :default, border: :default) {|section| ... } ⇒ Object, Section Also known as: begin

Creates a Section element — a bordered container with an optional title.

Examples:

Manual close

sec = ui.section 'Results'
ui.ok 'All good'
sec.end

Block form with title

ui.section 'Summary' do
  ui.puts '3 files processed.'
end

Block form without title

ui.section do
  ui.puts 'Anonymous section content.'
end

Parameters:

  • title (#to_s, nil) (defaults to: nil)

    optional header text

  • type (:default, :message, :information, :warning, :error, :fatal) (defaults to: :default)

    visual style of the section

  • border (:default, :rounded, :single, :double, :heavy) (defaults to: :default)

    border style

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Section)

    itself, if no block is specified



510
511
512
# File 'lib/natty-ui/features.rb', line 510

def section(title = nil, type: :default, border: :default, &)
  __with(Section.new(self, title, type, border), &)
end

#select(*items, abortable: false, selected: nil) ⇒ Array #select(abortable: false, selected: nil, **pairs) ⇒ Array

Presents a list of options and returns all items the user selects.

In ANSI mode the user toggles items with Space and confirms with Enter. In dumb mode items are numbered and the user types item numbers.

Examples:

Positional items

picks = ui.select 'Kitty', 'iTerm2', 'Ghostty'

Positional items with all pre-selected

picks = ui.select 'A', 'B', 'C', selected: :all do
  ui.puts 'Choose features to enable:'
end

Keyword pairs

flags = ui.select verbose: 'Verbose', debug: 'Debug', trace: 'Trace'

Overloads:

  • #select(*items, abortable: false, selected: nil) ⇒ Array

    Items are passed as positional arguments; the selected items themselves are returned.

    Parameters:

    • items (#to_s, ...)

      options to choose from

    • abortable (Boolean) (defaults to: false)

      when true the user can press Esc to cancel

    • selected (nil, :all, #each) (defaults to: nil)

      pre-selected items: nil = none, :all = all, or an enumerable of item values to pre-select

  • #select(abortable: false, selected: nil, **pairs) ⇒ Array

    Items are passed as keyword pairs { return_value => label }; the matching keys are returned.

    Parameters:

    • abortable (Boolean) (defaults to: false)

      when true the user can press Esc to cancel

    • selected (nil, :all, #each) (defaults to: nil)
    • pairs (Hash{Object => #to_s})

      map of return values to labels

Yields:

Yield Parameters:

Returns:

  • (Array)

    keys of selected pairs, or nil if aborted



796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
# File 'lib/natty-ui/features.rb', line 796

def select(*items, abortable: false, selected: nil, **pairs)
  return if items.empty? && pairs.empty?
  yield(temp = temporary) if block_given?
  items = items.to_h { [it, it] }.merge!(pairs)
  (Terminal.ansi? ? Select : DumbSelect).new(
    self,
    if selected == :all
      items.map { it << true }
    elsif selected.is_a?(Enumerable)
      items.map { |ret, txt| [ret, txt, selected.include?(ret)] }
    elsif selected
      items.map { |ret, txt| [ret, txt, selected == ret] }
    else
      items.map { it << false }
    end
  ).select(abortable)
ensure
  temp&.end
end

#sh(*cmd, env = {}, shell: false, input: nil, **spawn_options) ⇒ Object

Executes a shell command and prints its output to the terminal.

All arguments and options are forwarded to Terminal.sh, which in turn uses Process.spawn.

Examples:

Run a simple command

ui.sh 'echo "Hello Ruby!"'

Pipe a string as stdin

ui.sh 'cat', input: 'Hello from stdin'

Parameters:

  • cmd (#to_s, ...)

    command and arguments, same as Process.spawn

  • env (Hash, nil) (defaults to: {})

    additional environment variables

  • shell (Boolean) (defaults to: false)

    when true runs the command through a system shell

  • input (defaults to: nil)

    piped standard input; accepts any object with #readpartial, #to_io, #each, #to_a, or anything IO.write accepts (e.g. a String)

  • spawn_options (Hash)

    additional options forwarded to Process.spawn



841
# File 'lib/natty-ui/features.rb', line 841

def sh(...) = Shell.render(self, ...)

#space(count = 1) ⇒ Features

Prints one or more blank lines.

Examples:

Print a single blank line

ui.space

Print three blank lines

ui.space 3

Parameters:

  • count (#to_int) (defaults to: 1)

    number of blank lines to print

Returns:



127
128
129
# File 'lib/natty-ui/features.rb', line 127

def space(count = 1)
  (count = count.to_int) < 1 ? self : puts(" \n" * count)
end

#table(**options) {|table| ... } ⇒ Features

Renders a Table to the terminal.

The method yields a Table object for population; if no block is given nothing is rendered.

Border name symbols: :rounded (default), :single, :double, :heavy, :single_double, :double_single, :single_heavy, :heavy_single

Examples:

Simple table with a double outer frame

ui.table border_frame: :double do |t|
  t.add_row '[b]Name', '[b]Score', align: :center
  t.add_row 'Alice', 42
  t.add_row 'Bob',   17
end

Parameters:

  • options (Hash)

    a customizable set of options

Options Hash (**options):

  • :border (:default, :none, :single, :double, :heavy) — default: :default

    default border used for all border parts

  • :border_frame (nil, :none, :single, :double, :heavy)

    outer frame; falls back to :border

  • :border_vertical (nil, :none, :single, :double, :heavy)

    vertical column separators; falls back to :border

  • :border_horizontal (nil, :none, :single, :double, :heavy)

    horizontal row separators; falls back to :border

  • :border_style (Symbol, String, Array<Style>, Array<String>, nil)

    ANSI style applied to all borders

  • :frame (Symbol, Array<Symbol>) — default: :all

    which frame sides to draw: :all or an enumerable of :top, :right, :bottom, :left

  • :width (#to_int, Float, :max, nil)

    :max expands to the full terminal width; a negative #to_int is an offset from the terminal width; a Float is a fraction of the terminal width

Yields:

  • (table)

    a Table instance to populate with rows and cells

Yield Parameters:

  • table (Table)

    the table

Returns:



406
407
408
409
410
411
# File 'lib/natty-ui/features.rb', line 406

def table(**options)
  return self unless block_given?
  yield(table = Table.new)
  return self if table.empty?
  puts(*TableRenderer.lines(columns, table, **options), bbcode: false)
end

#task(title, pin: false) {|task| ... } ⇒ Object, Task

Creates a Task element — a labelled step that shows a spinner while running and a check mark on success.

Examples:

Manual close

t = ui.task 'Installing dependencies'
run_install
t.end

Block form

ui.task 'Installing dependencies' do
  run_install
end

Parameters:

  • title (#to_s)

    task description

  • pin (Boolean) (defaults to: false)

    whether the task title should be pinned

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Task)

    itself, if no block is specified



617
# File 'lib/natty-ui/features.rb', line 617

def task(title, pin: false, &) = __with(Task.new(self, title, pin), &)

#temporary {|temp| ... } ⇒ Object, Temporary

Creates a Temporary element whose output is erased when it closes.

Examples:

Manual close

tmp = ui.temporary
ui.puts 'Loading…'
sleep 1
tmp.end   # erases "Loading…"

Block form

ui.temporary do
  ui.puts 'Thinking…'
  sleep 2
end  # "Thinking…" is erased here

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Temporary)

    itself, if no block is specified



439
# File 'lib/natty-ui/features.rb', line 439

def temporary(&) = __with(Temporary.new(self), &)

#vbars(values, min: nil, max: nil, normalize: false, height: 10, bar_width: 3, style: nil) ⇒ Features

Prints a vertical bar chart.

All values must be non-negative.

Examples:

Simple bar chart

ui.vbars [3, 7, 2, 9, 5]

Normalised chart with custom height

ui.vbars [10, 40, 25, 60], normalize: true, height: 15

Parameters:

  • values (#each)

    collection of non-negative Numeric values

  • min (Numeric, nil) (defaults to: nil)

    lower bound for scaling; nil uses the data minimum

  • max (Numeric, nil) (defaults to: nil)

    upper bound for scaling; nil uses the data maximum

  • normalize (Boolean) (defaults to: false)

    when true applies min-max normalization; when false scales each bar relative to the maximum value

  • height (#to_int) (defaults to: 10)

    chart height in lines (minimum 3; default: 10)

  • bar_width (#to_int, :auto) (defaults to: 3)

    width of each bar in characters; :auto fits the graph in available terminal width

  • style (Symbol, String, Array<Style>, Array<String>, nil) (defaults to: nil)

    ANSI style applied to the bars

Returns:

Raises:

  • (ArgumentError)


317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/natty-ui/features.rb', line 317

def vbars(
  values,
  min: nil,
  max: nil,
  normalize: false,
  height: 10,
  bar_width: 3,
  style: nil
)
  bars = VBars.new(values, min, max, normalize)
  return self if bars.empty?
  raise(ArgumentError, 'values can not be negative') unless bars.valid?
  puts(*bars.lines(columns, height, bar_width, style), bbcode: false)
end

#warning(title, border: :default) {|section| ... } ⇒ Object, Section Also known as: warn

Creates a Section with :warning styling.

Parameters:

  • title (#to_s)

    header text

  • border (:default, :rounded, :single, :double, :heavy) (defaults to: :default)

    border style

Yields:

Yield Parameters:

Returns:

  • (Object)

    return value of the block

  • (Section)

    itself, if no block is specified



544
545
546
# File 'lib/natty-ui/features.rb', line 544

def warning(title, border: :default, &)
  section(title, border:, type: :warning, &)
end