ratatui_ruby 1.3.0 → 1.3.3

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 (301) hide show
  1. checksums.yaml +4 -4
  2. data/ext/ratatui_ruby/Cargo.lock +2 -1
  3. data/ext/ratatui_ruby/Cargo.toml +2 -1
  4. data/ext/ratatui_ruby/src/color.rs +1 -1
  5. data/ext/ratatui_ruby/src/errors.rs +1 -1
  6. data/ext/ratatui_ruby/src/events.rs +158 -19
  7. data/ext/ratatui_ruby/src/frame.rs +1 -1
  8. data/ext/ratatui_ruby/src/lib.rs +1 -1
  9. data/ext/ratatui_ruby/src/lib_header.rs +1 -1
  10. data/ext/ratatui_ruby/src/rendering.rs +1 -1
  11. data/ext/ratatui_ruby/src/string_width.rs +1 -1
  12. data/ext/ratatui_ruby/src/style.rs +1 -1
  13. data/ext/ratatui_ruby/src/terminal/capabilities.rs +1 -1
  14. data/ext/ratatui_ruby/src/terminal/init.rs +1 -1
  15. data/ext/ratatui_ruby/src/terminal/mod.rs +1 -1
  16. data/ext/ratatui_ruby/src/terminal/mutations.rs +1 -1
  17. data/ext/ratatui_ruby/src/terminal/queries.rs +1 -1
  18. data/ext/ratatui_ruby/src/terminal/query.rs +1 -1
  19. data/ext/ratatui_ruby/src/terminal/storage.rs +1 -1
  20. data/ext/ratatui_ruby/src/terminal/wrapper.rs +1 -1
  21. data/ext/ratatui_ruby/src/text.rs +1 -1
  22. data/ext/ratatui_ruby/src/widgets/barchart.rs +1 -1
  23. data/ext/ratatui_ruby/src/widgets/block.rs +1 -1
  24. data/ext/ratatui_ruby/src/widgets/calendar.rs +1 -1
  25. data/ext/ratatui_ruby/src/widgets/canvas.rs +1 -1
  26. data/ext/ratatui_ruby/src/widgets/center.rs +1 -1
  27. data/ext/ratatui_ruby/src/widgets/chart.rs +1 -1
  28. data/ext/ratatui_ruby/src/widgets/clear.rs +1 -1
  29. data/ext/ratatui_ruby/src/widgets/cursor.rs +1 -1
  30. data/ext/ratatui_ruby/src/widgets/gauge.rs +1 -1
  31. data/ext/ratatui_ruby/src/widgets/layout.rs +1 -1
  32. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +1 -1
  33. data/ext/ratatui_ruby/src/widgets/list.rs +1 -1
  34. data/ext/ratatui_ruby/src/widgets/list_state.rs +1 -1
  35. data/ext/ratatui_ruby/src/widgets/mod.rs +1 -1
  36. data/ext/ratatui_ruby/src/widgets/overlay.rs +1 -1
  37. data/ext/ratatui_ruby/src/widgets/paragraph.rs +1 -1
  38. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +1 -1
  39. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +1 -1
  40. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +1 -1
  41. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +1 -1
  42. data/ext/ratatui_ruby/src/widgets/sparkline.rs +1 -1
  43. data/ext/ratatui_ruby/src/widgets/table.rs +1 -1
  44. data/ext/ratatui_ruby/src/widgets/table_state.rs +1 -1
  45. data/ext/ratatui_ruby/src/widgets/tabs.rs +1 -1
  46. data/lib/ratatui_ruby/version.rb +1 -1
  47. metadata +1 -255
  48. data/.builds/ruby-3.2.yml +0 -54
  49. data/.builds/ruby-3.3.yml +0 -54
  50. data/.builds/ruby-3.4.yml +0 -54
  51. data/.builds/ruby-4.0.0.yml +0 -54
  52. data/.pre-commit-config.yaml +0 -16
  53. data/.rubocop.yml +0 -10
  54. data/AGENTS.md +0 -147
  55. data/CHANGELOG.md +0 -771
  56. data/README.md +0 -187
  57. data/README.rdoc +0 -302
  58. data/Rakefile +0 -11
  59. data/Steepfile +0 -50
  60. data/doc/concepts/application_architecture.md +0 -321
  61. data/doc/concepts/application_testing.md +0 -193
  62. data/doc/concepts/async.md +0 -190
  63. data/doc/concepts/custom_widgets.md +0 -247
  64. data/doc/concepts/debugging.md +0 -401
  65. data/doc/concepts/event_handling.md +0 -162
  66. data/doc/concepts/interactive_design.md +0 -146
  67. data/doc/contributors/auditing/parity.md +0 -239
  68. data/doc/contributors/design/ruby_frontend.md +0 -448
  69. data/doc/contributors/design/rust_backend.md +0 -434
  70. data/doc/contributors/design.md +0 -11
  71. data/doc/contributors/developing_examples.md +0 -400
  72. data/doc/contributors/documentation_style.md +0 -121
  73. data/doc/contributors/index.md +0 -21
  74. data/doc/contributors/releasing.md +0 -215
  75. data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -381
  76. data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -200
  77. data/doc/contributors/todo/align/term.md +0 -351
  78. data/doc/contributors/todo/align/terminal.md +0 -647
  79. data/doc/contributors/todo/future_work.md +0 -169
  80. data/doc/contributors/upstream_requests/paragraph_span_rects.md +0 -259
  81. data/doc/contributors/upstream_requests/tab_rects.md +0 -173
  82. data/doc/contributors/upstream_requests/title_rects.md +0 -132
  83. data/doc/custom.css +0 -22
  84. data/doc/getting_started/quickstart.md +0 -291
  85. data/doc/getting_started/why.md +0 -93
  86. data/doc/images/app_all_events.png +0 -0
  87. data/doc/images/app_cli_rich_moments.gif +0 -0
  88. data/doc/images/app_color_picker.png +0 -0
  89. data/doc/images/app_debugging_showcase.gif +0 -0
  90. data/doc/images/app_debugging_showcase.png +0 -0
  91. data/doc/images/app_external_editor.gif +0 -0
  92. data/doc/images/app_login_form.png +0 -0
  93. data/doc/images/app_stateful_interaction.png +0 -0
  94. data/doc/images/verify_quickstart_dsl.png +0 -0
  95. data/doc/images/verify_quickstart_layout.png +0 -0
  96. data/doc/images/verify_quickstart_lifecycle.png +0 -0
  97. data/doc/images/verify_readme_usage.png +0 -0
  98. data/doc/images/widget_barchart.png +0 -0
  99. data/doc/images/widget_block.png +0 -0
  100. data/doc/images/widget_box.png +0 -0
  101. data/doc/images/widget_calendar.png +0 -0
  102. data/doc/images/widget_canvas.png +0 -0
  103. data/doc/images/widget_cell.png +0 -0
  104. data/doc/images/widget_center.png +0 -0
  105. data/doc/images/widget_chart.png +0 -0
  106. data/doc/images/widget_gauge.png +0 -0
  107. data/doc/images/widget_layout_split.png +0 -0
  108. data/doc/images/widget_line_gauge.png +0 -0
  109. data/doc/images/widget_list.png +0 -0
  110. data/doc/images/widget_map.png +0 -0
  111. data/doc/images/widget_overlay.png +0 -0
  112. data/doc/images/widget_popup.png +0 -0
  113. data/doc/images/widget_ratatui_logo.png +0 -0
  114. data/doc/images/widget_ratatui_mascot.png +0 -0
  115. data/doc/images/widget_rect.png +0 -0
  116. data/doc/images/widget_render.png +0 -0
  117. data/doc/images/widget_rich_text.png +0 -0
  118. data/doc/images/widget_scroll_text.png +0 -0
  119. data/doc/images/widget_scrollbar.png +0 -0
  120. data/doc/images/widget_sparkline.png +0 -0
  121. data/doc/images/widget_style_colors.png +0 -0
  122. data/doc/images/widget_table.png +0 -0
  123. data/doc/images/widget_tabs.png +0 -0
  124. data/doc/images/widget_text_width.png +0 -0
  125. data/doc/index.md +0 -34
  126. data/doc/troubleshooting/async.md +0 -4
  127. data/doc/troubleshooting/terminal_limitations.md +0 -131
  128. data/doc/troubleshooting/tui_output.md +0 -197
  129. data/examples/app_all_events/README.md +0 -114
  130. data/examples/app_all_events/app.rb +0 -98
  131. data/examples/app_all_events/model/app_model.rb +0 -159
  132. data/examples/app_all_events/model/event_color_cycle.rb +0 -43
  133. data/examples/app_all_events/model/event_entry.rb +0 -94
  134. data/examples/app_all_events/model/msg.rb +0 -39
  135. data/examples/app_all_events/model/timestamp.rb +0 -56
  136. data/examples/app_all_events/update.rb +0 -75
  137. data/examples/app_all_events/view/app_view.rb +0 -80
  138. data/examples/app_all_events/view/controls_view.rb +0 -54
  139. data/examples/app_all_events/view/counts_view.rb +0 -61
  140. data/examples/app_all_events/view/live_view.rb +0 -72
  141. data/examples/app_all_events/view/log_view.rb +0 -57
  142. data/examples/app_all_events/view.rb +0 -9
  143. data/examples/app_cli_rich_moments/README.md +0 -81
  144. data/examples/app_cli_rich_moments/app.rb +0 -189
  145. data/examples/app_color_picker/README.md +0 -156
  146. data/examples/app_color_picker/app.rb +0 -76
  147. data/examples/app_color_picker/clipboard.rb +0 -86
  148. data/examples/app_color_picker/color.rb +0 -193
  149. data/examples/app_color_picker/controls.rb +0 -92
  150. data/examples/app_color_picker/copy_dialog.rb +0 -168
  151. data/examples/app_color_picker/export_pane.rb +0 -128
  152. data/examples/app_color_picker/harmony.rb +0 -58
  153. data/examples/app_color_picker/input.rb +0 -176
  154. data/examples/app_color_picker/main_container.rb +0 -180
  155. data/examples/app_color_picker/palette.rb +0 -111
  156. data/examples/app_debugging_showcase/README.md +0 -119
  157. data/examples/app_debugging_showcase/app.rb +0 -318
  158. data/examples/app_external_editor/README.md +0 -62
  159. data/examples/app_external_editor/app.rb +0 -344
  160. data/examples/app_login_form/README.md +0 -58
  161. data/examples/app_login_form/app.rb +0 -109
  162. data/examples/app_stateful_interaction/README.md +0 -35
  163. data/examples/app_stateful_interaction/app.rb +0 -328
  164. data/examples/timeout_demo.rb +0 -45
  165. data/examples/verify_quickstart_dsl/README.md +0 -55
  166. data/examples/verify_quickstart_dsl/app.rb +0 -49
  167. data/examples/verify_quickstart_layout/README.md +0 -77
  168. data/examples/verify_quickstart_layout/app.rb +0 -73
  169. data/examples/verify_quickstart_lifecycle/README.md +0 -68
  170. data/examples/verify_quickstart_lifecycle/app.rb +0 -62
  171. data/examples/verify_readme_usage/README.md +0 -49
  172. data/examples/verify_readme_usage/app.rb +0 -42
  173. data/examples/verify_website_managed/README.md +0 -48
  174. data/examples/verify_website_managed/app.rb +0 -36
  175. data/examples/verify_website_menu/README.md +0 -60
  176. data/examples/verify_website_menu/app.rb +0 -84
  177. data/examples/verify_website_spinner/README.md +0 -44
  178. data/examples/verify_website_spinner/app.rb +0 -34
  179. data/examples/widget_barchart/README.md +0 -58
  180. data/examples/widget_barchart/app.rb +0 -240
  181. data/examples/widget_block/README.md +0 -44
  182. data/examples/widget_block/app.rb +0 -258
  183. data/examples/widget_box/README.md +0 -54
  184. data/examples/widget_box/app.rb +0 -255
  185. data/examples/widget_calendar/README.md +0 -48
  186. data/examples/widget_calendar/app.rb +0 -115
  187. data/examples/widget_canvas/README.md +0 -31
  188. data/examples/widget_canvas/app.rb +0 -130
  189. data/examples/widget_cell/README.md +0 -45
  190. data/examples/widget_cell/app.rb +0 -112
  191. data/examples/widget_center/README.md +0 -33
  192. data/examples/widget_center/app.rb +0 -118
  193. data/examples/widget_chart/README.md +0 -50
  194. data/examples/widget_chart/app.rb +0 -220
  195. data/examples/widget_gauge/README.md +0 -50
  196. data/examples/widget_gauge/app.rb +0 -229
  197. data/examples/widget_layout_split/README.md +0 -53
  198. data/examples/widget_layout_split/app.rb +0 -260
  199. data/examples/widget_line_gauge/README.md +0 -50
  200. data/examples/widget_line_gauge/app.rb +0 -219
  201. data/examples/widget_list/README.md +0 -58
  202. data/examples/widget_list/app.rb +0 -382
  203. data/examples/widget_map/README.md +0 -48
  204. data/examples/widget_map/app.rb +0 -95
  205. data/examples/widget_overlay/README.md +0 -45
  206. data/examples/widget_overlay/app.rb +0 -250
  207. data/examples/widget_popup/README.md +0 -45
  208. data/examples/widget_popup/app.rb +0 -106
  209. data/examples/widget_ratatui_logo/README.md +0 -43
  210. data/examples/widget_ratatui_logo/app.rb +0 -104
  211. data/examples/widget_ratatui_mascot/README.md +0 -43
  212. data/examples/widget_ratatui_mascot/app.rb +0 -95
  213. data/examples/widget_rect/README.md +0 -53
  214. data/examples/widget_rect/app.rb +0 -222
  215. data/examples/widget_render/README.md +0 -46
  216. data/examples/widget_render/app.rb +0 -186
  217. data/examples/widget_render/app.rbs +0 -41
  218. data/examples/widget_rich_text/README.md +0 -44
  219. data/examples/widget_rich_text/app.rb +0 -193
  220. data/examples/widget_scroll_text/README.md +0 -46
  221. data/examples/widget_scroll_text/app.rb +0 -109
  222. data/examples/widget_scrollbar/README.md +0 -46
  223. data/examples/widget_scrollbar/app.rb +0 -155
  224. data/examples/widget_sparkline/README.md +0 -51
  225. data/examples/widget_sparkline/app.rb +0 -277
  226. data/examples/widget_style_colors/README.md +0 -43
  227. data/examples/widget_style_colors/app.rb +0 -83
  228. data/examples/widget_table/README.md +0 -57
  229. data/examples/widget_table/app.rb +0 -285
  230. data/examples/widget_tabs/README.md +0 -50
  231. data/examples/widget_tabs/app.rb +0 -183
  232. data/examples/widget_text_width/README.md +0 -44
  233. data/examples/widget_text_width/app.rb +0 -117
  234. data/migrate_to_buffer.rb +0 -145
  235. data/mise.toml +0 -8
  236. data/tasks/autodoc/examples.rb +0 -87
  237. data/tasks/autodoc/member.rb +0 -58
  238. data/tasks/autodoc/name.rb +0 -21
  239. data/tasks/autodoc.rake +0 -21
  240. data/tasks/bump/bump_workflow.rb +0 -49
  241. data/tasks/bump/cargo_lockfile.rb +0 -21
  242. data/tasks/bump/changelog.rb +0 -104
  243. data/tasks/bump/header.rb +0 -32
  244. data/tasks/bump/history.rb +0 -32
  245. data/tasks/bump/links.rb +0 -69
  246. data/tasks/bump/manifest.rb +0 -33
  247. data/tasks/bump/patch_release.rb +0 -19
  248. data/tasks/bump/release_branch.rb +0 -17
  249. data/tasks/bump/release_from_trunk.rb +0 -49
  250. data/tasks/bump/repository.rb +0 -54
  251. data/tasks/bump/ruby_gem.rb +0 -29
  252. data/tasks/bump/sem_ver.rb +0 -44
  253. data/tasks/bump/unreleased_section.rb +0 -73
  254. data/tasks/bump.rake +0 -61
  255. data/tasks/doc/documentation.rb +0 -59
  256. data/tasks/doc/link/file_url.rb +0 -30
  257. data/tasks/doc/link/relative_path.rb +0 -61
  258. data/tasks/doc/link/web_url.rb +0 -55
  259. data/tasks/doc/link.rb +0 -52
  260. data/tasks/doc/link_audit.rb +0 -116
  261. data/tasks/doc/problem.rb +0 -40
  262. data/tasks/doc/source_file.rb +0 -93
  263. data/tasks/doc.rake +0 -905
  264. data/tasks/example_viewer.html.erb +0 -172
  265. data/tasks/extension.rake +0 -14
  266. data/tasks/license/headers_md.rb +0 -223
  267. data/tasks/license/headers_rb.rb +0 -210
  268. data/tasks/license/license_utils.rb +0 -130
  269. data/tasks/license/snippets_md.rb +0 -315
  270. data/tasks/license/snippets_rdoc.rb +0 -150
  271. data/tasks/license.rake +0 -91
  272. data/tasks/lint.rake +0 -170
  273. data/tasks/rbs_predicates/predicate_catalog.rb +0 -52
  274. data/tasks/rbs_predicates/predicate_tests.rb +0 -124
  275. data/tasks/rbs_predicates/rbs_signature.rb +0 -63
  276. data/tasks/rbs_predicates.rake +0 -31
  277. data/tasks/rdoc_config.rb +0 -29
  278. data/tasks/resources/build.yml.erb +0 -60
  279. data/tasks/resources/index.html.erb +0 -141
  280. data/tasks/resources/rubies.yml +0 -7
  281. data/tasks/sourcehut.rake +0 -122
  282. data/tasks/steep.rake +0 -11
  283. data/tasks/terminal_preview/app_screenshot.rb +0 -45
  284. data/tasks/terminal_preview/crash_report.rb +0 -54
  285. data/tasks/terminal_preview/example_app.rb +0 -27
  286. data/tasks/terminal_preview/launcher_script.rb +0 -48
  287. data/tasks/terminal_preview/preview_collection.rb +0 -60
  288. data/tasks/terminal_preview/preview_timing.rb +0 -24
  289. data/tasks/terminal_preview/safety_confirmation.rb +0 -58
  290. data/tasks/terminal_preview/saved_screenshot.rb +0 -56
  291. data/tasks/terminal_preview/system_appearance.rb +0 -13
  292. data/tasks/terminal_preview/terminal_window.rb +0 -138
  293. data/tasks/terminal_preview/window_id.rb +0 -16
  294. data/tasks/terminal_preview.rake +0 -30
  295. data/tasks/test.rake +0 -36
  296. data/tasks/website/index_page.rb +0 -30
  297. data/tasks/website/version.rb +0 -122
  298. data/tasks/website/version_menu.rb +0 -68
  299. data/tasks/website/versioned_documentation.rb +0 -83
  300. data/tasks/website/website.rb +0 -53
  301. data/tasks/website.rake +0 -28
