ratatui_ruby 0.5.0 → 0.6.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 +6 -0
- data/CHANGELOG.md +44 -7
- data/README.md +11 -4
- data/REUSE.toml +2 -7
- data/doc/application_architecture.md +84 -10
- data/doc/application_testing.md +75 -29
- data/doc/contributors/design/ruby_frontend.md +39 -3
- data/doc/contributors/design/rust_backend.md +1 -0
- data/doc/contributors/developing_examples.md +129 -44
- data/doc/contributors/examples_audit/p1_high.md +21 -0
- data/doc/contributors/examples_audit/p2_moderate.md +81 -0
- data/doc/contributors/examples_audit.md +41 -0
- data/doc/event_handling.md +11 -3
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_color_picker.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_demo.png +0 -0
- data/doc/images/widget_block_demo.png +0 -0
- data/doc/images/widget_canvas_demo.png +0 -0
- data/doc/images/widget_cell_demo.png +0 -0
- data/doc/images/widget_center_demo.png +0 -0
- data/doc/images/widget_chart_demo.png +0 -0
- data/doc/images/widget_list_demo.png +0 -0
- data/doc/images/widget_overlay_demo.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_sparkline_demo.png +0 -0
- data/doc/images/widget_table_demo.png +0 -0
- data/doc/images/widget_tabs_demo.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/quickstart.md +69 -76
- data/doc/terminal_limitations.md +92 -0
- data/examples/app_all_events/README.md +45 -27
- data/examples/app_all_events/app.rb +38 -35
- data/examples/app_all_events/model/app_model.rb +157 -0
- data/examples/app_all_events/model/event_entry.rb +17 -0
- data/examples/app_all_events/model/msg.rb +37 -0
- data/examples/app_all_events/update.rb +73 -0
- data/examples/app_all_events/view/app_view.rb +8 -8
- data/examples/app_all_events/view/controls_view.rb +8 -6
- data/examples/app_all_events/view/counts_view.rb +12 -8
- data/examples/app_all_events/view/live_view.rb +8 -7
- data/examples/app_all_events/view/log_view.rb +10 -15
- data/examples/app_color_picker/README.md +84 -44
- data/examples/app_color_picker/app.rb +24 -62
- data/examples/app_color_picker/controls.rb +90 -0
- data/examples/app_color_picker/copy_dialog.rb +45 -49
- data/examples/app_color_picker/export_pane.rb +126 -0
- data/examples/app_color_picker/input.rb +99 -67
- data/examples/app_color_picker/main_container.rb +178 -0
- data/examples/app_color_picker/palette.rb +55 -26
- data/examples/app_login_form/README.md +47 -0
- data/examples/app_login_form/app.rb +2 -3
- data/examples/app_stateful_interaction/README.md +31 -0
- data/examples/app_stateful_interaction/app.rb +272 -0
- data/examples/timeout_demo.rb +43 -0
- data/examples/verify_quickstart_dsl/README.md +48 -0
- data/examples/verify_quickstart_dsl/app.rb +2 -0
- data/examples/verify_quickstart_layout/README.md +71 -0
- data/examples/verify_quickstart_layout/app.rb +2 -0
- data/examples/verify_quickstart_lifecycle/README.md +56 -0
- data/examples/verify_quickstart_lifecycle/app.rb +8 -2
- data/examples/verify_readme_usage/README.md +43 -0
- data/examples/verify_readme_usage/app.rb +8 -2
- data/examples/widget_barchart_demo/README.md +49 -0
- data/examples/widget_barchart_demo/app.rb +5 -5
- data/examples/widget_block_demo/README.md +34 -0
- data/examples/widget_block_demo/app.rb +256 -0
- data/examples/widget_box_demo/README.md +45 -0
- data/examples/widget_calendar_demo/README.md +39 -0
- data/examples/widget_canvas_demo/README.md +27 -0
- data/examples/widget_canvas_demo/app.rb +123 -0
- data/examples/widget_cell_demo/README.md +36 -0
- data/examples/widget_cell_demo/app.rb +31 -24
- data/examples/widget_center_demo/README.md +29 -0
- data/examples/widget_center_demo/app.rb +116 -0
- data/examples/widget_chart_demo/README.md +41 -0
- data/examples/widget_chart_demo/app.rb +7 -2
- data/examples/widget_gauge_demo/README.md +41 -0
- data/examples/widget_layout_split/README.md +44 -0
- data/examples/widget_line_gauge_demo/README.md +41 -0
- data/examples/widget_list_demo/README.md +49 -0
- data/examples/widget_list_demo/app.rb +91 -107
- data/examples/widget_map_demo/README.md +39 -0
- data/examples/{app_map_demo → widget_map_demo}/app.rb +2 -2
- data/examples/widget_overlay_demo/app.rb +248 -0
- data/examples/widget_popup_demo/README.md +36 -0
- data/examples/widget_ratatui_logo_demo/README.md +34 -0
- data/examples/widget_ratatui_mascot_demo/README.md +34 -0
- data/examples/widget_rect/README.md +38 -0
- data/examples/widget_render/README.md +37 -0
- data/examples/widget_rich_text/README.md +35 -0
- data/examples/widget_rich_text/app.rb +62 -33
- data/examples/widget_scroll_text/README.md +37 -0
- data/examples/widget_scroll_text/app.rb +0 -1
- data/examples/widget_scrollbar_demo/README.md +37 -0
- data/examples/widget_sparkline_demo/README.md +42 -0
- data/examples/widget_sparkline_demo/app.rb +4 -3
- data/examples/widget_style_colors/README.md +34 -0
- data/examples/widget_table_demo/README.md +48 -0
- data/examples/{app_table_select → widget_table_demo}/app.rb +46 -8
- data/examples/widget_tabs_demo/README.md +41 -0
- data/examples/widget_tabs_demo/app.rb +15 -1
- data/examples/widget_text_width/README.md +35 -0
- data/examples/widget_text_width/app.rb +106 -0
- data/exe/.gitkeep +0 -0
- data/ext/ratatui_ruby/Cargo.lock +11 -4
- data/ext/ratatui_ruby/Cargo.toml +2 -1
- data/ext/ratatui_ruby/src/events.rs +238 -26
- data/ext/ratatui_ruby/src/frame.rs +113 -1
- data/ext/ratatui_ruby/src/lib.rs +34 -4
- data/ext/ratatui_ruby/src/string_width.rs +101 -0
- data/ext/ratatui_ruby/src/terminal.rs +39 -15
- data/ext/ratatui_ruby/src/text.rs +1 -1
- data/ext/ratatui_ruby/src/widgets/barchart.rs +24 -6
- data/ext/ratatui_ruby/src/widgets/gauge.rs +9 -2
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +9 -2
- data/ext/ratatui_ruby/src/widgets/list.rs +179 -3
- data/ext/ratatui_ruby/src/widgets/list_state.rs +137 -0
- data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +93 -1
- data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/table.rs +113 -1
- data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
- data/lib/ratatui_ruby/cell.rb +4 -4
- data/lib/ratatui_ruby/event/key/character.rb +35 -0
- data/lib/ratatui_ruby/event/key/media.rb +44 -0
- data/lib/ratatui_ruby/event/key/modifier.rb +95 -0
- data/lib/ratatui_ruby/event/key/navigation.rb +55 -0
- data/lib/ratatui_ruby/event/key/system.rb +45 -0
- data/lib/ratatui_ruby/event/key.rb +111 -51
- data/lib/ratatui_ruby/event/mouse.rb +3 -3
- data/lib/ratatui_ruby/event/paste.rb +1 -1
- data/lib/ratatui_ruby/frame.rb +96 -0
- data/lib/ratatui_ruby/list_state.rb +88 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +2 -2
- data/lib/ratatui_ruby/schema/cursor.rb +5 -0
- data/lib/ratatui_ruby/schema/gauge.rb +3 -1
- data/lib/ratatui_ruby/schema/line_gauge.rb +2 -2
- data/lib/ratatui_ruby/schema/list.rb +25 -4
- data/lib/ratatui_ruby/schema/list_item.rb +41 -0
- data/lib/ratatui_ruby/schema/rect.rb +43 -0
- data/lib/ratatui_ruby/schema/style.rb +24 -4
- data/lib/ratatui_ruby/schema/table.rb +21 -3
- data/lib/ratatui_ruby/schema/text.rb +69 -1
- data/lib/ratatui_ruby/scrollbar_state.rb +112 -0
- data/lib/ratatui_ruby/session/autodoc.rb +65 -0
- data/lib/ratatui_ruby/session.rb +22 -7
- data/lib/ratatui_ruby/table_state.rb +90 -0
- data/lib/ratatui_ruby/test_helper/event_injection.rb +169 -0
- data/lib/ratatui_ruby/test_helper/snapshot.rb +390 -0
- data/lib/ratatui_ruby/test_helper/style_assertions.rb +351 -0
- data/lib/ratatui_ruby/test_helper/terminal.rb +127 -0
- data/lib/ratatui_ruby/test_helper/test_doubles.rb +68 -0
- data/lib/ratatui_ruby/test_helper.rb +65 -358
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +42 -19
- data/sig/examples/app_stateful_interaction/app.rbs +33 -0
- data/sig/examples/widget_block_demo/app.rbs +32 -0
- data/sig/examples/{app_map_demo → widget_map_demo}/app.rbs +2 -2
- data/sig/examples/{app_table_select → widget_table_demo}/app.rbs +2 -2
- data/sig/examples/{widget_table_flex → widget_text_width}/app.rbs +2 -3
- data/sig/ratatui_ruby/event.rbs +11 -1
- data/sig/ratatui_ruby/frame.rbs +2 -0
- data/sig/ratatui_ruby/list_state.rbs +13 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +2 -2
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +3 -3
- data/sig/ratatui_ruby/schema/gauge.rbs +2 -2
- data/sig/ratatui_ruby/schema/line_gauge.rbs +2 -2
- data/sig/ratatui_ruby/schema/list.rbs +4 -2
- data/sig/ratatui_ruby/schema/list_item.rbs +10 -0
- data/sig/ratatui_ruby/schema/rect.rbs +3 -0
- data/sig/ratatui_ruby/schema/style.rbs +3 -3
- data/sig/ratatui_ruby/schema/table.rbs +3 -1
- data/sig/ratatui_ruby/schema/text.rbs +8 -6
- data/sig/ratatui_ruby/scrollbar_state.rbs +18 -0
- data/sig/ratatui_ruby/session.rbs +13 -0
- data/sig/ratatui_ruby/table_state.rbs +15 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +16 -0
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +12 -0
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +64 -0
- data/sig/ratatui_ruby/test_helper/terminal.rbs +14 -0
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +22 -0
- data/sig/ratatui_ruby/test_helper.rbs +5 -4
- data/tasks/autodoc/examples.rb +79 -0
- data/tasks/autodoc/inventory.rb +9 -7
- data/tasks/autodoc.rake +11 -5
- data/tasks/bump/changelog.rb +3 -3
- data/tasks/bump/links.rb +67 -0
- data/tasks/sourcehut.rake +61 -21
- data/tasks/terminal_preview/app_screenshot.rb +13 -3
- data/tasks/terminal_preview/saved_screenshot.rb +4 -3
- metadata +111 -37
- data/doc/images/app_table_select.png +0 -0
- data/doc/images/widget_block_padding.png +0 -0
- data/doc/images/widget_block_titles.png +0 -0
- data/doc/images/widget_list_styles.png +0 -0
- data/examples/app_all_events/model/events.rb +0 -180
- data/examples/app_all_events/model/highlight.rb +0 -57
- data/examples/app_all_events/test/snapshots/after_focus_lost.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_focus_regained.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_horizontal_resize.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_key_a.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_key_ctrl_x.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_mouse_click.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_mouse_drag.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_multiple_events.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_paste.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_resize.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_right_click.txt +0 -24
- data/examples/app_all_events/test/snapshots/after_vertical_resize.txt +0 -24
- data/examples/app_all_events/test/snapshots/initial_state.txt +0 -24
- data/examples/app_all_events/view_state.rb +0 -42
- data/examples/app_color_picker/scene.rb +0 -201
- data/examples/widget_block_padding/app.rb +0 -67
- data/examples/widget_block_titles/app.rb +0 -69
- data/examples/widget_list_styles/app.rb +0 -141
- data/examples/widget_table_flex/app.rb +0 -95
- data/sig/examples/widget_block_padding/app.rbs +0 -11
- data/sig/examples/widget_block_titles/app.rbs +0 -11
- data/sig/examples/widget_list_styles/app.rbs +0 -11
- data/tasks/bump/comparison_links.rb +0 -41
- /data/doc/images/{app_map_demo.png → widget_map_demo.png} +0 -0
|
@@ -28,6 +28,8 @@ module RatatuiRuby
|
|
|
28
28
|
# :attr_reader: label
|
|
29
29
|
# Text label to display (optional).
|
|
30
30
|
#
|
|
31
|
+
# Accepts String or Text::Span for rich styling.
|
|
32
|
+
#
|
|
31
33
|
# If nil, it often displays the percentage automatically depending on renderer logic,
|
|
32
34
|
# but explicit labels are preferred.
|
|
33
35
|
|
|
@@ -52,7 +54,7 @@ module RatatuiRuby
|
|
|
52
54
|
#
|
|
53
55
|
# [ratio] Float (0.0 - 1.0).
|
|
54
56
|
# [percent] Integer (0 - 100), alternative to ratio.
|
|
55
|
-
# [label] String (optional).
|
|
57
|
+
# [label] String or Text::Span (optional).
|
|
56
58
|
# [style] Style object for the background (optional).
|
|
57
59
|
# [gauge_style] Style object for the filled bar (optional).
|
|
58
60
|
# [block] Block widget (optional).
|
|
@@ -26,7 +26,7 @@ module RatatuiRuby
|
|
|
26
26
|
|
|
27
27
|
##
|
|
28
28
|
# :attr_reader: label
|
|
29
|
-
# Optional label.
|
|
29
|
+
# Optional label (String or Text::Span for rich styling).
|
|
30
30
|
|
|
31
31
|
##
|
|
32
32
|
# :attr_reader: style
|
|
@@ -55,7 +55,7 @@ module RatatuiRuby
|
|
|
55
55
|
# Creates a new LineGauge.
|
|
56
56
|
#
|
|
57
57
|
# [ratio] Float (0.0 - 1.0).
|
|
58
|
-
# [label] String (optional).
|
|
58
|
+
# [label] String or Text::Span (optional).
|
|
59
59
|
# [style] Style (optional, base style for the gauge).
|
|
60
60
|
# [filled_style] Style.
|
|
61
61
|
# [unfilled_style] Style.
|
|
@@ -27,15 +27,34 @@ module RatatuiRuby
|
|
|
27
27
|
# highlight_style: Style.new(bg: :blue),
|
|
28
28
|
# highlight_symbol: ">> "
|
|
29
29
|
# )
|
|
30
|
-
class List < Data.define(:items, :selected_index, :style, :highlight_style, :highlight_symbol, :repeat_highlight_symbol, :highlight_spacing, :direction, :scroll_padding, :block)
|
|
30
|
+
class List < Data.define(:items, :selected_index, :offset, :style, :highlight_style, :highlight_symbol, :repeat_highlight_symbol, :highlight_spacing, :direction, :scroll_padding, :block)
|
|
31
31
|
##
|
|
32
32
|
# :attr_reader: items
|
|
33
|
-
# The items to display
|
|
33
|
+
# The items to display.
|
|
34
|
+
#
|
|
35
|
+
# Accepts Array of Strings, Text::Spans, Text::Lines, or ListItem objects.
|
|
36
|
+
# For styled individual rows, use ListItem with a style.
|
|
34
37
|
|
|
35
38
|
##
|
|
36
39
|
# :attr_reader: selected_index
|
|
37
40
|
# Index of the active selection (Integer or nil).
|
|
38
41
|
|
|
42
|
+
##
|
|
43
|
+
# :attr_reader: offset
|
|
44
|
+
# Scroll offset (Integer or nil).
|
|
45
|
+
#
|
|
46
|
+
# Controls the viewport's starting position in the list.
|
|
47
|
+
#
|
|
48
|
+
# When +nil+ (default), Ratatui auto-scrolls to keep the selection visible ("natural scrolling").
|
|
49
|
+
#
|
|
50
|
+
# When set, forces the viewport to start at this item index. Use this for:
|
|
51
|
+
# - **Passive scrolling**: Scroll through a log viewer without selecting items.
|
|
52
|
+
# - **Click-to-select math**: Calculate which item index corresponds to a click coordinate.
|
|
53
|
+
#
|
|
54
|
+
# *Important*: When both +offset+ and +selected_index+ are set, Ratatui may still adjust
|
|
55
|
+
# the viewport during rendering to ensure the selection stays visible. Set +selected_index+
|
|
56
|
+
# to +nil+ for fully manual scroll control.
|
|
57
|
+
|
|
39
58
|
##
|
|
40
59
|
# :attr_reader: style
|
|
41
60
|
# Base style for unselected items.
|
|
@@ -76,8 +95,9 @@ module RatatuiRuby
|
|
|
76
95
|
#
|
|
77
96
|
# Integer parameters accept any object responding to +to_int+ or +to_i+ (duck-typed).
|
|
78
97
|
#
|
|
79
|
-
# [items] Array of Strings.
|
|
98
|
+
# [items] Array of Strings, Text::Spans, Text::Lines, or ListItem objects.
|
|
80
99
|
# [selected_index] Numeric (nullable, coerced to Integer).
|
|
100
|
+
# [offset] Numeric (nullable, coerced to Integer). Forces scroll position when set.
|
|
81
101
|
# [style] Style object.
|
|
82
102
|
# [highlight_style] Style object.
|
|
83
103
|
# [highlight_symbol] String (default: <tt>"> "</tt>).
|
|
@@ -86,10 +106,11 @@ module RatatuiRuby
|
|
|
86
106
|
# [direction] Symbol (default: <tt>:top_to_bottom</tt>).
|
|
87
107
|
# [scroll_padding] Numeric (nullable, coerced to Integer, default: <tt>nil</tt>).
|
|
88
108
|
# [block] Block (optional).
|
|
89
|
-
def initialize(items: [], selected_index: nil, style: nil, highlight_style: nil, highlight_symbol: "> ", repeat_highlight_symbol: false, highlight_spacing: :when_selected, direction: :top_to_bottom, scroll_padding: nil, block: nil)
|
|
109
|
+
def initialize(items: [], selected_index: nil, offset: nil, style: nil, highlight_style: nil, highlight_symbol: "> ", repeat_highlight_symbol: false, highlight_spacing: :when_selected, direction: :top_to_bottom, scroll_padding: nil, block: nil)
|
|
90
110
|
super(
|
|
91
111
|
items:,
|
|
92
112
|
selected_index: selected_index.nil? ? nil : Integer(selected_index),
|
|
113
|
+
offset: offset.nil? ? nil : Integer(offset),
|
|
93
114
|
style:,
|
|
94
115
|
highlight_style:,
|
|
95
116
|
highlight_symbol:,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
module RatatuiRuby
|
|
7
|
+
# A styled list item combining content with optional style.
|
|
8
|
+
#
|
|
9
|
+
# By default, List items are strings. For more control over styling individual rows,
|
|
10
|
+
# wrap the content in a ListItem to apply a style specific to that item.
|
|
11
|
+
#
|
|
12
|
+
# The content can be a String, Text::Span, or Text::Line. The style applies to the
|
|
13
|
+
# entire row background.
|
|
14
|
+
#
|
|
15
|
+
# === Examples
|
|
16
|
+
#
|
|
17
|
+
# # Item with red background
|
|
18
|
+
# ListItem.new(content: "Error", style: Style.new(bg: :red))
|
|
19
|
+
#
|
|
20
|
+
# # Item with styled content
|
|
21
|
+
# ListItem.new(
|
|
22
|
+
# content: Text::Span.new(content: "Status: OK", style: Style.new(fg: :green, modifiers: [:bold]))
|
|
23
|
+
# )
|
|
24
|
+
class ListItem < Data.define(:content, :style)
|
|
25
|
+
##
|
|
26
|
+
# :attr_reader: content
|
|
27
|
+
# The content to display (String, Text::Span, or Text::Line).
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# :attr_reader: style
|
|
31
|
+
# The style to apply to the item (optional Style).
|
|
32
|
+
|
|
33
|
+
# Creates a new ListItem.
|
|
34
|
+
#
|
|
35
|
+
# [content] String, Text::Span, or Text::Line.
|
|
36
|
+
# [style] Style object (optional).
|
|
37
|
+
def initialize(content:, style: nil)
|
|
38
|
+
super
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -69,5 +69,48 @@ module RatatuiRuby
|
|
|
69
69
|
def contains?(px, py)
|
|
70
70
|
px >= x && px < x + width && py >= y && py < y + height
|
|
71
71
|
end
|
|
72
|
+
|
|
73
|
+
# Tests whether this rectangle overlaps with another.
|
|
74
|
+
#
|
|
75
|
+
# Essential for determining if a widget is visible within a viewport or clipping area.
|
|
76
|
+
#
|
|
77
|
+
# viewport = Rect.new(x: 0, y: 0, width: 80, height: 24)
|
|
78
|
+
# widget = Rect.new(x: 70, y: 20, width: 20, height: 10)
|
|
79
|
+
# viewport.intersects?(widget) # => true (partial overlap)
|
|
80
|
+
#
|
|
81
|
+
# [other]
|
|
82
|
+
# Another Rect to test against.
|
|
83
|
+
#
|
|
84
|
+
# Returns true if the rectangles overlap.
|
|
85
|
+
def intersects?(other)
|
|
86
|
+
x < other.x + other.width &&
|
|
87
|
+
x + width > other.x &&
|
|
88
|
+
y < other.y + other.height &&
|
|
89
|
+
y + height > other.y
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Returns the overlapping area between this rectangle and another.
|
|
93
|
+
#
|
|
94
|
+
# Essential for calculating visible portions of widgets inside scroll views.
|
|
95
|
+
#
|
|
96
|
+
# viewport = Rect.new(x: 0, y: 0, width: 80, height: 24)
|
|
97
|
+
# widget = Rect.new(x: 70, y: 20, width: 20, height: 10)
|
|
98
|
+
# visible = viewport.intersection(widget)
|
|
99
|
+
# # => Rect(x: 70, y: 20, width: 10, height: 4)
|
|
100
|
+
#
|
|
101
|
+
# [other]
|
|
102
|
+
# Another Rect to intersect with.
|
|
103
|
+
#
|
|
104
|
+
# Returns a new Rect representing the intersection, or +nil+ if no overlap.
|
|
105
|
+
def intersection(other)
|
|
106
|
+
return nil unless intersects?(other)
|
|
107
|
+
|
|
108
|
+
new_x = [x, other.x].max
|
|
109
|
+
new_y = [y, other.y].max
|
|
110
|
+
new_right = [x + width, other.x + other.width].min
|
|
111
|
+
new_bottom = [y + height, other.y + other.height].min
|
|
112
|
+
|
|
113
|
+
Rect.new(x: new_x, y: new_y, width: new_right - new_x, height: new_bottom - new_y)
|
|
114
|
+
end
|
|
72
115
|
end
|
|
73
116
|
end
|
|
@@ -20,18 +20,38 @@ module RatatuiRuby
|
|
|
20
20
|
#
|
|
21
21
|
# # Hex colors
|
|
22
22
|
# Style.new(fg: "#ff00ff")
|
|
23
|
+
#
|
|
24
|
+
# === Supported Colors
|
|
25
|
+
#
|
|
26
|
+
# ==== Integer
|
|
27
|
+
# Represents an indexed color from the Xterm 256-color palette (0-255).
|
|
28
|
+
# * <tt>0</tt>–<tt>15</tt>: Standard and bright ANSI colors.
|
|
29
|
+
# * <tt>16</tt>–<tt>231</tt>: {6x6x6 Color Cube}[https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit].
|
|
30
|
+
# * <tt>232</tt>–<tt>255</tt>: Grayscale ramp.
|
|
31
|
+
#
|
|
32
|
+
# ==== Symbol
|
|
33
|
+
# Represents a named color from the standard ANSI palette. Supported values:
|
|
34
|
+
# * <tt>:black</tt>, <tt>:red</tt>, <tt>:green</tt>, <tt>:yellow</tt>,
|
|
35
|
+
# <tt>:blue</tt>, <tt>:magenta</tt>, <tt>:cyan</tt>, <tt>:gray</tt>
|
|
36
|
+
# * <tt>:dark_gray</tt>, <tt>:light_red</tt>, <tt>:light_green</tt>,
|
|
37
|
+
# <tt>:light_yellow</tt>, <tt>:light_blue</tt>, <tt>:light_magenta</tt>,
|
|
38
|
+
# <tt>:light_cyan</tt>, <tt>:white</tt>
|
|
39
|
+
#
|
|
40
|
+
# ==== String
|
|
41
|
+
# Represents a specific RGB color using a Hex code (<tt>"#RRGGBB"</tt>).
|
|
42
|
+
# Requires a terminal emulator with "True Color" (24-bit color) support.
|
|
23
43
|
class Style < Data.define(:fg, :bg, :modifiers)
|
|
24
44
|
##
|
|
25
45
|
# :attr_reader: fg
|
|
26
46
|
# Foreground color.
|
|
27
47
|
#
|
|
28
|
-
# Symbol (<tt>:red</tt>)
|
|
48
|
+
# Symbol (<tt>:red</tt>), Hex String (<tt>"#ffffff"</tt>), or Integer (0-255).
|
|
29
49
|
|
|
30
50
|
##
|
|
31
51
|
# :attr_reader: bg
|
|
32
52
|
# Background color.
|
|
33
53
|
#
|
|
34
|
-
# Symbol (<tt>:black</tt>)
|
|
54
|
+
# Symbol (<tt>:black</tt>), Hex String (<tt>"#000000"</tt>), or Integer (0-255).
|
|
35
55
|
|
|
36
56
|
##
|
|
37
57
|
# :attr_reader: modifiers
|
|
@@ -42,8 +62,8 @@ module RatatuiRuby
|
|
|
42
62
|
|
|
43
63
|
# Creates a new Style.
|
|
44
64
|
#
|
|
45
|
-
# [fg] Color (Symbol/String).
|
|
46
|
-
# [bg] Color (Symbol/String).
|
|
65
|
+
# [fg] Color (Symbol/String/Integer).
|
|
66
|
+
# [bg] Color (Symbol/String/Integer).
|
|
47
67
|
# [modifiers] Array of Symbols.
|
|
48
68
|
def initialize(fg: nil, bg: nil, modifiers: [])
|
|
49
69
|
super
|
|
@@ -20,7 +20,7 @@ module RatatuiRuby
|
|
|
20
20
|
# Run the interactive demo from the terminal:
|
|
21
21
|
#
|
|
22
22
|
# ruby examples/widget_table_flex/app.rb
|
|
23
|
-
class Table < Data.define(:header, :rows, :widths, :highlight_style, :highlight_symbol, :highlight_spacing, :column_highlight_style, :cell_highlight_style, :selected_row, :selected_column, :block, :footer, :flex, :style, :column_spacing)
|
|
23
|
+
class Table < Data.define(:header, :rows, :widths, :highlight_style, :highlight_symbol, :highlight_spacing, :column_highlight_style, :cell_highlight_style, :selected_row, :selected_column, :offset, :block, :footer, :flex, :style, :column_spacing)
|
|
24
24
|
##
|
|
25
25
|
# :attr_reader: header
|
|
26
26
|
# Header row content (Array of Strings).
|
|
@@ -43,7 +43,7 @@ module RatatuiRuby
|
|
|
43
43
|
|
|
44
44
|
##
|
|
45
45
|
# :attr_reader: highlight_spacing
|
|
46
|
-
# When to show the highlight symbol column (
|
|
46
|
+
# When to show the highlight symbol column (<tt>:always</tt>, <tt>:when_selected</tt>, <tt>:never</tt>).
|
|
47
47
|
|
|
48
48
|
##
|
|
49
49
|
# :attr_reader: column_highlight_style
|
|
@@ -61,6 +61,22 @@ module RatatuiRuby
|
|
|
61
61
|
# :attr_reader: selected_column
|
|
62
62
|
# Index of the selected column (Integer or nil).
|
|
63
63
|
|
|
64
|
+
##
|
|
65
|
+
# :attr_reader: offset
|
|
66
|
+
# Scroll offset (Integer or nil).
|
|
67
|
+
#
|
|
68
|
+
# Controls the viewport's starting row position in the table.
|
|
69
|
+
#
|
|
70
|
+
# When +nil+ (default), Ratatui auto-scrolls to keep the selection visible ("natural scrolling").
|
|
71
|
+
#
|
|
72
|
+
# When set, forces the viewport to start at this row index. Use this for:
|
|
73
|
+
# - **Passive scrolling**: Scroll through a log table without selecting rows.
|
|
74
|
+
# - **Click-to-select math**: Calculate which row index corresponds to a click coordinate.
|
|
75
|
+
#
|
|
76
|
+
# *Important*: When both +offset+ and +selected_row+ are set, Ratatui may still adjust
|
|
77
|
+
# the viewport during rendering to ensure the selection stays visible. Set +selected_row+
|
|
78
|
+
# to +nil+ for fully manual scroll control.
|
|
79
|
+
|
|
64
80
|
##
|
|
65
81
|
# :attr_reader: block
|
|
66
82
|
# Optional wrapping block.
|
|
@@ -93,12 +109,13 @@ module RatatuiRuby
|
|
|
93
109
|
# [cell_highlight_style] Style object.
|
|
94
110
|
# [selected_row] Integer (nullable).
|
|
95
111
|
# [selected_column] Integer (nullable).
|
|
112
|
+
# [offset] Numeric (nullable, coerced to Integer). Forces scroll position when set.
|
|
96
113
|
# [block] Block (optional).
|
|
97
114
|
# [footer] Array of strings/paragraphs (optional).
|
|
98
115
|
# [flex] Symbol (optional, default: <tt>:legacy</tt>).
|
|
99
116
|
# [style] Style object or Hash (optional).
|
|
100
117
|
# [column_spacing] Integer (optional, default: 1).
|
|
101
|
-
def initialize(header: nil, rows: [], widths: [], highlight_style: nil, highlight_symbol: "> ", highlight_spacing: :when_selected, column_highlight_style: nil, cell_highlight_style: nil, selected_row: nil, selected_column: nil, block: nil, footer: nil, flex: :legacy, style: nil, column_spacing: 1)
|
|
118
|
+
def initialize(header: nil, rows: [], widths: [], 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)
|
|
102
119
|
super(
|
|
103
120
|
header:,
|
|
104
121
|
rows:,
|
|
@@ -110,6 +127,7 @@ module RatatuiRuby
|
|
|
110
127
|
cell_highlight_style:,
|
|
111
128
|
selected_row: selected_row.nil? ? nil : Integer(selected_row),
|
|
112
129
|
selected_column: selected_column.nil? ? nil : Integer(selected_column),
|
|
130
|
+
offset: offset.nil? ? nil : Integer(offset),
|
|
113
131
|
block:,
|
|
114
132
|
footer:,
|
|
115
133
|
flex:,
|
|
@@ -4,8 +4,42 @@
|
|
|
4
4
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
|
|
6
6
|
module RatatuiRuby
|
|
7
|
-
# Namespace for rich text components (Span and
|
|
7
|
+
# Namespace for rich text components (Span, Line) and text utilities.
|
|
8
8
|
# Distinct from canvas shapes and other Line usages.
|
|
9
|
+
#
|
|
10
|
+
# == Text Measurement
|
|
11
|
+
#
|
|
12
|
+
# The Text module provides a utility method for calculating the display width
|
|
13
|
+
# of strings in terminal cells. This accounts for unicode complexity:
|
|
14
|
+
#
|
|
15
|
+
# - ASCII characters: 1 cell each
|
|
16
|
+
# - CJK (Chinese, Japanese, Korean) characters: 2 cells each (full-width)
|
|
17
|
+
# - Emoji: typically 2 cells each (varies by terminal)
|
|
18
|
+
# - Combining marks: 0 cells (zero-width)
|
|
19
|
+
#
|
|
20
|
+
# This is essential for layout calculations in TUI applications, where you need to know
|
|
21
|
+
# how much space a string will occupy on the screen, not just its byte or character length.
|
|
22
|
+
#
|
|
23
|
+
# === Use Cases
|
|
24
|
+
#
|
|
25
|
+
# - Auto-sizing widgets (Button, Badge) that fit their content
|
|
26
|
+
# - Calculating padding or centering for text alignment
|
|
27
|
+
# - Building responsive layouts that adapt to content width
|
|
28
|
+
# - Measuring text for scrolling or truncation logic
|
|
29
|
+
#
|
|
30
|
+
# === Examples
|
|
31
|
+
#
|
|
32
|
+
# # Simple ASCII text
|
|
33
|
+
# RatatuiRuby::Text.width("Hello") # => 5
|
|
34
|
+
#
|
|
35
|
+
# # With emoji
|
|
36
|
+
# RatatuiRuby::Text.width("Hello 👍") # => 8 (5 + space + 2-width emoji)
|
|
37
|
+
#
|
|
38
|
+
# # With CJK characters
|
|
39
|
+
# RatatuiRuby::Text.width("你好") # => 4 (each CJK char is 2 cells)
|
|
40
|
+
#
|
|
41
|
+
# # Mixed content
|
|
42
|
+
# RatatuiRuby::Text.width("Hi 你好 👍") # => 11 (2 + space + 4 + space + 2)
|
|
9
43
|
module Text
|
|
10
44
|
# A styled string fragment.
|
|
11
45
|
#
|
|
@@ -86,5 +120,39 @@ module RatatuiRuby
|
|
|
86
120
|
new(spans: [Span.new(content:, style: nil)], alignment:)
|
|
87
121
|
end
|
|
88
122
|
end
|
|
123
|
+
|
|
124
|
+
##
|
|
125
|
+
# :method: width
|
|
126
|
+
# :call-seq: width(string) -> Integer
|
|
127
|
+
#
|
|
128
|
+
# Calculates the display width of a string in terminal cells.
|
|
129
|
+
#
|
|
130
|
+
# 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.
|
|
131
|
+
#
|
|
132
|
+
# 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.
|
|
133
|
+
#
|
|
134
|
+
# This method returns the true display width. Use it to auto-size widgets, calculate padding, center text, or build responsive layouts.
|
|
135
|
+
#
|
|
136
|
+
# === Examples
|
|
137
|
+
#
|
|
138
|
+
# RatatuiRuby::Text.width("Hello") # => 5 (5 ASCII chars × 1 cell)
|
|
139
|
+
#
|
|
140
|
+
# RatatuiRuby::Text.width("你好") # => 4 (2 CJK chars × 2 cells)
|
|
141
|
+
#
|
|
142
|
+
# RatatuiRuby::Text.width("Hello 👍") # => 8 (5 ASCII + 1 space + 1 emoji × 2)
|
|
143
|
+
#
|
|
144
|
+
# # In the Session DSL (easier)
|
|
145
|
+
# RatatuiRuby.run do |tui|
|
|
146
|
+
# width = tui.text_width("Hello 👍")
|
|
147
|
+
# end
|
|
148
|
+
#
|
|
149
|
+
# [string] String to measure (String or object convertible to String)
|
|
150
|
+
# Returns: Integer (number of terminal cells the string occupies)
|
|
151
|
+
# Raises: TypeError if the argument is not a String
|
|
152
|
+
#
|
|
153
|
+
# (Native method implemented in Rust)
|
|
154
|
+
def self.width(string)
|
|
155
|
+
RatatuiRuby._text_width(string)
|
|
156
|
+
end
|
|
89
157
|
end
|
|
90
158
|
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
module RatatuiRuby
|
|
7
|
+
# Mutable state object for Scrollbar widgets.
|
|
8
|
+
#
|
|
9
|
+
# When using {Frame#render_stateful_widget}, the State object is the
|
|
10
|
+
# *single source of truth* for position and content length. Widget
|
|
11
|
+
# properties (+position+, +content_length+) are *ignored* in stateful mode.
|
|
12
|
+
#
|
|
13
|
+
# == Example
|
|
14
|
+
#
|
|
15
|
+
# @scrollbar_state = RatatuiRuby::ScrollbarState.new(100)
|
|
16
|
+
# @scrollbar_state.position = 25
|
|
17
|
+
#
|
|
18
|
+
# RatatuiRuby.draw do |frame|
|
|
19
|
+
# scrollbar = RatatuiRuby::Scrollbar.new(orientation: :vertical_right)
|
|
20
|
+
# frame.render_stateful_widget(scrollbar, frame.area, @scrollbar_state)
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
class ScrollbarState
|
|
24
|
+
##
|
|
25
|
+
# :method: new
|
|
26
|
+
# :call-seq: new(content_length) -> ScrollbarState
|
|
27
|
+
#
|
|
28
|
+
# Creates a new ScrollbarState with the given content length.
|
|
29
|
+
#
|
|
30
|
+
# (Native method implemented in Rust)
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# :method: position
|
|
34
|
+
# :call-seq: position() -> Integer
|
|
35
|
+
#
|
|
36
|
+
# Returns the current scroll position.
|
|
37
|
+
#
|
|
38
|
+
# (Native method implemented in Rust)
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# :method: position=
|
|
42
|
+
# :call-seq: position=(value) -> Integer
|
|
43
|
+
#
|
|
44
|
+
# Sets the current scroll position.
|
|
45
|
+
#
|
|
46
|
+
# (Native method implemented in Rust)
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# :method: content_length
|
|
50
|
+
# :call-seq: content_length() -> Integer
|
|
51
|
+
#
|
|
52
|
+
# Returns the total content length.
|
|
53
|
+
#
|
|
54
|
+
# (Native method implemented in Rust)
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
# :method: content_length=
|
|
58
|
+
# :call-seq: content_length=(value) -> Integer
|
|
59
|
+
#
|
|
60
|
+
# Sets the total content length.
|
|
61
|
+
#
|
|
62
|
+
# (Native method implemented in Rust)
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# :method: viewport_content_length
|
|
66
|
+
# :call-seq: viewport_content_length() -> Integer
|
|
67
|
+
#
|
|
68
|
+
# Returns the viewport content length.
|
|
69
|
+
#
|
|
70
|
+
# (Native method implemented in Rust)
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# :method: viewport_content_length=
|
|
74
|
+
# :call-seq: viewport_content_length=(value) -> Integer
|
|
75
|
+
#
|
|
76
|
+
# Sets the viewport content length.
|
|
77
|
+
#
|
|
78
|
+
# (Native method implemented in Rust)
|
|
79
|
+
|
|
80
|
+
##
|
|
81
|
+
# :method: first
|
|
82
|
+
# :call-seq: first() -> nil
|
|
83
|
+
#
|
|
84
|
+
# Scrolls to the first position.
|
|
85
|
+
#
|
|
86
|
+
# (Native method implemented in Rust)
|
|
87
|
+
|
|
88
|
+
##
|
|
89
|
+
# :method: last
|
|
90
|
+
# :call-seq: last() -> nil
|
|
91
|
+
#
|
|
92
|
+
# Scrolls to the last position.
|
|
93
|
+
#
|
|
94
|
+
# (Native method implemented in Rust)
|
|
95
|
+
|
|
96
|
+
##
|
|
97
|
+
# :method: next
|
|
98
|
+
# :call-seq: next() -> nil
|
|
99
|
+
#
|
|
100
|
+
# Scrolls to the next position.
|
|
101
|
+
#
|
|
102
|
+
# (Native method implemented in Rust)
|
|
103
|
+
|
|
104
|
+
##
|
|
105
|
+
# :method: prev
|
|
106
|
+
# :call-seq: prev() -> nil
|
|
107
|
+
#
|
|
108
|
+
# Scrolls to the previous position.
|
|
109
|
+
#
|
|
110
|
+
# (Native method implemented in Rust)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -26,6 +26,11 @@ module RatatuiRuby
|
|
|
26
26
|
#
|
|
27
27
|
# Delegates to RatatuiRuby._tabs_width.
|
|
28
28
|
#
|
|
29
|
+
# :method: _text_width
|
|
30
|
+
# :call-seq: _text_width(*args, **kwargs, &block)
|
|
31
|
+
#
|
|
32
|
+
# Delegates to RatatuiRuby._text_width.
|
|
33
|
+
#
|
|
29
34
|
# :method: clear_events
|
|
30
35
|
# :call-seq: clear_events(*args, **kwargs, &block)
|
|
31
36
|
#
|
|
@@ -223,6 +228,16 @@ module RatatuiRuby
|
|
|
223
228
|
#
|
|
224
229
|
# Factory for RatatuiRuby::Dataset.new.
|
|
225
230
|
#
|
|
231
|
+
# :method: draw_cell
|
|
232
|
+
# :call-seq: draw_cell(*args, **kwargs, &block)
|
|
233
|
+
#
|
|
234
|
+
# Helper for RatatuiRuby::Draw.cell.
|
|
235
|
+
#
|
|
236
|
+
# :method: draw_string
|
|
237
|
+
# :call-seq: draw_string(*args, **kwargs, &block)
|
|
238
|
+
#
|
|
239
|
+
# Helper for RatatuiRuby::Draw.string.
|
|
240
|
+
#
|
|
226
241
|
# :method: draw_cell_cmd
|
|
227
242
|
# :call-seq: draw_cell_cmd(*args, **kwargs, &block)
|
|
228
243
|
#
|
|
@@ -238,6 +253,16 @@ module RatatuiRuby
|
|
|
238
253
|
#
|
|
239
254
|
# Factory for RatatuiRuby::Error.new.
|
|
240
255
|
#
|
|
256
|
+
# :method: error_safety
|
|
257
|
+
# :call-seq: error_safety(*args, **kwargs, &block)
|
|
258
|
+
#
|
|
259
|
+
# Factory for RatatuiRuby::Error::Safety.new.
|
|
260
|
+
#
|
|
261
|
+
# :method: error_terminal
|
|
262
|
+
# :call-seq: error_terminal(*args, **kwargs, &block)
|
|
263
|
+
#
|
|
264
|
+
# Factory for RatatuiRuby::Error::Terminal.new.
|
|
265
|
+
#
|
|
241
266
|
# :method: event
|
|
242
267
|
# :call-seq: event(*args, **kwargs, &block)
|
|
243
268
|
#
|
|
@@ -313,6 +338,21 @@ module RatatuiRuby
|
|
|
313
338
|
#
|
|
314
339
|
# Factory for RatatuiRuby::List.new.
|
|
315
340
|
#
|
|
341
|
+
# :method: list_item
|
|
342
|
+
# :call-seq: list_item(*args, **kwargs, &block)
|
|
343
|
+
#
|
|
344
|
+
# Factory for RatatuiRuby::ListItem.new.
|
|
345
|
+
#
|
|
346
|
+
# :method: list_state
|
|
347
|
+
# :call-seq: list_state(*args, **kwargs, &block)
|
|
348
|
+
#
|
|
349
|
+
# Factory for RatatuiRuby::ListState.new.
|
|
350
|
+
#
|
|
351
|
+
# :method: list_state_new
|
|
352
|
+
# :call-seq: list_state_new(*args, **kwargs, &block)
|
|
353
|
+
#
|
|
354
|
+
# Helper for RatatuiRuby::ListState.new.
|
|
355
|
+
#
|
|
316
356
|
# :method: overlay
|
|
317
357
|
# :call-seq: overlay(*args, **kwargs, &block)
|
|
318
358
|
#
|
|
@@ -348,6 +388,16 @@ module RatatuiRuby
|
|
|
348
388
|
#
|
|
349
389
|
# Factory for RatatuiRuby::Scrollbar.new.
|
|
350
390
|
#
|
|
391
|
+
# :method: scrollbar_state
|
|
392
|
+
# :call-seq: scrollbar_state(*args, **kwargs, &block)
|
|
393
|
+
#
|
|
394
|
+
# Factory for RatatuiRuby::ScrollbarState.new.
|
|
395
|
+
#
|
|
396
|
+
# :method: scrollbar_state_new
|
|
397
|
+
# :call-seq: scrollbar_state_new(*args, **kwargs, &block)
|
|
398
|
+
#
|
|
399
|
+
# Helper for RatatuiRuby::ScrollbarState.new.
|
|
400
|
+
#
|
|
351
401
|
# :method: shape_circle
|
|
352
402
|
# :call-seq: shape_circle(*args, **kwargs, &block)
|
|
353
403
|
#
|
|
@@ -398,11 +448,26 @@ module RatatuiRuby
|
|
|
398
448
|
#
|
|
399
449
|
# Factory for RatatuiRuby::Table.new.
|
|
400
450
|
#
|
|
451
|
+
# :method: table_state
|
|
452
|
+
# :call-seq: table_state(*args, **kwargs, &block)
|
|
453
|
+
#
|
|
454
|
+
# Factory for RatatuiRuby::TableState.new.
|
|
455
|
+
#
|
|
456
|
+
# :method: table_state_new
|
|
457
|
+
# :call-seq: table_state_new(*args, **kwargs, &block)
|
|
458
|
+
#
|
|
459
|
+
# Helper for RatatuiRuby::TableState.new.
|
|
460
|
+
#
|
|
401
461
|
# :method: tabs
|
|
402
462
|
# :call-seq: tabs(*args, **kwargs, &block)
|
|
403
463
|
#
|
|
404
464
|
# Factory for RatatuiRuby::Tabs.new.
|
|
405
465
|
#
|
|
466
|
+
# :method: text_width
|
|
467
|
+
# :call-seq: text_width(*args, **kwargs, &block)
|
|
468
|
+
#
|
|
469
|
+
# Helper for RatatuiRuby::Text.width.
|
|
470
|
+
#
|
|
406
471
|
# :method: text_line
|
|
407
472
|
# :call-seq: text_line(*args, **kwargs, &block)
|
|
408
473
|
#
|
data/lib/ratatui_ruby/session.rb
CHANGED
|
@@ -12,6 +12,14 @@ module RatatuiRuby
|
|
|
12
12
|
#
|
|
13
13
|
# Use it within <tt>RatatuiRuby.run</tt> to build your interface cleanly.
|
|
14
14
|
#
|
|
15
|
+
# == Thread/Ractor Safety
|
|
16
|
+
#
|
|
17
|
+
# Session is an *I/O handle*, not a data object. It has side effects (draw,
|
|
18
|
+
# poll_event) and is intentionally *not* Ractor-shareable. Caching it in
|
|
19
|
+
# instance variables (<tt>@tui = tui</tt>) during your application's run loop
|
|
20
|
+
# is fine. However, do not include it in immutable TEA Models/Messages or
|
|
21
|
+
# pass it to other Ractors.
|
|
22
|
+
#
|
|
15
23
|
# == Available Methods
|
|
16
24
|
#
|
|
17
25
|
# The session dynamically defines factory methods for all RatatuiRuby constants.
|
|
@@ -40,6 +48,7 @@ module RatatuiRuby
|
|
|
40
48
|
#
|
|
41
49
|
# * <tt>text_span(...)</tt> -> <tt>RatatuiRuby::Text::Span.new(...)</tt>
|
|
42
50
|
# * <tt>text_line(...)</tt> -> <tt>RatatuiRuby::Text::Line.new(...)</tt>
|
|
51
|
+
# * <tt>text_width(string)</tt> -> <tt>RatatuiRuby::Text.width(string)</tt>
|
|
43
52
|
#
|
|
44
53
|
# === Examples
|
|
45
54
|
#
|
|
@@ -123,15 +132,21 @@ module RatatuiRuby
|
|
|
123
132
|
define_method(method_name) do |*args, **kwargs, &block|
|
|
124
133
|
const.new(*args, **kwargs, &block)
|
|
125
134
|
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# 2. Singleton Method Helpers (for both Classes and Modules)
|
|
138
|
+
# e.g. Layout.split -> layout_split
|
|
139
|
+
# e.g. Text.width -> text_width
|
|
140
|
+
const.singleton_methods(false).each do |class_method|
|
|
141
|
+
parent_prefix = const_name.to_s
|
|
142
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
143
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
144
|
+
.downcase
|
|
126
145
|
|
|
127
|
-
|
|
128
|
-
# e.g. Layout.split -> layout_split
|
|
129
|
-
const.singleton_methods(false).each do |class_method|
|
|
130
|
-
session_method_name = "#{method_name}_#{class_method}"
|
|
146
|
+
session_method_name = "#{parent_prefix}_#{class_method}"
|
|
131
147
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
end
|
|
148
|
+
define_method(session_method_name) do |*args, **kwargs, &block|
|
|
149
|
+
const.public_send(class_method, *args, **kwargs, &block)
|
|
135
150
|
end
|
|
136
151
|
end
|
|
137
152
|
|