rich-ruby 1.0.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +546 -0
- data/examples/demo.rb +106 -0
- data/examples/showcase.rb +420 -0
- data/examples/smoke_test.rb +41 -0
- data/examples/stress_test.rb +604 -0
- data/examples/syntax_markdown_demo.rb +166 -0
- data/examples/verify.rb +215 -0
- data/examples/visual_demo.rb +145 -0
- data/lib/rich/_palettes.rb +148 -0
- data/lib/rich/box.rb +342 -0
- data/lib/rich/cells.rb +512 -0
- data/lib/rich/color.rb +628 -0
- data/lib/rich/color_triplet.rb +220 -0
- data/lib/rich/console.rb +549 -0
- data/lib/rich/control.rb +332 -0
- data/lib/rich/json.rb +254 -0
- data/lib/rich/layout.rb +314 -0
- data/lib/rich/markdown.rb +509 -0
- data/lib/rich/markup.rb +175 -0
- data/lib/rich/panel.rb +311 -0
- data/lib/rich/progress.rb +430 -0
- data/lib/rich/segment.rb +387 -0
- data/lib/rich/style.rb +433 -0
- data/lib/rich/syntax.rb +1145 -0
- data/lib/rich/table.rb +525 -0
- data/lib/rich/terminal_theme.rb +126 -0
- data/lib/rich/text.rb +433 -0
- data/lib/rich/tree.rb +220 -0
- data/lib/rich/version.rb +5 -0
- data/lib/rich/win32_console.rb +582 -0
- data/lib/rich.rb +108 -0
- metadata +106 -0
data/lib/rich/box.rb
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rich
|
|
4
|
+
# Box drawing character sets for borders and tables
|
|
5
|
+
class Box
|
|
6
|
+
# @return [String] Top-left corner
|
|
7
|
+
attr_reader :top_left
|
|
8
|
+
|
|
9
|
+
# @return [String] Top-right corner
|
|
10
|
+
attr_reader :top_right
|
|
11
|
+
|
|
12
|
+
# @return [String] Bottom-left corner
|
|
13
|
+
attr_reader :bottom_left
|
|
14
|
+
|
|
15
|
+
# @return [String] Bottom-right corner
|
|
16
|
+
attr_reader :bottom_right
|
|
17
|
+
|
|
18
|
+
# @return [String] Horizontal line
|
|
19
|
+
attr_reader :horizontal
|
|
20
|
+
|
|
21
|
+
# @return [String] Vertical line
|
|
22
|
+
attr_reader :vertical
|
|
23
|
+
|
|
24
|
+
# @return [String] Left T-junction
|
|
25
|
+
attr_reader :left_t
|
|
26
|
+
|
|
27
|
+
# @return [String] Right T-junction
|
|
28
|
+
attr_reader :right_t
|
|
29
|
+
|
|
30
|
+
# @return [String] Top T-junction
|
|
31
|
+
attr_reader :top_t
|
|
32
|
+
|
|
33
|
+
# @return [String] Bottom T-junction
|
|
34
|
+
attr_reader :bottom_t
|
|
35
|
+
|
|
36
|
+
# @return [String] Cross/plus junction
|
|
37
|
+
attr_reader :cross
|
|
38
|
+
|
|
39
|
+
# @return [String] Thick horizontal (for headers)
|
|
40
|
+
attr_reader :thick_horizontal
|
|
41
|
+
|
|
42
|
+
# @return [String] Thick left T-junction
|
|
43
|
+
attr_reader :thick_left_t
|
|
44
|
+
|
|
45
|
+
# @return [String] Thick right T-junction
|
|
46
|
+
attr_reader :thick_right_t
|
|
47
|
+
|
|
48
|
+
# @return [String] Thick cross
|
|
49
|
+
attr_reader :thick_cross
|
|
50
|
+
|
|
51
|
+
def initialize(
|
|
52
|
+
top_left:,
|
|
53
|
+
top_right:,
|
|
54
|
+
bottom_left:,
|
|
55
|
+
bottom_right:,
|
|
56
|
+
horizontal:,
|
|
57
|
+
vertical:,
|
|
58
|
+
left_t: nil,
|
|
59
|
+
right_t: nil,
|
|
60
|
+
top_t: nil,
|
|
61
|
+
bottom_t: nil,
|
|
62
|
+
cross: nil,
|
|
63
|
+
thick_horizontal: nil,
|
|
64
|
+
thick_left_t: nil,
|
|
65
|
+
thick_right_t: nil,
|
|
66
|
+
thick_cross: nil
|
|
67
|
+
)
|
|
68
|
+
@top_left = top_left
|
|
69
|
+
@top_right = top_right
|
|
70
|
+
@bottom_left = bottom_left
|
|
71
|
+
@bottom_right = bottom_right
|
|
72
|
+
@horizontal = horizontal
|
|
73
|
+
@vertical = vertical
|
|
74
|
+
@left_t = left_t || vertical
|
|
75
|
+
@right_t = right_t || vertical
|
|
76
|
+
@top_t = top_t || horizontal
|
|
77
|
+
@bottom_t = bottom_t || horizontal
|
|
78
|
+
@cross = cross || "+"
|
|
79
|
+
@thick_horizontal = thick_horizontal || horizontal
|
|
80
|
+
@thick_left_t = thick_left_t || @left_t
|
|
81
|
+
@thick_right_t = thick_right_t || @right_t
|
|
82
|
+
@thick_cross = thick_cross || @cross
|
|
83
|
+
freeze
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Get the top edge
|
|
87
|
+
# @param width [Integer] Width of content
|
|
88
|
+
# @return [String]
|
|
89
|
+
def top_edge(width)
|
|
90
|
+
"#{@top_left}#{@horizontal * [0, width - 2].max}#{@top_right}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Get the bottom edge
|
|
94
|
+
# @param width [Integer] Width of content
|
|
95
|
+
# @return [String]
|
|
96
|
+
def bottom_edge(width)
|
|
97
|
+
"#{@bottom_left}#{@horizontal * [0, width - 2].max}#{@bottom_right}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Get the row separator
|
|
101
|
+
# @param width_or_cells [Integer, Array] Total width or array of cell contents
|
|
102
|
+
# @param widths [Array<Integer>, nil] Array of column widths
|
|
103
|
+
# @return [String]
|
|
104
|
+
def row(width_or_cells, widths = nil)
|
|
105
|
+
if widths
|
|
106
|
+
# Table row separator with multiple columns
|
|
107
|
+
parts = widths.map { |w| @horizontal * w }
|
|
108
|
+
"#{@left_t}#{parts.join(@cross)}#{@right_t}"
|
|
109
|
+
else
|
|
110
|
+
# Single column separator
|
|
111
|
+
width = width_or_cells.is_a?(Integer) ? width_or_cells : Cells.cell_len(width_or_cells.to_s)
|
|
112
|
+
"#{@left_t}#{@horizontal * [0, width - 2].max}#{@right_t}"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
alias top top_edge
|
|
117
|
+
alias bottom bottom_edge
|
|
118
|
+
|
|
119
|
+
# Get a content row
|
|
120
|
+
# @param content [String] Content
|
|
121
|
+
# @param width [Integer] Width to pad to
|
|
122
|
+
# @param align [Symbol] Alignment (:left, :center, :right)
|
|
123
|
+
# @return [String]
|
|
124
|
+
def content_row(content, width, align: :left)
|
|
125
|
+
content_len = Cells.cell_len(content)
|
|
126
|
+
padding = width - content_len
|
|
127
|
+
|
|
128
|
+
case align
|
|
129
|
+
when :center
|
|
130
|
+
left_pad = padding / 2
|
|
131
|
+
right_pad = padding - left_pad
|
|
132
|
+
"#{@vertical}#{' ' * left_pad}#{content}#{' ' * right_pad}#{@vertical}"
|
|
133
|
+
when :right
|
|
134
|
+
"#{@vertical}#{' ' * padding}#{content}#{@vertical}"
|
|
135
|
+
else # :left
|
|
136
|
+
"#{@vertical}#{content}#{' ' * padding}#{@vertical}"
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Get header separator (thicker line)
|
|
141
|
+
# @param width [Integer] Width
|
|
142
|
+
# @return [String]
|
|
143
|
+
def header_separator(width)
|
|
144
|
+
"#{@thick_left_t}#{@thick_horizontal * width}#{@thick_right_t}"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Substitute ASCII characters for box characters
|
|
148
|
+
# @return [Box]
|
|
149
|
+
def to_ascii
|
|
150
|
+
ASCII
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Check if this is the ASCII box
|
|
154
|
+
# @return [Boolean]
|
|
155
|
+
def ascii?
|
|
156
|
+
self == ASCII
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Predefined box styles
|
|
160
|
+
class << self
|
|
161
|
+
# ASCII characters only
|
|
162
|
+
def ascii
|
|
163
|
+
ASCII
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Standard Unicode box drawing
|
|
167
|
+
def square
|
|
168
|
+
SQUARE
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Rounded corners
|
|
172
|
+
def rounded
|
|
173
|
+
ROUNDED
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Heavy/thick lines
|
|
177
|
+
def heavy
|
|
178
|
+
HEAVY
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Double lines
|
|
182
|
+
def double
|
|
183
|
+
DOUBLE
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Minimal (no corners)
|
|
187
|
+
def minimal
|
|
188
|
+
MINIMAL
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Simple horizontal lines only
|
|
192
|
+
def simple
|
|
193
|
+
SIMPLE
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# No border
|
|
197
|
+
def none
|
|
198
|
+
NONE
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# ASCII box (works everywhere)
|
|
203
|
+
ASCII = new(
|
|
204
|
+
top_left: "+",
|
|
205
|
+
top_right: "+",
|
|
206
|
+
bottom_left: "+",
|
|
207
|
+
bottom_right: "+",
|
|
208
|
+
horizontal: "-",
|
|
209
|
+
vertical: "|",
|
|
210
|
+
left_t: "+",
|
|
211
|
+
right_t: "+",
|
|
212
|
+
top_t: "+",
|
|
213
|
+
bottom_t: "+",
|
|
214
|
+
cross: "+",
|
|
215
|
+
thick_horizontal: "=",
|
|
216
|
+
thick_left_t: "+",
|
|
217
|
+
thick_right_t: "+",
|
|
218
|
+
thick_cross: "+"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Standard Unicode box
|
|
222
|
+
SQUARE = new(
|
|
223
|
+
top_left: "┌",
|
|
224
|
+
top_right: "┐",
|
|
225
|
+
bottom_left: "└",
|
|
226
|
+
bottom_right: "┘",
|
|
227
|
+
horizontal: "─",
|
|
228
|
+
vertical: "│",
|
|
229
|
+
left_t: "├",
|
|
230
|
+
right_t: "┤",
|
|
231
|
+
top_t: "┬",
|
|
232
|
+
bottom_t: "┴",
|
|
233
|
+
cross: "┼",
|
|
234
|
+
thick_horizontal: "━",
|
|
235
|
+
thick_left_t: "┝",
|
|
236
|
+
thick_right_t: "┥",
|
|
237
|
+
thick_cross: "┿"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# Rounded corners
|
|
241
|
+
ROUNDED = new(
|
|
242
|
+
top_left: "╭",
|
|
243
|
+
top_right: "╮",
|
|
244
|
+
bottom_left: "╰",
|
|
245
|
+
bottom_right: "╯",
|
|
246
|
+
horizontal: "─",
|
|
247
|
+
vertical: "│",
|
|
248
|
+
left_t: "├",
|
|
249
|
+
right_t: "┤",
|
|
250
|
+
top_t: "┬",
|
|
251
|
+
bottom_t: "┴",
|
|
252
|
+
cross: "┼",
|
|
253
|
+
thick_horizontal: "━",
|
|
254
|
+
thick_left_t: "┝",
|
|
255
|
+
thick_right_t: "┥",
|
|
256
|
+
thick_cross: "┿"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# Heavy/thick box
|
|
260
|
+
HEAVY = new(
|
|
261
|
+
top_left: "┏",
|
|
262
|
+
top_right: "┓",
|
|
263
|
+
bottom_left: "┗",
|
|
264
|
+
bottom_right: "┛",
|
|
265
|
+
horizontal: "━",
|
|
266
|
+
vertical: "┃",
|
|
267
|
+
left_t: "┣",
|
|
268
|
+
right_t: "┫",
|
|
269
|
+
top_t: "┳",
|
|
270
|
+
bottom_t: "┻",
|
|
271
|
+
cross: "╋",
|
|
272
|
+
thick_horizontal: "━",
|
|
273
|
+
thick_left_t: "┣",
|
|
274
|
+
thick_right_t: "┫",
|
|
275
|
+
thick_cross: "╋"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# Double line box
|
|
279
|
+
DOUBLE = new(
|
|
280
|
+
top_left: "╔",
|
|
281
|
+
top_right: "╗",
|
|
282
|
+
bottom_left: "╚",
|
|
283
|
+
bottom_right: "╝",
|
|
284
|
+
horizontal: "═",
|
|
285
|
+
vertical: "║",
|
|
286
|
+
left_t: "╠",
|
|
287
|
+
right_t: "╣",
|
|
288
|
+
top_t: "╦",
|
|
289
|
+
bottom_t: "╩",
|
|
290
|
+
cross: "╬",
|
|
291
|
+
thick_horizontal: "═",
|
|
292
|
+
thick_left_t: "╠",
|
|
293
|
+
thick_right_t: "╣",
|
|
294
|
+
thick_cross: "╬"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# Minimal (dashes, no corners)
|
|
298
|
+
MINIMAL = new(
|
|
299
|
+
top_left: " ",
|
|
300
|
+
top_right: " ",
|
|
301
|
+
bottom_left: " ",
|
|
302
|
+
bottom_right: " ",
|
|
303
|
+
horizontal: "─",
|
|
304
|
+
vertical: " ",
|
|
305
|
+
left_t: " ",
|
|
306
|
+
right_t: " ",
|
|
307
|
+
top_t: "─",
|
|
308
|
+
bottom_t: "─",
|
|
309
|
+
cross: "─"
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
# Simple (just horizontal lines)
|
|
313
|
+
SIMPLE = new(
|
|
314
|
+
top_left: "",
|
|
315
|
+
top_right: "",
|
|
316
|
+
bottom_left: "",
|
|
317
|
+
bottom_right: "",
|
|
318
|
+
horizontal: "─",
|
|
319
|
+
vertical: "",
|
|
320
|
+
left_t: "",
|
|
321
|
+
right_t: "",
|
|
322
|
+
top_t: "",
|
|
323
|
+
bottom_t: "",
|
|
324
|
+
cross: ""
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# No border at all
|
|
328
|
+
NONE = new(
|
|
329
|
+
top_left: "",
|
|
330
|
+
top_right: "",
|
|
331
|
+
bottom_left: "",
|
|
332
|
+
bottom_right: "",
|
|
333
|
+
horizontal: "",
|
|
334
|
+
vertical: "",
|
|
335
|
+
left_t: "",
|
|
336
|
+
right_t: "",
|
|
337
|
+
top_t: "",
|
|
338
|
+
bottom_t: "",
|
|
339
|
+
cross: ""
|
|
340
|
+
)
|
|
341
|
+
end
|
|
342
|
+
end
|