natty-ui 0.12.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +23 -24
- data/examples/24bit-colors.rb +4 -9
- data/examples/3bit-colors.rb +28 -8
- data/examples/8bit-colors.rb +18 -23
- data/examples/attributes.rb +30 -25
- data/examples/cols.rb +40 -0
- data/examples/elements.rb +31 -0
- data/examples/examples.rb +45 -0
- data/examples/illustration.rb +56 -54
- data/examples/ls.rb +16 -18
- data/examples/named-colors.rb +23 -0
- data/examples/sections.rb +29 -0
- data/examples/tables.rb +62 -0
- data/examples/tasks.rb +52 -0
- data/lib/natty-ui/attributes.rb +604 -0
- data/lib/natty-ui/choice.rb +56 -0
- data/lib/natty-ui/dumb_choice.rb +45 -0
- data/lib/natty-ui/element.rb +78 -0
- data/lib/natty-ui/features.rb +798 -0
- data/lib/natty-ui/framed.rb +51 -0
- data/lib/natty-ui/ls_renderer.rb +93 -0
- data/lib/natty-ui/progress.rb +187 -0
- data/lib/natty-ui/section.rb +69 -0
- data/lib/natty-ui/table.rb +241 -0
- data/lib/natty-ui/table_renderer.rb +147 -0
- data/lib/natty-ui/task.rb +44 -0
- data/lib/natty-ui/temporary.rb +38 -0
- data/lib/natty-ui/theme.rb +303 -0
- data/lib/natty-ui/utils.rb +79 -0
- data/lib/natty-ui/version.rb +1 -1
- data/lib/natty-ui/width_finder.rb +125 -0
- data/lib/natty-ui.rb +89 -147
- metadata +47 -56
- data/examples/animate.rb +0 -44
- data/examples/attributes_list.rb +0 -14
- data/examples/demo.rb +0 -53
- data/examples/message.rb +0 -32
- data/examples/progress.rb +0 -68
- data/examples/query.rb +0 -41
- data/examples/read_key.rb +0 -13
- data/examples/table.rb +0 -41
- data/lib/natty-ui/animation/binary.rb +0 -36
- data/lib/natty-ui/animation/default.rb +0 -38
- data/lib/natty-ui/animation/matrix.rb +0 -51
- data/lib/natty-ui/animation/rainbow.rb +0 -28
- data/lib/natty-ui/animation/type_writer.rb +0 -44
- data/lib/natty-ui/animation.rb +0 -69
- data/lib/natty-ui/ansi/constants.rb +0 -75
- data/lib/natty-ui/ansi.rb +0 -521
- data/lib/natty-ui/ansi_wrapper.rb +0 -199
- data/lib/natty-ui/frame.rb +0 -53
- data/lib/natty-ui/glyph.rb +0 -64
- data/lib/natty-ui/key_map.rb +0 -142
- data/lib/natty-ui/preload.rb +0 -12
- data/lib/natty-ui/spinner.rb +0 -120
- data/lib/natty-ui/text/east_asian_width.rb +0 -2529
- data/lib/natty-ui/text.rb +0 -203
- data/lib/natty-ui/wrapper/animate.rb +0 -17
- data/lib/natty-ui/wrapper/ask.rb +0 -78
- data/lib/natty-ui/wrapper/element.rb +0 -79
- data/lib/natty-ui/wrapper/features.rb +0 -21
- data/lib/natty-ui/wrapper/framed.rb +0 -45
- data/lib/natty-ui/wrapper/heading.rb +0 -60
- data/lib/natty-ui/wrapper/horizontal_rule.rb +0 -37
- data/lib/natty-ui/wrapper/list_in_columns.rb +0 -138
- data/lib/natty-ui/wrapper/message.rb +0 -109
- data/lib/natty-ui/wrapper/mixins.rb +0 -67
- data/lib/natty-ui/wrapper/progress.rb +0 -74
- data/lib/natty-ui/wrapper/query.rb +0 -89
- data/lib/natty-ui/wrapper/quote.rb +0 -25
- data/lib/natty-ui/wrapper/request.rb +0 -54
- data/lib/natty-ui/wrapper/section.rb +0 -118
- data/lib/natty-ui/wrapper/table.rb +0 -551
- data/lib/natty-ui/wrapper/task.rb +0 -55
- data/lib/natty-ui/wrapper.rb +0 -230
@@ -1,551 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'element'
|
4
|
-
|
5
|
-
module NattyUI
|
6
|
-
module Features
|
7
|
-
#
|
8
|
-
# Table view of data.
|
9
|
-
#
|
10
|
-
# @overload table(*args, type: :default, expand: false)
|
11
|
-
# Display the given arrays as rows of a table.
|
12
|
-
#
|
13
|
-
# @param [#map<#map<#to_s>>] args one or more arrays representing rows of the table
|
14
|
-
# @param [Symbol, String] type frame type; see {NattyUI::Frame}
|
15
|
-
# @param [false, true. :equal] expand
|
16
|
-
#
|
17
|
-
# @example
|
18
|
-
# ui.table(
|
19
|
-
# %w[name price origin],
|
20
|
-
# %w[apple 1$ California],
|
21
|
-
# %w[banana 2$ Brasil],
|
22
|
-
# %w[kiwi 1.5$ Newzeeland]
|
23
|
-
# )
|
24
|
-
#
|
25
|
-
# # name │ price │ origin
|
26
|
-
# # ───────┼───────┼───────────
|
27
|
-
# # apple │ 1$ │ California
|
28
|
-
# # ───────┼───────┼───────────
|
29
|
-
# # banana │ 2$ │ Brasil
|
30
|
-
# # ───────┼───────┼───────────
|
31
|
-
# # kiwi │ 1.5$ │ Newzeeland
|
32
|
-
#
|
33
|
-
# @overload table(type: :default, expand: false)
|
34
|
-
# Construct and display a table.
|
35
|
-
#
|
36
|
-
# @param [Symbol, String] type frame type; see {NattyUI::Frame}
|
37
|
-
# @param [false, true. :equal] expand
|
38
|
-
#
|
39
|
-
# @example
|
40
|
-
# ui.table(type: :heavy, expand: true) do |table|
|
41
|
-
# table.add('name', 'price', 'origin', style: 'bold green')
|
42
|
-
# table.add('apple', '1$', 'California')
|
43
|
-
# table.add('banana', '2$', 'Brasil')
|
44
|
-
# table.add('kiwi', '1.5$', 'Newzeeland')
|
45
|
-
# table.align_column(0, :right).align_row(0, :center)
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# # name ┃ price ┃ origin
|
49
|
-
# # ━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
50
|
-
# # apple ┃ 1$ ┃ California
|
51
|
-
# # ━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
52
|
-
# # banana ┃ 2$ ┃ Brasil
|
53
|
-
# # ━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
54
|
-
# # kiwi ┃ 1.5$ ┃ Newzeeland
|
55
|
-
#
|
56
|
-
# @yield [Table] table construction helper
|
57
|
-
# @return [Wrapper::Section, Wrapper] it's parent object
|
58
|
-
def table(*table, type: :default, expand: false)
|
59
|
-
type = NattyUI::Frame[type]
|
60
|
-
table = Table.create(*table)
|
61
|
-
yield(table) if block_given?
|
62
|
-
_element(:Table, table, type, expand)
|
63
|
-
end
|
64
|
-
|
65
|
-
#
|
66
|
-
# Table-like display of key/value pairs.
|
67
|
-
#
|
68
|
-
# @param [#to_s] seperator
|
69
|
-
# @param [Hash<#to_s,#to_s>] kwargs
|
70
|
-
# @return [Wrapper::Section, Wrapper] it's parent object
|
71
|
-
#
|
72
|
-
# @example
|
73
|
-
# ui.pairs(apple: '1$', banana: '2$', kiwi: '1.5$')
|
74
|
-
#
|
75
|
-
# # output:
|
76
|
-
# # apple: 1$
|
77
|
-
# # banana: 2$
|
78
|
-
# # kiwi: 1.5$
|
79
|
-
#
|
80
|
-
def pairs(seperator = ': ', **kwargs)
|
81
|
-
kwargs.empty? ? self : _element(:Pairs, kwargs, seperator)
|
82
|
-
end
|
83
|
-
|
84
|
-
#
|
85
|
-
# Helper class to define a table layout.
|
86
|
-
# @see #table
|
87
|
-
#
|
88
|
-
class Table
|
89
|
-
# @!visibility private
|
90
|
-
def self.create(*table)
|
91
|
-
table = table[0] if table.size == 1 && table[0].respond_to?(:each)
|
92
|
-
return table if table.is_a?(self.class)
|
93
|
-
ret = new
|
94
|
-
table.each { ret.add_row(*_1) }
|
95
|
-
ret
|
96
|
-
end
|
97
|
-
|
98
|
-
# @!visibility private
|
99
|
-
def initialize = @rows = []
|
100
|
-
|
101
|
-
# @return [Integer] count of rows
|
102
|
-
def row_count = @rows.size
|
103
|
-
|
104
|
-
# @return [Integer] count of columns
|
105
|
-
def col_count = @rows.max_by { _1&.size || 0 }&.size || 0
|
106
|
-
|
107
|
-
# Get the {Cell} at a table position.
|
108
|
-
#
|
109
|
-
# @param [Integer] row row index
|
110
|
-
# @param [Integer] col column index
|
111
|
-
# @return [Cell] at row/column
|
112
|
-
# @return [nil] if no cell defined at row/column
|
113
|
-
def [](row, col) = @rows.dig(row, col)
|
114
|
-
|
115
|
-
# Change {Cell} or (text) value at a table position.
|
116
|
-
#
|
117
|
-
# @example change {Cell} at row 2, column 3
|
118
|
-
# table[2, 3] = table.cell('Hello World', align: right, style: 'bold')
|
119
|
-
# @example change text at row 2, column 3
|
120
|
-
# table[2, 3] = 'Hello Ruby!'
|
121
|
-
# @example delete {Cell} at row 2, column 3
|
122
|
-
# table[2, 3] = nil
|
123
|
-
#
|
124
|
-
# @param [Integer] row row index
|
125
|
-
# @param [Integer] col column index
|
126
|
-
# @param [Cell, #to_s, nil] value Cell or text to use at specified position
|
127
|
-
# @return [Cell, #to_s, nil] the value
|
128
|
-
def []=(row, col, value)
|
129
|
-
row = (@rows[row] ||= [])
|
130
|
-
if value.nil? || value.is_a?(Cell)
|
131
|
-
row[col] = value
|
132
|
-
else
|
133
|
-
cell = row[col]
|
134
|
-
cell ? cell.value = value : row[col] = Cell.new(value, nil, nil)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
# Create a new cell.
|
139
|
-
#
|
140
|
-
# @example create a {Cell} with right aligned bold text "Hello World"
|
141
|
-
# table[2, 3] = table.cell('Hello World', align: right, style: 'bold')
|
142
|
-
#
|
143
|
-
# @param [#to_s] value text value
|
144
|
-
# @param [:left, :right, :center] align text alignment
|
145
|
-
# @param [String] style text style; see {Ansi.try_convert}
|
146
|
-
# @return [Cell] a new cell
|
147
|
-
def cell(value, align: :left, style: nil) = Cell.new(value, align, style)
|
148
|
-
|
149
|
-
# Add a new row to the table.
|
150
|
-
#
|
151
|
-
# @example add a row with three right-aligned columns
|
152
|
-
# table.add_row('One', 'Two', 'Three', align: :right)
|
153
|
-
#
|
154
|
-
# @param [#map] columns Enumerable-like object containing column texts
|
155
|
-
# @param [:left, :right, :center] align text alignment
|
156
|
-
# @param [String] style text style; see {Ansi.try_convert}
|
157
|
-
# @return [Table] itself
|
158
|
-
def add_row(*columns, align: nil, style: nil)
|
159
|
-
if columns.size == 1 && columns[0].respond_to?(:map)
|
160
|
-
columns = columns[0]
|
161
|
-
end
|
162
|
-
columns =
|
163
|
-
columns.map { |cell| as_cell(cell, align, style) if cell }.to_a
|
164
|
-
@rows << (columns.empty? ? nil : columns)
|
165
|
-
self
|
166
|
-
end
|
167
|
-
alias add add_row
|
168
|
-
|
169
|
-
# Add a new column to the table.
|
170
|
-
#
|
171
|
-
# @example add a column of three rows with bold styled text
|
172
|
-
# table.add_column('One', 'Two', 'Three', style: :bold)
|
173
|
-
#
|
174
|
-
# @param [#map] rows Enumerable-like object containing texts for each row
|
175
|
-
# @param [:left, :right, :center] align text alignment
|
176
|
-
# @param [String] style text style; see {Ansi.try_convert}
|
177
|
-
# @return [Table] itself
|
178
|
-
def add_column(*rows, align: nil, style: nil)
|
179
|
-
rows = rows[0] if rows.size == 1 && rows[0].respond_to?(:map)
|
180
|
-
row_idx = -1
|
181
|
-
rows.each do |cell|
|
182
|
-
(@rows[row_idx += 1] ||= []) << as_cell(cell, align, style)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
# Change style of one or more rows.
|
187
|
-
#
|
188
|
-
# @example define bold red text style for the first row
|
189
|
-
# table.style_row(0, 'bold red')
|
190
|
-
# @example define yellow text style for the first three rows
|
191
|
-
# table.style_row(0..2, 'yellow')
|
192
|
-
# @example define green text style for rows 3, 4 and 7
|
193
|
-
# table.style_row([3, 4, 7], 'green')
|
194
|
-
#
|
195
|
-
# @param [Integer, Enumerable<Integer>] row index of row(s) to change
|
196
|
-
# @param [String, nil] style text style; see {Ansi.try_convert}
|
197
|
-
# @return [Table] itself
|
198
|
-
def style_row(row, style)
|
199
|
-
if row.is_a?(Integer)
|
200
|
-
row = [row]
|
201
|
-
elsif !row.is_a?(Enumerable)
|
202
|
-
raise(TypeError, "invalid row value - #{row}")
|
203
|
-
end
|
204
|
-
row.each { |r| @rows[r]&.each { _1&.style = style } }
|
205
|
-
self
|
206
|
-
end
|
207
|
-
|
208
|
-
# Change style of one or more columns.
|
209
|
-
#
|
210
|
-
# @example define bold red text style for the first column
|
211
|
-
# table.style_column(0, 'bold red')
|
212
|
-
# @example define yellow text style for the first three columns
|
213
|
-
# table.style_column(0..2, 'yellow')
|
214
|
-
# @example define green text style for columns with index 3, 4 and 7
|
215
|
-
# table.style_column([3, 4, 7], 'green')
|
216
|
-
#
|
217
|
-
# @param [Integer, Enumerable<Integer>] column index of column(s) to change
|
218
|
-
# @param [String, nil] style text style; see {Ansi.try_convert}
|
219
|
-
# @return [Table] itself
|
220
|
-
def style_column(column, style)
|
221
|
-
if column.is_a?(Integer)
|
222
|
-
column = [column]
|
223
|
-
elsif !column.is_a?(Enumerable)
|
224
|
-
raise(TypeError, "invalid column value - #{column}")
|
225
|
-
end
|
226
|
-
@rows.each { |row| column.each { row[_1]&.style = style } }
|
227
|
-
self
|
228
|
-
end
|
229
|
-
|
230
|
-
# Change text alignment of one or more rows.
|
231
|
-
#
|
232
|
-
# @example align first row right
|
233
|
-
# table.align_row(0, :right)
|
234
|
-
# @example center first three rows
|
235
|
-
# table.align_row(0..2, :center)
|
236
|
-
# @example center the rows with index 3, 4 and 7
|
237
|
-
# table.align_row([3, 4, 7], :center)
|
238
|
-
#
|
239
|
-
# @param [Integer, Enumerable<Integer>] row index of row(s) to change
|
240
|
-
# @param [:left, :right, :center] alignment
|
241
|
-
# @return [Table] itself
|
242
|
-
def align_row(row, alignment)
|
243
|
-
if row.is_a?(Integer)
|
244
|
-
row = [row]
|
245
|
-
elsif !row.is_a?(Enumerable)
|
246
|
-
raise(TypeError, "invalid row value - #{row}")
|
247
|
-
end
|
248
|
-
row.each { |r| @rows[r]&.each { _1&.align = alignment } }
|
249
|
-
self
|
250
|
-
end
|
251
|
-
|
252
|
-
# Change text alignment of one or more column.
|
253
|
-
#
|
254
|
-
# @example align first column right
|
255
|
-
# table.align_column(0, :right)
|
256
|
-
# @example center first three columns
|
257
|
-
# table.align_column(0..2, :center)
|
258
|
-
# @example center the columns with index 3, 4 and 7
|
259
|
-
# table.align_column([3, 4, 7], :center)
|
260
|
-
#
|
261
|
-
# @param [Integer, Enumerable<Integer>] column index of column(s) to change
|
262
|
-
# @param [:left, :right, :center] alignment
|
263
|
-
# @return [Table] itself
|
264
|
-
def align_column(column, alignment)
|
265
|
-
if column.is_a?(Integer)
|
266
|
-
column = [column]
|
267
|
-
elsif !column.is_a?(Enumerable)
|
268
|
-
raise(TypeError, "invalid column value - #{column}")
|
269
|
-
end
|
270
|
-
@rows.each { |row| column.each { row[_1]&.align = alignment } }
|
271
|
-
self
|
272
|
-
end
|
273
|
-
|
274
|
-
# Convert the table to the compactest (two-dimensional) array
|
275
|
-
# representation.
|
276
|
-
#
|
277
|
-
# @return [Array<Array<Cell>>]
|
278
|
-
def to_a
|
279
|
-
ret = []
|
280
|
-
ridx = -1
|
281
|
-
@rows.each do |row|
|
282
|
-
ridx += 1
|
283
|
-
next unless row
|
284
|
-
count = 0
|
285
|
-
row =
|
286
|
-
row.map do |cell|
|
287
|
-
next unless cell
|
288
|
-
next if cell.value.empty?
|
289
|
-
count += 1
|
290
|
-
cell.dup
|
291
|
-
end
|
292
|
-
ret[ridx] = row if count.positive?
|
293
|
-
end
|
294
|
-
ret
|
295
|
-
end
|
296
|
-
|
297
|
-
private
|
298
|
-
|
299
|
-
def as_cell(value, align, style)
|
300
|
-
return Cell.new(value, align, style) unless value.is_a?(Cell)
|
301
|
-
cell = value.dup
|
302
|
-
cell.align = align if align
|
303
|
-
cell.style = style if style
|
304
|
-
cell
|
305
|
-
end
|
306
|
-
|
307
|
-
def initialize_copy(*)
|
308
|
-
super
|
309
|
-
@rows = to_a
|
310
|
-
end
|
311
|
-
|
312
|
-
class Cell
|
313
|
-
# @return [String, nil] text value of the cell
|
314
|
-
attr_reader :value
|
315
|
-
|
316
|
-
attr_writer :align, :style
|
317
|
-
|
318
|
-
# @!visibility private
|
319
|
-
attr_accessor :tag
|
320
|
-
|
321
|
-
# @!visibility private
|
322
|
-
def initialize(value, align, style)
|
323
|
-
@value = value.to_s
|
324
|
-
@align = align
|
325
|
-
@style = style
|
326
|
-
end
|
327
|
-
|
328
|
-
# @attribute [r] align
|
329
|
-
# @return [:left, :right, :center] text alignment
|
330
|
-
def align = ALIGNMENT[@align]
|
331
|
-
|
332
|
-
# @attribute [r] style
|
333
|
-
# @return [String, nil] text style; see {Ansi.try_convert}
|
334
|
-
def style
|
335
|
-
@style_ ||= Ansi.try_convert(@style)
|
336
|
-
end
|
337
|
-
|
338
|
-
def value=(value)
|
339
|
-
@value = value.to_s
|
340
|
-
end
|
341
|
-
|
342
|
-
private
|
343
|
-
|
344
|
-
def initialize_copy(*)
|
345
|
-
super
|
346
|
-
@value = @value.dup
|
347
|
-
@tag = nil
|
348
|
-
end
|
349
|
-
|
350
|
-
alignment = { left: :left, right: :right, center: :center }
|
351
|
-
alignment.default = :left
|
352
|
-
ALIGNMENT = alignment.compare_by_identity.freeze
|
353
|
-
end
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
class Wrapper
|
358
|
-
# An {Element} to print a table.
|
359
|
-
#
|
360
|
-
# @see Features#table
|
361
|
-
class Table < Element
|
362
|
-
protected
|
363
|
-
|
364
|
-
def call(table, frame, enlarge)
|
365
|
-
TableGen.each_line(
|
366
|
-
table.to_a,
|
367
|
-
@parent.available_width - 1,
|
368
|
-
frame,
|
369
|
-
enlarge
|
370
|
-
) { |line| @parent.puts(line) }
|
371
|
-
@parent
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
# An {Element} to print key/value pairs.
|
376
|
-
#
|
377
|
-
# @see Features#pairs
|
378
|
-
class Pairs < Element
|
379
|
-
protected
|
380
|
-
|
381
|
-
def call(kwargs, seperator)
|
382
|
-
TableGen.each_line_simple(
|
383
|
-
kwargs.map do |k, v|
|
384
|
-
[
|
385
|
-
Features::Table::Cell.new(k, :right, nil),
|
386
|
-
Features::Table::Cell.new(v, :left, nil)
|
387
|
-
]
|
388
|
-
end,
|
389
|
-
@parent.available_width - 1,
|
390
|
-
seperator
|
391
|
-
) { @parent.puts(_1) }
|
392
|
-
@parent
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
|
-
class TableGen
|
397
|
-
COLOR = Ansi[39]
|
398
|
-
|
399
|
-
def self.each_line(table, max_width, frame, expand)
|
400
|
-
gen = new(table, max_width, 3, expand)
|
401
|
-
return unless gen.ok?
|
402
|
-
col_div = "#{Ansi::RESET} #{COLOR}#{frame[4]}#{Ansi::RESET} "
|
403
|
-
row_div = "#{frame[5]}#{frame[6]}#{frame[5]}"
|
404
|
-
row_div =
|
405
|
-
"#{COLOR}#{
|
406
|
-
gen.widths.map { frame[5] * _1 }.join(row_div)
|
407
|
-
}#{Ansi::RESET}"
|
408
|
-
last_row = 0
|
409
|
-
gen.each do |number, line|
|
410
|
-
if last_row != number
|
411
|
-
last_row = number
|
412
|
-
yield(row_div)
|
413
|
-
end
|
414
|
-
yield(line.join(col_div) + Ansi::RESET)
|
415
|
-
end
|
416
|
-
end
|
417
|
-
|
418
|
-
def self.each_line_simple(table, max_width, seperator)
|
419
|
-
gen = new(table, max_width, Text.width(seperator), false)
|
420
|
-
return unless gen.ok?
|
421
|
-
col_div = "#{COLOR}#{seperator}#{Ansi::RESET}"
|
422
|
-
gen.each { yield(_2.join(col_div)) }
|
423
|
-
end
|
424
|
-
|
425
|
-
attr_reader :widths
|
426
|
-
|
427
|
-
def initialize(table, max_width, coldiv_size, expand)
|
428
|
-
return if coldiv_size > max_width # wtf
|
429
|
-
@table = table
|
430
|
-
@col_count = table.max_by { _1&.size || 0 }&.size || 0
|
431
|
-
@max_width = max_width
|
432
|
-
@widths = determine_widths
|
433
|
-
sum = @widths.sum
|
434
|
-
space = @max_width - ((@col_count - 1) * coldiv_size)
|
435
|
-
if space < sum
|
436
|
-
@widths = reduce_widths(sum, space, coldiv_size)
|
437
|
-
adjust!
|
438
|
-
elsif expand && sum < space
|
439
|
-
if expand == :equal
|
440
|
-
equal_widths(space)
|
441
|
-
else
|
442
|
-
enlarge_widths(sum, space)
|
443
|
-
end
|
444
|
-
adjust!
|
445
|
-
end
|
446
|
-
@empties = @widths.map { ' ' * _1 }
|
447
|
-
end
|
448
|
-
|
449
|
-
def ok? = @empties != nil
|
450
|
-
|
451
|
-
def each
|
452
|
-
ridx = -1
|
453
|
-
@table.each do |row|
|
454
|
-
ridx += 1
|
455
|
-
next yield(ridx, @empties) unless row
|
456
|
-
line_count = row.map { _1 ? _1.tag.lines.size : 0 }.max
|
457
|
-
line_count.times do |lidx|
|
458
|
-
cidx = -1
|
459
|
-
yield(
|
460
|
-
ridx,
|
461
|
-
@empties.map do |spacer|
|
462
|
-
cell = row[cidx += 1] or next spacer
|
463
|
-
str, str_size = cell.tag.lines[lidx]
|
464
|
-
next spacer unless str_size
|
465
|
-
str_fmt(cell.align, cell.style, str, str_size, spacer.size)
|
466
|
-
end
|
467
|
-
)
|
468
|
-
end
|
469
|
-
end
|
470
|
-
nil
|
471
|
-
end
|
472
|
-
|
473
|
-
private
|
474
|
-
|
475
|
-
def str_fmt(align, style, str, str_size, size)
|
476
|
-
return "#{style}#{str}" unless (size -= str_size).positive?
|
477
|
-
return "#{style}#{' ' * size}#{str}" if align == :right
|
478
|
-
if align == :center
|
479
|
-
right = size / 2
|
480
|
-
return "#{style}#{' ' * (size - right)}#{str}#{' ' * right}"
|
481
|
-
end
|
482
|
-
"#{style}#{str}#{' ' * size}"
|
483
|
-
end
|
484
|
-
|
485
|
-
def adjust!
|
486
|
-
@table.each do |row|
|
487
|
-
next unless row
|
488
|
-
cidx = -1
|
489
|
-
row.each do |cell|
|
490
|
-
cidx += 1
|
491
|
-
next unless cell
|
492
|
-
width = @widths[cidx]
|
493
|
-
next if cell.tag.value <= width
|
494
|
-
cell.tag.lines = Text.as_lines([cell.value], width)
|
495
|
-
end
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
def enlarge_widths(sum, space)
|
500
|
-
@widths.map! { ((((100.0 * _1) / sum) * space) / 100).round }
|
501
|
-
return if (diff = space - @widths.sum).zero?
|
502
|
-
@widths[
|
503
|
-
@widths.index(diff.negative? ? @widths.max : @widths.min)
|
504
|
-
] += diff
|
505
|
-
end
|
506
|
-
|
507
|
-
def equal_widths(space)
|
508
|
-
@widths = Array.new(@widths.size, space / @widths.size)
|
509
|
-
@widths[-1] += space - @widths.sum
|
510
|
-
end
|
511
|
-
|
512
|
-
def reduce_widths(sum, space, coldiv_size)
|
513
|
-
ws = @widths.dup
|
514
|
-
until sum <= space
|
515
|
-
max = ws.max
|
516
|
-
if max == 1
|
517
|
-
ws = @widths.take(ws.size - 1)
|
518
|
-
sum = ws.sum
|
519
|
-
space += coldiv_size
|
520
|
-
else
|
521
|
-
while (idx = ws.rindex(max)) && (sum > space)
|
522
|
-
ws[idx] -= 1
|
523
|
-
sum -= 1
|
524
|
-
end
|
525
|
-
end
|
526
|
-
end
|
527
|
-
ws
|
528
|
-
end
|
529
|
-
|
530
|
-
def determine_widths
|
531
|
-
ret = Array.new(@col_count, 1)
|
532
|
-
@table.each do |row|
|
533
|
-
next unless row
|
534
|
-
cidx = -1
|
535
|
-
row.each do |cell|
|
536
|
-
cidx += 1
|
537
|
-
next unless cell
|
538
|
-
cell.tag = Tag.new(Text.as_lines([cell.value], @max_width))
|
539
|
-
width = cell.tag.value = cell.tag.lines.max_by(&:last).last
|
540
|
-
ret[cidx] = width if ret[cidx] < width
|
541
|
-
end
|
542
|
-
end
|
543
|
-
ret
|
544
|
-
end
|
545
|
-
|
546
|
-
Tag = Struct.new(:lines, :value)
|
547
|
-
end
|
548
|
-
|
549
|
-
private_constant :TableGen
|
550
|
-
end
|
551
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'section'
|
4
|
-
require_relative 'mixins'
|
5
|
-
|
6
|
-
module NattyUI
|
7
|
-
module Features
|
8
|
-
# Creates task section implementing additional {ProgressAttributes}.
|
9
|
-
#
|
10
|
-
# A task section has additional states and can be closed with {#completed}
|
11
|
-
# or {#failed}.
|
12
|
-
#
|
13
|
-
# @param (see #information)
|
14
|
-
# @yieldparam [Wrapper::Task] task the created section
|
15
|
-
# @return [Object] the result of the code block
|
16
|
-
# @return [Wrapper::Task] itself, when no code block is given
|
17
|
-
def task(title, *args, &block)
|
18
|
-
_section(:Task, args, title: title, &block)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
module TaskMethods
|
23
|
-
protected
|
24
|
-
|
25
|
-
def initialize(parent, title:)
|
26
|
-
@temp = parent.wrapper.temporary
|
27
|
-
@final_text = [title]
|
28
|
-
super(parent, title: title, glyph: :task)
|
29
|
-
end
|
30
|
-
|
31
|
-
def finish
|
32
|
-
return @parent.failed(*@final_text) if failed?
|
33
|
-
@temp.call
|
34
|
-
_section(
|
35
|
-
:Message,
|
36
|
-
@final_text,
|
37
|
-
owner: @parent,
|
38
|
-
title: @final_text.shift,
|
39
|
-
glyph: @status = :completed
|
40
|
-
)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
private_constant :TaskMethods
|
44
|
-
|
45
|
-
class Wrapper
|
46
|
-
#
|
47
|
-
# A {Message} container to visualize the progression of a task.
|
48
|
-
#
|
49
|
-
# @see Features.task
|
50
|
-
class Task < Message
|
51
|
-
include ProgressAttributes
|
52
|
-
include TaskMethods
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|