ratatui_ruby 0.7.0 → 0.7.2

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 (284) 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 +8 -1
  7. data/CHANGELOG.md +34 -0
  8. data/README.md +5 -5
  9. data/Rakefile +1 -1
  10. data/doc/{application_architecture.md → concepts/application_architecture.md} +30 -0
  11. data/doc/concepts/async.md +160 -0
  12. data/doc/{event_handling.md → concepts/event_handling.md} +1 -1
  13. data/doc/contributors/auditing/parity.md +233 -0
  14. data/doc/contributors/developing_examples.md +3 -3
  15. data/doc/contributors/v1.0.0_blockers.md +8 -8
  16. data/doc/{quickstart.md → getting_started/quickstart.md} +26 -26
  17. data/doc/{why.md → getting_started/why.md} +1 -1
  18. data/doc/index.md +23 -9
  19. data/doc/troubleshooting/debugging.md +71 -0
  20. data/doc/{terminal_limitations.md → troubleshooting/terminal_limitations.md} +33 -0
  21. data/examples/app_all_events/README.md +1 -0
  22. data/examples/app_all_events/app.rb +2 -0
  23. data/examples/app_all_events/model/app_model.rb +2 -0
  24. data/examples/app_all_events/model/event_color_cycle.rb +2 -0
  25. data/examples/app_all_events/model/event_entry.rb +2 -0
  26. data/examples/app_all_events/model/msg.rb +2 -0
  27. data/examples/app_all_events/model/timestamp.rb +2 -0
  28. data/examples/app_all_events/update.rb +2 -0
  29. data/examples/app_all_events/view/app_view.rb +2 -0
  30. data/examples/app_all_events/view/controls_view.rb +2 -0
  31. data/examples/app_all_events/view/counts_view.rb +2 -0
  32. data/examples/app_all_events/view/live_view.rb +2 -0
  33. data/examples/app_all_events/view/log_view.rb +2 -0
  34. data/examples/app_all_events/view.rb +2 -0
  35. data/examples/app_color_picker/README.md +2 -0
  36. data/examples/app_color_picker/app.rb +2 -0
  37. data/examples/app_color_picker/clipboard.rb +2 -0
  38. data/examples/app_color_picker/color.rb +2 -0
  39. data/examples/app_color_picker/controls.rb +2 -0
  40. data/examples/app_color_picker/copy_dialog.rb +2 -0
  41. data/examples/app_color_picker/export_pane.rb +2 -0
  42. data/examples/app_color_picker/harmony.rb +2 -0
  43. data/examples/app_color_picker/input.rb +2 -0
  44. data/examples/app_color_picker/main_container.rb +2 -0
  45. data/examples/app_color_picker/palette.rb +2 -0
  46. data/examples/app_login_form/README.md +3 -0
  47. data/examples/app_login_form/app.rb +2 -0
  48. data/examples/app_stateful_interaction/README.md +2 -0
  49. data/examples/app_stateful_interaction/app.rb +2 -0
  50. data/examples/timeout_demo.rb +2 -0
  51. data/examples/verify_quickstart_dsl/README.md +2 -2
  52. data/examples/verify_quickstart_dsl/app.rb +2 -0
  53. data/examples/verify_quickstart_layout/README.md +2 -2
  54. data/examples/verify_quickstart_layout/app.rb +2 -0
  55. data/examples/verify_quickstart_lifecycle/README.md +2 -2
  56. data/examples/verify_quickstart_lifecycle/app.rb +2 -0
  57. data/examples/verify_readme_usage/app.rb +2 -0
  58. data/examples/{widget_barchart_demo → widget_barchart}/README.md +5 -3
  59. data/examples/{widget_barchart_demo → widget_barchart}/app.rb +7 -5
  60. data/examples/{widget_block_demo → widget_block}/README.md +5 -3
  61. data/examples/{widget_block_demo → widget_block}/app.rb +6 -4
  62. data/examples/{widget_box_demo → widget_box}/README.md +7 -4
  63. data/examples/{widget_box_demo → widget_box}/app.rb +7 -5
  64. data/examples/{widget_calendar_demo → widget_calendar}/README.md +6 -3
  65. data/examples/{widget_calendar_demo → widget_calendar}/app.rb +6 -4
  66. data/examples/{widget_canvas_demo → widget_canvas}/README.md +2 -2
  67. data/examples/{widget_canvas_demo → widget_canvas}/app.rb +6 -4
  68. data/examples/{widget_cell_demo → widget_cell}/README.md +6 -3
  69. data/examples/{widget_cell_demo → widget_cell}/app.rb +7 -5
  70. data/examples/{widget_center_demo → widget_center}/README.md +2 -2
  71. data/examples/{widget_center_demo → widget_center}/app.rb +6 -4
  72. data/examples/{widget_chart_demo → widget_chart}/README.md +7 -4
  73. data/examples/{widget_chart_demo → widget_chart}/app.rb +7 -5
  74. data/examples/{widget_gauge_demo → widget_gauge}/README.md +6 -3
  75. data/examples/{widget_gauge_demo → widget_gauge}/app.rb +7 -5
  76. data/examples/widget_layout_split/README.md +5 -2
  77. data/examples/widget_layout_split/app.rb +3 -1
  78. data/examples/{widget_line_gauge_demo → widget_line_gauge}/README.md +6 -3
  79. data/examples/{widget_line_gauge_demo → widget_line_gauge}/app.rb +7 -5
  80. data/examples/{widget_list_demo → widget_list}/README.md +7 -4
  81. data/examples/{widget_list_demo → widget_list}/app.rb +7 -5
  82. data/examples/{widget_map_demo → widget_map}/README.md +7 -4
  83. data/examples/{widget_map_demo → widget_map}/app.rb +4 -2
  84. data/examples/{widget_overlay_demo → widget_overlay}/README.md +6 -3
  85. data/examples/{widget_overlay_demo → widget_overlay}/app.rb +5 -3
  86. data/examples/{widget_popup_demo → widget_popup}/README.md +7 -4
  87. data/examples/{widget_popup_demo → widget_popup}/app.rb +6 -4
  88. data/examples/{widget_ratatui_logo_demo → widget_ratatui_logo}/README.md +6 -3
  89. data/examples/{widget_ratatui_logo_demo → widget_ratatui_logo}/app.rb +8 -6
  90. data/examples/{widget_ratatui_mascot_demo → widget_ratatui_mascot}/README.md +6 -3
  91. data/examples/{widget_ratatui_mascot_demo → widget_ratatui_mascot}/app.rb +6 -4
  92. data/examples/widget_rect/README.md +5 -2
  93. data/examples/widget_rect/app.rb +2 -0
  94. data/examples/widget_render/README.md +4 -1
  95. data/examples/widget_render/app.rb +2 -0
  96. data/examples/widget_rich_text/README.md +4 -1
  97. data/examples/widget_rich_text/app.rb +2 -0
  98. data/examples/widget_scroll_text/README.md +4 -1
  99. data/examples/widget_scroll_text/app.rb +3 -1
  100. data/examples/{widget_scrollbar_demo → widget_scrollbar}/README.md +7 -4
  101. data/examples/{widget_scrollbar_demo → widget_scrollbar}/app.rb +6 -4
  102. data/examples/{widget_sparkline_demo → widget_sparkline}/README.md +6 -3
  103. data/examples/{widget_sparkline_demo → widget_sparkline}/app.rb +7 -5
  104. data/examples/widget_style_colors/README.md +4 -1
  105. data/examples/widget_style_colors/app.rb +2 -0
  106. data/examples/{widget_table_demo → widget_table}/README.md +7 -4
  107. data/examples/{widget_table_demo → widget_table}/app.rb +4 -2
  108. data/examples/{widget_tabs_demo → widget_tabs}/README.md +6 -3
  109. data/examples/{widget_tabs_demo → widget_tabs}/app.rb +7 -5
  110. data/examples/widget_text_width/README.md +5 -2
  111. data/examples/widget_text_width/app.rb +2 -0
  112. data/exe/.gitkeep +0 -0
  113. data/ext/ratatui_ruby/Cargo.lock +1 -1
  114. data/ext/ratatui_ruby/Cargo.toml +1 -1
  115. data/ext/ratatui_ruby/extconf.rb +2 -0
  116. data/ext/ratatui_ruby/src/style.rs +25 -9
  117. data/ext/ratatui_ruby/src/widgets/barchart.rs +8 -6
  118. data/ext/ratatui_ruby/src/widgets/chart.rs +26 -4
  119. data/ext/ratatui_ruby/src/widgets/table.rs +13 -5
  120. data/ext/ratatui_ruby/src/widgets/tabs.rs +49 -9
  121. data/lib/ratatui_ruby/buffer/cell.rb +2 -0
  122. data/lib/ratatui_ruby/buffer.rb +2 -0
  123. data/lib/ratatui_ruby/cell.rb +2 -0
  124. data/lib/ratatui_ruby/event/focus_gained.rb +2 -0
  125. data/lib/ratatui_ruby/event/focus_lost.rb +2 -0
  126. data/lib/ratatui_ruby/event/key/character.rb +2 -0
  127. data/lib/ratatui_ruby/event/key/media.rb +2 -0
  128. data/lib/ratatui_ruby/event/key/modifier.rb +2 -0
  129. data/lib/ratatui_ruby/event/key/navigation.rb +2 -0
  130. data/lib/ratatui_ruby/event/key/system.rb +2 -0
  131. data/lib/ratatui_ruby/event/key.rb +2 -0
  132. data/lib/ratatui_ruby/event/mouse.rb +2 -0
  133. data/lib/ratatui_ruby/event/none.rb +2 -0
  134. data/lib/ratatui_ruby/event/paste.rb +2 -0
  135. data/lib/ratatui_ruby/event/resize.rb +2 -0
  136. data/lib/ratatui_ruby/event.rb +2 -0
  137. data/lib/ratatui_ruby/frame.rb +2 -0
  138. data/lib/ratatui_ruby/layout/constraint.rb +2 -0
  139. data/lib/ratatui_ruby/layout/layout.rb +2 -0
  140. data/lib/ratatui_ruby/layout/rect.rb +2 -0
  141. data/lib/ratatui_ruby/layout.rb +2 -0
  142. data/lib/ratatui_ruby/list_state.rb +2 -0
  143. data/lib/ratatui_ruby/schema/bar_chart/bar.rb +2 -0
  144. data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +2 -0
  145. data/lib/ratatui_ruby/schema/bar_chart.rb +4 -2
  146. data/lib/ratatui_ruby/schema/block.rb +4 -2
  147. data/lib/ratatui_ruby/schema/calendar.rb +4 -2
  148. data/lib/ratatui_ruby/schema/canvas.rb +2 -0
  149. data/lib/ratatui_ruby/schema/center.rb +2 -0
  150. data/lib/ratatui_ruby/schema/chart.rb +4 -2
  151. data/lib/ratatui_ruby/schema/clear.rb +2 -0
  152. data/lib/ratatui_ruby/schema/constraint.rb +2 -0
  153. data/lib/ratatui_ruby/schema/cursor.rb +2 -0
  154. data/lib/ratatui_ruby/schema/draw.rb +2 -0
  155. data/lib/ratatui_ruby/schema/gauge.rb +4 -2
  156. data/lib/ratatui_ruby/schema/layout.rb +2 -0
  157. data/lib/ratatui_ruby/schema/line_gauge.rb +4 -2
  158. data/lib/ratatui_ruby/schema/list.rb +3 -1
  159. data/lib/ratatui_ruby/schema/list_item.rb +2 -0
  160. data/lib/ratatui_ruby/schema/overlay.rb +2 -0
  161. data/lib/ratatui_ruby/schema/paragraph.rb +2 -0
  162. data/lib/ratatui_ruby/schema/ratatui_logo.rb +4 -2
  163. data/lib/ratatui_ruby/schema/ratatui_mascot.rb +4 -2
  164. data/lib/ratatui_ruby/schema/rect.rb +2 -0
  165. data/lib/ratatui_ruby/schema/row.rb +2 -0
  166. data/lib/ratatui_ruby/schema/scrollbar.rb +4 -2
  167. data/lib/ratatui_ruby/schema/shape/label.rb +2 -0
  168. data/lib/ratatui_ruby/schema/sparkline.rb +4 -2
  169. data/lib/ratatui_ruby/schema/style.rb +2 -0
  170. data/lib/ratatui_ruby/schema/table.rb +2 -0
  171. data/lib/ratatui_ruby/schema/tabs.rb +4 -2
  172. data/lib/ratatui_ruby/schema/text.rb +2 -0
  173. data/lib/ratatui_ruby/scrollbar_state.rb +2 -0
  174. data/lib/ratatui_ruby/style/style.rb +2 -0
  175. data/lib/ratatui_ruby/style.rb +2 -0
  176. data/lib/ratatui_ruby/table_state.rb +2 -0
  177. data/lib/ratatui_ruby/test_helper/event_injection.rb +2 -0
  178. data/lib/ratatui_ruby/test_helper/snapshot.rb +2 -0
  179. data/lib/ratatui_ruby/test_helper/style_assertions.rb +2 -0
  180. data/lib/ratatui_ruby/test_helper/terminal.rb +2 -0
  181. data/lib/ratatui_ruby/test_helper/test_doubles.rb +2 -0
  182. data/lib/ratatui_ruby/test_helper.rb +5 -3
  183. data/lib/ratatui_ruby/tui/buffer_factories.rb +2 -0
  184. data/lib/ratatui_ruby/tui/canvas_factories.rb +2 -0
  185. data/lib/ratatui_ruby/tui/core.rb +2 -0
  186. data/lib/ratatui_ruby/tui/layout_factories.rb +2 -0
  187. data/lib/ratatui_ruby/tui/state_factories.rb +2 -0
  188. data/lib/ratatui_ruby/tui/style_factories.rb +2 -0
  189. data/lib/ratatui_ruby/tui/text_factories.rb +2 -0
  190. data/lib/ratatui_ruby/tui/widget_factories.rb +2 -0
  191. data/lib/ratatui_ruby/tui.rb +2 -0
  192. data/lib/ratatui_ruby/version.rb +3 -1
  193. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -0
  194. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -0
  195. data/lib/ratatui_ruby/widgets/bar_chart.rb +4 -2
  196. data/lib/ratatui_ruby/widgets/block.rb +4 -2
  197. data/lib/ratatui_ruby/widgets/calendar.rb +4 -2
  198. data/lib/ratatui_ruby/widgets/canvas.rb +2 -0
  199. data/lib/ratatui_ruby/widgets/cell.rb +2 -0
  200. data/lib/ratatui_ruby/widgets/center.rb +2 -0
  201. data/lib/ratatui_ruby/widgets/chart.rb +4 -2
  202. data/lib/ratatui_ruby/widgets/clear.rb +2 -0
  203. data/lib/ratatui_ruby/widgets/cursor.rb +2 -0
  204. data/lib/ratatui_ruby/widgets/gauge.rb +4 -2
  205. data/lib/ratatui_ruby/widgets/line_gauge.rb +4 -2
  206. data/lib/ratatui_ruby/widgets/list.rb +3 -1
  207. data/lib/ratatui_ruby/widgets/list_item.rb +2 -0
  208. data/lib/ratatui_ruby/widgets/overlay.rb +2 -0
  209. data/lib/ratatui_ruby/widgets/paragraph.rb +2 -0
  210. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +4 -2
  211. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +4 -2
  212. data/lib/ratatui_ruby/widgets/row.rb +2 -0
  213. data/lib/ratatui_ruby/widgets/scrollbar.rb +4 -2
  214. data/lib/ratatui_ruby/widgets/shape/label.rb +2 -0
  215. data/lib/ratatui_ruby/widgets/sparkline.rb +4 -2
  216. data/lib/ratatui_ruby/widgets/table.rb +2 -0
  217. data/lib/ratatui_ruby/widgets/tabs.rb +12 -8
  218. data/lib/ratatui_ruby/widgets.rb +2 -0
  219. data/lib/ratatui_ruby.rb +2 -0
  220. data/tasks/autodoc/examples.rb +2 -0
  221. data/tasks/autodoc/member.rb +2 -0
  222. data/tasks/autodoc/name.rb +2 -0
  223. data/tasks/autodoc.rake +2 -0
  224. data/tasks/bump/cargo_lockfile.rb +2 -0
  225. data/tasks/bump/changelog.rb +10 -0
  226. data/tasks/bump/header.rb +2 -0
  227. data/tasks/bump/history.rb +2 -0
  228. data/tasks/bump/links.rb +2 -0
  229. data/tasks/bump/manifest.rb +2 -0
  230. data/tasks/bump/ruby_gem.rb +14 -0
  231. data/tasks/bump/sem_ver.rb +2 -0
  232. data/tasks/bump/unreleased_section.rb +18 -0
  233. data/tasks/bump.rake +2 -0
  234. data/tasks/doc.rake +268 -0
  235. data/tasks/extension.rake +2 -0
  236. data/tasks/lint.rake +115 -0
  237. data/tasks/rdoc_config.rb +18 -4
  238. data/tasks/sourcehut.rake +2 -0
  239. data/tasks/terminal_preview/app_screenshot.rb +2 -0
  240. data/tasks/terminal_preview/crash_report.rb +2 -0
  241. data/tasks/terminal_preview/example_app.rb +2 -0
  242. data/tasks/terminal_preview/launcher_script.rb +2 -0
  243. data/tasks/terminal_preview/preview_collection.rb +2 -0
  244. data/tasks/terminal_preview/preview_timing.rb +2 -0
  245. data/tasks/terminal_preview/safety_confirmation.rb +2 -0
  246. data/tasks/terminal_preview/saved_screenshot.rb +2 -0
  247. data/tasks/terminal_preview/system_appearance.rb +2 -0
  248. data/tasks/terminal_preview/terminal_window.rb +2 -0
  249. data/tasks/terminal_preview/window_id.rb +2 -0
  250. data/tasks/terminal_preview.rake +2 -0
  251. data/tasks/test.rake +2 -0
  252. data/tasks/website/index_page.rb +2 -0
  253. data/tasks/website/version.rb +12 -2
  254. data/tasks/website/version_menu.rb +2 -0
  255. data/tasks/website/versioned_documentation.rb +2 -0
  256. data/tasks/website/website.rb +2 -0
  257. data/tasks/website.rake +2 -0
  258. metadata +72 -72
  259. data/doc/contributors/architectural_overhaul/chat_conversations.md +0 -4952
  260. data/doc/contributors/architectural_overhaul/implementation_plan.md +0 -60
  261. data/doc/contributors/architectural_overhaul/task.md +0 -37
  262. /data/doc/{application_testing.md → concepts/application_testing.md} +0 -0
  263. /data/doc/{interactive_design.md → concepts/interactive_design.md} +0 -0
  264. /data/doc/images/{widget_barchart_demo.png → widget_barchart.png} +0 -0
  265. /data/doc/images/{widget_block_demo.png → widget_block.png} +0 -0
  266. /data/doc/images/{widget_box_demo.png → widget_box.png} +0 -0
  267. /data/doc/images/{widget_calendar_demo.png → widget_calendar.png} +0 -0
  268. /data/doc/images/{widget_canvas_demo.png → widget_canvas.png} +0 -0
  269. /data/doc/images/{widget_cell_demo.png → widget_cell.png} +0 -0
  270. /data/doc/images/{widget_center_demo.png → widget_center.png} +0 -0
  271. /data/doc/images/{widget_chart_demo.png → widget_chart.png} +0 -0
  272. /data/doc/images/{widget_gauge_demo.png → widget_gauge.png} +0 -0
  273. /data/doc/images/{widget_line_gauge_demo.png → widget_line_gauge.png} +0 -0
  274. /data/doc/images/{widget_list_demo.png → widget_list.png} +0 -0
  275. /data/doc/images/{widget_map_demo.png → widget_map.png} +0 -0
  276. /data/doc/images/{widget_overlay_demo.png → widget_overlay.png} +0 -0
  277. /data/doc/images/{widget_popup_demo.png → widget_popup.png} +0 -0
  278. /data/doc/images/{widget_ratatui_logo_demo.png → widget_ratatui_logo.png} +0 -0
  279. /data/doc/images/{widget_ratatui_mascot_demo.png → widget_ratatui_mascot.png} +0 -0
  280. /data/doc/images/{widget_scrollbar_demo.png → widget_scrollbar.png} +0 -0
  281. /data/doc/images/{widget_sparkline_demo.png → widget_sparkline.png} +0 -0
  282. /data/doc/images/{widget_table_demo.png → widget_table.png} +0 -0
  283. /data/doc/images/{widget_tabs_demo.png → widget_tabs.png} +0 -0
  284. /data/doc/{v0.7.0_migration.md → migration/v0_7_0.md} +0 -0
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
9
  require "ratatui_ruby"
