rubytui 1.2.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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +574 -0
  4. data/lib/rubytui/app.rb +174 -0
  5. data/lib/rubytui/backend.rb +158 -0
  6. data/lib/rubytui/backends/ansi_backend.rb +391 -0
  7. data/lib/rubytui/backends/test_backend.rb +223 -0
  8. data/lib/rubytui/buffer.rb +400 -0
  9. data/lib/rubytui/cell.rb +55 -0
  10. data/lib/rubytui/color.rb +153 -0
  11. data/lib/rubytui/color_mode.rb +203 -0
  12. data/lib/rubytui/errors.rb +13 -0
  13. data/lib/rubytui/event.rb +161 -0
  14. data/lib/rubytui/frame.rb +70 -0
  15. data/lib/rubytui/input/key.rb +93 -0
  16. data/lib/rubytui/input/parser.rb +231 -0
  17. data/lib/rubytui/input/reader.rb +119 -0
  18. data/lib/rubytui/layout/constraint.rb +83 -0
  19. data/lib/rubytui/layout/flex.rb +16 -0
  20. data/lib/rubytui/layout/layout.rb +205 -0
  21. data/lib/rubytui/modifier.rb +67 -0
  22. data/lib/rubytui/rect.rb +126 -0
  23. data/lib/rubytui/stateful_widget.rb +20 -0
  24. data/lib/rubytui/style.rb +143 -0
  25. data/lib/rubytui/symbols.rb +88 -0
  26. data/lib/rubytui/terminal.rb +218 -0
  27. data/lib/rubytui/text/line.rb +67 -0
  28. data/lib/rubytui/text/span.rb +34 -0
  29. data/lib/rubytui/text/text.rb +82 -0
  30. data/lib/rubytui/unicode.rb +162 -0
  31. data/lib/rubytui/version.rb +6 -0
  32. data/lib/rubytui/widget.rb +20 -0
  33. data/lib/rubytui/widgets/async_image.rb +248 -0
  34. data/lib/rubytui/widgets/block.rb +260 -0
  35. data/lib/rubytui/widgets/canvas.rb +248 -0
  36. data/lib/rubytui/widgets/chart.rb +224 -0
  37. data/lib/rubytui/widgets/gauge.rb +139 -0
  38. data/lib/rubytui/widgets/image.rb +330 -0
  39. data/lib/rubytui/widgets/input_field.rb +245 -0
  40. data/lib/rubytui/widgets/list.rb +186 -0
  41. data/lib/rubytui/widgets/paragraph.rb +181 -0
  42. data/lib/rubytui/widgets/popup.rb +140 -0
  43. data/lib/rubytui/widgets/scrollbar.rb +175 -0
  44. data/lib/rubytui/widgets/sparkline.rb +86 -0
  45. data/lib/rubytui/widgets/table.rb +231 -0
  46. data/lib/rubytui/widgets/tabs.rb +90 -0
  47. data/lib/rubytui.rb +389 -0
  48. metadata +89 -0
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyTUI
4
+ module Widgets
5
+ # Tabs renders a horizontal tab bar with selectable tabs.
6
+ #
7
+ # @example
8
+ # tabs = RubyTUI::Widgets::Tabs.new(titles: ["Home", "Logs", "Help"], selected: 1)
9
+ # frame.render_widget(tabs, area)
10
+ class Tabs
11
+ include Widget
12
+
13
+ # @param titles [Array<#to_s>] tab titles (default: [])
14
+ # @param selected [Integer] index of the active tab (default: 0)
15
+ # @param style [Style] base style, patched with +active_style+ or +inactive_style+
16
+ # (default: {Style::DEFAULT})
17
+ # @param active_style [Style, nil] style of the active tab (default: bold yellow foreground)
18
+ # @param inactive_style [Style, nil] style of inactive tabs and dividers
19
+ # (default: bright black foreground)
20
+ # @param divider [String] separator drawn between tabs (default: <tt>" │ "</tt>)
21
+ # @param highlight_style [Style, nil] currently unused by rendering (default: nil)
22
+ # @param block [Widgets::Block, nil] optional wrapping block
23
+ def initialize(
24
+ titles: [],
25
+ selected: 0,
26
+ style: Style::DEFAULT,
27
+ active_style: nil,
28
+ inactive_style: nil,
29
+ divider: " \u2502 ",
30
+ highlight_style: nil,
31
+ block: nil
32
+ )
33
+ @titles = titles
34
+ @selected = selected
35
+ @style = style
36
+ @active_style = active_style || Style.new.fg(Color::YELLOW).bold
37
+ @inactive_style = inactive_style || Style.new.fg(Color::BRIGHT_BLACK)
38
+ @divider = divider
39
+ @highlight_style = highlight_style
40
+ @block = block
41
+ end
42
+
43
+ # Draw the titles left to right on the first row of the area, separated by
44
+ # +divider+ and truncated at the right edge.
45
+ #
46
+ # @param area [Rect] the rectangular area to render into
47
+ # @param buf [Buffer] the buffer to write cells into
48
+ # @return [void]
49
+ def render(area, buf)
50
+ return if area.empty?
51
+
52
+ render_area = area
53
+ if @block
54
+ @block.render(area, buf)
55
+ render_area = @block.inner(area)
56
+ end
57
+
58
+ return if render_area.empty? || @titles.empty?
59
+
60
+ x = render_area.x
61
+ y = render_area.y
62
+
63
+ @titles.each_with_index do |title, i|
64
+ break if x >= render_area.right
65
+
66
+ is_active = i == @selected
67
+ tab_style = is_active ? @style.patch(@active_style) : @style.patch(@inactive_style)
68
+
69
+ # Render tab title
70
+ display = title.to_s
71
+ available = render_area.right - x
72
+ display = Buffer.truncate_to_width(display, available)
73
+ display_width = Buffer.string_width(display)
74
+
75
+ buf.set_string(x, y, display, tab_style)
76
+ x += display_width
77
+
78
+ # Render divider (except after last tab)
79
+ if i < @titles.length - 1
80
+ available = render_area.right - x
81
+ divider_text = Buffer.truncate_to_width(@divider, available)
82
+ divider_width = Buffer.string_width(divider_text)
83
+ buf.set_string(x, y, divider_text, @style.patch(@inactive_style))
84
+ x += divider_width
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
data/lib/rubytui.rb ADDED
@@ -0,0 +1,389 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Core primitives
4
+ require_relative "rubytui/version"
5
+ require_relative "rubytui/errors"
6
+ require_relative "rubytui/modifier"
7
+ require_relative "rubytui/color"
8
+ require_relative "rubytui/color_mode"
9
+ require_relative "rubytui/rect"
10
+ require_relative "rubytui/style"
11
+ require_relative "rubytui/cell"
12
+ require_relative "rubytui/unicode"
13
+ require_relative "rubytui/buffer"
14
+ require_relative "rubytui/symbols"
15
+
16
+ # Layout
17
+ require_relative "rubytui/layout/flex"
18
+ require_relative "rubytui/layout/constraint"
19
+ require_relative "rubytui/layout/layout"
20
+
21
+ # Widget protocol
22
+ require_relative "rubytui/widget"
23
+ require_relative "rubytui/stateful_widget"
24
+
25
+ # Backend
26
+ require_relative "rubytui/backend"
27
+ require_relative "rubytui/backends/test_backend"
28
+ require_relative "rubytui/backends/ansi_backend"
29
+
30
+ # Rendering pipeline
31
+ require_relative "rubytui/frame"
32
+ require_relative "rubytui/terminal"
33
+
34
+ # Text primitives
35
+ require_relative "rubytui/text/span"
36
+ require_relative "rubytui/text/line"
37
+ require_relative "rubytui/text/text"
38
+
39
+ # Widgets
40
+ require_relative "rubytui/widgets/block"
41
+ require_relative "rubytui/widgets/paragraph"
42
+ require_relative "rubytui/widgets/list"
43
+ require_relative "rubytui/widgets/table"
44
+ require_relative "rubytui/widgets/gauge"
45
+ require_relative "rubytui/widgets/sparkline"
46
+ require_relative "rubytui/widgets/scrollbar"
47
+ require_relative "rubytui/widgets/tabs"
48
+ require_relative "rubytui/widgets/canvas"
49
+ require_relative "rubytui/widgets/popup"
50
+ require_relative "rubytui/widgets/input_field"
51
+ require_relative "rubytui/widgets/chart"
52
+ require_relative "rubytui/widgets/image"
53
+ require_relative "rubytui/widgets/async_image"
54
+
55
+ # Input
56
+ require_relative "rubytui/input/key"
57
+ require_relative "rubytui/event"
58
+ require_relative "rubytui/input/parser"
59
+ require_relative "rubytui/input/reader"
60
+
61
+ # App framework
62
+ require_relative "rubytui/app"
63
+
64
+ # A pure Ruby terminal user interface library.
65
+ #
66
+ # RubyTUI provides immediate-mode rendering with double buffering,
67
+ # constraint-based layouts, and a duck-typed widget protocol.
68
+ #
69
+ # @example Interactive TUI application
70
+ # RubyTUI.run do |terminal, reader|
71
+ # loop do
72
+ # terminal.draw do |frame|
73
+ # frame.buffer.set_string(0, 0, "Hello!", Style.new.fg(Color::GREEN))
74
+ # end
75
+ # event = reader.poll(timeout_ms: 50)
76
+ # break if event.is_a?(RubyTUI::KeyEvent) && event.char == 'q'
77
+ # end
78
+ # end
79
+ #
80
+ # @example One-shot styled output (no event loop)
81
+ # RubyTUI.render_once(width: 80) do |frame|
82
+ # block = RubyTUI::Widgets::Block.new(title: " Info ", borders: :all)
83
+ # frame.render_widget(block, frame.area)
84
+ # end
85
+ #
86
+ # @example Quick table print
87
+ # RubyTUI.print_table(
88
+ # header: ["Name", "Value"],
89
+ # rows: [["Alice", "100"], ["Bob", "200"]],
90
+ # title: " Data "
91
+ # )
92
+ module RubyTUI
93
+ # Convenience alias for {Layout::Constraint}
94
+ Constraint = Layout::Constraint
95
+
96
+ class << self
97
+ # Initialize a terminal with ANSI backend.
98
+ #
99
+ # Enables raw mode, hides the cursor, and optionally enters alternate screen.
100
+ # Use {.restore} to undo these changes, or prefer {.run} for automatic cleanup.
101
+ #
102
+ # @param output [IO] output stream (default: $stdout)
103
+ # @param input [IO] input stream (default: $stdin)
104
+ # @param mouse [Boolean] enable mouse event reporting (default: false)
105
+ # @param alternate_screen [Boolean] enter alternate screen buffer (default: true)
106
+ # @return [Array(Terminal, Input::Reader)] terminal and reader pair
107
+ # @see .run
108
+ # @see .restore
109
+ def init(output: $stdout, input: $stdin, mouse: false, alternate_screen: true)
110
+ backend = AnsiBackend.new(output: output, input: input)
111
+ terminal = Terminal.new(backend: backend)
112
+ reader = Input::Reader.new(input: input)
113
+
114
+ backend.enable_raw_mode
115
+ backend.hide_cursor
116
+ terminal.enter_alternate_screen if alternate_screen
117
+ backend.enable_mouse if mouse
118
+ backend.flush
119
+
120
+ [terminal, reader]
121
+ end
122
+
123
+ # Restore terminal to normal state.
124
+ #
125
+ # Disables mouse, shows cursor, leaves alternate screen, and disables raw mode.
126
+ #
127
+ # @param terminal [Terminal] the terminal to restore
128
+ # @param alternate_screen [Boolean] whether alternate screen was used (must match {.init})
129
+ # (default: true)
130
+ # @return [void]
131
+ def restore(terminal, alternate_screen: true)
132
+ terminal.backend.disable_mouse
133
+ terminal.backend.show_cursor
134
+ terminal.leave_alternate_screen if alternate_screen
135
+ terminal.backend.disable_raw_mode
136
+ terminal.backend.flush
137
+ end
138
+
139
+ # Run a TUI application with automatic setup and teardown.
140
+ #
141
+ # Sets up the terminal (raw mode, hidden cursor, alternate screen) and
142
+ # yields a terminal and reader. Restores the terminal when the block exits.
143
+ #
144
+ # @param output [IO] output stream (default: $stdout)
145
+ # @param input [IO] input stream (default: $stdin)
146
+ # @param mouse [Boolean] enable mouse event reporting (default: false)
147
+ # @param alternate_screen [Boolean] use alternate screen buffer (default: true).
148
+ # Set to +false+ to keep output in terminal scrollback after exit.
149
+ # @yield [terminal, reader] the initialized terminal and input reader
150
+ # @yieldparam terminal [Terminal]
151
+ # @yieldparam reader [Input::Reader]
152
+ # @return [void]
153
+ #
154
+ # @example Basic interactive app
155
+ # RubyTUI.run do |terminal, reader|
156
+ # loop do
157
+ # terminal.draw { |frame| frame.buffer.set_string(0, 0, "Hi!") }
158
+ # event = reader.poll(timeout_ms: 50)
159
+ # break if event.is_a?(RubyTUI::KeyEvent) && event.char == 'q'
160
+ # end
161
+ # end
162
+ #
163
+ # @example Non-alternate-screen mode (output persists after exit)
164
+ # RubyTUI.run(alternate_screen: false) do |terminal, reader|
165
+ # terminal.draw { |frame| frame.buffer.set_string(0, 0, "Stays visible") }
166
+ # end
167
+ def run(output: $stdout, input: $stdin, mouse: false, alternate_screen: true)
168
+ terminal, reader = init(output: output, input: input, mouse: mouse,
169
+ alternate_screen: alternate_screen)
170
+ yield terminal, reader
171
+ ensure
172
+ restore(terminal, alternate_screen: alternate_screen) if terminal
173
+ end
174
+
175
+ # Render widgets once and print to stdout.
176
+ #
177
+ # No event loop, no alternate screen, no raw mode. Output stays in
178
+ # terminal scrollback. Ideal for CLI tools that want styled output
179
+ # using the widget/layout system without a full TUI.
180
+ #
181
+ # @param width [Integer, nil] output width in columns (default: auto-detect)
182
+ # @param height [Integer, nil] output height in rows (default: auto-detect)
183
+ # @param output [IO] output stream (default: $stdout)
184
+ # @yield [frame] a Frame to render widgets into
185
+ # @yieldparam frame [Frame]
186
+ # @return [Frame] the rendered frame
187
+ #
188
+ # @example Render a block widget
189
+ # RubyTUI.render_once(width: 60, height: 10) do |frame|
190
+ # block = RubyTUI::Widgets::Block.new(title: " Info ", borders: :all)
191
+ # frame.render_widget(block, frame.area)
192
+ # end
193
+ def render_once(width: nil, height: nil, output: $stdout)
194
+ w = width || terminal_width(output)
195
+ h = height || terminal_height(output)
196
+ area = Rect.new(0, 0, w, h)
197
+ buf = Buffer.new(area)
198
+ frame = Frame.new(buf, area)
199
+ yield frame
200
+ output.write(buf.to_ansi)
201
+ output.write("\n")
202
+ frame
203
+ end
204
+
205
+ # Print a styled table to stdout. No event loop needed.
206
+ #
207
+ # Renders a {Widgets::Table} with optional header, borders, and title,
208
+ # then prints the ANSI output directly. Auto-calculates the required height.
209
+ #
210
+ # @param header [Array<String>, nil] column header labels
211
+ # @param rows [Array<Array<String>>] table data rows
212
+ # @param widths [Array<Integer>] column widths (auto-calculated if empty)
213
+ # @param title [String, nil] box title rendered on the top border
214
+ # @param border [Symbol, Symbols::BorderSet] border style — +:rounded+, +:double+,
215
+ # +:thick+, +:light+, +:plain+, or a {Symbols::BorderSet} (default: +:rounded+)
216
+ # @param border_style [Style] style for the border characters (default: {Style::DEFAULT})
217
+ # @param header_style [Style, nil] style for header row (default: cyan bold)
218
+ # @param style [Style] base style for data rows (default: {Style::DEFAULT})
219
+ # @param highlight_symbol [String] prefix for the selected row (default: " ")
220
+ # @param column_spacing [Integer] gap between columns (default: 1)
221
+ # @param width [Integer, nil] total width in columns (default: auto-detect)
222
+ # @param output [IO] output stream (default: $stdout)
223
+ # @return [void]
224
+ #
225
+ # @example
226
+ # RubyTUI.print_table(
227
+ # header: ["Name", "Price", "Change"],
228
+ # rows: [["AAPL", "150.00", "+2.3%"], ["GOOG", "2800", "-1.1%"]],
229
+ # border: :rounded,
230
+ # title: " Stocks "
231
+ # )
232
+ def print_table(header: nil, rows: [], widths: [], title: nil,
233
+ border: :rounded, border_style: Style::DEFAULT,
234
+ header_style: nil, style: Style::DEFAULT,
235
+ highlight_symbol: " ", column_spacing: 1,
236
+ width: nil, output: $stdout)
237
+ border_set = resolve_border_set(border)
238
+ block_widget = title ? Widgets::Block.new(
239
+ title: title, borders: :all, border_set: border_set,
240
+ border_style: border_style
241
+ ) : nil
242
+
243
+ table = Widgets::Table.new(
244
+ header: header, rows: rows, widths: widths, style: style,
245
+ header_style: header_style, highlight_symbol: highlight_symbol,
246
+ column_spacing: column_spacing, block: block_widget
247
+ )
248
+ state = Widgets::TableState.new(selected: -1) # No selection for one-shot
249
+
250
+ # Calculate height: header(1) + separator(1) + rows + border(2)
251
+ h = rows.length + (header ? 2 : 0) + (title ? 2 : 0)
252
+ w = width || terminal_width(output)
253
+
254
+ area = Rect.new(0, 0, w, h)
255
+ buf = Buffer.new(area)
256
+ table.render(area, buf, state)
257
+ output.write(buf.to_ansi)
258
+ output.write("\n")
259
+ end
260
+
261
+ # Print a styled box with text content to stdout. No event loop needed.
262
+ #
263
+ # Renders a {Widgets::Paragraph} inside a {Widgets::Block} with borders,
264
+ # then prints the ANSI output directly.
265
+ #
266
+ # @param title [String, nil] box title rendered on the top border
267
+ # @param content [String, Array<String>] text content (newlines or array of lines)
268
+ # @param border [Symbol, Symbols::BorderSet] border style — +:rounded+, +:double+,
269
+ # +:thick+, +:light+, +:plain+, or a {Symbols::BorderSet} (default: +:rounded+)
270
+ # @param border_style [Style] style for the border characters (default: {Style::DEFAULT})
271
+ # @param style [Style] background style for the box area (default: {Style::DEFAULT})
272
+ # @param text_style [Style] style for the text content (default: {Style::DEFAULT})
273
+ # @param alignment [Symbol] text alignment — +:left+, +:center+, +:right+ (default: +:left+)
274
+ # @param width [Integer, nil] total width in columns (default: auto-detect)
275
+ # @param output [IO] output stream (default: $stdout)
276
+ # @return [void]
277
+ #
278
+ # @example
279
+ # RubyTUI.print_box(
280
+ # title: " Summary ",
281
+ # content: "Total: $1,234\nProfit: +5.2%",
282
+ # border_style: Style.new.fg(Color::YELLOW)
283
+ # )
284
+ def print_box(title: nil, content: "", border: :rounded,
285
+ border_style: Style::DEFAULT, style: Style::DEFAULT,
286
+ text_style: Style::DEFAULT, alignment: :left,
287
+ width: nil, output: $stdout)
288
+ border_set = resolve_border_set(border)
289
+ block_widget = Widgets::Block.new(
290
+ title: title, borders: :all, border_set: border_set,
291
+ border_style: border_style, style: style
292
+ )
293
+
294
+ text = case content
295
+ when String then Text.from(content)
296
+ when Array then Text.from(content.join("\n"))
297
+ else content
298
+ end
299
+
300
+ para = Widgets::Paragraph.new(
301
+ text: text, style: text_style, alignment: alignment,
302
+ block: block_widget
303
+ )
304
+
305
+ w = width || terminal_width(output)
306
+ line_count = case content
307
+ when String then content.count("\n") + 1
308
+ when Array then content.length
309
+ else 1
310
+ end
311
+ h = line_count + 2 # +2 for borders
312
+
313
+ area = Rect.new(0, 0, w, h)
314
+ buf = Buffer.new(area)
315
+ para.render(area, buf)
316
+ output.write(buf.to_ansi)
317
+ output.write("\n")
318
+ end
319
+
320
+ # Print a styled gauge/progress bar to stdout. No event loop needed.
321
+ #
322
+ # Renders a {Widgets::Gauge} with optional title block, then prints
323
+ # the ANSI output directly.
324
+ #
325
+ # @param ratio [Float] progress value between 0.0 and 1.0 (default: 0.0)
326
+ # @param label [String, nil] custom label (default: percentage)
327
+ # @param width [Integer, nil] total width in columns (default: auto-detect)
328
+ # @param gauge_style [Style, nil] style for the filled portion (default: green)
329
+ # @param title [String, nil] box title rendered on the top border
330
+ # @param border [Symbol, Symbols::BorderSet] border style — +:rounded+, +:double+,
331
+ # +:thick+, +:light+, +:plain+, or a {Symbols::BorderSet} (default: +:rounded+)
332
+ # @param border_style [Style] style for the border characters (default: {Style::DEFAULT})
333
+ # @param output [IO] output stream (default: $stdout)
334
+ # @return [void]
335
+ #
336
+ # @example
337
+ # RubyTUI.print_gauge(ratio: 0.75, title: " Progress ", width: 40)
338
+ def print_gauge(ratio: 0.0, label: nil, width: nil,
339
+ gauge_style: nil, title: nil,
340
+ border: :rounded, border_style: Style::DEFAULT,
341
+ output: $stdout)
342
+ block_widget = title ? Widgets::Block.new(
343
+ title: title, borders: :all,
344
+ border_set: resolve_border_set(border),
345
+ border_style: border_style
346
+ ) : nil
347
+
348
+ gauge = Widgets::Gauge.new(
349
+ ratio: ratio, label: label, gauge_style: gauge_style,
350
+ block: block_widget
351
+ )
352
+
353
+ w = width || terminal_width(output)
354
+ h = title ? 3 : 1
355
+
356
+ area = Rect.new(0, 0, w, h)
357
+ buf = Buffer.new(area)
358
+ gauge.render(area, buf)
359
+ output.write(buf.to_ansi)
360
+ output.write("\n")
361
+ end
362
+
363
+ private
364
+
365
+ def terminal_width(output)
366
+ output.respond_to?(:winsize) ? output.winsize[1] : 80
367
+ rescue Errno::ENOTTY, Errno::ENODEV, NoMethodError
368
+ 80
369
+ end
370
+
371
+ def terminal_height(output)
372
+ output.respond_to?(:winsize) ? output.winsize[0] : 24
373
+ rescue Errno::ENOTTY, Errno::ENODEV, NoMethodError
374
+ 24
375
+ end
376
+
377
+ def resolve_border_set(border)
378
+ case border
379
+ when :rounded then Symbols::ROUNDED
380
+ when :double then Symbols::DOUBLE
381
+ when :thick then Symbols::THICK
382
+ when :light then Symbols::LIGHT
383
+ when :plain then Symbols::PLAIN
384
+ else
385
+ border.is_a?(Symbols::BorderSet) ? border : Symbols::ROUNDED
386
+ end
387
+ end
388
+ end
389
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubytui
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.3
5
+ platform: ruby
6
+ authors:
7
+ - CoCL
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: |
13
+ A pure Ruby, zero-dependency terminal user interface library featuring
14
+ immediate-mode rendering with double buffering, constraint-based layouts,
15
+ a duck-typed widget system, cross-platform input handling, and Kitty
16
+ graphics protocol support for inline images.
17
+ email:
18
+ - ''
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - LICENSE
24
+ - README.md
25
+ - lib/rubytui.rb
26
+ - lib/rubytui/app.rb
27
+ - lib/rubytui/backend.rb
28
+ - lib/rubytui/backends/ansi_backend.rb
29
+ - lib/rubytui/backends/test_backend.rb
30
+ - lib/rubytui/buffer.rb
31
+ - lib/rubytui/cell.rb
32
+ - lib/rubytui/color.rb
33
+ - lib/rubytui/color_mode.rb
34
+ - lib/rubytui/errors.rb
35
+ - lib/rubytui/event.rb
36
+ - lib/rubytui/frame.rb
37
+ - lib/rubytui/input/key.rb
38
+ - lib/rubytui/input/parser.rb
39
+ - lib/rubytui/input/reader.rb
40
+ - lib/rubytui/layout/constraint.rb
41
+ - lib/rubytui/layout/flex.rb
42
+ - lib/rubytui/layout/layout.rb
43
+ - lib/rubytui/modifier.rb
44
+ - lib/rubytui/rect.rb
45
+ - lib/rubytui/stateful_widget.rb
46
+ - lib/rubytui/style.rb
47
+ - lib/rubytui/symbols.rb
48
+ - lib/rubytui/terminal.rb
49
+ - lib/rubytui/text/line.rb
50
+ - lib/rubytui/text/span.rb
51
+ - lib/rubytui/text/text.rb
52
+ - lib/rubytui/unicode.rb
53
+ - lib/rubytui/version.rb
54
+ - lib/rubytui/widget.rb
55
+ - lib/rubytui/widgets/async_image.rb
56
+ - lib/rubytui/widgets/block.rb
57
+ - lib/rubytui/widgets/canvas.rb
58
+ - lib/rubytui/widgets/chart.rb
59
+ - lib/rubytui/widgets/gauge.rb
60
+ - lib/rubytui/widgets/image.rb
61
+ - lib/rubytui/widgets/input_field.rb
62
+ - lib/rubytui/widgets/list.rb
63
+ - lib/rubytui/widgets/paragraph.rb
64
+ - lib/rubytui/widgets/popup.rb
65
+ - lib/rubytui/widgets/scrollbar.rb
66
+ - lib/rubytui/widgets/sparkline.rb
67
+ - lib/rubytui/widgets/table.rb
68
+ - lib/rubytui/widgets/tabs.rb
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 3.2.0
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubygems_version: 4.0.19
87
+ specification_version: 4
88
+ summary: Pure Ruby, zero-dependency terminal user interface library
89
+ test_files: []