ratatui_ruby 0.4.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 +98 -176
- data/CHANGELOG.md +80 -6
- data/README.md +19 -7
- data/REUSE.toml +15 -0
- data/doc/application_architecture.md +179 -45
- data/doc/application_testing.md +80 -32
- data/doc/contributors/design/ruby_frontend.md +48 -8
- data/doc/contributors/design/rust_backend.md +1 -0
- data/doc/contributors/developing_examples.md +191 -48
- data/doc/contributors/documentation_style.md +7 -0
- 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/contributors/index.md +2 -0
- data/doc/event_handling.md +21 -7
- 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_box_demo.png +0 -0
- data/doc/images/widget_calendar_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_gauge_demo.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge_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_ratatui_logo_demo.png +0 -0
- data/doc/images/widget_ratatui_mascot_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_scrollbar_demo.png +0 -0
- data/doc/images/widget_sparkline_demo.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table_demo.png +0 -0
- data/doc/images/widget_table_flex.png +0 -0
- data/doc/images/widget_tabs_demo.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/interactive_design.md +25 -30
- data/doc/quickstart.md +150 -130
- data/doc/terminal_limitations.md +92 -0
- data/examples/app_all_events/README.md +99 -0
- data/examples/app_all_events/app.rb +96 -0
- data/examples/app_all_events/model/app_model.rb +157 -0
- data/examples/app_all_events/model/event_color_cycle.rb +41 -0
- data/examples/app_all_events/model/event_entry.rb +92 -0
- data/examples/app_all_events/model/msg.rb +37 -0
- data/examples/app_all_events/model/timestamp.rb +54 -0
- data/examples/app_all_events/update.rb +73 -0
- data/examples/app_all_events/view/app_view.rb +78 -0
- data/examples/app_all_events/view/controls_view.rb +52 -0
- data/examples/app_all_events/view/counts_view.rb +59 -0
- data/examples/app_all_events/view/live_view.rb +70 -0
- data/examples/app_all_events/view/log_view.rb +55 -0
- data/examples/app_all_events/view.rb +7 -0
- data/examples/app_color_picker/README.md +134 -0
- data/examples/app_color_picker/app.rb +74 -0
- data/examples/app_color_picker/clipboard.rb +84 -0
- data/examples/app_color_picker/color.rb +191 -0
- data/examples/app_color_picker/controls.rb +90 -0
- data/examples/app_color_picker/copy_dialog.rb +166 -0
- data/examples/app_color_picker/export_pane.rb +126 -0
- data/examples/app_color_picker/harmony.rb +56 -0
- data/examples/app_color_picker/input.rb +174 -0
- data/examples/app_color_picker/main_container.rb +178 -0
- data/examples/app_color_picker/palette.rb +109 -0
- data/examples/app_login_form/README.md +47 -0
- data/examples/{login_form → app_login_form}/app.rb +38 -42
- 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/{quickstart_dsl → verify_quickstart_dsl}/app.rb +17 -6
- data/examples/verify_quickstart_layout/README.md +71 -0
- data/examples/verify_quickstart_layout/app.rb +71 -0
- data/examples/verify_quickstart_lifecycle/README.md +56 -0
- data/examples/verify_quickstart_lifecycle/app.rb +54 -0
- data/examples/verify_readme_usage/README.md +43 -0
- data/examples/verify_readme_usage/app.rb +40 -0
- data/examples/widget_barchart_demo/README.md +49 -0
- data/examples/widget_barchart_demo/app.rb +238 -0
- 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/{box_demo → widget_box_demo}/app.rb +99 -65
- data/examples/widget_calendar_demo/README.md +39 -0
- data/examples/widget_calendar_demo/app.rb +109 -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 +111 -0
- 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 +218 -0
- data/examples/widget_gauge_demo/README.md +41 -0
- data/examples/widget_gauge_demo/app.rb +212 -0
- data/examples/widget_layout_split/README.md +44 -0
- data/examples/widget_layout_split/app.rb +246 -0
- data/examples/widget_line_gauge_demo/README.md +41 -0
- data/examples/widget_line_gauge_demo/app.rb +217 -0
- data/examples/widget_list_demo/README.md +49 -0
- data/examples/widget_list_demo/app.rb +366 -0
- data/examples/widget_map_demo/README.md +39 -0
- data/examples/{map_demo → widget_map_demo}/app.rb +24 -21
- data/examples/widget_overlay_demo/app.rb +248 -0
- data/examples/widget_popup_demo/README.md +36 -0
- data/examples/widget_popup_demo/app.rb +104 -0
- data/examples/widget_ratatui_logo_demo/README.md +34 -0
- data/examples/widget_ratatui_logo_demo/app.rb +103 -0
- data/examples/widget_ratatui_mascot_demo/README.md +34 -0
- data/examples/widget_ratatui_mascot_demo/app.rb +93 -0
- data/examples/widget_rect/README.md +38 -0
- data/examples/widget_rect/app.rb +205 -0
- data/examples/widget_render/README.md +37 -0
- data/examples/widget_render/app.rb +184 -0
- data/examples/widget_rich_text/README.md +35 -0
- data/examples/widget_rich_text/app.rb +166 -0
- data/examples/widget_scroll_text/README.md +37 -0
- data/examples/widget_scroll_text/app.rb +107 -0
- data/examples/widget_scrollbar_demo/README.md +37 -0
- data/examples/widget_scrollbar_demo/app.rb +153 -0
- data/examples/widget_sparkline_demo/README.md +42 -0
- data/examples/widget_sparkline_demo/app.rb +275 -0
- data/examples/widget_style_colors/README.md +34 -0
- data/examples/widget_style_colors/app.rb +19 -21
- data/examples/widget_table_demo/README.md +48 -0
- data/examples/widget_table_demo/app.rb +239 -0
- data/examples/widget_tabs_demo/README.md +41 -0
- data/examples/widget_tabs_demo/app.rb +181 -0
- data/examples/widget_text_width/README.md +35 -0
- data/examples/widget_text_width/app.rb +106 -0
- data/ext/ratatui_ruby/Cargo.lock +11 -4
- data/ext/ratatui_ruby/Cargo.toml +2 -1
- data/ext/ratatui_ruby/src/events.rs +359 -62
- data/ext/ratatui_ruby/src/frame.rs +227 -0
- data/ext/ratatui_ruby/src/lib.rs +110 -27
- data/ext/ratatui_ruby/src/rendering.rs +8 -4
- data/ext/ratatui_ruby/src/string_width.rs +101 -0
- data/ext/ratatui_ruby/src/style.rs +138 -57
- data/ext/ratatui_ruby/src/terminal.rs +42 -22
- data/ext/ratatui_ruby/src/text.rs +14 -7
- data/ext/ratatui_ruby/src/widgets/barchart.rs +74 -54
- data/ext/ratatui_ruby/src/widgets/block.rs +7 -6
- data/ext/ratatui_ruby/src/widgets/canvas.rs +21 -3
- data/ext/ratatui_ruby/src/widgets/chart.rs +20 -10
- data/ext/ratatui_ruby/src/widgets/gauge.rs +9 -2
- data/ext/ratatui_ruby/src/widgets/layout.rs +9 -4
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +9 -2
- data/ext/ratatui_ruby/src/widgets/list.rs +211 -12
- 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/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +19 -8
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +17 -10
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +97 -3
- data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +14 -11
- data/ext/ratatui_ruby/src/widgets/table.rs +121 -5
- data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +11 -11
- data/lib/ratatui_ruby/cell.rb +7 -7
- 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 +112 -52
- data/lib/ratatui_ruby/event/mouse.rb +3 -3
- data/lib/ratatui_ruby/event/none.rb +43 -0
- data/lib/ratatui_ruby/event/paste.rb +1 -1
- data/lib/ratatui_ruby/event.rb +56 -4
- data/lib/ratatui_ruby/frame.rb +183 -0
- data/lib/ratatui_ruby/list_state.rb +88 -0
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +13 -13
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +1 -5
- data/lib/ratatui_ruby/schema/bar_chart.rb +217 -217
- data/lib/ratatui_ruby/schema/block.rb +163 -168
- data/lib/ratatui_ruby/schema/calendar.rb +66 -67
- data/lib/ratatui_ruby/schema/canvas.rb +63 -63
- data/lib/ratatui_ruby/schema/center.rb +46 -46
- data/lib/ratatui_ruby/schema/chart.rb +135 -143
- data/lib/ratatui_ruby/schema/clear.rb +42 -42
- data/lib/ratatui_ruby/schema/constraint.rb +76 -76
- data/lib/ratatui_ruby/schema/cursor.rb +30 -25
- data/lib/ratatui_ruby/schema/gauge.rb +54 -52
- data/lib/ratatui_ruby/schema/layout.rb +87 -87
- data/lib/ratatui_ruby/schema/line_gauge.rb +62 -62
- data/lib/ratatui_ruby/schema/list.rb +103 -80
- data/lib/ratatui_ruby/schema/list_item.rb +41 -0
- data/lib/ratatui_ruby/schema/overlay.rb +31 -31
- data/lib/ratatui_ruby/schema/paragraph.rb +80 -80
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +10 -6
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +10 -5
- data/lib/ratatui_ruby/schema/rect.rb +99 -56
- data/lib/ratatui_ruby/schema/scrollbar.rb +119 -119
- data/lib/ratatui_ruby/schema/shape/label.rb +1 -1
- data/lib/ratatui_ruby/schema/sparkline.rb +111 -110
- data/lib/ratatui_ruby/schema/style.rb +66 -46
- data/lib/ratatui_ruby/schema/table.rb +126 -115
- data/lib/ratatui_ruby/schema/tabs.rb +66 -67
- 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 +482 -0
- data/lib/ratatui_ruby/session.rb +55 -23
- 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 +66 -193
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +100 -51
- data/{examples/sparkline_demo → sig/examples/app_all_events}/app.rbs +3 -2
- data/sig/examples/app_all_events/model/event_entry.rbs +16 -0
- data/sig/examples/app_all_events/model/events.rbs +15 -0
- data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
- data/sig/examples/app_all_events/view/app_view.rbs +8 -0
- data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
- data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
- data/sig/examples/app_all_events/view/live_view.rbs +6 -0
- data/sig/examples/app_all_events/view/log_view.rbs +6 -0
- data/sig/examples/app_all_events/view.rbs +8 -0
- data/sig/examples/app_all_events/view_state.rbs +15 -0
- data/{examples/list_demo → sig/examples/app_color_picker}/app.rbs +2 -2
- data/sig/examples/app_login_form/app.rbs +11 -0
- data/sig/examples/app_stateful_interaction/app.rbs +33 -0
- data/sig/examples/verify_quickstart_dsl/app.rbs +11 -0
- data/sig/examples/verify_quickstart_lifecycle/app.rbs +11 -0
- data/sig/examples/verify_readme_usage/app.rbs +11 -0
- data/sig/examples/widget_block_demo/app.rbs +32 -0
- data/sig/examples/widget_box_demo/app.rbs +11 -0
- data/sig/examples/widget_calendar_demo/app.rbs +11 -0
- data/sig/examples/widget_cell_demo/app.rbs +11 -0
- data/sig/examples/widget_chart_demo/app.rbs +11 -0
- data/{examples/gauge_demo → sig/examples/widget_gauge_demo}/app.rbs +4 -0
- data/sig/examples/widget_layout_split/app.rbs +10 -0
- data/sig/examples/widget_line_gauge_demo/app.rbs +11 -0
- data/sig/examples/widget_list_demo/app.rbs +12 -0
- data/sig/examples/widget_map_demo/app.rbs +11 -0
- data/sig/examples/widget_popup_demo/app.rbs +11 -0
- data/sig/examples/widget_ratatui_logo_demo/app.rbs +11 -0
- data/sig/examples/widget_ratatui_mascot_demo/app.rbs +11 -0
- data/sig/examples/widget_rect/app.rbs +12 -0
- data/sig/examples/widget_render/app.rbs +10 -0
- data/sig/examples/widget_rich_text/app.rbs +11 -0
- data/sig/examples/widget_scroll_text/app.rbs +11 -0
- data/sig/examples/widget_scrollbar_demo/app.rbs +11 -0
- data/sig/examples/widget_sparkline_demo/app.rbs +10 -0
- data/{examples → sig/examples}/widget_style_colors/app.rbs +1 -1
- data/sig/examples/widget_table_demo/app.rbs +11 -0
- data/sig/examples/widget_text_width/app.rbs +10 -0
- data/sig/ratatui_ruby/event.rbs +11 -1
- data/sig/ratatui_ruby/frame.rbs +11 -0
- data/sig/ratatui_ruby/list_state.rbs +13 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +5 -4
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +3 -3
- data/sig/ratatui_ruby/schema/draw.rbs +4 -0
- data/sig/ratatui_ruby/schema/gauge.rbs +2 -2
- data/sig/ratatui_ruby/schema/layout.rbs +1 -1
- 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 +107 -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 +63 -0
- data/tasks/autodoc/member.rb +56 -0
- data/tasks/autodoc/name.rb +19 -0
- data/tasks/autodoc/notice.rb +26 -0
- data/tasks/autodoc/rbs.rb +38 -0
- data/tasks/autodoc/rdoc.rb +45 -0
- data/tasks/autodoc.rake +53 -0
- data/tasks/bump/changelog.rb +3 -3
- data/tasks/bump/history.rb +2 -2
- data/tasks/bump/links.rb +67 -0
- data/tasks/doc.rake +600 -6
- data/tasks/example_viewer.html.erb +172 -0
- data/tasks/lint.rake +8 -4
- data/tasks/resources/index.html.erb +6 -0
- data/tasks/sourcehut.rake +70 -30
- data/tasks/terminal_preview/app_screenshot.rb +14 -6
- data/tasks/terminal_preview/crash_report.rb +7 -9
- data/tasks/terminal_preview/launcher_script.rb +4 -6
- data/tasks/terminal_preview/preview_collection.rb +4 -6
- data/tasks/terminal_preview/safety_confirmation.rb +3 -5
- data/tasks/terminal_preview/saved_screenshot.rb +10 -11
- data/tasks/terminal_preview/terminal_window.rb +7 -9
- data/tasks/test.rake +1 -1
- data/tasks/website/index_page.rb +3 -3
- data/tasks/website/version.rb +10 -10
- data/tasks/website/version_menu.rb +10 -12
- data/tasks/website/versioned_documentation.rb +49 -17
- data/tasks/website/website.rb +6 -8
- data/tasks/website.rake +4 -4
- metadata +232 -127
- data/LICENSES/BSD-2-Clause.txt +0 -9
- data/doc/contributors/better_dx.md +0 -543
- data/doc/contributors/example_analysis.md +0 -82
- data/doc/images/all_events.png +0 -0
- data/doc/images/block_padding.png +0 -0
- data/doc/images/block_titles.png +0 -0
- data/doc/images/box_demo.png +0 -0
- data/doc/images/calendar_demo.png +0 -0
- data/doc/images/cell_demo.png +0 -0
- data/doc/images/chart_demo.png +0 -0
- data/doc/images/flex_layout.png +0 -0
- data/doc/images/gauge_demo.png +0 -0
- data/doc/images/line_gauge_demo.png +0 -0
- data/doc/images/list_demo.png +0 -0
- data/doc/images/list_styles.png +0 -0
- data/doc/images/login_form.png +0 -0
- data/doc/images/quickstart_dsl.png +0 -0
- data/doc/images/quickstart_lifecycle.png +0 -0
- data/doc/images/readme_usage.png +0 -0
- data/doc/images/rich_text.png +0 -0
- data/doc/images/scroll_text.png +0 -0
- data/doc/images/scrollbar_demo.png +0 -0
- data/doc/images/sparkline_demo.png +0 -0
- data/doc/images/table_flex.png +0 -0
- data/doc/images/table_select.png +0 -0
- data/examples/all_events/app.rb +0 -169
- data/examples/all_events/app.rbs +0 -7
- data/examples/all_events/test_app.rb +0 -139
- data/examples/analytics/app.rb +0 -258
- data/examples/analytics/app.rbs +0 -7
- data/examples/analytics/test_app.rb +0 -132
- data/examples/block_padding/app.rb +0 -63
- data/examples/block_padding/app.rbs +0 -7
- data/examples/block_padding/test_app.rb +0 -31
- data/examples/block_titles/app.rb +0 -61
- data/examples/block_titles/app.rbs +0 -7
- data/examples/block_titles/test_app.rb +0 -34
- data/examples/box_demo/app.rbs +0 -7
- data/examples/box_demo/test_app.rb +0 -88
- data/examples/calendar_demo/app.rb +0 -101
- data/examples/calendar_demo/app.rbs +0 -7
- data/examples/calendar_demo/test_app.rb +0 -108
- data/examples/cell_demo/app.rb +0 -108
- data/examples/cell_demo/app.rbs +0 -7
- data/examples/cell_demo/test_app.rb +0 -36
- data/examples/chart_demo/app.rb +0 -203
- data/examples/chart_demo/app.rbs +0 -7
- data/examples/chart_demo/test_app.rb +0 -102
- data/examples/custom_widget/app.rb +0 -51
- data/examples/custom_widget/app.rbs +0 -7
- data/examples/custom_widget/test_app.rb +0 -30
- data/examples/flex_layout/app.rb +0 -156
- data/examples/flex_layout/app.rbs +0 -7
- data/examples/flex_layout/test_app.rb +0 -65
- data/examples/gauge_demo/app.rb +0 -182
- data/examples/gauge_demo/test_app.rb +0 -120
- data/examples/hit_test/app.rb +0 -175
- data/examples/hit_test/app.rbs +0 -7
- data/examples/hit_test/test_app.rb +0 -102
- data/examples/line_gauge_demo/app.rb +0 -190
- data/examples/line_gauge_demo/app.rbs +0 -7
- data/examples/line_gauge_demo/test_app.rb +0 -129
- data/examples/list_demo/app.rb +0 -253
- data/examples/list_demo/test_app.rb +0 -237
- data/examples/list_styles/app.rb +0 -140
- data/examples/list_styles/app.rbs +0 -7
- data/examples/list_styles/test_app.rb +0 -157
- data/examples/login_form/app.rbs +0 -7
- data/examples/login_form/test_app.rb +0 -51
- data/examples/map_demo/app.rbs +0 -7
- data/examples/map_demo/test_app.rb +0 -149
- data/examples/mouse_events/app.rb +0 -97
- data/examples/mouse_events/app.rbs +0 -7
- data/examples/mouse_events/test_app.rb +0 -53
- data/examples/popup_demo/app.rb +0 -103
- data/examples/popup_demo/app.rbs +0 -7
- data/examples/popup_demo/test_app.rb +0 -54
- data/examples/quickstart_dsl/app.rbs +0 -7
- data/examples/quickstart_dsl/test_app.rb +0 -29
- data/examples/quickstart_lifecycle/app.rb +0 -39
- data/examples/quickstart_lifecycle/app.rbs +0 -7
- data/examples/quickstart_lifecycle/test_app.rb +0 -29
- data/examples/ratatui_logo_demo/app.rb +0 -79
- data/examples/ratatui_logo_demo/app.rbs +0 -7
- data/examples/ratatui_logo_demo/test_app.rb +0 -51
- data/examples/ratatui_mascot_demo/app.rb +0 -84
- data/examples/ratatui_mascot_demo/app.rbs +0 -7
- data/examples/ratatui_mascot_demo/test_app.rb +0 -47
- data/examples/readme_usage/app.rb +0 -29
- data/examples/readme_usage/app.rbs +0 -7
- data/examples/readme_usage/test_app.rb +0 -29
- data/examples/rich_text/app.rb +0 -141
- data/examples/rich_text/app.rbs +0 -7
- data/examples/rich_text/test_app.rb +0 -166
- data/examples/scroll_text/app.rb +0 -103
- data/examples/scroll_text/app.rbs +0 -7
- data/examples/scroll_text/test_app.rb +0 -110
- data/examples/scrollbar_demo/app.rb +0 -143
- data/examples/scrollbar_demo/app.rbs +0 -7
- data/examples/scrollbar_demo/test_app.rb +0 -77
- data/examples/sparkline_demo/app.rb +0 -240
- data/examples/sparkline_demo/test_app.rb +0 -107
- data/examples/table_flex/app.rb +0 -65
- data/examples/table_flex/app.rbs +0 -7
- data/examples/table_flex/test_app.rb +0 -36
- data/examples/table_select/app.rb +0 -198
- data/examples/table_select/app.rbs +0 -7
- data/examples/table_select/test_app.rb +0 -180
- data/examples/widget_style_colors/test_app.rb +0 -48
- data/tasks/bump/comparison_links.rb +0 -41
- /data/doc/images/{analytics.png → app_analytics.png} +0 -0
- /data/doc/images/{custom_widget.png → app_custom_widget.png} +0 -0
- /data/doc/images/{mouse_events.png → app_mouse_events.png} +0 -0
- /data/doc/images/{map_demo.png → widget_map_demo.png} +0 -0
- /data/doc/images/{popup_demo.png → widget_popup_demo.png} +0 -0
- /data/doc/images/{hit_test.png → widget_rect.png} +0 -0
- /data/{doc/images/ratatui_logo_demo.png → exe/.gitkeep} +0 -0
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require "timeout"
|
|
3
|
-
require "minitest/mock"
|
|
4
|
-
|
|
5
2
|
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require_relative "test_helper/terminal"
|
|
5
|
+
require_relative "test_helper/snapshot"
|
|
6
|
+
require_relative "test_helper/event_injection"
|
|
7
|
+
require_relative "test_helper/style_assertions"
|
|
8
|
+
require_relative "test_helper/test_doubles"
|
|
6
9
|
|
|
7
10
|
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
8
11
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -11,208 +14,78 @@ module RatatuiRuby
|
|
|
11
14
|
##
|
|
12
15
|
# Helpers for testing RatatuiRuby applications.
|
|
13
16
|
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
17
|
+
# Writing TUI tests by hand is tedious. You need a headless terminal, event
|
|
18
|
+
# injection, snapshot comparisons, and style assertions. Wiring all that up
|
|
19
|
+
# yourself is error-prone.
|
|
20
|
+
#
|
|
21
|
+
# This module bundles everything you need. Include it in your test class and
|
|
22
|
+
# start writing tests immediately.
|
|
23
|
+
#
|
|
24
|
+
# == Included Mixins
|
|
16
25
|
#
|
|
17
|
-
#
|
|
26
|
+
# [Terminal] Sets up a headless terminal and queries its buffer.
|
|
27
|
+
# [Snapshot] Compares the screen against stored reference files.
|
|
28
|
+
# [EventInjection] Simulates keypresses, mouse clicks, and resize events.
|
|
29
|
+
# [StyleAssertions] Checks foreground color, background color, and text modifiers.
|
|
30
|
+
# [TestDoubles] Provides mocks and stubs for testing views in isolation.
|
|
31
|
+
#
|
|
32
|
+
# == Example
|
|
18
33
|
#
|
|
19
34
|
# require "ratatui_ruby/test_helper"
|
|
20
35
|
#
|
|
21
|
-
# class
|
|
36
|
+
# class TestMyApp < Minitest::Test
|
|
22
37
|
# include RatatuiRuby::TestHelper
|
|
23
38
|
#
|
|
24
|
-
# def
|
|
39
|
+
# def test_initial_render
|
|
25
40
|
# with_test_terminal(80, 24) do
|
|
26
|
-
#
|
|
27
|
-
#
|
|
41
|
+
# MyApp.new.run_once
|
|
42
|
+
# assert_snapshot("initial")
|
|
43
|
+
# end
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# def test_themes
|
|
47
|
+
# with_test_terminal do
|
|
48
|
+
# app = ThemeDemo.new
|
|
49
|
+
# app.run_once
|
|
50
|
+
# assert_rich_snapshot("default_theme")
|
|
51
|
+
#
|
|
52
|
+
# inject_key("t", modifiers: [:ctrl])
|
|
53
|
+
# app.run_once
|
|
54
|
+
# assert_rich_snapshot("dark_theme")
|
|
55
|
+
#
|
|
56
|
+
# inject_key("t", modifiers: [:ctrl])
|
|
57
|
+
# app.run_once
|
|
58
|
+
# assert_rich_snapshot("high_contrast_theme")
|
|
59
|
+
# end
|
|
60
|
+
# end
|
|
61
|
+
#
|
|
62
|
+
# def test_highlighter_applies_selection_style
|
|
63
|
+
# with_test_terminal(40, 5) do
|
|
64
|
+
# RatatuiRuby.draw do |frame|
|
|
65
|
+
# highlighter = MyApp::UI::Highlighter.new(:yellow)
|
|
66
|
+
# highlighter.render_at(frame, 0, 2, "Selected Item")
|
|
67
|
+
# end
|
|
68
|
+
#
|
|
69
|
+
# assert_fg_color(:yellow, 0, 2)
|
|
70
|
+
# assert_bold(0, 2)
|
|
28
71
|
# end
|
|
29
72
|
# end
|
|
30
73
|
#
|
|
31
|
-
# def
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
74
|
+
# def test_view_in_isolation
|
|
75
|
+
# frame = MockFrame.new
|
|
76
|
+
# area = StubRect.new(width: 60, height: 20)
|
|
77
|
+
#
|
|
78
|
+
# MyView.new.call(state, tui, frame, area)
|
|
79
|
+
#
|
|
80
|
+
# widget = frame.rendered_widgets.first[:widget]
|
|
81
|
+
# assert_equal "Dashboard", widget.block.title
|
|
35
82
|
# end
|
|
36
83
|
# end
|
|
37
84
|
module TestHelper
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
# +height+:: height of the test terminal (default: 24)
|
|
44
|
-
#
|
|
45
|
-
# +timeout+:: maximum execution time in seconds (default: 2). Pass nil to disable.
|
|
46
|
-
#
|
|
47
|
-
# If a block is given, it is executed within the test terminal context.
|
|
48
|
-
def with_test_terminal(width = 80, height = 24, timeout: 2)
|
|
49
|
-
RatatuiRuby.init_test_terminal(width, height)
|
|
50
|
-
# Flush any lingering events from previous tests
|
|
51
|
-
while RatatuiRuby.poll_event; end
|
|
52
|
-
|
|
53
|
-
RatatuiRuby.stub :init_terminal, nil do
|
|
54
|
-
RatatuiRuby.stub :restore_terminal, nil do
|
|
55
|
-
begin
|
|
56
|
-
@_ratatui_test_terminal_active = true
|
|
57
|
-
if timeout
|
|
58
|
-
Timeout.timeout(timeout) do
|
|
59
|
-
yield
|
|
60
|
-
end
|
|
61
|
-
else
|
|
62
|
-
yield
|
|
63
|
-
end
|
|
64
|
-
ensure
|
|
65
|
-
@_ratatui_test_terminal_active = false
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
ensure
|
|
70
|
-
RatatuiRuby.restore_terminal
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
##
|
|
74
|
-
# Returns the current content of the terminal buffer as an array of strings.
|
|
75
|
-
# Each string represents a row in the terminal.
|
|
76
|
-
#
|
|
77
|
-
# buffer_content
|
|
78
|
-
# # => ["Row 1 text", "Row 2 text", ...]
|
|
79
|
-
def buffer_content
|
|
80
|
-
RatatuiRuby.get_buffer_content.split("\n")
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
##
|
|
84
|
-
# Returns the current cursor position as a hash with +:x+ and +:y+ keys.
|
|
85
|
-
#
|
|
86
|
-
# cursor_position
|
|
87
|
-
# # => { x: 0, y: 0 }
|
|
88
|
-
def cursor_position
|
|
89
|
-
x, y = RatatuiRuby.get_cursor_position
|
|
90
|
-
{ x:, y: }
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
##
|
|
94
|
-
# Injects an event into the event queue for testing.
|
|
95
|
-
#
|
|
96
|
-
# Pass any RatatuiRuby::Event object. The event will be returned by
|
|
97
|
-
# the next call to RatatuiRuby.poll_event.
|
|
98
|
-
#
|
|
99
|
-
# Raises a +RuntimeError+ if called outside of a +with_test_terminal+ block.
|
|
100
|
-
#
|
|
101
|
-
# == Examples
|
|
102
|
-
#
|
|
103
|
-
# with_test_terminal do
|
|
104
|
-
# # Key events
|
|
105
|
-
# inject_event(RatatuiRuby::Event::Key.new(code: "q"))
|
|
106
|
-
# inject_event(RatatuiRuby::Event::Key.new(code: "s", modifiers: ["ctrl"]))
|
|
107
|
-
#
|
|
108
|
-
# # Mouse events
|
|
109
|
-
# inject_event(RatatuiRuby::Event::Mouse.new(kind: "down", button: "left", x: 10, y: 5))
|
|
110
|
-
#
|
|
111
|
-
# # Resize events
|
|
112
|
-
# inject_event(RatatuiRuby::Event::Resize.new(width: 120, height: 40))
|
|
113
|
-
#
|
|
114
|
-
# # Paste events
|
|
115
|
-
# inject_event(RatatuiRuby::Event::Paste.new(content: "Hello"))
|
|
116
|
-
#
|
|
117
|
-
# # Focus events
|
|
118
|
-
# inject_event(RatatuiRuby::Event::FocusGained.new)
|
|
119
|
-
# inject_event(RatatuiRuby::Event::FocusLost.new)
|
|
120
|
-
# end
|
|
121
|
-
def inject_event(event)
|
|
122
|
-
unless @_ratatui_test_terminal_active
|
|
123
|
-
raise "Events must be injected inside a `with_test_terminal` block. " \
|
|
124
|
-
"Calling this method outside the block causes a race condition where the event " \
|
|
125
|
-
"is flushed before the application starts."
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
case event
|
|
129
|
-
when RatatuiRuby::Event::Key
|
|
130
|
-
RatatuiRuby.inject_test_event("key", { code: event.code, modifiers: event.modifiers })
|
|
131
|
-
when RatatuiRuby::Event::Mouse
|
|
132
|
-
RatatuiRuby.inject_test_event("mouse", {
|
|
133
|
-
kind: event.kind,
|
|
134
|
-
button: event.button,
|
|
135
|
-
x: event.x,
|
|
136
|
-
y: event.y,
|
|
137
|
-
modifiers: event.modifiers
|
|
138
|
-
})
|
|
139
|
-
when RatatuiRuby::Event::Resize
|
|
140
|
-
RatatuiRuby.inject_test_event("resize", { width: event.width, height: event.height })
|
|
141
|
-
when RatatuiRuby::Event::Paste
|
|
142
|
-
RatatuiRuby.inject_test_event("paste", { content: event.content })
|
|
143
|
-
when RatatuiRuby::Event::FocusGained
|
|
144
|
-
RatatuiRuby.inject_test_event("focus_gained", {})
|
|
145
|
-
when RatatuiRuby::Event::FocusLost
|
|
146
|
-
RatatuiRuby.inject_test_event("focus_lost", {})
|
|
147
|
-
else
|
|
148
|
-
raise ArgumentError, "Unknown event type: #{event.class}"
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
##
|
|
153
|
-
# Injects multiple Key events into the queue.
|
|
154
|
-
#
|
|
155
|
-
# Supports multiple formats for convenience:
|
|
156
|
-
#
|
|
157
|
-
# * String: Converted to a Key event with that code.
|
|
158
|
-
# * Symbol: Parsed as modifier_code (e.g., <tt>:ctrl_c</tt>, <tt>:enter</tt>).
|
|
159
|
-
# * Hash: Passed to Key.new constructor.
|
|
160
|
-
# * Key: Passed directly.
|
|
161
|
-
#
|
|
162
|
-
# == Examples
|
|
163
|
-
#
|
|
164
|
-
# with_test_terminal do
|
|
165
|
-
# inject_keys("a", "b", "c")
|
|
166
|
-
# inject_keys(:enter, :esc)
|
|
167
|
-
# inject_keys(:ctrl_c, :alt_shift_left)
|
|
168
|
-
# inject_keys("j", { code: "k", modifiers: ["ctrl"] })
|
|
169
|
-
# end
|
|
170
|
-
def inject_keys(*args)
|
|
171
|
-
args.each do |arg|
|
|
172
|
-
event = case arg
|
|
173
|
-
when String
|
|
174
|
-
RatatuiRuby::Event::Key.new(code: arg)
|
|
175
|
-
when Symbol
|
|
176
|
-
parts = arg.to_s.split("_")
|
|
177
|
-
code = parts.pop
|
|
178
|
-
modifiers = parts
|
|
179
|
-
RatatuiRuby::Event::Key.new(code: code, modifiers: modifiers)
|
|
180
|
-
when Hash
|
|
181
|
-
RatatuiRuby::Event::Key.new(**arg)
|
|
182
|
-
when RatatuiRuby::Event::Key
|
|
183
|
-
arg
|
|
184
|
-
else
|
|
185
|
-
raise ArgumentError, "Invalid key argument: #{arg.inspect}. Expected String, Symbol, Hash, or Key event."
|
|
186
|
-
end
|
|
187
|
-
inject_event(event)
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
alias inject_key inject_keys
|
|
191
|
-
|
|
192
|
-
##
|
|
193
|
-
# Returns the cell attributes at the given coordinates.
|
|
194
|
-
#
|
|
195
|
-
# get_cell(0, 0)
|
|
196
|
-
# # => { "symbol" => "H", "fg" => :red, "bg" => nil }
|
|
197
|
-
def get_cell(x, y)
|
|
198
|
-
RatatuiRuby.get_cell_at(x, y)
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
##
|
|
202
|
-
# Asserts that the cell at the given coordinates has the expected attributes.
|
|
203
|
-
#
|
|
204
|
-
# assert_cell_style(0, 0, char: "H", fg: :red)
|
|
205
|
-
def assert_cell_style(x, y, **expected_attributes)
|
|
206
|
-
cell = get_cell(x, y)
|
|
207
|
-
expected_attributes.each do |key, value|
|
|
208
|
-
actual_value = cell.public_send(key)
|
|
209
|
-
if value.nil?
|
|
210
|
-
assert_nil actual_value, "Expected cell at (#{x}, #{y}) to have #{key}=nil, but got #{actual_value.inspect}"
|
|
211
|
-
else
|
|
212
|
-
assert_equal value, actual_value, "Expected cell at (#{x}, #{y}) to have #{key}=#{value.inspect}, but got #{actual_value.inspect}"
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
end
|
|
85
|
+
include Terminal
|
|
86
|
+
include Snapshot
|
|
87
|
+
include EventInjection
|
|
88
|
+
include StyleAssertions
|
|
89
|
+
include TestDoubles
|
|
216
90
|
end
|
|
217
91
|
end
|
|
218
|
-
|
data/lib/ratatui_ruby/version.rb
CHANGED
data/lib/ratatui_ruby.rb
CHANGED
|
@@ -10,6 +10,7 @@ require_relative "ratatui_ruby/schema/layout"
|
|
|
10
10
|
require_relative "ratatui_ruby/schema/block"
|
|
11
11
|
require_relative "ratatui_ruby/schema/constraint"
|
|
12
12
|
require_relative "ratatui_ruby/schema/list"
|
|
13
|
+
require_relative "ratatui_ruby/schema/list_item"
|
|
13
14
|
require_relative "ratatui_ruby/schema/style"
|
|
14
15
|
require_relative "ratatui_ruby/schema/gauge"
|
|
15
16
|
require_relative "ratatui_ruby/schema/line_gauge"
|
|
@@ -34,6 +35,10 @@ require_relative "ratatui_ruby/schema/text"
|
|
|
34
35
|
require_relative "ratatui_ruby/schema/draw"
|
|
35
36
|
require_relative "ratatui_ruby/event"
|
|
36
37
|
require_relative "ratatui_ruby/cell"
|
|
38
|
+
require_relative "ratatui_ruby/frame"
|
|
39
|
+
require_relative "ratatui_ruby/list_state"
|
|
40
|
+
require_relative "ratatui_ruby/table_state"
|
|
41
|
+
require_relative "ratatui_ruby/scrollbar_state"
|
|
37
42
|
|
|
38
43
|
begin
|
|
39
44
|
require "ratatui_ruby/ratatui_ruby"
|
|
@@ -51,7 +56,13 @@ end
|
|
|
51
56
|
# Use `RatatuiRuby.run` to start your application.
|
|
52
57
|
module RatatuiRuby
|
|
53
58
|
# Generic error class for RatatuiRuby.
|
|
54
|
-
class Error < StandardError
|
|
59
|
+
class Error < StandardError
|
|
60
|
+
# Raised when a terminal operation fails (e.g., I/O error, backend failure).
|
|
61
|
+
class Terminal < Error; end
|
|
62
|
+
|
|
63
|
+
# Raised when an API safety contract is violated (e.g., accessing a Frame outside its valid scope).
|
|
64
|
+
class Safety < Error; end
|
|
65
|
+
end
|
|
55
66
|
|
|
56
67
|
##
|
|
57
68
|
# Initializes the terminal for TUI mode.
|
|
@@ -71,6 +82,23 @@ module RatatuiRuby
|
|
|
71
82
|
attr_accessor :experimental_warnings
|
|
72
83
|
end
|
|
73
84
|
|
|
85
|
+
##
|
|
86
|
+
# :singleton-method: restore_terminal
|
|
87
|
+
# Restores the terminal to its original state.
|
|
88
|
+
# Leaves alternate screen and disables raw mode.
|
|
89
|
+
#
|
|
90
|
+
# (Native method implemented in Rust)
|
|
91
|
+
|
|
92
|
+
##
|
|
93
|
+
# :singleton-method: inject_test_event
|
|
94
|
+
# Injects a mock event into the event queue for testing purposes.
|
|
95
|
+
# [event_type] "key" or "mouse"
|
|
96
|
+
# [data] a Hash containing event data
|
|
97
|
+
#
|
|
98
|
+
# inject_test_event("key", { code: "a" })
|
|
99
|
+
#
|
|
100
|
+
# (Native method implemented in Rust)
|
|
101
|
+
|
|
74
102
|
##
|
|
75
103
|
# Warns about usage of an experimental feature unless warnings are suppressed.
|
|
76
104
|
#
|
|
@@ -91,60 +119,100 @@ module RatatuiRuby
|
|
|
91
119
|
private_class_method :_init_terminal
|
|
92
120
|
|
|
93
121
|
##
|
|
94
|
-
#
|
|
95
|
-
# :call-seq: restore_terminal() -> nil
|
|
122
|
+
# Draws the given UI node tree to the terminal.
|
|
96
123
|
#
|
|
97
|
-
#
|
|
98
|
-
#
|
|
124
|
+
# TUI applications need to render widgets to the screen. Rendering could
|
|
125
|
+
# happen all at once with a pre-built tree, or incrementally with direct
|
|
126
|
+
# frame access.
|
|
99
127
|
#
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# :method: draw
|
|
104
|
-
# :call-seq: draw(node) -> nil
|
|
128
|
+
# This method handles both. Pass a tree for declarative rendering, or
|
|
129
|
+
# pass a block to manipulate the frame directly. The block receives a
|
|
130
|
+
# {Frame} object for imperative drawing.
|
|
105
131
|
#
|
|
106
|
-
#
|
|
107
|
-
#
|
|
132
|
+
# [tree] A widget tree (Paragraph, Layout, etc.) to render. Optional if
|
|
133
|
+
# a block is given.
|
|
108
134
|
#
|
|
109
|
-
#
|
|
135
|
+
# === Examples
|
|
136
|
+
#
|
|
137
|
+
# Legacy declarative style (tree-based):
|
|
138
|
+
#
|
|
139
|
+
# RatatuiRuby.draw(Paragraph.new(text: "Hello"))
|
|
140
|
+
#
|
|
141
|
+
# New imperative style (block-based):
|
|
142
|
+
#
|
|
143
|
+
# RatatuiRuby.draw do |frame|
|
|
144
|
+
# frame.render_widget(Paragraph.new(text: "Hello"), frame.area)
|
|
145
|
+
# end
|
|
146
|
+
#
|
|
147
|
+
def self.draw(tree = nil, &block)
|
|
148
|
+
if tree && block
|
|
149
|
+
raise ArgumentError, "Cannot provide both a tree and a block to draw"
|
|
150
|
+
end
|
|
151
|
+
unless tree || block
|
|
152
|
+
raise ArgumentError, "Must provide either a tree or a block to draw"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
if tree
|
|
156
|
+
_draw(tree)
|
|
157
|
+
else
|
|
158
|
+
_draw(&block)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# (Native method _draw implemented in Rust)
|
|
163
|
+
private_class_method :_draw
|
|
110
164
|
|
|
111
165
|
##
|
|
112
|
-
# :method: poll_event
|
|
113
|
-
# :call-seq: poll_event() -> Event, nil
|
|
114
|
-
#
|
|
115
166
|
# Checks for user input.
|
|
116
167
|
#
|
|
117
|
-
#
|
|
118
|
-
# Returns nil immediately if the queue is empty (non-blocking).
|
|
168
|
+
# Interactive apps must respond to input. Loops need to poll without burning CPU.
|
|
119
169
|
#
|
|
120
|
-
#
|
|
170
|
+
# This method checks for an event. It returns the event if one is found. It returns {RatatuiRuby::Event::None} if the timeout expires.
|
|
171
|
+
#
|
|
172
|
+
# [timeout] Float seconds to wait (default: 0.016).
|
|
173
|
+
# Pass <tt>nil</tt> to block indefinitely (wait forever).
|
|
174
|
+
# Pass <tt>0.0</tt> for a non-blocking check.
|
|
121
175
|
#
|
|
176
|
+
# === Examples
|
|
177
|
+
#
|
|
178
|
+
# # Standard loop (approx 60 FPS)
|
|
122
179
|
# event = RatatuiRuby.poll_event
|
|
123
|
-
# puts "Key pressed" if event.is_a?(RatatuiRuby::Event::Key)
|
|
124
180
|
#
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
181
|
+
# # Block until event (pauses execution)
|
|
182
|
+
# event = RatatuiRuby.poll_event(timeout: nil)
|
|
183
|
+
#
|
|
184
|
+
# # Non-blocking check (returns immediately)
|
|
185
|
+
# event = RatatuiRuby.poll_event(timeout: 0.0)
|
|
186
|
+
#
|
|
187
|
+
def self.poll_event(timeout: 0.016)
|
|
188
|
+
raise ArgumentError, "timeout must be non-negative" if timeout && timeout < 0
|
|
189
|
+
|
|
190
|
+
raw = _poll_event(timeout)
|
|
191
|
+
return Event::None.new.freeze if raw.nil?
|
|
128
192
|
|
|
129
193
|
case raw[:type]
|
|
130
194
|
when :key
|
|
131
|
-
Event::Key.new(
|
|
195
|
+
Event::Key.new(
|
|
196
|
+
code: raw[:code],
|
|
197
|
+
modifiers: (raw[:modifiers] || []).freeze,
|
|
198
|
+
kind: raw[:kind] || :standard
|
|
199
|
+
).freeze
|
|
132
200
|
when :mouse
|
|
133
201
|
Event::Mouse.new(
|
|
134
202
|
kind: raw[:kind].to_s,
|
|
135
203
|
x: raw[:x],
|
|
136
204
|
y: raw[:y],
|
|
137
205
|
button: raw[:button].to_s,
|
|
138
|
-
modifiers: raw[:modifiers] || []
|
|
139
|
-
)
|
|
206
|
+
modifiers: (raw[:modifiers] || []).freeze
|
|
207
|
+
).freeze
|
|
140
208
|
when :resize
|
|
141
|
-
Event::Resize.new(width: raw[:width], height: raw[:height])
|
|
209
|
+
Event::Resize.new(width: raw[:width], height: raw[:height]).freeze
|
|
142
210
|
when :paste
|
|
143
|
-
Event::Paste.new(content: raw[:content])
|
|
211
|
+
Event::Paste.new(content: raw[:content]).freeze
|
|
144
212
|
when :focus_gained
|
|
145
|
-
Event::FocusGained.new
|
|
213
|
+
Event::FocusGained.new.freeze
|
|
146
214
|
when :focus_lost
|
|
147
|
-
Event::FocusLost.new
|
|
215
|
+
Event::FocusLost.new.freeze
|
|
148
216
|
else
|
|
149
217
|
# Fallback for unknown events, though ideally we cover them all
|
|
150
218
|
nil
|
|
@@ -155,21 +223,6 @@ module RatatuiRuby
|
|
|
155
223
|
private_class_method :_poll_event
|
|
156
224
|
|
|
157
225
|
##
|
|
158
|
-
# :method: inject_test_event
|
|
159
|
-
# :call-seq: inject_test_event(event_type, data) -> nil
|
|
160
|
-
#
|
|
161
|
-
# Injects a mock event into the event queue for testing purposes.
|
|
162
|
-
# [event_type] "key" or "mouse"
|
|
163
|
-
# [data] a Hash containing event data
|
|
164
|
-
#
|
|
165
|
-
# inject_test_event("key", { code: "a" })
|
|
166
|
-
#
|
|
167
|
-
# (Native method implemented in Rust)
|
|
168
|
-
|
|
169
|
-
##
|
|
170
|
-
# :method: run
|
|
171
|
-
# :call-seq: run { |session| ... } -> Object
|
|
172
|
-
#
|
|
173
226
|
# Starts the TUI application lifecycle.
|
|
174
227
|
#
|
|
175
228
|
# Managing generic setup/teardown (raw mode, alternate screen) manualy is error-prone. If your app crashes, the terminal might be left in a broken state.
|
|
@@ -184,16 +237,13 @@ module RatatuiRuby
|
|
|
184
237
|
# end
|
|
185
238
|
def self.run(focus_events: true, bracketed_paste: true)
|
|
186
239
|
require_relative "ratatui_ruby/session"
|
|
187
|
-
init_terminal(focus_events
|
|
240
|
+
init_terminal(focus_events:, bracketed_paste:)
|
|
188
241
|
yield Session.new
|
|
189
242
|
ensure
|
|
190
243
|
restore_terminal
|
|
191
244
|
end
|
|
192
245
|
|
|
193
246
|
##
|
|
194
|
-
# :method: get_cell_at
|
|
195
|
-
# :call-seq: get_cell_at(x, y) -> Cell
|
|
196
|
-
#
|
|
197
247
|
# Inspects the terminal buffer at specific coordinates.
|
|
198
248
|
#
|
|
199
249
|
# When writing tests, you need to verify that your widget drew the correct characters and styles.
|
|
@@ -224,6 +274,5 @@ module RatatuiRuby
|
|
|
224
274
|
private_class_method :_get_cell_at
|
|
225
275
|
|
|
226
276
|
# Hide native Layout._split helper
|
|
227
|
-
Layout.singleton_class.
|
|
228
|
-
|
|
277
|
+
Layout.singleton_class.__send__(:private, :_split)
|
|
229
278
|
end
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
#
|
|
2
3
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
4
|
|
|
4
|
-
class
|
|
5
|
+
class AppAllEvents
|
|
5
6
|
# @public
|
|
6
|
-
def self.new: () ->
|
|
7
|
+
def self.new: () -> AppAllEvents
|
|
7
8
|
|
|
8
9
|
# @public
|
|
9
10
|
def run: () -> void
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
class EventEntry < Data
|
|
5
|
+
attr_reader type: Symbol
|
|
6
|
+
attr_reader sub_key: Symbol | String | nil
|
|
7
|
+
attr_reader color: Symbol
|
|
8
|
+
attr_reader timestamp: Timestamp
|
|
9
|
+
attr_reader data: Hash[Symbol, untyped]
|
|
10
|
+
|
|
11
|
+
def self.from_event(type: Symbol, sub_key: Symbol | String | nil, color: Symbol, timestamp: Timestamp, data: Hash[Symbol, untyped]) -> instance
|
|
12
|
+
def matches_type?: (Symbol check_type) -> bool
|
|
13
|
+
def matches_sub_type?: (Symbol check_type, Symbol | String check_sub_key) -> bool
|
|
14
|
+
def matches_kind?: (String kind) -> bool
|
|
15
|
+
def self.new: (?type: Symbol, ?sub_key: Symbol | String | nil, ?color: Symbol, ?timestamp: Timestamp, ?data: Hash[Symbol, untyped]) -> instance
|
|
16
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
class Events
|
|
5
|
+
def initialize: () -> void
|
|
6
|
+
def record: (Symbol type, ?time: Time, ?description: String, ?sub_key: Symbol | String | nil, ?data: Hash[Symbol, untyped], ?live_type: Symbol) -> void
|
|
7
|
+
def live_event: (Symbol type) -> { time: Time, description: String } | nil
|
|
8
|
+
def live_events: () -> Hash[Symbol, { time: Time, description: String }]
|
|
9
|
+
def visible: (Integer max_entries) -> Array[EventEntry]
|
|
10
|
+
def empty?: () -> bool
|
|
11
|
+
def count: (Symbol type, ?Symbol | nil sub_type) -> Integer
|
|
12
|
+
def count_by_kind: (String kind) -> Integer
|
|
13
|
+
def lit?: (Symbol type, ?Symbol | String | nil sub_key) -> bool
|
|
14
|
+
def entries: () -> Array[EventEntry]
|
|
15
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
class Timestamp < Data
|
|
5
|
+
attr_reader milliseconds: Integer
|
|
6
|
+
|
|
7
|
+
def self.now: () -> instance
|
|
8
|
+
def self.current: () -> Integer
|
|
9
|
+
def elapsed?: (Integer duration_ms) -> bool
|
|
10
|
+
def self.new: (?milliseconds: Numeric) -> instance
|
|
11
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
module View
|
|
5
|
+
interface _View
|
|
6
|
+
def call(state: ViewState, tui: RatatuiRuby::Session, frame: RatatuiRuby::Frame, area: RatatuiRuby::Rect) -> void
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
class ViewState < Data
|
|
5
|
+
attr_reader events: Events
|
|
6
|
+
attr_reader focused: bool
|
|
7
|
+
attr_reader hotkey_style: RatatuiRuby::Style
|
|
8
|
+
attr_reader dimmed_style: RatatuiRuby::Style
|
|
9
|
+
attr_reader lit_style: RatatuiRuby::Style
|
|
10
|
+
attr_reader border_color: Symbol
|
|
11
|
+
attr_reader area: RatatuiRuby::Rect?
|
|
12
|
+
|
|
13
|
+
def self.build(events: Events, focused: bool, tui: RatatuiRuby::Session, _resize_sub_counter: untyped) -> instance
|
|
14
|
+
def self.new: (?events: Events, ?focused: bool, ?hotkey_style: RatatuiRuby::Style, ?dimmed_style: RatatuiRuby::Style, ?lit_style: RatatuiRuby::Style, ?border_color: Symbol, ?area: RatatuiRuby::Rect | nil) -> instance
|
|
15
|
+
end
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
4
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
|
|
6
|
-
class
|
|
6
|
+
class AppColorPicker
|
|
7
7
|
# @public
|
|
8
|
-
def self.new: () ->
|
|
8
|
+
def self.new: () -> AppColorPicker
|
|
9
9
|
|
|
10
10
|
# @public
|
|
11
11
|
def run: () -> void
|