ruby_rich 0.4.0 → 0.4.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/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 +32 -25
|
@@ -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.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- zhuang biaowei
|
|
@@ -41,30 +41,22 @@ dependencies:
|
|
|
41
41
|
name: rouge
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
|
-
- - "
|
|
44
|
+
- - ">="
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version:
|
|
47
|
-
|
|
48
|
-
prerelease: false
|
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
-
requirements:
|
|
51
|
-
- - "~>"
|
|
46
|
+
version: '3.14'
|
|
47
|
+
- - "<"
|
|
52
48
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: 4.
|
|
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
|
|
49
|
+
version: '4.0'
|
|
61
50
|
type: :runtime
|
|
62
51
|
prerelease: false
|
|
63
52
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
53
|
requirements:
|
|
65
|
-
- - "
|
|
54
|
+
- - ">="
|
|
66
55
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: 3.
|
|
56
|
+
version: '3.14'
|
|
57
|
+
- - "<"
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '4.0'
|
|
68
60
|
- !ruby/object:Gem::Dependency
|
|
69
61
|
name: tty-cursor
|
|
70
62
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,33 +86,33 @@ dependencies:
|
|
|
94
86
|
- !ruby/object:Gem::Version
|
|
95
87
|
version: 0.8.2
|
|
96
88
|
- !ruby/object:Gem::Dependency
|
|
97
|
-
name:
|
|
89
|
+
name: redcarpet
|
|
98
90
|
requirement: !ruby/object:Gem::Requirement
|
|
99
91
|
requirements:
|
|
100
92
|
- - "~>"
|
|
101
93
|
- !ruby/object:Gem::Version
|
|
102
|
-
version:
|
|
94
|
+
version: 3.6.1
|
|
103
95
|
type: :runtime
|
|
104
96
|
prerelease: false
|
|
105
97
|
version_requirements: !ruby/object:Gem::Requirement
|
|
106
98
|
requirements:
|
|
107
99
|
- - "~>"
|
|
108
100
|
- !ruby/object:Gem::Version
|
|
109
|
-
version:
|
|
101
|
+
version: 3.6.1
|
|
110
102
|
- !ruby/object:Gem::Dependency
|
|
111
|
-
name:
|
|
103
|
+
name: unicode-display_width
|
|
112
104
|
requirement: !ruby/object:Gem::Requirement
|
|
113
105
|
requirements:
|
|
114
106
|
- - "~>"
|
|
115
107
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: 3.
|
|
108
|
+
version: 3.1.4
|
|
117
109
|
type: :runtime
|
|
118
110
|
prerelease: false
|
|
119
111
|
version_requirements: !ruby/object:Gem::Requirement
|
|
120
112
|
requirements:
|
|
121
113
|
- - "~>"
|
|
122
114
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: 3.
|
|
115
|
+
version: 3.1.4
|
|
124
116
|
description: A Ruby gem providing rich text formatting, progress bars, tables and
|
|
125
117
|
other console output enhancements
|
|
126
118
|
email: zbw@kaiyuanshe.org
|
|
@@ -129,22 +121,37 @@ extensions: []
|
|
|
129
121
|
extra_rdoc_files: []
|
|
130
122
|
files:
|
|
131
123
|
- lib/ruby_rich.rb
|
|
124
|
+
- lib/ruby_rich/agent_shell.rb
|
|
132
125
|
- lib/ruby_rich/ansi_code.rb
|
|
126
|
+
- lib/ruby_rich/app_shell.rb
|
|
127
|
+
- lib/ruby_rich/attachment.rb
|
|
133
128
|
- lib/ruby_rich/columns.rb
|
|
129
|
+
- lib/ruby_rich/composer.rb
|
|
134
130
|
- lib/ruby_rich/console.rb
|
|
135
131
|
- lib/ruby_rich/dialog.rb
|
|
132
|
+
- lib/ruby_rich/event.rb
|
|
133
|
+
- lib/ruby_rich/focus_manager.rb
|
|
136
134
|
- lib/ruby_rich/layout.rb
|
|
135
|
+
- lib/ruby_rich/line_editor.rb
|
|
137
136
|
- lib/ruby_rich/live.rb
|
|
138
137
|
- lib/ruby_rich/markdown.rb
|
|
139
138
|
- lib/ruby_rich/panel.rb
|
|
140
139
|
- lib/ruby_rich/print.rb
|
|
141
140
|
- lib/ruby_rich/progress_bar.rb
|
|
141
|
+
- lib/ruby_rich/progress_manager.rb
|
|
142
|
+
- lib/ruby_rich/sidebar.rb
|
|
143
|
+
- lib/ruby_rich/slash_input.rb
|
|
142
144
|
- lib/ruby_rich/status.rb
|
|
143
145
|
- lib/ruby_rich/syntax.rb
|
|
144
146
|
- lib/ruby_rich/table.rb
|
|
147
|
+
- lib/ruby_rich/terminal.rb
|
|
145
148
|
- lib/ruby_rich/text.rb
|
|
149
|
+
- lib/ruby_rich/theme.rb
|
|
150
|
+
- lib/ruby_rich/tool_block.rb
|
|
151
|
+
- lib/ruby_rich/transcript.rb
|
|
146
152
|
- lib/ruby_rich/tree.rb
|
|
147
153
|
- lib/ruby_rich/version.rb
|
|
154
|
+
- lib/ruby_rich/viewport.rb
|
|
148
155
|
homepage: https://github.com/zhuangbiaowei/ruby_rich
|
|
149
156
|
licenses:
|
|
150
157
|
- MIT
|
|
@@ -163,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
163
170
|
- !ruby/object:Gem::Version
|
|
164
171
|
version: '0'
|
|
165
172
|
requirements: []
|
|
166
|
-
rubygems_version:
|
|
173
|
+
rubygems_version: 4.0.10
|
|
167
174
|
specification_version: 4
|
|
168
175
|
summary: Rich text formatting and console output for Ruby
|
|
169
176
|
test_files: []
|