@@ -3,9 +3,9 @@ SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
3
  SPDX-License-Identifier: CC-BY-SA-4.0
4
4
  -->
5
5
 
6
- # Table Widget Example
6
+ # Table (Row, Cell) Example
7
7
 
8
- [![widget_table_demo](../../doc/images/widget_table_demo.png)](app.rb)
8
+ [![widget_table](../../doc/images/widget_table.png)](app.rb)
9
9
 
10
10
  Demonstrates advanced options for the `Table` widget, including selection, row-level highlighting, and column-level highlighting.
11
11
 
@@ -37,12 +37,15 @@ Data grids are complex. Users expect to navigate them with keys, select rows, an
37
37
  ## Usage
38
38
 
39
39
  ```bash
40
- ruby examples/widget_table_demo/app.rb
40
+ ruby examples/widget_table/app.rb
41
41
  ```
42
42
 
43
43
  ## Learning Outcomes
44
44
 
45
45
  Use this example if you need to...
46
+
46
47
  - Build a file explorer or process list.
47
48
  - Create a data-heavy dashboard.
48
- - Handle conflicting style requirements (e.g., "Highlight this row, but make this error cell red").
49
+ - Handle conflicting style requirements (e.g., "Highlight this row, but make this error cell red").
50
+
51
+ [Read the source code →](app.rb)
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
9
  require "bundler/setup"
