ratatui_ruby 0.8.0 → 0.9.1
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 +77 -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 +19 -185
- 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 +9 -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/events.rs +1 -0
- 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/sync.rb +52 -0
- data/lib/ratatui_ruby/event.rb +32 -2
- data/lib/ratatui_ruby/frame.rb +74 -2
- data/lib/ratatui_ruby/layout/constraint.rb +193 -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/synthetic_events.rb +86 -0
- 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 +62 -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 +101 -9
- 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 +14 -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 +15 -3
- data/doc/migration/v0_7_0.md +0 -236
data/README.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
|
# ratatui_ruby
|
|
@@ -21,7 +21,7 @@ Mailing List: Announcements](https://img.shields.io/badge/mailing_list-announcem
|
|
|
21
21
|
**ratatui_ruby** is a community wrapper that is not affiliated with [the Ratatui team](https://github.com/orgs/ratatui/people).
|
|
22
22
|
|
|
23
23
|
> [!WARNING]
|
|
24
|
-
> **ratatui_ruby** is currently in **
|
|
24
|
+
> **ratatui_ruby** is currently in **ALPHA**. The API may change between minor versions.
|
|
25
25
|
|
|
26
26
|
**[Why RatatuiRuby?](./doc/getting_started/why.md)** — Native Rust performance, zero runtime overhead, and Ruby's expressiveness. [See how we compare](./doc/getting_started/why.md) to CharmRuby, raw Rust, and Go.
|
|
27
27
|
|
|
@@ -44,27 +44,50 @@ including Ruby 4.
|
|
|
44
44
|
|
|
45
45
|
Add this line to your application's Gemfile:
|
|
46
46
|
|
|
47
|
+
<!-- SPDX-SnippetBegin -->
|
|
48
|
+
<!--
|
|
49
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
50
|
+
SPDX-License-Identifier: MIT-0
|
|
51
|
+
-->
|
|
47
52
|
```ruby
|
|
48
53
|
gem "ratatui_ruby"
|
|
49
54
|
```
|
|
55
|
+
<!-- SPDX-SnippetEnd -->
|
|
50
56
|
|
|
51
57
|
And then execute:
|
|
52
58
|
|
|
59
|
+
<!-- SPDX-SnippetBegin -->
|
|
60
|
+
<!--
|
|
61
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
62
|
+
SPDX-License-Identifier: MIT-0
|
|
63
|
+
-->
|
|
53
64
|
```bash
|
|
54
65
|
bundle install
|
|
55
66
|
```
|
|
67
|
+
<!-- SPDX-SnippetEnd -->
|
|
56
68
|
|
|
57
69
|
Or install it yourself with:
|
|
58
70
|
|
|
71
|
+
<!-- SPDX-SnippetBegin -->
|
|
72
|
+
<!--
|
|
73
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
74
|
+
SPDX-License-Identifier: MIT-0
|
|
75
|
+
-->
|
|
59
76
|
```bash
|
|
60
77
|
gem install ratatui_ruby
|
|
61
78
|
```
|
|
79
|
+
<!-- SPDX-SnippetEnd -->
|
|
62
80
|
|
|
63
81
|
|
|
64
82
|
## Usage
|
|
65
83
|
|
|
66
84
|
**ratatui_ruby** uses an immediate-mode API. You describe your UI using Ruby objects and call `draw` in a loop.
|
|
67
85
|
|
|
86
|
+
<!-- SPDX-SnippetBegin -->
|
|
87
|
+
<!--
|
|
88
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
89
|
+
SPDX-License-Identifier: MIT-0
|
|
90
|
+
-->
|
|
68
91
|
<!-- SYNC:START:examples/verify_readme_usage/app.rb:main -->
|
|
69
92
|
```ruby
|
|
70
93
|
RatatuiRuby.run do |tui|
|
|
@@ -77,7 +100,7 @@ RatatuiRuby.run do |tui|
|
|
|
77
100
|
block: tui.block(
|
|
78
101
|
title: "My Ruby TUI App",
|
|
79
102
|
borders: [:all],
|
|
80
|
-
|
|
103
|
+
border_style: { fg: "cyan" }
|
|
81
104
|
)
|
|
82
105
|
),
|
|
83
106
|
frame.area
|
|
@@ -93,6 +116,7 @@ RatatuiRuby.run do |tui|
|
|
|
93
116
|
end
|
|
94
117
|
```
|
|
95
118
|
<!-- SYNC:END -->
|
|
119
|
+
<!-- SPDX-SnippetEnd -->
|
|
96
120
|
|
|
97
121
|

|
|
98
122
|
|
|
@@ -138,8 +162,12 @@ Want to help develop **ratatui_ruby**? Check out the [contribution guide on the
|
|
|
138
162
|
|
|
139
163
|
## Copyright & License
|
|
140
164
|
|
|
141
|
-
**ratatui_ruby** is copyright 2025, Kerrick Long.
|
|
165
|
+
**ratatui_ruby** is copyright 2025, Kerrick Long.
|
|
166
|
+
|
|
167
|
+
The library is [LGPL-3.0-or-later](./LICENSES/LGPL-3.0-or-later.txt): you can use it in proprietary applications, but you must share changes you make to **ratatui_ruby** itself. Documentation snippets and widget examples are [MIT-0](./LICENSES/MIT-0.txt): copy and use them without attribution.
|
|
168
|
+
|
|
169
|
+
Documentation is [CC-BY-SA-4.0](./LICENSES/CC-BY-SA-4.0.txt). Build tooling and full app examples are [AGPL-3.0-or-later](./LICENSES/AGPL-3.0-or-later.txt). See each file's SPDX comment for specifics.
|
|
142
170
|
|
|
143
|
-
Some parts of this program are copied from other sources under appropriate reuse licenses, and the copyright belongs to their respective owners. See the [REUSE Specification – Version 3.3](https://reuse.software/spec-3.3/) for
|
|
171
|
+
Some parts of this program are copied from other sources under appropriate reuse licenses, and the copyright belongs to their respective owners. See the [REUSE Specification – Version 3.3](https://reuse.software/spec-3.3/) for details.
|
|
144
172
|
|
|
145
173
|
This program was created with significant assistance from multiple LLMs. The process was human-controlled through creative prompts, with human contributions to each commit. See commit footers for model attribution. [declare-ai.org](https://declare-ai.org/1.0.0/creative.html)
|
data/Rakefile
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
SPDX-FileCopyrightText:
|
|
3
|
-
|
|
4
|
-
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
5
4
|
-->
|
|
6
5
|
|
|
7
6
|
# Application Architecture
|
|
@@ -24,6 +23,11 @@ Terminals have state. They remember cursor positions, input modes, and screen bu
|
|
|
24
23
|
|
|
25
24
|
This method acts as a safety net. It initializes the terminal, yields control to your block, and restores the terminal afterwards—even if your code raises an exception.
|
|
26
25
|
|
|
26
|
+
<!-- SPDX-SnippetBegin -->
|
|
27
|
+
<!--
|
|
28
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
29
|
+
SPDX-License-Identifier: MIT-0
|
|
30
|
+
-->
|
|
27
31
|
```ruby
|
|
28
32
|
RatatuiRuby.run do |tui|
|
|
29
33
|
loop do
|
|
@@ -35,11 +39,17 @@ RatatuiRuby.run do |tui|
|
|
|
35
39
|
end
|
|
36
40
|
# Terminal is restored here
|
|
37
41
|
```
|
|
42
|
+
<!-- SPDX-SnippetEnd -->
|
|
38
43
|
|
|
39
44
|
#### Manual Management
|
|
40
45
|
|
|
41
46
|
Need granular control? You can initialize and restore the terminal yourself. Use `ensure` blocks to guarantee cleanup.
|
|
42
47
|
|
|
48
|
+
<!-- SPDX-SnippetBegin -->
|
|
49
|
+
<!--
|
|
50
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
51
|
+
SPDX-License-Identifier: MIT-0
|
|
52
|
+
-->
|
|
43
53
|
```ruby
|
|
44
54
|
RatatuiRuby.init_terminal
|
|
45
55
|
begin
|
|
@@ -51,6 +61,7 @@ ensure
|
|
|
51
61
|
# Terminal is restored here
|
|
52
62
|
end
|
|
53
63
|
```
|
|
64
|
+
<!-- SPDX-SnippetEnd -->
|
|
54
65
|
|
|
55
66
|
#### Signal Handling
|
|
56
67
|
|
|
@@ -69,6 +80,11 @@ External processes send signals. Your TUI must handle them gracefully.
|
|
|
69
80
|
> [!IMPORTANT]
|
|
70
81
|
> **Ctrl+C in Raw Mode:** When your app is in raw mode, pressing Ctrl+C does *not* send SIGINT. It's captured as a `:ctrl_c` key event. Handle this in your event loop—don't use `trap("INT")`.
|
|
71
82
|
|
|
83
|
+
<!-- SPDX-SnippetBegin -->
|
|
84
|
+
<!--
|
|
85
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
86
|
+
SPDX-License-Identifier: MIT-0
|
|
87
|
+
-->
|
|
72
88
|
```ruby
|
|
73
89
|
RatatuiRuby.run do |tui|
|
|
74
90
|
loop do
|
|
@@ -78,6 +94,7 @@ RatatuiRuby.run do |tui|
|
|
|
78
94
|
end
|
|
79
95
|
end
|
|
80
96
|
```
|
|
97
|
+
<!-- SPDX-SnippetEnd -->
|
|
81
98
|
|
|
82
99
|
**Recovery:** If a TUI app leaves your terminal broken, run `reset` in the shell to restore normal behavior.
|
|
83
100
|
|
|
@@ -97,6 +114,11 @@ Most widgets are stateless configuration. You create them, render them, and they
|
|
|
97
114
|
|
|
98
115
|
**Use Case:** When you need to read back the scroll offset (e.g., for mouse hit testing) or persist selection without managing indexes manually.
|
|
99
116
|
|
|
117
|
+
<!-- SPDX-SnippetBegin -->
|
|
118
|
+
<!--
|
|
119
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
120
|
+
SPDX-License-Identifier: MIT-0
|
|
121
|
+
-->
|
|
100
122
|
```ruby
|
|
101
123
|
# Initialize state once
|
|
102
124
|
@list_state = RatatuiRuby::ListState.new
|
|
@@ -116,6 +138,7 @@ RatatuiRuby.run do |tui|
|
|
|
116
138
|
end
|
|
117
139
|
end
|
|
118
140
|
```
|
|
141
|
+
<!-- SPDX-SnippetEnd -->
|
|
119
142
|
|
|
120
143
|
### API Convenience
|
|
121
144
|
|
|
@@ -125,6 +148,11 @@ Writing UI trees involves nesting many widgets.
|
|
|
125
148
|
|
|
126
149
|
**The Solution:** The TUI API (`tui`) provides shorthand factories for every widget. It yields a TUI object to your block.
|
|
127
150
|
|
|
151
|
+
<!-- SPDX-SnippetBegin -->
|
|
152
|
+
<!--
|
|
153
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
154
|
+
SPDX-License-Identifier: MIT-0
|
|
155
|
+
-->
|
|
128
156
|
```ruby
|
|
129
157
|
RatatuiRuby.run do |tui|
|
|
130
158
|
loop do
|
|
@@ -167,11 +195,17 @@ RatatuiRuby.run do |tui|
|
|
|
167
195
|
end
|
|
168
196
|
end
|
|
169
197
|
```
|
|
198
|
+
<!-- SPDX-SnippetEnd -->
|
|
170
199
|
|
|
171
200
|
#### Raw API
|
|
172
201
|
|
|
173
202
|
Building your own abstractions? You might prefer explicit class instantiation. The raw constants are always available.
|
|
174
203
|
|
|
204
|
+
<!-- SPDX-SnippetBegin -->
|
|
205
|
+
<!--
|
|
206
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
207
|
+
SPDX-License-Identifier: MIT-0
|
|
208
|
+
-->
|
|
175
209
|
```ruby
|
|
176
210
|
RatatuiRuby.run do
|
|
177
211
|
loop do
|
|
@@ -212,6 +246,7 @@ RatatuiRuby.run do
|
|
|
212
246
|
end
|
|
213
247
|
end
|
|
214
248
|
```
|
|
249
|
+
<!-- SPDX-SnippetEnd -->
|
|
215
250
|
|
|
216
251
|
## Thread and Ractor Safety
|
|
217
252
|
|
|
@@ -236,6 +271,11 @@ These have side effects and are intentionally not shareable:
|
|
|
236
271
|
| `TUI` | Cache in `@tui` during run loop. Don't include in Models. |
|
|
237
272
|
| `Frame` | Pass to helpers during draw block. Invalid after block returns. |
|
|
238
273
|
|
|
274
|
+
<!-- SPDX-SnippetBegin -->
|
|
275
|
+
<!--
|
|
276
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
277
|
+
SPDX-License-Identifier: MIT-0
|
|
278
|
+
-->
|
|
239
279
|
```ruby
|
|
240
280
|
# Good: Cache session in instance variable
|
|
241
281
|
RatatuiRuby.run do |tui|
|
|
@@ -246,6 +286,7 @@ end
|
|
|
246
286
|
# Bad: Include in immutable Model (won't work with Ractors)
|
|
247
287
|
Model = Data.define(:tui, :count) # Don't do this
|
|
248
288
|
```
|
|
289
|
+
<!-- SPDX-SnippetEnd -->
|
|
249
290
|
|
|
250
291
|
|
|
251
292
|
## Reference Architectures
|
|
@@ -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
|
# Application Testing Guide
|
|
@@ -18,19 +18,31 @@ Use it to write fast, deterministic tests for your TUI applications.
|
|
|
18
18
|
|
|
19
19
|
First, require the test helper in your test file or `test_helper.rb`:
|
|
20
20
|
|
|
21
|
+
<!-- SPDX-SnippetBegin -->
|
|
22
|
+
<!--
|
|
23
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
24
|
+
SPDX-License-Identifier: MIT-0
|
|
25
|
+
-->
|
|
21
26
|
```ruby
|
|
22
27
|
require "ratatui_ruby/test_helper"
|
|
23
28
|
require "minitest/autorun" # or your preferred test framework
|
|
24
29
|
```
|
|
30
|
+
<!-- SPDX-SnippetEnd -->
|
|
25
31
|
|
|
26
32
|
Then, include the module in your test class:
|
|
27
33
|
|
|
34
|
+
<!-- SPDX-SnippetBegin -->
|
|
35
|
+
<!--
|
|
36
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
37
|
+
SPDX-License-Identifier: MIT-0
|
|
38
|
+
-->
|
|
28
39
|
```ruby
|
|
29
40
|
class MyApplicationTest < Minitest::Test
|
|
30
41
|
include RatatuiRuby::TestHelper
|
|
31
42
|
# ...
|
|
32
43
|
end
|
|
33
44
|
```
|
|
45
|
+
<!-- SPDX-SnippetEnd -->
|
|
34
46
|
|
|
35
47
|
## Writing a View Test
|
|
36
48
|
|
|
@@ -40,6 +52,11 @@ To test a view or widget, wrap your assertions in `with_test_terminal`. This set
|
|
|
40
52
|
2. **Render your code:** Instantiate your widget and draw it to a frame.
|
|
41
53
|
3. **Assert output:** Check the `buffer_content` against your expectations.
|
|
42
54
|
|
|
55
|
+
<!-- SPDX-SnippetBegin -->
|
|
56
|
+
<!--
|
|
57
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
58
|
+
SPDX-License-Identifier: MIT-0
|
|
59
|
+
-->
|
|
43
60
|
```ruby
|
|
44
61
|
def test_rendering
|
|
45
62
|
# Uses default 80x24 terminal
|
|
@@ -57,6 +74,7 @@ def test_rendering
|
|
|
57
74
|
end
|
|
58
75
|
end
|
|
59
76
|
```
|
|
77
|
+
<!-- SPDX-SnippetEnd -->
|
|
60
78
|
|
|
61
79
|
For the full API list, including `buffer_content` and `cursor_position`, see [RatatuiRuby::TestHelper::Terminal](../lib/ratatui_ruby/test_helper/terminal.rb).
|
|
62
80
|
|
|
@@ -66,6 +84,11 @@ You often need to check colors and modifiers (bold, italic) to ensure your highl
|
|
|
66
84
|
|
|
67
85
|
Use `assert_fg_color`, `assert_bg_color`, and modifier helpers like `assert_bold`.
|
|
68
86
|
|
|
87
|
+
<!-- SPDX-SnippetBegin -->
|
|
88
|
+
<!--
|
|
89
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
90
|
+
SPDX-License-Identifier: MIT-0
|
|
91
|
+
-->
|
|
69
92
|
```ruby
|
|
70
93
|
# Assert specific cell style
|
|
71
94
|
assert_fg_color(:red, 0, 0)
|
|
@@ -74,6 +97,7 @@ assert_bold(0, 0)
|
|
|
74
97
|
# Or check a whole area
|
|
75
98
|
assert_area_style({ x: 0, y: 0, w: 10, h: 1 }, bg: :blue)
|
|
76
99
|
```
|
|
100
|
+
<!-- SPDX-SnippetEnd -->
|
|
77
101
|
|
|
78
102
|
See [RatatuiRuby::TestHelper::StyleAssertions](../lib/ratatui_ruby/test_helper/style_assertions.rb) for the comprehensive list of style helpers.
|
|
79
103
|
|
|
@@ -86,6 +110,11 @@ Use `inject_event` to push mock events into the queue. This ensures safe, determ
|
|
|
86
110
|
> [!IMPORTANT]
|
|
87
111
|
> Call `inject_event` inside a `with_test_terminal` block to avoid race conditions.
|
|
88
112
|
|
|
113
|
+
<!-- SPDX-SnippetBegin -->
|
|
114
|
+
<!--
|
|
115
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
116
|
+
SPDX-License-Identifier: MIT-0
|
|
117
|
+
-->
|
|
89
118
|
```ruby
|
|
90
119
|
with_test_terminal do
|
|
91
120
|
# Simulate 'q' key press
|
|
@@ -96,6 +125,7 @@ with_test_terminal do
|
|
|
96
125
|
assert_equal "q", event.code
|
|
97
126
|
end
|
|
98
127
|
```
|
|
128
|
+
<!-- SPDX-SnippetEnd -->
|
|
99
129
|
|
|
100
130
|
See [RatatuiRuby::TestHelper::EventInjection](../lib/ratatui_ruby/test_helper/event_injection.rb) for helper methods like `inject_keys` and `inject_click`.
|
|
101
131
|
|
|
@@ -105,12 +135,18 @@ Snapshots let you verify complex layouts without manually asserting every line.
|
|
|
105
135
|
|
|
106
136
|
Use `assert_snapshots` to compare the current screen against stored reference files.
|
|
107
137
|
|
|
138
|
+
<!-- SPDX-SnippetBegin -->
|
|
139
|
+
<!--
|
|
140
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
141
|
+
SPDX-License-Identifier: MIT-0
|
|
142
|
+
-->
|
|
108
143
|
```ruby
|
|
109
144
|
with_test_terminal do
|
|
110
145
|
MyApp.new.run
|
|
111
146
|
assert_snapshots("dashboard_view")
|
|
112
147
|
end
|
|
113
148
|
```
|
|
149
|
+
<!-- SPDX-SnippetEnd -->
|
|
114
150
|
|
|
115
151
|
This generates both `.txt` (plain text) and `.ansi` (styled) snapshot files. The `.ansi` files contain ANSI escape codes—`cat` them in a terminal to see exactly what the screen looked like. For a visual tour of your test suite, try `cat **/*.ansi` in any shell that supports globbing.
|
|
116
152
|
|
|
@@ -130,6 +166,11 @@ Sometimes you want to test a single view component without spinning up the full
|
|
|
130
166
|
|
|
131
167
|
Use `MockFrame` and `StubRect` to test render logic in isolation.
|
|
132
168
|
|
|
169
|
+
<!-- SPDX-SnippetBegin -->
|
|
170
|
+
<!--
|
|
171
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
172
|
+
SPDX-License-Identifier: MIT-0
|
|
173
|
+
-->
|
|
133
174
|
```ruby
|
|
134
175
|
def test_logs_view
|
|
135
176
|
frame = RatatuiRuby::TestHelper::TestDoubles::MockFrame.new
|
|
@@ -143,6 +184,7 @@ def test_logs_view
|
|
|
143
184
|
assert_equal "Logs", rendered[:widget].block.title
|
|
144
185
|
end
|
|
145
186
|
```
|
|
187
|
+
<!-- SPDX-SnippetEnd -->
|
|
146
188
|
|
|
147
189
|
See [RatatuiRuby::TestHelper::TestDoubles](../lib/ratatui_ruby/test_helper/test_doubles.rb).
|
|
148
190
|
|
data/doc/concepts/async.md
CHANGED
|
@@ -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
|
# Async Operations in TUI Applications
|
|
@@ -21,12 +21,18 @@ This guide explains async patterns that work with raw terminal mode.
|
|
|
21
21
|
|
|
22
22
|
### What Breaks
|
|
23
23
|
|
|
24
|
+
<!-- SPDX-SnippetBegin -->
|
|
25
|
+
<!--
|
|
26
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
27
|
+
SPDX-License-Identifier: MIT-0
|
|
28
|
+
-->
|
|
24
29
|
```ruby
|
|
25
30
|
# These fail inside a Thread during raw mode:
|
|
26
31
|
`git ls-remote --tags origin` # Returns empty or hangs
|
|
27
32
|
IO.popen(["git", "ls-remote", ...]) # Same
|
|
28
33
|
Open3.capture2("git", "ls-remote", ...) # Same
|
|
29
34
|
```
|
|
35
|
+
<!-- SPDX-SnippetEnd -->
|
|
30
36
|
|
|
31
37
|
The commands succeed synchronously. They fail asynchronously. The difference: thread context inherits the parent's raw terminal state.
|
|
32
38
|
|
|
@@ -46,11 +52,17 @@ Ruby's GIL releases during I/O. But:
|
|
|
46
52
|
|
|
47
53
|
Run slow operations before entering the TUI:
|
|
48
54
|
|
|
55
|
+
<!-- SPDX-SnippetBegin -->
|
|
56
|
+
<!--
|
|
57
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
58
|
+
SPDX-License-Identifier: MIT-0
|
|
59
|
+
-->
|
|
49
60
|
```ruby
|
|
50
61
|
def initialize
|
|
51
62
|
@data = fetch_data # Runs before RatatuiRuby.run
|
|
52
63
|
end
|
|
53
64
|
```
|
|
65
|
+
<!-- SPDX-SnippetEnd -->
|
|
54
66
|
|
|
55
67
|
**Trade-off**: Delays startup.
|
|
56
68
|
|
|
@@ -58,6 +70,11 @@ end
|
|
|
58
70
|
|
|
59
71
|
Spawn a separate process before entering raw mode. Write results to a temp file. Poll for completion:
|
|
60
72
|
|
|
73
|
+
<!-- SPDX-SnippetBegin -->
|
|
74
|
+
<!--
|
|
75
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
76
|
+
SPDX-License-Identifier: MIT-0
|
|
77
|
+
-->
|
|
61
78
|
```ruby
|
|
62
79
|
class AsyncChecker
|
|
63
80
|
CACHE_FILE = File.join(Dir.tmpdir, "my_check_result.txt")
|
|
@@ -81,6 +98,7 @@ class AsyncChecker
|
|
|
81
98
|
end
|
|
82
99
|
end
|
|
83
100
|
```
|
|
101
|
+
<!-- SPDX-SnippetEnd -->
|
|
84
102
|
|
|
85
103
|
**Key points**:
|
|
86
104
|
|
|
@@ -93,9 +111,15 @@ end
|
|
|
93
111
|
|
|
94
112
|
Ruby threads work for pure computation:
|
|
95
113
|
|
|
114
|
+
<!-- SPDX-SnippetBegin -->
|
|
115
|
+
<!--
|
|
116
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
117
|
+
SPDX-License-Identifier: MIT-0
|
|
118
|
+
-->
|
|
96
119
|
```ruby
|
|
97
120
|
Thread.new { @result = expensive_calculation }
|
|
98
121
|
```
|
|
122
|
+
<!-- SPDX-SnippetEnd -->
|
|
99
123
|
|
|
100
124
|
Avoid threads for shell commands.
|
|
101
125
|
|
|
@@ -122,6 +146,11 @@ For TUI async, `Process.spawn` solves the problem cleanly.
|
|
|
122
146
|
|
|
123
147
|
Check if a tag exists on the remote:
|
|
124
148
|
|
|
149
|
+
<!-- SPDX-SnippetBegin -->
|
|
150
|
+
<!--
|
|
151
|
+
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
152
|
+
SPDX-License-Identifier: MIT-0
|
|
153
|
+
-->
|
|
125
154
|
```ruby
|
|
126
155
|
class GitRepo
|
|
127
156
|
CACHE_FILE = File.join(Dir.tmpdir, "git_tag_pushed.txt")
|
|
@@ -156,5 +185,6 @@ class GitRepo
|
|
|
156
185
|
end
|
|
157
186
|
end
|
|
158
187
|
```
|
|
188
|
+
<!-- SPDX-SnippetEnd -->
|
|
159
189
|
|
|
160
190
|
The TUI starts instantly. The tag check runs in the background. The checklist updates when the result arrives.
|