ratatui_ruby 0.5.0 → 0.7.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 +10 -4
- data/CHANGELOG.md +79 -7
- data/README.md +37 -5
- data/REUSE.toml +2 -7
- data/doc/application_architecture.md +96 -22
- data/doc/application_testing.md +76 -30
- data/doc/contributors/architectural_overhaul/chat_conversations.md +4952 -0
- data/doc/contributors/architectural_overhaul/implementation_plan.md +60 -0
- data/doc/contributors/architectural_overhaul/task.md +37 -0
- data/doc/contributors/design/ruby_frontend.md +288 -56
- data/doc/contributors/design/rust_backend.md +349 -54
- data/doc/contributors/developing_examples.md +134 -49
- data/doc/contributors/index.md +7 -5
- data/doc/contributors/v1.0.0_blockers.md +1729 -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/index.md +11 -6
- data/doc/interactive_design.md +2 -2
- data/doc/quickstart.md +127 -165
- data/doc/terminal_limitations.md +92 -0
- data/doc/v0.7.0_migration.md +236 -0
- data/doc/why.md +93 -0
- data/examples/app_all_events/README.md +47 -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 +9 -9
- data/examples/app_all_events/view/controls_view.rb +9 -7
- data/examples/app_all_events/view/counts_view.rb +13 -9
- data/examples/app_all_events/view/live_view.rb +9 -8
- data/examples/app_all_events/view/log_view.rb +11 -16
- data/examples/app_color_picker/README.md +84 -42
- 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 +49 -0
- data/examples/app_login_form/app.rb +2 -3
- data/examples/app_stateful_interaction/README.md +33 -0
- data/examples/app_stateful_interaction/app.rb +272 -0
- data/examples/timeout_demo.rb +43 -0
- data/examples/verify_quickstart_dsl/README.md +49 -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 +10 -4
- 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 +50 -0
- data/examples/widget_barchart_demo/app.rb +5 -5
- data/examples/widget_block_demo/README.md +36 -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_calendar_demo/app.rb +5 -1
- 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 +4 -4
- data/examples/widget_overlay_demo/README.md +36 -0
- 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_logo_demo/app.rb +1 -1
- 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_render/app.rb +3 -3
- 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 +65 -12
- 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 +113 -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 +116 -3
- data/ext/ratatui_ruby/src/lib.rs +37 -6
- data/ext/ratatui_ruby/src/rendering.rs +22 -21
- 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 +13 -4
- data/ext/ratatui_ruby/src/widgets/barchart.rs +24 -6
- data/ext/ratatui_ruby/src/widgets/canvas.rs +5 -5
- 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 +191 -34
- data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
- data/lib/ratatui_ruby/buffer/cell.rb +168 -0
- data/lib/ratatui_ruby/buffer.rb +15 -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 +100 -4
- data/lib/ratatui_ruby/layout/constraint.rb +95 -0
- data/lib/ratatui_ruby/layout/layout.rb +106 -0
- data/lib/ratatui_ruby/layout/rect.rb +118 -0
- data/lib/ratatui_ruby/layout.rb +19 -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/layout.rb +1 -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/row.rb +66 -0
- data/lib/ratatui_ruby/schema/style.rb +24 -4
- data/lib/ratatui_ruby/schema/table.rb +29 -11
- data/lib/ratatui_ruby/schema/text.rb +96 -3
- data/lib/ratatui_ruby/scrollbar_state.rb +112 -0
- data/lib/ratatui_ruby/style/style.rb +81 -0
- data/lib/ratatui_ruby/style.rb +15 -0
- 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 +414 -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/tui/buffer_factories.rb +20 -0
- data/lib/ratatui_ruby/tui/canvas_factories.rb +44 -0
- data/lib/ratatui_ruby/tui/core.rb +38 -0
- data/lib/ratatui_ruby/tui/layout_factories.rb +74 -0
- data/lib/ratatui_ruby/tui/state_factories.rb +33 -0
- data/lib/ratatui_ruby/tui/style_factories.rb +20 -0
- data/lib/ratatui_ruby/tui/text_factories.rb +44 -0
- data/lib/ratatui_ruby/tui/widget_factories.rb +195 -0
- data/lib/ratatui_ruby/tui.rb +75 -0
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +47 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +25 -0
- data/lib/ratatui_ruby/widgets/bar_chart.rb +239 -0
- data/lib/ratatui_ruby/widgets/block.rb +192 -0
- data/lib/ratatui_ruby/widgets/calendar.rb +84 -0
- data/lib/ratatui_ruby/widgets/canvas.rb +231 -0
- data/lib/ratatui_ruby/widgets/cell.rb +47 -0
- data/lib/ratatui_ruby/widgets/center.rb +59 -0
- data/lib/ratatui_ruby/widgets/chart.rb +185 -0
- data/lib/ratatui_ruby/widgets/clear.rb +54 -0
- data/lib/ratatui_ruby/widgets/cursor.rb +42 -0
- data/lib/ratatui_ruby/widgets/gauge.rb +72 -0
- data/lib/ratatui_ruby/widgets/line_gauge.rb +80 -0
- data/lib/ratatui_ruby/widgets/list.rb +127 -0
- data/lib/ratatui_ruby/widgets/list_item.rb +43 -0
- data/lib/ratatui_ruby/widgets/overlay.rb +43 -0
- data/lib/ratatui_ruby/widgets/paragraph.rb +99 -0
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +31 -0
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +36 -0
- data/lib/ratatui_ruby/widgets/row.rb +68 -0
- data/lib/ratatui_ruby/widgets/scrollbar.rb +143 -0
- data/lib/ratatui_ruby/widgets/shape/label.rb +68 -0
- data/lib/ratatui_ruby/widgets/sparkline.rb +134 -0
- data/lib/ratatui_ruby/widgets/table.rb +141 -0
- data/lib/ratatui_ruby/widgets/tabs.rb +85 -0
- data/lib/ratatui_ruby/widgets.rb +40 -0
- data/lib/ratatui_ruby.rb +64 -57
- data/sig/examples/app_all_events/view.rbs +1 -1
- data/sig/examples/app_all_events/view_state.rbs +1 -1
- 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/row.rbs +22 -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 +9 -6
- data/sig/ratatui_ruby/scrollbar_state.rbs +18 -0
- data/sig/ratatui_ruby/session.rbs +41 -48
- 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/sig/ratatui_ruby/tui/buffer_factories.rbs +10 -0
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +14 -0
- data/sig/ratatui_ruby/tui/core.rbs +14 -0
- data/sig/ratatui_ruby/tui/layout_factories.rbs +19 -0
- data/sig/ratatui_ruby/tui/state_factories.rbs +12 -0
- data/sig/ratatui_ruby/tui/style_factories.rbs +10 -0
- data/sig/ratatui_ruby/tui/text_factories.rbs +14 -0
- data/sig/ratatui_ruby/tui/widget_factories.rbs +39 -0
- data/sig/ratatui_ruby/tui.rbs +19 -0
- data/tasks/autodoc/examples.rb +79 -0
- data/tasks/autodoc.rake +7 -35
- data/tasks/bump/changelog.rb +3 -3
- data/tasks/bump/links.rb +67 -0
- data/tasks/sourcehut.rake +64 -21
- data/tasks/terminal_preview/app_screenshot.rb +13 -3
- data/tasks/terminal_preview/saved_screenshot.rb +4 -3
- metadata +169 -48
- data/doc/contributors/dwim_dx.md +0 -366
- data/doc/images/app_analytics.png +0 -0
- data/doc/images/app_custom_widget.png +0 -0
- data/doc/images/app_mouse_events.png +0 -0
- 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/doc/images/widget_table_flex.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/lib/ratatui_ruby/session/autodoc.rb +0 -417
- data/lib/ratatui_ruby/session.rb +0 -163
- 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/autodoc/inventory.rb +0 -61
- data/tasks/autodoc/notice.rb +0 -26
- data/tasks/autodoc/rbs.rb +0 -38
- data/tasks/autodoc/rdoc.rb +0 -45
- data/tasks/bump/comparison_links.rb +0 -41
- /data/doc/images/{app_map_demo.png → widget_map_demo.png} +0 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Migrating to v0.7.0
|
|
7
|
+
|
|
8
|
+
v0.7.0 restructures the library to align with upstream Ratatui. For most users, this is a non-breaking change. For some, it is breaking.
|
|
9
|
+
|
|
10
|
+
## Are You Affected?
|
|
11
|
+
|
|
12
|
+
**If your code looks like this, you're fine:**
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
RatatuiRuby.run do |tui|
|
|
16
|
+
tui.draw tui.paragraph(text: "Hello", block: tui.block(title: "Title"))
|
|
17
|
+
event = tui.poll_event
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The TUI API method names are unchanged. Your application works without modification.
|
|
22
|
+
|
|
23
|
+
**If your code uses `highlight_style:` on Tables, rename it:**
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
# Before (v0.6.0)
|
|
27
|
+
tui.table(rows: [...], highlight_style: tui.style(fg: :yellow))
|
|
28
|
+
|
|
29
|
+
# After (v0.7.0)
|
|
30
|
+
tui.table(rows: [...], row_highlight_style: tui.style(fg: :yellow))
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This change aligns with Ratatui's API naming convention.
|
|
34
|
+
|
|
35
|
+
**If your code instantiates classes directly, you have work to do:**
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
# These lines break in v0.7.0
|
|
39
|
+
paragraph = RatatuiRuby::Paragraph.new(text: "Hello")
|
|
40
|
+
style = RatatuiRuby::Style.new(fg: :red)
|
|
41
|
+
rect = RatatuiRuby::Rect.new(x: 0, y: 0, width: 10, height: 5)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The old flat namespace no longer exists. Classes moved into modules.
|
|
45
|
+
|
|
46
|
+
## Option 1: Use the TUI API (Recommended)
|
|
47
|
+
|
|
48
|
+
Switch to the TUI API. It hides namespace verbosity and provides IDE autocomplete.
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
RatatuiRuby.run do |tui|
|
|
52
|
+
# All these work exactly as before
|
|
53
|
+
paragraph = tui.paragraph(text: "Hello")
|
|
54
|
+
style = tui.style(fg: :red)
|
|
55
|
+
rect = tui.rect(x: 0, y: 0, width: 10, height: 5)
|
|
56
|
+
constraint = tui.constraint_length(20)
|
|
57
|
+
|
|
58
|
+
# New in v0.7.0
|
|
59
|
+
cell = tui.table_cell(content: "Error", style: tui.style(bg: :red))
|
|
60
|
+
row = tui.table_row(cells: ["A", "B", "C"], style: tui.style(bg: :dark_gray))
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Option 2: Update to New Namespaces
|
|
65
|
+
|
|
66
|
+
If you prefer direct class instantiation, update to the new paths:
|
|
67
|
+
|
|
68
|
+
| Before | After |
|
|
69
|
+
|--------|-------|
|
|
70
|
+
| `RatatuiRuby::Rect` | `RatatuiRuby::Layout::Rect` |
|
|
71
|
+
| `RatatuiRuby::Constraint` | `RatatuiRuby::Layout::Constraint` |
|
|
72
|
+
| `RatatuiRuby::Layout` | `RatatuiRuby::Layout::Layout` |
|
|
73
|
+
| `RatatuiRuby::Style` | `RatatuiRuby::Style::Style` |
|
|
74
|
+
| `RatatuiRuby::Paragraph` | `RatatuiRuby::Widgets::Paragraph` |
|
|
75
|
+
| `RatatuiRuby::Block` | `RatatuiRuby::Widgets::Block` |
|
|
76
|
+
| `RatatuiRuby::Table` | `RatatuiRuby::Widgets::Table` |
|
|
77
|
+
| `RatatuiRuby::List` | `RatatuiRuby::Widgets::List` |
|
|
78
|
+
| `RatatuiRuby::Cell` | `RatatuiRuby::Buffer::Cell` |
|
|
79
|
+
| *(all other widgets)* | `RatatuiRuby::Widgets::*` |
|
|
80
|
+
|
|
81
|
+
### Bulk Migration
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
find . -name "*.rb" -exec sed -i '' \
|
|
85
|
+
's/RatatuiRuby::Rect/RatatuiRuby::Layout::Rect/g; \
|
|
86
|
+
s/RatatuiRuby::Constraint\./RatatuiRuby::Layout::Constraint./g; \
|
|
87
|
+
s/RatatuiRuby::Paragraph\.new/RatatuiRuby::Widgets::Paragraph.new/g; \
|
|
88
|
+
s/RatatuiRuby::Block\.new/RatatuiRuby::Widgets::Block.new/g; \
|
|
89
|
+
s/RatatuiRuby::List\.new/RatatuiRuby::Widgets::List.new/g; \
|
|
90
|
+
s/RatatuiRuby::Table\.new/RatatuiRuby::Widgets::Table.new/g; \
|
|
91
|
+
s/RatatuiRuby::Style\.new/RatatuiRuby::Style::Style.new/g; \
|
|
92
|
+
s/RatatuiRuby::Session/RatatuiRuby::TUI/g; \
|
|
93
|
+
s/highlight_style:/row_highlight_style:/g' {} \;
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Session → TUI Rename
|
|
97
|
+
|
|
98
|
+
The `Session` class is now `TUI`. If you reference it directly:
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
# Before
|
|
102
|
+
tui = RatatuiRuby::Session.new
|
|
103
|
+
|
|
104
|
+
# After
|
|
105
|
+
tui = RatatuiRuby::TUI.new
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Most users never reference the class directly. The `|tui|` block parameter works unchanged.
|
|
109
|
+
|
|
110
|
+
## Table: highlight_style → row_highlight_style
|
|
111
|
+
|
|
112
|
+
The `highlight_style:` parameter on Table is now `row_highlight_style:`. This aligns with Ratatui's naming convention where `row_highlight_style`, `column_highlight_style`, and `cell_highlight_style` form a consistent trio.
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
# Before (v0.6.0)
|
|
116
|
+
tui.table(
|
|
117
|
+
rows: data,
|
|
118
|
+
highlight_style: tui.style(fg: :yellow)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# After (v0.7.0)
|
|
122
|
+
tui.table(
|
|
123
|
+
rows: data,
|
|
124
|
+
row_highlight_style: tui.style(fg: :yellow)
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Text::Line style Field
|
|
129
|
+
|
|
130
|
+
`Text::Line` now accepts a `style:` parameter for line-level styling. This matches Ratatui's `Line` struct.
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
# New in v0.7.0: Line-level styling
|
|
134
|
+
line = tui.text_line(
|
|
135
|
+
spans: [tui.text_span(content: "Hello")],
|
|
136
|
+
style: tui.style(bg: :dark_gray) # Applied to entire line
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Existing code without `style:` continues to work unchanged.
|
|
141
|
+
|
|
142
|
+
## New Table Cell and Row Classes
|
|
143
|
+
|
|
144
|
+
v0.7.0 adds `Widgets::Cell` and `Widgets::Row` for table construction with per-cell styling:
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
table = tui.table(
|
|
148
|
+
rows: [
|
|
149
|
+
tui.table_row(
|
|
150
|
+
cells: [
|
|
151
|
+
tui.table_cell(content: "Name", style: tui.style(fg: :blue)),
|
|
152
|
+
"Value"
|
|
153
|
+
],
|
|
154
|
+
style: tui.style(bg: :dark_gray)
|
|
155
|
+
)
|
|
156
|
+
],
|
|
157
|
+
widths: [tui.constraint_length(20), tui.constraint_fill]
|
|
158
|
+
)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Buffer::Cell vs Widgets::Cell
|
|
162
|
+
|
|
163
|
+
Two `Cell` classes now exist:
|
|
164
|
+
|
|
165
|
+
- **`Buffer::Cell`** — Terminal cell for inspection (returned by `get_cell_at`)
|
|
166
|
+
- **`Widgets::Cell`** — Table cell for construction (content + style wrapper)
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
# Buffer inspection (unchanged)
|
|
170
|
+
cell = RatatuiRuby.get_cell_at(0, 0) # Returns Buffer::Cell
|
|
171
|
+
cell.char # => "X"
|
|
172
|
+
cell.fg # => :red
|
|
173
|
+
|
|
174
|
+
# Table cell construction (new)
|
|
175
|
+
cell = tui.table_cell(content: "Error", style: tui.style(bg: :red))
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Why This Change?
|
|
179
|
+
|
|
180
|
+
The old flat namespace caused name collisions (`Cell` for buffers vs. tables) and diverged from Ratatui's module structure. The new hierarchy:
|
|
181
|
+
|
|
182
|
+
- Maps 1:1 to Ratatui documentation
|
|
183
|
+
- Prevents future collisions
|
|
184
|
+
- Enables IDE autocomplete via explicit TUI methods
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## For LLMs
|
|
189
|
+
|
|
190
|
+
Copy the following prompt to your AI assistant to help migrate your `ratatui_ruby` application from v0.6.0 to v0.7.0.
|
|
191
|
+
|
|
192
|
+
````markdown
|
|
193
|
+
I'm migrating a Ruby TUI application from `ratatui_ruby` v0.6.0 to v0.7.0. The library restructured its namespaces. Apply these transformations:
|
|
194
|
+
|
|
195
|
+
**Namespace Changes:**
|
|
196
|
+
- `RatatuiRuby::Rect` → `RatatuiRuby::Layout::Rect`
|
|
197
|
+
- `RatatuiRuby::Constraint` → `RatatuiRuby::Layout::Constraint`
|
|
198
|
+
- `RatatuiRuby::Layout` → `RatatuiRuby::Layout::Layout`
|
|
199
|
+
- `RatatuiRuby::Style` → `RatatuiRuby::Style::Style`
|
|
200
|
+
- `RatatuiRuby::Paragraph` → `RatatuiRuby::Widgets::Paragraph`
|
|
201
|
+
- `RatatuiRuby::Block` → `RatatuiRuby::Widgets::Block`
|
|
202
|
+
- `RatatuiRuby::Table` → `RatatuiRuby::Widgets::Table`
|
|
203
|
+
- `RatatuiRuby::List` → `RatatuiRuby::Widgets::List`
|
|
204
|
+
- `RatatuiRuby::Cell` → `RatatuiRuby::Buffer::Cell`
|
|
205
|
+
- All other widgets: `RatatuiRuby::X` → `RatatuiRuby::Widgets::X`
|
|
206
|
+
|
|
207
|
+
**Class Rename:**
|
|
208
|
+
- `RatatuiRuby::Session` → `RatatuiRuby::TUI`
|
|
209
|
+
|
|
210
|
+
**Parameter Rename:**
|
|
211
|
+
- `Table` `highlight_style:` → `row_highlight_style:`
|
|
212
|
+
|
|
213
|
+
**Preferred Approach:** Convert direct class instantiation to TUI API:
|
|
214
|
+
```ruby
|
|
215
|
+
# Instead of:
|
|
216
|
+
RatatuiRuby::Widgets::Paragraph.new(text: "Hello")
|
|
217
|
+
|
|
218
|
+
# Use:
|
|
219
|
+
tui.paragraph(text: "Hello")
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**TUI API method names are unchanged.** Code using `tui.paragraph(...)`, `tui.block(...)`, `tui.style(...)` etc. works without modification.
|
|
223
|
+
|
|
224
|
+
**Cell Disambiguation:**
|
|
225
|
+
- `Buffer::Cell` — Terminal cell for inspection (returned by `get_cell_at`)
|
|
226
|
+
- `Widgets::Cell` — Table cell for construction (use `tui.table_cell`)
|
|
227
|
+
- The old `RatatuiRuby::Cell` is now `RatatuiRuby::Buffer::Cell`
|
|
228
|
+
|
|
229
|
+
**New in v0.7.0:**
|
|
230
|
+
- `tui.table_cell(content:, style:)` — styled table cells
|
|
231
|
+
- `tui.table_row(cells:, style:, height:)` — styled table rows
|
|
232
|
+
- `Text::Line` now accepts `style:` parameter
|
|
233
|
+
|
|
234
|
+
Please update my code following these rules.
|
|
235
|
+
````
|
|
236
|
+
|
data/doc/why.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
# Why RatatuiRuby?
|
|
6
|
+
|
|
7
|
+
The terminal is having a renaissance. Ruby deserves to be at the forefront.
|
|
8
|
+
|
|
9
|
+
**RatatuiRuby** is a high-performance, immediate-mode TUI engine that brings the power of Rust's [Ratatui](https://ratatui.rs) library directly into Ruby. No ports. No emulations. A native bridge to the industry-standard Rust crate.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## The Pitch
|
|
13
|
+
|
|
14
|
+
You want to build a terminal UI. You love Ruby. Your options were:
|
|
15
|
+
|
|
16
|
+
1. **Learn Go** for Bubble Tea
|
|
17
|
+
2. **Learn Rust** for Ratatui
|
|
18
|
+
3. **Use a pure-Ruby library** with limited performance
|
|
19
|
+
|
|
20
|
+
We built a fourth option: **Write Ruby. Run Rust.**
|
|
21
|
+
|
|
22
|
+
RatatuiRuby gives you Rust's layout engine, rendering speed, and battle-tested widgets — with Ruby's expressiveness, ecosystem, and joy.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## RatatuiRuby vs. CharmRuby
|
|
26
|
+
|
|
27
|
+
[CharmRuby](https://github.com/marcoroth/charm_ruby) is an excellent project by Marco Roth. It provides Ruby bindings to Charm's Go libraries (Bubble Tea, Lipgloss). The Ruby ecosystem is better because both projects exist.
|
|
28
|
+
|
|
29
|
+
So which one should you choose?
|
|
30
|
+
|
|
31
|
+
| | CharmRuby | RatatuiRuby |
|
|
32
|
+
|---|-----------|-------------|
|
|
33
|
+
| **Backend** | Go runtime | Rust (no runtime) |
|
|
34
|
+
| **Architecture** | Elm Architecture (MVU) | Immediate-mode + your choice |
|
|
35
|
+
| **GC Behavior** | Two GCs (Ruby + Go) | One GC (Ruby only) |
|
|
36
|
+
| **Rendering** | String manipulation | Constraint-based layout tree |
|
|
37
|
+
| **Best for** | Fans of Bubble Tea, MVU | Native performance, heavy-duty apps |
|
|
38
|
+
|
|
39
|
+
**What's a runtime?** A runtime is background machinery that a language needs to run. Go has one (for goroutines and garbage collection). Rust doesn't — it compiles to plain machine code. When you use Go bindings, you're running *two* runtimes in the same process (Ruby's and Go's), which adds complexity and memory overhead. With Rust bindings, there's only Ruby.
|
|
40
|
+
|
|
41
|
+
**Choose CharmRuby** if you prefer Charm's aesthetics or are migrating existing Bubble Tea code.
|
|
42
|
+
|
|
43
|
+
**Choose RatatuiRuby** if you want zero-overhead native performance and architectural freedom. RatatuiRuby doesn't force a framework — you can build MVU, component-based, or any pattern you prefer.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## Why Not Just Write Rust?
|
|
47
|
+
|
|
48
|
+
Rust is amazing. It's also strict.
|
|
49
|
+
|
|
50
|
+
The borrow checker enforces memory safety. That's great for systems programming. It's painful for UI iteration. Moving a sidebar, changing a color, or swapping a widget often requires refactoring ownership chains.
|
|
51
|
+
|
|
52
|
+
With RatatuiRuby, you just change the object. You get Rust's performance where it matters — rendering — and Ruby's flexibility where it counts — designing.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
## Why Not Just Write Go?
|
|
56
|
+
|
|
57
|
+
Go is pragmatic. But using Go bindings means running *two* runtimes in the same process: Ruby's and Go's. That adds complexity and memory overhead.
|
|
58
|
+
|
|
59
|
+
With RatatuiRuby, there's only Ruby. Rust compiles to plain machine code with no runtime — it integrates seamlessly.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
## Why Ruby?
|
|
63
|
+
|
|
64
|
+
[Ruby isn't just another language](https://www.ruby-lang.org/en/). It's an ecosystem:
|
|
65
|
+
|
|
66
|
+
- **[ActiveRecord](https://guides.rubyonrails.org/active_record_basics.html)** — Query your database with elegant, chainable methods
|
|
67
|
+
- **[RSpec](https://rspec.info/)** — Write expressive, readable tests with `describe`, `it`, and `expect`
|
|
68
|
+
- **[Blocks](https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/blocks.html)** — Pass behavior to methods with `do...end`, the heart of Ruby's expressiveness
|
|
69
|
+
- **[Metaprogramming](https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/objinitialization.html)** — Define methods dynamically, build DSLs, and write code that writes code
|
|
70
|
+
- **[Bundler](https://bundler.io/)** — Access 180,000+ gems with a single `bundle add`
|
|
71
|
+
|
|
72
|
+
Build a dashboard for your Rails app. Monitor your Sidekiq jobs. Create developer tools in the same language as the code they inspect.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
## The Philosophy: A Solid Foundation
|
|
76
|
+
|
|
77
|
+
RatatuiRuby is a **low-level engine**. It provides raw primitives — Layouts, Blocks, Text, Tables, Charts — to build anything.
|
|
78
|
+
|
|
79
|
+
It doesn't force a framework on you. You can use:
|
|
80
|
+
- **Model-View-Update** for dashboards and data displays
|
|
81
|
+
- **Component-based** patterns for interactive tools
|
|
82
|
+
- **Your own architecture** for everything else
|
|
83
|
+
|
|
84
|
+
This is the foundation for Ruby's next generation of TUI tools, dashboards, and interactive scripts.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## Get Started
|
|
88
|
+
|
|
89
|
+
Ready to build?
|
|
90
|
+
|
|
91
|
+
- [Quickstart Guide](./quickstart.md) — Your first app in 5 minutes
|
|
92
|
+
- [Widget Gallery](./quickstart.md#widget-demos) — See what's possible
|
|
93
|
+
- [Application Architecture](./application_architecture.md) — Patterns for scaling
|
|
@@ -5,37 +5,56 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
|
|
5
5
|
|
|
6
6
|
# App All Events Example
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
[](app.rb)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
This example application captures and visualizes every event supported by `ratatui_ruby`. It serves as a comprehensive reference for event handling and a demonstration of the Model-View-Update architectural pattern.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## Architecture: Model-View-Update
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
The **Model** manages the application's domain data and logic. It knows nothing about the UI.
|
|
14
|
+
This application demonstrates **unidirectional data flow** inspired by The Elm Architecture. This separation ensures that state management is predictable and easy to test.
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
### 1. Model (`model/app_model.rb`)
|
|
17
|
+
A single immutable `Data.define` object holding **all** application state:
|
|
18
|
+
* Event log entries
|
|
19
|
+
* Focus state
|
|
20
|
+
* Window size
|
|
21
|
+
* Highlight timestamps
|
|
22
|
+
* Color cycle index
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
The **View State** (comparable to a ViewModel or Presenter) is an immutable data structure built specifically for the View.
|
|
24
|
+
State changes use `.with(...)` to return a new Model instance.
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
### 2. Msg (`model/msg.rb`)
|
|
27
|
+
Semantic value objects that decouple raw terminal events from business logic:
|
|
28
|
+
* `Msg::Input` — keyboard, mouse, or paste events
|
|
29
|
+
* `Msg::Resize` — terminal size changes
|
|
30
|
+
* `Msg::Focus` — focus gained/lost
|
|
31
|
+
* `Msg::Quit` — exit signal
|
|
25
32
|
|
|
26
|
-
### 3.
|
|
27
|
-
|
|
33
|
+
### 3. Update (`update.rb`)
|
|
34
|
+
A **pure function** that computes the next state:
|
|
28
35
|
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
```ruby
|
|
37
|
+
Update.call(msg, model) -> Model
|
|
38
|
+
```
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
The **`AppAllEvents`** class ties it all together. It owns the main loop:
|
|
40
|
+
All logic previously in `Events.record` now lives here. The function never mutates, never draws, never performs IO.
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
42
|
+
### 4. View (`view/`)
|
|
43
|
+
Pure rendering logic. Views accept the immutable `AppModel` and draw to the screen.
|
|
44
|
+
* **`View::App`**: Root view handling high-level layout
|
|
45
|
+
* **Sub-views**: `Counts`, `Live`, `Log`, `Controls`
|
|
46
|
+
|
|
47
|
+
### 5. Runtime (`app.rb`)
|
|
48
|
+
The MVU loop:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
loop do
|
|
52
|
+
tui.draw { |f| view.call(model, tui, f, f.area) }
|
|
53
|
+
msg = map_event_to_msg(tui.poll_event, model)
|
|
54
|
+
break if msg.is_a?(Msg::Quit)
|
|
55
|
+
model = Update.call(msg, model)
|
|
56
|
+
end
|
|
57
|
+
```
|
|
39
58
|
|
|
40
59
|
## Library Features Showcased
|
|
41
60
|
|
|
@@ -57,10 +76,10 @@ Reading this code will teach you how to:
|
|
|
57
76
|
If you are building an app and your logic isn't catching `Ctrl+Left`, run this app and press the keys. You will see exactly how `ratatui_ruby` parses that input (e.g., is it a `Key` event? What are the modifiers?).
|
|
58
77
|
|
|
59
78
|
### "How do I structure a real app?"
|
|
60
|
-
Hello World examples are great, but they don't scale. This example shows how to structure an application that can grow. By
|
|
79
|
+
Hello World examples are great, but they don't scale. This example shows how to structure an application that can grow. By using immutable state and pure functions, it solves the problem of "where does my state live and how does it change?"
|
|
61
80
|
|
|
62
|
-
### "How do I
|
|
63
|
-
|
|
81
|
+
### "How do I test my business logic?"
|
|
82
|
+
The `Update` function is pure. You can test it by constructing a `Msg`, calling `Update.call(msg, model)`, and asserting on the returned `Model`. No mocking required.
|
|
64
83
|
|
|
65
84
|
## Comparison: Choosing an Architecture
|
|
66
85
|
|
|
@@ -68,14 +87,15 @@ Complex applications require structured state habits. `AppAllEvents` and the [Co
|
|
|
68
87
|
|
|
69
88
|
### The Dashboard Approach (AppAllEvents)
|
|
70
89
|
|
|
71
|
-
Dashboards display data. They rarely require complex mouse interaction.
|
|
90
|
+
Dashboards display data. They rarely require complex mouse interaction. Model-View-Update works best here. State is immutable. Logic is pure. Updates are predictable. This simplifies testing.
|
|
72
91
|
|
|
73
92
|
Use this pattern for logs, monitors, and data viewers.
|
|
74
93
|
|
|
75
94
|
### The Tool Approach (Color Picker)
|
|
76
95
|
|
|
77
|
-
Tools require interaction. Users click buttons and drag sliders.
|
|
96
|
+
Tools require interaction. Users click buttons and drag sliders. Each UI component needs to know where it exists on screen for hit testing.
|
|
78
97
|
|
|
79
|
-
The Color Picker uses a
|
|
98
|
+
The Color Picker uses a Component-Based pattern. Each component encapsulates its own rendering, state, and event handling. The Container routes events and coordinates cross-component effects.
|
|
80
99
|
|
|
81
100
|
Use this pattern for forms, editors, and mouse-driven tools.
|
|
101
|
+
|
|
@@ -7,8 +7,9 @@ $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
|
7
7
|
$LOAD_PATH.unshift File.expand_path(__dir__)
|
|
8
8
|
|
|
9
9
|
require "ratatui_ruby"
|
|
10
|
-
require_relative "model/
|
|
11
|
-
require_relative "
|
|
10
|
+
require_relative "model/app_model"
|
|
11
|
+
require_relative "model/msg"
|
|
12
|
+
require_relative "update"
|
|
12
13
|
require_relative "view/app_view"
|
|
13
14
|
|
|
14
15
|
# Demonstrates the full range of terminal events supported by RatatuiRuby.
|
|
@@ -20,6 +21,14 @@ require_relative "view/app_view"
|
|
|
20
21
|
#
|
|
21
22
|
# Use it to verify your terminal's capabilities or as a reference for complex event handling.
|
|
22
23
|
#
|
|
24
|
+
# === Architecture
|
|
25
|
+
#
|
|
26
|
+
# This example uses the Model-View-Update pattern:
|
|
27
|
+
# - **Model**: Immutable AppModel holds all state
|
|
28
|
+
# - **Msg**: Semantic message types decouple events from logic
|
|
29
|
+
# - **Update**: Pure function computes next state
|
|
30
|
+
# - **View**: Renders Model to screen
|
|
31
|
+
#
|
|
23
32
|
# === Examples
|
|
24
33
|
#
|
|
25
34
|
# # Run from the command line:
|
|
@@ -31,62 +40,56 @@ class AppAllEvents
|
|
|
31
40
|
# List of all event types tracked by this application.
|
|
32
41
|
EVENT_TYPES = %i[key mouse resize paste focus none].freeze
|
|
33
42
|
|
|
34
|
-
# Creates a new AppAllEvents instance and initializes its
|
|
43
|
+
# Creates a new AppAllEvents instance and initializes its view.
|
|
35
44
|
def initialize
|
|
36
45
|
@view = View::App.new
|
|
37
|
-
@events = Events.new
|
|
38
|
-
@focused = true
|
|
39
|
-
@last_dimensions = [80, 24]
|
|
40
46
|
end
|
|
41
47
|
|
|
42
48
|
# Starts the application event loop.
|
|
43
49
|
#
|
|
50
|
+
# Implements the MVU (Model-View-Update) runtime:
|
|
51
|
+
# 1. **View**: Render current model
|
|
52
|
+
# 2. **Poll**: Get next event
|
|
53
|
+
# 3. **Map**: Convert raw event to semantic Msg
|
|
54
|
+
# 4. **Update**: Compute next model
|
|
55
|
+
#
|
|
44
56
|
# === Example
|
|
45
57
|
#
|
|
46
58
|
# app.run
|
|
47
59
|
def run
|
|
48
60
|
RatatuiRuby.run do |tui|
|
|
49
|
-
|
|
61
|
+
model = AppModel.initial
|
|
62
|
+
|
|
50
63
|
loop do
|
|
51
|
-
|
|
52
|
-
break if handle_input == :quit
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
64
|
+
tui.draw { |frame| @view.call(model, tui, frame, frame.area) }
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@focused,
|
|
61
|
-
@tui,
|
|
62
|
-
nil
|
|
63
|
-
)
|
|
66
|
+
event = tui.poll_event
|
|
67
|
+
msg = map_event_to_msg(event, model)
|
|
68
|
+
break if msg.is_a?(Msg::Quit)
|
|
64
69
|
|
|
65
|
-
|
|
70
|
+
model = Update.call(msg, model)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
66
73
|
end
|
|
67
74
|
|
|
68
|
-
private def
|
|
69
|
-
event = @tui.poll_event
|
|
70
|
-
|
|
75
|
+
private def map_event_to_msg(event, model)
|
|
71
76
|
case event
|
|
72
77
|
when RatatuiRuby::Event::Key
|
|
73
|
-
return
|
|
74
|
-
return
|
|
75
|
-
|
|
78
|
+
return Msg::Quit.new if event.code == "q"
|
|
79
|
+
return Msg::Quit.new if event.code == "c" && event.modifiers.include?("ctrl")
|
|
80
|
+
|
|
81
|
+
Msg::Input.new(event:)
|
|
76
82
|
when RatatuiRuby::Event::Resize
|
|
77
|
-
|
|
78
|
-
@last_dimensions = [event.width, event.height]
|
|
83
|
+
Msg::Resize.new(width: event.width, height: event.height, previous_size: model.window_size)
|
|
79
84
|
when RatatuiRuby::Event::FocusGained
|
|
80
|
-
|
|
81
|
-
@events.record(event)
|
|
85
|
+
Msg::Focus.new(gained: true)
|
|
82
86
|
when RatatuiRuby::Event::FocusLost
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
Msg::Focus.new(gained: false)
|
|
88
|
+
when RatatuiRuby::Event::None
|
|
89
|
+
Msg::NoneEvent.new
|
|
85
90
|
else
|
|
86
|
-
|
|
91
|
+
Msg::Input.new(event:)
|
|
87
92
|
end
|
|
88
|
-
|
|
89
|
-
nil
|
|
90
93
|
end
|
|
91
94
|
end
|
|
92
95
|
|