@@ -18,7 +20,7 @@ PROCESSES = [
18
20
  { pid: 6789, name: "node", cpu: 18.9 },
19
21
  ].freeze
20
22
 
21
- class WidgetTableDemo
23
+ class WidgetTable
22
24
  attr_reader :selected_index, :selected_col, :current_style_index, :column_spacing, :highlight_spacing, :column_highlight_style, :cell_highlight_style
23
25
 
24
26
  HIGHLIGHT_SPACINGS = [
@@ -250,5 +252,5 @@ class WidgetTableDemo
250
252
  end
251
253
 
252
254
  if __FILE__ == $0
253
- WidgetTableDemo.new.run
255
+ WidgetTable.new.run
254
256
  end
@@ -5,7 +5,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
5
5
 
6
6
  # Tabs Widget Example
7
7
 
8
- [![widget_tabs_demo](../../doc/images/widget_tabs_demo.png)](app.rb)
8
+ [![widget_tabs](../../doc/images/widget_tabs.png)](app.rb)
9
9
 
10
10
  Demonstrates view segregation with interactive navigation.
11
11
 
@@ -30,12 +30,15 @@ Screen real estate is limited. You cannot show everything at once. Tabs segregat
30
30
  ## Usage
31
31
 
32
32
  ```bash
33
- ruby examples/widget_tabs_demo/app.rb
33
+ ruby examples/widget_tabs/app.rb
34
34
  ```
35
35
 
36
36
  ## Learning Outcomes
37
37
 
38
38
  Use this example if you need to...
39
+
39
40
  - Build a multi-pane dashboard.
40
41
  - Create a "Settings" screen with different categories.
41
- - Implement a "wizard" interface with steps.
42
+ - Implement a "wizard" interface with steps.
43
+
44
+ [Read the source code →](app.rb)
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
9
  require "ratatui_ruby"
@@ -19,10 +21,10 @@ require "faker"
19
21
  #
20
22
  # Run the demo from the terminal:
21
23
  #
22
- # ruby examples/widget_tabs_demo/app.rb
24
+ # ruby examples/widget_tabs/app.rb
23
25
  #
24
- # rdoc-image:/doc/images/widget_tabs_demo.png
25
- class WidgetTabsDemo
26
+ # rdoc-image:/doc/images/widget_tabs.png
27
+ class WidgetTabs
26
28
  def initialize
27
29
  @selected_tab = 0
28
30
  @tabs = ["Revenue", "Traffic", "Errors", "Quarterly"]
@@ -93,7 +95,7 @@ class WidgetTabsDemo
93
95
  tabs = @tui.tabs(
94
96
  titles: @tabs,
95
97
  selected_index: @selected_tab,
96
- block: @tui.block(title: "Tabs Demo", borders: [:all]),
98
+ block: @tui.block(title: "Tabs", borders: [:all]),
97
99
  divider: @dividers[@divider_index],
98
100
  highlight_style: @highlight_styles[@highlight_style_index][:style],
99
101
  style: @base_styles[@base_style_index][:style],
@@ -178,4 +180,4 @@ class WidgetTabsDemo
178
180
  end
179
181
  end
180
182
 
181
- WidgetTabsDemo.new.run if __FILE__ == $0
183
+ WidgetTabs.new.run if __FILE__ == $0
@@ -3,7 +3,7 @@ SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
3
  SPDX-License-Identifier: CC-BY-SA-4.0
4
4
  -->
5
5
 
6
- # Text Width Calculator
6
+ # Text Width (Unicode Width) Calculator
7
7
 
8
8
  [![widget_text_width](../../doc/images/widget_text_width.png)](app.rb)
9
9
 
@@ -30,6 +30,9 @@ ruby examples/widget_text_width/app.rb
30
30
  ## Learning Outcomes
31
31
 
32
32
  Use this example if you need to...
33
+
33
34
  - Align text correctly in columns.
34
35
  - Truncate strings that are too long for a widget.
35
- - Build your own custom layout engine.
36
+ - Build your own custom layout engine.
37
+
38
+ [Read the source code →](app.rb)
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
7
9
  require "ratatui_ruby"
data/exe/.gitkeep CHANGED
File without changes
@@ -1012,7 +1012,7 @@ dependencies = [
1012
1012
 
1013
1013
  [[package]]
1014
1014
  name = "ratatui_ruby"
1015
- version = "0.7.0"
1015
+ version = "0.7.2"
1016
1016
  dependencies = [
1017
1017
  "bumpalo",
1018
1018
  "lazy_static",
@@ -3,7 +3,7 @@
3
3
 
4
4
  [package]
5
5
  name = "ratatui_ruby"
6
- version = "0.7.0"
6
+ version = "0.7.2"
7
7
  edition = "2021"
8
8
 
9
9
  [lib]
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  require "mkmf"
7
9
  require "rb_sys/mkmf"
@@ -12,6 +12,8 @@ use ratatui::{
12
12
  widgets::{Block, BorderType, Borders, Padding},
13
13
  };
14
14
 
15
+ use crate::text::parse_line;
16
+
15
17
  pub fn parse_color(color_str: &str) -> Option<Color> {
16
18
  // Try standard ratatui parsing first (named colors, indexed, etc.)
17
19
  if let Ok(color) = color_str.parse::<Color>() {
@@ -274,15 +276,22 @@ fn parse_titles(block_val: Value, mut block: Block<'_>) -> Result<Block<'_>, Err
274
276
  let index = isize::try_from(i)
275
277
  .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
276
278
  let title_item: Value = titles_array.entry(index)?;
277
- let mut content = String::new();
278
279
  let mut alignment = Alignment::Left;
279
280
  let mut is_bottom = false;
280
281
  let mut style = Style::default();
282
+ let mut line: Option<Line<'static>> = None;
281
283
 
282
284
  if let Some(hash) = magnus::RHash::from_value(title_item) {
283
285
  if let Ok(v) = hash.lookup::<_, Value>(ruby.to_symbol("content")) {
284
286
  if !v.is_nil() {
285
- content = v.funcall("to_s", ())?;
287
+ // First, try to parse as a Line object (preserves styling)
288
+ if let Ok(parsed_line) = parse_line(v) {
289
+ line = Some(parsed_line);
290
+ } else {
291
+ // Fallback to string
292
+ let content: String = v.funcall("to_s", ())?;
293
+ line = Some(Line::from(content));
294
+ }
286
295
  }
287
296
  }
288
297
  if let Ok(v) = hash.lookup::<_, Value>(ruby.to_symbol("alignment")) {
@@ -307,15 +316,22 @@ fn parse_titles(block_val: Value, mut block: Block<'_>) -> Result<Block<'_>, Err
307
316
  }
308
317
  }
309
318
  } else {
310
- content = title_item.funcall("to_s", ())?;
319
+ let content: String = title_item.funcall("to_s", ())?;
320
+ line = Some(Line::from(content));
311
321
  }
312
322
 
313
- let line = Line::from(content).alignment(alignment).style(style);
314
- block = if is_bottom {
315
- block.title_bottom(line)
316
- } else {
317
- block.title_top(line)
318
- };
323
+ if let Some(mut l) = line {
324
+ l = l.alignment(alignment);
325
+ // Only apply style if the line doesn't already have styled spans
326
+ if style != Style::default() {
327
+ l = l.style(style);
328
+ }
329
+ block = if is_bottom {
330
+ block.title_bottom(l)
331
+ } else {
332
+ block.title_top(l)
333
+ };
334
+ }
319
335
  }
320
336
  }
321
337
  }
@@ -48,12 +48,14 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
48
48
  let group_obj: Value = array.entry(index)?;
49
49
 
50
50
  let label_val: Value = group_obj.funcall("label", ())?;
51
- let label_str: String = if label_val.is_nil() {
52
- String::new()
51
+ let group_label: Line = if label_val.is_nil() {
52
+ Line::from("")
53
+ } else if let Ok(line) = parse_line(label_val) {
54
+ line
53
55
  } else {
54
- label_val.funcall("to_s", ())?
56
+ let label_str: String = label_val.funcall("to_s", ())?;
57
+ Line::from(label_str)
55
58
  };
56
- let label_ref = bump.alloc_str(&label_str) as &str;
57
59
 
58
60
  let bars_array: RArray = group_obj.funcall("bars", ())?;
59
61
  let mut bars: Vec<Bar> = Vec::new();
@@ -110,8 +112,8 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
110
112
  }
111
113
 
112
114
  let mut group = BarGroup::new(bars);
113
- if !label_ref.is_empty() {
114
- group = group.label(Line::from(label_ref));
115
+ if !group_label.spans.is_empty() {
116
+ group = group.label(group_label);
115
117
  }
116
118
  bar_chart = bar_chart.data(group);
117
119
  }
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
4
  use crate::style::{parse_block, parse_style};
5
+ use crate::text::parse_line;
5
6
  use bumpalo::Bump;
6
7
  use magnus::{prelude::*, Error, Symbol, Value};
7
8
  use ratatui::{
@@ -12,6 +13,7 @@ use ratatui::{
12
13
  Frame,
13
14
  };
14
15
 
16
+ #[allow(clippy::too_many_lines)]
15
17
  pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
16
18
  let bump = Bump::new();
17
19
  let ruby = magnus::Ruby::get().unwrap();
@@ -59,7 +61,13 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
59
61
  let index = isize::try_from(i)
60
62
  .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
61
63
  let ds_val: Value = datasets_val.entry(index)?;
62
- let name: String = ds_val.funcall("name", ())?;
64
+ let name_val: Value = ds_val.funcall("name", ())?;
65
+ let name = if let Ok(line) = parse_line(name_val) {
66
+ line
67
+ } else {
68
+ let name_str: String = name_val.funcall("to_s", ())?;
69
+ ratatui::text::Line::from(name_str)
70
+ };
63
71
  let marker_sym: Symbol = ds_val.funcall("marker", ())?;
64
72
  let graph_type_sym: Symbol = ds_val.funcall("graph_type", ())?;
65
73
 
@@ -132,7 +140,15 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
132
140
 
133
141
  fn parse_axis(axis_val: Value) -> Result<Axis<'static>, Error> {
134
142
  let ruby = magnus::Ruby::get().unwrap();
135
- let title: String = axis_val.funcall("title", ())?;
143
+ let title_val: Value = axis_val.funcall("title", ())?;
144
+ let title = if title_val.is_nil() {
145
+ ratatui::text::Line::from("")
146
+ } else if let Ok(line) = parse_line(title_val) {
147
+ line
148
+ } else {
149
+ let title_str: String = title_val.funcall("to_s", ())?;
150
+ ratatui::text::Line::from(title_str)
151
+ };
136
152
  let bounds_val: magnus::RArray = axis_val.funcall("bounds", ())?;
137
153
  let labels_val: magnus::RArray = axis_val.funcall("labels", ())?;
138
154
  let style_val: Value = axis_val.funcall("style", ())?;
@@ -144,8 +160,14 @@ fn parse_axis(axis_val: Value) -> Result<Axis<'static>, Error> {
144
160
  for i in 0..labels_val.len() {
145
161
  let index = isize::try_from(i)
146
162
  .map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
147
- let label: String = labels_val.entry(index)?;
148
- labels.push(Span::from(label));
163
+ let entry_val: Value = labels_val.entry(index)?;
164
+ let label = if let Ok(line) = parse_line(entry_val) {
165
+ line
166
+ } else {
167
+ let label_str: String = entry_val.funcall("to_s", ())?;
168
+ ratatui::text::Line::from(label_str)
169
+ };
170
+ labels.push(label);
149
171
  }
150
172
 
151
173
  let mut axis = Axis::default().title(title).bounds(bounds).labels(labels);
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
4
  use crate::style::{parse_block, parse_style};
5
- use crate::text::{parse_line, parse_span};
5
+ use crate::text::{parse_line, parse_span, parse_text};
6
6
  use crate::widgets::table_state::RubyTableState;
7
7
  use bumpalo::Bump;
8
8
  use magnus::{prelude::*, Error, Symbol, TryConvert, Value};
@@ -87,8 +87,12 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
87
87
  }
88
88
 
89
89
  if !highlight_symbol_val.is_nil() {
90
- let symbol: String = highlight_symbol_val.funcall("to_s", ())?;
91
- table = table.highlight_symbol(symbol);
90
+ if let Ok(text) = parse_text(highlight_symbol_val) {
91
+ table = table.highlight_symbol(ratatui::text::Text::from(text));
92
+ } else {
93
+ let symbol: String = highlight_symbol_val.funcall("to_s", ())?;
94
+ table = table.highlight_symbol(symbol);
95
+ }
92
96
  }
93
97
 
94
98
  let style_val: Value = node.funcall("style", ())?;
@@ -207,8 +211,12 @@ pub fn render_stateful(
207
211
  table = table.cell_highlight_style(parse_style(cell_highlight_style_val)?);
208
212
  }
209
213
  if !highlight_symbol_val.is_nil() {
210
- let symbol: String = highlight_symbol_val.funcall("to_s", ())?;
211
- table = table.highlight_symbol(symbol);
214
+ if let Ok(text) = parse_text(highlight_symbol_val) {
215
+ table = table.highlight_symbol(ratatui::text::Text::from(text));
216
+ } else {
217
+ let symbol: String = highlight_symbol_val.funcall("to_s", ())?;
218
+ table = table.highlight_symbol(symbol);
219
+ }
212
220
  }
213
221
  if !style_val.is_nil() {
214
222
  table = table.style(parse_style(style_val)?);
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: AGPL-3.0-or-later
3
3
 
4
4
  use crate::style::parse_block;
5
+ use crate::text::{parse_line, parse_span};
5
6
  use bumpalo::Bump;
6
7
  use magnus::{prelude::*, Error, Value};
7
8
  use ratatui::{layout::Rect, text::Line, widgets::Tabs, Frame};
@@ -13,7 +14,39 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
13
14
  Ok(())
14
15
  }
15
16
 
16
- use crate::text::parse_line;
17
+ /// Parses padding value with duck-typing support:
18
+ /// - Integer: generates that many spaces
19
+ /// - Line: uses styled Line directly
20
+ /// - Span: wraps in Line
21
+ /// - String or `to_s` responder: converts to Line
22
+ fn parse_padding(val: Value) -> Result<Line<'static>, Error> {
23
+ // Handle nil or zero
24
+ if val.is_nil() {
25
+ return Ok(Line::from(""));
26
+ }
27
+
28
+ // Try as Integer first (most common case)
29
+ if let Ok(n) = usize::try_convert(val) {
30
+ if n == 0 {
31
+ return Ok(Line::from(""));
32
+ }
33
+ return Ok(Line::from(" ".repeat(n)));
34
+ }
35
+
36
+ // Try to parse as Line
37
+ if let Ok(line) = parse_line(val) {
38
+ return Ok(line);
39
+ }
40
+
41
+ // Try to parse as Span (wrap in Line)
42
+ if let Ok(span) = parse_span(val) {
43
+ return Ok(Line::from(vec![span]));
44
+ }
45
+
46
+ // Fallback: call to_s and convert to Line
47
+ let s: String = val.funcall("to_s", ())?;
48
+ Ok(Line::from(s))
49
+ }
17
50
 
18
51
  fn create_tabs(node: Value, bump: &Bump) -> Result<Tabs<'_>, Error> {
19
52
  let ruby = magnus::Ruby::get().unwrap();
@@ -22,8 +55,8 @@ fn create_tabs(node: Value, bump: &Bump) -> Result<Tabs<'_>, Error> {
22
55
  let block_val: Value = node.funcall("block", ())?;
23
56
  let divider_val: Value = node.funcall("divider", ())?;
24
57
  let highlight_style_val: Value = node.funcall("highlight_style", ())?;
25
- let padding_left: usize = node.funcall("padding_left", ())?;
26
- let padding_right: usize = node.funcall("padding_right", ())?;
58
+ let padding_left_val: Value = node.funcall("padding_left", ())?;
59
+ let padding_right_val: Value = node.funcall("padding_right", ())?;
27
60
 
28
61
  let titles_array = magnus::RArray::from_value(titles_val)
29
62
  .ok_or_else(|| Error::new(ruby.exception_type_error(), "expected array for titles"))?;
@@ -44,8 +77,12 @@ fn create_tabs(node: Value, bump: &Bump) -> Result<Tabs<'_>, Error> {
44
77
  let mut tabs = Tabs::new(titles).select(selected_index);
45
78
 
46
79
  if !divider_val.is_nil() {
47
- let divider: String = divider_val.funcall("to_s", ())?;
48
- tabs = tabs.divider(divider);
80
+ if let Ok(span) = parse_span(divider_val) {
81
+ tabs = tabs.divider(span);
82
+ } else {
83
+ let divider: String = divider_val.funcall("to_s", ())?;
84
+ tabs = tabs.divider(divider);
85
+ }
49
86
  }
50
87
 
51
88
  if !highlight_style_val.is_nil() {
@@ -62,10 +99,11 @@ fn create_tabs(node: Value, bump: &Bump) -> Result<Tabs<'_>, Error> {
62
99
  tabs = tabs.block(parse_block(block_val, bump)?);
63
100
  }
64
101
 
65
- if padding_left > 0 || padding_right > 0 {
66
- let left_str = " ".repeat(padding_left);
67
- let right_str = " ".repeat(padding_right);
68
- tabs = tabs.padding(left_str, right_str);
102
+ // Handle duck-typed padding: Integer (spaces), String, Line, or anything with to_s
103
+ let left_padding = parse_padding(padding_left_val)?;
104
+ let right_padding = parse_padding(padding_right_val)?;
105
+ if !left_padding.spans.is_empty() || !right_padding.spans.is_empty() {
106
+ tabs = tabs.padding(left_padding, right_padding);
69
107
  }
70
108
 
71
109
  Ok(tabs)
@@ -101,6 +139,8 @@ pub fn width(node: Value) -> Result<usize, Error> {
101
139
  if titles_count > 1 {
102
140
  let divider_width = if divider_val.is_nil() {
103
141
  1 // Default divider is "|"
142
+ } else if let Ok(span) = parse_span(divider_val) {
143
+ span.width()
104
144
  } else {
105
145
  let d: String = divider_val.funcall("to_s", ())?;
106
146
  ratatui::text::Span::raw(d).width()
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  module Buffer
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  # Buffer primitives for terminal cell inspection.
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  # Represents a single cell in the terminal buffer.
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  require_relative "key/character"
7
9
  require_relative "key/media"
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ #--
3
4
  # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
4
5
  # SPDX-License-Identifier: AGPL-3.0-or-later
6
+ #++
5
7
 
6
8
  module RatatuiRuby
7
9
  class Event