ratatui_ruby 0.9.1 → 0.10.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 +4 -4
- data/.builds/ruby-3.2.yml +1 -1
- data/.builds/ruby-3.3.yml +1 -1
- data/.builds/ruby-3.4.yml +1 -1
- data/.builds/ruby-4.0.0.yml +1 -1
- data/AGENTS.md +2 -1
- data/CHANGELOG.md +98 -0
- data/REUSE.toml +5 -0
- data/Rakefile +1 -1
- data/Steepfile +49 -0
- data/doc/concepts/debugging.md +401 -0
- data/doc/getting_started/quickstart.md +8 -3
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_color_picker.png +0 -0
- data/doc/images/app_debugging_showcase.gif +0 -0
- data/doc/images/app_debugging_showcase.png +0 -0
- data/doc/images/app_login_form.png +0 -0
- data/doc/images/app_stateful_interaction.png +0 -0
- data/doc/images/verify_quickstart_dsl.png +0 -0
- data/doc/images/verify_quickstart_layout.png +0 -0
- data/doc/images/verify_quickstart_lifecycle.png +0 -0
- data/doc/images/verify_readme_usage.png +0 -0
- data/doc/images/widget_barchart.png +0 -0
- data/doc/images/widget_block.png +0 -0
- data/doc/images/widget_box.png +0 -0
- data/doc/images/widget_calendar.png +0 -0
- data/doc/images/widget_canvas.png +0 -0
- data/doc/images/widget_cell.png +0 -0
- data/doc/images/widget_center.png +0 -0
- data/doc/images/widget_chart.png +0 -0
- data/doc/images/widget_gauge.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge.png +0 -0
- data/doc/images/widget_list.png +0 -0
- data/doc/images/widget_map.png +0 -0
- data/doc/images/widget_overlay.png +0 -0
- data/doc/images/widget_popup.png +0 -0
- data/doc/images/widget_ratatui_logo.png +0 -0
- data/doc/images/widget_ratatui_mascot.png +0 -0
- data/doc/images/widget_rect.png +0 -0
- data/doc/images/widget_render.png +0 -0
- data/doc/images/widget_rich_text.png +0 -0
- data/doc/images/widget_scroll_text.png +0 -0
- data/doc/images/widget_scrollbar.png +0 -0
- data/doc/images/widget_sparkline.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table.png +0 -0
- data/doc/images/widget_tabs.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/troubleshooting/async.md +4 -0
- data/examples/app_debugging_showcase/README.md +119 -0
- data/examples/app_debugging_showcase/app.rb +318 -0
- data/examples/widget_canvas/app.rb +19 -14
- data/examples/widget_gauge/app.rb +18 -3
- data/examples/widget_layout_split/app.rb +10 -4
- data/examples/widget_list/app.rb +22 -6
- data/examples/widget_rect/app.rb +7 -6
- data/examples/widget_rich_text/app.rb +62 -37
- data/examples/widget_style_colors/app.rb +26 -47
- data/examples/widget_table/app.rb +28 -5
- data/examples/widget_text_width/app.rb +6 -4
- data/ext/ratatui_ruby/Cargo.lock +48 -1
- data/ext/ratatui_ruby/Cargo.toml +6 -2
- data/ext/ratatui_ruby/src/color.rs +82 -0
- data/ext/ratatui_ruby/src/errors.rs +28 -0
- data/ext/ratatui_ruby/src/events.rs +15 -14
- data/ext/ratatui_ruby/src/lib.rs +56 -0
- data/ext/ratatui_ruby/src/rendering.rs +3 -1
- data/ext/ratatui_ruby/src/style.rs +48 -21
- data/ext/ratatui_ruby/src/terminal.rs +40 -9
- data/ext/ratatui_ruby/src/text.rs +21 -9
- data/ext/ratatui_ruby/src/widgets/chart.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/layout.rs +90 -2
- data/ext/ratatui_ruby/src/widgets/list.rs +6 -5
- data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/table.rs +7 -6
- data/ext/ratatui_ruby/src/widgets/table_state.rs +55 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +3 -2
- data/lib/ratatui_ruby/buffer/cell.rb +25 -15
- data/lib/ratatui_ruby/buffer.rb +134 -2
- data/lib/ratatui_ruby/cell.rb +13 -5
- data/lib/ratatui_ruby/debug.rb +215 -0
- data/lib/ratatui_ruby/event/key.rb +3 -2
- data/lib/ratatui_ruby/event.rb +1 -1
- data/lib/ratatui_ruby/layout/constraint.rb +49 -0
- data/lib/ratatui_ruby/layout/layout.rb +119 -13
- data/lib/ratatui_ruby/layout/position.rb +55 -0
- data/lib/ratatui_ruby/layout/rect.rb +188 -0
- data/lib/ratatui_ruby/layout/size.rb +55 -0
- data/lib/ratatui_ruby/layout.rb +4 -0
- data/lib/ratatui_ruby/style/color.rb +149 -0
- data/lib/ratatui_ruby/style/style.rb +51 -4
- data/lib/ratatui_ruby/style.rb +2 -0
- data/lib/ratatui_ruby/symbols.rb +435 -0
- data/lib/ratatui_ruby/synthetic_events.rb +1 -1
- data/lib/ratatui_ruby/table_state.rb +51 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb +2 -1
- data/lib/ratatui_ruby/test_helper/event_injection.rb +6 -1
- data/lib/ratatui_ruby/test_helper.rb +9 -0
- data/lib/ratatui_ruby/text/line.rb +245 -0
- data/lib/ratatui_ruby/text/span.rb +158 -0
- data/lib/ratatui_ruby/text.rb +99 -0
- data/lib/ratatui_ruby/tui/canvas_factories.rb +103 -0
- data/lib/ratatui_ruby/tui/core.rb +13 -2
- data/lib/ratatui_ruby/tui/layout_factories.rb +50 -3
- data/lib/ratatui_ruby/tui/state_factories.rb +42 -0
- data/lib/ratatui_ruby/tui/text_factories.rb +40 -0
- data/lib/ratatui_ruby/tui/widget_factories.rb +135 -60
- data/lib/ratatui_ruby/tui.rb +22 -1
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart.rb +30 -20
- data/lib/ratatui_ruby/widgets/block.rb +14 -6
- data/lib/ratatui_ruby/widgets/calendar.rb +2 -0
- data/lib/ratatui_ruby/widgets/canvas.rb +56 -0
- data/lib/ratatui_ruby/widgets/cell.rb +2 -0
- data/lib/ratatui_ruby/widgets/center.rb +2 -0
- data/lib/ratatui_ruby/widgets/chart.rb +6 -0
- data/lib/ratatui_ruby/widgets/clear.rb +2 -0
- data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
- data/lib/ratatui_ruby/widgets/cursor.rb +2 -0
- data/lib/ratatui_ruby/widgets/gauge.rb +61 -3
- data/lib/ratatui_ruby/widgets/line_gauge.rb +66 -4
- data/lib/ratatui_ruby/widgets/list.rb +87 -3
- data/lib/ratatui_ruby/widgets/list_item.rb +2 -0
- data/lib/ratatui_ruby/widgets/overlay.rb +2 -0
- data/lib/ratatui_ruby/widgets/paragraph.rb +4 -0
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -0
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -0
- data/lib/ratatui_ruby/widgets/row.rb +45 -0
- data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -0
- data/lib/ratatui_ruby/widgets/shape/label.rb +2 -0
- data/lib/ratatui_ruby/widgets/sparkline.rb +21 -13
- data/lib/ratatui_ruby/widgets/table.rb +13 -3
- data/lib/ratatui_ruby/widgets/tabs.rb +6 -4
- data/lib/ratatui_ruby/widgets.rb +1 -0
- data/lib/ratatui_ruby.rb +40 -9
- data/sig/examples/app_all_events/model/app_model.rbs +23 -0
- data/sig/examples/app_all_events/model/event_entry.rbs +15 -8
- data/sig/examples/app_all_events/model/timestamp.rbs +1 -1
- data/sig/examples/app_all_events/view.rbs +1 -1
- data/sig/examples/app_stateful_interaction/app.rbs +5 -5
- data/sig/examples/widget_block_demo/app.rbs +6 -6
- data/sig/manifest.yaml +5 -0
- data/sig/patches/data.rbs +26 -0
- data/sig/patches/debugger__.rbs +8 -0
- data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
- data/sig/ratatui_ruby/buffer.rbs +18 -0
- data/sig/ratatui_ruby/cell.rbs +44 -0
- data/sig/ratatui_ruby/clear.rbs +18 -0
- data/sig/ratatui_ruby/constraint.rbs +26 -0
- data/sig/ratatui_ruby/debug.rbs +45 -0
- data/sig/ratatui_ruby/draw.rbs +30 -0
- data/sig/ratatui_ruby/event.rbs +68 -8
- data/sig/ratatui_ruby/frame.rbs +4 -4
- data/sig/ratatui_ruby/interfaces.rbs +25 -0
- data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
- data/sig/ratatui_ruby/layout/layout.rbs +45 -0
- data/sig/ratatui_ruby/layout/position.rbs +18 -0
- data/sig/ratatui_ruby/layout/rect.rbs +64 -0
- data/sig/ratatui_ruby/layout/size.rbs +18 -0
- data/sig/ratatui_ruby/output_guard.rbs +23 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +83 -4
- data/sig/ratatui_ruby/rect.rbs +17 -0
- data/sig/ratatui_ruby/style/color.rbs +22 -0
- data/sig/ratatui_ruby/style/style.rbs +29 -0
- data/sig/ratatui_ruby/symbols.rbs +141 -0
- data/sig/ratatui_ruby/synthetic_events.rbs +21 -0
- data/sig/ratatui_ruby/table_state.rbs +6 -0
- data/sig/ratatui_ruby/terminal_lifecycle.rbs +31 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +2 -2
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +22 -3
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +8 -1
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -3
- data/sig/ratatui_ruby/text/line.rbs +27 -0
- data/sig/ratatui_ruby/text/span.rbs +23 -0
- data/sig/ratatui_ruby/text.rbs +12 -0
- data/sig/ratatui_ruby/tui/buffer_factories.rbs +1 -1
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +23 -5
- data/sig/ratatui_ruby/tui/core.rbs +2 -2
- data/sig/ratatui_ruby/tui/layout_factories.rbs +16 -2
- data/sig/ratatui_ruby/tui/state_factories.rbs +8 -3
- data/sig/ratatui_ruby/tui/style_factories.rbs +3 -1
- data/sig/ratatui_ruby/tui/text_factories.rbs +7 -4
- data/sig/ratatui_ruby/tui/widget_factories.rbs +123 -30
- data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
- data/sig/ratatui_ruby/widgets/block.rbs +51 -0
- data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
- data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
- data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
- data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
- data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
- data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
- data/sig/ratatui_ruby/widgets/list.rbs +63 -0
- data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
- data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
- data/sig/ratatui_ruby/widgets/row.rbs +43 -0
- data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
- data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
- data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
- data/sig/ratatui_ruby/widgets/table.rbs +78 -0
- data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
- data/sig/ratatui_ruby/{schema/list_item.rbs → widgets.rbs} +4 -4
- data/tasks/steep.rake +11 -0
- metadata +80 -63
- data/doc/contributors/v1.0.0_blockers.md +0 -870
- data/doc/troubleshooting/debugging.md +0 -101
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +0 -47
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +0 -25
- data/lib/ratatui_ruby/schema/bar_chart.rb +0 -287
- data/lib/ratatui_ruby/schema/block.rb +0 -198
- data/lib/ratatui_ruby/schema/calendar.rb +0 -84
- data/lib/ratatui_ruby/schema/canvas.rb +0 -239
- data/lib/ratatui_ruby/schema/center.rb +0 -67
- data/lib/ratatui_ruby/schema/chart.rb +0 -159
- data/lib/ratatui_ruby/schema/clear.rb +0 -62
- data/lib/ratatui_ruby/schema/constraint.rb +0 -151
- data/lib/ratatui_ruby/schema/cursor.rb +0 -50
- data/lib/ratatui_ruby/schema/gauge.rb +0 -72
- data/lib/ratatui_ruby/schema/layout.rb +0 -122
- data/lib/ratatui_ruby/schema/line_gauge.rb +0 -80
- data/lib/ratatui_ruby/schema/list.rb +0 -135
- data/lib/ratatui_ruby/schema/list_item.rb +0 -51
- data/lib/ratatui_ruby/schema/overlay.rb +0 -51
- data/lib/ratatui_ruby/schema/paragraph.rb +0 -107
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +0 -31
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +0 -36
- data/lib/ratatui_ruby/schema/rect.rb +0 -174
- data/lib/ratatui_ruby/schema/row.rb +0 -76
- data/lib/ratatui_ruby/schema/scrollbar.rb +0 -143
- data/lib/ratatui_ruby/schema/shape/label.rb +0 -76
- data/lib/ratatui_ruby/schema/sparkline.rb +0 -142
- data/lib/ratatui_ruby/schema/style.rb +0 -97
- data/lib/ratatui_ruby/schema/table.rb +0 -141
- data/lib/ratatui_ruby/schema/tabs.rb +0 -85
- data/lib/ratatui_ruby/schema/text.rb +0 -217
- data/sig/examples/app_all_events/model/events.rbs +0 -15
- data/sig/examples/app_all_events/view_state.rbs +0 -21
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +0 -22
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +0 -19
- data/sig/ratatui_ruby/schema/bar_chart.rbs +0 -38
- data/sig/ratatui_ruby/schema/block.rbs +0 -18
- data/sig/ratatui_ruby/schema/calendar.rbs +0 -23
- data/sig/ratatui_ruby/schema/canvas.rbs +0 -81
- data/sig/ratatui_ruby/schema/center.rbs +0 -17
- data/sig/ratatui_ruby/schema/chart.rbs +0 -39
- data/sig/ratatui_ruby/schema/constraint.rbs +0 -30
- data/sig/ratatui_ruby/schema/cursor.rbs +0 -16
- data/sig/ratatui_ruby/schema/draw.rbs +0 -33
- data/sig/ratatui_ruby/schema/gauge.rbs +0 -23
- data/sig/ratatui_ruby/schema/layout.rbs +0 -27
- data/sig/ratatui_ruby/schema/line_gauge.rbs +0 -24
- data/sig/ratatui_ruby/schema/list.rbs +0 -28
- data/sig/ratatui_ruby/schema/overlay.rbs +0 -15
- data/sig/ratatui_ruby/schema/paragraph.rbs +0 -20
- data/sig/ratatui_ruby/schema/ratatui_logo.rbs +0 -14
- data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +0 -17
- data/sig/ratatui_ruby/schema/rect.rbs +0 -48
- data/sig/ratatui_ruby/schema/row.rbs +0 -28
- data/sig/ratatui_ruby/schema/scrollbar.rbs +0 -42
- data/sig/ratatui_ruby/schema/sparkline.rbs +0 -22
- data/sig/ratatui_ruby/schema/style.rbs +0 -19
- data/sig/ratatui_ruby/schema/table.rbs +0 -32
- data/sig/ratatui_ruby/schema/tabs.rbs +0 -21
- data/sig/ratatui_ruby/schema/text.rbs +0 -31
- /data/lib/ratatui_ruby/{schema/draw.rb → draw.rb} +0 -0
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
module RatatuiRuby
|
|
9
|
-
# Displays high-density data in a compact row.
|
|
10
|
-
#
|
|
11
|
-
# Users need context. A single value ("90% CPU") tells you current status, but not the trend.
|
|
12
|
-
# Full charts take up too much room.
|
|
13
|
-
#
|
|
14
|
-
# This widget solves the density problem. It condenses history into a single line of variable-height blocks.
|
|
15
|
-
#
|
|
16
|
-
# Use it in dashboards, headers, or list items to providing trending data at a glance.
|
|
17
|
-
#
|
|
18
|
-
# {rdoc-image:/doc/images/widget_sparkline.png}[link:/examples/widget_sparkline/app_rb.html]
|
|
19
|
-
#
|
|
20
|
-
# === Example
|
|
21
|
-
#
|
|
22
|
-
# Run the interactive demo from the terminal:
|
|
23
|
-
#
|
|
24
|
-
# ruby examples/widget_sparkline/app.rb
|
|
25
|
-
class Sparkline < Data.define(:data, :max, :style, :block, :direction, :absent_value_symbol, :absent_value_style, :bar_set)
|
|
26
|
-
##
|
|
27
|
-
# :attr_reader: data
|
|
28
|
-
# Array of integer values to plot.
|
|
29
|
-
|
|
30
|
-
##
|
|
31
|
-
# :attr_reader: max
|
|
32
|
-
# Maximum value for scaling (optional).
|
|
33
|
-
#
|
|
34
|
-
# If nil, derived from data max.
|
|
35
|
-
|
|
36
|
-
##
|
|
37
|
-
# :attr_reader: style
|
|
38
|
-
# Style for the bars.
|
|
39
|
-
|
|
40
|
-
##
|
|
41
|
-
# :attr_reader: block
|
|
42
|
-
# Optional wrapping block.
|
|
43
|
-
|
|
44
|
-
##
|
|
45
|
-
# :attr_reader: direction
|
|
46
|
-
# Direction to render data.
|
|
47
|
-
#
|
|
48
|
-
# Accepts +:left_to_right+ (default) or +:right_to_left+.
|
|
49
|
-
# Use +:right_to_left+ when new data should appear on the left.
|
|
50
|
-
|
|
51
|
-
##
|
|
52
|
-
# :attr_reader: absent_value_symbol
|
|
53
|
-
# Character to render for absent (nil) values (optional).
|
|
54
|
-
#
|
|
55
|
-
# If nil, absent values are rendered with a space.
|
|
56
|
-
|
|
57
|
-
##
|
|
58
|
-
# :attr_reader: absent_value_style
|
|
59
|
-
# Style for absent (nil) values (optional).
|
|
60
|
-
|
|
61
|
-
##
|
|
62
|
-
# :attr_reader: bar_set
|
|
63
|
-
# Custom characters for the bars (optional).
|
|
64
|
-
#
|
|
65
|
-
# A Hash with keys defining the characters for the bars.
|
|
66
|
-
# Keys: <tt>:empty</tt>, <tt>:one_eighth</tt>, <tt>:one_quarter</tt>, <tt>:three_eighths</tt>, <tt>:half</tt>, <tt>:five_eighths</tt>, <tt>:three_quarters</tt>, <tt>:seven_eighths</tt>, <tt>:full</tt>.
|
|
67
|
-
#
|
|
68
|
-
# You can also use integers (0-8) as keys, where 0 is empty, 4 is half, and 8 is full.
|
|
69
|
-
#
|
|
70
|
-
# Alternatively, you can pass an Array of 9 strings, where index 0 is empty and index 8 is full.
|
|
71
|
-
#
|
|
72
|
-
# === Examples
|
|
73
|
-
#
|
|
74
|
-
#--
|
|
75
|
-
# SPDX-SnippetBegin
|
|
76
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
77
|
-
# SPDX-License-Identifier: MIT-0
|
|
78
|
-
#++
|
|
79
|
-
# bar_set: {
|
|
80
|
-
# empty: " ",
|
|
81
|
-
# one_eighth: " ",
|
|
82
|
-
# one_quarter: "▂",
|
|
83
|
-
# three_eighths: "▃",
|
|
84
|
-
# half: "▄",
|
|
85
|
-
# five_eighths: "▅",
|
|
86
|
-
# three_quarters: "▆",
|
|
87
|
-
# seven_eighths: "▇",
|
|
88
|
-
# full: "█"
|
|
89
|
-
# }
|
|
90
|
-
#
|
|
91
|
-
# # Numeric keys (0-8)
|
|
92
|
-
# bar_set: {
|
|
93
|
-
# 0 => " ", 1 => " ", 2 => "▂", 3 => "▃", 4 => "▄", 5 => "▅", 6 => "▆", 7 => "▇", 8 => "█"
|
|
94
|
-
# }
|
|
95
|
-
#
|
|
96
|
-
# # Array (9 items)
|
|
97
|
-
# bar_set: [" ", " ", "▂", "▃", "▄", "▅", "▆", "▇", "█"]
|
|
98
|
-
#--
|
|
99
|
-
# SPDX-SnippetEnd
|
|
100
|
-
#++
|
|
101
|
-
|
|
102
|
-
BAR_KEYS = %i[empty one_eighth one_quarter three_eighths half five_eighths three_quarters seven_eighths full].freeze
|
|
103
|
-
|
|
104
|
-
# Creates a new Sparkline widget.
|
|
105
|
-
#
|
|
106
|
-
# [data] Array of Integers or nil. nil marks an absent value (distinct from 0).
|
|
107
|
-
# [max] Max value (optional).
|
|
108
|
-
# [style] Style (optional).
|
|
109
|
-
# [block] Block (optional).
|
|
110
|
-
# [direction] +:left_to_right+ or +:right_to_left+ (default: +:left_to_right+).
|
|
111
|
-
# [absent_value_symbol] Character for absent (nil) values (optional).
|
|
112
|
-
# [absent_value_style] Style for absent (nil) values (optional).
|
|
113
|
-
# [bar_set] Hash or Array of custom characters (optional).
|
|
114
|
-
def initialize(data:, max: nil, style: nil, block: nil, direction: :left_to_right, absent_value_symbol: nil, absent_value_style: nil, bar_set: nil)
|
|
115
|
-
if bar_set
|
|
116
|
-
if bar_set.is_a?(Array) && bar_set.size == 9
|
|
117
|
-
# Convert Array to Hash using BAR_KEYS order
|
|
118
|
-
bar_set = BAR_KEYS.zip(bar_set).to_h
|
|
119
|
-
else
|
|
120
|
-
bar_set = bar_set.dup
|
|
121
|
-
# Normalize numeric keys (0-8) to symbolic keys
|
|
122
|
-
BAR_KEYS.each_with_index do |key, i|
|
|
123
|
-
if (val = bar_set.delete(i) || bar_set.delete(i.to_s))
|
|
124
|
-
bar_set[key] = val
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
coerced_data = data.map { |v| v.nil? ? nil : Integer(v) }
|
|
130
|
-
super(
|
|
131
|
-
data: coerced_data,
|
|
132
|
-
max: max.nil? ? nil : Integer(max),
|
|
133
|
-
style:,
|
|
134
|
-
block:,
|
|
135
|
-
direction:,
|
|
136
|
-
absent_value_symbol:,
|
|
137
|
-
absent_value_style:,
|
|
138
|
-
bar_set:
|
|
139
|
-
)
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
end
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
module RatatuiRuby
|
|
9
|
-
# Defines colors and text modifiers.
|
|
10
|
-
#
|
|
11
|
-
# The terminal is traditionally monochrome, but efficient interfaces use color to convey meaning.
|
|
12
|
-
# Red for errors. Green for success. Bold for headers.
|
|
13
|
-
#
|
|
14
|
-
# This value object encapsulates those choices. It applies foreground and background colors. It adds effects like italics or blinking.
|
|
15
|
-
#
|
|
16
|
-
# Use it to theme your application or highlight critical data.
|
|
17
|
-
#
|
|
18
|
-
# === Examples
|
|
19
|
-
#
|
|
20
|
-
#--
|
|
21
|
-
# SPDX-SnippetBegin
|
|
22
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
23
|
-
# SPDX-License-Identifier: MIT-0
|
|
24
|
-
#++
|
|
25
|
-
# # Standard colors
|
|
26
|
-
# Style.new(fg: :red, bg: :white, modifiers: [:bold])
|
|
27
|
-
#
|
|
28
|
-
# # Hex colors
|
|
29
|
-
# Style.new(fg: "#ff00ff")
|
|
30
|
-
#
|
|
31
|
-
#--
|
|
32
|
-
# SPDX-SnippetEnd
|
|
33
|
-
#++
|
|
34
|
-
# === Supported Colors
|
|
35
|
-
#
|
|
36
|
-
# ==== Integer
|
|
37
|
-
# Represents an indexed color from the Xterm 256-color palette (0-255).
|
|
38
|
-
# * <tt>0</tt>–<tt>15</tt>: Standard and bright ANSI colors.
|
|
39
|
-
# * <tt>16</tt>–<tt>231</tt>: {6x6x6 Color Cube}[https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit].
|
|
40
|
-
# * <tt>232</tt>–<tt>255</tt>: Grayscale ramp.
|
|
41
|
-
#
|
|
42
|
-
# ==== Symbol
|
|
43
|
-
# Represents a named color from the standard ANSI palette. Supported values:
|
|
44
|
-
# * <tt>:black</tt>, <tt>:red</tt>, <tt>:green</tt>, <tt>:yellow</tt>,
|
|
45
|
-
# <tt>:blue</tt>, <tt>:magenta</tt>, <tt>:cyan</tt>, <tt>:gray</tt>
|
|
46
|
-
# * <tt>:dark_gray</tt>, <tt>:light_red</tt>, <tt>:light_green</tt>,
|
|
47
|
-
#--
|
|
48
|
-
# SPDX-SnippetBegin
|
|
49
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
50
|
-
# SPDX-License-Identifier: MIT-0
|
|
51
|
-
#++
|
|
52
|
-
# <tt>:light_yellow</tt>, <tt>:light_blue</tt>, <tt>:light_magenta</tt>,
|
|
53
|
-
# <tt>:light_cyan</tt>, <tt>:white</tt>
|
|
54
|
-
#
|
|
55
|
-
#--
|
|
56
|
-
# SPDX-SnippetEnd
|
|
57
|
-
#++
|
|
58
|
-
# ==== String
|
|
59
|
-
# Represents a specific RGB color using a Hex code (<tt>"#RRGGBB"</tt>).
|
|
60
|
-
# Requires a terminal emulator with "True Color" (24-bit color) support.
|
|
61
|
-
class Style < Data.define(:fg, :bg, :modifiers)
|
|
62
|
-
##
|
|
63
|
-
# :attr_reader: fg
|
|
64
|
-
# Foreground color.
|
|
65
|
-
#
|
|
66
|
-
# Symbol (<tt>:red</tt>), Hex String (<tt>"#ffffff"</tt>), or Integer (0-255).
|
|
67
|
-
|
|
68
|
-
##
|
|
69
|
-
# :attr_reader: bg
|
|
70
|
-
# Background color.
|
|
71
|
-
#
|
|
72
|
-
# Symbol (<tt>:black</tt>), Hex String (<tt>"#000000"</tt>), or Integer (0-255).
|
|
73
|
-
|
|
74
|
-
##
|
|
75
|
-
# :attr_reader: modifiers
|
|
76
|
-
# Text effects.
|
|
77
|
-
#
|
|
78
|
-
# Array of symbols: <tt>:bold</tt>, <tt>:dim</tt>, <tt>:italic</tt>, <tt>:underlined</tt>,
|
|
79
|
-
# <tt>:slow_blink</tt>, <tt>:rapid_blink</tt>, <tt>:reversed</tt>, <tt>:hidden</tt>, <tt>:crossed_out</tt>.
|
|
80
|
-
|
|
81
|
-
# Creates a new Style.
|
|
82
|
-
#
|
|
83
|
-
# [fg] Color (Symbol/String/Integer).
|
|
84
|
-
# [bg] Color (Symbol/String/Integer).
|
|
85
|
-
# [modifiers] Array of Symbols.
|
|
86
|
-
def initialize(fg: nil, bg: nil, modifiers: [])
|
|
87
|
-
super
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Returns an empty style.
|
|
91
|
-
#
|
|
92
|
-
# Use this as a baseline to prevent style inheritance issues or when no styling is required.
|
|
93
|
-
def self.default
|
|
94
|
-
new
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
module RatatuiRuby
|
|
9
|
-
# Displays structured data in rows and columns.
|
|
10
|
-
#
|
|
11
|
-
# Data is often multidimensional. You need to show relationships between fields (Name, Age, ID).
|
|
12
|
-
# Aligning columns manually in a monospaced environment is painful and error-prone.
|
|
13
|
-
#
|
|
14
|
-
# This widget creates a grid. It enforces column widths using constraints. It renders headers, rows, and footers aligned perfectly.
|
|
15
|
-
#
|
|
16
|
-
# Use it to display database records, logs, or file lists.
|
|
17
|
-
#
|
|
18
|
-
# {rdoc-image:/doc/images/widget_table_flex.png}[link:/examples/widget_table_flex/app_rb.html]
|
|
19
|
-
#
|
|
20
|
-
# === Example
|
|
21
|
-
#
|
|
22
|
-
# Run the interactive demo from the terminal:
|
|
23
|
-
#
|
|
24
|
-
# ruby examples/widget_table_flex/app.rb
|
|
25
|
-
class Table < Data.define(:header, :rows, :widths, :row_highlight_style, :highlight_symbol, :highlight_spacing, :column_highlight_style, :cell_highlight_style, :selected_row, :selected_column, :offset, :block, :footer, :flex, :style, :column_spacing)
|
|
26
|
-
##
|
|
27
|
-
# :attr_reader: header
|
|
28
|
-
# Header row content (Array of Strings, Text::Spans, Text::Lines, or Paragraphs).
|
|
29
|
-
|
|
30
|
-
##
|
|
31
|
-
# :attr_reader: rows
|
|
32
|
-
# Data rows (Array of Arrays). Each cell can be String, Text::Span, Text::Line, Paragraph, or Cell.
|
|
33
|
-
|
|
34
|
-
##
|
|
35
|
-
# :attr_reader: widths
|
|
36
|
-
# Column width constraints (Array of Constraint).
|
|
37
|
-
|
|
38
|
-
##
|
|
39
|
-
# :attr_reader: row_highlight_style
|
|
40
|
-
# Style for the selected row.
|
|
41
|
-
|
|
42
|
-
##
|
|
43
|
-
# :attr_reader: highlight_symbol
|
|
44
|
-
# Symbol for the selected row.
|
|
45
|
-
|
|
46
|
-
##
|
|
47
|
-
# :attr_reader: highlight_spacing
|
|
48
|
-
# When to show the highlight symbol column (<tt>:always</tt>, <tt>:when_selected</tt>, <tt>:never</tt>).
|
|
49
|
-
|
|
50
|
-
##
|
|
51
|
-
# :attr_reader: column_highlight_style
|
|
52
|
-
# Style for the selected column.
|
|
53
|
-
|
|
54
|
-
##
|
|
55
|
-
# :attr_reader: cell_highlight_style
|
|
56
|
-
# Style for the selected cell (intersection of row and column).
|
|
57
|
-
|
|
58
|
-
##
|
|
59
|
-
# :attr_reader: selected_row
|
|
60
|
-
# Index of the selected row (Integer or nil).
|
|
61
|
-
|
|
62
|
-
##
|
|
63
|
-
# :attr_reader: selected_column
|
|
64
|
-
# Index of the selected column (Integer or nil).
|
|
65
|
-
|
|
66
|
-
##
|
|
67
|
-
# :attr_reader: offset
|
|
68
|
-
# Scroll offset (Integer or nil).
|
|
69
|
-
#
|
|
70
|
-
# Controls the viewport's starting row position in the table.
|
|
71
|
-
#
|
|
72
|
-
# When +nil+ (default), Ratatui auto-scrolls to keep the selection visible ("natural scrolling").
|
|
73
|
-
#
|
|
74
|
-
# When set, forces the viewport to start at this row index. Use this for:
|
|
75
|
-
# - **Passive scrolling**: Scroll through a log table without selecting rows.
|
|
76
|
-
# - **Click-to-select math**: Calculate which row index corresponds to a click coordinate.
|
|
77
|
-
#
|
|
78
|
-
# *Important*: When both +offset+ and +selected_row+ are set, Ratatui may still adjust
|
|
79
|
-
# the viewport during rendering to ensure the selection stays visible. Set +selected_row+
|
|
80
|
-
# to +nil+ for fully manual scroll control.
|
|
81
|
-
|
|
82
|
-
##
|
|
83
|
-
# :attr_reader: block
|
|
84
|
-
# Optional wrapping block.
|
|
85
|
-
|
|
86
|
-
##
|
|
87
|
-
# :attr_reader: footer
|
|
88
|
-
# Footer row content (Array of Strings, Text::Spans, Text::Lines, or Paragraphs).
|
|
89
|
-
|
|
90
|
-
##
|
|
91
|
-
# :attr_reader: flex
|
|
92
|
-
# Flex mode for column distribution.
|
|
93
|
-
|
|
94
|
-
##
|
|
95
|
-
# :attr_reader: style
|
|
96
|
-
# Base style for the entire table.
|
|
97
|
-
|
|
98
|
-
##
|
|
99
|
-
# :attr_reader: column_spacing
|
|
100
|
-
# Spacing between columns (Integer, default 1).
|
|
101
|
-
|
|
102
|
-
# Creates a new Table.
|
|
103
|
-
#
|
|
104
|
-
# [header] Array of strings, Text::Spans, Text::Lines, or paragraphs.
|
|
105
|
-
# [rows] 2D Array where each cell is String, Text::Span, Text::Line, Paragraph, or Cell.
|
|
106
|
-
# [widths] Array of Constraints.
|
|
107
|
-
# [row_highlight_style] Style object.
|
|
108
|
-
# [highlight_symbol] String.
|
|
109
|
-
# [highlight_spacing] Symbol (optional, default: <tt>:when_selected</tt>).
|
|
110
|
-
# [column_highlight_style] Style object.
|
|
111
|
-
# [cell_highlight_style] Style object.
|
|
112
|
-
# [selected_row] Integer (nullable).
|
|
113
|
-
# [selected_column] Integer (nullable).
|
|
114
|
-
# [offset] Numeric (nullable, coerced to Integer). Forces scroll position when set.
|
|
115
|
-
# [block] Block (optional).
|
|
116
|
-
# [footer] Array of strings/paragraphs (optional).
|
|
117
|
-
# [flex] Symbol (optional, default: <tt>:legacy</tt>).
|
|
118
|
-
# [style] Style object or Hash (optional).
|
|
119
|
-
# [column_spacing] Integer (optional, default: 1).
|
|
120
|
-
def initialize(header: nil, rows: [], widths: [], row_highlight_style: nil, highlight_symbol: "> ", highlight_spacing: :when_selected, column_highlight_style: nil, cell_highlight_style: nil, selected_row: nil, selected_column: nil, offset: nil, block: nil, footer: nil, flex: :legacy, style: nil, column_spacing: 1)
|
|
121
|
-
super(
|
|
122
|
-
header:,
|
|
123
|
-
rows:,
|
|
124
|
-
widths:,
|
|
125
|
-
row_highlight_style:,
|
|
126
|
-
highlight_symbol:,
|
|
127
|
-
highlight_spacing:,
|
|
128
|
-
column_highlight_style:,
|
|
129
|
-
cell_highlight_style:,
|
|
130
|
-
selected_row: selected_row.nil? ? nil : Integer(selected_row),
|
|
131
|
-
selected_column: selected_column.nil? ? nil : Integer(selected_column),
|
|
132
|
-
offset: offset.nil? ? nil : Integer(offset),
|
|
133
|
-
block:,
|
|
134
|
-
footer:,
|
|
135
|
-
flex:,
|
|
136
|
-
style:,
|
|
137
|
-
column_spacing: Integer(column_spacing)
|
|
138
|
-
)
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
end
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
module RatatuiRuby
|
|
9
|
-
# Displays a tab bar for navigation.
|
|
10
|
-
#
|
|
11
|
-
# Screen real estate is limited. You cannot show everything at once. Segregating content into views is necessary for complex apps.
|
|
12
|
-
#
|
|
13
|
-
# This widget separates dimensions. It displays a row of titles, indicating which view is active.
|
|
14
|
-
#
|
|
15
|
-
# Use it at the top of your interface to switch between major modes or contexts.
|
|
16
|
-
#
|
|
17
|
-
# {rdoc-image:/doc/images/widget_tabs.png}[link:/examples/widget_tabs/app_rb.html]
|
|
18
|
-
#
|
|
19
|
-
# === Example
|
|
20
|
-
#
|
|
21
|
-
# Run the interactive demo from the terminal:
|
|
22
|
-
#
|
|
23
|
-
# ruby examples/widget_tabs/app.rb
|
|
24
|
-
class Tabs < Data.define(:titles, :selected_index, :block, :divider, :highlight_style, :style, :padding_left, :padding_right)
|
|
25
|
-
##
|
|
26
|
-
# :attr_reader: titles
|
|
27
|
-
# Tab titles (Array of Strings).
|
|
28
|
-
|
|
29
|
-
##
|
|
30
|
-
# :attr_reader: selected_index
|
|
31
|
-
# Index of the active tab.
|
|
32
|
-
|
|
33
|
-
##
|
|
34
|
-
# :attr_reader: block
|
|
35
|
-
# Optional wrapping block.
|
|
36
|
-
|
|
37
|
-
##
|
|
38
|
-
# :attr_reader: divider
|
|
39
|
-
# Separator string between tabs.
|
|
40
|
-
|
|
41
|
-
##
|
|
42
|
-
# :attr_reader: highlight_style
|
|
43
|
-
# Style for the selected tab title.
|
|
44
|
-
|
|
45
|
-
##
|
|
46
|
-
# :attr_reader: style
|
|
47
|
-
# Base style for the tabs area.
|
|
48
|
-
|
|
49
|
-
##
|
|
50
|
-
# :attr_reader: padding_left
|
|
51
|
-
# Left padding for the tabs area (Integer, default: 0).
|
|
52
|
-
|
|
53
|
-
##
|
|
54
|
-
# :attr_reader: padding_right
|
|
55
|
-
# Right padding for the tabs area (Integer, default: 0).
|
|
56
|
-
|
|
57
|
-
# Creates a new Tabs widget.
|
|
58
|
-
#
|
|
59
|
-
# [titles] Array of Strings/Lines.
|
|
60
|
-
# [selected_index] Integer (default: 0).
|
|
61
|
-
# [block] Block (optional).
|
|
62
|
-
# [divider] String (optional).
|
|
63
|
-
# [highlight_style] Style (optional).
|
|
64
|
-
# [style] Style (optional).
|
|
65
|
-
# [padding_left] Integer (default: 0).
|
|
66
|
-
# [padding_right] Integer (default: 0).
|
|
67
|
-
def initialize(titles: [], selected_index: 0, block: nil, divider: nil, highlight_style: nil, style: nil, padding_left: 0, padding_right: 0)
|
|
68
|
-
super(
|
|
69
|
-
titles:,
|
|
70
|
-
selected_index: Integer(selected_index),
|
|
71
|
-
block:,
|
|
72
|
-
divider:,
|
|
73
|
-
highlight_style:,
|
|
74
|
-
style:,
|
|
75
|
-
padding_left: Integer(padding_left),
|
|
76
|
-
padding_right: Integer(padding_right)
|
|
77
|
-
)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# Returns the total width of the tabs.
|
|
81
|
-
def width
|
|
82
|
-
RatatuiRuby._tabs_width(self)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
module RatatuiRuby
|
|
9
|
-
# Namespace for rich text components (Span, Line) and text utilities.
|
|
10
|
-
# Distinct from canvas shapes and other Line usages.
|
|
11
|
-
#
|
|
12
|
-
# == Text Measurement
|
|
13
|
-
#
|
|
14
|
-
# The Text module provides a utility method for calculating the display width
|
|
15
|
-
# of strings in terminal cells. This accounts for unicode complexity:
|
|
16
|
-
#
|
|
17
|
-
# - ASCII characters: 1 cell each
|
|
18
|
-
# - CJK (Chinese, Japanese, Korean) characters: 2 cells each (full-width)
|
|
19
|
-
# - Emoji: typically 2 cells each (varies by terminal)
|
|
20
|
-
# - Combining marks: 0 cells (zero-width)
|
|
21
|
-
#
|
|
22
|
-
# This is essential for layout calculations in TUI applications, where you need to know
|
|
23
|
-
# how much space a string will occupy on the screen, not just its byte or character length.
|
|
24
|
-
#
|
|
25
|
-
# === Use Cases
|
|
26
|
-
#
|
|
27
|
-
# - Auto-sizing widgets (Button, Badge) that fit their content
|
|
28
|
-
# - Calculating padding or centering for text alignment
|
|
29
|
-
# - Building responsive layouts that adapt to content width
|
|
30
|
-
# - Measuring text for scrolling or truncation logic
|
|
31
|
-
#
|
|
32
|
-
# === Examples
|
|
33
|
-
#
|
|
34
|
-
#--
|
|
35
|
-
# SPDX-SnippetBegin
|
|
36
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
37
|
-
# SPDX-License-Identifier: MIT-0
|
|
38
|
-
#++
|
|
39
|
-
# # Simple ASCII text
|
|
40
|
-
# RatatuiRuby::Text.width("Hello") # => 5
|
|
41
|
-
#
|
|
42
|
-
# # With emoji
|
|
43
|
-
# RatatuiRuby::Text.width("Hello 👍") # => 8 (5 + space + 2-width emoji)
|
|
44
|
-
#
|
|
45
|
-
# # With CJK characters
|
|
46
|
-
# RatatuiRuby::Text.width("你好") # => 4 (each CJK char is 2 cells)
|
|
47
|
-
#
|
|
48
|
-
# # Mixed content
|
|
49
|
-
# RatatuiRuby::Text.width("Hi 你好 👍") # => 11 (2 + space + 4 + space + 2)
|
|
50
|
-
#--
|
|
51
|
-
# SPDX-SnippetEnd
|
|
52
|
-
#++
|
|
53
|
-
module Text
|
|
54
|
-
# A styled string fragment.
|
|
55
|
-
#
|
|
56
|
-
# Text is rarely uniform. You need to bold a keyword, colorize an error, or dim a timestamp.
|
|
57
|
-
#
|
|
58
|
-
# This class attaches style to content. It pairs a string with visual attributes.
|
|
59
|
-
#
|
|
60
|
-
# combine spans into a {Line} to create rich text.
|
|
61
|
-
#
|
|
62
|
-
# === Examples
|
|
63
|
-
#
|
|
64
|
-
# Text::Span.new(content: "Error", style: Style.new(fg: :red, modifiers: [:bold]))
|
|
65
|
-
class Span < Data.define(:content, :style)
|
|
66
|
-
##
|
|
67
|
-
# :attr_reader: content
|
|
68
|
-
# The text content.
|
|
69
|
-
|
|
70
|
-
##
|
|
71
|
-
# :attr_reader: style
|
|
72
|
-
# The style to apply.
|
|
73
|
-
|
|
74
|
-
# Creates a new Span.
|
|
75
|
-
#
|
|
76
|
-
# [content] String.
|
|
77
|
-
# [style] Style object (optional).
|
|
78
|
-
def initialize(content:, style: nil)
|
|
79
|
-
super
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Concise helper for styling.
|
|
83
|
-
#
|
|
84
|
-
# Text::Span.styled("Bold", Style.new(modifiers: [:bold]))
|
|
85
|
-
def self.styled(content, style = nil)
|
|
86
|
-
new(content:, style:)
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# A sequence of styled spans.
|
|
91
|
-
#
|
|
92
|
-
# Words form sentences. Spans form lines.
|
|
93
|
-
#
|
|
94
|
-
# This class composes multiple {Span} objects into a single horizontal row of text.
|
|
95
|
-
# It handles the layout of rich text fragments within the flow of a paragraph.
|
|
96
|
-
#
|
|
97
|
-
# Use it to build multi-colored headers, status messages, or log entries.
|
|
98
|
-
#
|
|
99
|
-
# === Examples
|
|
100
|
-
#
|
|
101
|
-
#--
|
|
102
|
-
# SPDX-SnippetBegin
|
|
103
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
104
|
-
# SPDX-License-Identifier: MIT-0
|
|
105
|
-
#++
|
|
106
|
-
# Text::Line.new(
|
|
107
|
-
# spans: [
|
|
108
|
-
# Text::Span.styled("User: ", Style.new(modifiers: [:bold])),
|
|
109
|
-
# Text::Span.styled("kerrick", Style.new(fg: :blue))
|
|
110
|
-
# ]
|
|
111
|
-
# )
|
|
112
|
-
#--
|
|
113
|
-
# SPDX-SnippetEnd
|
|
114
|
-
#++
|
|
115
|
-
class Line < Data.define(:spans, :alignment, :style)
|
|
116
|
-
##
|
|
117
|
-
# :attr_reader: spans
|
|
118
|
-
# Array of Span objects.
|
|
119
|
-
|
|
120
|
-
##
|
|
121
|
-
# :attr_reader: alignment
|
|
122
|
-
# Alignment within the container.
|
|
123
|
-
#
|
|
124
|
-
# <tt>:left</tt>, <tt>:center</tt>, or <tt>:right</tt>.
|
|
125
|
-
|
|
126
|
-
##
|
|
127
|
-
# :attr_reader: style
|
|
128
|
-
# Line-level style applied to all spans.
|
|
129
|
-
#
|
|
130
|
-
# A Style object that sets colors/modifiers for the entire line.
|
|
131
|
-
|
|
132
|
-
# Creates a new Line.
|
|
133
|
-
#
|
|
134
|
-
# [spans] Array of Span objects (or Strings).
|
|
135
|
-
# [alignment] Symbol (optional).
|
|
136
|
-
# [style] Style object (optional).
|
|
137
|
-
def initialize(spans: [], alignment: nil, style: nil)
|
|
138
|
-
super
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
# Creates a simple line from a string.
|
|
142
|
-
#
|
|
143
|
-
# Text::Line.from_string("Hello")
|
|
144
|
-
def self.from_string(content, alignment: nil)
|
|
145
|
-
new(spans: [Span.new(content:, style: nil)], alignment:)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
# Calculates the display width of this line in terminal cells.
|
|
149
|
-
#
|
|
150
|
-
# Sums the widths of all span contents using the same unicode-aware
|
|
151
|
-
# algorithm as Text.width. Useful for layout calculations.
|
|
152
|
-
#
|
|
153
|
-
# === Examples
|
|
154
|
-
#
|
|
155
|
-
#--
|
|
156
|
-
# SPDX-SnippetBegin
|
|
157
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
158
|
-
# SPDX-License-Identifier: MIT-0
|
|
159
|
-
#++
|
|
160
|
-
# line = Text::Line.new(spans: [
|
|
161
|
-
# Text::Span.new(content: "Hello "),
|
|
162
|
-
# Text::Span.new(content: "世界")
|
|
163
|
-
# ])
|
|
164
|
-
# line.width # => 10 (6 ASCII + 4 CJK)
|
|
165
|
-
#
|
|
166
|
-
#--
|
|
167
|
-
# SPDX-SnippetEnd
|
|
168
|
-
#++
|
|
169
|
-
# Returns: Integer (number of terminal cells)
|
|
170
|
-
def width
|
|
171
|
-
RatatuiRuby::Text.width(spans.map { |s| s.content.to_s }.join)
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
##
|
|
176
|
-
# :method: width
|
|
177
|
-
# :call-seq: width(string) -> Integer
|
|
178
|
-
#
|
|
179
|
-
# Calculates the display width of a string in terminal cells.
|
|
180
|
-
#
|
|
181
|
-
# Layout demands precision. Terminals measure space in cells, not characters. An ASCII letter occupies one cell. A Chinese character occupies two. An emoji occupies two. Combining marks occupy zero.
|
|
182
|
-
#
|
|
183
|
-
# Measuring width manually is error-prone. You can count <tt>string.length</tt>, but that counts characters, not cells. A string with one emoji counts as 1 character but occupies 2 cells.
|
|
184
|
-
#
|
|
185
|
-
# This method returns the true display width. Use it to auto-size widgets, calculate padding, center text, or build responsive layouts.
|
|
186
|
-
#
|
|
187
|
-
# === Examples
|
|
188
|
-
#
|
|
189
|
-
#--
|
|
190
|
-
# SPDX-SnippetBegin
|
|
191
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
192
|
-
# SPDX-License-Identifier: MIT-0
|
|
193
|
-
#++
|
|
194
|
-
# RatatuiRuby::Text.width("Hello") # => 5 (5 ASCII chars × 1 cell)
|
|
195
|
-
#
|
|
196
|
-
# RatatuiRuby::Text.width("你好") # => 4 (2 CJK chars × 2 cells)
|
|
197
|
-
#
|
|
198
|
-
# RatatuiRuby::Text.width("Hello 👍") # => 8 (5 ASCII + 1 space + 1 emoji × 2)
|
|
199
|
-
#
|
|
200
|
-
# # In the Session DSL (easier)
|
|
201
|
-
# RatatuiRuby.run do |tui|
|
|
202
|
-
# width = tui.text_width("Hello 👍")
|
|
203
|
-
# end
|
|
204
|
-
#
|
|
205
|
-
#--
|
|
206
|
-
# SPDX-SnippetEnd
|
|
207
|
-
#++
|
|
208
|
-
# [string] String to measure (String or object convertible to String)
|
|
209
|
-
# Returns: Integer (number of terminal cells the string occupies)
|
|
210
|
-
# Raises: TypeError if the argument is not a String
|
|
211
|
-
#
|
|
212
|
-
# (Native method implemented in Rust)
|
|
213
|
-
def self.width(string)
|
|
214
|
-
RatatuiRuby._text_width(string)
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
-
|
|
4
|
-
class Events
|
|
5
|
-
def initialize: () -> void
|
|
6
|
-
def record: (Symbol type, ?time: Time, ?description: String, ?sub_key: Symbol | String | nil, ?data: Hash[Symbol, untyped], ?live_type: Symbol) -> void
|
|
7
|
-
def live_event: (Symbol type) -> { time: Time, description: String } | nil
|
|
8
|
-
def live_events: () -> Hash[Symbol, { time: Time, description: String }]
|
|
9
|
-
def visible: (Integer max_entries) -> Array[EventEntry]
|
|
10
|
-
def empty?: () -> bool
|
|
11
|
-
def count: (Symbol type, ?Symbol | nil sub_type) -> Integer
|
|
12
|
-
def count_by_kind: (String kind) -> Integer
|
|
13
|
-
def lit?: (Symbol type, ?Symbol | String | nil sub_key) -> bool
|
|
14
|
-
def entries: () -> Array[EventEntry]
|
|
15
|
-
end
|