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
data/doc/event_handling.md
CHANGED
|
@@ -10,7 +10,15 @@ SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
10
10
|
|
|
11
11
|
Events are retrieved using `RatatuiRuby.poll_event`. This method returns an instance of a subclass of `RatatuiRuby::Event` (e.g., `RatatuiRuby::Event::Key`, `RatatuiRuby::Event::Mouse`). When no event is available, it returns `RatatuiRuby::Event::None`—a [null object](https://martinfowler.com/eaaCatalog/specialCase.html) that safely responds to all event predicates with `false`.
|
|
12
12
|
|
|
13
|
-
## 1.
|
|
13
|
+
## 1. Blocking vs. Polling
|
|
14
|
+
|
|
15
|
+
Most applications run in a loop (e.g., a game loop or UI loop). To prevent high CPU usage, the loop should wait briefly for input.
|
|
16
|
+
|
|
17
|
+
* **Default (Polling):** `RatatuiRuby.poll_event` (no args) waits for **0.016s** (approx 60 FPS). If no event occurs, it returns `RatatuiRuby::Event::None`. This keeps the application responsive.
|
|
18
|
+
* **Blocking:** `RatatuiRuby.poll_event(timeout: nil)` waits **forever** until an event occurs. Use this for scripts that only react to input and do not need to update the UI on a timer.
|
|
19
|
+
* **Non-Blocking:** `RatatuiRuby.poll_event(timeout: 0.0)` returns immediately.
|
|
20
|
+
|
|
21
|
+
## 2. Symbol and String Comparison (Simplest)
|
|
14
22
|
|
|
15
23
|
For simple key events, `RatatuiRuby::Event::Key` objects can be compared directly to Symbols or Strings. This is often the quickest way to get started.
|
|
16
24
|
|
|
@@ -36,7 +44,7 @@ if event == :enter
|
|
|
36
44
|
end
|
|
37
45
|
```
|
|
38
46
|
|
|
39
|
-
##
|
|
47
|
+
## 3. Predicate Methods (Intermediate)
|
|
40
48
|
|
|
41
49
|
If you need more control or logic (e.g. `if/elsif`), or need to handle non-key events like Resize or Mouse, use the predicate methods.
|
|
42
50
|
|
|
@@ -82,7 +90,7 @@ if event.mouse? && event.scroll_up?
|
|
|
82
90
|
end
|
|
83
91
|
```
|
|
84
92
|
|
|
85
|
-
##
|
|
93
|
+
## 4. Pattern Matching (Powerful)
|
|
86
94
|
|
|
87
95
|
For complex applications, Ruby 3.0+ Pattern Matching with the `type:` discriminator is the most idiomatic and concise approach.
|
|
88
96
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/doc/index.md
CHANGED
|
@@ -7,13 +7,18 @@
|
|
|
7
7
|
|
|
8
8
|
## Documentation for Users
|
|
9
9
|
|
|
10
|
-
- [README](../README.md)
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
10
|
+
- [README](../README.md): Project overview and installation
|
|
11
|
+
- [Why RatatuiRuby?](./why.md): Philosophy, comparisons, and what makes us different
|
|
12
|
+
- [Quickstart](./quickstart.md): Build your first TUI app
|
|
13
|
+
- [Application Architecture](./application_architecture.md): Lifecycle patterns and API choices
|
|
14
|
+
- [Event Handling](./event_handling.md): Keyboard, mouse, and terminal events
|
|
15
|
+
- [Interactive Design](./interactive_design.md): Cached layout pattern for hit testing
|
|
16
|
+
- [Terminal Limitations](./terminal_limitations.md): Platform quirks and workarounds
|
|
17
|
+
- [Testing Your Application](./application_testing.md): Snapshot testing and style assertions
|
|
18
|
+
- [Migrating to v0.7.0](./v0.7.0_migration.md): Namespace changes and upgrade guide
|
|
14
19
|
|
|
15
20
|
|
|
16
21
|
## Documentation for Contributors
|
|
17
22
|
|
|
18
|
-
- [Contributing Guidelines](https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md)
|
|
19
|
-
- [More Documentation for Contributors](./contributors/index.md)
|
|
23
|
+
- [Contributing Guidelines](https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md): How to contribute patches and features
|
|
24
|
+
- [More Documentation for Contributors](./contributors/index.md): Internal design docs and style guides
|
data/doc/interactive_design.md
CHANGED
|
@@ -103,10 +103,10 @@ end
|
|
|
103
103
|
|
|
104
104
|
## Layout.split
|
|
105
105
|
|
|
106
|
-
`Layout.split` computes layout geometry without rendering. It returns an array of `Rect` objects. While you can call `RatatuiRuby::Layout.split` directly, we recommend using the `
|
|
106
|
+
`Layout.split` computes layout geometry without rendering. It returns an array of `Rect` objects. While you can call `RatatuiRuby::Layout.split` directly, we recommend using the `TUI` helper (`tui.layout_split`) for cleaner application code.
|
|
107
107
|
|
|
108
108
|
```ruby
|
|
109
|
-
# Preferred (
|
|
109
|
+
# Preferred (TUI API)
|
|
110
110
|
left, right = tui.layout_split(area, constraints: [...])
|
|
111
111
|
|
|
112
112
|
# Manual (Core API)
|
data/doc/quickstart.md
CHANGED
|
@@ -8,25 +8,7 @@ Welcome to **ratatui_ruby**! This guide will help you get up and running with yo
|
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```ruby
|
|
14
|
-
gem "ratatui_ruby"
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
And then execute:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
bundle install
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Or install it yourself as:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
gem install ratatui_ruby
|
|
29
|
-
```
|
|
11
|
+
See [Installation in the README](../README.md#installation) for setup instructions.
|
|
30
12
|
|
|
31
13
|
|
|
32
14
|
## Tutorials
|
|
@@ -35,21 +17,20 @@ gem install ratatui_ruby
|
|
|
35
17
|
|
|
36
18
|
Here is a "Hello World" application that demonstrates the core lifecycle of a **ratatui_ruby** app.
|
|
37
19
|
|
|
20
|
+
<!-- SYNC:START:../examples/verify_quickstart_lifecycle/app.rb:main -->
|
|
38
21
|
```ruby
|
|
39
|
-
require "ratatui_ruby"
|
|
40
|
-
|
|
41
22
|
# 1. Initialize the terminal
|
|
42
23
|
RatatuiRuby.init_terminal
|
|
43
|
-
|
|
24
|
+
|
|
44
25
|
begin
|
|
45
26
|
# The Main Loop
|
|
46
27
|
loop do
|
|
47
28
|
# 2. Create your UI (Immediate Mode)
|
|
48
29
|
# We define a Paragraph widget inside a Block with a title and borders.
|
|
49
|
-
view = RatatuiRuby::Paragraph.new(
|
|
30
|
+
view = RatatuiRuby::Widgets::Paragraph.new(
|
|
50
31
|
text: "Hello, Ratatui! Press 'q' to quit.",
|
|
51
32
|
alignment: :center,
|
|
52
|
-
block: RatatuiRuby::Block.new(
|
|
33
|
+
block: RatatuiRuby::Widgets::Block.new(
|
|
53
34
|
title: "My Ruby TUI App",
|
|
54
35
|
title_alignment: :center,
|
|
55
36
|
borders: [:all],
|
|
@@ -57,23 +38,28 @@ begin
|
|
|
57
38
|
style: { fg: "white" }
|
|
58
39
|
)
|
|
59
40
|
)
|
|
60
|
-
|
|
41
|
+
|
|
61
42
|
# 3. Draw the UI
|
|
62
43
|
RatatuiRuby.draw do |frame|
|
|
63
44
|
frame.render_widget(view, frame.area)
|
|
64
45
|
end
|
|
65
|
-
|
|
46
|
+
|
|
66
47
|
# 4. Poll for events
|
|
67
|
-
|
|
68
|
-
|
|
48
|
+
case RatatuiRuby.poll_event
|
|
49
|
+
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
50
|
+
break
|
|
51
|
+
else
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
69
54
|
end
|
|
70
55
|
ensure
|
|
71
56
|
# 5. Restore the terminal to its original state
|
|
72
57
|
RatatuiRuby.restore_terminal
|
|
73
58
|
end
|
|
74
59
|
```
|
|
60
|
+
<!-- SYNC:END -->
|
|
75
61
|
|
|
76
|
-

|
|
62
|
+
[](../examples/verify_quickstart_lifecycle/README.md)
|
|
77
63
|
|
|
78
64
|
#### How it works
|
|
79
65
|
|
|
@@ -83,14 +69,13 @@ end
|
|
|
83
69
|
4. **`RatatuiRuby.poll_event`**: Returns a typed `Event` object with predicates like `key?`, `mouse?`, `resize?`, etc. Returns `RatatuiRuby::Event::None` if no events are pending. Use predicates to check event type without pattern matching.
|
|
84
70
|
5. **`RatatuiRuby.restore_terminal`**: Essential for leaving raw mode and returning to the shell. Always wrap your loop in `begin...ensure` to guarantee this runs.
|
|
85
71
|
|
|
86
|
-
###
|
|
72
|
+
### Simplified API
|
|
87
73
|
|
|
88
|
-
You can simplify your code by using `RatatuiRuby.run`. This method handles the terminal lifecycle for you, yielding a `
|
|
74
|
+
You can simplify your code by using `RatatuiRuby.run`. This method handles the terminal lifecycle for you, yielding a `TUI` object with factory methods for widgets.
|
|
89
75
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# 1. Initialize the terminal and ensure it is restored.
|
|
76
|
+
<!-- SYNC:START:../examples/verify_quickstart_dsl/app.rb:main -->
|
|
77
|
+
```ruby
|
|
78
|
+
# 1. Initialize the terminal, start the run loop, and ensure the terminal is restored.
|
|
94
79
|
RatatuiRuby.run do |tui|
|
|
95
80
|
loop do
|
|
96
81
|
# 2. Create your UI with methods instead of classes.
|
|
@@ -121,12 +106,13 @@ RatatuiRuby.run do |tui|
|
|
|
121
106
|
end
|
|
122
107
|
end
|
|
123
108
|
```
|
|
109
|
+
<!-- SYNC:END -->
|
|
124
110
|
|
|
125
111
|
#### How it works
|
|
126
112
|
|
|
127
113
|
1. **`RatatuiRuby.run`**: This context manager initializes the terminal before the block starts and ensures `restore_terminal` is called when the block exits (even if an error occurs).
|
|
128
|
-
2. **Widget Shorthand**: The block yields a `
|
|
129
|
-
3. **Method Shorthand**: The
|
|
114
|
+
2. **Widget Shorthand**: The block yields a `TUI` object (here named `tui`). This object provides factory methods for every widget, allowing you to write `tui.paragraph(...)` instead of the more verbose `RatatuiRuby::Widgets::Paragraph.new(...)`.
|
|
115
|
+
3. **Method Shorthand**: The `TUI` object also provides aliases for module functions of `RatatuiRuby`, allowing you to write `tui.draw(...)` instead of the more verbose `RatatuiRuby.draw(...)`.
|
|
130
116
|
4. **Pattern Matching for Events**: Use `case...in` with pattern matching for elegant event dispatch. Always include an `else` clause at the end to catch unmatched event types (mouse, resize, paste, focus, etc.), otherwise Ruby raises `NoMatchingPatternError`.
|
|
131
117
|
|
|
132
118
|
For a deeper dive into the available application architectures (Manual vs Managed), see [Application Architecture](./application_architecture.md).
|
|
@@ -135,164 +121,140 @@ For a deeper dive into the available application architectures (Manual vs Manage
|
|
|
135
121
|
|
|
136
122
|
Real-world applications often need to split the screen into multiple areas. `RatatuiRuby::Layout` lets you do this easily.
|
|
137
123
|
|
|
124
|
+
<!-- SYNC:START:../examples/verify_quickstart_layout/app.rb:main -->
|
|
138
125
|
```ruby
|
|
139
|
-
|
|
126
|
+
loop do
|
|
127
|
+
tui.draw do |frame|
|
|
128
|
+
# 1. Split the screen
|
|
129
|
+
top, bottom = tui.layout_split(
|
|
130
|
+
frame.area,
|
|
131
|
+
direction: :vertical,
|
|
132
|
+
constraints: [
|
|
133
|
+
tui.constraint_percentage(75),
|
|
134
|
+
tui.constraint_percentage(25),
|
|
135
|
+
]
|
|
136
|
+
)
|
|
140
137
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
tui.constraint_percentage(25),
|
|
151
|
-
]
|
|
152
|
-
)
|
|
138
|
+
# 2. Render Top Widget
|
|
139
|
+
frame.render_widget(
|
|
140
|
+
tui.paragraph(
|
|
141
|
+
text: "Hello, Ratatui!",
|
|
142
|
+
alignment: :center,
|
|
143
|
+
block: tui.block(title: "Content", borders: [:all], border_color: "cyan")
|
|
144
|
+
),
|
|
145
|
+
top
|
|
146
|
+
)
|
|
153
147
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
148
|
+
# 3. Render Bottom Widget with Styled Text
|
|
149
|
+
# We use a Line of Spans to style specific characters
|
|
150
|
+
text_line = tui.text_line(
|
|
151
|
+
spans: [
|
|
152
|
+
tui.text_span(content: "Press '"),
|
|
153
|
+
tui.text_span(
|
|
154
|
+
content: "q",
|
|
155
|
+
style: tui.style(modifiers: [:bold, :underlined])
|
|
160
156
|
),
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
# We use a Line of Spans to style specific characters
|
|
166
|
-
text_line = tui.text_line(
|
|
167
|
-
spans: [
|
|
168
|
-
tui.text_span(content: "Press '"),
|
|
169
|
-
tui.text_span(
|
|
170
|
-
content: "q",
|
|
171
|
-
style: tui.style(modifiers: [:bold, :underlined])
|
|
172
|
-
),
|
|
173
|
-
tui.text_span(content: "' to quit."),
|
|
174
|
-
],
|
|
175
|
-
alignment: :center
|
|
176
|
-
)
|
|
157
|
+
tui.text_span(content: "' to quit."),
|
|
158
|
+
],
|
|
159
|
+
alignment: :center
|
|
160
|
+
)
|
|
177
161
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
162
|
+
frame.render_widget(
|
|
163
|
+
tui.paragraph(
|
|
164
|
+
text: text_line,
|
|
165
|
+
block: tui.block(title: "Controls", borders: [:all])
|
|
166
|
+
),
|
|
167
|
+
bottom
|
|
168
|
+
)
|
|
169
|
+
end
|
|
186
170
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
end
|
|
171
|
+
case tui.poll_event
|
|
172
|
+
in { type: :key, code: "q" }
|
|
173
|
+
break
|
|
174
|
+
else
|
|
175
|
+
# Ignore other events
|
|
193
176
|
end
|
|
194
177
|
end
|
|
195
178
|
```
|
|
179
|
+
<!-- SYNC:END -->
|
|
196
180
|
|
|
197
181
|
#### How it works
|
|
198
182
|
|
|
199
|
-
1. **`tui.layout_split` (`RatatuiRuby::Layout.split`)**: Takes an area (like `frame.area`) and splits it into multiple sub-areas based on constraints.
|
|
200
|
-
2. **`tui.constraint_*` (`RatatuiRuby::Constraint`)**: Defines how space is distributed (e.g., `percentage`, `length`, `min`, `max`).
|
|
183
|
+
1. **`tui.layout_split` (`RatatuiRuby::Layout::Layout.split`)**: Takes an area (like `frame.area`) and splits it into multiple sub-areas based on constraints.
|
|
184
|
+
2. **`tui.constraint_*` (`RatatuiRuby::Layout::Constraint`)**: Defines how space is distributed (e.g., `percentage`, `length`, `min`, `max`).
|
|
201
185
|
3. **`Frame#render_widget(widget, rect)`**: You pass the specific area (like `top` or `bottom`) to render the widget into that exact region.
|
|
202
186
|
4. **`tui.text_span` (`RatatuiRuby::Text::Span`)**: Allows for rich styling within a single line of text.
|
|
203
187
|
|
|
188
|
+
[](../examples/verify_quickstart_layout/README.md)
|
|
189
|
+
|
|
204
190
|
## Examples
|
|
205
191
|
|
|
206
192
|
These examples showcase the full power of **ratatui_ruby**. You can find their source code in the [examples directory](../examples).
|
|
207
193
|
|
|
208
|
-
###
|
|
209
|
-
|
|
210
|
-
Full-featured examples demonstrating complex layouts and real-world TUI patterns.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
#### [All Events](../examples/app_all_events/app.rb)
|
|
215
|
-
|
|
216
|
-
Handling terminal events is unpredictable. Developers need to know exactly what the terminal sends for `Ctrl+C` or a mouse drag.
|
|
217
|
-
|
|
218
|
-
This app captures and visualizes every event—keys, mouse, resize, paste, and focus.
|
|
219
|
-
|
|
220
|
-
Use it to debug your input handling or verify terminal behavior.
|
|
221
|
-
|
|
222
|
-
**What you'll learn:**
|
|
223
|
-
|
|
224
|
-
* **MVVM Architecture**: Separates logic (Model), state (ViewModel), and rendering (View) for clean, testable code.
|
|
225
|
-
* **Event Handling**: Captures and distinguishes all input types, including modifiers (`Ctrl+C`) and focus changes.
|
|
226
|
-
* **Scalable Structure**: Organizes a non-trivial application into small, focused classes instead of a monolithic script.
|
|
227
|
-
|
|
228
|
-

|
|
229
|
-
|
|
230
|
-
#### [Color Picker](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_color_picker/app.rb)
|
|
231
|
-
|
|
232
|
-
Interactive tools require complex state. Mapping mouse clicks to widgets and handling modal dialogs creates messy code if handled in the main loop.
|
|
233
|
-
|
|
234
|
-
This app implements a full Color Picker using a "Scene-Orchestrated" pattern. The Scene calculates layout and exposes cached rectangles for hit testing.
|
|
235
|
-
|
|
236
|
-
Use it to build forms, editors, and mouse-driven tools.
|
|
237
|
-
|
|
238
|
-
**What you'll learn:**
|
|
239
|
-
|
|
240
|
-
* **Scene-Orchestrated MVC**: Separates the View (layout/rendering) from the Controller (event loop) and Model (business logic).
|
|
241
|
-
* **Hit Testing**: Caches layout rectangles during the render pass to handle mouse clicks on specific elements.
|
|
242
|
-
* **Modal Dialogs**: Implements overlay patterns that intercept input.
|
|
243
|
-
|
|
244
|
-
#### [Custom Widget (Escape Hatch)](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_custom_widget/app.rb)
|
|
245
|
-
|
|
246
|
-
Demonstrates how to define a custom widget in pure Ruby using the `render(area, buffer)` escape hatch for low-level drawing.
|
|
247
|
-
|
|
248
|
-

|
|
249
|
-
|
|
250
|
-
#### [Layout Split Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/widget_layout_split/app.rb)
|
|
194
|
+
### Widget Demos
|
|
251
195
|
|
|
252
|
-
|
|
196
|
+
Focused examples for individual widgets. Each demonstrates a single widget and its configuration options.
|
|
197
|
+
|
|
198
|
+
| Widget | What it demonstrates |
|
|
199
|
+
|--------|---------------------|
|
|
200
|
+
| [Bar Chart](../examples/widget_barchart_demo/app.rb) | Grouped bars, data visualization, custom bar styling |
|
|
201
|
+
| [Block](../examples/widget_block_demo/app.rb) | Borders, titles, padding, nested widgets |
|
|
202
|
+
| [Box](../examples/widget_box_demo/app.rb) | Block + Paragraph composition, text wrapping |
|
|
203
|
+
| [Calendar](../examples/widget_calendar_demo/app.rb) | Date highlighting, month display, event markers |
|
|
204
|
+
| [Chart](../examples/widget_chart_demo/app.rb) | Line/scatter plots, axes, legends, datasets |
|
|
205
|
+
| [Gauge](../examples/widget_gauge_demo/app.rb) | Progress bars, percentage display, unicode blocks |
|
|
206
|
+
| [Layout Split](../examples/widget_layout_split/app.rb) | Constraint types, flex modes, responsive layouts |
|
|
207
|
+
| [Line Gauge](../examples/widget_line_gauge_demo/app.rb) | Horizontal progress, labels, thin-style gauges |
|
|
208
|
+
| [List](../examples/widget_list_demo/app.rb) | Selection, scrolling, highlight styles, rich text items |
|
|
209
|
+
| [Map](../examples/widget_map_demo/app.rb) | Canvas widget, world map rendering, coordinates |
|
|
210
|
+
| [Popup](../examples/widget_popup_demo/app.rb) | Clear widget, modal dialogs, overlay composition |
|
|
211
|
+
| [Ratatui Logo](../examples/widget_ratatui_logo_demo/app.rb) | Decorative branding widget |
|
|
212
|
+
| [Ratatui Mascot](../examples/widget_ratatui_mascot_demo/app.rb) | ASCII art Ferris mascot |
|
|
213
|
+
| [Rect](../examples/widget_rect/app.rb) | Geometry helpers, area calculations, contains/intersection |
|
|
214
|
+
| [Rich Text](../examples/widget_rich_text/app.rb) | Spans, lines, inline styling, mixed colors |
|
|
215
|
+
| [Scrollbar](../examples/widget_scrollbar_demo/app.rb) | Orientations, thumb/track styling, scroll state |
|
|
216
|
+
| [Scroll Text](../examples/widget_scroll_text/app.rb) | Paragraph scrolling, viewport control, long content |
|
|
217
|
+
| [Sparkline](../examples/widget_sparkline_demo/app.rb) | Mini charts, time series, bar sets |
|
|
218
|
+
| [Style Colors](../examples/widget_style_colors/app.rb) | Named colors, RGB, indexed 256-color palette |
|
|
219
|
+
| [Table](../examples/widget_table_demo/app.rb) | Row selection, column widths, per-cell styling |
|
|
220
|
+
| [Tabs](../examples/widget_tabs_demo/app.rb) | Tab navigation, highlighting, dividers |
|
|
221
|
+
| [Text Width](../examples/widget_text_width/app.rb) | Unicode-aware width measurement, CJK support |
|
|
222
|
+
| [Canvas](../examples/widget_canvas_demo/app.rb) | Drawing shapes, markers, custom graphics |
|
|
223
|
+
| [Cell](../examples/widget_cell_demo/app.rb) | Buffer cell inspection, styling attributes |
|
|
224
|
+
| [Center](../examples/widget_center_demo/app.rb) | Centering content, horizontal/vertical alignment |
|
|
225
|
+
| [Overlay](../examples/widget_overlay_demo/app.rb) | Layering widgets, modal backgrounds |
|
|
226
|
+
| [Custom Render](../examples/widget_render/app.rb) | Low-level Draw API, escape hatch for custom widgets |
|
|
253
227
|
|
|
254
|
-
|
|
228
|
+
### Sample Applications
|
|
255
229
|
|
|
256
|
-
|
|
230
|
+
These larger examples combine widgets into complete applications, demonstrating real-world TUI patterns and architectures.
|
|
257
231
|
|
|
258
|
-
|
|
232
|
+
| Application | Architecture | What you'll learn |
|
|
233
|
+
|-------------|--------------|-------------------|
|
|
234
|
+
| [All Events](../examples/app_all_events/app.rb) | Model-View-Update | Event handling, unidirectional data flow, scalable structure |
|
|
235
|
+
| [Color Picker](../examples/app_color_picker/app.rb) | Component-Based | Hit testing, modal dialogs, encapsulated state |
|
|
236
|
+
| [Login Form](../examples/app_login_form/app.rb) | Overlay + Center | Modal forms, cursor positioning, text input |
|
|
237
|
+
| [Stateful Interaction](../examples/app_stateful_interaction/app.rb) | State Objects | ListState/TableState, offset read-back, mouse click-to-row |
|
|
259
238
|
|
|
260
|
-
|
|
239
|
+
#### All Events
|
|
261
240
|
|
|
262
|
-
|
|
241
|
+
[](../examples/app_all_events/README.md)
|
|
263
242
|
|
|
264
|
-
|
|
243
|
+
#### Color Picker
|
|
265
244
|
|
|
266
|
-
](../examples/app_color_picker/README.md)
|
|
267
246
|
|
|
268
|
-
####
|
|
247
|
+
#### Login Form
|
|
269
248
|
|
|
270
|
-
|
|
249
|
+
[](../examples/app_login_form/README.md)
|
|
271
250
|
|
|
272
|
-

|
|
273
251
|
|
|
252
|
+
## Next Steps
|
|
274
253
|
|
|
275
|
-
|
|
254
|
+
Now that you've seen what **ratatui_ruby** can do:
|
|
276
255
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
* [Box (Block/Paragraph)](../examples/widget_box_demo/app.rb)
|
|
283
|
-
* [Calendar](../examples/widget_calendar_demo/app.rb)
|
|
284
|
-
* [Chart](../examples/widget_chart_demo/app.rb)
|
|
285
|
-
* [Gauge](../examples/widget_gauge_demo/app.rb)
|
|
286
|
-
* [Line Gauge](../examples/widget_line_gauge_demo/app.rb)
|
|
287
|
-
* [List](../examples/widget_list_demo/app.rb)
|
|
288
|
-
* [Popup (Clear)](../examples/widget_popup_demo/app.rb)
|
|
289
|
-
* [Rect](../examples/widget_rect/app.rb)
|
|
290
|
-
* [Ratatui Logo](../examples/widget_ratatui_logo_demo/app.rb)
|
|
291
|
-
* [Ratatui Mascot](../examples/widget_ratatui_mascot_demo/app.rb)
|
|
292
|
-
* [Rich Text](../examples/widget_rich_text/app.rb)
|
|
293
|
-
* [Scrollbar](../examples/widget_scrollbar_demo/app.rb)
|
|
294
|
-
* [Scroll Text](../examples/widget_scroll_text/app.rb)
|
|
295
|
-
* [Sparkline](../examples/widget_sparkline_demo/app.rb)
|
|
296
|
-
* [Table Flex](../examples/widget_table_flex/app.rb)
|
|
297
|
-
* [Tabs](../examples/widget_tabs_demo/app.rb)
|
|
298
|
-
* [Widget Style Colors](../examples/widget_style_colors/app.rb)
|
|
256
|
+
- **Deep dive**: Read the [Application Architecture](./application_architecture.md) guide for scaling patterns
|
|
257
|
+
- **Test your TUI**: See the [Testing Guide](./application_testing.md) for snapshot and style assertions
|
|
258
|
+
- **Explore the API**: Browse the [full RDoc documentation](./index.md)
|
|
259
|
+
- **Learn the philosophy**: Read [Why RatatuiRuby?](./why.md) for comparisons and design decisions
|
|
260
|
+
- **Get help**: Join the [discussion mailing list](https://lists.sr.ht/~kerrick/ratatui_ruby-discuss)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Terminal Limitations
|
|
7
|
+
|
|
8
|
+
Some behaviors are outside the control of `ratatui_ruby`. This document explains common pitfalls that affect your application or your users, but cannot be fixed in the library.
|
|
9
|
+
|
|
10
|
+
## Keyboard Event Interception
|
|
11
|
+
|
|
12
|
+
### The Problem
|
|
13
|
+
|
|
14
|
+
Your application receives a key event, but the modifier flags are missing. You pressed Ctrl+PageUp, but the event shows `code="page_up"` with `modifiers=[]`.
|
|
15
|
+
|
|
16
|
+
### The Cause
|
|
17
|
+
|
|
18
|
+
Terminal emulators intercept certain key combinations for their own features. The key press never reaches your application—the terminal consumes it first.
|
|
19
|
+
|
|
20
|
+
Common culprits on macOS:
|
|
21
|
+
|
|
22
|
+
| Key Combination | Terminal Behavior |
|
|
23
|
+
|---------------------|--------------------------------------|
|
|
24
|
+
| Ctrl+PageUp/Down | Switch tabs (Terminal.app, iTerm2) |
|
|
25
|
+
| Ctrl+Tab | Switch tabs |
|
|
26
|
+
| Cmd+T / Cmd+N | New tab / New window |
|
|
27
|
+
| Cmd+C / Cmd+V | Copy / Paste (not Ctrl) |
|
|
28
|
+
|
|
29
|
+
Linux terminals vary widely. Windows Terminal and ConEmu have their own defaults.
|
|
30
|
+
|
|
31
|
+
### The Solution
|
|
32
|
+
|
|
33
|
+
1. **Test with different terminals.** Kitty, WezTerm, and Alacritty pass more key combinations through to applications by default. If a key works in Kitty but not Terminal.app, the terminal is the issue.
|
|
34
|
+
|
|
35
|
+
2. **Reconfigure your terminal.** Most terminal emulators let you unbind or remap default shortcuts in their settings.
|
|
36
|
+
|
|
37
|
+
3. **Use alternative key bindings.** If your users will run your application in various terminals, design your keybindings to avoid commonly intercepted combinations:
|
|
38
|
+
- Use Alt+PageUp instead of Ctrl+PageUp
|
|
39
|
+
- Use Ctrl+J/K instead of Ctrl+Up/Down
|
|
40
|
+
- Avoid Ctrl+Tab entirely
|
|
41
|
+
|
|
42
|
+
4. **Document requirements.** If your application depends on specific key combinations, document the terminal requirements for your users.
|
|
43
|
+
|
|
44
|
+
### Enhanced Keyboard Protocol
|
|
45
|
+
|
|
46
|
+
Some terminals support the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/), which provides unambiguous key event reporting including:
|
|
47
|
+
|
|
48
|
+
- Individual modifier key events (LeftShift vs RightShift)
|
|
49
|
+
- Media keys (Play, Pause, Volume controls)
|
|
50
|
+
- Repeat and release events
|
|
51
|
+
|
|
52
|
+
Terminals with full protocol support:
|
|
53
|
+
- Kitty
|
|
54
|
+
- WezTerm
|
|
55
|
+
- Foot
|
|
56
|
+
- Alacritty (partial)
|
|
57
|
+
|
|
58
|
+
Standard terminals (Terminal.app, iTerm2, GNOME Terminal) do not support the enhanced protocol.
|
|
59
|
+
|
|
60
|
+
**RatatuiRuby Status:** The underlying library (crossterm) supports this protocol, but RatatuiRuby does not yet expose a way to enable it. The key code mappings for media keys and individual modifier keys exist, but they will only be received from terminals that enable the protocol by default. This is planned for a future release.
|
|
61
|
+
|
|
62
|
+
## Mouse Event Limitations
|
|
63
|
+
|
|
64
|
+
### The Problem
|
|
65
|
+
|
|
66
|
+
Mouse events work in some terminals but not others. Or they work, but only up to certain coordinates.
|
|
67
|
+
|
|
68
|
+
### The Cause
|
|
69
|
+
|
|
70
|
+
Mouse reporting requires terminal escape sequence support. Older terminals may not support:
|
|
71
|
+
|
|
72
|
+
- SGR mouse mode (coordinates > 223)
|
|
73
|
+
- Mouse motion tracking
|
|
74
|
+
- Button-event tracking
|
|
75
|
+
|
|
76
|
+
### The Solution
|
|
77
|
+
|
|
78
|
+
Ensure your terminal supports modern mouse modes. Most actively maintained terminals do. If running in a legacy environment, test mouse functionality and provide keyboard alternatives.
|
|
79
|
+
|
|
80
|
+
## Focus Events
|
|
81
|
+
|
|
82
|
+
### The Problem
|
|
83
|
+
|
|
84
|
+
`Event::FocusGained` and `Event::FocusLost` are never received.
|
|
85
|
+
|
|
86
|
+
### The Cause
|
|
87
|
+
|
|
88
|
+
Focus event reporting requires explicit terminal support and configuration. Some terminals don't support it at all.
|
|
89
|
+
|
|
90
|
+
### The Solution
|
|
91
|
+
|
|
92
|
+
Don't rely on focus events for critical functionality. Treat them as nice-to-have enhancements. If your application shows stale data when the user returns, periodically refresh instead of waiting for focus events.
|