ratatui_ruby 0.8.0 → 0.9.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 +2 -2
- data/.builds/ruby-3.3.yml +2 -2
- data/.builds/ruby-3.4.yml +2 -2
- data/.builds/ruby-4.0.0.yml +2 -2
- data/.pre-commit-config.yaml +1 -1
- data/AGENTS.md +3 -3
- data/CHANGELOG.md +53 -1
- data/LICENSES/LGPL-3.0-or-later.txt +304 -0
- data/LICENSES/MIT-0.txt +16 -0
- data/README.md +33 -5
- data/Rakefile +1 -1
- data/doc/concepts/application_architecture.md +44 -3
- data/doc/concepts/application_testing.md +43 -1
- data/doc/concepts/async.md +32 -2
- data/doc/concepts/custom_widgets.md +247 -0
- data/doc/concepts/event_handling.md +32 -3
- data/doc/concepts/interactive_design.md +32 -2
- data/doc/contributors/auditing/parity.md +7 -1
- data/doc/contributors/design/ruby_frontend.md +85 -1
- data/doc/contributors/design/rust_backend.md +67 -1
- data/doc/contributors/developing_examples.md +56 -2
- data/doc/contributors/documentation_style.md +20 -3
- data/doc/contributors/future_work.md +169 -0
- data/doc/contributors/index.md +1 -1
- data/doc/contributors/v1.0.0_blockers.md +15 -175
- data/doc/getting_started/quickstart.md +22 -4
- data/doc/getting_started/why.md +1 -1
- data/doc/index.md +2 -1
- data/doc/troubleshooting/debugging.md +32 -2
- data/doc/troubleshooting/terminal_limitations.md +8 -2
- data/doc/troubleshooting/tui_output.md +42 -0
- data/examples/app_all_events/README.md +14 -2
- data/examples/app_all_events/app.rb +1 -1
- data/examples/app_all_events/model/app_model.rb +1 -1
- data/examples/app_all_events/model/event_color_cycle.rb +1 -1
- data/examples/app_all_events/model/event_entry.rb +1 -1
- data/examples/app_all_events/model/msg.rb +1 -1
- data/examples/app_all_events/model/timestamp.rb +1 -1
- data/examples/app_all_events/update.rb +1 -1
- data/examples/app_all_events/view/app_view.rb +1 -1
- data/examples/app_all_events/view/controls_view.rb +1 -1
- data/examples/app_all_events/view/counts_view.rb +1 -1
- data/examples/app_all_events/view/live_view.rb +1 -1
- data/examples/app_all_events/view/log_view.rb +1 -1
- data/examples/app_all_events/view.rb +1 -1
- data/examples/app_color_picker/README.md +20 -2
- data/examples/app_color_picker/app.rb +1 -1
- data/examples/app_color_picker/clipboard.rb +1 -1
- data/examples/app_color_picker/color.rb +1 -1
- data/examples/app_color_picker/controls.rb +1 -1
- data/examples/app_color_picker/copy_dialog.rb +1 -1
- data/examples/app_color_picker/export_pane.rb +1 -1
- data/examples/app_color_picker/harmony.rb +1 -1
- data/examples/app_color_picker/input.rb +1 -1
- data/examples/app_color_picker/main_container.rb +1 -1
- data/examples/app_color_picker/palette.rb +1 -1
- data/examples/app_login_form/README.md +8 -2
- data/examples/app_login_form/app.rb +1 -1
- data/examples/app_stateful_interaction/README.md +2 -2
- data/examples/app_stateful_interaction/app.rb +71 -17
- data/examples/timeout_demo.rb +1 -1
- data/examples/verify_quickstart_dsl/README.md +6 -0
- data/examples/verify_quickstart_dsl/app.rb +3 -3
- data/examples/verify_quickstart_layout/README.md +6 -0
- data/examples/verify_quickstart_layout/app.rb +3 -3
- data/examples/verify_quickstart_lifecycle/README.md +6 -0
- data/examples/verify_quickstart_lifecycle/app.rb +3 -3
- data/examples/verify_readme_usage/README.md +6 -0
- data/examples/verify_readme_usage/app.rb +3 -3
- data/examples/widget_barchart/README.md +6 -0
- data/examples/widget_barchart/app.rb +2 -2
- data/examples/widget_block/README.md +7 -1
- data/examples/widget_block/app.rb +2 -2
- data/examples/widget_box/README.md +6 -0
- data/examples/widget_box/app.rb +9 -6
- data/examples/widget_calendar/README.md +6 -0
- data/examples/widget_calendar/app.rb +2 -2
- data/examples/widget_canvas/README.md +4 -0
- data/examples/widget_canvas/app.rb +2 -2
- data/examples/widget_cell/README.md +6 -0
- data/examples/widget_cell/app.rb +2 -3
- data/examples/widget_center/README.md +4 -0
- data/examples/widget_center/app.rb +2 -2
- data/examples/widget_chart/README.md +6 -0
- data/examples/widget_chart/app.rb +2 -2
- data/examples/widget_gauge/README.md +6 -0
- data/examples/widget_gauge/app.rb +2 -2
- data/examples/widget_layout_split/README.md +6 -0
- data/examples/widget_layout_split/app.rb +3 -3
- data/examples/widget_line_gauge/README.md +6 -0
- data/examples/widget_line_gauge/app.rb +2 -2
- data/examples/widget_list/README.md +6 -0
- data/examples/widget_list/app.rb +2 -2
- data/examples/widget_map/README.md +8 -2
- data/examples/widget_map/app.rb +2 -2
- data/examples/widget_overlay/README.md +7 -1
- data/examples/widget_overlay/app.rb +2 -2
- data/examples/widget_popup/README.md +6 -0
- data/examples/widget_popup/app.rb +2 -2
- data/examples/widget_ratatui_logo/README.md +6 -0
- data/examples/widget_ratatui_logo/app.rb +2 -3
- data/examples/widget_ratatui_mascot/README.md +6 -0
- data/examples/widget_ratatui_mascot/app.rb +2 -2
- data/examples/widget_rect/README.md +12 -0
- data/examples/widget_rect/app.rb +40 -26
- data/examples/widget_render/README.md +6 -0
- data/examples/widget_render/app.rb +2 -2
- data/examples/widget_render/app.rbs +41 -0
- data/examples/widget_rich_text/README.md +6 -0
- data/examples/widget_rich_text/app.rb +2 -2
- data/examples/widget_scroll_text/README.md +6 -0
- data/examples/widget_scroll_text/app.rb +2 -2
- data/examples/widget_scrollbar/README.md +6 -0
- data/examples/widget_scrollbar/app.rb +2 -2
- data/examples/widget_sparkline/README.md +6 -0
- data/examples/widget_sparkline/app.rb +2 -2
- data/examples/widget_style_colors/README.md +6 -0
- data/examples/widget_style_colors/app.rb +2 -2
- data/examples/widget_table/README.md +8 -2
- data/examples/widget_table/app.rb +2 -2
- data/examples/widget_tabs/README.md +6 -0
- data/examples/widget_tabs/app.rb +2 -2
- data/examples/widget_text_width/README.md +6 -0
- data/examples/widget_text_width/app.rb +4 -4
- data/ext/ratatui_ruby/Cargo.lock +1 -1
- data/ext/ratatui_ruby/Cargo.toml +1 -1
- data/ext/ratatui_ruby/extconf.rb +2 -2
- data/ext/ratatui_ruby/src/rendering.rs +1 -1
- data/ext/ratatui_ruby/src/style.rs +0 -8
- data/ext/ratatui_ruby/src/widgets/chart.rs +0 -118
- data/ext/ratatui_ruby/src/widgets/list_state.rs +36 -0
- data/lib/ratatui_ruby/buffer/cell.rb +34 -2
- data/lib/ratatui_ruby/buffer.rb +2 -2
- data/lib/ratatui_ruby/cell.rb +34 -2
- data/lib/ratatui_ruby/event/focus_gained.rb +26 -2
- data/lib/ratatui_ruby/event/focus_lost.rb +26 -2
- data/lib/ratatui_ruby/event/key/character.rb +18 -2
- data/lib/ratatui_ruby/event/key/media.rb +2 -2
- data/lib/ratatui_ruby/event/key/modifier.rb +10 -2
- data/lib/ratatui_ruby/event/key/navigation.rb +2 -2
- data/lib/ratatui_ruby/event/key/system.rb +2 -2
- data/lib/ratatui_ruby/event/key.rb +114 -2
- data/lib/ratatui_ruby/event/mouse.rb +42 -2
- data/lib/ratatui_ruby/event/none.rb +10 -2
- data/lib/ratatui_ruby/event/paste.rb +34 -2
- data/lib/ratatui_ruby/event/resize.rb +34 -2
- data/lib/ratatui_ruby/event.rb +26 -2
- data/lib/ratatui_ruby/frame.rb +74 -2
- data/lib/ratatui_ruby/layout/constraint.rb +58 -2
- data/lib/ratatui_ruby/layout/layout.rb +47 -2
- data/lib/ratatui_ruby/layout/rect.rb +403 -2
- data/lib/ratatui_ruby/layout.rb +2 -2
- data/lib/ratatui_ruby/list_state.rb +113 -2
- data/lib/ratatui_ruby/output_guard.rb +26 -3
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +2 -2
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +2 -2
- data/lib/ratatui_ruby/schema/bar_chart.rb +50 -2
- data/lib/ratatui_ruby/schema/block.rb +21 -15
- data/lib/ratatui_ruby/schema/calendar.rb +2 -2
- data/lib/ratatui_ruby/schema/canvas.rb +10 -2
- data/lib/ratatui_ruby/schema/center.rb +10 -2
- data/lib/ratatui_ruby/schema/chart.rb +2 -28
- data/lib/ratatui_ruby/schema/clear.rb +10 -2
- data/lib/ratatui_ruby/schema/constraint.rb +58 -2
- data/lib/ratatui_ruby/schema/cursor.rb +10 -2
- data/lib/ratatui_ruby/schema/draw.rb +10 -2
- data/lib/ratatui_ruby/schema/gauge.rb +2 -2
- data/lib/ratatui_ruby/schema/layout.rb +18 -2
- data/lib/ratatui_ruby/schema/line_gauge.rb +2 -2
- data/lib/ratatui_ruby/schema/list.rb +10 -2
- data/lib/ratatui_ruby/schema/list_item.rb +10 -2
- data/lib/ratatui_ruby/schema/overlay.rb +10 -2
- data/lib/ratatui_ruby/schema/paragraph.rb +10 -2
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +2 -2
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +2 -2
- data/lib/ratatui_ruby/schema/rect.rb +58 -2
- data/lib/ratatui_ruby/schema/row.rb +10 -2
- data/lib/ratatui_ruby/schema/scrollbar.rb +2 -2
- data/lib/ratatui_ruby/schema/shape/label.rb +10 -2
- data/lib/ratatui_ruby/schema/sparkline.rb +10 -2
- data/lib/ratatui_ruby/schema/style.rb +18 -2
- data/lib/ratatui_ruby/schema/table.rb +2 -2
- data/lib/ratatui_ruby/schema/tabs.rb +2 -2
- data/lib/ratatui_ruby/schema/text.rb +34 -2
- data/lib/ratatui_ruby/scrollbar_state.rb +10 -2
- data/lib/ratatui_ruby/style/style.rb +18 -2
- data/lib/ratatui_ruby/style.rb +2 -2
- data/lib/ratatui_ruby/table_state.rb +10 -2
- data/lib/ratatui_ruby/terminal_lifecycle.rb +18 -3
- data/lib/ratatui_ruby/test_helper/event_injection.rb +34 -2
- data/lib/ratatui_ruby/test_helper/snapshot.rb +74 -9
- data/lib/ratatui_ruby/test_helper/style_assertions.rb +98 -2
- data/lib/ratatui_ruby/test_helper/terminal.rb +50 -2
- data/lib/ratatui_ruby/test_helper/test_doubles.rb +18 -2
- data/lib/ratatui_ruby/test_helper.rb +10 -2
- data/lib/ratatui_ruby/tui/buffer_factories.rb +2 -2
- data/lib/ratatui_ruby/tui/canvas_factories.rb +2 -2
- data/lib/ratatui_ruby/tui/core.rb +2 -2
- data/lib/ratatui_ruby/tui/layout_factories.rb +32 -2
- data/lib/ratatui_ruby/tui/state_factories.rb +2 -2
- data/lib/ratatui_ruby/tui/style_factories.rb +2 -2
- data/lib/ratatui_ruby/tui/text_factories.rb +2 -2
- data/lib/ratatui_ruby/tui/widget_factories.rb +2 -2
- data/lib/ratatui_ruby/tui.rb +11 -3
- data/lib/ratatui_ruby/version.rb +3 -3
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -2
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -2
- data/lib/ratatui_ruby/widgets/bar_chart.rb +58 -2
- data/lib/ratatui_ruby/widgets/block.rb +37 -15
- data/lib/ratatui_ruby/widgets/calendar.rb +2 -2
- data/lib/ratatui_ruby/widgets/canvas.rb +10 -2
- data/lib/ratatui_ruby/widgets/cell.rb +10 -2
- data/lib/ratatui_ruby/widgets/center.rb +10 -2
- data/lib/ratatui_ruby/widgets/chart.rb +2 -28
- data/lib/ratatui_ruby/widgets/clear.rb +10 -2
- data/lib/ratatui_ruby/widgets/cursor.rb +10 -2
- data/lib/ratatui_ruby/widgets/gauge.rb +16 -2
- data/lib/ratatui_ruby/widgets/line_gauge.rb +16 -2
- data/lib/ratatui_ruby/widgets/list.rb +41 -2
- data/lib/ratatui_ruby/widgets/list_item.rb +10 -2
- data/lib/ratatui_ruby/widgets/overlay.rb +10 -2
- data/lib/ratatui_ruby/widgets/paragraph.rb +10 -2
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -2
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -2
- data/lib/ratatui_ruby/widgets/row.rb +10 -2
- data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -2
- data/lib/ratatui_ruby/widgets/shape/label.rb +10 -2
- data/lib/ratatui_ruby/widgets/sparkline.rb +10 -2
- data/lib/ratatui_ruby/widgets/table.rb +62 -2
- data/lib/ratatui_ruby/widgets/tabs.rb +2 -2
- data/lib/ratatui_ruby/widgets.rb +2 -2
- data/lib/ratatui_ruby.rb +90 -2
- data/sig/examples/app_all_events/view.rbs +7 -1
- data/sig/examples/app_all_events/view_state.rbs +7 -1
- data/sig/examples/app_color_picker/app.rbs +5 -0
- data/sig/examples/app_stateful_interaction/app.rbs +7 -1
- data/sig/examples/verify_quickstart_dsl/app.rbs +7 -1
- data/sig/examples/verify_quickstart_lifecycle/app.rbs +7 -1
- data/sig/examples/verify_readme_usage/app.rbs +7 -1
- data/sig/examples/widget_block_demo/app.rbs +6 -0
- data/sig/examples/widget_box_demo/app.rbs +7 -1
- data/sig/examples/widget_calendar_demo/app.rbs +7 -1
- data/sig/examples/widget_cell_demo/app.rbs +7 -1
- data/sig/examples/widget_chart_demo/app.rbs +7 -1
- data/sig/examples/widget_gauge_demo/app.rbs +7 -1
- data/sig/examples/widget_layout_split/app.rbs +7 -1
- data/sig/examples/widget_line_gauge_demo/app.rbs +7 -1
- data/sig/examples/widget_list_demo/app.rbs +5 -0
- data/sig/examples/widget_map_demo/app.rbs +7 -1
- data/sig/examples/widget_popup_demo/app.rbs +7 -1
- data/sig/examples/widget_ratatui_logo_demo/app.rbs +7 -1
- data/sig/examples/widget_ratatui_mascot_demo/app.rbs +7 -1
- data/sig/examples/widget_rect/app.rbs +7 -1
- data/sig/examples/widget_render/app.rbs +7 -1
- data/sig/examples/widget_rich_text/app.rbs +7 -1
- data/sig/examples/widget_scroll_text/app.rbs +7 -1
- data/sig/examples/widget_scrollbar_demo/app.rbs +7 -1
- data/sig/examples/widget_sparkline_demo/app.rbs +7 -1
- data/sig/examples/widget_style_colors/app.rbs +7 -1
- data/sig/examples/widget_table_demo/app.rbs +7 -1
- data/sig/examples/widget_text_width/app.rbs +7 -1
- data/sig/ratatui_ruby/event.rbs +7 -1
- data/sig/ratatui_ruby/frame.rbs +15 -3
- data/sig/ratatui_ruby/list_state.rbs +11 -1
- data/sig/ratatui_ruby/ratatui_ruby.rbs +8 -2
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +7 -1
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +6 -0
- data/sig/ratatui_ruby/schema/bar_chart.rbs +6 -0
- data/sig/ratatui_ruby/schema/block.rbs +7 -1
- data/sig/ratatui_ruby/schema/calendar.rbs +6 -0
- data/sig/ratatui_ruby/schema/canvas.rbs +6 -0
- data/sig/ratatui_ruby/schema/center.rbs +6 -0
- data/sig/ratatui_ruby/schema/chart.rbs +6 -9
- data/sig/ratatui_ruby/schema/constraint.rbs +6 -0
- data/sig/ratatui_ruby/schema/cursor.rbs +6 -0
- data/sig/ratatui_ruby/schema/draw.rbs +6 -0
- data/sig/ratatui_ruby/schema/gauge.rbs +9 -1
- data/sig/ratatui_ruby/schema/layout.rbs +6 -0
- data/sig/ratatui_ruby/schema/line_gauge.rbs +9 -1
- data/sig/ratatui_ruby/schema/list.rbs +9 -1
- data/sig/ratatui_ruby/schema/list_item.rbs +7 -1
- data/sig/ratatui_ruby/schema/overlay.rbs +6 -0
- data/sig/ratatui_ruby/schema/paragraph.rbs +6 -0
- data/sig/ratatui_ruby/schema/ratatui_logo.rbs +6 -0
- data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +5 -0
- data/sig/ratatui_ruby/schema/rect.rbs +30 -0
- data/sig/ratatui_ruby/schema/row.rbs +7 -1
- data/sig/ratatui_ruby/schema/scrollbar.rbs +6 -0
- data/sig/ratatui_ruby/schema/sparkline.rbs +6 -0
- data/sig/ratatui_ruby/schema/style.rbs +7 -1
- data/sig/ratatui_ruby/schema/table.rbs +11 -1
- data/sig/ratatui_ruby/schema/tabs.rbs +6 -0
- data/sig/ratatui_ruby/schema/text.rbs +7 -1
- data/sig/ratatui_ruby/scrollbar_state.rbs +7 -1
- data/sig/ratatui_ruby/session.rbs +7 -1
- data/sig/ratatui_ruby/table_state.rbs +7 -1
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +7 -1
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +7 -1
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +7 -1
- data/sig/ratatui_ruby/test_helper/terminal.rbs +7 -1
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -1
- data/sig/ratatui_ruby/test_helper.rbs +7 -1
- data/sig/ratatui_ruby/tui/buffer_factories.rbs +7 -1
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +7 -1
- data/sig/ratatui_ruby/tui/core.rbs +7 -1
- data/sig/ratatui_ruby/tui/layout_factories.rbs +7 -1
- data/sig/ratatui_ruby/tui/state_factories.rbs +7 -1
- data/sig/ratatui_ruby/tui/style_factories.rbs +7 -1
- data/sig/ratatui_ruby/tui/text_factories.rbs +7 -1
- data/sig/ratatui_ruby/tui/widget_factories.rbs +7 -1
- data/sig/ratatui_ruby/tui.rbs +7 -1
- data/sig/ratatui_ruby/version.rbs +6 -0
- data/tasks/autodoc/examples.rb +1 -1
- data/tasks/autodoc/member.rb +1 -1
- data/tasks/autodoc/name.rb +1 -1
- data/tasks/bump/cargo_lockfile.rb +1 -1
- data/tasks/bump/changelog.rb +1 -1
- data/tasks/bump/header.rb +1 -1
- data/tasks/bump/history.rb +1 -1
- data/tasks/bump/links.rb +1 -1
- data/tasks/bump/manifest.rb +1 -1
- data/tasks/bump/ruby_gem.rb +1 -1
- data/tasks/bump/sem_ver.rb +1 -1
- data/tasks/bump/unreleased_section.rb +1 -1
- data/tasks/license/headers_md.rb +223 -0
- data/tasks/license/headers_rb.rb +210 -0
- data/tasks/license/license_utils.rb +130 -0
- data/tasks/license/snippets_md.rb +315 -0
- data/tasks/license/snippets_rdoc.rb +150 -0
- data/tasks/license.rake +91 -0
- data/tasks/rdoc_config.rb +1 -1
- data/tasks/resources/build.yml.erb +13 -7
- data/tasks/sourcehut.rake +3 -1
- data/tasks/terminal_preview/app_screenshot.rb +1 -1
- data/tasks/terminal_preview/crash_report.rb +1 -1
- data/tasks/terminal_preview/example_app.rb +1 -1
- data/tasks/terminal_preview/launcher_script.rb +1 -1
- data/tasks/terminal_preview/preview_collection.rb +1 -1
- data/tasks/terminal_preview/preview_timing.rb +1 -1
- data/tasks/terminal_preview/safety_confirmation.rb +1 -1
- data/tasks/terminal_preview/saved_screenshot.rb +1 -1
- data/tasks/terminal_preview/system_appearance.rb +1 -1
- data/tasks/terminal_preview/terminal_window.rb +1 -1
- data/tasks/terminal_preview/window_id.rb +1 -1
- data/tasks/website/index_page.rb +1 -1
- data/tasks/website/version.rb +1 -1
- data/tasks/website/version_menu.rb +1 -1
- data/tasks/website/versioned_documentation.rb +1 -1
- data/tasks/website/website.rb +1 -1
- metadata +13 -3
- data/doc/migration/v0_7_0.md +0 -236
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
SPDX-FileCopyrightText:
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
3
|
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
4
|
-->
|
|
5
5
|
# Quickstart
|
|
@@ -17,6 +17,11 @@ See [Installation in the README](../README.md#installation) for setup instructio
|
|
|
17
17
|
|
|
18
18
|
Here is a "Hello World" application that demonstrates the core lifecycle of a **ratatui_ruby** app.
|
|
19
19
|
|
|
20
|
+
<!-- SPDX-SnippetBegin -->
|
|
21
|
+
<!--
|
|
22
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
23
|
+
SPDX-License-Identifier: MIT-0
|
|
24
|
+
-->
|
|
20
25
|
<!-- SYNC:START:examples/verify_quickstart_lifecycle/app.rb:main -->
|
|
21
26
|
```ruby
|
|
22
27
|
# 1. Initialize the terminal
|
|
@@ -34,7 +39,7 @@ begin
|
|
|
34
39
|
title: "My Ruby TUI App",
|
|
35
40
|
title_alignment: :center,
|
|
36
41
|
borders: [:all],
|
|
37
|
-
|
|
42
|
+
border_style: { fg: "cyan" },
|
|
38
43
|
style: { fg: "white" }
|
|
39
44
|
)
|
|
40
45
|
)
|
|
@@ -64,6 +69,7 @@ ensure
|
|
|
64
69
|
end
|
|
65
70
|
```
|
|
66
71
|
<!-- SYNC:END -->
|
|
72
|
+
<!-- SPDX-SnippetEnd -->
|
|
67
73
|
|
|
68
74
|
[](../../examples/verify_quickstart_lifecycle/README.md)
|
|
69
75
|
|
|
@@ -80,6 +86,11 @@ end
|
|
|
80
86
|
|
|
81
87
|
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.
|
|
82
88
|
|
|
89
|
+
<!-- SPDX-SnippetBegin -->
|
|
90
|
+
<!--
|
|
91
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
92
|
+
SPDX-License-Identifier: MIT-0
|
|
93
|
+
-->
|
|
83
94
|
<!-- SYNC:START:examples/verify_quickstart_dsl/app.rb:main -->
|
|
84
95
|
```ruby
|
|
85
96
|
# 1. Initialize the terminal, start the run loop, and ensure the terminal is restored.
|
|
@@ -93,7 +104,7 @@ RatatuiRuby.run do |tui|
|
|
|
93
104
|
title: "My Ruby TUI App",
|
|
94
105
|
title_alignment: :center,
|
|
95
106
|
borders: [:all],
|
|
96
|
-
|
|
107
|
+
border_style: { fg: "cyan" },
|
|
97
108
|
style: { fg: "white" }
|
|
98
109
|
)
|
|
99
110
|
)
|
|
@@ -114,6 +125,7 @@ RatatuiRuby.run do |tui|
|
|
|
114
125
|
end
|
|
115
126
|
```
|
|
116
127
|
<!-- SYNC:END -->
|
|
128
|
+
<!-- SPDX-SnippetEnd -->
|
|
117
129
|
|
|
118
130
|
#### How it works
|
|
119
131
|
|
|
@@ -128,6 +140,11 @@ For a deeper dive into the available application architectures (Manual vs Manage
|
|
|
128
140
|
|
|
129
141
|
Real-world applications often need to split the screen into multiple areas. `RatatuiRuby::Layout` lets you do this easily.
|
|
130
142
|
|
|
143
|
+
<!-- SPDX-SnippetBegin -->
|
|
144
|
+
<!--
|
|
145
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
146
|
+
SPDX-License-Identifier: MIT-0
|
|
147
|
+
-->
|
|
131
148
|
<!-- SYNC:START:examples/verify_quickstart_layout/app.rb:main -->
|
|
132
149
|
```ruby
|
|
133
150
|
loop do
|
|
@@ -147,7 +164,7 @@ loop do
|
|
|
147
164
|
tui.paragraph(
|
|
148
165
|
text: "Hello, Ratatui!",
|
|
149
166
|
alignment: :center,
|
|
150
|
-
block: tui.block(title: "Content", borders: [:all],
|
|
167
|
+
block: tui.block(title: "Content", borders: [:all], border_style: { fg: "cyan" })
|
|
151
168
|
),
|
|
152
169
|
top
|
|
153
170
|
)
|
|
@@ -184,6 +201,7 @@ loop do
|
|
|
184
201
|
end
|
|
185
202
|
```
|
|
186
203
|
<!-- SYNC:END -->
|
|
204
|
+
<!-- SPDX-SnippetEnd -->
|
|
187
205
|
|
|
188
206
|
#### How it works
|
|
189
207
|
|
data/doc/getting_started/why.md
CHANGED
data/doc/index.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
SPDX-FileCopyrightText:
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
3
|
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
4
|
-->
|
|
5
5
|
# Start Here
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
- [Event Handling](./concepts/event_handling.md): Keyboard, mouse, and terminal events
|
|
21
21
|
- [Interactive Design](./concepts/interactive_design.md): Cached layout pattern for hit testing
|
|
22
22
|
- [Testing Your Application](./concepts/application_testing.md): Snapshot testing and style assertions
|
|
23
|
+
- [Custom Widgets](./concepts/custom_widgets.md): Build anything with the Draw API
|
|
23
24
|
- [Async Operations](./concepts/async.md): Background tasks and non-blocking I/O
|
|
24
25
|
|
|
25
26
|
### Troubleshooting
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
SPDX-FileCopyrightText:
|
|
3
|
-
SPDX-License-Identifier:
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
4
|
-->
|
|
5
5
|
|
|
6
6
|
# Debugging TUI Applications
|
|
@@ -15,6 +15,11 @@ Write debug output to files. Tail them in a separate terminal.
|
|
|
15
15
|
|
|
16
16
|
Create timestamped log files to avoid overwrites:
|
|
17
17
|
|
|
18
|
+
<!-- SPDX-SnippetBegin -->
|
|
19
|
+
<!--
|
|
20
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
21
|
+
SPDX-License-Identifier: MIT-0
|
|
22
|
+
-->
|
|
18
23
|
```ruby
|
|
19
24
|
FileUtils.mkdir_p(File.join(Dir.tmpdir, "my_debug"))
|
|
20
25
|
timestamp = Time.now.strftime('%Y%m%d_%H%M%S_%N')
|
|
@@ -23,15 +28,27 @@ File.write(
|
|
|
23
28
|
"variable=#{value.inspect}\n"
|
|
24
29
|
)
|
|
25
30
|
```
|
|
31
|
+
<!-- SPDX-SnippetEnd -->
|
|
26
32
|
|
|
27
33
|
Or append to a single file:
|
|
28
34
|
|
|
35
|
+
<!-- SPDX-SnippetBegin -->
|
|
36
|
+
<!--
|
|
37
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
38
|
+
SPDX-License-Identifier: MIT-0
|
|
39
|
+
-->
|
|
29
40
|
```ruby
|
|
30
41
|
File.write("/tmp/debug.log", "#{Time.now}: #{message}\n", mode: "a")
|
|
31
42
|
```
|
|
43
|
+
<!-- SPDX-SnippetEnd -->
|
|
32
44
|
|
|
33
45
|
Tail the logs in a separate terminal:
|
|
34
46
|
|
|
47
|
+
<!-- SPDX-SnippetBegin -->
|
|
48
|
+
<!--
|
|
49
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
50
|
+
SPDX-License-Identifier: MIT-0
|
|
51
|
+
-->
|
|
35
52
|
```bash
|
|
36
53
|
# Single file
|
|
37
54
|
tail -f /tmp/debug.log
|
|
@@ -39,6 +56,7 @@ tail -f /tmp/debug.log
|
|
|
39
56
|
# Directory of timestamped files
|
|
40
57
|
watch -n 0.5 'ls -la /tmp/my_debug/ && cat /tmp/my_debug/*.log'
|
|
41
58
|
```
|
|
59
|
+
<!-- SPDX-SnippetEnd -->
|
|
42
60
|
|
|
43
61
|
## REPL Debugging with `__FILE__` Guards
|
|
44
62
|
|
|
@@ -46,17 +64,29 @@ Unit tests verify correctness. But during exploratory debugging, you want to pok
|
|
|
46
64
|
|
|
47
65
|
Wrap your main execution in a guard:
|
|
48
66
|
|
|
67
|
+
<!-- SPDX-SnippetBegin -->
|
|
68
|
+
<!--
|
|
69
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
70
|
+
SPDX-License-Identifier: MIT-0
|
|
71
|
+
-->
|
|
49
72
|
```ruby
|
|
50
73
|
if __FILE__ == $PROGRAM_NAME
|
|
51
74
|
MyApp.new.run
|
|
52
75
|
end
|
|
53
76
|
```
|
|
77
|
+
<!-- SPDX-SnippetEnd -->
|
|
54
78
|
|
|
55
79
|
Now load the file and interact with classes directly:
|
|
56
80
|
|
|
81
|
+
<!-- SPDX-SnippetBegin -->
|
|
82
|
+
<!--
|
|
83
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
84
|
+
SPDX-License-Identifier: MIT-0
|
|
85
|
+
-->
|
|
57
86
|
```bash
|
|
58
87
|
ruby -e 'load "./bin/my_tui"; obj = MyClass.new; sleep 1; puts obj.result'
|
|
59
88
|
```
|
|
89
|
+
<!-- SPDX-SnippetEnd -->
|
|
60
90
|
|
|
61
91
|
This exercises domain logic without entering raw terminal mode. Use it for exploratory debugging. Write tests using the [TestHelper](application_testing.md) for regression coverage.
|
|
62
92
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
SPDX-FileCopyrightText:
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
4
|
-->
|
|
5
5
|
|
|
6
6
|
# Terminal Limitations
|
|
@@ -114,12 +114,18 @@ There's no way to catch SIGKILL. You can only mitigate the impact.
|
|
|
114
114
|
|
|
115
115
|
**Script graceful shutdowns.** If you write deployment or process management scripts, prefer graceful signals with a timeout before SIGKILL:
|
|
116
116
|
|
|
117
|
+
<!-- SPDX-SnippetBegin -->
|
|
118
|
+
<!--
|
|
119
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
120
|
+
SPDX-License-Identifier: MIT-0
|
|
121
|
+
-->
|
|
117
122
|
```bash
|
|
118
123
|
# Graceful first, force if needed
|
|
119
124
|
kill -15 $PID
|
|
120
125
|
sleep 2
|
|
121
126
|
kill -0 $PID 2>/dev/null && kill -9 $PID
|
|
122
127
|
```
|
|
128
|
+
<!-- SPDX-SnippetEnd -->
|
|
123
129
|
|
|
124
130
|
See [Application Architecture: Signal Handling](../concepts/application_architecture.md#signal-handling) for programmatic cleanup strategies.
|
|
125
131
|
|
|
@@ -28,6 +28,11 @@ In raw mode:
|
|
|
28
28
|
|
|
29
29
|
If you're using a gem that might write to stdout/stderr, wrap its calls:
|
|
30
30
|
|
|
31
|
+
<!-- SPDX-SnippetBegin -->
|
|
32
|
+
<!--
|
|
33
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
34
|
+
SPDX-License-Identifier: MIT-0
|
|
35
|
+
-->
|
|
31
36
|
```ruby
|
|
32
37
|
RatatuiRuby.run do |tui|
|
|
33
38
|
RatatuiRuby.guard_io do
|
|
@@ -38,9 +43,15 @@ RatatuiRuby.run do |tui|
|
|
|
38
43
|
# Object::STDERR.puts "debug: something" # Escape hatch (corrupts display!)
|
|
39
44
|
end
|
|
40
45
|
```
|
|
46
|
+
<!-- SPDX-SnippetEnd -->
|
|
41
47
|
|
|
42
48
|
### Defer output until after the TUI exits
|
|
43
49
|
|
|
50
|
+
<!-- SPDX-SnippetBegin -->
|
|
51
|
+
<!--
|
|
52
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
53
|
+
SPDX-License-Identifier: MIT-0
|
|
54
|
+
-->
|
|
44
55
|
```ruby
|
|
45
56
|
messages = []
|
|
46
57
|
|
|
@@ -54,11 +65,17 @@ end
|
|
|
54
65
|
# Now safe to print
|
|
55
66
|
messages.each { |msg| puts msg }
|
|
56
67
|
```
|
|
68
|
+
<!-- SPDX-SnippetEnd -->
|
|
57
69
|
|
|
58
70
|
### Use Logger to write to a file
|
|
59
71
|
|
|
60
72
|
The `Logger` class from Ruby's standard library is the idiomatic solution:
|
|
61
73
|
|
|
74
|
+
<!-- SPDX-SnippetBegin -->
|
|
75
|
+
<!--
|
|
76
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
77
|
+
SPDX-License-Identifier: MIT-0
|
|
78
|
+
-->
|
|
62
79
|
```ruby
|
|
63
80
|
require "logger"
|
|
64
81
|
require "tmpdir"
|
|
@@ -73,9 +90,15 @@ RatatuiRuby.run do |tui|
|
|
|
73
90
|
# ... TUI logic ...
|
|
74
91
|
end
|
|
75
92
|
```
|
|
93
|
+
<!-- SPDX-SnippetEnd -->
|
|
76
94
|
|
|
77
95
|
### Display messages in the TUI itself
|
|
78
96
|
|
|
97
|
+
<!-- SPDX-SnippetBegin -->
|
|
98
|
+
<!--
|
|
99
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
100
|
+
SPDX-License-Identifier: MIT-0
|
|
101
|
+
-->
|
|
79
102
|
```ruby
|
|
80
103
|
RatatuiRuby.run do |tui|
|
|
81
104
|
@status_message = "Something happened"
|
|
@@ -89,6 +112,7 @@ RatatuiRuby.run do |tui|
|
|
|
89
112
|
end
|
|
90
113
|
end
|
|
91
114
|
```
|
|
115
|
+
<!-- SPDX-SnippetEnd -->
|
|
92
116
|
|
|
93
117
|
## Library Behavior
|
|
94
118
|
|
|
@@ -100,6 +124,11 @@ You don't need to do anything special for library warnings—they're handled aut
|
|
|
100
124
|
|
|
101
125
|
If you need to write to stdout/stderr even when `guard_io` is active (e.g., for [pipeline integration](#headless-mode-batchpipelinecli) or IPC), use the original IO constants:
|
|
102
126
|
|
|
127
|
+
<!-- SPDX-SnippetBegin -->
|
|
128
|
+
<!--
|
|
129
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
130
|
+
SPDX-License-Identifier: MIT-0
|
|
131
|
+
-->
|
|
103
132
|
```ruby
|
|
104
133
|
RatatuiRuby.guard_io do
|
|
105
134
|
SomeChattyGem.do_something # This is swallowed
|
|
@@ -108,6 +137,7 @@ RatatuiRuby.guard_io do
|
|
|
108
137
|
Object::STDOUT.puts "structured output for downstream tools"
|
|
109
138
|
end
|
|
110
139
|
```
|
|
140
|
+
<!-- SPDX-SnippetEnd -->
|
|
111
141
|
|
|
112
142
|
This works regardless of whether `guard_io` is active. During a TUI session, the display will be corrupted—but the output will reach its destination.
|
|
113
143
|
|
|
@@ -115,6 +145,11 @@ This works regardless of whether `guard_io` is active. During a TUI session, the
|
|
|
115
145
|
|
|
116
146
|
If your app supports both TUI and non-TUI modes (e.g., `my_app --no-tui`), call `headless!` at startup to silence `guard_io` warnings:
|
|
117
147
|
|
|
148
|
+
<!-- SPDX-SnippetBegin -->
|
|
149
|
+
<!--
|
|
150
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
151
|
+
SPDX-License-Identifier: MIT-0
|
|
152
|
+
-->
|
|
118
153
|
```ruby
|
|
119
154
|
if ARGV.include?("--no-tui")
|
|
120
155
|
RatatuiRuby.headless!
|
|
@@ -126,6 +161,7 @@ else
|
|
|
126
161
|
end
|
|
127
162
|
end
|
|
128
163
|
```
|
|
164
|
+
<!-- SPDX-SnippetEnd -->
|
|
129
165
|
|
|
130
166
|
When headless, `guard_io` becomes a no-op (output flows normally), and calling `run` or `init_terminal` raises an error.
|
|
131
167
|
|
|
@@ -133,6 +169,11 @@ When headless, `guard_io` becomes a no-op (output flows normally), and calling `
|
|
|
133
169
|
|
|
134
170
|
Some apps need to temporarily leave TUI mode for user interaction—like lazygit does when opening an external editor for commit messages. Use `restore_terminal` and `init_terminal`:
|
|
135
171
|
|
|
172
|
+
<!-- SPDX-SnippetBegin -->
|
|
173
|
+
<!--
|
|
174
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
175
|
+
SPDX-License-Identifier: MIT-0
|
|
176
|
+
-->
|
|
136
177
|
```ruby
|
|
137
178
|
RatatuiRuby.run do |tui|
|
|
138
179
|
# ... TUI is active ...
|
|
@@ -151,5 +192,6 @@ RatatuiRuby.run do |tui|
|
|
|
151
192
|
# ... TUI is active again ...
|
|
152
193
|
end
|
|
153
194
|
```
|
|
195
|
+
<!-- SPDX-SnippetEnd -->
|
|
154
196
|
|
|
155
197
|
This pattern lets you hand control back to the user or spawn external processes that need normal terminal access.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
SPDX-FileCopyrightText:
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
4
|
-->
|
|
5
5
|
|
|
6
6
|
# App All Events Example
|
|
@@ -33,9 +33,15 @@ Semantic value objects that decouple raw terminal events from business logic:
|
|
|
33
33
|
### 3. Update (`update.rb`)
|
|
34
34
|
A **pure function** that computes the next state:
|
|
35
35
|
|
|
36
|
+
<!-- SPDX-SnippetBegin -->
|
|
37
|
+
<!--
|
|
38
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
39
|
+
SPDX-License-Identifier: MIT-0
|
|
40
|
+
-->
|
|
36
41
|
```ruby
|
|
37
42
|
Update.call(msg, model) -> Model
|
|
38
43
|
```
|
|
44
|
+
<!-- SPDX-SnippetEnd -->
|
|
39
45
|
|
|
40
46
|
All logic previously in `Events.record` now lives here. The function never mutates, never draws, never performs IO.
|
|
41
47
|
|
|
@@ -47,6 +53,11 @@ Pure rendering logic. Views accept the immutable `AppModel` and draw to the scre
|
|
|
47
53
|
### 5. Runtime (`app.rb`)
|
|
48
54
|
The MVU loop:
|
|
49
55
|
|
|
56
|
+
<!-- SPDX-SnippetBegin -->
|
|
57
|
+
<!--
|
|
58
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
59
|
+
SPDX-License-Identifier: MIT-0
|
|
60
|
+
-->
|
|
50
61
|
```ruby
|
|
51
62
|
loop do
|
|
52
63
|
tui.draw { |f| view.call(model, tui, f, f.area) }
|
|
@@ -55,6 +66,7 @@ loop do
|
|
|
55
66
|
model = Update.call(msg, model)
|
|
56
67
|
end
|
|
57
68
|
```
|
|
69
|
+
<!-- SPDX-SnippetEnd -->
|
|
58
70
|
|
|
59
71
|
## Library Features Showcased
|
|
60
72
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
SPDX-FileCopyrightText:
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
4
|
-->
|
|
5
5
|
|
|
6
6
|
# Color Picker Example
|
|
@@ -23,6 +23,11 @@ This app uses a **Strict Component-Based Architecture** where every UI element e
|
|
|
23
23
|
|
|
24
24
|
Every component implements this duck-type interface:
|
|
25
25
|
|
|
26
|
+
<!-- SPDX-SnippetBegin -->
|
|
27
|
+
<!--
|
|
28
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
29
|
+
SPDX-License-Identifier: MIT-0
|
|
30
|
+
-->
|
|
26
31
|
```ruby
|
|
27
32
|
# Renders the component into the given area
|
|
28
33
|
# Caches `area` for hit testing
|
|
@@ -40,6 +45,7 @@ end
|
|
|
40
45
|
def tick
|
|
41
46
|
end
|
|
42
47
|
```
|
|
48
|
+
<!-- SPDX-SnippetEnd -->
|
|
43
49
|
|
|
44
50
|
### 1. The MainContainer (Orchestrator)
|
|
45
51
|
|
|
@@ -85,6 +91,11 @@ Components return semantic symbols instead of just `:consumed`:
|
|
|
85
91
|
|
|
86
92
|
The `MainContainer` interprets these signals to coordinate cross-component communication:
|
|
87
93
|
|
|
94
|
+
<!-- SPDX-SnippetBegin -->
|
|
95
|
+
<!--
|
|
96
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
97
|
+
SPDX-License-Identifier: MIT-0
|
|
98
|
+
-->
|
|
88
99
|
```ruby
|
|
89
100
|
result = @input.handle_event(event)
|
|
90
101
|
case result
|
|
@@ -93,6 +104,7 @@ when :submitted
|
|
|
93
104
|
return :consumed
|
|
94
105
|
end
|
|
95
106
|
```
|
|
107
|
+
<!-- SPDX-SnippetEnd -->
|
|
96
108
|
|
|
97
109
|
### ⏱️ Lifecycle Hooks (`tick`)
|
|
98
110
|
|
|
@@ -109,9 +121,15 @@ Read this example if you are trying to solve:
|
|
|
109
121
|
|
|
110
122
|
## Usage
|
|
111
123
|
|
|
124
|
+
<!-- SPDX-SnippetBegin -->
|
|
125
|
+
<!--
|
|
126
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
127
|
+
SPDX-License-Identifier: MIT-0
|
|
128
|
+
-->
|
|
112
129
|
```bash
|
|
113
130
|
ruby examples/app_color_picker/app.rb
|
|
114
131
|
```
|
|
132
|
+
<!-- SPDX-SnippetEnd -->
|
|
115
133
|
|
|
116
134
|
- Type a hex code (e.g., `#FF0055`) or color name (`cyan`).
|
|
117
135
|
- Press `Enter` to generate the palette.
|