rich-ruby 1.0.1 → 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/CHANGELOG.md +80 -0
- data/LICENSE +21 -21
- data/README.md +547 -547
- data/docs/architecture.md +43 -0
- data/docs/cheat-sheet.md +52 -0
- data/docs/customization.md +53 -0
- data/docs/how-to-use.md +96 -0
- data/docs/test-report.md +112 -0
- data/docs/troubleshooting.md +36 -0
- data/docs/windows-notes.md +30 -0
- data/examples/demo.rb +106 -106
- data/examples/showcase.rb +420 -420
- data/examples/smoke_test.rb +41 -41
- data/examples/stress_test.rb +604 -604
- data/examples/syntax_markdown_demo.rb +166 -166
- data/examples/verify.rb +216 -215
- data/examples/visual_demo.rb +145 -145
- data/lib/rich/_palettes.rb +148 -148
- data/lib/rich/box.rb +342 -342
- data/lib/rich/cells.rb +524 -512
- data/lib/rich/color.rb +631 -628
- data/lib/rich/color_triplet.rb +227 -220
- data/lib/rich/console.rb +604 -549
- data/lib/rich/control.rb +332 -332
- data/lib/rich/json.rb +260 -254
- data/lib/rich/layout.rb +314 -314
- data/lib/rich/markdown.rb +531 -509
- data/lib/rich/markup.rb +186 -175
- data/lib/rich/panel.rb +318 -311
- data/lib/rich/progress.rb +430 -430
- data/lib/rich/segment.rb +387 -387
- data/lib/rich/style.rb +464 -433
- data/lib/rich/syntax.rb +1220 -1145
- data/lib/rich/table.rb +547 -525
- data/lib/rich/terminal_theme.rb +126 -126
- data/lib/rich/text.rb +460 -433
- data/lib/rich/tree.rb +220 -220
- data/lib/rich/version.rb +5 -5
- data/lib/rich/win32_console.rb +620 -582
- data/lib/rich.rb +108 -108
- metadata +15 -5
data/lib/rich/panel.rb
CHANGED
|
@@ -1,311 +1,318 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "box"
|
|
4
|
-
require_relative "style"
|
|
5
|
-
require_relative "segment"
|
|
6
|
-
require_relative "cells"
|
|
7
|
-
require_relative "text"
|
|
8
|
-
|
|
9
|
-
module Rich
|
|
10
|
-
# A bordered panel container for content
|
|
11
|
-
class Panel
|
|
12
|
-
# @return [Object] Content to display
|
|
13
|
-
attr_reader :content
|
|
14
|
-
|
|
15
|
-
# @return [String, nil] Panel title
|
|
16
|
-
attr_reader :title
|
|
17
|
-
|
|
18
|
-
# @return [String, nil] Panel subtitle
|
|
19
|
-
attr_reader :subtitle
|
|
20
|
-
|
|
21
|
-
# @return [Box] Box style
|
|
22
|
-
attr_reader :box
|
|
23
|
-
|
|
24
|
-
# @return [Style, nil] Border style
|
|
25
|
-
attr_reader :border_style
|
|
26
|
-
|
|
27
|
-
# @return [Style, nil] Title style
|
|
28
|
-
attr_reader :title_style
|
|
29
|
-
|
|
30
|
-
# @return [Style, nil] Subtitle style
|
|
31
|
-
attr_reader :subtitle_style
|
|
32
|
-
|
|
33
|
-
# @return [Boolean] Expand to fill width
|
|
34
|
-
attr_reader :expand
|
|
35
|
-
|
|
36
|
-
# @return [Integer] Padding inside panel
|
|
37
|
-
attr_reader :padding
|
|
38
|
-
|
|
39
|
-
# @return [Integer, nil] Fixed width
|
|
40
|
-
attr_reader :width
|
|
41
|
-
|
|
42
|
-
# @return [Symbol] Title alignment
|
|
43
|
-
attr_reader :title_align
|
|
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
|
-
segments.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
segments.
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
segments
|
|
294
|
-
|
|
295
|
-
# Right
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
segments
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "box"
|
|
4
|
+
require_relative "style"
|
|
5
|
+
require_relative "segment"
|
|
6
|
+
require_relative "cells"
|
|
7
|
+
require_relative "text"
|
|
8
|
+
|
|
9
|
+
module Rich
|
|
10
|
+
# A bordered panel container for content
|
|
11
|
+
class Panel
|
|
12
|
+
# @return [Object] Content to display
|
|
13
|
+
attr_reader :content
|
|
14
|
+
|
|
15
|
+
# @return [String, nil] Panel title
|
|
16
|
+
attr_reader :title
|
|
17
|
+
|
|
18
|
+
# @return [String, nil] Panel subtitle
|
|
19
|
+
attr_reader :subtitle
|
|
20
|
+
|
|
21
|
+
# @return [Box] Box style
|
|
22
|
+
attr_reader :box
|
|
23
|
+
|
|
24
|
+
# @return [Style, nil] Border style
|
|
25
|
+
attr_reader :border_style
|
|
26
|
+
|
|
27
|
+
# @return [Style, nil] Title style
|
|
28
|
+
attr_reader :title_style
|
|
29
|
+
|
|
30
|
+
# @return [Style, nil] Subtitle style
|
|
31
|
+
attr_reader :subtitle_style
|
|
32
|
+
|
|
33
|
+
# @return [Boolean] Expand to fill width
|
|
34
|
+
attr_reader :expand
|
|
35
|
+
|
|
36
|
+
# @return [Integer] Padding inside panel
|
|
37
|
+
attr_reader :padding
|
|
38
|
+
|
|
39
|
+
# @return [Integer, nil] Fixed width
|
|
40
|
+
attr_reader :width
|
|
41
|
+
|
|
42
|
+
# @return [Symbol] Title alignment
|
|
43
|
+
attr_reader :title_align
|
|
44
|
+
|
|
45
|
+
# @return [Symbol] Subtitle alignment
|
|
46
|
+
attr_reader :subtitle_align
|
|
47
|
+
|
|
48
|
+
def initialize(
|
|
49
|
+
content,
|
|
50
|
+
title: nil,
|
|
51
|
+
subtitle: nil,
|
|
52
|
+
box: Box::ROUNDED,
|
|
53
|
+
border_style: nil,
|
|
54
|
+
title_style: nil,
|
|
55
|
+
subtitle_style: nil,
|
|
56
|
+
expand: true,
|
|
57
|
+
padding: 1,
|
|
58
|
+
width: nil,
|
|
59
|
+
title_align: :center,
|
|
60
|
+
subtitle_align: :center
|
|
61
|
+
)
|
|
62
|
+
@content = content
|
|
63
|
+
@title = title
|
|
64
|
+
@subtitle = subtitle
|
|
65
|
+
@box = box
|
|
66
|
+
@border_style = border_style.is_a?(String) ? Style.parse(border_style) : border_style
|
|
67
|
+
@title_style = title_style.is_a?(String) ? Style.parse(title_style) : title_style
|
|
68
|
+
@subtitle_style = subtitle_style.is_a?(String) ? Style.parse(subtitle_style) : subtitle_style
|
|
69
|
+
@expand = expand
|
|
70
|
+
@padding = padding
|
|
71
|
+
@width = width
|
|
72
|
+
@title_align = title_align
|
|
73
|
+
@subtitle_align = subtitle_align
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Render panel to segments
|
|
77
|
+
# @param max_width [Integer] Maximum width
|
|
78
|
+
# @return [Array<Segment>]
|
|
79
|
+
def to_segments(max_width: 80)
|
|
80
|
+
segments = []
|
|
81
|
+
inner_width = calculate_inner_width(max_width)
|
|
82
|
+
content_width = [inner_width - @padding * 2, 0].max
|
|
83
|
+
|
|
84
|
+
# Render content to lines
|
|
85
|
+
content_lines = render_content(content_width)
|
|
86
|
+
|
|
87
|
+
# Top border with title
|
|
88
|
+
segments.concat(render_top_border(inner_width))
|
|
89
|
+
segments << Segment.new("\n")
|
|
90
|
+
|
|
91
|
+
# Padding top
|
|
92
|
+
@padding.times do
|
|
93
|
+
segments.concat(render_empty_row(inner_width))
|
|
94
|
+
segments << Segment.new("\n")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Content rows
|
|
98
|
+
content_lines.each do |line|
|
|
99
|
+
segments.concat(render_content_row(line, inner_width))
|
|
100
|
+
segments << Segment.new("\n")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Padding bottom
|
|
104
|
+
@padding.times do
|
|
105
|
+
segments.concat(render_empty_row(inner_width))
|
|
106
|
+
segments << Segment.new("\n")
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Bottom border with subtitle
|
|
110
|
+
segments.concat(render_bottom_border(inner_width))
|
|
111
|
+
|
|
112
|
+
segments
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Render panel to string with ANSI codes
|
|
116
|
+
# @param max_width [Integer] Maximum width
|
|
117
|
+
# @param color_system [Symbol] Color system
|
|
118
|
+
# @return [String]
|
|
119
|
+
def render(max_width: 80, color_system: ColorSystem::TRUECOLOR)
|
|
120
|
+
Segment.render(to_segments(max_width: max_width), color_system: color_system)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Print panel to console
|
|
124
|
+
# @param console [Console] Console to print to
|
|
125
|
+
def print_to(console)
|
|
126
|
+
rendered = render(max_width: console.width, color_system: console.color_system)
|
|
127
|
+
console.write(rendered)
|
|
128
|
+
console.write("\n")
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
class << self
|
|
132
|
+
# Create a simple panel
|
|
133
|
+
# @param content [String] Content
|
|
134
|
+
# @param title [String, nil] Title
|
|
135
|
+
# @return [Panel]
|
|
136
|
+
def fit(content, title: nil)
|
|
137
|
+
new(content, title: title, expand: false)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
private
|
|
142
|
+
|
|
143
|
+
def calculate_inner_width(max_width)
|
|
144
|
+
raw = if @width
|
|
145
|
+
@width - 2 # Subtract borders
|
|
146
|
+
elsif @expand
|
|
147
|
+
max_width - 2
|
|
148
|
+
else
|
|
149
|
+
content_width = measure_content_width + @padding * 2
|
|
150
|
+
[content_width, max_width - 2].min
|
|
151
|
+
end
|
|
152
|
+
# Never go negative: a width smaller than the two border columns would
|
|
153
|
+
# otherwise produce `String * -1` and crash.
|
|
154
|
+
[raw, 0].max
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def measure_content_width
|
|
158
|
+
case @content
|
|
159
|
+
when String
|
|
160
|
+
Cells.cell_len(@content)
|
|
161
|
+
when Text
|
|
162
|
+
@content.cell_length
|
|
163
|
+
else
|
|
164
|
+
Cells.cell_len(@content.to_s)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def render_content(width)
|
|
169
|
+
case @content
|
|
170
|
+
when String
|
|
171
|
+
wrap_text(@content, width)
|
|
172
|
+
when Text
|
|
173
|
+
@content.wrap(width).map { |t| t.to_segments }
|
|
174
|
+
else
|
|
175
|
+
wrap_text(@content.to_s, width)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def wrap_text(text, width)
|
|
180
|
+
lines = []
|
|
181
|
+
text.split("\n").each do |line|
|
|
182
|
+
if Cells.cell_len(line) <= width
|
|
183
|
+
lines << [Segment.new(line)]
|
|
184
|
+
else
|
|
185
|
+
# Simple wrapping
|
|
186
|
+
current_line = +""
|
|
187
|
+
current_width = 0
|
|
188
|
+
|
|
189
|
+
line.each_char do |char|
|
|
190
|
+
char_width = Cells.char_width(char)
|
|
191
|
+
if current_width + char_width > width
|
|
192
|
+
lines << [Segment.new(current_line)]
|
|
193
|
+
current_line = +char
|
|
194
|
+
current_width = char_width
|
|
195
|
+
else
|
|
196
|
+
current_line << char
|
|
197
|
+
current_width += char_width
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
lines << [Segment.new(current_line)] unless current_line.empty?
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
lines
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def render_top_border(inner_width)
|
|
208
|
+
render_label_edge(@title, @title_align, @box.top_left, @box.top_right,
|
|
209
|
+
@title_style, inner_width)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def render_bottom_border(inner_width)
|
|
213
|
+
render_label_edge(@subtitle, @subtitle_align, @box.bottom_left, @box.bottom_right,
|
|
214
|
+
@subtitle_style, inner_width)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Build a horizontal edge that optionally embeds a centered/left/right
|
|
218
|
+
# label. The edge always spans exactly inner_width cells between the two
|
|
219
|
+
# corners, and every fill count is clamped non-negative so a label that is
|
|
220
|
+
# as wide as (or wider than) the panel can never crash or misalign.
|
|
221
|
+
def render_label_edge(label, align, left_corner, right_corner, label_style, inner_width)
|
|
222
|
+
segments = []
|
|
223
|
+
|
|
224
|
+
unless label
|
|
225
|
+
segments << Segment.new(left_corner, style: @border_style)
|
|
226
|
+
segments << Segment.new(@box.horizontal * inner_width, style: @border_style)
|
|
227
|
+
segments << Segment.new(right_corner, style: @border_style)
|
|
228
|
+
return segments
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
text = " #{label} "
|
|
232
|
+
if Cells.cell_len(text) > inner_width
|
|
233
|
+
label = truncate_label(label, [inner_width - 2, 0].max)
|
|
234
|
+
text = " #{label} "
|
|
235
|
+
end
|
|
236
|
+
text_width = Cells.cell_len(text)
|
|
237
|
+
remaining = [inner_width - text_width, 0].max
|
|
238
|
+
|
|
239
|
+
case align
|
|
240
|
+
when :left
|
|
241
|
+
left = [2, remaining].min
|
|
242
|
+
right = remaining - left
|
|
243
|
+
when :right
|
|
244
|
+
right = [2, remaining].min
|
|
245
|
+
left = remaining - right
|
|
246
|
+
else # :center
|
|
247
|
+
left = remaining / 2
|
|
248
|
+
right = remaining - left
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
segments << Segment.new(left_corner, style: @border_style)
|
|
252
|
+
segments << Segment.new(@box.horizontal * left, style: @border_style)
|
|
253
|
+
segments << Segment.new(text, style: label_style || @border_style)
|
|
254
|
+
segments << Segment.new(@box.horizontal * right, style: @border_style)
|
|
255
|
+
segments << Segment.new(right_corner, style: @border_style)
|
|
256
|
+
segments
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Truncate a label to a maximum cell width (used when a title/subtitle is
|
|
260
|
+
# wider than the panel).
|
|
261
|
+
def truncate_label(text, max_width)
|
|
262
|
+
return "" if max_width <= 0
|
|
263
|
+
|
|
264
|
+
result = +""
|
|
265
|
+
current_width = 0
|
|
266
|
+
text.to_s.each_char do |char|
|
|
267
|
+
cw = Cells.char_width(char)
|
|
268
|
+
break if current_width + cw > max_width
|
|
269
|
+
|
|
270
|
+
result << char
|
|
271
|
+
current_width += cw
|
|
272
|
+
end
|
|
273
|
+
result
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def render_content_row(content_segments, inner_width)
|
|
277
|
+
segments = []
|
|
278
|
+
|
|
279
|
+
# Left border
|
|
280
|
+
segments << Segment.new(@box.vertical, style: @border_style)
|
|
281
|
+
|
|
282
|
+
# Left padding
|
|
283
|
+
segments << Segment.new(" " * @padding)
|
|
284
|
+
|
|
285
|
+
# Content (cropped so it can never exceed the content area and push the
|
|
286
|
+
# right border out of alignment)
|
|
287
|
+
content_area = [inner_width - @padding * 2, 0].max
|
|
288
|
+
content_width = content_segments.sum(&:cell_length)
|
|
289
|
+
if content_width > content_area
|
|
290
|
+
content_segments = Segment.crop_line(content_segments, content_area)
|
|
291
|
+
content_width = content_segments.sum(&:cell_length)
|
|
292
|
+
end
|
|
293
|
+
segments.concat(content_segments)
|
|
294
|
+
|
|
295
|
+
# Right padding (fill to width)
|
|
296
|
+
remaining = inner_width - @padding * 2 - content_width
|
|
297
|
+
segments << Segment.new(" " * [remaining, 0].max)
|
|
298
|
+
|
|
299
|
+
# Right padding
|
|
300
|
+
segments << Segment.new(" " * @padding)
|
|
301
|
+
|
|
302
|
+
# Right border
|
|
303
|
+
segments << Segment.new(@box.vertical, style: @border_style)
|
|
304
|
+
|
|
305
|
+
segments
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def render_empty_row(inner_width)
|
|
309
|
+
segments = []
|
|
310
|
+
|
|
311
|
+
segments << Segment.new(@box.vertical, style: @border_style)
|
|
312
|
+
segments << Segment.new(" " * inner_width)
|
|
313
|
+
segments << Segment.new(@box.vertical, style: @border_style)
|
|
314
|
+
|
|
315
|
+
segments
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|