Module: NattyUI::Features

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

Overview

These are all supported features by NattyUI or any other sub- element like #section, #message, #information, #warning, #error, #failed, #framed, #task, ...

Any printed text can contain BBCode-like embedded ANSI attributes which will be used when the output terminal supports attributes and colors.

Printing Methods collapse

Sub-Elements collapse

User Interaction collapse

Utilities collapse

Instance Method Details

#await(yes: 'Enter', no: 'Esc') ⇒ true, ... #await(yes: 'Enter', no: 'Esc') {|temp| ... } ⇒ true, ...

Wait for user input.

Examples:

Wait until user wants to coninue

ui.await { ui.puts '[faint][\\Press ENTER to continue...][/faint]' }

Ask yes/no-question

ui.await(yes: %w[j o t s y d Enter], no: %w[n Esc]) do
  ui.puts 'Do you like NayttUI?'
end
# => true, for user's YES
# => false, for user's NO
# Info:
# The keys will work for Afrikaans, Dutch, English, French, German,
# Italian, Polish, Portuguese, Romanian, Spanish and Swedish.

Overloads:

  • #await(yes: 'Enter', no: 'Esc') {|temp| ... } ⇒ true, ...

    Yield Parameters:

    • temp (Temporary)

      temporary displayed section (section will be erased after input)

Parameters:

  • yes (String, Enumerable<String>) (defaults to: 'Enter')

    key code/s a user can input to return positive result

  • no (String, Enumerable<String>) (defaults to: 'Esc')

    key code/s a user can input to return negative resault

Returns:

  • (true, false)

    whether the user inputs a positive result

  • (nil)

    in error case



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

def await(yes: 'Enter', no: 'Esc')
  return __await(yes, no) unless block_given?
  temporary do |temp|
    yield(temp)
    __await(yes, no)
  end
end

#choice(*choices, abortable: false) ⇒ Integer? #choice(*choices, abortable: false) {|temp| ... } ⇒ Integer? #choice(**choices, abortable: false) ⇒ Object? #choice(**choices, abortable: false) {|temp| ... } ⇒ Object?

Allows the user to select an option from a selection. The selected option is returned.

