ratatui_ruby 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +1 -1
  3. data/.builds/ruby-3.3.yml +1 -1
  4. data/.builds/ruby-3.4.yml +1 -1
  5. data/.builds/ruby-4.0.0.yml +1 -1
  6. data/AGENTS.md +10 -4
  7. data/CHANGELOG.md +79 -7
  8. data/README.md +37 -5
  9. data/REUSE.toml +2 -7
  10. data/doc/application_architecture.md +96 -22
  11. data/doc/application_testing.md +76 -30
  12. data/doc/contributors/architectural_overhaul/chat_conversations.md +4952 -0
  13. data/doc/contributors/architectural_overhaul/implementation_plan.md +60 -0
  14. data/doc/contributors/architectural_overhaul/task.md +37 -0
  15. data/doc/contributors/design/ruby_frontend.md +288 -56
  16. data/doc/contributors/design/rust_backend.md +349 -54
  17. data/doc/contributors/developing_examples.md +134 -49
  18. data/doc/contributors/index.md +7 -5
  19. data/doc/contributors/v1.0.0_blockers.md +1729 -0
  20. data/doc/event_handling.md +11 -3
  21. data/doc/images/app_all_events.png +0 -0
  22. data/doc/images/app_color_picker.png +0 -0
  23. data/doc/images/app_login_form.png +0 -0
  24. data/doc/images/app_stateful_interaction.png +0 -0
  25. data/doc/images/verify_quickstart_dsl.png +0 -0
  26. data/doc/images/verify_quickstart_layout.png +0 -0
  27. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  28. data/doc/images/verify_readme_usage.png +0 -0
  29. data/doc/images/widget_barchart_demo.png +0 -0
  30. data/doc/images/widget_block_demo.png +0 -0
  31. data/doc/images/widget_canvas_demo.png +0 -0
  32. data/doc/images/widget_cell_demo.png +0 -0
  33. data/doc/images/widget_center_demo.png +0 -0
  34. data/doc/images/widget_chart_demo.png +0 -0
  35. data/doc/images/widget_list_demo.png +0 -0
  36. data/doc/images/widget_overlay_demo.png +0 -0
  37. data/doc/images/widget_render.png +0 -0
  38. data/doc/images/widget_rich_text.png +0 -0
  39. data/doc/images/widget_scroll_text.png +0 -0
  40. data/doc/images/widget_sparkline_demo.png +0 -0
  41. data/doc/images/widget_table_demo.png +0 -0
  42. data/doc/images/widget_tabs_demo.png +0 -0
  43. data/doc/images/widget_text_width.png +0 -0
  44. data/doc/index.md +11 -6
  45. data/doc/interactive_design.md +2 -2
  46. data/doc/quickstart.md +127 -165
  47. data/doc/terminal_limitations.md +92 -0
  48. data/doc/v0.7.0_migration.md +236 -0
  49. data/doc/why.md +93 -0
  50. data/examples/app_all_events/README.md +47 -27
  51. data/examples/app_all_events/app.rb +38 -35
  52. data/examples/app_all_events/model/app_model.rb +157 -0
  53. data/examples/app_all_events/model/event_entry.rb +17 -0
  54. data/examples/app_all_events/model/msg.rb +37 -0
  55. data/examples/app_all_events/update.rb +73 -0
  56. data/examples/app_all_events/view/app_view.rb +9 -9
  57. data/examples/app_all_events/view/controls_view.rb +9 -7
  58. data/examples/app_all_events/view/counts_view.rb +13 -9
  59. data/examples/app_all_events/view/live_view.rb +9 -8
  60. data/examples/app_all_events/view/log_view.rb +11 -16
  61. data/examples/app_color_picker/README.md +84 -42
  62. data/examples/app_color_picker/app.rb +24 -62
  63. data/examples/app_color_picker/controls.rb +90 -0
  64. data/examples/app_color_picker/copy_dialog.rb +45 -49
  65. data/examples/app_color_picker/export_pane.rb +126 -0
  66. data/examples/app_color_picker/input.rb +99 -67
  67. data/examples/app_color_picker/main_container.rb +178 -0
  68. data/examples/app_color_picker/palette.rb +55 -26
  69. data/examples/app_login_form/README.md +49 -0
  70. data/examples/app_login_form/app.rb +2 -3
  71. data/examples/app_stateful_interaction/README.md +33 -0
  72. data/examples/app_stateful_interaction/app.rb +272 -0
  73. data/examples/timeout_demo.rb +43 -0
  74. data/examples/verify_quickstart_dsl/README.md +49 -0
  75. data/examples/verify_quickstart_dsl/app.rb +2 -0
  76. data/examples/verify_quickstart_layout/README.md +71 -0
  77. data/examples/verify_quickstart_layout/app.rb +2 -0
  78. data/examples/verify_quickstart_lifecycle/README.md +56 -0
  79. data/examples/verify_quickstart_lifecycle/app.rb +10 -4
  80. data/examples/verify_readme_usage/README.md +43 -0
  81. data/examples/verify_readme_usage/app.rb +8 -2
  82. data/examples/widget_barchart_demo/README.md +50 -0
  83. data/examples/widget_barchart_demo/app.rb +5 -5
  84. data/examples/widget_block_demo/README.md +36 -0
  85. data/examples/widget_block_demo/app.rb +256 -0
  86. data/examples/widget_box_demo/README.md +45 -0
  87. data/examples/widget_calendar_demo/README.md +39 -0
  88. data/examples/widget_calendar_demo/app.rb +5 -1
  89. data/examples/widget_canvas_demo/README.md +27 -0
  90. data/examples/widget_canvas_demo/app.rb +123 -0
  91. data/examples/widget_cell_demo/README.md +36 -0
  92. data/examples/widget_cell_demo/app.rb +31 -24
  93. data/examples/widget_center_demo/README.md +29 -0
  94. data/examples/widget_center_demo/app.rb +116 -0
  95. data/examples/widget_chart_demo/README.md +41 -0
  96. data/examples/widget_chart_demo/app.rb +7 -2
  97. data/examples/widget_gauge_demo/README.md +41 -0
  98. data/examples/widget_layout_split/README.md +44 -0
  99. data/examples/widget_line_gauge_demo/README.md +41 -0
  100. data/examples/widget_list_demo/README.md +49 -0
  101. data/examples/widget_list_demo/app.rb +91 -107
  102. data/examples/widget_map_demo/README.md +39 -0
  103. data/examples/{app_map_demo → widget_map_demo}/app.rb +4 -4
  104. data/examples/widget_overlay_demo/README.md +36 -0
  105. data/examples/widget_overlay_demo/app.rb +248 -0
  106. data/examples/widget_popup_demo/README.md +36 -0
  107. data/examples/widget_ratatui_logo_demo/README.md +34 -0
  108. data/examples/widget_ratatui_logo_demo/app.rb +1 -1
  109. data/examples/widget_ratatui_mascot_demo/README.md +34 -0
  110. data/examples/widget_rect/README.md +38 -0
  111. data/examples/widget_render/README.md +37 -0
  112. data/examples/widget_render/app.rb +3 -3
  113. data/examples/widget_rich_text/README.md +35 -0
  114. data/examples/widget_rich_text/app.rb +62 -33
  115. data/examples/widget_scroll_text/README.md +37 -0
  116. data/examples/widget_scroll_text/app.rb +0 -1
  117. data/examples/widget_scrollbar_demo/README.md +37 -0
  118. data/examples/widget_sparkline_demo/README.md +42 -0
  119. data/examples/widget_sparkline_demo/app.rb +4 -3
  120. data/examples/widget_style_colors/README.md +34 -0
  121. data/examples/widget_table_demo/README.md +48 -0
  122. data/examples/{app_table_select → widget_table_demo}/app.rb +65 -12
  123. data/examples/widget_tabs_demo/README.md +41 -0
  124. data/examples/widget_tabs_demo/app.rb +15 -1
  125. data/examples/widget_text_width/README.md +35 -0
  126. data/examples/widget_text_width/app.rb +113 -0
  127. data/exe/.gitkeep +0 -0
  128. data/ext/ratatui_ruby/Cargo.lock +11 -4
  129. data/ext/ratatui_ruby/Cargo.toml +2 -1
  130. data/ext/ratatui_ruby/src/events.rs +238 -26
  131. data/ext/ratatui_ruby/src/frame.rs +116 -3
  132. data/ext/ratatui_ruby/src/lib.rs +37 -6
  133. data/ext/ratatui_ruby/src/rendering.rs +22 -21
  134. data/ext/ratatui_ruby/src/string_width.rs +101 -0
  135. data/ext/ratatui_ruby/src/terminal.rs +39 -15
  136. data/ext/ratatui_ruby/src/text.rs +13 -4
  137. data/ext/ratatui_ruby/src/widgets/barchart.rs +24 -6
  138. data/ext/ratatui_ruby/src/widgets/canvas.rs +5 -5
  139. data/ext/ratatui_ruby/src/widgets/gauge.rs +9 -2
  140. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +9 -2
  141. data/ext/ratatui_ruby/src/widgets/list.rs +179 -3
  142. data/ext/ratatui_ruby/src/widgets/list_state.rs +137 -0
  143. data/ext/ratatui_ruby/src/widgets/mod.rs +3 -0
  144. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +93 -1
  145. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
  146. data/ext/ratatui_ruby/src/widgets/table.rs +191 -34
  147. data/ext/ratatui_ruby/src/widgets/table_state.rs +121 -0
  148. data/lib/ratatui_ruby/buffer/cell.rb +168 -0
  149. data/lib/ratatui_ruby/buffer.rb +15 -0
  150. data/lib/ratatui_ruby/cell.rb +4 -4
  151. data/lib/ratatui_ruby/event/key/character.rb +35 -0
  152. data/lib/ratatui_ruby/event/key/media.rb +44 -0
  153. data/lib/ratatui_ruby/event/key/modifier.rb +95 -0
  154. data/lib/ratatui_ruby/event/key/navigation.rb +55 -0
  155. data/lib/ratatui_ruby/event/key/system.rb +45 -0
  156. data/lib/ratatui_ruby/event/key.rb +111 -51
  157. data/lib/ratatui_ruby/event/mouse.rb +3 -3
  158. data/lib/ratatui_ruby/event/paste.rb +1 -1
  159. data/lib/ratatui_ruby/frame.rb +100 -4
  160. data/lib/ratatui_ruby/layout/constraint.rb +95 -0
  161. data/lib/ratatui_ruby/layout/layout.rb +106 -0
  162. data/lib/ratatui_ruby/layout/rect.rb +118 -0
  163. data/lib/ratatui_ruby/layout.rb +19 -0
  164. data/lib/ratatui_ruby/list_state.rb +88 -0
  165. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +2 -2
  166. data/lib/ratatui_ruby/schema/cursor.rb +5 -0
  167. data/lib/ratatui_ruby/schema/gauge.rb +3 -1
  168. data/lib/ratatui_ruby/schema/layout.rb +1 -1
  169. data/lib/ratatui_ruby/schema/line_gauge.rb +2 -2
  170. data/lib/ratatui_ruby/schema/list.rb +25 -4
  171. data/lib/ratatui_ruby/schema/list_item.rb +41 -0
  172. data/lib/ratatui_ruby/schema/rect.rb +43 -0
  173. data/lib/ratatui_ruby/schema/row.rb +66 -0
  174. data/lib/ratatui_ruby/schema/style.rb +24 -4
  175. data/lib/ratatui_ruby/schema/table.rb +29 -11
  176. data/lib/ratatui_ruby/schema/text.rb +96 -3
  177. data/lib/ratatui_ruby/scrollbar_state.rb +112 -0
  178. data/lib/ratatui_ruby/style/style.rb +81 -0
  179. data/lib/ratatui_ruby/style.rb +15 -0
  180. data/lib/ratatui_ruby/table_state.rb +90 -0
  181. data/lib/ratatui_ruby/test_helper/event_injection.rb +169 -0
  182. data/lib/ratatui_ruby/test_helper/snapshot.rb +414 -0
  183. data/lib/ratatui_ruby/test_helper/style_assertions.rb +351 -0
  184. data/lib/ratatui_ruby/test_helper/terminal.rb +127 -0
  185. data/lib/ratatui_ruby/test_helper/test_doubles.rb +68 -0
  186. data/lib/ratatui_ruby/test_helper.rb +65 -358
  187. data/lib/ratatui_ruby/tui/buffer_factories.rb +20 -0
  188. data/lib/ratatui_ruby/tui/canvas_factories.rb +44 -0
  189. data/lib/ratatui_ruby/tui/core.rb +38 -0
  190. data/lib/ratatui_ruby/tui/layout_factories.rb +74 -0
  191. data/lib/ratatui_ruby/tui/state_factories.rb +33 -0
  192. data/lib/ratatui_ruby/tui/style_factories.rb +20 -0
  193. data/lib/ratatui_ruby/tui/text_factories.rb +44 -0
  194. data/lib/ratatui_ruby/tui/widget_factories.rb +195 -0
  195. data/lib/ratatui_ruby/tui.rb +75 -0
  196. data/lib/ratatui_ruby/version.rb +1 -1
  197. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +47 -0
  198. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +25 -0
  199. data/lib/ratatui_ruby/widgets/bar_chart.rb +239 -0
  200. data/lib/ratatui_ruby/widgets/block.rb +192 -0
  201. data/lib/ratatui_ruby/widgets/calendar.rb +84 -0
  202. data/lib/ratatui_ruby/widgets/canvas.rb +231 -0
  203. data/lib/ratatui_ruby/widgets/cell.rb +47 -0
  204. data/lib/ratatui_ruby/widgets/center.rb +59 -0
  205. data/lib/ratatui_ruby/widgets/chart.rb +185 -0
  206. data/lib/ratatui_ruby/widgets/clear.rb +54 -0
  207. data/lib/ratatui_ruby/widgets/cursor.rb +42 -0
  208. data/lib/ratatui_ruby/widgets/gauge.rb +72 -0
  209. data/lib/ratatui_ruby/widgets/line_gauge.rb +80 -0
  210. data/lib/ratatui_ruby/widgets/list.rb +127 -0
  211. data/lib/ratatui_ruby/widgets/list_item.rb +43 -0
  212. data/lib/ratatui_ruby/widgets/overlay.rb +43 -0
  213. data/lib/ratatui_ruby/widgets/paragraph.rb +99 -0
  214. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +31 -0
  215. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +36 -0
  216. data/lib/ratatui_ruby/widgets/row.rb +68 -0
  217. data/lib/ratatui_ruby/widgets/scrollbar.rb +143 -0
  218. data/lib/ratatui_ruby/widgets/shape/label.rb +68 -0
  219. data/lib/ratatui_ruby/widgets/sparkline.rb +134 -0
  220. data/lib/ratatui_ruby/widgets/table.rb +141 -0
  221. data/lib/ratatui_ruby/widgets/tabs.rb +85 -0
  222. data/lib/ratatui_ruby/widgets.rb +40 -0
  223. data/lib/ratatui_ruby.rb +64 -57
  224. data/sig/examples/app_all_events/view.rbs +1 -1
  225. data/sig/examples/app_all_events/view_state.rbs +1 -1
  226. data/sig/examples/app_stateful_interaction/app.rbs +33 -0
  227. data/sig/examples/widget_block_demo/app.rbs +32 -0
  228. data/sig/examples/{app_map_demo → widget_map_demo}/app.rbs +2 -2
  229. data/sig/examples/{app_table_select → widget_table_demo}/app.rbs +2 -2
  230. data/sig/examples/{widget_table_flex → widget_text_width}/app.rbs +2 -3
  231. data/sig/ratatui_ruby/event.rbs +11 -1
  232. data/sig/ratatui_ruby/frame.rbs +2 -0
  233. data/sig/ratatui_ruby/list_state.rbs +13 -0
  234. data/sig/ratatui_ruby/ratatui_ruby.rbs +2 -2
  235. data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +3 -3
  236. data/sig/ratatui_ruby/schema/gauge.rbs +2 -2
  237. data/sig/ratatui_ruby/schema/line_gauge.rbs +2 -2
  238. data/sig/ratatui_ruby/schema/list.rbs +4 -2
  239. data/sig/ratatui_ruby/schema/list_item.rbs +10 -0
  240. data/sig/ratatui_ruby/schema/rect.rbs +3 -0
  241. data/sig/ratatui_ruby/schema/row.rbs +22 -0
  242. data/sig/ratatui_ruby/schema/style.rbs +3 -3
  243. data/sig/ratatui_ruby/schema/table.rbs +3 -1
  244. data/sig/ratatui_ruby/schema/text.rbs +9 -6
  245. data/sig/ratatui_ruby/scrollbar_state.rbs +18 -0
  246. data/sig/ratatui_ruby/session.rbs +41 -48
  247. data/sig/ratatui_ruby/table_state.rbs +15 -0
  248. data/sig/ratatui_ruby/test_helper/event_injection.rbs +16 -0
  249. data/sig/ratatui_ruby/test_helper/snapshot.rbs +12 -0
  250. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +64 -0
  251. data/sig/ratatui_ruby/test_helper/terminal.rbs +14 -0
  252. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +22 -0
  253. data/sig/ratatui_ruby/test_helper.rbs +5 -4
  254. data/sig/ratatui_ruby/tui/buffer_factories.rbs +10 -0
  255. data/sig/ratatui_ruby/tui/canvas_factories.rbs +14 -0
  256. data/sig/ratatui_ruby/tui/core.rbs +14 -0
  257. data/sig/ratatui_ruby/tui/layout_factories.rbs +19 -0
  258. data/sig/ratatui_ruby/tui/state_factories.rbs +12 -0
  259. data/sig/ratatui_ruby/tui/style_factories.rbs +10 -0
  260. data/sig/ratatui_ruby/tui/text_factories.rbs +14 -0
  261. data/sig/ratatui_ruby/tui/widget_factories.rbs +39 -0
  262. data/sig/ratatui_ruby/tui.rbs +19 -0
  263. data/tasks/autodoc/examples.rb +79 -0
  264. data/tasks/autodoc.rake +7 -35
  265. data/tasks/bump/changelog.rb +3 -3
  266. data/tasks/bump/links.rb +67 -0
  267. data/tasks/sourcehut.rake +64 -21
  268. data/tasks/terminal_preview/app_screenshot.rb +13 -3
  269. data/tasks/terminal_preview/saved_screenshot.rb +4 -3
  270. metadata +169 -48
  271. data/doc/contributors/dwim_dx.md +0 -366
  272. data/doc/images/app_analytics.png +0 -0
  273. data/doc/images/app_custom_widget.png +0 -0
  274. data/doc/images/app_mouse_events.png +0 -0
  275. data/doc/images/app_table_select.png +0 -0
  276. data/doc/images/widget_block_padding.png +0 -0
  277. data/doc/images/widget_block_titles.png +0 -0
  278. data/doc/images/widget_list_styles.png +0 -0
  279. data/doc/images/widget_table_flex.png +0 -0
  280. data/examples/app_all_events/model/events.rb +0 -180
  281. data/examples/app_all_events/model/highlight.rb +0 -57
  282. data/examples/app_all_events/test/snapshots/after_focus_lost.txt +0 -24
  283. data/examples/app_all_events/test/snapshots/after_focus_regained.txt +0 -24
  284. data/examples/app_all_events/test/snapshots/after_horizontal_resize.txt +0 -24
  285. data/examples/app_all_events/test/snapshots/after_key_a.txt +0 -24
  286. data/examples/app_all_events/test/snapshots/after_key_ctrl_x.txt +0 -24
  287. data/examples/app_all_events/test/snapshots/after_mouse_click.txt +0 -24
  288. data/examples/app_all_events/test/snapshots/after_mouse_drag.txt +0 -24
  289. data/examples/app_all_events/test/snapshots/after_multiple_events.txt +0 -24
  290. data/examples/app_all_events/test/snapshots/after_paste.txt +0 -24
  291. data/examples/app_all_events/test/snapshots/after_resize.txt +0 -24
  292. data/examples/app_all_events/test/snapshots/after_right_click.txt +0 -24
  293. data/examples/app_all_events/test/snapshots/after_vertical_resize.txt +0 -24
  294. data/examples/app_all_events/test/snapshots/initial_state.txt +0 -24
  295. data/examples/app_all_events/view_state.rb +0 -42
  296. data/examples/app_color_picker/scene.rb +0 -201
  297. data/examples/widget_block_padding/app.rb +0 -67
  298. data/examples/widget_block_titles/app.rb +0 -69
  299. data/examples/widget_list_styles/app.rb +0 -141
  300. data/examples/widget_table_flex/app.rb +0 -95
  301. data/lib/ratatui_ruby/session/autodoc.rb +0 -417
  302. data/lib/ratatui_ruby/session.rb +0 -163
  303. data/sig/examples/widget_block_padding/app.rbs +0 -11
  304. data/sig/examples/widget_block_titles/app.rbs +0 -11
  305. data/sig/examples/widget_list_styles/app.rbs +0 -11
  306. data/tasks/autodoc/inventory.rb +0 -61
  307. data/tasks/autodoc/notice.rb +0 -26
  308. data/tasks/autodoc/rbs.rb +0 -38
  309. data/tasks/autodoc/rdoc.rb +0 -45
  310. data/tasks/bump/comparison_links.rb +0 -41
  311. /data/doc/images/{app_map_demo.png → widget_map_demo.png} +0 -0
