ruby_rich 0.4.0 → 0.4.1
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/lib/ruby_rich/agent_shell.rb +254 -0
- data/lib/ruby_rich/ansi_code.rb +46 -0
- data/lib/ruby_rich/app_shell.rb +374 -0
- data/lib/ruby_rich/attachment.rb +25 -0
- data/lib/ruby_rich/composer.rb +512 -0
- data/lib/ruby_rich/console.rb +174 -25
- data/lib/ruby_rich/dialog.rb +2 -1
- data/lib/ruby_rich/event.rb +29 -0
- data/lib/ruby_rich/focus_manager.rb +77 -0
- data/lib/ruby_rich/layout.rb +117 -29
- data/lib/ruby_rich/line_editor.rb +325 -0
- data/lib/ruby_rich/live.rb +100 -19
- data/lib/ruby_rich/markdown.rb +100 -230
- data/lib/ruby_rich/panel.rb +1 -1
- data/lib/ruby_rich/print.rb +6 -6
- data/lib/ruby_rich/progress_manager.rb +150 -0
- data/lib/ruby_rich/sidebar.rb +85 -0
- data/lib/ruby_rich/slash_input.rb +197 -0
- data/lib/ruby_rich/table.rb +12 -12
- data/lib/ruby_rich/terminal.rb +510 -0
- data/lib/ruby_rich/text.rb +1 -1
- data/lib/ruby_rich/theme.rb +96 -0
- data/lib/ruby_rich/tool_block.rb +92 -0
- data/lib/ruby_rich/transcript.rb +553 -0
- data/lib/ruby_rich/version.rb +1 -1
- data/lib/ruby_rich/viewport.rb +468 -0
- data/lib/ruby_rich.rb +38 -13
- metadata +23 -22
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyRich
|
|
4
|
+
class Viewport
|
|
5
|
+
attr_accessor :width, :height, :scroll_top
|
|
6
|
+
attr_reader :content, :selected_text
|
|
7
|
+
|
|
8
|
+
def initialize(content = "", scrollbar: true, auto_scroll: false, scrollbar_style: :blue)
|
|
9
|
+
@content = content
|
|
10
|
+
@scrollbar = scrollbar
|
|
11
|
+
@auto_scroll = auto_scroll
|
|
12
|
+
@scrollbar_style = scrollbar_style
|
|
13
|
+
@width = 0
|
|
14
|
+
@height = 0
|
|
15
|
+
@scroll_top = 0
|
|
16
|
+
@dragging_scrollbar = false
|
|
17
|
+
@drag_start_y = nil
|
|
18
|
+
@drag_start_scroll_top = nil
|
|
19
|
+
@selecting = false
|
|
20
|
+
@selection_start = nil
|
|
21
|
+
@selection_end = nil
|
|
22
|
+
@selected_text = ""
|
|
23
|
+
@focused = true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def focus
|
|
27
|
+
@focused = true
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def blur
|
|
32
|
+
@focused = false
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def content=(new_content)
|
|
37
|
+
was_at_bottom = at_bottom?
|
|
38
|
+
@content = new_content
|
|
39
|
+
scroll_to_bottom if @auto_scroll && was_at_bottom
|
|
40
|
+
clamp_scroll
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def attach(layout, priority: 100)
|
|
44
|
+
[:page_up, :page_down, :home, :end, :up, :down].each do |event_name|
|
|
45
|
+
layout.key(event_name, priority) do |event_data, _live|
|
|
46
|
+
handle_event(event_data, layout)
|
|
47
|
+
false
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
[:mouse_wheel, :mouse_down, :mouse_drag, :mouse_up].each do |event_name|
|
|
52
|
+
layout.key(event_name, priority) do |event_data, _live|
|
|
53
|
+
handle_event(event_data, layout)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def handle_event(event_data, layout = nil)
|
|
61
|
+
return false if keyboard_event?(event_data) && !@focused
|
|
62
|
+
return false if mouse_event?(event_data) && !@focused
|
|
63
|
+
|
|
64
|
+
case event_data[:name]
|
|
65
|
+
when :page_up
|
|
66
|
+
scroll_by(-page_size)
|
|
67
|
+
false
|
|
68
|
+
when :page_down
|
|
69
|
+
scroll_by(page_size)
|
|
70
|
+
false
|
|
71
|
+
when :home
|
|
72
|
+
scroll_to(0)
|
|
73
|
+
false
|
|
74
|
+
when :end
|
|
75
|
+
scroll_to_bottom
|
|
76
|
+
false
|
|
77
|
+
when :up
|
|
78
|
+
scroll_by(-1)
|
|
79
|
+
false
|
|
80
|
+
when :down
|
|
81
|
+
scroll_by(1)
|
|
82
|
+
false
|
|
83
|
+
when :mouse_wheel
|
|
84
|
+
scroll_by(event_data[:direction] == :down ? 3 : -3)
|
|
85
|
+
true
|
|
86
|
+
when :mouse_down
|
|
87
|
+
return copy_selection if event_data[:button] == :right
|
|
88
|
+
|
|
89
|
+
start_scrollbar_drag(event_data, layout) || start_selection(event_data, layout)
|
|
90
|
+
when :mouse_drag
|
|
91
|
+
drag_scrollbar(event_data, layout) || drag_selection(event_data, layout)
|
|
92
|
+
when :mouse_up
|
|
93
|
+
stop_scrollbar_drag || stop_selection
|
|
94
|
+
else
|
|
95
|
+
false
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def render
|
|
100
|
+
clamp_scroll
|
|
101
|
+
return [] if @height.to_i <= 0 || @width.to_i <= 0
|
|
102
|
+
|
|
103
|
+
visible_width = content_width
|
|
104
|
+
visible = rendered_lines[@scroll_top, @height] || []
|
|
105
|
+
lines = Array.new(@height) { "" }
|
|
106
|
+
|
|
107
|
+
@height.times do |index|
|
|
108
|
+
absolute_line = @scroll_top + index
|
|
109
|
+
lines[index] = apply_selection(fit_line(visible[index].to_s, visible_width), absolute_line)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
return lines unless show_scrollbar?
|
|
113
|
+
|
|
114
|
+
scrollbar = render_scrollbar
|
|
115
|
+
lines.each_with_index.map { |line, index| line + scrollbar[index] }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def scroll_by(delta)
|
|
119
|
+
scroll_to(@scroll_top + delta)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def scroll_to(line)
|
|
123
|
+
@scroll_top = line.to_i
|
|
124
|
+
clamp_scroll
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def scroll_to_bottom
|
|
128
|
+
@scroll_top = max_scroll_top
|
|
129
|
+
clamp_scroll
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def at_bottom?
|
|
133
|
+
@scroll_top >= max_scroll_top
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def max_scroll_top
|
|
137
|
+
[rendered_lines.length - @height, 0].max
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
def rendered_lines
|
|
143
|
+
@rendered_lines = normalize_lines(@content)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def keyboard_event?(event_data)
|
|
147
|
+
event_data[:type] == :key
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def mouse_event?(event_data)
|
|
151
|
+
event_data[:type] == :mouse
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def normalize_lines(value)
|
|
155
|
+
value.width = content_width if value.respond_to?(:width=)
|
|
156
|
+
|
|
157
|
+
rendered = if value.respond_to?(:render)
|
|
158
|
+
value.render
|
|
159
|
+
else
|
|
160
|
+
value
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
case rendered
|
|
164
|
+
when String
|
|
165
|
+
rendered.split("\n")
|
|
166
|
+
when Array
|
|
167
|
+
rendered
|
|
168
|
+
else
|
|
169
|
+
rendered.to_s.split("\n")
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def page_size
|
|
174
|
+
[@height - 1, 1].max
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def content_width
|
|
178
|
+
@scrollbar ? [@width - 1, 1].max : @width
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def show_scrollbar?
|
|
182
|
+
@scrollbar && @width.positive?
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def render_scrollbar
|
|
186
|
+
lines = Array.new(@height) { track_char }
|
|
187
|
+
return lines if @height <= 0
|
|
188
|
+
|
|
189
|
+
thumb_size.times do |offset|
|
|
190
|
+
index = thumb_top + offset
|
|
191
|
+
lines[index] = thumb_char if index.between?(0, @height - 1)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
lines
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def thumb_size
|
|
198
|
+
total = rendered_lines.length
|
|
199
|
+
return @height if total <= @height
|
|
200
|
+
|
|
201
|
+
[(@height.to_f * @height / total).ceil, 1].max
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def thumb_top
|
|
205
|
+
total_scroll = max_scroll_top
|
|
206
|
+
return 0 if total_scroll.zero?
|
|
207
|
+
|
|
208
|
+
travel = [@height - thumb_size, 0].max
|
|
209
|
+
(@scroll_top.to_f / total_scroll * travel).round
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def track_char
|
|
213
|
+
"#{AnsiCode.color(:black, true)}│#{AnsiCode.reset}"
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def thumb_char
|
|
217
|
+
"#{AnsiCode.color(@scrollbar_style, true)}│#{AnsiCode.reset}"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def fit_line(line, target_width)
|
|
221
|
+
plain_width = display_width(line)
|
|
222
|
+
return line + (" " * (target_width - plain_width)) if plain_width <= target_width
|
|
223
|
+
|
|
224
|
+
truncate_display(line, target_width)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def truncate_display(line, target_width)
|
|
228
|
+
result = +""
|
|
229
|
+
width = 0
|
|
230
|
+
in_escape = false
|
|
231
|
+
escape = +""
|
|
232
|
+
|
|
233
|
+
line.each_char do |char|
|
|
234
|
+
if in_escape
|
|
235
|
+
escape << char
|
|
236
|
+
if char == "m"
|
|
237
|
+
result << escape
|
|
238
|
+
escape = +""
|
|
239
|
+
in_escape = false
|
|
240
|
+
end
|
|
241
|
+
next
|
|
242
|
+
elsif char.ord == 27
|
|
243
|
+
escape << char
|
|
244
|
+
in_escape = true
|
|
245
|
+
next
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
char_width = Unicode::DisplayWidth.of(char)
|
|
249
|
+
break if width + char_width > target_width
|
|
250
|
+
|
|
251
|
+
result << char
|
|
252
|
+
width += char_width
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
result
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def display_width(line)
|
|
259
|
+
line.gsub(/\e\[[0-9;:]*m/, "").chars.sum { |char| Unicode::DisplayWidth.of(char) }
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def clamp_scroll
|
|
263
|
+
@scroll_top = [[@scroll_top, 0].max, max_scroll_top].min
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def start_scrollbar_drag(event_data, layout)
|
|
267
|
+
return false unless layout
|
|
268
|
+
return false unless event_data[:x] == layout.x_offset + @width - 1
|
|
269
|
+
|
|
270
|
+
@dragging_scrollbar = true
|
|
271
|
+
@drag_start_y = event_data[:y]
|
|
272
|
+
@drag_start_scroll_top = @scroll_top
|
|
273
|
+
scroll_to(scroll_top_for_y(event_data[:y], layout))
|
|
274
|
+
true
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def start_selection(event_data, layout)
|
|
278
|
+
return false unless layout
|
|
279
|
+
return false if event_data[:x] >= layout.x_offset + content_width
|
|
280
|
+
return false unless event_data[:y].between?(layout.y_offset, layout.y_offset + @height - 1)
|
|
281
|
+
|
|
282
|
+
@selecting = true
|
|
283
|
+
@selection_start = mouse_position(event_data, layout)
|
|
284
|
+
@selection_end = @selection_start
|
|
285
|
+
@selected_text = ""
|
|
286
|
+
true
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def drag_scrollbar(event_data, layout)
|
|
290
|
+
return false unless @dragging_scrollbar && layout
|
|
291
|
+
|
|
292
|
+
if @drag_start_y
|
|
293
|
+
travel = [@height - thumb_size, 1].max
|
|
294
|
+
scroll_travel = max_scroll_top
|
|
295
|
+
delta_y = event_data[:y] - @drag_start_y
|
|
296
|
+
scroll_to(@drag_start_scroll_top + (delta_y.to_f / travel * scroll_travel).round)
|
|
297
|
+
else
|
|
298
|
+
scroll_to(scroll_top_for_y(event_data[:y], layout))
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
true
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def drag_selection(event_data, layout)
|
|
305
|
+
return false unless @selecting && layout
|
|
306
|
+
|
|
307
|
+
@selection_end = mouse_position(event_data, layout)
|
|
308
|
+
true
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def stop_scrollbar_drag
|
|
312
|
+
was_dragging = @dragging_scrollbar
|
|
313
|
+
@dragging_scrollbar = false
|
|
314
|
+
@drag_start_y = nil
|
|
315
|
+
@drag_start_scroll_top = nil
|
|
316
|
+
was_dragging
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def stop_selection
|
|
320
|
+
return false unless @selecting
|
|
321
|
+
|
|
322
|
+
@selecting = false
|
|
323
|
+
@selected_text = extract_selected_text
|
|
324
|
+
copy_selection
|
|
325
|
+
true
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def copy_selection
|
|
329
|
+
return false if @selected_text.to_s.empty?
|
|
330
|
+
|
|
331
|
+
copy_to_clipboard(@selected_text)
|
|
332
|
+
true
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def scroll_top_for_y(y, layout)
|
|
336
|
+
relative_y = [[y - layout.y_offset, 0].max, @height - 1].min
|
|
337
|
+
travel = [@height - thumb_size, 1].max
|
|
338
|
+
(relative_y.to_f / travel * max_scroll_top).round
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def mouse_position(event_data, layout)
|
|
342
|
+
{
|
|
343
|
+
line: @scroll_top + [[event_data[:y] - layout.y_offset, 0].max, @height - 1].min,
|
|
344
|
+
col: [[event_data[:x] - layout.x_offset, 0].max, content_width].min
|
|
345
|
+
}
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def normalized_selection
|
|
349
|
+
return nil unless @selection_start && @selection_end
|
|
350
|
+
|
|
351
|
+
a = @selection_start
|
|
352
|
+
b = @selection_end
|
|
353
|
+
if a[:line] < b[:line] || (a[:line] == b[:line] && a[:col] <= b[:col])
|
|
354
|
+
[a, b]
|
|
355
|
+
else
|
|
356
|
+
[b, a]
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def apply_selection(line, absolute_line)
|
|
361
|
+
range = normalized_selection
|
|
362
|
+
return line unless range
|
|
363
|
+
|
|
364
|
+
start_pos, end_pos = range
|
|
365
|
+
return line if absolute_line < start_pos[:line] || absolute_line > end_pos[:line]
|
|
366
|
+
|
|
367
|
+
start_col = absolute_line == start_pos[:line] ? start_pos[:col] : 0
|
|
368
|
+
end_col = absolute_line == end_pos[:line] ? end_pos[:col] : content_width
|
|
369
|
+
highlight_display_range(line, start_col, end_col)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def highlight_display_range(line, start_col, end_col)
|
|
373
|
+
return line if end_col <= start_col
|
|
374
|
+
|
|
375
|
+
result = +""
|
|
376
|
+
width = 0
|
|
377
|
+
active = false
|
|
378
|
+
in_escape = false
|
|
379
|
+
escape = +""
|
|
380
|
+
|
|
381
|
+
line.each_char do |char|
|
|
382
|
+
if in_escape
|
|
383
|
+
escape << char
|
|
384
|
+
if char == "m"
|
|
385
|
+
result << escape
|
|
386
|
+
escape = +""
|
|
387
|
+
in_escape = false
|
|
388
|
+
end
|
|
389
|
+
next
|
|
390
|
+
elsif char.ord == 27
|
|
391
|
+
escape << char
|
|
392
|
+
in_escape = true
|
|
393
|
+
next
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
char_width = Unicode::DisplayWidth.of(char)
|
|
397
|
+
should_highlight = width < end_col && width + char_width > start_col
|
|
398
|
+
if should_highlight && !active
|
|
399
|
+
result << AnsiCode.inverse
|
|
400
|
+
active = true
|
|
401
|
+
elsif !should_highlight && active
|
|
402
|
+
result << AnsiCode.reset
|
|
403
|
+
active = false
|
|
404
|
+
end
|
|
405
|
+
result << char
|
|
406
|
+
width += char_width
|
|
407
|
+
end
|
|
408
|
+
result << AnsiCode.reset if active
|
|
409
|
+
result
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def extract_selected_text
|
|
413
|
+
range = normalized_selection
|
|
414
|
+
return "" unless range
|
|
415
|
+
|
|
416
|
+
start_pos, end_pos = range
|
|
417
|
+
(start_pos[:line]..end_pos[:line]).map do |line_index|
|
|
418
|
+
line = strip_ansi(rendered_lines[line_index].to_s)
|
|
419
|
+
start_col = line_index == start_pos[:line] ? start_pos[:col] : 0
|
|
420
|
+
end_col = line_index == end_pos[:line] ? end_pos[:col] : display_width(line)
|
|
421
|
+
slice_display_range(line, start_col, end_col).rstrip
|
|
422
|
+
end.join("\n")
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def slice_display_range(line, start_col, end_col)
|
|
426
|
+
result = +""
|
|
427
|
+
width = 0
|
|
428
|
+
line.each_char do |char|
|
|
429
|
+
char_width = Unicode::DisplayWidth.of(char)
|
|
430
|
+
result << char if width < end_col && width + char_width > start_col
|
|
431
|
+
width += char_width
|
|
432
|
+
end
|
|
433
|
+
result
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def strip_ansi(text)
|
|
437
|
+
text.gsub(/\e\[[0-9;:]*m/, "")
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def copy_to_clipboard(text)
|
|
441
|
+
if RubyRich::Terminal.windows?
|
|
442
|
+
copy_to_windows_clipboard(text)
|
|
443
|
+
elsif ENV["WAYLAND_DISPLAY"]
|
|
444
|
+
IO.popen("wl-copy", "w") { |io| io.write(text) }
|
|
445
|
+
elsif ENV["DISPLAY"]
|
|
446
|
+
IO.popen("xclip -selection clipboard", "w") { |io| io.write(text) }
|
|
447
|
+
elsif RUBY_PLATFORM.match?(/darwin/)
|
|
448
|
+
IO.popen("pbcopy", "w") { |io| io.write(text) }
|
|
449
|
+
end
|
|
450
|
+
rescue IOError, SystemCallError
|
|
451
|
+
nil
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def copy_to_windows_clipboard(text)
|
|
455
|
+
script = "[Console]::InputEncoding=[System.Text.UTF8Encoding]::new($false); Set-Clipboard -Value ([Console]::In.ReadToEnd())"
|
|
456
|
+
IO.popen(["powershell", "-NoProfile", "-NonInteractive", "-Command", script], "w") do |io|
|
|
457
|
+
io.set_encoding(Encoding::UTF_8)
|
|
458
|
+
io.write(text.to_s.encode(Encoding::UTF_8))
|
|
459
|
+
end
|
|
460
|
+
rescue IOError, SystemCallError
|
|
461
|
+
IO.popen("clip", "w") do |io|
|
|
462
|
+
io.binmode
|
|
463
|
+
io.write("\uFEFF".encode("UTF-16LE"))
|
|
464
|
+
io.write(text.to_s.encode("UTF-16LE"))
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
end
|
data/lib/ruby_rich.rb
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
# Load all dependency gems
|
|
4
|
+
require 'logger'
|
|
4
5
|
require 'rouge'
|
|
5
6
|
require 'tty-cursor'
|
|
6
7
|
require 'tty-screen'
|
|
7
8
|
require 'redcarpet'
|
|
8
9
|
|
|
9
|
-
#
|
|
10
|
+
# Load all internal modules
|
|
10
11
|
require_relative 'ruby_rich/console'
|
|
12
|
+
require_relative 'ruby_rich/event'
|
|
13
|
+
require_relative 'ruby_rich/terminal'
|
|
11
14
|
require_relative 'ruby_rich/table'
|
|
12
15
|
require_relative 'ruby_rich/progress_bar'
|
|
16
|
+
require_relative 'ruby_rich/progress_manager'
|
|
13
17
|
require_relative 'ruby_rich/layout'
|
|
14
18
|
require_relative 'ruby_rich/live'
|
|
15
19
|
require_relative 'ruby_rich/text'
|
|
@@ -22,49 +26,70 @@ require_relative 'ruby_rich/tree'
|
|
|
22
26
|
require_relative 'ruby_rich/columns'
|
|
23
27
|
require_relative 'ruby_rich/status'
|
|
24
28
|
require_relative 'ruby_rich/ansi_code'
|
|
29
|
+
require_relative 'ruby_rich/theme'
|
|
30
|
+
require_relative 'ruby_rich/slash_input'
|
|
31
|
+
require_relative 'ruby_rich/attachment'
|
|
32
|
+
require_relative 'ruby_rich/line_editor'
|
|
33
|
+
require_relative 'ruby_rich/tool_block'
|
|
34
|
+
require_relative 'ruby_rich/viewport'
|
|
35
|
+
require_relative 'ruby_rich/composer'
|
|
36
|
+
require_relative 'ruby_rich/focus_manager'
|
|
37
|
+
require_relative 'ruby_rich/transcript'
|
|
38
|
+
require_relative 'ruby_rich/sidebar'
|
|
39
|
+
require_relative 'ruby_rich/app_shell'
|
|
40
|
+
require_relative 'ruby_rich/agent_shell'
|
|
25
41
|
require_relative 'ruby_rich/version'
|
|
26
42
|
|
|
27
|
-
#
|
|
43
|
+
# Define main module
|
|
28
44
|
module RubyRich
|
|
29
45
|
class Error < StandardError; end
|
|
30
|
-
|
|
31
|
-
#
|
|
46
|
+
|
|
47
|
+
# Provide a convenient method to create console instance
|
|
32
48
|
def self.console
|
|
33
49
|
@console ||= Console.new
|
|
34
50
|
end
|
|
35
51
|
|
|
36
|
-
#
|
|
52
|
+
# Provide a convenient method to create rich text
|
|
37
53
|
def self.text(content = '')
|
|
38
54
|
RichText.new(content)
|
|
39
55
|
end
|
|
40
56
|
|
|
41
|
-
#
|
|
57
|
+
# Provide a convenient method to create table
|
|
42
58
|
def self.table(border_style: :none)
|
|
43
59
|
Table.new(border_style: border_style)
|
|
44
60
|
end
|
|
45
61
|
|
|
46
|
-
#
|
|
62
|
+
# Provide a convenient method for syntax highlighting
|
|
47
63
|
def self.syntax(code, language = nil, theme: :default)
|
|
48
64
|
Syntax.highlight(code, language, theme: theme)
|
|
49
65
|
end
|
|
50
66
|
|
|
51
|
-
#
|
|
67
|
+
# Provide a convenient method to render Markdown
|
|
52
68
|
def self.markdown(text, options = {})
|
|
53
69
|
Markdown.render(text, options)
|
|
54
70
|
end
|
|
55
71
|
|
|
56
|
-
#
|
|
72
|
+
# Provide a convenient method to create tree structure
|
|
57
73
|
def self.tree(root_name = 'Root', style: :default)
|
|
58
74
|
Tree.new(root_name, style: style)
|
|
59
75
|
end
|
|
60
76
|
|
|
61
|
-
#
|
|
77
|
+
# Provide a convenient method to create multi-column layout
|
|
62
78
|
def self.columns(total_width: 80, gutter_width: 2)
|
|
63
79
|
Columns.new(total_width: total_width, gutter_width: gutter_width)
|
|
64
80
|
end
|
|
65
81
|
|
|
66
|
-
#
|
|
82
|
+
# Provide a convenient method to create status indicator
|
|
67
83
|
def self.status(type, **options)
|
|
68
84
|
Status.indicator(type, **options)
|
|
69
85
|
end
|
|
70
|
-
|
|
86
|
+
|
|
87
|
+
def self.logger=(logger)
|
|
88
|
+
@logger = logger
|
|
89
|
+
end
|
|
90
|
+
def self.logger
|
|
91
|
+
@logger ||= Logger.new($stdout).tap do |log|
|
|
92
|
+
log.progname = "Ruby Rich"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_rich
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- zhuang biaowei
|
|
@@ -51,20 +51,6 @@ dependencies:
|
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
53
|
version: 4.5.2
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: unicode-display_width
|
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - "~>"
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: 3.1.4
|
|
61
|
-
type: :runtime
|
|
62
|
-
prerelease: false
|
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - "~>"
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: 3.1.4
|
|
68
54
|
- !ruby/object:Gem::Dependency
|
|
69
55
|
name: tty-cursor
|
|
70
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,33 +80,33 @@ dependencies:
|
|
|
94
80
|
- !ruby/object:Gem::Version
|
|
95
81
|
version: 0.8.2
|
|
96
82
|
- !ruby/object:Gem::Dependency
|
|
97
|
-
name:
|
|
83
|
+
name: redcarpet
|
|
98
84
|
requirement: !ruby/object:Gem::Requirement
|
|
99
85
|
requirements:
|
|
100
86
|
- - "~>"
|
|
101
87
|
- !ruby/object:Gem::Version
|
|
102
|
-
version:
|
|
88
|
+
version: 3.6.1
|
|
103
89
|
type: :runtime
|
|
104
90
|
prerelease: false
|
|
105
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
106
92
|
requirements:
|
|
107
93
|
- - "~>"
|
|
108
94
|
- !ruby/object:Gem::Version
|
|
109
|
-
version:
|
|
95
|
+
version: 3.6.1
|
|
110
96
|
- !ruby/object:Gem::Dependency
|
|
111
|
-
name:
|
|
97
|
+
name: unicode-display_width
|
|
112
98
|
requirement: !ruby/object:Gem::Requirement
|
|
113
99
|
requirements:
|
|
114
100
|
- - "~>"
|
|
115
101
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: 3.
|
|
102
|
+
version: 3.1.4
|
|
117
103
|
type: :runtime
|
|
118
104
|
prerelease: false
|
|
119
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
120
106
|
requirements:
|
|
121
107
|
- - "~>"
|
|
122
108
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: 3.
|
|
109
|
+
version: 3.1.4
|
|
124
110
|
description: A Ruby gem providing rich text formatting, progress bars, tables and
|
|
125
111
|
other console output enhancements
|
|
126
112
|
email: zbw@kaiyuanshe.org
|
|
@@ -129,22 +115,37 @@ extensions: []
|
|
|
129
115
|
extra_rdoc_files: []
|
|
130
116
|
files:
|
|
131
117
|
- lib/ruby_rich.rb
|
|
118
|
+
- lib/ruby_rich/agent_shell.rb
|
|
132
119
|
- lib/ruby_rich/ansi_code.rb
|
|
120
|
+
- lib/ruby_rich/app_shell.rb
|
|
121
|
+
- lib/ruby_rich/attachment.rb
|
|
133
122
|
- lib/ruby_rich/columns.rb
|
|
123
|
+
- lib/ruby_rich/composer.rb
|
|
134
124
|
- lib/ruby_rich/console.rb
|
|
135
125
|
- lib/ruby_rich/dialog.rb
|
|
126
|
+
- lib/ruby_rich/event.rb
|
|
127
|
+
- lib/ruby_rich/focus_manager.rb
|
|
136
128
|
- lib/ruby_rich/layout.rb
|
|
129
|
+
- lib/ruby_rich/line_editor.rb
|
|
137
130
|
- lib/ruby_rich/live.rb
|
|
138
131
|
- lib/ruby_rich/markdown.rb
|
|
139
132
|
- lib/ruby_rich/panel.rb
|
|
140
133
|
- lib/ruby_rich/print.rb
|
|
141
134
|
- lib/ruby_rich/progress_bar.rb
|
|
135
|
+
- lib/ruby_rich/progress_manager.rb
|
|
136
|
+
- lib/ruby_rich/sidebar.rb
|
|
137
|
+
- lib/ruby_rich/slash_input.rb
|
|
142
138
|
- lib/ruby_rich/status.rb
|
|
143
139
|
- lib/ruby_rich/syntax.rb
|
|
144
140
|
- lib/ruby_rich/table.rb
|
|
141
|
+
- lib/ruby_rich/terminal.rb
|
|
145
142
|
- lib/ruby_rich/text.rb
|
|
143
|
+
- lib/ruby_rich/theme.rb
|
|
144
|
+
- lib/ruby_rich/tool_block.rb
|
|
145
|
+
- lib/ruby_rich/transcript.rb
|
|
146
146
|
- lib/ruby_rich/tree.rb
|
|
147
147
|
- lib/ruby_rich/version.rb
|
|
148
|
+
- lib/ruby_rich/viewport.rb
|
|
148
149
|
homepage: https://github.com/zhuangbiaowei/ruby_rich
|
|
149
150
|
licenses:
|
|
150
151
|
- MIT
|
|
@@ -163,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
163
164
|
- !ruby/object:Gem::Version
|
|
164
165
|
version: '0'
|
|
165
166
|
requirements: []
|
|
166
|
-
rubygems_version:
|
|
167
|
+
rubygems_version: 4.0.10
|
|
167
168
|
specification_version: 4
|
|
168
169
|
summary: Rich text formatting and console output for Ruby
|
|
169
170
|
test_files: []
|