ratatui_ruby 1.1.0 → 1.1.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.
Files changed (259) hide show
  1. checksums.yaml +4 -4
  2. data/ext/ratatui_ruby/Cargo.lock +1 -1
  3. data/ext/ratatui_ruby/Cargo.toml +1 -1
  4. data/lib/ratatui_ruby/version.rb +1 -1
  5. metadata +1 -255
  6. data/.builds/ruby-3.2.yml +0 -54
  7. data/.builds/ruby-3.3.yml +0 -54
  8. data/.builds/ruby-3.4.yml +0 -54
  9. data/.builds/ruby-4.0.0.yml +0 -54
  10. data/.pre-commit-config.yaml +0 -16
  11. data/.rubocop.yml +0 -10
  12. data/AGENTS.md +0 -147
  13. data/CHANGELOG.md +0 -736
  14. data/README.md +0 -187
  15. data/README.rdoc +0 -302
  16. data/Rakefile +0 -11
  17. data/Steepfile +0 -50
  18. data/doc/concepts/application_architecture.md +0 -321
  19. data/doc/concepts/application_testing.md +0 -193
  20. data/doc/concepts/async.md +0 -190
  21. data/doc/concepts/custom_widgets.md +0 -247
  22. data/doc/concepts/debugging.md +0 -401
  23. data/doc/concepts/event_handling.md +0 -162
  24. data/doc/concepts/interactive_design.md +0 -146
  25. data/doc/contributors/auditing/parity.md +0 -239
  26. data/doc/contributors/design/ruby_frontend.md +0 -448
  27. data/doc/contributors/design/rust_backend.md +0 -434
  28. data/doc/contributors/design.md +0 -11
  29. data/doc/contributors/developing_examples.md +0 -400
  30. data/doc/contributors/documentation_style.md +0 -121
  31. data/doc/contributors/index.md +0 -21
  32. data/doc/contributors/releasing.md +0 -215
  33. data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -381
  34. data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -200
  35. data/doc/contributors/todo/align/term.md +0 -351
  36. data/doc/contributors/todo/align/terminal.md +0 -647
  37. data/doc/contributors/todo/future_work.md +0 -169
  38. data/doc/contributors/upstream_requests/paragraph_span_rects.md +0 -259
  39. data/doc/contributors/upstream_requests/tab_rects.md +0 -173
  40. data/doc/contributors/upstream_requests/title_rects.md +0 -132
  41. data/doc/custom.css +0 -22
  42. data/doc/getting_started/quickstart.md +0 -291
  43. data/doc/getting_started/why.md +0 -93
  44. data/doc/images/app_all_events.png +0 -0
  45. data/doc/images/app_cli_rich_moments.gif +0 -0
  46. data/doc/images/app_color_picker.png +0 -0
  47. data/doc/images/app_debugging_showcase.gif +0 -0
  48. data/doc/images/app_debugging_showcase.png +0 -0
  49. data/doc/images/app_external_editor.gif +0 -0
  50. data/doc/images/app_login_form.png +0 -0
  51. data/doc/images/app_stateful_interaction.png +0 -0
  52. data/doc/images/verify_quickstart_dsl.png +0 -0
  53. data/doc/images/verify_quickstart_layout.png +0 -0
  54. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  55. data/doc/images/verify_readme_usage.png +0 -0
  56. data/doc/images/widget_barchart.png +0 -0
  57. data/doc/images/widget_block.png +0 -0
  58. data/doc/images/widget_box.png +0 -0
  59. data/doc/images/widget_calendar.png +0 -0
  60. data/doc/images/widget_canvas.png +0 -0
  61. data/doc/images/widget_cell.png +0 -0
  62. data/doc/images/widget_center.png +0 -0
  63. data/doc/images/widget_chart.png +0 -0
  64. data/doc/images/widget_gauge.png +0 -0
  65. data/doc/images/widget_layout_split.png +0 -0
  66. data/doc/images/widget_line_gauge.png +0 -0
  67. data/doc/images/widget_list.png +0 -0
  68. data/doc/images/widget_map.png +0 -0
  69. data/doc/images/widget_overlay.png +0 -0
  70. data/doc/images/widget_popup.png +0 -0
  71. data/doc/images/widget_ratatui_logo.png +0 -0
  72. data/doc/images/widget_ratatui_mascot.png +0 -0
  73. data/doc/images/widget_rect.png +0 -0
  74. data/doc/images/widget_render.png +0 -0
  75. data/doc/images/widget_rich_text.png +0 -0
  76. data/doc/images/widget_scroll_text.png +0 -0
  77. data/doc/images/widget_scrollbar.png +0 -0
  78. data/doc/images/widget_sparkline.png +0 -0
  79. data/doc/images/widget_style_colors.png +0 -0
  80. data/doc/images/widget_table.png +0 -0
  81. data/doc/images/widget_tabs.png +0 -0
  82. data/doc/images/widget_text_width.png +0 -0
  83. data/doc/index.md +0 -34
  84. data/doc/troubleshooting/async.md +0 -4
  85. data/doc/troubleshooting/terminal_limitations.md +0 -131
  86. data/doc/troubleshooting/tui_output.md +0 -197
  87. data/examples/app_all_events/README.md +0 -114
  88. data/examples/app_all_events/app.rb +0 -98
  89. data/examples/app_all_events/model/app_model.rb +0 -159
  90. data/examples/app_all_events/model/event_color_cycle.rb +0 -43
  91. data/examples/app_all_events/model/event_entry.rb +0 -94
  92. data/examples/app_all_events/model/msg.rb +0 -39
  93. data/examples/app_all_events/model/timestamp.rb +0 -56
  94. data/examples/app_all_events/update.rb +0 -75
  95. data/examples/app_all_events/view/app_view.rb +0 -80
  96. data/examples/app_all_events/view/controls_view.rb +0 -54
  97. data/examples/app_all_events/view/counts_view.rb +0 -61
  98. data/examples/app_all_events/view/live_view.rb +0 -72
  99. data/examples/app_all_events/view/log_view.rb +0 -57
  100. data/examples/app_all_events/view.rb +0 -9
  101. data/examples/app_cli_rich_moments/README.md +0 -81
  102. data/examples/app_cli_rich_moments/app.rb +0 -189
  103. data/examples/app_color_picker/README.md +0 -156
  104. data/examples/app_color_picker/app.rb +0 -76
  105. data/examples/app_color_picker/clipboard.rb +0 -86
  106. data/examples/app_color_picker/color.rb +0 -193
  107. data/examples/app_color_picker/controls.rb +0 -92
  108. data/examples/app_color_picker/copy_dialog.rb +0 -168
  109. data/examples/app_color_picker/export_pane.rb +0 -128
  110. data/examples/app_color_picker/harmony.rb +0 -58
  111. data/examples/app_color_picker/input.rb +0 -176
  112. data/examples/app_color_picker/main_container.rb +0 -180
  113. data/examples/app_color_picker/palette.rb +0 -111
  114. data/examples/app_debugging_showcase/README.md +0 -119
  115. data/examples/app_debugging_showcase/app.rb +0 -318
  116. data/examples/app_external_editor/README.md +0 -62
  117. data/examples/app_external_editor/app.rb +0 -344
  118. data/examples/app_login_form/README.md +0 -58
  119. data/examples/app_login_form/app.rb +0 -109
  120. data/examples/app_stateful_interaction/README.md +0 -35
  121. data/examples/app_stateful_interaction/app.rb +0 -328
  122. data/examples/timeout_demo.rb +0 -45
  123. data/examples/verify_quickstart_dsl/README.md +0 -55
  124. data/examples/verify_quickstart_dsl/app.rb +0 -49
  125. data/examples/verify_quickstart_layout/README.md +0 -77
  126. data/examples/verify_quickstart_layout/app.rb +0 -73
  127. data/examples/verify_quickstart_lifecycle/README.md +0 -68
  128. data/examples/verify_quickstart_lifecycle/app.rb +0 -62
  129. data/examples/verify_readme_usage/README.md +0 -49
  130. data/examples/verify_readme_usage/app.rb +0 -42
  131. data/examples/verify_website_managed/README.md +0 -48
  132. data/examples/verify_website_managed/app.rb +0 -36
  133. data/examples/verify_website_menu/README.md +0 -60
  134. data/examples/verify_website_menu/app.rb +0 -84
  135. data/examples/verify_website_spinner/README.md +0 -44
  136. data/examples/verify_website_spinner/app.rb +0 -34
  137. data/examples/widget_barchart/README.md +0 -58
  138. data/examples/widget_barchart/app.rb +0 -240
  139. data/examples/widget_block/README.md +0 -44
  140. data/examples/widget_block/app.rb +0 -258
  141. data/examples/widget_box/README.md +0 -54
  142. data/examples/widget_box/app.rb +0 -255
  143. data/examples/widget_calendar/README.md +0 -48
  144. data/examples/widget_calendar/app.rb +0 -115
  145. data/examples/widget_canvas/README.md +0 -31
  146. data/examples/widget_canvas/app.rb +0 -130
  147. data/examples/widget_cell/README.md +0 -45
  148. data/examples/widget_cell/app.rb +0 -112
  149. data/examples/widget_center/README.md +0 -33
  150. data/examples/widget_center/app.rb +0 -118
  151. data/examples/widget_chart/README.md +0 -50
  152. data/examples/widget_chart/app.rb +0 -220
  153. data/examples/widget_gauge/README.md +0 -50
  154. data/examples/widget_gauge/app.rb +0 -229
  155. data/examples/widget_layout_split/README.md +0 -53
  156. data/examples/widget_layout_split/app.rb +0 -260
  157. data/examples/widget_line_gauge/README.md +0 -50
  158. data/examples/widget_line_gauge/app.rb +0 -219
  159. data/examples/widget_list/README.md +0 -58
  160. data/examples/widget_list/app.rb +0 -382
  161. data/examples/widget_map/README.md +0 -48
  162. data/examples/widget_map/app.rb +0 -95
  163. data/examples/widget_overlay/README.md +0 -45
  164. data/examples/widget_overlay/app.rb +0 -250
  165. data/examples/widget_popup/README.md +0 -45
  166. data/examples/widget_popup/app.rb +0 -106
  167. data/examples/widget_ratatui_logo/README.md +0 -43
  168. data/examples/widget_ratatui_logo/app.rb +0 -104
  169. data/examples/widget_ratatui_mascot/README.md +0 -43
  170. data/examples/widget_ratatui_mascot/app.rb +0 -95
  171. data/examples/widget_rect/README.md +0 -53
  172. data/examples/widget_rect/app.rb +0 -222
  173. data/examples/widget_render/README.md +0 -46
  174. data/examples/widget_render/app.rb +0 -186
  175. data/examples/widget_render/app.rbs +0 -41
  176. data/examples/widget_rich_text/README.md +0 -44
  177. data/examples/widget_rich_text/app.rb +0 -193
  178. data/examples/widget_scroll_text/README.md +0 -46
  179. data/examples/widget_scroll_text/app.rb +0 -109
  180. data/examples/widget_scrollbar/README.md +0 -46
  181. data/examples/widget_scrollbar/app.rb +0 -155
  182. data/examples/widget_sparkline/README.md +0 -51
  183. data/examples/widget_sparkline/app.rb +0 -277
  184. data/examples/widget_style_colors/README.md +0 -43
  185. data/examples/widget_style_colors/app.rb +0 -83
  186. data/examples/widget_table/README.md +0 -57
  187. data/examples/widget_table/app.rb +0 -285
  188. data/examples/widget_tabs/README.md +0 -50
  189. data/examples/widget_tabs/app.rb +0 -183
  190. data/examples/widget_text_width/README.md +0 -44
  191. data/examples/widget_text_width/app.rb +0 -117
  192. data/migrate_to_buffer.rb +0 -145
  193. data/mise.toml +0 -8
  194. data/tasks/autodoc/examples.rb +0 -87
  195. data/tasks/autodoc/member.rb +0 -58
  196. data/tasks/autodoc/name.rb +0 -21
  197. data/tasks/autodoc.rake +0 -21
  198. data/tasks/bump/bump_workflow.rb +0 -49
  199. data/tasks/bump/cargo_lockfile.rb +0 -21
  200. data/tasks/bump/changelog.rb +0 -104
  201. data/tasks/bump/header.rb +0 -32
  202. data/tasks/bump/history.rb +0 -32
  203. data/tasks/bump/links.rb +0 -69
  204. data/tasks/bump/manifest.rb +0 -33
  205. data/tasks/bump/patch_release.rb +0 -19
  206. data/tasks/bump/release_branch.rb +0 -17
  207. data/tasks/bump/release_from_trunk.rb +0 -49
  208. data/tasks/bump/repository.rb +0 -54
  209. data/tasks/bump/ruby_gem.rb +0 -29
  210. data/tasks/bump/sem_ver.rb +0 -44
  211. data/tasks/bump/unreleased_section.rb +0 -73
  212. data/tasks/bump.rake +0 -61
  213. data/tasks/doc/documentation.rb +0 -59
  214. data/tasks/doc/link/file_url.rb +0 -30
  215. data/tasks/doc/link/relative_path.rb +0 -61
  216. data/tasks/doc/link/web_url.rb +0 -55
  217. data/tasks/doc/link.rb +0 -52
  218. data/tasks/doc/link_audit.rb +0 -116
  219. data/tasks/doc/problem.rb +0 -40
  220. data/tasks/doc/source_file.rb +0 -93
  221. data/tasks/doc.rake +0 -905
  222. data/tasks/example_viewer.html.erb +0 -172
  223. data/tasks/extension.rake +0 -14
  224. data/tasks/license/headers_md.rb +0 -223
  225. data/tasks/license/headers_rb.rb +0 -210
  226. data/tasks/license/license_utils.rb +0 -130
  227. data/tasks/license/snippets_md.rb +0 -315
  228. data/tasks/license/snippets_rdoc.rb +0 -150
  229. data/tasks/license.rake +0 -91
  230. data/tasks/lint.rake +0 -170
  231. data/tasks/rbs_predicates/predicate_catalog.rb +0 -52
  232. data/tasks/rbs_predicates/predicate_tests.rb +0 -124
  233. data/tasks/rbs_predicates/rbs_signature.rb +0 -63
  234. data/tasks/rbs_predicates.rake +0 -31
  235. data/tasks/rdoc_config.rb +0 -29
  236. data/tasks/resources/build.yml.erb +0 -60
  237. data/tasks/resources/index.html.erb +0 -141
  238. data/tasks/resources/rubies.yml +0 -7
  239. data/tasks/sourcehut.rake +0 -110
  240. data/tasks/steep.rake +0 -11
  241. data/tasks/terminal_preview/app_screenshot.rb +0 -45
  242. data/tasks/terminal_preview/crash_report.rb +0 -54
  243. data/tasks/terminal_preview/example_app.rb +0 -27
  244. data/tasks/terminal_preview/launcher_script.rb +0 -48
  245. data/tasks/terminal_preview/preview_collection.rb +0 -60
  246. data/tasks/terminal_preview/preview_timing.rb +0 -24
  247. data/tasks/terminal_preview/safety_confirmation.rb +0 -58
  248. data/tasks/terminal_preview/saved_screenshot.rb +0 -56
  249. data/tasks/terminal_preview/system_appearance.rb +0 -13
  250. data/tasks/terminal_preview/terminal_window.rb +0 -138
  251. data/tasks/terminal_preview/window_id.rb +0 -16
  252. data/tasks/terminal_preview.rake +0 -30
  253. data/tasks/test.rake +0 -36
  254. data/tasks/website/index_page.rb +0 -30
  255. data/tasks/website/version.rb +0 -122
  256. data/tasks/website/version_menu.rb +0 -68
  257. data/tasks/website/versioned_documentation.rb +0 -83
  258. data/tasks/website/website.rb +0 -53
  259. data/tasks/website.rake +0 -28