@@ -10,7 +10,15 @@ SPDX-License-Identifier: AGPL-3.0-or-later
10
10
 
11
11
  Events are retrieved using `RatatuiRuby.poll_event`. This method returns an instance of a subclass of `RatatuiRuby::Event` (e.g., `RatatuiRuby::Event::Key`, `RatatuiRuby::Event::Mouse`). When no event is available, it returns `RatatuiRuby::Event::None`—a [null object](https://martinfowler.com/eaaCatalog/specialCase.html) that safely responds to all event predicates with `false`.
12
12
 
13
- ## 1. Symbol and String Comparison (Simplest)
13
+ ## 1. Blocking vs. Polling
14
+
15
+ Most applications run in a loop (e.g., a game loop or UI loop). To prevent high CPU usage, the loop should wait briefly for input.
16
+
17
+ * **Default (Polling):** `RatatuiRuby.poll_event` (no args) waits for **0.016s** (approx 60 FPS). If no event occurs, it returns `RatatuiRuby::Event::None`. This keeps the application responsive.
18
+ * **Blocking:** `RatatuiRuby.poll_event(timeout: nil)` waits **forever** until an event occurs. Use this for scripts that only react to input and do not need to update the UI on a timer.
19
+ * **Non-Blocking:** `RatatuiRuby.poll_event(timeout: 0.0)` returns immediately.
20
+
21
+ ## 2. Symbol and String Comparison (Simplest)
14
22
 
15
23
  For simple key events, `RatatuiRuby::Event::Key` objects can be compared directly to Symbols or Strings. This is often the quickest way to get started.
16
24
 
@@ -36,7 +44,7 @@ if event == :enter
36
44
  end
37
45
  ```
38
46
 
39
- ## 2. Predicate Methods (Intermediate)
47
+ ## 3. Predicate Methods (Intermediate)
40
48
 
41
49
  If you need more control or logic (e.g. `if/elsif`), or need to handle non-key events like Resize or Mouse, use the predicate methods.
42
50
 
@@ -82,7 +90,7 @@ if event.mouse? && event.scroll_up?
82
90
  end
83
91
  ```
84
92
 
85
- ## 3. Pattern Matching (Powerful)
93
+ ## 4. Pattern Matching (Powerful)
86
94
 
87
95
  For complex applications, Ruby 3.0+ Pattern Matching with the `type:` discriminator is the most idiomatic and concise approach.
88
96
 
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/doc/index.md CHANGED
@@ -7,13 +7,18 @@
7
7
 
8
8
  ## Documentation for Users
9
9
 
10
- - [README](../README.md)
11
- - [Quickstart](./quickstart.md)
12
- - [Application Architecture](./application_architecture.md)
13
- - [Testing Your Application](./application_testing.md)
10
+ - [README](../README.md): Project overview and installation
11
+ - [Why RatatuiRuby?](./why.md): Philosophy, comparisons, and what makes us different
12
+ - [Quickstart](./quickstart.md): Build your first TUI app
13
+ - [Application Architecture](./application_architecture.md): Lifecycle patterns and API choices
14
+ - [Event Handling](./event_handling.md): Keyboard, mouse, and terminal events
15
+ - [Interactive Design](./interactive_design.md): Cached layout pattern for hit testing
16
+ - [Terminal Limitations](./terminal_limitations.md): Platform quirks and workarounds
17
+ - [Testing Your Application](./application_testing.md): Snapshot testing and style assertions
18
+ - [Migrating to v0.7.0](./v0.7.0_migration.md): Namespace changes and upgrade guide
14
19
 
15
20
 
16
21
  ## Documentation for Contributors
17
22
 
18
- - [Contributing Guidelines](https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md)
19
- - [More Documentation for Contributors](./contributors/index.md)
23
+ - [Contributing Guidelines](https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md): How to contribute patches and features
24
+ - [More Documentation for Contributors](./contributors/index.md): Internal design docs and style guides
@@ -103,10 +103,10 @@ end
103
103
 
104
104
  ## Layout.split
105
105
 
106
- `Layout.split` computes layout geometry without rendering. It returns an array of `Rect` objects. While you can call `RatatuiRuby::Layout.split` directly, we recommend using the `Session` helper (`tui.layout_split`) for cleaner application code.
106
+ `Layout.split` computes layout geometry without rendering. It returns an array of `Rect` objects. While you can call `RatatuiRuby::Layout.split` directly, we recommend using the `TUI` helper (`tui.layout_split`) for cleaner application code.
107
107
 
108
108
  ```ruby
109
- # Preferred (Session API)
109
+ # Preferred (TUI API)
110
110
  left, right = tui.layout_split(area, constraints: [...])
111
111
 
112
112
  # Manual (Core API)
data/doc/quickstart.md CHANGED
@@ -8,25 +8,7 @@ Welcome to **ratatui_ruby**! This guide will help you get up and running with yo
8
8
 
9
9
  ## Installation
10
10
 
11
- Add this line to your application's Gemfile:
12
-
13
- ```ruby
14
- gem "ratatui_ruby"
15
- ```
16
-
17
-
18
- And then execute:
19
-
20
- ```bash
21
- bundle install
22
- ```
23
-
24
-
25
- Or install it yourself as:
26
-
27
- ```bash
28
- gem install ratatui_ruby
29
- ```
11
+ See [Installation in the README](../README.md#installation) for setup instructions.
30
12
 
31
13
 
32
14
  ## Tutorials
@@ -35,21 +17,20 @@ gem install ratatui_ruby
35
17
 
36
18
  Here is a "Hello World" application that demonstrates the core lifecycle of a **ratatui_ruby** app.
37
19
 
20
+ <!-- SYNC:START:../examples/verify_quickstart_lifecycle/app.rb:main -->
38
21
  ```ruby
39
- require "ratatui_ruby"
40
-
41
22
  # 1. Initialize the terminal
42
23
  RatatuiRuby.init_terminal
43
-
24
+
44
25
  begin
45
26
  # The Main Loop
46
27
  loop do
47
28
  # 2. Create your UI (Immediate Mode)
48
29
  # We define a Paragraph widget inside a Block with a title and borders.
49
- view = RatatuiRuby::Paragraph.new(
30
+ view = RatatuiRuby::Widgets::Paragraph.new(
50
31
  text: "Hello, Ratatui! Press 'q' to quit.",
51
32
  alignment: :center,
52
- block: RatatuiRuby::Block.new(
33
+ block: RatatuiRuby::Widgets::Block.new(
53
34
  title: "My Ruby TUI App",
54
35
  title_alignment: :center,
55
36
  borders: [:all],
@@ -57,23 +38,28 @@ begin
57
38
  style: { fg: "white" }
58
39
  )
59
40
  )
60
-
41
+
61
42
  # 3. Draw the UI
62
43
  RatatuiRuby.draw do |frame|
63
44
  frame.render_widget(view, frame.area)
64
45
  end
65
-
46
+
66
47
  # 4. Poll for events
67
- event = RatatuiRuby.poll_event
68
- break if event.key? && event.code == "q"
48
+ case RatatuiRuby.poll_event
49
+ in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
50
+ break
51
+ else
52
+ nil
53
+ end
69
54
  end
70
55
  ensure
71
56
  # 5. Restore the terminal to its original state
72
57
  RatatuiRuby.restore_terminal
73
58
  end
74
59
  ```
60
+ <!-- SYNC:END -->
75
61
 
76
- ![quickstart_lifecycle](./images/verify_quickstart_lifecycle.png)
62
+ [![quickstart_lifecycle](./images/verify_quickstart_lifecycle.png)](../examples/verify_quickstart_lifecycle/README.md)
77
63
 
78
64
  #### How it works
79
65
 
@@ -83,14 +69,13 @@ end
83
69
  4. **`RatatuiRuby.poll_event`**: Returns a typed `Event` object with predicates like `key?`, `mouse?`, `resize?`, etc. Returns `RatatuiRuby::Event::None` if no events are pending. Use predicates to check event type without pattern matching.
84
70
  5. **`RatatuiRuby.restore_terminal`**: Essential for leaving raw mode and returning to the shell. Always wrap your loop in `begin...ensure` to guarantee this runs.
85
71
 
86
- ### Idiomatic Session
72
+ ### Simplified API
87
73
 
88
- You can simplify your code by using `RatatuiRuby.run`. This method handles the terminal lifecycle for you, yielding a `Session` object with factory methods for widgets.
74
+ You can simplify your code by using `RatatuiRuby.run`. This method handles the terminal lifecycle for you, yielding a `TUI` object with factory methods for widgets.
89
75
 
90
- ```rb
91
- require "ratatui_ruby"
92
-
93
- # 1. Initialize the terminal and ensure it is restored.
76
+ <!-- SYNC:START:../examples/verify_quickstart_dsl/app.rb:main -->
77
+ ```ruby
78
+ # 1. Initialize the terminal, start the run loop, and ensure the terminal is restored.
94
79
  RatatuiRuby.run do |tui|
95
80
  loop do
96
81
  # 2. Create your UI with methods instead of classes.
@@ -121,12 +106,13 @@ RatatuiRuby.run do |tui|
121
106
  end
122
107
  end
123
108
  ```
109
+ <!-- SYNC:END -->
124
110
 
125
111
  #### How it works
126
112
 
127
113
  1. **`RatatuiRuby.run`**: This context manager initializes the terminal before the block starts and ensures `restore_terminal` is called when the block exits (even if an error occurs).
128
- 2. **Widget Shorthand**: The block yields a `Session` object (here named `tui`). This object provides factory methods for every widget, allowing you to write `tui.paragraph(...)` instead of the more verbose `RatatuiRuby::Paragraph.new(...)`.
129
- 3. **Method Shorthand**: The session object also provides aliases for module functions of `RatatuiRuby`, allowing you to write `tui.draw(...)` instead of the more verbose `RatatuiRuby.draw(...)`.
114
+ 2. **Widget Shorthand**: The block yields a `TUI` object (here named `tui`). This object provides factory methods for every widget, allowing you to write `tui.paragraph(...)` instead of the more verbose `RatatuiRuby::Widgets::Paragraph.new(...)`.
115
+ 3. **Method Shorthand**: The `TUI` object also provides aliases for module functions of `RatatuiRuby`, allowing you to write `tui.draw(...)` instead of the more verbose `RatatuiRuby.draw(...)`.
130
116
  4. **Pattern Matching for Events**: Use `case...in` with pattern matching for elegant event dispatch. Always include an `else` clause at the end to catch unmatched event types (mouse, resize, paste, focus, etc.), otherwise Ruby raises `NoMatchingPatternError`.
131
117
 
132
118
  For a deeper dive into the available application architectures (Manual vs Managed), see [Application Architecture](./application_architecture.md).
@@ -135,164 +121,140 @@ For a deeper dive into the available application architectures (Manual vs Manage
135
121
 
136
122
  Real-world applications often need to split the screen into multiple areas. `RatatuiRuby::Layout` lets you do this easily.
137
123
 
124
+ <!-- SYNC:START:../examples/verify_quickstart_layout/app.rb:main -->
138
125
  ```ruby
139
- require "ratatui_ruby"
126
+ loop do
127
+ tui.draw do |frame|
128
+ # 1. Split the screen
129
+ top, bottom = tui.layout_split(
130
+ frame.area,
131
+ direction: :vertical,
132
+ constraints: [
133
+ tui.constraint_percentage(75),
134
+ tui.constraint_percentage(25),
135
+ ]
136
+ )
140
137
 
141
- RatatuiRuby.run do |tui|
142
- loop do
143
- tui.draw do |frame|
144
- # 1. Split the screen
145
- top, bottom = tui.layout_split(
146
- frame.area,
147
- direction: :vertical,
148
- constraints: [
149
- tui.constraint_percentage(75),
150
- tui.constraint_percentage(25),
151
- ]
152
- )
138
+ # 2. Render Top Widget
139
+ frame.render_widget(
140
+ tui.paragraph(
141
+ text: "Hello, Ratatui!",
142
+ alignment: :center,
143
+ block: tui.block(title: "Content", borders: [:all], border_color: "cyan")
144
+ ),
145
+ top
146
+ )
153
147
 
154
- # 2. Render Top Widget
155
- frame.render_widget(
156
- tui.paragraph(
157
- text: "Hello, Ratatui!",
158
- alignment: :center,
159
- block: tui.block(title: "Content", borders: [:all], border_color: "cyan")
148
+ # 3. Render Bottom Widget with Styled Text
149
+ # We use a Line of Spans to style specific characters
150
+ text_line = tui.text_line(
151
+ spans: [
152
+ tui.text_span(content: "Press '"),
153
+ tui.text_span(
154
+ content: "q",
155
+ style: tui.style(modifiers: [:bold, :underlined])
160
156
  ),
161
- top
162
- )
163
-
164
- # 3. Render Bottom Widget with Styled Text
165
- # We use a Line of Spans to style specific characters
166
- text_line = tui.text_line(
167
- spans: [
168
- tui.text_span(content: "Press '"),
169
- tui.text_span(
170
- content: "q",
171
- style: tui.style(modifiers: [:bold, :underlined])
172
- ),
173
- tui.text_span(content: "' to quit."),
174
- ],
175
- alignment: :center
176
- )
157
+ tui.text_span(content: "' to quit."),
158
+ ],
159
+ alignment: :center
160
+ )
177
161
 
178
- frame.render_widget(
179
- tui.paragraph(
180
- text: text_line,
181
- block: tui.block(title: "Controls", borders: [:all])
182
- ),
183
- bottom
184
- )
185
- end
162
+ frame.render_widget(
163
+ tui.paragraph(
164
+ text: text_line,
165
+ block: tui.block(title: "Controls", borders: [:all])
166
+ ),
167
+ bottom
168
+ )
169
+ end
186
170
 
187
- case tui.poll_event
188
- in { type: :key, code: "q" }
189
- break
190
- else
191
- # Ignore other events
192
- end
171
+ case tui.poll_event
172
+ in { type: :key, code: "q" }
173
+ break
174
+ else
175
+ # Ignore other events
193
176
  end
194
177
  end
195
178
  ```
179
+ <!-- SYNC:END -->
196
180
 
197
181
  #### How it works
198
182
 
199
- 1. **`tui.layout_split` (`RatatuiRuby::Layout.split`)**: Takes an area (like `frame.area`) and splits it into multiple sub-areas based on constraints.
200
- 2. **`tui.constraint_*` (`RatatuiRuby::Constraint`)**: Defines how space is distributed (e.g., `percentage`, `length`, `min`, `max`).
183
+ 1. **`tui.layout_split` (`RatatuiRuby::Layout::Layout.split`)**: Takes an area (like `frame.area`) and splits it into multiple sub-areas based on constraints.
184
+ 2. **`tui.constraint_*` (`RatatuiRuby::Layout::Constraint`)**: Defines how space is distributed (e.g., `percentage`, `length`, `min`, `max`).
201
185
  3. **`Frame#render_widget(widget, rect)`**: You pass the specific area (like `top` or `bottom`) to render the widget into that exact region.
202
186
  4. **`tui.text_span` (`RatatuiRuby::Text::Span`)**: Allows for rich styling within a single line of text.
203
187
 
188
+ [![quickstart_layout](./images/verify_quickstart_layout.png)](../examples/verify_quickstart_layout/README.md)
189
+
204
190
  ## Examples
205
191
 
206
192
  These examples showcase the full power of **ratatui_ruby**. You can find their source code in the [examples directory](../examples).
207
193
 
208
- ### Sample Applications
209
-
210
- Full-featured examples demonstrating complex layouts and real-world TUI patterns.
211
-
212
-
213
-
214
- #### [All Events](../examples/app_all_events/app.rb)
215
-
216
- Handling terminal events is unpredictable. Developers need to know exactly what the terminal sends for `Ctrl+C` or a mouse drag.
217
-
218
- This app captures and visualizes every event—keys, mouse, resize, paste, and focus.
219
-
220
- Use it to debug your input handling or verify terminal behavior.
221
-
222
- **What you'll learn:**
223
-
224
- * **MVVM Architecture**: Separates logic (Model), state (ViewModel), and rendering (View) for clean, testable code.
225
- * **Event Handling**: Captures and distinguishes all input types, including modifiers (`Ctrl+C`) and focus changes.
226
- * **Scalable Structure**: Organizes a non-trivial application into small, focused classes instead of a monolithic script.
227
-
228
- ![all_events](./images/app_all_events.png)
229
-
230
- #### [Color Picker](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_color_picker/app.rb)
231
-
232
- Interactive tools require complex state. Mapping mouse clicks to widgets and handling modal dialogs creates messy code if handled in the main loop.
233
-
234
- This app implements a full Color Picker using a "Scene-Orchestrated" pattern. The Scene calculates layout and exposes cached rectangles for hit testing.
235
-
236
- Use it to build forms, editors, and mouse-driven tools.
237
-
238
- **What you'll learn:**
239
-
240
- * **Scene-Orchestrated MVC**: Separates the View (layout/rendering) from the Controller (event loop) and Model (business logic).
241
- * **Hit Testing**: Caches layout rectangles during the render pass to handle mouse clicks on specific elements.
242
- * **Modal Dialogs**: Implements overlay patterns that intercept input.
243
-
244
- #### [Custom Widget (Escape Hatch)](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_custom_widget/app.rb)
245
-
246
- Demonstrates how to define a custom widget in pure Ruby using the `render(area, buffer)` escape hatch for low-level drawing.
247
-
248
- ![custom_widget](./images/app_custom_widget.png)
249
-
250
- #### [Layout Split Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/widget_layout_split/app.rb)
194
+ ### Widget Demos
251
195
 
252
- Demonstrates `Layout.split` with interactive attribute cycling. Features hotkey controls For direction (vertical/horizontal), all 7 flex modes (legacy, start, center, end, space_between, space_around, space_evenly), and constraint types (fill, length, percentage, min, ratio).
196
+ Focused examples for individual widgets. Each demonstrates a single widget and its configuration options.
197
+
198
+ | Widget | What it demonstrates |
199
+ |--------|---------------------|
200
+ | [Bar Chart](../examples/widget_barchart_demo/app.rb) | Grouped bars, data visualization, custom bar styling |
201
+ | [Block](../examples/widget_block_demo/app.rb) | Borders, titles, padding, nested widgets |
202
+ | [Box](../examples/widget_box_demo/app.rb) | Block + Paragraph composition, text wrapping |
203
+ | [Calendar](../examples/widget_calendar_demo/app.rb) | Date highlighting, month display, event markers |
204
+ | [Chart](../examples/widget_chart_demo/app.rb) | Line/scatter plots, axes, legends, datasets |
205
+ | [Gauge](../examples/widget_gauge_demo/app.rb) | Progress bars, percentage display, unicode blocks |
206
+ | [Layout Split](../examples/widget_layout_split/app.rb) | Constraint types, flex modes, responsive layouts |
207
+ | [Line Gauge](../examples/widget_line_gauge_demo/app.rb) | Horizontal progress, labels, thin-style gauges |
208
+ | [List](../examples/widget_list_demo/app.rb) | Selection, scrolling, highlight styles, rich text items |
209
+ | [Map](../examples/widget_map_demo/app.rb) | Canvas widget, world map rendering, coordinates |
210
+ | [Popup](../examples/widget_popup_demo/app.rb) | Clear widget, modal dialogs, overlay composition |
211
+ | [Ratatui Logo](../examples/widget_ratatui_logo_demo/app.rb) | Decorative branding widget |
212
+ | [Ratatui Mascot](../examples/widget_ratatui_mascot_demo/app.rb) | ASCII art Ferris mascot |
213
+ | [Rect](../examples/widget_rect/app.rb) | Geometry helpers, area calculations, contains/intersection |
214
+ | [Rich Text](../examples/widget_rich_text/app.rb) | Spans, lines, inline styling, mixed colors |
215
+ | [Scrollbar](../examples/widget_scrollbar_demo/app.rb) | Orientations, thumb/track styling, scroll state |
216
+ | [Scroll Text](../examples/widget_scroll_text/app.rb) | Paragraph scrolling, viewport control, long content |
217
+ | [Sparkline](../examples/widget_sparkline_demo/app.rb) | Mini charts, time series, bar sets |
218
+ | [Style Colors](../examples/widget_style_colors/app.rb) | Named colors, RGB, indexed 256-color palette |
219
+ | [Table](../examples/widget_table_demo/app.rb) | Row selection, column widths, per-cell styling |
220
+ | [Tabs](../examples/widget_tabs_demo/app.rb) | Tab navigation, highlighting, dividers |
221
+ | [Text Width](../examples/widget_text_width/app.rb) | Unicode-aware width measurement, CJK support |
222
+ | [Canvas](../examples/widget_canvas_demo/app.rb) | Drawing shapes, markers, custom graphics |
223
+ | [Cell](../examples/widget_cell_demo/app.rb) | Buffer cell inspection, styling attributes |
224
+ | [Center](../examples/widget_center_demo/app.rb) | Centering content, horizontal/vertical alignment |
225
+ | [Overlay](../examples/widget_overlay_demo/app.rb) | Layering widgets, modal backgrounds |
226
+ | [Custom Render](../examples/widget_render/app.rb) | Low-level Draw API, escape hatch for custom widgets |
253
227
 
254
- ![widget_layout_split](./images/widget_layout_split.png)
228
+ ### Sample Applications
255
229
 
256
- #### [Login Form](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_login_form/app.rb)
230
+ These larger examples combine widgets into complete applications, demonstrating real-world TUI patterns and architectures.
257
231
 
258
- Shows how to use `Overlay`, `Center`, and `Cursor` to build a modal login form with text input.
232
+ | Application | Architecture | What you'll learn |
233
+ |-------------|--------------|-------------------|
234
+ | [All Events](../examples/app_all_events/app.rb) | Model-View-Update | Event handling, unidirectional data flow, scalable structure |
235
+ | [Color Picker](../examples/app_color_picker/app.rb) | Component-Based | Hit testing, modal dialogs, encapsulated state |
236
+ | [Login Form](../examples/app_login_form/app.rb) | Overlay + Center | Modal forms, cursor positioning, text input |
237
+ | [Stateful Interaction](../examples/app_stateful_interaction/app.rb) | State Objects | ListState/TableState, offset read-back, mouse click-to-row |
259
238
 
260
- ![login_form](./images/app_login_form.png)
239
+ #### All Events
261
240
 
262
- #### [Map Demo](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_map_demo/app.rb)
241
+ [![all_events](./images/app_all_events.png)](../examples/app_all_events/README.md)
263
242
 
264
- Exhibits the `Canvas` widget's power, rendering a world map with city labels, animated circles, and lines.
243
+ #### Color Picker
265
244
 
266
- ![map_demo](./images/app_map_demo.png)
245
+ [![color_picker](./images/app_color_picker.png)](../examples/app_color_picker/README.md)
267
246
 
268
- #### [Table Select](https://git.sr.ht/~kerrick/ratatui_ruby/tree/main/item/examples/app_table_select/app.rb)
247
+ #### Login Form
269
248
 
270
- Demonstrates interactive row selection in the `Table` widget with keyboard navigation, highlighting selected rows with custom styles and symbols, applying a base style, and dynamically adjusting `column_spacing`. Also demonstrates `column_highlight_style` and the new `cell_highlight_style` for precise selection visualization.
249
+ [![login_form](./images/app_login_form.png)](../examples/app_login_form/README.md)
271
250
 
272
- ![table_select](./images/app_table_select.png)
273
251
 
252
+ ## Next Steps
274
253
 
275
- ### Widget Demos
254
+ Now that you've seen what **ratatui_ruby** can do:
276
255
 
277
- These smaller, focused examples demonstrate specific widgets and their configuration options.
278
-
279
- * [Bar Chart](../examples/widget_barchart_demo/app.rb)
280
- * [Block Padding](../examples/widget_block_padding/app.rb)
281
- * [Block Titles](../examples/widget_block_titles/app.rb)
282
- * [Box (Block/Paragraph)](../examples/widget_box_demo/app.rb)
283
- * [Calendar](../examples/widget_calendar_demo/app.rb)
284
- * [Chart](../examples/widget_chart_demo/app.rb)
285
- * [Gauge](../examples/widget_gauge_demo/app.rb)
286
- * [Line Gauge](../examples/widget_line_gauge_demo/app.rb)
287
- * [List](../examples/widget_list_demo/app.rb)
288
- * [Popup (Clear)](../examples/widget_popup_demo/app.rb)
289
- * [Rect](../examples/widget_rect/app.rb)
290
- * [Ratatui Logo](../examples/widget_ratatui_logo_demo/app.rb)
291
- * [Ratatui Mascot](../examples/widget_ratatui_mascot_demo/app.rb)
292
- * [Rich Text](../examples/widget_rich_text/app.rb)
293
- * [Scrollbar](../examples/widget_scrollbar_demo/app.rb)
294
- * [Scroll Text](../examples/widget_scroll_text/app.rb)
295
- * [Sparkline](../examples/widget_sparkline_demo/app.rb)
296
- * [Table Flex](../examples/widget_table_flex/app.rb)
297
- * [Tabs](../examples/widget_tabs_demo/app.rb)
298
- * [Widget Style Colors](../examples/widget_style_colors/app.rb)
256
+ - **Deep dive**: Read the [Application Architecture](./application_architecture.md) guide for scaling patterns
257
+ - **Test your TUI**: See the [Testing Guide](./application_testing.md) for snapshot and style assertions
258
+ - **Explore the API**: Browse the [full RDoc documentation](./index.md)
259
+ - **Learn the philosophy**: Read [Why RatatuiRuby?](./why.md) for comparisons and design decisions
260
+ - **Get help**: Join the [discussion mailing list](https://lists.sr.ht/~kerrick/ratatui_ruby-discuss)
@@ -0,0 +1,92 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
+ SPDX-License-Identifier: CC-BY-SA-4.0
4
+ -->
5
+
6
+ # Terminal Limitations
7
+
8
+ Some behaviors are outside the control of `ratatui_ruby`. This document explains common pitfalls that affect your application or your users, but cannot be fixed in the library.
9
+
10
+ ## Keyboard Event Interception
11
+
12
+ ### The Problem
13
+
14
+ Your application receives a key event, but the modifier flags are missing. You pressed Ctrl+PageUp, but the event shows `code="page_up"` with `modifiers=[]`.
15
+
16
+ ### The Cause
17
+
18
+ Terminal emulators intercept certain key combinations for their own features. The key press never reaches your application—the terminal consumes it first.
19
+
20
+ Common culprits on macOS:
21
+
22
+ | Key Combination | Terminal Behavior |
23
+ |---------------------|--------------------------------------|
24
+ | Ctrl+PageUp/Down | Switch tabs (Terminal.app, iTerm2) |
25
+ | Ctrl+Tab | Switch tabs |
26
+ | Cmd+T / Cmd+N | New tab / New window |
27
+ | Cmd+C / Cmd+V | Copy / Paste (not Ctrl) |
28
+
29
+ Linux terminals vary widely. Windows Terminal and ConEmu have their own defaults.
30
+
31
+ ### The Solution
32
+
33
+ 1. **Test with different terminals.** Kitty, WezTerm, and Alacritty pass more key combinations through to applications by default. If a key works in Kitty but not Terminal.app, the terminal is the issue.
34
+
35
+ 2. **Reconfigure your terminal.** Most terminal emulators let you unbind or remap default shortcuts in their settings.
36
+
37
+ 3. **Use alternative key bindings.** If your users will run your application in various terminals, design your keybindings to avoid commonly intercepted combinations:
38
+ - Use Alt+PageUp instead of Ctrl+PageUp
39
+ - Use Ctrl+J/K instead of Ctrl+Up/Down
40
+ - Avoid Ctrl+Tab entirely
41
+
42
+ 4. **Document requirements.** If your application depends on specific key combinations, document the terminal requirements for your users.
43
+
44
+ ### Enhanced Keyboard Protocol
45
+
46
+ Some terminals support the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/), which provides unambiguous key event reporting including:
47
+
48
+ - Individual modifier key events (LeftShift vs RightShift)
49
+ - Media keys (Play, Pause, Volume controls)
50
+ - Repeat and release events
51
+
52
+ Terminals with full protocol support:
53
+ - Kitty
54
+ - WezTerm
55
+ - Foot
56
+ - Alacritty (partial)
57
+
58
+ Standard terminals (Terminal.app, iTerm2, GNOME Terminal) do not support the enhanced protocol.
59
+
60
+ **RatatuiRuby Status:** The underlying library (crossterm) supports this protocol, but RatatuiRuby does not yet expose a way to enable it. The key code mappings for media keys and individual modifier keys exist, but they will only be received from terminals that enable the protocol by default. This is planned for a future release.
61
+
62
+ ## Mouse Event Limitations
63
+
64
+ ### The Problem
65
+
66
+ Mouse events work in some terminals but not others. Or they work, but only up to certain coordinates.
67
+
68
+ ### The Cause
69
+
70
+ Mouse reporting requires terminal escape sequence support. Older terminals may not support:
71
+
72
+ - SGR mouse mode (coordinates > 223)
73
+ - Mouse motion tracking
74
+ - Button-event tracking
75
+
76
+ ### The Solution
77
+
78
+ Ensure your terminal supports modern mouse modes. Most actively maintained terminals do. If running in a legacy environment, test mouse functionality and provide keyboard alternatives.
79
+
80
+ ## Focus Events
81
+
82
+ ### The Problem
83
+
84
+ `Event::FocusGained` and `Event::FocusLost` are never received.
85
+
86
+ ### The Cause
87
+
88
+ Focus event reporting requires explicit terminal support and configuration. Some terminals don't support it at all.
89
+
90
+ ### The Solution
91
+
92
+ Don't rely on focus events for critical functionality. Treat them as nice-to-have enhancements. If your application shows stale data when the user returns, periodically refresh instead of waiting for focus events.