charming 0.1.1 → 0.1.3
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/README.md +2 -2
- data/lib/charming/application.rb +14 -3
- data/lib/charming/cli.rb +23 -0
- data/lib/charming/controller/class_methods.rb +115 -0
- data/lib/charming/controller/command_palette.rb +135 -0
- data/lib/charming/controller/component_dispatching.rb +81 -0
- data/lib/charming/controller/dispatching.rb +60 -0
- data/lib/charming/controller/focus_management.rb +30 -0
- data/lib/charming/controller/rendering.rb +127 -0
- data/lib/charming/controller/session_state.rb +41 -0
- data/lib/charming/controller/sidebar_navigation.rb +111 -0
- data/lib/charming/controller.rb +35 -559
- data/lib/charming/database_commands.rb +16 -0
- data/lib/charming/database_installer.rb +27 -0
- data/lib/charming/focus.rb +58 -2
- data/lib/charming/generators/app_file_generator.rb +13 -0
- data/lib/charming/generators/app_generator.rb +123 -47
- data/lib/charming/generators/base.rb +26 -0
- data/lib/charming/generators/component_generator.rb +10 -10
- data/lib/charming/generators/controller_generator.rb +22 -11
- data/lib/charming/generators/model_generator.rb +38 -29
- data/lib/charming/generators/name.rb +10 -0
- data/lib/charming/generators/screen_generator.rb +78 -32
- data/lib/charming/generators/templates/app/Gemfile.template +5 -0
- data/lib/charming/generators/templates/app/README.md.template +9 -0
- data/lib/charming/generators/templates/app/Rakefile.template +3 -0
- data/lib/charming/generators/templates/app/application.template +13 -0
- data/lib/charming/generators/templates/app/application_controller.template +19 -0
- data/lib/charming/generators/templates/app/application_record.template +7 -0
- data/lib/charming/generators/templates/app/application_state.template +6 -0
- data/lib/charming/generators/templates/app/database_config.template +12 -0
- data/lib/charming/generators/templates/app/executable.template +7 -0
- data/lib/charming/generators/templates/app/gemspec.template +6 -0
- data/lib/charming/generators/templates/app/home_controller.template +6 -0
- data/lib/charming/generators/templates/app/home_state.template +7 -0
- data/lib/charming/generators/templates/app/keep.template +0 -0
- data/lib/charming/generators/templates/app/layout.template +110 -0
- data/lib/charming/generators/templates/app/root_file.template +20 -0
- data/lib/charming/generators/templates/app/routes.template +5 -0
- data/lib/charming/generators/templates/app/seeds.template +1 -0
- data/lib/charming/generators/templates/app/spec_controller.template +17 -0
- data/lib/charming/generators/templates/app/spec_helper.template +3 -0
- data/lib/charming/generators/templates/app/spec_state.template +17 -0
- data/lib/charming/generators/templates/app/spec_view.template +16 -0
- data/lib/charming/generators/templates/app/version.template +5 -0
- data/lib/charming/generators/templates/app/view.template +21 -0
- data/lib/charming/generators/templates/component/component.rb.template +9 -0
- data/lib/charming/generators/templates/controller/controller.rb.template +6 -0
- data/lib/charming/generators/templates/model/migration.rb.template +9 -0
- data/lib/charming/generators/templates/model/model.rb.template +6 -0
- data/lib/charming/generators/templates/model/spec.rb.template +9 -0
- data/lib/charming/generators/templates/screen/controller.rb.template +7 -0
- data/lib/charming/generators/templates/screen/spec_controller.rb.template +17 -0
- data/lib/charming/generators/templates/screen/spec_state.rb.template +17 -0
- data/lib/charming/generators/templates/screen/spec_view.rb.template +13 -0
- data/lib/charming/generators/templates/screen/state.rb.template +7 -0
- data/lib/charming/generators/templates/screen/view.rb.template +11 -0
- data/lib/charming/generators/templates/view/view.rb.template +11 -0
- data/lib/charming/generators/view_generator.rb +19 -3
- data/lib/charming/internal/renderer/differential.rb +25 -2
- data/lib/charming/internal/renderer/full_repaint.rb +6 -0
- data/lib/charming/internal/terminal/adapter.rb +29 -3
- data/lib/charming/internal/terminal/key_normalizer.rb +84 -0
- data/lib/charming/internal/terminal/memory_backend.rb +28 -1
- data/lib/charming/internal/terminal/mouse_parser.rb +81 -0
- data/lib/charming/internal/terminal/tty_backend.rb +65 -115
- data/lib/charming/presentation/component.rb +3 -5
- data/lib/charming/presentation/components/activity_indicator.rb +173 -134
- data/lib/charming/presentation/components/command_palette.rb +94 -96
- data/lib/charming/presentation/components/command_palette_modal.rb +33 -0
- data/lib/charming/presentation/components/empty_state.rb +47 -36
- data/lib/charming/presentation/components/form/builder.rb +52 -40
- data/lib/charming/presentation/components/form/confirm.rb +50 -39
- data/lib/charming/presentation/components/form/field.rb +94 -71
- data/lib/charming/presentation/components/form/input.rb +61 -49
- data/lib/charming/presentation/components/form/note.rb +27 -20
- data/lib/charming/presentation/components/form/select.rb +84 -63
- data/lib/charming/presentation/components/form/textarea.rb +67 -53
- data/lib/charming/presentation/components/form.rb +120 -93
- data/lib/charming/presentation/components/keyboard_handler.rb +41 -43
- data/lib/charming/presentation/components/list.rb +123 -97
- data/lib/charming/presentation/components/markdown.rb +21 -17
- data/lib/charming/presentation/components/modal.rb +55 -43
- data/lib/charming/presentation/components/progressbar.rb +61 -50
- data/lib/charming/presentation/components/spinner.rb +35 -27
- data/lib/charming/presentation/components/table.rb +108 -85
- data/lib/charming/presentation/components/text_area.rb +219 -173
- data/lib/charming/presentation/components/text_input.rb +120 -98
- data/lib/charming/presentation/components/viewport.rb +218 -168
- data/lib/charming/presentation/layout/builder.rb +84 -0
- data/lib/charming/presentation/layout/overlay.rb +55 -0
- data/lib/charming/presentation/layout/pane.rb +149 -0
- data/lib/charming/presentation/layout/rect.rb +21 -0
- data/lib/charming/presentation/layout/screen_layout.rb +58 -0
- data/lib/charming/presentation/layout/split.rb +132 -0
- data/lib/charming/presentation/layout.rb +28 -30
- data/lib/charming/presentation/markdown/block_renderers.rb +118 -0
- data/lib/charming/presentation/markdown/inline_renderers.rb +66 -0
- data/lib/charming/presentation/markdown/render_context.rb +20 -0
- data/lib/charming/presentation/markdown/renderer.rb +82 -174
- data/lib/charming/presentation/markdown/syntax_highlighter.rb +58 -44
- data/lib/charming/presentation/markdown.rb +4 -3
- data/lib/charming/presentation/template_view.rb +22 -17
- data/lib/charming/presentation/templates/erb_handler.rb +4 -6
- data/lib/charming/presentation/templates.rb +47 -32
- data/lib/charming/presentation/ui/ansi_codes.rb +87 -0
- data/lib/charming/presentation/ui/ansi_slicer.rb +92 -0
- data/lib/charming/presentation/ui/border.rb +24 -26
- data/lib/charming/presentation/ui/border_painter.rb +56 -0
- data/lib/charming/presentation/ui/canvas.rb +80 -0
- data/lib/charming/presentation/ui/style.rb +170 -205
- data/lib/charming/presentation/ui/theme.rb +133 -135
- data/lib/charming/presentation/ui/width.rb +12 -14
- data/lib/charming/presentation/ui.rb +70 -213
- data/lib/charming/presentation/view.rb +107 -92
- data/lib/charming/runtime.rb +25 -10
- data/lib/charming/tasks/inline_executor.rb +9 -0
- data/lib/charming/tasks/task.rb +3 -0
- data/lib/charming/tasks/threaded_executor.rb +12 -0
- data/lib/charming/version.rb +1 -1
- data/lib/charming.rb +16 -2
- metadata +60 -10
- data/lib/charming/generators/app_generator/app_spec_templates.rb +0 -90
- data/lib/charming/generators/app_generator/basic_templates.rb +0 -81
- data/lib/charming/generators/app_generator/component_templates.rb +0 -36
- data/lib/charming/generators/app_generator/controller_template.rb +0 -60
- data/lib/charming/generators/app_generator/database_templates.rb +0 -45
- data/lib/charming/generators/app_generator/layout_template.rb +0 -66
- data/lib/charming/generators/app_generator/screen_spec_templates.rb +0 -69
- data/lib/charming/generators/app_generator/state_templates.rb +0 -30
- data/lib/charming/generators/app_generator/view_template.rb +0 -84
|
@@ -1,244 +1,209 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Charming
|
|
4
|
-
module
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
white: 37,
|
|
25
|
-
bright_black: 90,
|
|
26
|
-
bright_red: 91,
|
|
27
|
-
bright_green: 92,
|
|
28
|
-
bright_yellow: 93,
|
|
29
|
-
bright_blue: 94,
|
|
30
|
-
bright_magenta: 95,
|
|
31
|
-
bright_cyan: 96,
|
|
32
|
-
bright_white: 97
|
|
33
|
-
}.freeze
|
|
34
|
-
|
|
35
|
-
def initialize(options = {})
|
|
36
|
-
@options = {
|
|
37
|
-
attributes: [],
|
|
38
|
-
padding: [0, 0, 0, 0],
|
|
39
|
-
align: :left
|
|
40
|
-
}.merge(options)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def foreground(color)
|
|
44
|
-
with(foreground: color)
|
|
45
|
-
end
|
|
46
|
-
alias_method :fg, :foreground
|
|
47
|
-
|
|
48
|
-
def background(color)
|
|
49
|
-
with(background: color)
|
|
50
|
-
end
|
|
51
|
-
alias_method :bg, :background
|
|
52
|
-
|
|
53
|
-
ATTRIBUTES.each_key do |attribute|
|
|
54
|
-
define_method(attribute) do
|
|
55
|
-
with(attributes: (@options.fetch(:attributes) + [attribute]).uniq)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def padding(*values)
|
|
60
|
-
with(padding: expand_box_values(values))
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def border(style = :normal, sides: nil, foreground: nil)
|
|
64
|
-
with(border: style, border_sides: sides, border_foreground: foreground)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def width(value)
|
|
68
|
-
with(width: value)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def height(value)
|
|
72
|
-
with(height: value)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def align(value)
|
|
76
|
-
with(align: value)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def render(value)
|
|
80
|
-
lines = apply_dimensions(value.to_s.lines(chomp: true))
|
|
81
|
-
lines = apply_padding(lines)
|
|
82
|
-
lines = apply_border(lines)
|
|
83
|
-
apply_ansi(lines.join("\n"))
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
private
|
|
87
|
-
|
|
88
|
-
def with(changes)
|
|
89
|
-
self.class.new(@options.merge(changes))
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def apply_dimensions(lines)
|
|
93
|
-
content_width = target_content_width(lines)
|
|
94
|
-
dimensioned = lines.map { |line| align_line(fit_line(line, content_width), content_width) }
|
|
95
|
-
apply_height(dimensioned, content_width)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def target_content_width(lines)
|
|
99
|
-
explicit_width = @options[:width]
|
|
100
|
-
natural_width = lines.map { |line| Width.measure(line) }.max || 0
|
|
101
|
-
explicit_width || natural_width
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def fit_line(line, width)
|
|
105
|
-
return line if Width.measure(line) <= width
|
|
4
|
+
module UI
|
|
5
|
+
# Style is an immutable builder for terminal text styling. Every method returns a new
|
|
6
|
+
# Style instance with the requested attribute added, so styles can be safely chained and
|
|
7
|
+
# shared across views. `render(value)` applies the accumulated style to a string.
|
|
8
|
+
class Style
|
|
9
|
+
ATTRIBUTES = ANSICodes::ATTRIBUTES
|
|
10
|
+
|
|
11
|
+
COLORS = ANSICodes::COLORS
|
|
12
|
+
|
|
13
|
+
# Initializes a new style with an optional options hash. Recognized keys: `:attributes`
|
|
14
|
+
# (array of attribute symbols), `:padding` ([top, right, bottom, left]), `:align`
|
|
15
|
+
# (`:left`/`:right`/`:center`), and any of `:foreground`, `:background`, `:border`,
|
|
16
|
+
# `:border_sides`, `:border_foreground`, `:width`, `:height`.
|
|
17
|
+
def initialize(options = {})
|
|
18
|
+
@options = {
|
|
19
|
+
attributes: [],
|
|
20
|
+
padding: [0, 0, 0, 0],
|
|
21
|
+
align: :left
|
|
22
|
+
}.merge(options)
|
|
23
|
+
end
|
|
106
24
|
|
|
107
|
-
|
|
108
|
-
|
|
25
|
+
# Returns a new Style with the foreground *color* set. *color* is a color name (":red"),
|
|
26
|
+
# 256-color index (integer), or hex string ("#rrggbb").
|
|
27
|
+
def foreground(color)
|
|
28
|
+
with(foreground: color)
|
|
29
|
+
end
|
|
30
|
+
alias_method :fg, :foreground
|
|
109
31
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
32
|
+
# Returns a new Style with the background *color* set.
|
|
33
|
+
def background(color)
|
|
34
|
+
with(background: color)
|
|
35
|
+
end
|
|
36
|
+
alias_method :bg, :background
|
|
113
37
|
|
|
114
|
-
|
|
115
|
-
|
|
38
|
+
# Attribute methods (bold, italic, underline, …) are defined dynamically by the
|
|
39
|
+
# metaprogramming loop below. Each toggles a single text attribute on the style.
|
|
40
|
+
ATTRIBUTES.each_key do |attribute|
|
|
41
|
+
define_method(attribute) do
|
|
42
|
+
with(attributes: (@options.fetch(:attributes) + [attribute]).uniq)
|
|
116
43
|
end
|
|
44
|
+
end
|
|
117
45
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
pad_line(line, inner_width, left, right)
|
|
124
|
-
end
|
|
46
|
+
# Returns a new Style with the padding set. Accepts 1, 2, or 4 values following CSS-style
|
|
47
|
+
# shorthand: 1 → all sides, 2 → [vertical, horizontal], 4 → [top, right, bottom, left].
|
|
48
|
+
def padding(*values)
|
|
49
|
+
with(padding: expand_box_values(values))
|
|
50
|
+
end
|
|
125
51
|
|
|
126
|
-
|
|
127
|
-
|
|
52
|
+
# Returns a new Style with the border set. *style* is a border name (e.g., :normal,
|
|
53
|
+
# :rounded). *sides* optionally restricts the border to specific sides. *foreground*
|
|
54
|
+
# sets the border color.
|
|
55
|
+
def border(style = :normal, sides: nil, foreground: nil)
|
|
56
|
+
with(border: style, border_sides: sides, border_foreground: foreground)
|
|
57
|
+
end
|
|
128
58
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
59
|
+
# Returns a new Style that fixes the rendered width to *value* (in display columns).
|
|
60
|
+
def width(value)
|
|
61
|
+
with(width: value)
|
|
62
|
+
end
|
|
132
63
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
body = lines.map { |line| border_line(line, width, border, sides) }
|
|
64
|
+
# Returns a new Style that fixes the rendered height to *value* (in rows).
|
|
65
|
+
def height(value)
|
|
66
|
+
with(height: value)
|
|
67
|
+
end
|
|
138
68
|
|
|
139
|
-
|
|
140
|
-
|
|
69
|
+
# Returns a new Style with horizontal alignment set (`:left`, `:right`, or `:center`).
|
|
70
|
+
def align(value)
|
|
71
|
+
with(align: value)
|
|
72
|
+
end
|
|
141
73
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
74
|
+
# Applies the configured style to *value* and returns the styled string. Steps:
|
|
75
|
+
# 1. wrap to `:width`, 2. align horizontally, 3. expand to `:height`, 4. apply padding,
|
|
76
|
+
# 5. paint border, 6. emit ANSI attribute/foreground/background escapes.
|
|
77
|
+
def render(value)
|
|
78
|
+
lines = apply_dimensions(value.to_s.lines(chomp: true))
|
|
79
|
+
lines = apply_padding(lines)
|
|
80
|
+
lines = apply_border(lines)
|
|
81
|
+
apply_ansi(lines.join("\n"))
|
|
82
|
+
end
|
|
145
83
|
|
|
146
|
-
|
|
147
|
-
left = sides.include?(:left) ? render_border(border.vertical) : ""
|
|
148
|
-
right = sides.include?(:right) ? render_border(border.vertical) : ""
|
|
84
|
+
private
|
|
149
85
|
|
|
150
|
-
|
|
151
|
-
|
|
86
|
+
# Returns a copy of self with *changes* merged into the options hash.
|
|
87
|
+
def with(changes)
|
|
88
|
+
self.class.new(@options.merge(changes))
|
|
89
|
+
end
|
|
152
90
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
91
|
+
# Wraps each line to the target width and applies horizontal alignment, then expands
|
|
92
|
+
# to the target height.
|
|
93
|
+
def apply_dimensions(lines)
|
|
94
|
+
content_width = target_content_width(lines)
|
|
95
|
+
dimensioned = lines.map { |line| align_line(fit_line(line, content_width), content_width) }
|
|
96
|
+
apply_height(dimensioned, content_width)
|
|
97
|
+
end
|
|
156
98
|
|
|
157
|
-
|
|
158
|
-
|
|
99
|
+
# Returns the target content width: the explicit :width if set, otherwise the natural
|
|
100
|
+
# max display width of the lines.
|
|
101
|
+
def target_content_width(lines)
|
|
102
|
+
explicit_width = @options[:width]
|
|
103
|
+
natural_width = lines.map { |line| Width.measure(line) }.max || 0
|
|
104
|
+
explicit_width || natural_width
|
|
105
|
+
end
|
|
159
106
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
107
|
+
# Clips *line* to *width* display columns, preserving ANSI styling where possible.
|
|
108
|
+
def fit_line(line, width)
|
|
109
|
+
return line if Width.measure(line) <= width
|
|
163
110
|
|
|
164
|
-
|
|
165
|
-
|
|
111
|
+
UI.visible_slice(line, 0, width)
|
|
112
|
+
end
|
|
166
113
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
114
|
+
# Truncates or pads the lines array to *height* rows, filling with blank rows.
|
|
115
|
+
def apply_height(lines, width)
|
|
116
|
+
height = @options[:height]
|
|
117
|
+
return lines unless height
|
|
170
118
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
119
|
+
visible = lines.first(height)
|
|
120
|
+
visible + Array.new([height - visible.length, 0].max) { " " * width }
|
|
121
|
+
end
|
|
174
122
|
|
|
175
|
-
|
|
123
|
+
# Applies padding by prepending/appending blank rows (vertical) and indenting each
|
|
124
|
+
# line (horizontal).
|
|
125
|
+
def apply_padding(lines)
|
|
126
|
+
top, right, bottom, left = @options.fetch(:padding)
|
|
127
|
+
inner_width = lines.map { |line| Width.measure(line) }.max || 0
|
|
128
|
+
empty = " " * (left + inner_width + right)
|
|
129
|
+
padded = lines.map do |line|
|
|
130
|
+
pad_line(line, inner_width, left, right)
|
|
176
131
|
end
|
|
177
132
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return value if codes.empty?
|
|
133
|
+
Array.new(top, empty) + padded + Array.new(bottom, empty)
|
|
134
|
+
end
|
|
181
135
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
136
|
+
# Paints the configured border around the lines, when :border is set.
|
|
137
|
+
def apply_border(lines)
|
|
138
|
+
border_name = @options[:border]
|
|
139
|
+
return lines unless border_name
|
|
185
140
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
color_codes(@options[:foreground], foreground: true) +
|
|
189
|
-
color_codes(@options[:background], foreground: false)
|
|
190
|
-
end
|
|
141
|
+
border_painter(border_name).paint(lines, content_width(lines))
|
|
142
|
+
end
|
|
191
143
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return truecolor_codes(color, foreground: foreground) if color.to_s.start_with?("#")
|
|
144
|
+
# Pads a single line to *inner_width*, with *left* and *right* padding spaces.
|
|
145
|
+
def pad_line(line, inner_width, left, right)
|
|
146
|
+
(" " * left) + line + (" " * (inner_width - Width.measure(line) + right))
|
|
147
|
+
end
|
|
197
148
|
|
|
198
|
-
|
|
199
|
-
|
|
149
|
+
# Builds a BorderPainter configured for the current border options.
|
|
150
|
+
def border_painter(border_name)
|
|
151
|
+
BorderPainter.new(
|
|
152
|
+
border: Border.fetch(border_name),
|
|
153
|
+
sides: @options[:border_sides],
|
|
154
|
+
foreground: @options[:border_foreground],
|
|
155
|
+
background: @options[:background]
|
|
156
|
+
)
|
|
157
|
+
end
|
|
200
158
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
159
|
+
# Returns the natural display width of the longest line in *lines*.
|
|
160
|
+
def content_width(lines)
|
|
161
|
+
lines.map { |line| Width.measure(line) }.max || 0
|
|
162
|
+
end
|
|
205
163
|
|
|
206
|
-
|
|
207
|
-
|
|
164
|
+
# Applies the active ANSI attribute/foreground/background codes to *value*.
|
|
165
|
+
def apply_ansi(value)
|
|
166
|
+
ansi_codes_obj.apply(value)
|
|
167
|
+
end
|
|
208
168
|
|
|
209
|
-
|
|
210
|
-
|
|
169
|
+
# The list of active ANSI escape sequence strings (attribute + foreground + background).
|
|
170
|
+
def ansi_codes
|
|
171
|
+
ansi_codes_obj.codes
|
|
172
|
+
end
|
|
211
173
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
174
|
+
# Builds an ANSICodes object from the active attributes, foreground, and background.
|
|
175
|
+
def ansi_codes_obj
|
|
176
|
+
ANSICodes.new(
|
|
177
|
+
attributes: @options.fetch(:attributes),
|
|
178
|
+
foreground: @options[:foreground],
|
|
179
|
+
background: @options[:background]
|
|
180
|
+
)
|
|
181
|
+
end
|
|
215
182
|
|
|
216
|
-
|
|
217
|
-
|
|
183
|
+
# Pads *line* on the left or right (or both, for :center) according to :align.
|
|
184
|
+
def align_line(line, width)
|
|
185
|
+
remaining = width - Width.measure(line)
|
|
186
|
+
return line if remaining <= 0
|
|
218
187
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
left = remaining / 2
|
|
228
|
-
(" " * left) + line + (" " * (remaining - left))
|
|
229
|
-
else
|
|
230
|
-
line + (" " * remaining)
|
|
231
|
-
end
|
|
188
|
+
case @options.fetch(:align)
|
|
189
|
+
when :right
|
|
190
|
+
(" " * remaining) + line
|
|
191
|
+
when :center
|
|
192
|
+
left = remaining / 2
|
|
193
|
+
(" " * left) + line + (" " * (remaining - left))
|
|
194
|
+
else
|
|
195
|
+
line + (" " * remaining)
|
|
232
196
|
end
|
|
197
|
+
end
|
|
233
198
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
199
|
+
# Normalizes 1/2/4 padding value arguments into a [top, right, bottom, left] array.
|
|
200
|
+
def expand_box_values(values)
|
|
201
|
+
case values.length
|
|
202
|
+
when 1 then [values[0], values[0], values[0], values[0]]
|
|
203
|
+
when 2 then [values[0], values[1], values[0], values[1]]
|
|
204
|
+
when 4 then values
|
|
205
|
+
else
|
|
206
|
+
raise ArgumentError, "padding expects 1, 2, or 4 values"
|
|
242
207
|
end
|
|
243
208
|
end
|
|
244
209
|
end
|