Overloads:

  • #choice(*choices, abortable: false) ⇒ Integer?

    Parameters:

    • choices (#to_s)

      one or more alternatives to select from

    • abortable (true, false) (defaults to: false)

      whether the user is allowed to abort with 'Esc' or 'Ctrl+c'

    Returns:

    • (Integer)

      index of selected choice

    • (nil)

      when user aborted the selection

  • #choice(*choices, abortable: false) {|temp| ... } ⇒ Integer?

    Examples:

    Request a fruit

    ui.choice('Apple', 'Banana', 'Orange') { ui.puts 'What do you prefer?' }
    # => 0, when user likes apples
    # => 1, when bananas are user's favorite
    # => 2, when user is a oranges lover

    Parameters:

    • choices (#to_s)

      one or more alternatives to select from

    • abortable (true, false) (defaults to: false)

      whether the user is allowed to abort with 'Esc' or 'Ctrl+c'

    Yield Parameters:

    • temp (Temporary)

      temporary displayed section (section will be erased after input)

    Returns:

    • (Integer)

      index of selected choice

    • (nil)

      when user aborted the selection

  • #choice(**choices, abortable: false) ⇒ Object?

    Parameters:

    • choices (#to_s)

      one or more alternatives to select from

    • abortable (true, false) (defaults to: false)

      whether the user is allowed to abort with 'Esc' or 'Ctrl+c'

    • selected (#to_s, nil)

      optionally pre-selected option

    Returns:

    • (Object)

      key for selected choice

    • (nil)

      when user aborted the selection

  • #choice(**choices, abortable: false) {|temp| ... } ⇒ Object?

    Examples:

    Request a preference

    ui.choice(
      k: 'Kitty',
      i: 'iTerm2',
      g: 'Ghostty',
      t: 'Tabby',
      r: 'Rio',
      abortable: true
    ) { ui.puts 'Which terminal emulator do you like?' }
    # => whether the user selected: :k, :i, :g, :t, :r
    # => nil, when the user aborted

    Parameters:

    • choices (#to_s)

      one or more alternatives to select from

    • abortable (true, false) (defaults to: false)

      whether the user is allowed to abort with 'Esc' or 'Ctrl+c'

    • selected (Integer)

      pre-selected option index

    Yield Parameters:

    • temp (Temporary)

      temporary displayed section (section will be erased after input)

    Returns:

    • (Object)

      key for selected choice

    • (nil)

      when user aborted the selection



952
953
954
955
956
957
958
959
960
961
# File 'lib/natty-ui/features.rb', line 952

def choice(*choices, abortable: false, selected: nil, **kwchoices, &block)
  return if choices.empty? && kwchoices.empty?
  choice =
    if Terminal.ansi?
      Choice.new(self, choices, kwchoices, abortable, selected)
    else
      DumbChoice.new(self, choices, kwchoices, abortable)
    end
  __with(choice) { choice.select(&block) }
end

#cols(*columns, **attributes) {|row| ... } ⇒ Features

Print text in columns. This is a shorthand to define a Table with a single row.

Parameters:

  • columns (#to_s)

    two or more convertible objects to print side by side

  • attributes ({Symbol => Object})

    attributes for the table and default attributes for table cells

Options Hash (**attributes):

  • :width (Integer) — default: nil

    width of a column, see Attributes::Width

  • :border (Symbol) — default: nil

    kind of border, see Table::Attributes

  • :border_style (Enumerable<Symbol>) — default: nil

    style of border, see Table::Attributes

  • :border_around (true, false) — default: false

    whether the table should have a border around, see Table::Attributes

  • :position (:left, :right, :centered) — default: false

    where to align the table, see Table::Attributes

Yield Parameters:

  • row (Table::Row)

    helper to define the row layout

Returns:



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

def cols(*columns, **attributes)
  tab_att, att = Utils.split_table_attr(attributes)
  table(**tab_att) do |table|
    table.add do |row|
      columns.each { row.add(_1, **att) }
      yield(row) if block_given?
    end
  end
end

#div(*text, **attributes) ⇒ Features

Print a text division with attributes. This is a shorthand to define a Table with a single cell.

Parameters:

  • attributes ({Symbol => Object})

    attributes for the division

  • text (*#to_s)

    one or more objects to print line by line

Options Hash (**attributes):

  • :align (:left, :right, :centered) — default: :left

    text alignment, see Attributes::Align

  • :padding (Integer, Enumerable<Integer>) — default: nil

    text padding, see Attributes::Padding

  • :style (Enumerable<Symbol>) — default: nil

    text style, see Attributes::Style

  • :width (Integer) — default: nil

    width of the cell, see Attributes::Width

  • :border (Symbol) — default: nil

    kind of border, see Table::Attributes

  • :border_style (Enumerable<Symbol>) — default: nil

    style of border, see Table::Attributes

  • :border_around (true, false) — default: false

    whether the table should have a border around, see Table::Attributes

  • :position (:left, :right, :centered) — default: false

    where to align the table, see Table::Attributes

Returns:



434
435
436
437
438
439
# File 'lib/natty-ui/features.rb', line 434

def div(*text, **attributes)
  return self if text.empty?
  tab_att, att = Utils.split_table_attr(attributes)
  tab_att[:border_around] = true
  table(**tab_att) { |table| table.add { _1.add(*text, **att) } }
end

#error(title) {|message| ... } ⇒ Object #error(title, *text, **options) ⇒ Section Also known as: err

Create a visually separated section marked as error with title for the output of text elements.

Like any other Element sections support all NattyUI::Features.

Overloads:

  • #error(title) {|message| ... } ⇒ Object

    Returns the result of the given block.

    Parameters:

    • title (#to_s)

      section title

    Yield Parameters:

    Returns:

    • (Object)

      the result of the given block

  • #error(title, *text, **options) ⇒ Section

    Returns itself.

    Parameters:

    • title (#to_s)

      section title

    • text (*#to_s)

      optional objects to print line by line

    • options ({Symbol => Object})

      print options – see #puts

    Returns:



750
751
752
# File 'lib/natty-ui/features.rb', line 750

def error(title, *text, **options, &block)
  __sec(:error, true, title, text, options, &block)
end

#failed(title) {|message| ... } ⇒ Object #failed(title, *text, **options) ⇒ Section

Create a visually separated section marked as failure with title for the output of text elements.

Like any other Element sections support all NattyUI::Features.

Overloads:

  • #failed(title) {|message| ... } ⇒ Object

    Returns the result of the given block.

    Parameters:

    • title (#to_s)

      section title

    Yield Parameters:

    Returns:

    • (Object)

      the result of the given block

  • #failed(title, *text, **options) ⇒ Section

    Returns itself.

    Parameters:

    • title (#to_s)

      section title

    • text (*#to_s)

      optional objects to print line by line

    • options ({Symbol => Object})

      print options – see #puts

    Returns:



759
760
761
# File 'lib/natty-ui/features.rb', line 759

def failed(title, *text, **options, &block)
  __sec(:failed, true, title, text, options, &block)
end

#framed(align: :left, border: :default, border_style: nil) {|framed| ... } ⇒ Object #framed(*text, align: :left, border: :default, border_style: nil, **options) ⇒ Element

Create a framed section. Like any other Element sections support all NattyUI::Features.

Overloads:

  • #framed(align: :left, border: :default, border_style: nil) {|framed| ... } ⇒ Object

    Returns the result of the given block.

    Parameters:

    Yield Parameters:

    Returns:

    • (Object)

      the result of the given block

  • #framed(*text, align: :left, border: :default, border_style: nil, **options) ⇒ Element

    Returns itself.

    Parameters:

    • text (*#to_s)

      optional objects to print line by line

    • align (:left, :right, :centered) (defaults to: :left)

      text alignment, see Attributes::Align

    • border (Symbol) (defaults to: :default)

      kind of border, see Attributes::Border

    • border_style (Enumerable<Symbol>) (defaults to: nil)

      style of border, see Attributes::BorderStyle

    • options ({Symbol => Object})

      print options – see #puts

    Returns:



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

def framed(
  *text,
  align: :left,
  border: :default,
  border_style: nil,
  **options,
  &block
)
  __with(
    Framed.new(
      self,
      Utils.align(align),
      Theme.current.border(border),
      Utils.style(border_style)
    ),
    *text,
    **options,
    &block
  )
end

#h1(*text) ⇒ Features

Print given text as a H1 #heading.

Parameters:

  • text (*#to_s)

    one or more objects to print line by line

Returns:



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

def h1(*text) = heading(1, *text)

#h2(*text) ⇒ Features

Print given text as a H2 #heading.

Parameters:

  • text (*#to_s)

    one or more objects to print line by line

Returns:



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

def h2(*text) = heading(2, *text)

#h3(*text) ⇒ Features

Print given text as a H3 #heading.

Parameters:

  • text (*#to_s)

    one or more objects to print line by line

Returns:



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

def h3(*text) = heading(3, *text)

#h4(*text) ⇒ Features

Print given text as a H4 #heading.

Parameters:

  • text (*#to_s)

    one or more objects to print line by line

Returns:



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

def h4(*text) = heading(4, *text)

#h5(*text) ⇒ Features

Print given text as a H5 #heading.

Parameters:

  • text (*#to_s)

    one or more objects to print line by line

Returns:



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

def h5(*text) = heading(5, *text)

#h6(*text) ⇒ Features

Print given text as a H6 #heading.

Parameters:

  • text (*#to_s)

    one or more objects to print line by line

Returns:



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

def h6(*text) = heading(6, *text)

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

Dump given values as horizontal bars.

Examples:

Draw green bars

ui.hbars 1..10, style: :green

Draw bars in half sreen width

ui.hbars 1..10, style: :blue, width: 0.5

Parameters:

  • values (#to_a, Array<Numeric>)

    values to print

  • min (#to_f) (defaults to: nil)

    start value

  • max (#to_f) (defaults to: nil)

    end value

  • normalize (true, false) (defaults to: false)

    whether the values should be normalized

  • text (true, false) (defaults to: true)

    whether the values should be printed too

  • width (:auto, :min, Integer) (defaults to: :auto)

    with of each bar

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

    bar drawing style

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

    text style

Returns:

Raises:

  • (ArgumentError)

    if any value is negative



501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
# File 'lib/natty-ui/features.rb', line 501

def hbars(
  values,
  min: nil,
  max: nil,
  normalize: false,
  text: true,
  width: :auto,
  style: nil,
  text_style: nil
)
  return self if (values = values.to_a).empty?
  if values.any?(&:negative?)
    raise(ArgumentError, 'values can not be negative')
  end
  style = text_style = nil unless Terminal.ansi?
  renderer = HBarsRenderer.new(values, min, max)
  renderer.with_text(text_style) if text
  puts(*renderer.lines(Utils.as_size(3..columns, width), style, normalize))
end

#heading(level, *text) ⇒ Features

Print given text as a heading.

There are specific shortcuts for heading levels: #h1, #h2, #h3, #h4, #h5, #h6.

Examples:

Print a level 1 heading

ui.heading(1, 'This is a H1 heading element')
# => ╴╶╴╶─═══ This is a H1 heading element ═══─╴╶╴╶

Parameters:

  • level (#to_i)

    heading level, one of 1..6

  • text (*#to_s)

    one or more objects to print line by line

Returns:



240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/natty-ui/features.rb', line 240

def heading(level, *text)
  prefix, suffix = Theme.current.heading(level)
  puts(
    *text,
    max_width: columns,
    prefix: prefix,
    prefix_width: prefix.width,
    suffix: suffix,
    suffix_width: suffix.width,
    align: :centered
  )
end

#hr(type = :default) ⇒ Features

Print a horizontal rule.

Examples:

Print double line

ui.hr :double

Parameters:

  • type (Symbol) (defaults to: :default)

    border type

Returns:



304
305
306
307
308
# File 'lib/natty-ui/features.rb', line 304

def hr(type = :default)
  theme = Theme.current
  bc = theme.border(type)[10]
  puts("#{theme.heading_sytle}#{bc * columns}")
end

#information(title) {|message| ... } ⇒ Object #information(title, *text, **options) ⇒ Section Also known as: info

Create a visually separated section marked as informational with title for the output of text elements.

Like any other Element sections support all NattyUI::Features.

Overloads:

  • #information(title) {|message| ... } ⇒ Object

    Returns the result of the given block.

    Parameters:

    • title (#to_s)

      section title

    Yield Parameters:

    Returns:

    • (Object)

      the result of the given block

  • #information(title, *text, **options) ⇒ Section

    Returns itself.

    Parameters:

    • title (#to_s)

      section title

    • text (*#to_s)

      optional objects to print line by line

    • options ({Symbol => Object})

      print options – see #puts

    Returns:



732
733
734
# File 'lib/natty-ui/features.rb', line 732

def information(title, *text, **options, &block)
  __sec(:information, true, title, text, options, &block)
end

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

Print given items as list (like 'ls' command).

Each list item will optionally be decorated with the given glyph as:

  • Integer as the start value for a numbered list
  • Symbol as the start symbol
  • :hex to create a hexadecimal numbered list
  • any text as prefix

Examples:

Print all Ruby files as a numbered list

ui.ls Dir['*/**/*.rb'], glyph: 1

Print all Ruby files as a bullet point list (with green bullets)

ui.ls Dir['*/**/*.rb'], glyph: '[green]•[/fg]'

Parameters:

  • items (#to_s)

    one or more convertible objects to list

  • compact (true, false) (defaults to: true)

    whether the compact display format should be used

  • glyph (Integer, :hex, Symbol, #to_s) (defaults to: nil)

    glyph to be used as prefix

Returns:



343
344
345
346
347
# File 'lib/natty-ui/features.rb', line 343

def ls(*items, compact: true, glyph: nil)
  return self if items.empty?
  renderer = compact ? CompactLSRenderer : LSRenderer
  puts(*renderer.lines(items, glyph, columns))
end

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

Print given text with a decoration mark.

Parameters:

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

    marker type

  • text (*#to_s)

    one or more objects to print line by line

Returns:



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

def mark(*text, mark: :default, **options)
  mark = Theme.current.mark(mark)
  options[:first_line_prefix] = mark
  options[:first_line_prefix_width] = mark.width
  puts(*text, **options)
end

#message(title) {|message| ... } ⇒ Object #message(title, *text, **options) ⇒ Section Also known as: msg

Create a visually separated section with title for the output of text elements.

Like any other Element sections support all NattyUI::Features.

Overloads:

  • #message(title) {|message| ... } ⇒ Object

    Returns the result of the given block.

    Parameters:

    • title (#to_s)

      section title

    Yield Parameters:

    Returns:

    • (Object)

      the result of the given block

  • #message(title, *text, **options) ⇒ Section

    Returns itself.

    Parameters:

    • title (#to_s)

      section title

    • text (*#to_s)

      optional objects to print line by line

    • options ({Symbol => Object})

      print options – see #puts

    Returns:



723
724
725
# File 'lib/natty-ui/features.rb', line 723

def message(title, *text, **options, &block)
  __sec(:message, false, title, text, options, &block)
end

#options(abortable: false, selected: nil, **choices) {|temp| ... } ⇒ {#to_s => [true,false]}?

Allows the user to select from several options. All options are returned with their selection status.

Parameters:

  • choices ({#to_s => [true,false]})

    Hash of options and their selection state

  • abortable (true, false) (defaults to: false)

    whether the user is allowed to abort with 'Esc' or 'Ctrl+c'

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

    optionally pre-selected key

Yield Parameters:

  • temp (Temporary)

    temporary displayed section (section will be erased after input)

Returns:

  • ({#to_s => [true,false]})

    Hash of options and their selection state

  • (nil)

    when user aborted the selection



980
981
982
983
984
985
986
987
988
989
# File 'lib/natty-ui/features.rb', line 980

def options(abortable: false, selected: nil, **choices, &block)
  return {} if choices.empty?
  options =
    if Terminal.ansi?
      Options.new(self, choices, abortable, selected)
    else
      DumbOptions.new(self, choices, abortable, selected)
    end
  __with(options) { options.select(&block) }
end

#pin(*text, mark: nil, **options) ⇒ Features

Print given text as lines like #puts. Used in elements with temporary output like #task the text will be kept ("pinned").

It can optionally have a decoration marker in first line like #mark.

Examples:

Print two lines decorated as information which are pinned

ui.task 'Do something important' do |task|
  # ...
  task.pin("This is text", "which is pinned", mark: :information)
  # ...
end
# => ✓ Do something important
# =>   𝒊 This is text
# =>     which is pinned.

Parameters:

  • text (*#to_s)

    one or more objects to print line by line

  • options ({Symbol => Object})
  • mark (Symbol, #to_s) (defaults to: nil)

    marker type

Options Hash (**options):

  • :align (:left, :right, :centered) — default: :left

    text alignment

  • :eol (true, false) — default: true

    whether to respect newline characters

Returns:



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

def pin(*text, mark: nil, **options)
  mark(*text, mark: mark, pin: true, **options)
end

#progress(title, max: nil, pin: false) ⇒ ProgressHelper #progress(title, max: nil, pin: false) {|progress| ... } ⇒ Object

Dynamically display a task progress. When a max parameter is given the progress will be displayed as a progress bar below the title. Otherwise the progress is displayed just by accumulating dots.

Examples:

Display a progress bar

ui.progress('Download file', max: 1024) do |progress|
  while progress.value < progress.max
    # just to simulate the download
    sleep(0.1)
    bytes_read = rand(10..128)

    # here we actualize the progress
    progress.value += bytes_read
  end
end

Display simple progress

progress = ui.progress 'Check some stuff'
10.times do
  # simulate some work
  sleep 0.1

  # here we actualize the progress
  progress.step
end
progress.ok 'Stuff checked ok'

Overloads:

  • #progress(title, max: nil, pin: false) ⇒ ProgressHelper

    Returns itself.

    Parameters:

    • title (#to_s)

      title text to display

    • max (#to_f) (defaults to: nil)

      expected maximum value

    • pin (true, false) (defaults to: false)

      whether the final progress state should be "pinned" to parent element

    Returns:

  • #progress(title, max: nil, pin: false) {|progress| ... } ⇒ Object

    Returns the result of the given block.

    Parameters:

    • title (#to_s)

      title text

    • max (#to_f) (defaults to: nil)

      expected maximum value

    • pin (true, false) (defaults to: false)

      whether the final progress state should be "pinned" to parent element

    Yield Parameters:

    Returns:

    • (Object)

      the result of the given block



573
574
575
576
577
578
579
580
581
582
# File 'lib/natty-ui/features.rb', line 573

def progress(title, max: nil, pin: false, &block)
  __with(
    if Terminal.ansi?
      Progress.new(self, title, max, pin)
    else
      DumbProgress.new(self, title, max)
    end,
    &block
  )
end

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

Print given text as lines.

Examples:

Print two lines text, right aligned

ui.puts "Two lines", "of nice text", align: :right
# =>    Two lines
# => of nice text

Print two lines text, with a prefix

ui.puts "Two lines", "of nice text", prefix: ': '
# => : Two lines
# => : of nice text

Parameters:

  • text (*#to_s)

    one or more objects to print line by line

  • options ({Symbol => Object})

Options Hash (**options):

  • :align (:left, :right, :centered) — default: :left

    text alignment

  • :eol (true, false) — default: true

    whether to respect newline characters

Returns:

See Also:



40
41
42
43
44
45
46
47
48
49
50
51
52
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/natty-ui/features.rb', line 40

def puts(*text, **options)
  if options.empty?
    bbcode = true
    max_width = Terminal.columns
  else
    bbcode = true if (bbcode = options[:bbcode]).nil?
    ignore_newline = options[:eol] == false || options[:ignore_newline]

    if (max_width = options[:max_width]).nil?
      max_width = Terminal.columns
    elsif max_width < 1
      if max_width > 0
        max_width *= Terminal.columns
      elsif max_width < 0
        max_width += Terminal.columns
      else
        return self
      end
    end

    return self if max_width <= 0

    prefix_width =
      if (prefix = options[:prefix])
        prefix = Ansi.bbcode(prefix) if bbcode
        options[:prefix_width] || Text.width(prefix, bbcode: false)
      else
        0
      end

    if (first_line = options[:first_line_prefix])
      first_line = Ansi.bbcode(first_line) if bbcode
      first_line_width =
        options[:first_line_prefix_width] ||
          Text.width(first_line, bbcode: false)

      if prefix_width < first_line_width
        prefix_next = "#{prefix}#{' ' * (first_line_width - prefix_width)}"
        prefix = first_line
        prefix_width = first_line_width
      else
        prefix_next = prefix
        prefix =
          if first_line_width < prefix_width
            first_line + (' ' * (prefix_width - first_line_width))
          else
            first_line
          end
      end
    end

    max_width -= prefix_width

    if (suffix = options[:suffix])
      suffix = Ansi.bbcode(suffix) if bbcode
      max_width -=
        options[:suffix_width] || Text.width(suffix, bbcode: false)
    end
  end

  return self if max_width <= 0

  lines =
    Text.each_line_with_size(
      *text,
      limit: max_width,
      bbcode: bbcode,
      ansi: Terminal.ansi?,
      ignore_newline: ignore_newline
    )
  tail = options[:tail] and lines = lines.to_a.last(tail)
  @__eol ||= Terminal.ansi? ? "\e[m\n" : "\n"

  if (align = options[:align]).nil?
    lines.each do |line, _|
      Terminal.print(prefix, line, suffix, @__eol, bbcode: false)
      @lines_written += 1
      prefix, prefix_next = prefix_next, nil if prefix_next
    end
    return self
  end

  unless options[:expand]
    max_width = (lines = lines.to_a).max_by(&:last)[-1]
  end

  case align
  when :right
    lines.each do |line, width|
      Terminal.print(
        prefix,
        ' ' * (max_width - width),
        line,
        suffix,
        @__eol,
        bbcode: false
      )
      @lines_written += 1
      prefix, prefix_next = prefix_next, nil if prefix_next
    end
  when :centered
    lines.each do |line, width|
      space = max_width - width
      Terminal.print(
        prefix,
        ' ' * (lw = space / 2),
        line,
        ' ' * (space - lw),
        suffix,
        @__eol,
        bbcode: false
      )
      @lines_written += 1
      prefix, prefix_next = prefix_next, nil if prefix_next
    end
  else
    lines.each do |line, width|
      Terminal.print(
        prefix,
        line,
        ' ' * (max_width - width),
        suffix,
        @__eol,
        bbcode: false
      )
      @lines_written += 1
      prefix, prefix_next = prefix_next, nil if prefix_next
    end
  end
  self
end

#quote(*text) ⇒ Features

Print given text as a quotation.

Parameters:

  • text (*#to_s)

    one or more objects to print line by line

Returns:



215
216
217
218
219
220
221
222
223
224
# File 'lib/natty-ui/features.rb', line 215

def quote(*text)
  width = columns * 0.75
  quote = Theme.current.mark(:quote)
  puts(
    *text,
    prefix: quote,
    prefix_width: quote.width,
    max_width: width < 20 ? nil : width.round
  )
end

#run(*cmd, preserve_spaces: false, max_lines: 10, **options) ⇒ [Process::Status, Array<String>, Array<String>]?

Execute a shell program and return output. Limit the lines displayed.

Examples:

Capture output and error

status, out, err = ui.run('ls ./ && ls ./this_does_not_exist')
# => #<Process::Status: pid 25562 exit 1>
# => [...] # the output of first `ls`
# => ["ls: ./this_does_not_exist: No such file or directory"]

Parameters:

  • cmd (String)

    command and optional arguments

  • preserve_spaces (true, false) (defaults to: false)

    whether the spaces and tabs of the output should be preserve

  • max_lines (Integer) (defaults to: 10)

    limit of displayed lines

  • options (Hash)

    executions options

Returns:

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

    process status, output and error output when command was executed

  • (nil)

    in error case (like command not found)

See Also:



633
634
635
636
637
638
639
640
641
642
643
# File 'lib/natty-ui/features.rb', line 633

def run(*cmd, preserve_spaces: false, max_lines: 10, **options)
  result =
    ShellRenderer.run(
      self,
      cmd,
      options,
      preserve_spaces,
      max_lines.clamp(1, Terminal.rows)
    )
  result if result[0]
end

#section {|section| ... } ⇒ Object #section(*text, **options) ⇒ Section Also known as: begin

Create a visually separated section for the output of text elements. Besides this simple sections there exist sections of different kinds: #message, #information, #warning, #error, #failed, #framed

Like any other Element sections support all NattyUI::Features.

Overloads:

  • #section {|section| ... } ⇒ Object

    Returns the result of the given block.

    Examples:

    ui.section do |section|
      section.h1 'About Sections'
      section.space
      section.puts 'Sections are areas of text elements.'
      section.puts 'You can use any other feature inside such an area.'
    end
    # => ╭────╶╶╶
    # => │ ╴╶╴╶─═══ About Sections ═══─╴╶╴╶
    # => │
    # => │ Sections are areas of text elements.
    # => │ You can use any other feature inside such an area.
    # => ╰──── ─╶╶╶

    Yield Parameters:

    Returns:

    • (Object)

      the result of the given block

  • #section(*text, **options) ⇒ Section

    Returns itself.

    Examples:

    section = ui.section
    section.h1 'About Sections'
    section.space
    section.puts 'Sections are areas of text elements.'
    section.end # close the section

    Parameters:

    • text (*#to_s)

      optional objects to print line by line

    • options ({Symbol => Object})

      print options – see #puts

    Returns:



694
695
696
# File 'lib/natty-ui/features.rb', line 694

def section(*text, **options, &block)
  __sec(:default, false, nil, text, options, &block)
end

#select(*choices, abortable: false, selected: nil) {|temp| ... } ⇒ Array<#to_s>?

Allows the user to select from several options. The selected options are returned.

Examples:

Select a terminal

ui.select %w[Kitty iTerm2 Ghostty Tabby Rio] do
 ui.puts '[i]Which terminal applications did you already tested?[/i]'
end

Parameters:

  • choices (Array<#to_s>)

    selectable options

  • abortable (true, false) (defaults to: false)

    whether the user is allowed to abort with 'Esc' or 'Ctrl+c'

  • selected (Integer, :all, nil) (defaults to: nil)

    optionally pre-selected option index or :all to pre-select all items

Yield Parameters:

  • temp (Temporary)

    temporary displayed section (section will be erased after input)

Returns:

  • (Array<#to_s>)

    selected options

  • (nil)

    when user aborted the selection



1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
# File 'lib/natty-ui/features.rb', line 1012

def select(*choices, abortable: false, selected: nil, &block)
  return [] if choices.empty?
  choices = choices[0] if choices.size == 1 && choices[0].is_a?(Enumerable)
  if selected == :all
    sel = true
  elsif selected
    selected = choices[selected.to_i]
  end
  options(
    abortable: abortable,
    selected: selected,
    **choices.to_h { [_1, sel] },
    &block
  ).filter_map { |key, selected| key if selected }
end

#sh(*cmd, preserve_spaces: false, **options) ⇒ Process::Status?

Execute a program.

Examples:

Execute a simple command

ui.sh 'ls'

Execute a command wih arguments

ret = ui.sh('curl', '--version')
raise('Curl not found') unless ret&.success?

Execute shell commands

ui.sh "mkdir 'test' && cd 'test'"

Execute a command with environment variables

ui.sh({'ENV' => 'test'}, 'rails')

Parameters:

  • cmd (String)

    command and optional arguments

  • preserve_spaces (true, false) (defaults to: false)

    whether the spaces and tabs of the output should be preserve

  • options (Hash)

    executions options

Returns:

  • (Process::Status)

    when command was executed

  • (nil)

    in error case (like command not found)

See Also:



608
609
610
# File 'lib/natty-ui/features.rb', line 608

def sh(*cmd, preserve_spaces: false, **options)
  ShellRenderer.sh(self, cmd, options, preserve_spaces)
end

#space(count = 1) ⇒ Features

Print one or more space lines.

Parameters:

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

    lines to print

Returns:



316
317
318
# File 'lib/natty-ui/features.rb', line 316

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

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

Generate and print a table. See Table for much more details about table generation.

Examples:

Draw a very simple 3x4 table with complete borders

ui.table(border: :default, border_around: true, padding: [0, 1]) do |table|
  table.add 1, 2, 3, 4
  table.add 5, 6, 7, 8
  table.add 9, 10, 11, 12
end

Parameters:

  • attributes ({Symbol => Object})

    attributes for the table and default attributes for table cells

Options Hash (**attributes):

  • :border (Symbol) — default: nil

    kind of border, see Table::Attributes

  • :border_style (Enumerable<Symbol>) — default: nil

    style of border, see Table::Attributes

  • :border_around (true, false) — default: false

    whether the table should have a border around, see Table::Attributes

  • :position (:left, :right, :centered) — default: false

    where to align the table, see Table::Attributes

Yield Parameters:

  • table (Table)

    helper to define the table layout

Returns:



378
379
380
381
382
383
384
385
386
# File 'lib/natty-ui/features.rb', line 378

def table(**attributes)
  return self unless block_given?
  yield(table = Table.new(**attributes))
  puts(
    *TableRenderer[table, columns],
    align: table.attributes.position,
    expand: true
  )
end

#task(title, *text, pin: false, **options) {|task| ... } ⇒ Task

Generate a task section.

Parameters:

  • title (#to_s)

    task title text

  • text (*#to_s)

    optional objects to print line by line

  • pin (true, false) (defaults to: false)

    whether to keep text "pinned"

  • options ({Symbol => Object})

    print options – see #puts

Yield Parameters:

  • task (Task)

    itself

Returns:



828
829
830
# File 'lib/natty-ui/features.rb', line 828

def task(title, *text, pin: false, **options, &block)
  __with(Task.new(self, title, pin), *text, **options, &block)
end

#temporary(*text, **options) {|temp| ... } ⇒ Object

Display some temporary content. The content displayed in the block will be erased after the block ends.

Examples:

ui.temporary(<<~MSG) { ui.await }
  This is a [i]temporary[/i] displayed text.
  It will disappear when you press [b]ENTER[/b].
MSG
ui.temporary do
  ui.information 'Hint' do
    ui.puts 'This is a [i]temporary[/i] displayed text.'
    ui.puts 'It will disappear when you press [b]ENTER[/b].'
  end
  ui.await
end

Yield Parameters:



1061
1062
1063
# File 'lib/natty-ui/features.rb', line 1061

def temporary(*text, **options, &block)
  __with(Temporary.new(self), *text, **options, &block)
end

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

Dump given values as vertical bars.

Examples:

Draw green bars

ui.vbars 1..10, style: :green

Draw very big bars

ui.vbars 1..10, bar_width: 5, height: 20

Parameters:

  • values (#to_a, Array<Numeric>)

    values to print

  • normalize (true, false) (defaults to: false)

    whether the values should be normalized

  • height (Integer) (defaults to: 10)

    output height

  • bar_width (:auto, :min, Integer) (defaults to: :auto)

    with of each bar

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

    drawing style

Returns:

Raises:

  • (ArgumentError)

    if any value is negative



458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
# File 'lib/natty-ui/features.rb', line 458

def vbars(
  values,
  normalize: false,
  height: 10,
  bar_width: :auto,
  style: nil
)
  return self if (values = values.to_a).empty?
  if values.any?(&:negative?)
    raise(ArgumentError, 'values can not be negative')
  end
  puts(
    *VBarsRenderer.lines(
      values,
      columns,
      height,
      normalize,
      bar_width,
      Terminal.ansi? ? style : nil
    )
  )
end

#warning(title) {|message| ... } ⇒ Object #warning(title, *text, **options) ⇒ Section Also known as: warn

Create a visually separated section marked as warning with title for the output of text elements.

Like any other Element sections support all NattyUI::Features.

Overloads:

  • #warning(title) {|message| ... } ⇒ Object

    Returns the result of the given block.

    Parameters:

    • title (#to_s)

      section title

    Yield Parameters:

    Returns:

    • (Object)

      the result of the given block

  • #warning(title, *text, **options) ⇒ Section

    Returns itself.

    Parameters:

    • title (#to_s)

      section title

    • text (*#to_s)

      optional objects to print line by line

    • options ({Symbol => Object})

      print options – see #puts

    Returns:



741
742
743
# File 'lib/natty-ui/features.rb', line 741

def warning(title, *text, **options, &block)
  __sec(:warning, true, title, text, options, &block)
end