natty-ui 0.34.0 → 1.0.2
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/.yardopts +0 -1
- data/README.md +6 -6
- data/examples/24bit-colors.rb +9 -5
- data/examples/3bit-colors.rb +7 -7
- data/examples/8bit-colors.rb +5 -5
- data/examples/attributes.rb +2 -3
- data/examples/elements.rb +9 -6
- data/examples/examples.rb +9 -9
- data/examples/frames.rb +31 -0
- data/examples/hbars.rb +6 -3
- data/examples/info.rb +13 -10
- data/examples/key-codes.rb +8 -9
- data/examples/ls.rb +24 -22
- data/examples/named-colors.rb +4 -3
- data/examples/sections.rb +27 -17
- data/examples/select.rb +28 -0
- data/examples/sh.rb +25 -7
- data/examples/tables.rb +19 -37
- data/examples/tasks.rb +32 -22
- data/examples/vbars.rb +5 -3
- data/lib/natty-ui/dumb_progress.rb +68 -0
- data/lib/natty-ui/element.rb +64 -65
- data/lib/natty-ui/features.rb +773 -872
- data/lib/natty-ui/frame.rb +87 -0
- data/lib/natty-ui/helper/table.rb +1376 -0
- data/lib/natty-ui/margin.rb +83 -0
- data/lib/natty-ui/progress.rb +116 -149
- data/lib/natty-ui/renderer/bars.rb +93 -0
- data/lib/natty-ui/renderer/choice.rb +56 -0
- data/lib/natty-ui/renderer/dumb_choice.rb +34 -0
- data/lib/natty-ui/renderer/dumb_select.rb +60 -0
- data/lib/natty-ui/renderer/dumb_shell_runner.rb +19 -0
- data/lib/natty-ui/renderer/heading.rb +26 -0
- data/lib/natty-ui/renderer/horizontal_rule.rb +32 -0
- data/lib/natty-ui/{ls_renderer.rb → renderer/ls.rb} +15 -27
- data/lib/natty-ui/renderer/mark.rb +13 -0
- data/lib/natty-ui/renderer/quote.rb +13 -0
- data/lib/natty-ui/renderer/select.rb +63 -0
- data/lib/natty-ui/renderer/shell.rb +15 -0
- data/lib/natty-ui/renderer/shell_runner.rb +29 -0
- data/lib/natty-ui/renderer/table_renderer.rb +429 -0
- data/lib/natty-ui/section.rb +142 -41
- data/lib/natty-ui/task.rb +39 -27
- data/lib/natty-ui/temporary.rb +27 -14
- data/lib/natty-ui/utils/border.rb +139 -0
- data/lib/natty-ui/utils/str_const.rb +62 -0
- data/lib/natty-ui/utils/utils.rb +47 -0
- data/lib/natty-ui/version.rb +1 -1
- data/lib/natty-ui.rb +87 -30
- metadata +31 -28
- data/examples/cols.rb +0 -38
- data/examples/illustration.rb +0 -60
- data/examples/options.rb +0 -28
- data/examples/themes.rb +0 -51
- data/lib/natty-ui/attributes.rb +0 -593
- data/lib/natty-ui/choice.rb +0 -67
- data/lib/natty-ui/dumb_choice.rb +0 -47
- data/lib/natty-ui/dumb_options.rb +0 -64
- data/lib/natty-ui/framed.rb +0 -51
- data/lib/natty-ui/hbars_renderer.rb +0 -66
- data/lib/natty-ui/options.rb +0 -78
- data/lib/natty-ui/shell_renderer.rb +0 -91
- data/lib/natty-ui/table.rb +0 -325
- data/lib/natty-ui/table_renderer.rb +0 -165
- data/lib/natty-ui/theme.rb +0 -403
- data/lib/natty-ui/utils.rb +0 -111
- data/lib/natty-ui/vbars_renderer.rb +0 -49
- data/lib/natty-ui/width_finder.rb +0 -137
- data/natty-ui.gemspec +0 -34
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'terminal/text'
|
|
4
|
-
require_relative 'width_finder'
|
|
5
|
-
|
|
6
|
-
module NattyUI
|
|
7
|
-
class TableRenderer
|
|
8
|
-
def self.[](table, max_width)
|
|
9
|
-
columns = table.columns.map(&:width)
|
|
10
|
-
return [] if columns.empty?
|
|
11
|
-
att = table.attributes
|
|
12
|
-
case att.max_width
|
|
13
|
-
when Float
|
|
14
|
-
max_width *= att.max_width
|
|
15
|
-
when Integer
|
|
16
|
-
max_width = [max_width, att.max_width].min
|
|
17
|
-
end
|
|
18
|
-
unless att.border_chars.nil?
|
|
19
|
-
max_width -= (columns.size - 1)
|
|
20
|
-
max_width -= 2 if att.border_around
|
|
21
|
-
end
|
|
22
|
-
return [] if max_width < columns.size
|
|
23
|
-
new(columns, table.each.to_a, att, max_width).lines
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
attr_reader :lines
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def initialize(columns, rows, att, max_width)
|
|
31
|
-
@max_width, @columns = WidthFinder.find(columns, max_width)
|
|
32
|
-
init_borders(att)
|
|
33
|
-
@columns = @columns.each.with_index
|
|
34
|
-
|
|
35
|
-
@lines = render(rows.shift)
|
|
36
|
-
@lines.unshift(@b_top) if @b_top
|
|
37
|
-
|
|
38
|
-
if @b_between
|
|
39
|
-
rows.each do |row|
|
|
40
|
-
@lines << @b_between
|
|
41
|
-
@lines += render(row)
|
|
42
|
-
end
|
|
43
|
-
else
|
|
44
|
-
rows.each { |row| @lines += render(row) }
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
@lines << @b_bottom if @b_bottom
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def render(row)
|
|
51
|
-
cells = @columns.map { |cw, i| Cell.new(row[i], cw) }
|
|
52
|
-
height = cells.max_by { _1.text.size }.text.size
|
|
53
|
-
cells.each { _1.correct_height(height) }
|
|
54
|
-
Array.new(height) do |line|
|
|
55
|
-
"#{@b_outer}#{cells.map { _1.text[line] }.join(@b_inner)}#{@b_outer}"
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def init_borders(att)
|
|
60
|
-
chars = att.border_chars or return
|
|
61
|
-
style = border_style(att)
|
|
62
|
-
@b_inner = style[chars[9]]
|
|
63
|
-
return if chars[10] == ' '
|
|
64
|
-
return init_borders_around(chars, style) if att.border_around
|
|
65
|
-
@b_between = chars[10] * (@max_width + @columns.size - 1)
|
|
66
|
-
i = -1
|
|
67
|
-
@columns[0..-2].each { |w| @b_between[i += w + 1] = chars[4] }
|
|
68
|
-
@b_between = style[@b_between]
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def init_borders_around(chars, style)
|
|
72
|
-
fw = chars[10] * (@max_width + @columns.size - 1)
|
|
73
|
-
@b_top = "#{chars[0]}#{fw}#{chars[2]}"
|
|
74
|
-
@b_bottom = "#{chars[6]}#{fw}#{chars[8]}"
|
|
75
|
-
@b_between = "#{chars[3]}#{fw}#{chars[5]}"
|
|
76
|
-
i = 0
|
|
77
|
-
@columns[0..-2].each do |w|
|
|
78
|
-
@b_top[i += w + 1] = chars[1]
|
|
79
|
-
@b_bottom[i] = chars[7]
|
|
80
|
-
@b_between[i] = chars[4]
|
|
81
|
-
end
|
|
82
|
-
@b_top = style[@b_top]
|
|
83
|
-
@b_bottom = style[@b_bottom]
|
|
84
|
-
@b_between = style[@b_between]
|
|
85
|
-
@b_outer = @b_inner
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def border_style(att)
|
|
89
|
-
style = att.border_style_bbcode
|
|
90
|
-
style ? ->(line) { "#{style}#{line}[/]" } : lambda(&:itself)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
class Cell
|
|
94
|
-
attr_reader :width, :text
|
|
95
|
-
|
|
96
|
-
def correct_height(height)
|
|
97
|
-
return self if (diff = height - @text.size) <= 0
|
|
98
|
-
@text =
|
|
99
|
-
case @vertical
|
|
100
|
-
when :bottom
|
|
101
|
-
[Array.new(diff, @empty), @text]
|
|
102
|
-
when :middle
|
|
103
|
-
tc = diff / 2
|
|
104
|
-
[Array.new(tc, @empty), @text, Array.new(diff - tc, @empty)]
|
|
105
|
-
else
|
|
106
|
-
[@text, Array.new(diff, @empty)]
|
|
107
|
-
end.flatten(1)
|
|
108
|
-
self
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def initialize(cell, width)
|
|
112
|
-
return @text = [] unless cell
|
|
113
|
-
att = cell.attributes
|
|
114
|
-
@padding = att.padding.dup
|
|
115
|
-
@align = att.align
|
|
116
|
-
@vertical = att.vertical
|
|
117
|
-
@style = att.style_bbcode
|
|
118
|
-
@text = width_corrected(cell.text, width, att.eol == false)
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
private
|
|
122
|
-
|
|
123
|
-
def width_corrected(text, width, ignore_newline)
|
|
124
|
-
@width, @padding[3], @padding[1] =
|
|
125
|
-
WidthFinder.adjust(width, @padding[3], @padding[1])
|
|
126
|
-
@empty = @style ? "#{@style}#{' ' * width}[/]" : ' ' * width
|
|
127
|
-
[
|
|
128
|
-
Array.new(@padding[0], @empty),
|
|
129
|
-
Text.each_line_with_size(
|
|
130
|
-
*text,
|
|
131
|
-
limit: @width,
|
|
132
|
-
bbcode: true,
|
|
133
|
-
ignore_newline: ignore_newline,
|
|
134
|
-
ansi: Terminal.ansi?
|
|
135
|
-
).map(&txt_fmt),
|
|
136
|
-
Array.new(@padding[2], @empty)
|
|
137
|
-
].flatten(1)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def txt_fmt
|
|
141
|
-
lpad, rpad = pads
|
|
142
|
-
case @align
|
|
143
|
-
when :right
|
|
144
|
-
->(txt, w) { "#{lpad}#{' ' * (@width - w)}#{txt}#{rpad}" }
|
|
145
|
-
when :centered
|
|
146
|
-
lambda do |txt, w|
|
|
147
|
-
s = @width - w
|
|
148
|
-
"#{lpad}#{' ' * (lw = s / 2)}#{txt}#{' ' * (s - lw)}#{rpad}"
|
|
149
|
-
end
|
|
150
|
-
else
|
|
151
|
-
->(txt, w) { "#{lpad}#{txt}#{' ' * (@width - w)}#{rpad}" }
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def pads
|
|
156
|
-
return ' ' * @padding[3], "[/]#{' ' * @padding[1]}" unless @style
|
|
157
|
-
["#{@style}#{' ' * @padding[3]}", "#{' ' * @padding[1]}[/]"]
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
private_constant :Cell
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
private_constant :TableRenderer
|
|
165
|
-
end
|
data/lib/natty-ui/theme.rb
DELETED
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'utils'
|
|
4
|
-
|
|
5
|
-
module NattyUI
|
|
6
|
-
# @todo This chapter needs more documentation.
|
|
7
|
-
#
|
|
8
|
-
# A theme defines the style of elements.
|
|
9
|
-
#
|
|
10
|
-
class Theme
|
|
11
|
-
class << self
|
|
12
|
-
# Currently used theme
|
|
13
|
-
#
|
|
14
|
-
# @return [Theme]
|
|
15
|
-
attr_reader :current
|
|
16
|
-
|
|
17
|
-
# Name of currently used theme
|
|
18
|
-
#
|
|
19
|
-
# @return [Symbol]
|
|
20
|
-
attr_reader :current_name
|
|
21
|
-
|
|
22
|
-
# Names of all registered themes
|
|
23
|
-
#
|
|
24
|
-
# @attribute [r] names
|
|
25
|
-
# @return [Array<Symbol>]
|
|
26
|
-
def names = @ll.keys.sort!
|
|
27
|
-
|
|
28
|
-
# Use a theme
|
|
29
|
-
#
|
|
30
|
-
# @param name [Symbol]
|
|
31
|
-
# @return [Symbol] name of used theme
|
|
32
|
-
def use(name)
|
|
33
|
-
sel = find(name).last
|
|
34
|
-
if sel.is_a?(Proc)
|
|
35
|
-
sel[builder = Builder.new]
|
|
36
|
-
sel = @ll[name][-1] = builder.build.freeze
|
|
37
|
-
end
|
|
38
|
-
@current = sel
|
|
39
|
-
@current_name = name
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Get the descrition of a theme.
|
|
43
|
-
#
|
|
44
|
-
# @param name [Symbol]
|
|
45
|
-
# @return [String] description of the theme
|
|
46
|
-
def description(name) = find(name).first
|
|
47
|
-
|
|
48
|
-
# Register a theme
|
|
49
|
-
#
|
|
50
|
-
# @param name [Symbol] theme name
|
|
51
|
-
# @param description [#to_s] theme description
|
|
52
|
-
# @yieldparam builder [Builder] theme build helper
|
|
53
|
-
# @return [Theme] itself
|
|
54
|
-
def register(name, description = nil, &block)
|
|
55
|
-
raise(ArgumentError, 'block missing') unless block
|
|
56
|
-
@ll[name.to_sym] = [description&.to_s || name.to_s.capitalize, block]
|
|
57
|
-
self
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
|
|
62
|
-
def find(name)
|
|
63
|
-
@ll.fetch(name) { raise(ArgumentError, "no such theme - #{name}") }
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# @todo This chapter needs more documentation.
|
|
68
|
-
#
|
|
69
|
-
# Helper class to define a {Theme}.
|
|
70
|
-
#
|
|
71
|
-
class Builder
|
|
72
|
-
attr_accessor :section_border
|
|
73
|
-
attr_reader :mark,
|
|
74
|
-
:border,
|
|
75
|
-
:heading,
|
|
76
|
-
:heading_sytle,
|
|
77
|
-
:section_styles,
|
|
78
|
-
:task_style,
|
|
79
|
-
:choice_current_style,
|
|
80
|
-
:choice_style,
|
|
81
|
-
:sh_out_style,
|
|
82
|
-
:sh_err_style
|
|
83
|
-
|
|
84
|
-
def heading_sytle=(value)
|
|
85
|
-
@heading_sytle = Utils.style(value)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def task_style=(value)
|
|
89
|
-
@task_style = Utils.style(value)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def choice_current_style=(value)
|
|
93
|
-
@choice_current_style = Utils.style(value)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def choice_style=(value)
|
|
97
|
-
@choice_style = Utils.style(value)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def sh_out_style=(value)
|
|
101
|
-
@sh_out_style = Utils.style(value)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def sh_err_style=(value)
|
|
105
|
-
@sh_err_style = Utils.style(value)
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# @return [Theme] new theme
|
|
109
|
-
def build = Theme.new(self)
|
|
110
|
-
|
|
111
|
-
def define_marker(**defs)
|
|
112
|
-
@mark.merge!(defs)
|
|
113
|
-
self
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def define_border(**defs)
|
|
117
|
-
defs.each_pair do |name, str|
|
|
118
|
-
s = str.to_s
|
|
119
|
-
case Text.width(s, bbcode: false)
|
|
120
|
-
when 1
|
|
121
|
-
@border[name.to_sym] = "#{s * 11} "
|
|
122
|
-
when 11
|
|
123
|
-
@border[name.to_sym] = "#{s} "
|
|
124
|
-
when 13
|
|
125
|
-
@border[name.to_sym] = s
|
|
126
|
-
else
|
|
127
|
-
raise(
|
|
128
|
-
TypeError,
|
|
129
|
-
"invalid boder definition for #{name} - #{str.inspect}"
|
|
130
|
-
)
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
self
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def define_heading(*defs)
|
|
137
|
-
@heading = defs.flatten.take(6)
|
|
138
|
-
@heading += Array.new(6 - @heading.size, @heading[-1])
|
|
139
|
-
self
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def define_section(**defs)
|
|
143
|
-
defs.each_pair do |name, style|
|
|
144
|
-
style = Utils.style(style)
|
|
145
|
-
@section_styles[name.to_sym] = style if style
|
|
146
|
-
end
|
|
147
|
-
self
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
private
|
|
151
|
-
|
|
152
|
-
def initialize
|
|
153
|
-
define_heading(%w[╸╸╺╸╺━━━ ╴╶╴╶─═══ ╴╶╴╶─── ════ ━━━━ ────])
|
|
154
|
-
@mark = {
|
|
155
|
-
default: '•',
|
|
156
|
-
bullet: '•',
|
|
157
|
-
checkmark: '✓',
|
|
158
|
-
quote: '▍',
|
|
159
|
-
information: '𝒊',
|
|
160
|
-
warning: '!',
|
|
161
|
-
error: '𝙓',
|
|
162
|
-
failed: '𝑭',
|
|
163
|
-
current: '➔',
|
|
164
|
-
choice: '◦',
|
|
165
|
-
current_choice: '◉',
|
|
166
|
-
option: '[ ]',
|
|
167
|
-
option_selected: '[X]',
|
|
168
|
-
sh_out: ':',
|
|
169
|
-
sh_err: '𝙓'
|
|
170
|
-
}
|
|
171
|
-
@border = {
|
|
172
|
-
######### 0123456789012
|
|
173
|
-
default: '┌┬┐├┼┤└┴┘│─╶╴',
|
|
174
|
-
defaulth: '───────── ─╶╴',
|
|
175
|
-
defaultv: '││││││││││ ',
|
|
176
|
-
double: '╔╦╗╠╬╣╚╩╝║═',
|
|
177
|
-
doubleh: '═════════ ═',
|
|
178
|
-
doublev: '║║║║║║║║║║ ',
|
|
179
|
-
heavy: '┏┳┓┣╋┫┗┻┛┃━╺╸',
|
|
180
|
-
heavyh: '━━━━━━━━━ ━╺╸',
|
|
181
|
-
heavyv: '┃┃┃┃┃┃┃┃┃┃ ',
|
|
182
|
-
rounded: '╭┬╮├┼┤╰┴╯│─╶╴'
|
|
183
|
-
}
|
|
184
|
-
@section_border = :rounded
|
|
185
|
-
@section_styles = {}
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
attr_reader :task_style,
|
|
190
|
-
:choice_current_style,
|
|
191
|
-
:choice_style,
|
|
192
|
-
:sh_out_style,
|
|
193
|
-
:sh_err_style,
|
|
194
|
-
:option_states
|
|
195
|
-
|
|
196
|
-
def defined_marks = @mark.keys.sort!
|
|
197
|
-
def defined_borders = @border.keys.sort!
|
|
198
|
-
def heading(index) = @heading[index.to_i.clamp(1, 6) - 1]
|
|
199
|
-
|
|
200
|
-
def mark(value)
|
|
201
|
-
return @mark[value] if value.is_a?(Symbol)
|
|
202
|
-
(element = Str.new(value, true)).empty? ? @mark[:default] : element
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def border(value)
|
|
206
|
-
return @border[value] if value.is_a?(Symbol)
|
|
207
|
-
case Text.width(value = value.to_s, bbcode: false)
|
|
208
|
-
when 1
|
|
209
|
-
"#{value * 11} "
|
|
210
|
-
when 11
|
|
211
|
-
"#{value} "
|
|
212
|
-
when 13
|
|
213
|
-
value
|
|
214
|
-
else
|
|
215
|
-
@border[:default]
|
|
216
|
-
end
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
def section_border(kind)
|
|
220
|
-
kind.is_a?(Symbol) ? @sections[kind] : @sections[:default]
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
def initialize(theme)
|
|
224
|
-
@heading = create_heading(theme.heading, theme.heading_sytle).freeze
|
|
225
|
-
@border = create_border(theme.border).freeze
|
|
226
|
-
@mark = create_mark(theme.mark).freeze
|
|
227
|
-
@task_style = as_style(theme.task_style)
|
|
228
|
-
@choice_current_style = as_style(theme.choice_current_style)
|
|
229
|
-
@choice_style = as_style(theme.choice_style)
|
|
230
|
-
@sh_out_style = as_style(theme.sh_out_style)
|
|
231
|
-
@sh_err_style = as_style(theme.sh_err_style)
|
|
232
|
-
@sections =
|
|
233
|
-
create_sections(
|
|
234
|
-
SectionBorder.create(border(theme.section_border)),
|
|
235
|
-
theme.section_styles.dup.compare_by_identity
|
|
236
|
-
)
|
|
237
|
-
@option_states = create_option_states
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
private
|
|
241
|
-
|
|
242
|
-
def as_style(value) = (Ansi[*value].freeze if value)
|
|
243
|
-
|
|
244
|
-
def create_option_states
|
|
245
|
-
# [current?][selected?]
|
|
246
|
-
c = @mark[:current_choice]
|
|
247
|
-
n = @mark[:none]
|
|
248
|
-
uns = @mark[:option]
|
|
249
|
-
sel = @mark[:option_selected]
|
|
250
|
-
{
|
|
251
|
-
false => { false => n + uns, true => n + sel }.compare_by_identity,
|
|
252
|
-
true => { false => c + uns, true => c + sel }.compare_by_identity
|
|
253
|
-
}.compare_by_identity.freeze
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
def create_sections(template, styles)
|
|
257
|
-
Hash
|
|
258
|
-
.new do |h, kind|
|
|
259
|
-
h[kind] = SectionBorder.new(*template.parts(styles[kind])).freeze
|
|
260
|
-
end
|
|
261
|
-
.compare_by_identity
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
def create_mark(mark)
|
|
265
|
-
return {} if mark.empty?
|
|
266
|
-
mark = mark.to_h { |n, e| [n.to_sym, Str.new("#{e} ")] }
|
|
267
|
-
mark[:none] ||= Str.new(' ', 2)
|
|
268
|
-
with_default(mark)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def create_border(border)
|
|
272
|
-
return {} if border.empty?
|
|
273
|
-
with_default(border.transform_values { _1.dup.freeze })
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
def create_heading(heading, style)
|
|
277
|
-
return create_styled_heading(heading, style) if style
|
|
278
|
-
heading.map do |left|
|
|
279
|
-
right = " #{left.reverse}"
|
|
280
|
-
[left = Str.new("#{left} ", true), Str.new(right, left.width)]
|
|
281
|
-
end
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def create_styled_heading(heading, style)
|
|
285
|
-
heading.map do |left|
|
|
286
|
-
right = Ansi.decorate(left.reverse, *style)
|
|
287
|
-
[
|
|
288
|
-
left = Str.new("#{Ansi.decorate(left, *style)} ", true),
|
|
289
|
-
Str.new(" #{right}", left.width)
|
|
290
|
-
]
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
def with_default(map)
|
|
295
|
-
map.default = (map[:default] ||= map[map.first.first])
|
|
296
|
-
map.compare_by_identity
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
SectionBorder =
|
|
300
|
-
Struct.new(:top, :top_left, :top_right, :bottom, :prefix) do
|
|
301
|
-
def self.create(border)
|
|
302
|
-
mid = border[10] * 2
|
|
303
|
-
mid2 = mid * 2
|
|
304
|
-
right = "#{border[11]}#{border[12] * 2}"
|
|
305
|
-
new(
|
|
306
|
-
border[0] + mid2 + right,
|
|
307
|
-
border[0] + mid,
|
|
308
|
-
mid + right,
|
|
309
|
-
border[6] + mid2 + right,
|
|
310
|
-
border[9]
|
|
311
|
-
)
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
def parts(style)
|
|
315
|
-
if style
|
|
316
|
-
style = Ansi[*style]
|
|
317
|
-
reset = Ansi::RESET
|
|
318
|
-
end
|
|
319
|
-
[
|
|
320
|
-
Str.new("#{style}#{top}#{reset}", 6),
|
|
321
|
-
Str.new("#{style}#{top_left}#{reset} ", 4),
|
|
322
|
-
Str.new(" #{style}#{top_right}#{reset}", 6),
|
|
323
|
-
Str.new("#{style}#{bottom}#{reset}", 6),
|
|
324
|
-
Str.new("#{style}#{prefix}#{reset} ", 2)
|
|
325
|
-
]
|
|
326
|
-
end
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
private_constant :SectionBorder
|
|
330
|
-
|
|
331
|
-
@ll = {}
|
|
332
|
-
|
|
333
|
-
register(:mono, 'Monochrome – Non-ANSI fallback', &:itself)
|
|
334
|
-
|
|
335
|
-
register(:default, 'Default – uses default colors') do |theme|
|
|
336
|
-
theme.heading_sytle = :bright_blue
|
|
337
|
-
theme.task_style = %i[bright_green b]
|
|
338
|
-
# theme.choice_style =
|
|
339
|
-
theme.sh_out_style = :default
|
|
340
|
-
theme.sh_err_style = :bright_yellow
|
|
341
|
-
theme.choice_current_style = %i[bright_white on_blue b]
|
|
342
|
-
theme.define_marker(
|
|
343
|
-
bullet: '[bright_white]•[/fg]',
|
|
344
|
-
checkmark: '[bright_green]✓[/fg]',
|
|
345
|
-
quote: '[bright_blue]▍[/fg]',
|
|
346
|
-
information: '[bright_yellow]𝒊[/fg]',
|
|
347
|
-
warning: '[bright_yellow]![/fg]',
|
|
348
|
-
error: '[red]𝙓[/fg]',
|
|
349
|
-
failed: '[bright_red]𝑭[/fg]',
|
|
350
|
-
current: '[bright_green]➔[/fg]',
|
|
351
|
-
choice: '[bright_white]◦[/fg]',
|
|
352
|
-
current_choice: '[bright_green]➔[/fg]',
|
|
353
|
-
option: '[dim][ ][/dim]',
|
|
354
|
-
option_selected: '[dim][[/dim][green]X[/fg][dim]][/dim]',
|
|
355
|
-
sh_out: '[bright_white]:[/fg]',
|
|
356
|
-
sh_err: '[red]𝙓[/fg]'
|
|
357
|
-
)
|
|
358
|
-
theme.define_section(
|
|
359
|
-
default: :bright_blue,
|
|
360
|
-
message: :bright_blue,
|
|
361
|
-
information: :bright_blue,
|
|
362
|
-
warning: :bright_yellow,
|
|
363
|
-
error: :red,
|
|
364
|
-
failed: :bright_red
|
|
365
|
-
)
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
register(:emoji, 'Emoji – emoticons and default colors') do |theme|
|
|
369
|
-
theme.heading_sytle = :bright_blue
|
|
370
|
-
theme.task_style = %i[bright_green b]
|
|
371
|
-
# theme.choice_style =
|
|
372
|
-
theme.sh_out_style = :default
|
|
373
|
-
theme.sh_err_style = :bright_red
|
|
374
|
-
theme.choice_current_style = %i[bright_white on_blue b]
|
|
375
|
-
theme.define_marker(
|
|
376
|
-
bullet: '▫️',
|
|
377
|
-
checkmark: '✅',
|
|
378
|
-
quote: '[bright_blue]▍[/fg]',
|
|
379
|
-
information: '📌',
|
|
380
|
-
warning: '⚠️',
|
|
381
|
-
error: '❗️',
|
|
382
|
-
failed: '‼️',
|
|
383
|
-
current: '➡️',
|
|
384
|
-
choice: '[bright_white]•[/fg]',
|
|
385
|
-
current_choice: '[bright_green]●[/fg]',
|
|
386
|
-
option: '[dim][ ][/dim] ',
|
|
387
|
-
option_selected: '[dim][[/dim][green]X[/fg][dim]][/dim]',
|
|
388
|
-
sh_out: '[white b]:[/]',
|
|
389
|
-
sh_err: '❗️'
|
|
390
|
-
)
|
|
391
|
-
theme.define_section(
|
|
392
|
-
default: :bright_blue,
|
|
393
|
-
message: :bright_blue,
|
|
394
|
-
information: :bright_blue,
|
|
395
|
-
warning: :bright_yellow,
|
|
396
|
-
error: :red,
|
|
397
|
-
failed: :bright_red
|
|
398
|
-
)
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
use(Terminal.colors == 2 ? :mono : :default)
|
|
402
|
-
end
|
|
403
|
-
end
|
data/lib/natty-ui/utils.rb
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module NattyUI
|
|
4
|
-
module Utils
|
|
5
|
-
class << self
|
|
6
|
-
def style(value)
|
|
7
|
-
value =
|
|
8
|
-
case value
|
|
9
|
-
when Array
|
|
10
|
-
value.dup
|
|
11
|
-
when Enumerable
|
|
12
|
-
value.to_a
|
|
13
|
-
when Symbol, Integer
|
|
14
|
-
[value]
|
|
15
|
-
when nil
|
|
16
|
-
return
|
|
17
|
-
else
|
|
18
|
-
value.to_s.delete_prefix('[').delete_suffix(']').split
|
|
19
|
-
end
|
|
20
|
-
value.uniq!
|
|
21
|
-
value.keep_if { Ansi.valid?(_1) }.empty? ? nil : value
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def align(value)
|
|
25
|
-
POS_ALI.include?(value) ? value : :left
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def position(value)
|
|
29
|
-
value if POS_ALI.include?(value)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def vertical(value)
|
|
33
|
-
VERT.include?(value) ? value : :top
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def split_table_attr(values)
|
|
37
|
-
[values.slice(*TAB_ATTR), values.except(*TAB_ATTR)]
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def padding(*value)
|
|
41
|
-
value = value.flatten.take(4).map! { [0, _1.to_i].max }
|
|
42
|
-
case value.size
|
|
43
|
-
when 0
|
|
44
|
-
[0, 0, 0, 0]
|
|
45
|
-
when 1
|
|
46
|
-
Array.new(4, value[0])
|
|
47
|
-
when 2
|
|
48
|
-
value * 2
|
|
49
|
-
when 3
|
|
50
|
-
value << value[1]
|
|
51
|
-
else
|
|
52
|
-
value
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
alias margin padding
|
|
56
|
-
|
|
57
|
-
def as_size(range, value)
|
|
58
|
-
return range.begin if value == :min
|
|
59
|
-
return range.end if value.nil? || value.is_a?(Symbol)
|
|
60
|
-
(
|
|
61
|
-
if value.is_a?(Numeric)
|
|
62
|
-
(value > 0 && value < 1 ? (range.end * value) : value).round
|
|
63
|
-
else
|
|
64
|
-
value.to_i
|
|
65
|
-
end
|
|
66
|
-
).clamp(range)
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
POS_ALI = %i[right centered].freeze
|
|
71
|
-
VERT = %i[bottom middle].freeze
|
|
72
|
-
TAB_ATTR = %i[border_around border border_style position].freeze
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
class Str
|
|
76
|
-
attr_reader :to_s
|
|
77
|
-
alias to_str to_s
|
|
78
|
-
def empty? = width == 0
|
|
79
|
-
def inspect = @to_s.inspect
|
|
80
|
-
|
|
81
|
-
def width
|
|
82
|
-
return @width if @width
|
|
83
|
-
@width = Text.width(@to_s)
|
|
84
|
-
freeze
|
|
85
|
-
@width
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def +(other)
|
|
89
|
-
other = Str.new(other) unless other.is_a?(Str)
|
|
90
|
-
Str.new(@to_s + other.to_s, width + other.width)
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
if Terminal.ansi?
|
|
94
|
-
def initialize(str, width = nil)
|
|
95
|
-
@to_s = Ansi.bbcode(str).freeze
|
|
96
|
-
return unless width
|
|
97
|
-
@width = @width.is_a?(Integer) ? width : Text.width(@to_s)
|
|
98
|
-
freeze
|
|
99
|
-
end
|
|
100
|
-
else
|
|
101
|
-
def initialize(str, width = nil)
|
|
102
|
-
@to_s = Ansi.plain(str).freeze
|
|
103
|
-
return unless width
|
|
104
|
-
@width = @width.is_a?(Integer) ? width : Text.width(@to_s)
|
|
105
|
-
freeze
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
private_constant :Utils, :Str
|
|
111
|
-
end
|