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)


676
677
678
679
680
681
682
# File 'lib/natty-ui/features.rb', line 676

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



754
755
756
757
758
759
760
761
762
763
764
# File 'lib/natty-ui/features.rb', line 754

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



560
561
562
# File 'lib/natty-ui/features.rb', line 560

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



570
571
572
# File 'lib/natty-ui/features.rb', line 570

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'
frm.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



599
600
601
# File 'lib/natty-ui/features.rb', line 599

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:



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

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

#h2(title) ⇒ Features

Prints a level-2 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



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

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

#h3(title) ⇒ Features

Prints a level-3 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



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

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

#h4(title) ⇒ Features

Prints a level-4 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



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

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

#h5(title) ⇒ Features

Prints a level-5 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



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

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

#h6(title) ⇒ Features

Prints a level-6 heading.

Parameters:

  • title (#to_s)

    heading text

Returns:



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

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)


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

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:



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

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:



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

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



538
539
540
# File 'lib/natty-ui/features.rb', line 538

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:



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

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



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

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:



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

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



527
528
529
# File 'lib/natty-ui/features.rb', line 527

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:



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

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:



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

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



646
647
648
649
650
651
652
653
654
655
656
# File 'lib/natty-ui/features.rb', line 646

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
116
# 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 prefix.is_a?(StrConst)
      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 cprefix.is_a?(StrConst)
      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 suffix.is_a?(StrConst)
      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 csuffix.is_a?(StrConst)
      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



704
705
706
707
708
709
710
711
712
713
714
715
716
717
# File 'lib/natty-ui/features.rb', line 704

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:



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

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



870
871
872
873
874
875
876
877
# File 'lib/natty-ui/features.rb', line 870

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'
sec.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



515
516
517
# File 'lib/natty-ui/features.rb', line 515

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



801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
# File 'lib/natty-ui/features.rb', line 801

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



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

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:



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

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:



407
408
409
410
411
412
413
414
415
416
# File 'lib/natty-ui/features.rb', line 407

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,
    eol: :no_paragraph
  )
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



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

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
tmp.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



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

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)


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

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



549
550
551
# File 'lib/natty-ui/features.rb', line 549

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