@@ -1,132 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
-
6
- # Feature Request: Expose Block Title Rects
7
-
8
- ## Summary
9
-
10
- `Block` computes the position of each title during rendering but does not expose this information. Interactive applications need title rects for mouse click hit-testing.
11
-
12
- ## The Problem
13
-
14
- Building clickable TUI interfaces requires knowing where widgets render. When a block has multiple titles (e.g., a left-aligned title and a right-aligned toggle label), each title occupies a specific screen region. The application cannot query these regions.
15
-
16
- Currently, the only options are:
17
-
18
- 1. **Recompute the layout manually.** Duplicate the logic from `render_left_titles`, `render_right_titles`, and `render_center_titles`. This is fragile—any upstream change breaks the user's code.
19
- 2. **Use coarse hit-testing.** Check if a click is anywhere in the block's top border row. This cannot distinguish between multiple titles.
20
-
21
- Neither approach is satisfactory.
22
-
23
- ## Use Case
24
-
25
- Consider a TUI with a tabbed interface where the block's title bar contains:
26
-
27
- - A left-aligned title: `"Announce v0.7.3"`
28
- - A right-aligned toggle: `"emate"` (clickable to switch email clients)
29
-
30
- ```
31
- ┌Announce v0.7.3───────────────────────────────emate┐
32
- │ Preview Email ▸ Preview Commit ▸ Announce │
33
- │ │
34
- └───────────────────────────────────────────────────┘
35
- ```
36
-
37
- The application wants to:
38
-
39
- 1. Detect clicks on `"emate"` and toggle the email client
40
- 2. Detect clicks on tab names and switch tabs
41
- 3. Ignore clicks on the border characters
42
-
43
- Without title rects, the application must manually compute where `"emate"` renders based on block width, borders, alignment, and title content. This duplicates private logic from `Block::render_right_titles`.
44
-
45
- ## Current State (v0.30.0)
46
-
47
- `Block` has private methods that compute title areas:
48
-
49
- ```rust
50
- // Private - not accessible to users
51
- fn titles_area(&self, area: Rect, position: Position) -> Rect { ... }
52
- fn render_left_titles(&self, position: Position, area: Rect, buf: &mut Buffer) { ... }
53
- fn render_center_titles(&self, position: Position, area: Rect, buf: &mut Buffer) { ... }
54
- fn render_right_titles(&self, position: Position, area: Rect, buf: &mut Buffer) { ... }
55
- ```
56
-
57
- The `titles_area` method computes the general title region. The `render_*_titles` methods compute individual title rects during rendering but do not expose them.
58
-
59
- ## Proposed API
60
-
61
- Following the pattern established by `Block::inner(area)`, add a pure computation method that takes an area and returns computed sub-rects without rendering:
62
-
63
- ```rust
64
- impl Block {
65
- /// Returns the bounding rect for each title given an area.
66
- ///
67
- /// The rects are returned in the same order as titles were added.
68
- /// Useful for hit-testing mouse clicks against specific titles.
69
- ///
70
- /// # Example
71
- ///
72
- /// ```rust
73
- /// let block = Block::bordered()
74
- /// .title_top("Left Title")
75
- /// .title_top(Line::from("Right").right_aligned());
76
- ///
77
- /// let rects = block.title_rects(area);
78
- /// if rects[1].contains(mouse_position) {
79
- /// // Clicked on "Right"
80
- /// }
81
- /// ```
82
- pub fn title_rects(&self, area: Rect) -> Vec<Rect> { ... }
83
- }
84
- ```
85
-
86
- Alternatively, expose the individual areas by alignment:
87
-
88
- ```rust
89
- /// Returns the rect for the title at the given index.
90
- pub fn title_rect(&self, area: Rect, index: usize) -> Option<Rect> { ... }
91
-
92
- /// Returns the titles area for a given position (top or bottom).
93
- pub fn titles_area(&self, area: Rect, position: Position) -> Rect { ... }
94
- ```
95
-
96
- ## Workaround
97
-
98
- Without this API, users must replicate the title layout algorithm. Here is the current approach used in RatatuiRuby:
99
-
100
- ```rust
101
- // Manually compute right-aligned title position
102
- let email_label_width = email_client.len() as u16;
103
- let email_label_x = area.x + area.width - email_label_width - 2; // border + padding
104
- let email_label_rect = Rect::new(email_label_x, area.y, email_label_width, 1);
105
-
106
- if email_label_rect.contains(click_position) {
107
- toggle_email_client();
108
- }
109
- ```
110
-
111
- This works for simple cases but breaks when:
112
-
113
- - Borders are not all present (`Borders::LEFT` affects x offset)
114
- - Multiple right-aligned titles exist (spacing affects position)
115
- - Upstream layout logic changes
116
-
117
- ## Impact
118
-
119
- This feature benefits any application with interactive block titles:
120
-
121
- - Clickable tabs in title bars
122
- - Toggle buttons in headers
123
- - Breadcrumb navigation
124
- - Window controls (minimize/maximize/close buttons in the title area)
125
-
126
- Related discussion: [ratatui#738](https://github.com/ratatui/ratatui/issues/738) (title positioning behavior)
127
-
128
- ---
129
-
130
- This issue includes creative contributions from Claude (Anthropic) via Antigravity (Google). [https://declare-ai.org/1.0.0/creative.html](https://declare-ai.org/1.0.0/creative.html)
131
-
132
- *Discovered while implementing click handling for block title toggles in RatatuiRuby.*
data/doc/custom.css DELETED
@@ -1,22 +0,0 @@
1
- /*
2
- * SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
- * SPDX-License-Identifier: AGPL-3.0-or-later
4
- */
5
-
6
- img {
7
- max-width: 100%;
8
- height: auto;
9
- }
10
-
11
- .theme-toggle {
12
- margin-left: 0 !important;
13
- }
14
-
15
- /* Terminal Previews (Native PNGs)
16
- * The images already contain the window chrome and shadows.
17
- * We just need to center them and ensure they scale down on mobile.
18
- */
19
- img[src*="images/"] {
20
- display: block;
21
- margin: 2em auto;
22
- }
@@ -1,291 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
- # Quickstart
6
-
7
- Welcome to **ratatui_ruby**! This guide will help you get up and running with your first Terminal User Interface in Ruby.
8
-
9
- ## Installation
10
-
11
- See [Installation in the README](../../README.md#installation) for setup instructions.
12
-
13
-
14
- ## Tutorials
15
-
16
- ### Basic Application
17
-
18
- Here is a "Hello World" application that demonstrates the core lifecycle of a **ratatui_ruby** app.
19
-
20
- <!-- SPDX-SnippetBegin -->
21
- <!--
22
- SPDX-FileCopyrightText: 2026 Kerrick Long
23
- SPDX-License-Identifier: MIT-0
24
- -->
25
- <!-- SYNC:START:examples/verify_quickstart_lifecycle/app.rb:main -->
26
- ```ruby
27
- # 1. Initialize the terminal
28
- RatatuiRuby.init_terminal
29
-
30
- begin
31
- # The Main Loop
32
- loop do
33
- # 2. Create your UI (Immediate Mode)
34
- # We define a Paragraph widget inside a Block with a title and borders.
35
- view = RatatuiRuby::Widgets::Paragraph.new(
36
- text: "Hello, Ratatui! Press 'q' to quit.",
37
- alignment: :center,
38
- block: RatatuiRuby::Widgets::Block.new(
39
- title: "My Ruby TUI App",
40
- title_alignment: :center,
41
- borders: [:all],
42
- border_style: { fg: "cyan" },
43
- style: { fg: "white" }
44
- )
45
- )
46
-
47
- # 3. Draw the UI
48
- RatatuiRuby.draw do |frame|
49
- frame.render_widget(view, frame.area)
50
- end
51
-
52
- # 4. Poll for events
53
- case RatatuiRuby.poll_event
54
- in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
55
- break
56
- else
57
- nil
58
- end
59
-
60
- # 5. Guard against accidental output (optional but recommended)
61
- # Wrap any code that might puts/warn to prevent screen corruption.
62
- RatatuiRuby.guard_io do
63
- # SomeChattyGem.do_something
64
- end
65
- end
66
- ensure
67
- # 6. Restore the terminal to its original state
68
- RatatuiRuby.restore_terminal
69
- end
70
- ```
71
- <!-- SYNC:END -->
72
- <!-- SPDX-SnippetEnd -->
73
-
74
- [![quickstart_lifecycle](../images/verify_quickstart_lifecycle.png)](../../examples/verify_quickstart_lifecycle/README.md)
75
-
76
- #### How it works
77
-
78
- 1. **`RatatuiRuby.init_terminal`**: Enters raw mode and switches to the alternate screen.
79
- 2. **Immediate Mode UI**: On every iteration, describe your UI by creating `Data` objects (e.g., `Paragraph`, `Block`).
80
- 3. **`RatatuiRuby.draw { |frame| ... }`**: The block receives a `Frame` object as a canvas. Render widgets onto specific areas. Nothing is drawn until the block finishes, ensuring flicker-free updates.
81
- 4. **`RatatuiRuby.poll_event`**: Returns a typed `Event` object with predicates like `key?`, `mouse?`, `resize?`, etc. Returns `RatatuiRuby::Event::None` if no events are pending. Use predicates to check event type without pattern matching.
82
- 5. **`RatatuiRuby.guard_io { }`**: Wraps code that might write to stdout/stderr (e.g., chatty gems). Output is swallowed to prevent screen corruption. Optional but recommended for production apps.
83
- 6. **`RatatuiRuby.restore_terminal`**: Essential for leaving raw mode and returning to the shell. Always wrap your loop in `begin...ensure` to guarantee this runs.
84
-
85
- ### Simplified API
86
-
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.
88
-
89
- <!-- SPDX-SnippetBegin -->
90
- <!--
91
- SPDX-FileCopyrightText: 2026 Kerrick Long
92
- SPDX-License-Identifier: MIT-0
93
- -->
94
- <!-- SYNC:START:examples/verify_quickstart_dsl/app.rb:main -->
95
- ```ruby
96
- # 1. Initialize the terminal, start the run loop, and ensure the terminal is restored.
97
- RatatuiRuby.run do |tui|
98
- loop do
99
- # 2. Create your UI with methods instead of classes.
100
- view = tui.paragraph(
101
- text: "Hello, Ratatui! Press 'q' to quit.",
102
- alignment: :center,
103
- block: tui.block(
104
- title: "My Ruby TUI App",
105
- title_alignment: :center,
106
- borders: [:all],
107
- border_style: { fg: "cyan" },
108
- style: { fg: "white" }
109
- )
110
- )
111
-
112
- # 3. Use RatatuiRuby methods, too.
113
- tui.draw do |frame|
114
- frame.render_widget(view, frame.area)
115
- end
116
-
117
- # 4. Poll for events with pattern matching
118
- case tui.poll_event
119
- in { type: :key, code: "q" }
120
- break
121
- else
122
- # Ignore other events
123
- end
124
- end
125
- end
126
- ```
127
- <!-- SYNC:END -->
128
- <!-- SPDX-SnippetEnd -->
129
-
130
- #### How it works
131
-
132
- 1. **`RatatuiRuby.run`**: This context manager initializes the terminal before the block starts and ensures `restore_terminal` is called when the block exits (even if an error occurs).
133
- 2. **Widget Shorthand**: The block yields a `TUI` object (here named `tui`). This object provides factory methods for every widget, allowing you to write `tui.paragraph(...)` instead of the more verbose `RatatuiRuby::Widgets::Paragraph.new(...)`.
134
- 3. **Method Shorthand**: The `TUI` object also provides aliases for module functions of `RatatuiRuby`, allowing you to write `tui.draw(...)` instead of the more verbose `RatatuiRuby.draw(...)`.
135
- 4. **Pattern Matching for Events**: Use `case...in` with pattern matching for elegant event dispatch. Always include an `else` clause at the end to catch unmatched event types (mouse, resize, paste, focus, etc.), otherwise Ruby raises `NoMatchingPatternError`.
136
-
137
- For a deeper dive into the available application architectures (Manual vs Managed), see [Application Architecture](../concepts/application_architecture.md).
138
-
139
- ### Adding Layouts
140
-
141
- Real-world applications often need to split the screen into multiple areas. `RatatuiRuby::Layout` lets you do this easily.
142
-
143
- <!-- SPDX-SnippetBegin -->
144
- <!--
145
- SPDX-FileCopyrightText: 2026 Kerrick Long
146
- SPDX-License-Identifier: MIT-0
147
- -->
148
- <!-- SYNC:START:examples/verify_quickstart_layout/app.rb:main -->
149
- ```ruby
150
- loop do
151
- tui.draw do |frame|
152
- # 1. Split the screen
153
- top, bottom = tui.layout_split(
154
- frame.area,
155
- direction: :vertical,
156
- constraints: [
157
- tui.constraint_percentage(75),
158
- tui.constraint_percentage(25),
159
- ]
160
- )
161
-
162
- # 2. Render Top Widget
163
- frame.render_widget(
164
- tui.paragraph(
165
- text: "Hello, Ratatui!",
166
- alignment: :center,
167
- block: tui.block(title: "Content", borders: [:all], border_style: { fg: "cyan" })
168
- ),
169
- top
170
- )
171
-
172
- # 3. Render Bottom Widget with Styled Text
173
- # We use a Line of Spans to style specific characters
174
- text_line = tui.text_line(
175
- spans: [
176
- tui.text_span(content: "Press '"),
177
- tui.text_span(
178
- content: "q",
179
- style: tui.style(modifiers: [:bold, :underlined])
180
- ),
181
- tui.text_span(content: "' to quit."),
182
- ],
183
- alignment: :center
184
- )
185
-
186
- frame.render_widget(
187
- tui.paragraph(
188
- text: text_line,
189
- block: tui.block(title: "Controls", borders: [:all])
190
- ),
191
- bottom
192
- )
193
- end
194
-
195
- case tui.poll_event
196
- in { type: :key, code: "q" }
197
- break
198
- else
199
- # Ignore other events
200
- end
201
- end
202
- ```
203
- <!-- SYNC:END -->
204
- <!-- SPDX-SnippetEnd -->
205
-
206
- #### How it works
207
-
208
- 1. **`tui.layout_split` (`RatatuiRuby::Layout::Layout.split`)**: Takes an area (like `frame.area`) and splits it into multiple sub-areas based on constraints.
209
- 2. **`tui.constraint_*` (`RatatuiRuby::Layout::Constraint`)**: Defines how space is distributed (e.g., `percentage`, `length`, `min`, `max`).
210
- 3. **`Frame#render_widget(widget, rect)`**: You pass the specific area (like `top` or `bottom`) to render the widget into that exact region.
211
- 4. **`tui.text_span` (`RatatuiRuby::Text::Span`)**: Allows for rich styling within a single line of text.
212
-
213
- [![quickstart_layout](../images/verify_quickstart_layout.png)](../../examples/verify_quickstart_layout/README.md)
214
-
215
- ## Examples
216
-
217
- These examples showcase the full power of **ratatui_ruby**. You can find their source code in the [examples directory](../../examples).
218
-
219
- ### Widget Demos
220
-
221
- Focused examples for individual widgets. Each demonstrates a single widget and its configuration options.
222
-
223
- | Widget | What it demonstrates |
224
- | ------------------------------------------------------------- | ---------------------------------------------------------- |
225
- | [Bar Chart](../../examples/widget_barchart/app.rb) | Grouped bars, data visualization, custom bar styling |
226
- | [Block](../../examples/widget_block/app.rb) | Borders, titles, padding, nested widgets |
227
- | [Box](../../examples/widget_box/app.rb) | Block + Paragraph composition, text wrapping |
228
- | [Calendar](../../examples/widget_calendar/app.rb) | Date highlighting, month display, event markers |
229
- | [Chart](../../examples/widget_chart/app.rb) | Line/scatter plots, axes, legends, datasets |
230
- | [Gauge](../../examples/widget_gauge/app.rb) | Progress bars, percentage display, unicode blocks |
231
- | [Layout Split](../../examples/widget_layout_split/app.rb) | Constraint types, flex modes, responsive layouts |
232
- | [Line Gauge](../../examples/widget_line_gauge/app.rb) | Horizontal progress, labels, thin-style gauges |
233
- | [List](../../examples/widget_list/app.rb) | Selection, scrolling, highlight styles, rich text items |
234
- | [Map](../../examples/widget_map/app.rb) | Canvas widget, world map rendering, coordinates |
235
- | [Popup](../../examples/widget_popup/app.rb) | Clear widget, modal dialogs, overlay composition |
236
- | [Ratatui Logo](../../examples/widget_ratatui_logo/app.rb) | Decorative branding widget |
237
- | [Ratatui Mascot](../../examples/widget_ratatui_mascot/app.rb) | ASCII art Ferris mascot |
238
- | [Rect](../../examples/widget_rect/app.rb) | Geometry helpers, area calculations, contains/intersection |
239
- | [Rich Text](../../examples/widget_rich_text/app.rb) | Spans, lines, inline styling, mixed colors |
240
- | [Scrollbar](../../examples/widget_scrollbar/app.rb) | Orientations, thumb/track styling, scroll state |
241
- | [Scroll Text](../../examples/widget_scroll_text/app.rb) | Paragraph scrolling, viewport control, long content |
242
- | [Sparkline](../../examples/widget_sparkline/app.rb) | Mini charts, time series, bar sets |
243
- | [Style Colors](../../examples/widget_style_colors/app.rb) | Named colors, RGB, indexed 256-color palette |
244
- | [Table](../../examples/widget_table/app.rb) | Row selection, column widths, per-cell styling |
245
- | [Tabs](../../examples/widget_tabs/app.rb) | Tab navigation, highlighting, dividers |
246
- | [Text Width](../../examples/widget_text_width/app.rb) | Unicode-aware width measurement, CJK support |
247
- | [Canvas](../../examples/widget_canvas/app.rb) | Drawing shapes, markers, custom graphics |
248
- | [Cell](../../examples/widget_cell/app.rb) | Buffer cell inspection, styling attributes |
249
- | [Center](../../examples/widget_center/app.rb) | Centering content, horizontal/vertical alignment |
250
- | [Overlay](../../examples/widget_overlay/app.rb) | Layering widgets, modal backgrounds |
251
- | [Custom Render](../../examples/widget_render/app.rb) | Low-level Draw API, escape hatch for custom widgets |
252
-
253
- ### Sample Applications
254
-
255
- These larger examples combine widgets into complete applications, demonstrating real-world TUI patterns and architectures.
256
-
257
- | Application | Architecture | What you'll learn |
258
- | ---------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------ |
259
- | [All Events](../../examples/app_all_events/app.rb) | Model-View-Update | Event handling, unidirectional data flow, scalable structure |
260
- | [Color Picker](../../examples/app_color_picker/app.rb) | Component-Based | Hit testing, modal dialogs, encapsulated state |
261
- | [Debugging Showcase](../../examples/app_debugging_showcase/app.rb) | Simple Loop | Remote debugging, Rust backtraces, improved error messages |
262
- | [Login Form](../../examples/app_login_form/app.rb) | Overlay + Center | Modal forms, cursor positioning, text input |
263
- | [Stateful Interaction](../../examples/app_stateful_interaction/app.rb) | State Objects | ListState/TableState, offset read-back, mouse click-to-row |
264
-
265
- #### All Events
266
-
267
- [![all_events](../images/app_all_events.png)](../../examples/app_all_events/README.md)
268
-
269
- #### Color Picker
270
-
271
- [![color_picker](../images/app_color_picker.png)](../../examples/app_color_picker/README.md)
272
-
273
- #### Debugging Showcase
274
-
275
- [![debugging_showcase](../images/app_debugging_showcase.gif)](../../examples/app_debugging_showcase/README.md)
276
-
277
- #### Login Form
278
-
279
- [![login_form](../images/app_login_form.png)](../../examples/app_login_form/README.md)
280
-
281
-
282
- ## Next Steps
283
-
284
- Now that you've seen what **ratatui_ruby** can do:
285
-
286
- - **Deep dive**: Read the [Application Architecture](../concepts/application_architecture.md) guide for scaling patterns
287
- - **Test your TUI**: See the [Testing Guide](../concepts/application_testing.md) for snapshot and style assertions
288
- - **Avoid common mistakes**: See [Terminal Output During TUI Sessions](../troubleshooting/tui_output.md) to prevent screen corruption
289
- - **Explore the API**: Browse the [full RDoc documentation](../index.md)
290
- - **Learn the philosophy**: Read [Why RatatuiRuby?](./why.md) for comparisons and design decisions
291
- - **Get help**: Join the [discussion mailing list](https://lists.sr.ht/~kerrick/ratatui_ruby-discuss)
@@ -1,93 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
- SPDX-License-Identifier: CC-BY-SA-4.0
4
- -->
5
- # Why RatatuiRuby?
6
-
7
- The terminal is having a renaissance. Ruby deserves to be at the forefront.
8
-
9
- **RatatuiRuby** is a high-performance, immediate-mode TUI engine that brings the power of Rust's [Ratatui](https://ratatui.rs) library directly into Ruby. No ports. No emulations. A native bridge to the industry-standard Rust crate.
10
-
11
-
12
- ## The Pitch
13
-
14
- You want to build a terminal UI. You love Ruby. Your options were:
15
-
16
- 1. **Learn Go** for Bubble Tea
17
- 2. **Learn Rust** for Ratatui
18
- 3. **Use a pure-Ruby library** with limited performance
19
-
20
- We built a fourth option: **Write Ruby. Run Rust.**
21
-
22
- RatatuiRuby gives you Rust's layout engine, rendering speed, and battle-tested widgets — with Ruby's expressiveness, ecosystem, and joy.
23
-
24
-
25
- ## RatatuiRuby vs. CharmRuby
26
-
27
- [CharmRuby](https://charm-ruby.dev) is an excellent project by Marco Roth. It provides Ruby bindings to Charm's Go libraries (Bubble Tea, Lipgloss). The Ruby ecosystem is better because both projects exist.
28
-
29
- So which one should you choose?
30
-
31
- | | CharmRuby | RatatuiRuby |
32
- |---|-----------|-------------|
33
- | **Backend** | Go runtime | Rust (no runtime) |
34
- | **Architecture** | Elm Architecture (MVU) | Immediate-mode + your choice |
35
- | **GC Behavior** | Two GCs (Ruby + Go) | One GC (Ruby only) |
36
- | **Rendering** | String manipulation | Constraint-based layout tree |
37
- | **Best for** | Fans of Bubble Tea, MVU | Native performance, heavy-duty apps |
38
-
39
- **What's a runtime?** A runtime is background machinery that a language needs to run. Go has one (for goroutines and garbage collection). Rust doesn't — it compiles to plain machine code. When you use Go bindings, you're running *two* runtimes in the same process (Ruby's and Go's), which adds complexity and memory overhead. With Rust bindings, there's only Ruby.
40
-
41
- **Choose CharmRuby** if you prefer Charm's aesthetics or are migrating existing Bubble Tea code.
42
-
43
- **Choose RatatuiRuby** if you want zero-overhead native performance and architectural freedom. RatatuiRuby doesn't force a framework — you can build MVU, component-based, or any pattern you prefer.
44
-
45
-
46
- ## Why Not Just Write Rust?
47
-
48
- Rust is amazing. It's also strict.
49
-
50
- The borrow checker enforces memory safety. That's great for systems programming. It's painful for UI iteration. Moving a sidebar, changing a color, or swapping a widget often requires refactoring ownership chains.
51
-
52
- With RatatuiRuby, you just change the object. You get Rust's performance where it matters — rendering — and Ruby's flexibility where it counts — designing.
53
-
54
-
55
- ## Why Not Just Write Go?
56
-
57
- Go is pragmatic. But using Go bindings means running *two* runtimes in the same process: Ruby's and Go's. That adds complexity and memory overhead.
58
-
59
- With RatatuiRuby, there's only Ruby. Rust compiles to plain machine code with no runtime — it integrates seamlessly.
60
-
61
-
62
- ## Why Ruby?
63
-
64
- [Ruby isn't just another language](https://www.ruby-lang.org/en/). It's an ecosystem:
65
-
66
- - **[ActiveRecord](https://guides.rubyonrails.org/active_record_basics.html)** — Query your database with elegant, chainable methods
67
- - **[RSpec](https://rspec.info/)** — Write expressive, readable tests with `describe`, `it`, and `expect`
68
- - **[Blocks](https://docs.ruby-lang.org/en/4.0/syntax/calling_methods_rdoc.html#label-Block+Argument)** — Pass behavior to methods with `do...end`, the heart of Ruby's expressiveness
69
- - **[Metaprogramming](https://docs.ruby-lang.org/en/4.0/Module.html#method-i-class_eval)** — Define methods dynamically, build DSLs, and write code that writes code
70
- - **[Bundler](https://bundler.io/)** — Access 180,000+ gems with a single `bundle add`
71
-
72
- Build a dashboard for your Rails app. Monitor your Sidekiq jobs. Create developer tools in the same language as the code they inspect.
73
-
74
-
75
- ## The Philosophy: A Solid Foundation
76
-
77
- RatatuiRuby is a **low-level engine**. It provides raw primitives — Layouts, Blocks, Text, Tables, Charts — to build anything.
78
-
79
- It doesn't force a framework on you. You can use:
80
- - **Model-View-Update** for dashboards and data displays
81
- - **Component-based** patterns for interactive tools
82
- - **Your own architecture** for everything else
83
-
84
- This is the foundation for Ruby's next generation of TUI tools, dashboards, and interactive scripts.
85
-
86
-
87
- ## Get Started
88
-
89
- Ready to build?
90
-
91
- - [Quickstart Guide](./quickstart.md) — Your first app in 5 minutes
92
- - [Widget Gallery](./quickstart.md#widget-demos) — See what's possible
93
- - [Application Architecture](../concepts/application_architecture.md) — Patterns for scaling
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file