data/migrate_to_buffer.rb DELETED
@@ -1,145 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- #
6
- # SPDX-License-Identifier: AGPL-3.0-or-later
7
- #++
8
-
9
- # !/usr/bin/env ruby
10
-
11
- # Migration script to refactor widget renderers from Frame to Buffer
12
-
13
- require "fileutils"
14
-
15
- WIDGETS_DIR = "/Users/kerrick/Developer/ratatui_ruby/ext/ratatui_ruby/src/widgets"
16
-
17
- # Files to update (excluding block.rs which is already done)
18
- WIDGET_FILES = %w[
19
- barchart.rs
20
- calendar.rs
21
- canvas.rs
22
- center.rs
23
- chart.rs
24
- clear.rs
25
- cursor.rs
26
- gauge.rs
27
- layout.rs
28
- line_gauge.rs
29
- list.rs
30
- overlay.rs
31
- paragraph.rs
32
- ratatui_logo.rs
33
- ratatui_mascot.rs
34
- scrollbar.rs
35
- sparkline.rs
36
- table.rs
37
- tabs.rs
38
- ].freeze
39
-
40
- def migrate_file(filepath)
41
- puts "Migrating #{File.basename(filepath)}..."
42
-
43
- content = File.read(filepath)
44
- original_content = content.dup
45
-
46
- # 1. Update function signature
47
- content.gsub!("pub fn render(frame: &mut Frame,", "pub fn render(buffer: &mut Buffer,")
48
- content.gsub!("pub fn render_ratatui_mascot(frame: &mut Frame,", "pub fn render_ratatui_mascot(buffer: &mut Buffer,")
49
-
50
- # 2. Update imports - Add Buffer, remove Frame
51
- # Handle various import patterns
52
- content.gsub!(/use ratatui::\{([^}]*),\s*Frame\s*\};/, 'use ratatui::{\1};')
53
- content.gsub!(/use ratatui::\{Frame,\s*([^}]*)\};/, 'use ratatui::{\1};')
54
- content.gsub!("use ratatui::Frame;", "")
55
-
56
- # Add Buffer import if not present
57
- unless content.match?(/use ratatui::(?:\{[^}]*)?buffer::Buffer/)
58
- # Find the ratatui use statement and add buffer::Buffer
59
- content.gsub!("use ratatui::{", "use ratatui::{buffer::Buffer, ")
60
- content.gsub!("use ratatui::layout::Rect;", "use ratatui::{buffer::Buffer, layout::Rect};")
61
- end
62
-
63
- # 3. Update widget.render calls
64
- # frame.render_widget(widget, area) → widget.render(area, buffer)
65
- content.gsub!(/frame\.render_widget\(([^,]+),\s*([^)]+)\)/, '\1.render(\2, buffer)')
66
-
67
- # 4. Update direct buffer access
68
- content.gsub!("frame.buffer_mut()", "buffer")
69
-
70
- # 5. Update recursive render_node calls
71
- content.gsub!("render_node(frame,", "render_node(buffer,")
72
-
73
- # 5.5. Update stateful widget rendering
74
- # frame.render_stateful_widget(widget, area, state) → StatefulWidget::render(widget, area, buffer, state)
75
- content.gsub!(/frame\.render_stateful_widget\(([^,]+),\s*([^,]+),\s*([^)]+)\)/, 'StatefulWidget::render(\1, \2, buffer, \3)')
76
-
77
- # Add StatefulWidget import if stateful widgets are used
78
- if content.match?(/StatefulWidget::render/) && !content.match?(/use ratatui::widgets::StatefulWidget/) && content.match?(/use ratatui::/)
79
- content.sub!("use ratatui::{", "use ratatui::{widgets::StatefulWidget, ")
80
- end
81
-
82
- # 6. Clean up any double-added Buffer imports and duplicate Widget imports
83
- content.gsub!(/buffer::Buffer,\s*buffer::Buffer,/, "buffer::Buffer,")
84
- content.gsub!(/widgets::Widget,\s*widgets::Widget/, "widgets::Widget")
85
- content.gsub!(/(use ratatui::\{[^}]*widgets::Widget[^}]*),\s*widgets::Widget/, '\1')
86
-
87
- # 7. Fix Widget trait usage - make sure Widget is imported where .render is called
88
- # Add Widget to imports if calling .render on widgets
89
- if content.match?(/\.render\(area,\s*buffer\)/) && !content.match?(/use ratatui::widgets::Widget/) && content.match?(/use ratatui::\{/) && !content.match?(/widgets::Widget/)
90
- content.sub!("use ratatui::{", "use ratatui::{widgets::Widget, ")
91
- end
92
-
93
- # 8. For files that don't have proper Buffer imports yet, add them
94
- if !content.match?(/use ratatui::\{[^}]*buffer::Buffer/) && content.match?(/use ratatui::/)
95
- # Try to add to first ratatui import
96
- content.sub!("use ratatui::", "use ratatui::{buffer::Buffer};\nuse ratatui::")
97
- end
98
-
99
- # 9. Special case: cursor.rs uses frame.set_cursor_position which doesn't exist on Buffer
100
- # Cursor widget needs special handling - it can't work with just Buffer
101
- if File.basename(filepath) == "cursor.rs"
102
- puts " ⚠ cursor.rs requires special handling - skipping set_cursor_position"
103
- # This widget can't be fully migrated as set_cursor_position is Frame-only
104
- # Will need manual fix or different approach
105
- end
106
- # Only write if content changed
107
- if content != original_content
108
- File.write(filepath, content)
109
- puts " ✓ Updated #{File.basename(filepath)}"
110
- true
111
- else
112
- puts " - No changes needed for #{File.basename(filepath)}"
113
- false
114
- end
115
- end
116
-
117
- def main
118
- puts "Starting widget renderer migration..."
119
- puts "=" * 60
120
-
121
- updated_count = 0
122
-
123
- WIDGET_FILES.each do |filename|
124
- filepath = File.join(WIDGETS_DIR, filename)
125
-
126
- unless File.exist?(filepath)
127
- puts " ⚠ File not found: #{filename}"
128
- next
129
- end
130
-
131
- # Create backup
132
- backup_path = "#{filepath}.premigration"
133
- FileUtils.cp(filepath, backup_path) unless File.exist?(backup_path)
134
-
135
- updated_count += 1 if migrate_file(filepath)
136
- end
137
-
138
- puts "=" * 60
139
- puts "Migration complete!"
140
- puts " Files updated: #{updated_count}/#{WIDGET_FILES.length}"
141
- puts "\nBackups saved with .premigration extension"
142
- puts "Run 'bundle exec rake compile' to verify the changes"
143
- end
144
-
145
- main if __FILE__ == $PROGRAM_NAME
data/mise.toml DELETED
@@ -1,8 +0,0 @@
1
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
- # SPDX-License-Identifier: AGPL-3.0-or-later
3
-
4
- [tools]
5
- ruby = "4.0.0"
6
- rust = "1.91.1"
7
- python = "3.12"
8
- pre-commit = "latest"
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- module Autodoc
9
- class Examples
10
- def self.sync
11
- new.sync
12
- end
13
-
14
- def sync
15
- Dir.glob("{README.md,doc/**/*.md,examples/*/README.md}").each do |readme_path|
16
- sync_readme(readme_path)
17
- end
18
- end
19
-
20
- private def sync_readme(readme_path)
21
- content = File.read(readme_path)
22
- dir = File.dirname(readme_path)
23
-
24
- new_content = content.gsub(/<!-- SYNC:START:([^ ]+) -->.*?<!-- SYNC:END -->/m) do
25
- marker_info = $1
26
- source_rel_path, segment_id = marker_info.split(":")
27
-
28
- # Support both repo-root-relative paths (no leading ./) and file-relative paths
29
- source_path = if source_rel_path.start_with?("./", "../")
30
- File.join(dir, source_rel_path)
31
- else
32
- source_rel_path # Already relative to repo root
33
- end
34
-
35
- unless File.exist?(source_path)
36
- warn "Warning: Source file not found: #{source_path}"
37
- next $&
38
- end
39
-
40
- source_content = File.read(source_path)
41
- extracted_content = if segment_id
42
- extract_segment(source_content, segment_id, source_path)
43
- else
44
- source_content
45
- end
46
-
47
- # Detect language from extension
48
- ext = File.extname(source_path).delete(".")
49
- lang = (ext == "rb") ? "ruby" : ext
50
-
51
- # Build replacement
52
- "<!-- SYNC:START:#{marker_info} -->\n```#{lang}\n#{extracted_content}```\n<!-- SYNC:END -->"
53
- end
54
-
55
- if new_content != content
56
- puts "Syncing #{readme_path}..."
57
- File.write(readme_path, new_content)
58
- end
59
- end
60
-
61
- def extract_segment(content, segment_id, source_path)
62
- start_marker = /#\s*\[SYNC:START:#{segment_id}\]/
63
- end_marker = /#\s*\[SYNC:END:#{segment_id}\]/
64
-
65
- lines = content.lines
66
- start_idx = lines.find_index { |l| l =~ start_marker }
67
- end_idx = lines.find_index { |l| l =~ end_marker }
68
-
69
- if start_idx && end_idx
70
- "#{unindent(lines[(start_idx + 1)...end_idx].join).strip}\n"
71
- else
72
- warn "Warning: Segment '#{segment_id}' not found in #{source_path}"
73
- content # Fallback to full content or error? Let's fallback to original for now.
74
- end
75
- end
76
-
77
- def unindent(text)
78
- lines = text.lines
79
- # Don't unindent if empty or just one line
80
- return text if lines.empty?
81
-
82
- # Find common leading whitespace
83
- indentation = lines.grep(/\S/).map { |l| l[/^\s*/].length }.min || 0
84
- lines.map { |l| (l.length > indentation) ? l[indentation..-1] : "#{l.strip}\n" }.join
85
- end
86
- end
87
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- module Autodoc
9
- module Member
10
- class Delegate < Data.define(:name)
11
- def rbs
12
- " def #{name}: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped"
13
- end
14
-
15
- def rdoc
16
- [
17
- " # :method: #{name}",
18
- " # :call-seq: #{name}(*args, **kwargs, &block)",
19
- " #",
20
- " # Delegates to RatatuiRuby.#{name}.",
21
- " #",
22
- ]
23
- end
24
- end
25
-
26
- class Factory < Data.define(:name, :const_name)
27
- def rbs
28
- " def #{name}: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped"
29
- end
30
-
31
- def rdoc
32
- [
33
- " # :method: #{name}",
34
- " # :call-seq: #{name}(*args, **kwargs, &block)",
35
- " #",
36
- " # Factory for RatatuiRuby::#{const_name}.new.",
37
- " #",
38
- ]
39
- end
40
- end
41
-
42
- class Helper < Data.define(:name, :class_method, :const_name)
43
- def rbs
44
- " def #{name}: (*untyped args, **untyped kwargs) ?{ (*untyped) -> untyped } -> untyped"
45
- end
46
-
47
- def rdoc
48
- [
49
- " # :method: #{name}",
50
- " # :call-seq: #{name}(*args, **kwargs, &block)",
51
- " #",
52
- " # Helper for RatatuiRuby::#{const_name}.#{class_method}.",
53
- " #",
54
- ]
55
- end
56
- end
57
- end
58
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- module Autodoc
9
- class Name < Data.define(:string)
10
- def snake
11
- string.to_s
12
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
13
- .gsub(/([a-z\d])([A-Z])/, '\1_\2')
14
- .downcase
15
- end
16
-
17
- def to_s
18
- string.to_s
19
- end
20
- end
21
- end
data/tasks/autodoc.rake DELETED
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- require_relative "autodoc/examples"
9
-
10
- namespace :autodoc do
11
- desc "Update all automatically generated documentation"
12
- task all: [:examples]
13
-
14
- desc "Sync code snippets in example READMEs with source files"
15
- task :examples do
16
- Autodoc::Examples.sync
17
- end
18
- end
19
-
20
- desc "Update all automatically generated documentation"
21
- task autodoc: "autodoc:all"
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- require_relative "repository"
9
- require_relative "changelog"
10
-
11
- # Base class for version bump workflows.
12
- # Subclasses implement the template methods: prepare, release_on_branch, finalize.
13
- class BumpWorkflow
14
- def initialize(gem:, repository: Repository.new)
15
- @gem = gem
16
- @repository = repository
17
- end
18
-
19
- def call(segment)
20
- @repository.assert_can_bump!(segment)
21
- @target = @gem.version.next(segment)
22
-
23
- prepare(segment)
24
- release_on_branch
25
- finalize
26
- end
27
-
28
- attr_reader :target
29
-
30
- private def release_on_branch
31
- changelog = Changelog.new
32
- @commit_message = changelog.commit_message(target)
33
- changelog.release(target)
34
- @gem.update_version(target)
35
- generate_ci_manifests
36
- @repository.commit_all(@commit_message)
37
- end
38
-
39
- private def generate_ci_manifests
40
- Rake::Task["sourcehut:build:manifest"].reenable
41
- Rake::Task["sourcehut:build"].reenable
42
- Rake::Task["sourcehut"].reenable
43
- Rake::Task["sourcehut"].invoke
44
- end
45
-
46
- # Template methods for subclasses
47
- private def prepare(segment) = nil
48
- private def finalize = nil
49
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- # Lockfiles need to be refreshed by a tool after Manifests are changed.
9
- class CargoLockfile < Data.define(:path, :dir, :name)
10
- def exists?
11
- File.exist?(path)
12
- end
13
-
14
- def refresh
15
- return unless exists?
16
-
17
- Dir.chdir(dir) do
18
- system("cargo update -p #{name} --offline")
19
- end
20
- end
21
- end
@@ -1,104 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- require_relative "links"
9
- require_relative "unreleased_section"
10
- require_relative "history"
11
- require_relative "header"
12
-
13
- # Changelog manages the project's CHANGELOG.md file.
14
- class Changelog
15
- # Creates a new Changelog for the file at the given path.
16
- def initialize(path: "CHANGELOG.md")
17
- @path = path
18
- end
19
-
20
- # Releases a new version in the changelog.
21
- # This moves the unreleased changes to a new version heading and resets the unreleased section.
22
- def release(new_version)
23
- content = File.read(@path)
24
-
25
- header = Header.parse(content)
26
- unreleased = UnreleasedSection.parse(content)
27
- links = Links.from_markdown(content)
28
-
29
- raise "Could not parse CHANGELOG.md" unless header && unreleased && links
30
-
31
- history = History.parse(content, header.length, unreleased.to_s.length, links.to_s)
32
-
33
- links.release(new_version)
34
- history.add(unreleased.as_version(new_version))
35
-
36
- File.write(@path, "#{header}#{UnreleasedSection.fresh}\n\n#{history}\n#{links}")
37
- nil
38
- end
39
-
40
- # Removes entries from [Unreleased] that were released in the given version.
41
- # Used when creating a release branch from trunk.
42
- def prune_released_entries(released_entries)
43
- content = File.read(@path)
44
-
45
- header = Header.parse(content)
46
- unreleased = UnreleasedSection.parse(content)
47
- links = Links.from_markdown(content)
48
-
49
- raise "Could not parse CHANGELOG.md" unless header && unreleased && links
50
-
51
- history = History.parse(content, header.length, unreleased.to_s.length, links.to_s)
52
-
53
- pruned = unreleased.without_entries(released_entries)
54
-
55
- File.write(@path, "#{header}#{pruned}\n\n#{history}\n#{links}")
56
- nil
57
- end
58
-
59
- # Imports a release section from another branch's changelog.
60
- # Adds the version section to history and dedupes from [Unreleased].
61
- # Uses "first wins" — if entry already deduped, doesn't re-add it.
62
- def import_release(version, release_changelog_content)
63
- release_section = extract_version_section(release_changelog_content, version)
64
- return unless release_section
65
-
66
- content = File.read(@path)
67
-
68
- header = Header.parse(content)
69
- unreleased = UnreleasedSection.parse(content)
70
- links = Links.from_markdown(content)
71
-
72
- raise "Could not parse CHANGELOG.md" unless header && unreleased && links
73
-
74
- history = History.parse(content, header.length, unreleased.to_s.length, links.to_s)
75
-
76
- # Add the release section to history (inserted in version order)
77
- history.add(release_section)
78
- links.release(version)
79
-
80
- # Dedupe from [Unreleased] (first-wins: if already gone, no-op)
81
- release_entries = release_section.lines.select { |l| l.strip.start_with?("- ") }.map(&:strip)
82
- pruned = unreleased.without_entries(release_entries)
83
-
84
- File.write(@path, "#{header}#{pruned}\n\n#{history}\n#{links}")
85
- nil
86
- end
87
-
88
- def commit_message(version)
89
- content = File.read(@path)
90
- unreleased = UnreleasedSection.parse(content)
91
- return nil unless unreleased
92
-
93
- "chore: release v#{version}\n\n#{unreleased.commit_body}"
94
- end
95
-
96
- private def extract_version_section(changelog_content, version)
97
- # Match the version heading and capture until the next version heading or links section
98
- pattern = /^## \[#{Regexp.escape(version.to_s)}\][^\n]*\n(.*?)(?=^## \[|\n\[Unreleased\]:)/m
99
- match = changelog_content.match(pattern)
100
- return nil unless match
101
-
102
- "## [#{version}]#{match[0].split("\n", 2).first.split(']', 2).last}\n#{match[1]}"
103
- end
104
- end
data/tasks/bump/header.rb DELETED
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- # Header manages the header section of the changelog.
9
- class Header
10
- PATTERN = /^(.*?)(?=## \[Unreleased\])/m
11
-
12
- # Extracts the header section from the given content.
13
- def self.parse(content)
14
- match = content.match(PATTERN)
15
- new(match[1]) if match
16
- end
17
-
18
- # Creates a new Header from the given content.
19
- def initialize(content)
20
- @content = content.dup
21
- end
22
-
23
- # Returns the length of the header content.
24
- def length
25
- @content.length
26
- end
27
-
28
- # Returns the current state of the header as a string.
29
- def to_s
30
- @content
31
- end
32
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- # History manages the versioned history of the changelog.
9
- class History
10
- # Extracts the history section from the given content, between unreleased and links.
11
- def self.parse(content, header_length, unreleased_length, links_text)
12
- start = header_length + unreleased_length
13
- text = "#{content[start...(content.index(links_text))].strip}\n"
14
- new(text)
15
- end
16
-
17
- # Creates a new History from the given content.
18
- def initialize(content)
19
- @content = content.dup
20
- end
21
-
22
- # Adds a new versioned section to the history.
23
- def add(section)
24
- @content = "#{"#{section}\n\n#{@content}".strip}\n"
25
- nil
26
- end
27
-
28
- # Returns the current state of the history as a string.
29
- def to_s
30
- @content
31
- end
32
- end
data/tasks/bump/links.rb DELETED
@@ -1,69 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- # Manages the version comparison links at the botton of the changelog.
9
- #
10
- # Release automation needs to update links. Manually calculating git diff URLs
11
- # for every release is tedious and error-prone. SourceHut does not have
12
- # standard comparison views, complicating matters further.
13
- #
14
- # This class manages the collection of links. It parses them from the markdown.
15
- # It generates the correct tree links for SourceHut. It properly shifts the
16
- # "Unreleased" pointer.
17
- #
18
- # Use it to update the changelog during a release.
19
- class Links
20
- PATTERN = /^(\[Unreleased\]: .*)$/m
21
- UNRELEASED_PATTERN = %r{^\[Unreleased\]: (.*?/refs/)HEAD$}
22
-
23
- # Creates a Links object from the full markdown content.
24
- #
25
- # [content] String. The full text of the changelog.
26
- def self.from_markdown(content)
27
- match = content.match(PATTERN)
28
- return unless match
29
-
30
- new(match[1].strip)
31
- end
32
-
33
- # Returns the raw text of the links.
34
- attr_reader :text
35
-
36
- # Creates a new Links object.
37
- #
38
- # [text] String. The raw text of the links section.
39
- def initialize(text)
40
- @text = text.dup
41
- end
42
-
43
- # Releases a new version.
44
- #
45
- # Updates the "Unreleased" link to point to the new head. Adds a new link for
46
- # the just-released version pointing to its specific tag.
47
- #
48
- # [version] String. The new version number (e.g., <tt>"0.5.0"</tt>).
49
- def release(version)
50
- return unless base_url
51
-
52
- new_unreleased = "[Unreleased]: #{base_url}HEAD" # .../HEAD
53
- new_version_link = "[#{version}]: #{base_url}v#{version}" # .../v1.0.0
54
-
55
- @text.sub!(UNRELEASED_PATTERN, "#{new_unreleased}\n#{new_version_link}")
56
- self
57
- end
58
-
59
- # Returns the string representation of the links.
60
- def to_s
61
- @text
62
- end
63
-
64
- # The base URL for the repository's references.
65
- private def base_url
66
- match = @text.match(UNRELEASED_PATTERN)
67
- match[1] if match
68
- end
69
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- #--
4
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
- # SPDX-License-Identifier: AGPL-3.0-or-later
6
- #++
7
-
8
- # Manifests hold a copy of the version number and should be changed manually.
9
- # Use Regexp lookarounds in `pattern` to match the version number.
10
- class Manifest < Data.define(:path, :pattern, :primary)
11
- def read
12
- File.read(path)
13
- end
14
-
15
- def initialize(path:, pattern:, primary: false)
16
- super
17
- end
18
-
19
- def version
20
- content = read
21
- match = content.match(pattern)
22
- raise "Version missing in manifest #{path}" unless match
23
-
24
- SemVer.parse(match[0])
25
- end
26
-
27
- def write(version)
28
- return unless File.exist?(path)
29
-
30
- new_content = read.gsub(pattern, version.to_s)
31
- File.write(path, new_content)
32
- end
33
- end