Class: Terminal::Text::Formatter

Inherits:
Object
  • Object
show all
Defined in:
lib/terminal/text/formatter.rb

Overview

Processes text with BBCode markup and ANSI escape codes into display-width-aware lines. Supports Unicode-aware word-wrapping, alignment, padding, and prefix/suffix decorations.

Examples:

Basic word-wrapping

fmt = Terminal::Text::Formatter.new('Hello World, this is a test')
fmt.lines(width: 12)
# => ["Hello World,", "this is a", "test"]

Formatted output with alignment

Terminal::Text::Formatter.format(
  'Hello', align: :center, width: 20
)
# => ["       Hello        "]

See Also:

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*str, ansi: true, bbcode: true, spaces: true, eol: true) ⇒ Formatter

Create a new formatter by tokenizing the given text.

Parameters:

  • str (Array<#to_s>)

    text to process

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

    recognize ANSI escape codes

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

    process BBCode markup

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

    preserve whitespace; when +false+ leading/trailing spaces and multiple spaces are collapsed

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

    preserve line endings; when +false+ newlines are treated as spaces



93
94
95
96
97
98
99
100
# File 'lib/terminal/text/formatter.rb', line 93

def initialize(*str, ansi: true, bbcode: true, spaces: true, eol: true)
  @lex = []
  return if str.empty?
  ansi ? _generate_ansi(str, bbcode) : _generate(str, bbcode)
  return if @lex.empty?
  @lex = _ignore_whitespace unless spaces
  @lex = _ignore_newline unless eol
end

Class Method Details

.[](*str, with_size: false, ansi: true, bbcode: true, spaces: true, eol: true, width: nil) ⇒ Array<String, Integer>

Parse text into lines, optionally with display widths.

Examples:

Terminal::Text::Formatter['Hello World', width: 5]
# => ["Hello", "World"]

With size information

Terminal::Text::Formatter['Hello', with_size: true]
# => [["Hello", 5]]

Parameters:

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

    when +true+, return +[line, width]+ pairs instead of plain strings

  • str (Array<#to_s>)

    text to process

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

    recognize ANSI escape codes

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

    process BBCode markup

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

    preserve whitespace; when +false+ leading/trailing spaces and multiple spaces are collapsed

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

    preserve line endings; when +false+ newlines are treated as spaces

  • width (Integer, nil) (defaults to: nil)

    maximum line width in columns; +nil+ returns unwrapped lines

Returns:

  • (Array<String, Integer>)

    pairs of +[line_text, display_width]+

See Also:



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/terminal/text/formatter.rb', line 39

def self.[](
  *str,
  with_size: false,
  ansi: true,
  bbcode: true,
  spaces: true,
  eol: true,
  width: nil
)
  ret = new(*str, ansi:, bbcode:, spaces:, eol:).lines_with_size(width:)
  with_size ? ret : ret.map(&:first)
end

.format(*str, ansi: true, bbcode: true, spaces: true, eol: true, align: nil, width: nil, height: nil, padding: nil, prefix: nil, suffix: nil) ⇒ Object

Format text with alignment, padding, and decorations.

Parameters:

  • str (Array<#to_s>)

    text to process

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

    recognize ANSI escape codes

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

    process BBCode markup

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

    preserve whitespace; when +false+ leading/trailing spaces and multiple spaces are collapsed

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

    preserve line endings; when +false+ newlines are treated as spaces

  • align (Symbol, nil) (defaults to: nil)

    text alignment: +:left+, +:right+, +:center+, or +nil+ (no fill)

  • width (Integer, nil) (defaults to: nil)

    output line width in columns

  • height (Integer, nil) (defaults to: nil)

    number of output lines; negative values take lines from the end

  • padding (Integer, Array, nil) (defaults to: nil)

    CSS-style padding

    • 1 value: all sides;
    • 2 values: [vertical, horizontal];
    • 3 values: [top, horizontal, bottom];
    • 4 values: [top, right, bottom, left]
  • prefix (#to_s, nil) (defaults to: nil)

    string prepended to each line

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

    string appended to each line

Raises:

  • (ArgumentError)

    if +width+ is zero or negative

See Also:



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/terminal/text/formatter.rb', line 60

def self.format(
  *str,
  ansi: true,
  bbcode: true,
  spaces: true,
  eol: true,
  align: nil,
  width: nil,
  height: nil,
  padding: nil,
  prefix: nil,
  suffix: nil
)
  new(*str, ansi:, bbcode:, spaces:, eol:).format(
    align:,
    width:,
    height:,
    padding:,
    prefix:,
    suffix:
  )
end

Instance Method Details

#empty?true, false

Whether the formatter has any content.

Returns:

  • (true, false)


219
# File 'lib/terminal/text/formatter.rb', line 219

def empty? = @lex.empty?

#format(align: nil, width: nil, height: nil, padding: nil, prefix: nil, suffix: nil) ⇒ Array<String>

Format lines with alignment, padding, and decorations.

Examples:

Centered text with padding

fmt = Terminal::Text::Formatter.new('Hi')
fmt.format(align: :center, width: 10, padding: [0, 1])
# => [" Hi         "]

Parameters:

  • align (Symbol, nil) (defaults to: nil)

    text alignment: +:left+, +:right+, +:center+, or +nil+ (no fill)

  • width (Integer, nil) (defaults to: nil)

    output line width in columns

  • height (Integer, nil) (defaults to: nil)

    number of output lines; negative values take lines from the end

  • padding (Integer, Array, nil) (defaults to: nil)

    CSS-style padding

    • 1 value: all sides;
    • 2 values: [vertical, horizontal];
    • 3 values: [top, horizontal, bottom];
    • 4 values: [top, right, bottom, left]
  • prefix (#to_s, nil) (defaults to: nil)

    string prepended to each line

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

    string appended to each line

Returns:

  • (Array<String>)

    formatted output lines

Raises:

  • (ArgumentError)

    if +width+ is zero or negative



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/terminal/text/formatter.rb', line 154

def format(
  align: nil,
  width: nil,
  height: nil,
  padding: nil,
  prefix: nil,
  suffix: nil
)
  top, right, bottom, left = _padding(padding)

  if height
    return [] if (height = height.to_i) == 0
    if height < 0
      tail = true
      height = -height
    end
    height -= top
    height -= -bottom
    return [] if height < 1
  end

  if width
    w = (width = width.to_i) - left - right
    raise(ArgumentError, "invalid width - #{width.inspect}") if w < 1
    lws = _limited(w)
    lws = tail ? lws.last(height) : lws.take(height) if height
    empty = "#{prefix}#{' ' * width}#{suffix}" if top + bottom > 0
  else
    lws = @unlimited || _unlimited
    lws = tail ? lws.last(height) : lws.take(height) if height
    w = lws.empty? ? 0 : lws.max_by(&:last)[-1]
    if top + bottom > 0
      empty = "#{prefix}#{' ' * (w + left + right)}#{suffix}"
    end
  end

  ret = []
  ret.fill(empty, 0, top) if top > 0
  left = left < 1 ? prefix.to_s : "#{prefix}#{' ' * left}"
  right = right < 1 ? suffix.to_s : "#{' ' * right}#{suffix}"

  space = SPACE_CACHE.dup

  case align
  when :left
    lws.each { |l, s| ret << "#{left}#{l}#{space[w - s]}#{right}" }
  when :right
    lws.each { |l, s| ret << "#{left}#{space[w - s]}#{l}#{right}" }
  when :center
    lws.each do |l, s|
      ls = (s = w - s) / 2
      next ret << "#{left}#{l}#{right}" if ls < 1
      ret << "#{left}#{space[ls]}#{l}#{space[s - ls]}#{right}"
    end
  else
    lws.each { |l, _| ret << "#{left}#{l}#{right}" }
  end

  return ret.fill(empty, ret.size, bottom) if bottom > 0
  ret.empty? ? ret << '' : ret
end

#lines(width: nil) ⇒ Array<String>

Word-wrap and return lines as strings.

Examples:

fmt = Terminal::Text::Formatter.new('Hello World')
fmt.lines(width: 5)
# => ["Hello", "World"]

Parameters:

  • width (Integer, nil) (defaults to: nil)

    maximum line width in columns

Returns:

  • (Array<String>)

Raises:

  • (ArgumentError)

    if +width+ is zero or negative



131
# File 'lib/terminal/text/formatter.rb', line 131

def lines(width: nil) = lines_with_size(width:).map(&:first)

#lines_with_size(width: nil) ⇒ Array<String, Integer>

Word-wrap and return lines with their display widths.

Examples:

fmt = Terminal::Text::Formatter.new('Hello World')
fmt.lines_with_size(width: 5)
# => [["Hello", 5], ["World", 5]]

Parameters:

  • width (Integer, nil) (defaults to: nil)

    maximum line width in columns; +nil+ returns unwrapped lines

Returns:

  • (Array<String, Integer>)

    pairs of +[line_text, display_width]+

Raises:

  • (ArgumentError)
  • (ArgumentError)

    if +width+ is zero or negative



114
115
116
117
118
119
# File 'lib/terminal/text/formatter.rb', line 114

def lines_with_size(width: nil)
  return [] if @lex.empty?
  return @unlimited || _unlimited unless width
  (w = width.to_i) > 0 and return _limited(w)
  raise(ArgumentError, "invalid width - #{width.inspect}")
end

#max_line_widthInteger

Maximum display width of any line.

Examples:

fmt = Terminal::Text::Formatter.new("short\na longer line")
fmt.max_line_width # => 13

Returns:

  • (Integer)

    widest line in columns, +0+ when empty



228
229
230
231
# File 'lib/terminal/text/formatter.rb', line 228

def max_line_width
  @max_line_width ||=
    (@lex.empty? ? 0 : (@unlimited || _unlimited).max_by(&:last)[-1])
end