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, #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, false #await(yes: 'Enter', no: 'Esc') {|temp| ... } ⇒ true, false

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, false

    Returns wheter the user inputs a positive result.

    Yield Parameters:

    • temp (Temporary)

      temporary displayed section (section will be erased after input)



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

def await(yes: 'Enter', no: 'Esc')
  temporary do |arg|
    yield(arg) if block_given?
    while (key = Terminal.read_key)
      if (no == key) || (no.is_a?(Enumerable) && no.include?(key))
        return false
      end
      if (yes == key) || (yes.is_a?(Enumerable) && yes.include?(key))
        return true
      end
    end
  end
end

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

Request a user's chocie.

Overloads:

  • #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
    

    Yield Parameters:

    • temp (Temporary)

      temporary displayed section (section will be erased after input)

  • #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?' }
    # => wheter the user selected: :k, :i, :g, :t, :r
    # => nil, when the user aborted
    

    Yield Parameters:

    • temp (Temporary)

      temporary displayed section (section will be erased after input)



722
723
724
725
726
727
728
729
730
731
732
733
734
# File 'lib/natty-ui/features.rb', line 722

def choice(*choices, abortable: false, **kwchoices, &block)
  return if choices.empty? && kwchoices.empty?
  choice =
    case NattyUI.input_mode
    when :default
      Choice.new(self, choices, kwchoices, abortable)
    when :dumb
      DumbChoice.new(self, choices, kwchoices, abortable)
    else
      return
    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.

Options Hash (**attributes):

Yield Parameters:

  • row (Table::Row)

    helper to define the row layout



374
375
376
377
378
379
380
381
# File 'lib/natty-ui/features.rb', line 374

def cols(*columns, **attributes)
  table(**attributes) do |table|
    table.add do |row|
      columns.each { row.add(_1, **attributes) }
      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.

Options Hash (**attributes):



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

def div(*text, **attributes)
  return self if text.empty?
  table(border_around: true, **attributes) do |table|
    table.add { _1.add(*text, **attributes) }
  end
end

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

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

Yield Parameters:

See Also:



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

def error(title, *text, &block) = __tsec(:error, title, text, &block)

#failed(title, *text) {|section| ... } ⇒ Object

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

Yield Parameters:

See Also:



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

def failed(title, *text, &block) = __tsec(:failed, title, text, &block)

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

Create a framed section.

Yield Parameters:



568
569
570
571
572
573
574
575
576
577
578
579
# File 'lib/natty-ui/features.rb', line 568

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

#h1(*text) ⇒ Features

Print given text as a H1 #heading.



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

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

#h2(*text) ⇒ Features

Print given text as a H2 #heading.



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

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

#h3(*text) ⇒ Features

Print given text as a H3 #heading.



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

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

#h4(*text) ⇒ Features

Print given text as a H4 #heading.



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

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

#h5(*text) ⇒ Features

Print given text as a H5 #heading.



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

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

#h6(*text) ⇒ Features

Print given text as a H6 #heading.



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

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

#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 ═══─╴╶╴╶


218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/natty-ui/features.rb', line 218

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:

ui.hr(:heavy)


282
283
284
285
286
# File 'lib/natty-ui/features.rb', line 282

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

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

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

Yield Parameters:

See Also:



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

def information(title, *text, &block)
  __tsec(:information, title, text, &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]')


321
322
323
324
325
# File 'lib/natty-ui/features.rb', line 321

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) ⇒ Features

Print given text with a decoration mark.



183
184
185
186
# File 'lib/natty-ui/features.rb', line 183

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

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

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

Yield Parameters:

See Also:



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

def message(title, *text, &block) = __sec(:message, title, text, &block)

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

Options Hash (**options):

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

    text alignment

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

    whether to igniore newline characters



170
171
172
173
174
# File 'lib/natty-ui/features.rb', line 170

def pin(*text, mark: nil, **options)
  options[:pin] = true
  options[:first_line_prefix] = Theme.current.mark(mark) if mark
  puts(*text, **options)
end

#progress(title, max: nil, pin: false) ⇒ Progress #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) {|progress| ... } ⇒ Object

    Returns the result of the given block.

    Yield Parameters:

    • progress (Progress)

      itself



463
464
465
466
467
468
469
470
471
# File 'lib/natty-ui/features.rb', line 463

def progress(title, max: nil, pin: false, &block)
  progress =
    if Terminal.ansi?
      Progress.new(self, title, max, pin)
    else
      DumbProgress.new(self, title, max)
    end
  block ? __with(progress, &block) : progress
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

Options Hash (**options):

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

    text alignment

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

    whether to igniore newline characters

See Also:



39
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
# File 'lib/natty-ui/features.rb', line 39

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

  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

  return self if max_width <= 0

  lines =
    Text.each_line_with_size(
      *text,
      limit: max_width,
      bbcode: bbcode,
      ansi: Terminal.ansi?,
      ignore_newline: options[:ignore_newline]
    )

  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]
    lines = lines.to_a
    max_width = lines.max_by(&:last).last
  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.



193
194
195
196
197
198
199
200
201
202
# File 'lib/natty-ui/features.rb', line 193

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.to_i
  )
end

#section(*text) {|section| ... } ⇒ Object

Create a visually separated section for the output of text elements. Like any other Element sections support all NattyUI::Features.

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:



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

def section(*text, &block) = __sec(:default, nil, text, &block)

#space(count = 1) ⇒ Features

Print one or more space lines.



294
295
296
# File 'lib/natty-ui/features.rb', line 294

def space(count = 1)
  (count = count.to_i).positive? ? puts(*Array.new(count, "\n")) : 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 table with three rows, four columns, 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

Options Hash (**attributes):

Yield Parameters:

  • table (Table)

    helper to define the table layout



353
354
355
356
357
# File 'lib/natty-ui/features.rb', line 353

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

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

Generate a task section.

Yield Parameters:

  • task (Task)

    itself



591
592
593
# File 'lib/natty-ui/features.rb', line 591

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

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

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

Examples:

Show tempoary information

ui.temporary do
  ui.info('Information', 'This text will disappear when you pressed ENTER.')
  ui.await
end

Yield Parameters:



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

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

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

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

Yield Parameters:

See Also:



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

def warning(title, *text, &block) = __tsec(:warning, title, text, &block)