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/tasks/sourcehut.rake DELETED
@@ -1,122 +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
- desc "Generate SourceHut build manifests from template"
9
- task sourcehut: "sourcehut:build"
10
-
11
- namespace :sourcehut do
12
- desc "Build SourceHut manifests"
13
- task build: "sourcehut:build:manifest"
14
-
15
- namespace :build do
16
- desc "Generate SourceHut build manifests from template"
17
- task :manifest do
18
- require "erb"
19
- require "yaml"
20
-
21
- spec = Gem::Specification.load("ratatui_ruby.gemspec")
22
-
23
- # Read version directly from file to ensure we get the latest version
24
- # even if it was just bumped in the same Rake execution
25
- version_content = File.read("lib/ratatui_ruby/version.rb")
26
- version = version_content.match(/VERSION = "(.+?)"/)[1]
27
-
28
- # Normalize version using Gem::Version - RubyGems converts hyphens
29
- # (e.g., "1.0.0-beta.1" -> "1.0.0.pre.beta.1")
30
- normalized_version = Gem::Version.new(version).to_s
31
-
32
- gem_filename = "#{spec.name}-#{normalized_version}.gem"
33
-
34
- rubies = YAML.load_file("tasks/resources/rubies.yml")
35
-
36
- bundler_version = File.read("Gemfile.lock").match(/BUNDLED WITH\n\s+([\d.]+)/)[1]
37
-
38
- template = File.read("tasks/resources/build.yml.erb")
39
- erb = ERB.new(template, trim_mode: "-")
40
-
41
- FileUtils.mkdir_p ".builds"
42
-
43
- # Remove old generated files to ensure a clean state
44
- Dir.glob(".builds/*.yml").each { |f| File.delete(f) }
45
-
46
- rubies.each do |ruby_version|
47
- filename = ".builds/ruby-#{ruby_version}.yml"
48
- puts "Generating #{filename}..."
49
- gem_name = spec.name
50
- has_rust = File.exist?("ext/#{gem_name}/Cargo.toml")
51
- content = erb.result_with_hash(ruby_version:, gem_name:, gem_filename:, bundler_version:, has_rust:)
52
- File.write(filename, content)
53
- end
54
- end
55
- end
56
-
57
- desc "Update stable branch to match release and set as default"
58
- task :update_stable do
59
- # Read version to determine tag
60
- version_content = File.read("lib/ratatui_ruby/version.rb")
61
- version = version_content.match(/VERSION = "(.+?)"/)[1]
62
- tag_name = "v#{version}"
63
-
64
- # Verify that the version file matches the actual git tag
65
- # This prevents updating stable to the wrong version if the release failed
66
- latest_tag = `git describe --tags --abbrev=0`.strip
67
- if latest_tag != tag_name
68
- abort "Fatal: Version mismatch! 'lib/ratatui_ruby/version.rb' says #{tag_name}, but the latest git tag is #{latest_tag}."
69
- end
70
-
71
- # Get current stable version (if stable branch exists)
72
- stable_version_str = `git show stable:lib/ratatui_ruby/version.rb 2>/dev/null`.match(/VERSION = "(.+?)"/)&.[](1)
73
- if stable_version_str
74
- stable_version = Gem::Version.new(stable_version_str)
75
- new_version = Gem::Version.new(version)
76
-
77
- if new_version <= stable_version
78
- puts "Skipping stable update: #{version} is not newer than current stable #{stable_version_str}"
79
- next
80
- end
81
- end
82
-
83
- puts "Updating stable branch to point to #{tag_name}..."
84
- # Resolve the tag to a commit hash (peel annotated tags)
85
- # This renders a commit SHA that can be pushed to a branch head
86
- commit_sha = `git rev-parse #{tag_name}^{}`.strip
87
-
88
- # Update local stable branch to match
89
- sh "git branch -f stable #{commit_sha}"
90
-
91
- # Push the commit to remote stable branch
92
- # Force-push because stable is reset to each release, not fast-forwarded.
93
- sh "git push --force origin #{commit_sha}:stable"
94
- end
95
- end
96
-
97
- if Rake::Task.task_defined?("release")
98
- Rake::Task["release"].enhance do
99
- # Replace Bundler's normalized tag with semver-style for prerelease versions.
100
- # Bundler creates tags using normalized Gem::Version (e.g., v1.0.0.pre.beta.1).
101
- # Semver uses hyphens (e.g., v1.0.0-beta.1). We want only the semver tag.
102
- version_content = File.read("lib/ratatui_ruby/version.rb")
103
- version = version_content.match(/VERSION = "(.+?)"/)[1]
104
-
105
- if version.include?("-")
106
- normalized_tag = "v#{Gem::Version.new(version)}"
107
- semver_tag = "v#{version}"
108
-
109
- if normalized_tag != semver_tag
110
- puts "Replacing normalized tag #{normalized_tag} with semver tag #{semver_tag}..."
111
- # Delete the normalized tag locally and remotely
112
- sh "git tag -d #{normalized_tag}"
113
- sh "git push origin :refs/tags/#{normalized_tag}"
114
- # Create the semver tag pointing to the same commit
115
- sh "git tag #{semver_tag} HEAD"
116
- sh "git push origin #{semver_tag}"
117
- end
118
- end
119
-
120
- Rake::Task["sourcehut:update_stable"].invoke
121
- end
122
- end
data/tasks/steep.rake DELETED
@@ -1,11 +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
- desc "Run Steep type checker"
9
- task :steep do
10
- sh "bundle exec steep check"
11
- end
@@ -1,45 +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 "tmpdir"
9
- require_relative "launcher_script"
10
- require_relative "terminal_window"
11
- require_relative "crash_report"
12
-
13
- class AppScreenshot < Data.define(:app, :output_path)
14
- def capture
15
- print " 📸 #{app}..."
16
-
17
- LauncherScript.new(app.app_path, Dir.pwd).run do |launcher|
18
- TerminalWindow.new(launcher.path, launcher.pid_file).open do |window|
19
- take_snapshot(window.window_id)
20
-
21
- if File.size?(output_path)
22
- puts " done."
23
- true
24
- else
25
- FileUtils.rm_f(output_path)
26
- puts " FAILED"
27
- puts
28
- puts " Window rendered nothing (app may have crashed before drawing)"
29
- puts
30
- false
31
- end
32
- end
33
- end
34
- rescue => e
35
- puts " FAILED"
36
- puts
37
- puts CrashReport.new(app, e, "Program crashed before screenshot could be taken:")
38
- puts
39
- false
40
- end
41
-
42
- private def take_snapshot(window_id)
43
- system("screencapture", "-l", window_id.to_s, "-o", "-x", output_path)
44
- end
45
- end
@@ -1,54 +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
- class CrashReport < Data.define(:app, :error, :preamble)
9
- def self.new(app, error, preamble = nil)
10
- # Allow preamble to be optional while Data.define requires all fields
11
- super(app:, error:, preamble:)
12
- end
13
-
14
- def to_s
15
- output = error.message.strip
16
- formatted_error = output.split("\n").map { |line| format_line(line) }.join("\n")
17
- preamble_section = preamble ? <<~PREAMBLE.chomp : ""
18
- #{box_top}
19
- #{format_line(preamble)}
20
- #{box_bottom}
21
- PREAMBLE
22
-
23
- <<~TEXT
24
- #{preamble_section}
25
- #{border_top(app.to_s)}
26
- #{formatted_error}
27
- #{box_bottom}
28
- TEXT
29
- end
30
-
31
- private def box_top
32
- "┌#{'─' * (width - 2)}┐"
33
- end
34
-
35
- private def box_bottom
36
- "└#{'─' * (width - 2)}┘"
37
- end
38
-
39
- private def border_top(title)
40
- left = "┌─ #{title} "
41
- right = "┐"
42
- dashes = "─" * (width - left.length - right.length)
43
- left + dashes + right
44
- end
45
-
46
- private def format_line(line)
47
- truncated = line[0...(width - 4)]
48
- "│ #{truncated.ljust(width - 4)} │"
49
- end
50
-
51
- private def width
52
- 80
53
- end
54
- end
@@ -1,27 +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
- class ExampleApp < Data.define(:directory)
9
- def self.all
10
- examples_dir = File.expand_path("../../examples", __dir__)
11
- Dir.glob("#{examples_dir}/*/app.rb").map do |path|
12
- new(File.basename(File.dirname(path)))
13
- end.sort_by(&:directory)
14
- end
15
-
16
- def app_path
17
- "examples/#{directory}/app.rb"
18
- end
19
-
20
- def screenshot_filename
21
- "#{directory}.png"
22
- end
23
-
24
- def to_s
25
- directory
26
- end
27
- end
@@ -1,48 +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 "fileutils"
9
- require "tmpdir"
10
-
11
- class LauncherScript < Data.define(:app_path, :repo_root)
12
- def initialize(app_path:, repo_root:)
13
- super
14
- write
15
- end
16
-
17
- def run
18
- yield self
19
- ensure
20
- cleanup
21
- end
22
-
23
- def path
24
- File.join(Dir.tmpdir, "preview_launcher.sh")
25
- end
26
-
27
- def pid_file
28
- File.join(Dir.tmpdir, "preview_launcher.pid")
29
- end
30
-
31
- private def cleanup
32
- FileUtils.rm_f(path)
33
- FileUtils.rm_f(pid_file)
34
- rescue Errno::ENOENT
35
- # Already deleted
36
- end
37
-
38
- private def write
39
- File.open(path, "w") do |f|
40
- f.puts "#!/bin/zsh"
41
- f.puts "cd '#{repo_root}'"
42
- f.puts "clear"
43
- f.puts "echo $$ > '#{pid_file}'"
44
- f.puts "exec bundle exec ruby '#{app_path}'"
45
- end
46
- FileUtils.chmod(0o755, path)
47
- end
48
- end
@@ -1,60 +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 "fileutils"
9
- require_relative "example_app"
10
- require_relative "app_screenshot"
11
- require_relative "crash_report"
12
- require_relative "preview_timing"
13
- require_relative "safety_confirmation"
14
- require_relative "saved_screenshot"
15
-
16
- class PreviewCollection
17
- def initialize(output_dir)
18
- @output_dir = output_dir
19
- end
20
-
21
- def generate
22
- abort "Error: This task requires macOS." unless RUBY_PLATFORM.match?(/darwin/)
23
-
24
- apps = ExampleApp.all
25
- stale_count = count_stale_apps(apps)
26
-
27
- if stale_count.zero?
28
- puts "\n✨ All #{apps.count} screenshots are up to date."
29
- return
30
- end
31
-
32
- SafetyConfirmation.new(stale_count, apps.count).request
33
-
34
- puts "\nHere we go!"
35
- failures = apps.count { |app| !capture_app(app) }
36
-
37
- if failures.zero?
38
- puts "\n✨ All captures complete. Check doc/images/."
39
- else
40
- abort "\n❌ #{failures} capture(s) failed."
41
- end
42
- end
43
-
44
- private def count_stale_apps(apps)
45
- apps.count { |app| SavedScreenshot.for(app, @output_dir).stale? }
46
- end
47
-
48
- private def capture_app(app)
49
- saved = SavedScreenshot.for(app, @output_dir)
50
-
51
- if saved.stale?
52
- success = AppScreenshot.new(app, saved.path).capture
53
- sleep PreviewTiming.between_captures
54
- success
55
- else
56
- puts " ⏭️ #{app} (unchanged)"
57
- true
58
- end
59
- end
60
- end
@@ -1,24 +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
- class PreviewTiming
9
- def self.window_startup
10
- 1.5
11
- end
12
-
13
- def self.between_captures
14
- 0.2
15
- end
16
-
17
- def self.close_delay
18
- 1.0
19
- end
20
-
21
- def self.total
22
- window_startup + close_delay + between_captures
23
- end
24
- 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
- require_relative "preview_timing"
9
- require_relative "system_appearance"
10
-
11
- class SafetyConfirmation
12
- def initialize(stale_count, total_count)
13
- @stale_count = stale_count
14
- @total_count = total_count
15
- end
16
-
17
- def request
18
- print_warning
19
- wait_for_user
20
- end
21
-
22
- private def print_warning
23
- unchanged_count = @total_count - @stale_count
24
- puts "\n#{'=' * 60}"
25
- puts " 📸 NATIVE TERMINAL CAPTURE 📸"
26
- puts "=" * 60
27
- puts "This task will:"
28
- puts " 1. Take control of your mouse/keyboard focus"
29
- puts " 2. Rapidly open and close Terminal windows"
30
- puts " 3. Capture #{@stale_count} screenshots (#{unchanged_count} unchanged)"
31
- puts
32
- puts "Before starting, be sure Terminal.app has the following permissions"
33
- puts "in System Settings.app -> Privacy & Security:"
34
- puts " - Screen & System Audio Recording"
35
- puts " - Automation -> System Events"
36
- puts
37
- puts "⚠️ PLEASE DO NOT TOUCH YOUR COMPUTER WHILE THIS RUNS."
38
- min_time = (@stale_count * PreviewTiming.total).to_i
39
- max_time = (@stale_count * (PreviewTiming.total + PreviewTiming.close_delay)).to_i
40
- puts " (Estimated time: #{min_time}-#{max_time} seconds)"
41
- puts
42
- end
43
-
44
- private def wait_for_user
45
- loop do
46
- print "Continue? [Y/n]: "
47
- response = $stdin.gets.strip.downcase
48
-
49
- if response.empty? || response == "y"
50
- return if SystemAppearance.dark?
51
- puts "⚠️ Dark Mode is not enabled. Please enable it in System Settings or Control Center before proceeding."
52
- puts
53
- elsif response == "n"
54
- abort "Cancelled."
55
- end
56
- end
57
- end
58
- end
@@ -1,56 +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 "time"
9
-
10
- class SavedScreenshot < Data.define(:app, :path)
11
- def self.for(app, output_dir)
12
- new(app, File.join(output_dir, app.screenshot_filename))
13
- end
14
-
15
- def stale?
16
- return true unless valid?
17
-
18
- app_last_modified > screenshot_last_commit_time
19
- end
20
-
21
- private def valid?
22
- # File must exist and have content (not 0 bytes)
23
- File.size?(path) || false
24
- end
25
-
26
- private def app_last_modified
27
- # If the file has staged or unstaged changes, it's definitely stale
28
- return Time.now.to_i if changed?
29
-
30
- # Otherwise, compare against the last git commit time
31
- app_last_commit_time
32
- end
33
-
34
- private def changed?
35
- system("git diff HEAD --quiet #{app.app_path} 2>/dev/null")
36
- !$?.success?
37
- end
38
-
39
- private def app_last_commit_time
40
- output = `git log -1 --format=%cI "#{app.app_path}" 2>/dev/null`.strip
41
- return 0 if output.empty?
42
-
43
- Time.iso8601(output).to_i
44
- rescue
45
- 0
46
- end
47
-
48
- private def screenshot_last_commit_time
49
- output = `git log -1 --format=%cI "#{path}" 2>/dev/null`.strip
50
- return Time.now.to_i if output.empty?
51
-
52
- Time.iso8601(output).to_i
53
- rescue
54
- Time.now.to_i
55
- end
56
- end
@@ -1,13 +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
- class SystemAppearance
9
- def self.dark?
10
- result = `osascript -e 'tell application "System Events" to tell appearance preferences to get dark mode'`.strip
11
- result == "true"
12
- end
13
- end
@@ -1,138 +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 "window_id"
9
- require_relative "preview_timing"
10
-
11
- class TerminalWindow
12
- CTRL_C = "ASCII character 3"
13
-
14
- def initialize(launcher_script_path, pid_file)
15
- @launcher_script_path = launcher_script_path
16
- @pid_file = pid_file
17
- @window_id = nil
18
- end
19
-
20
- def open
21
- setup_script = <<~APPLESCRIPT
22
- tell application "Terminal"
23
- set newTab to do script "#{@launcher_script_path}"
24
- set currentWindow to window 1
25
-
26
- set number of rows of currentWindow to 24
27
- set number of columns of currentWindow to 80
28
- set position of currentWindow to {100, 100}
29
- set frontmost of currentWindow to true
30
-
31
- return id of currentWindow
32
- end tell
33
- APPLESCRIPT
34
-
35
- @window_id = WindowID.new(`osascript -e '#{setup_script}'`.strip)
36
- wait_for_startup
37
- yield self
38
- ensure
39
- close if @window_id
40
- end
41
-
42
- def window_id
43
- @window_id
44
- end
45
-
46
- private def close
47
- try_graceful_shutdown
48
- kill_process if process_still_alive?
49
-
50
- delay_script = <<~APPLESCRIPT
51
- tell application "Terminal"
52
- delay #{PreviewTiming.close_delay}
53
-
54
- try
55
- close window id #{@window_id}
56
- end try
57
- end tell
58
- APPLESCRIPT
59
-
60
- system("osascript", "-e", delay_script, out: File::NULL, err: File::NULL)
61
- end
62
-
63
- private def wait_for_startup
64
- sleep PreviewTiming.window_startup
65
-
66
- unless @window_id.valid?
67
- raise "Failed to open terminal window"
68
- end
69
-
70
- unless process_running?
71
- error_output = contents
72
- raise error_output
73
- end
74
- end
75
-
76
- private def try_graceful_shutdown
77
- shutdown_script = <<~APPLESCRIPT
78
- tell application "Terminal"
79
- try
80
- do script (#{CTRL_C}) in window id #{@window_id}
81
- end try
82
- end tell
83
- APPLESCRIPT
84
-
85
- system("osascript", "-e", shutdown_script, out: File::NULL, err: File::NULL)
86
- sleep 0.2
87
- end
88
-
89
- private def process_still_alive?
90
- return false unless @pid_file && File.exist?(@pid_file)
91
-
92
- pid = File.read(@pid_file).strip.to_i
93
- Process.kill(0, pid)
94
- true
95
- rescue Errno::ESRCH, Errno::ENOENT
96
- false
97
- end
98
-
99
- private def kill_process
100
- return unless @pid_file && File.exist?(@pid_file)
101
-
102
- pid = File.read(@pid_file).strip.to_i
103
- Process.kill("TERM", pid)
104
- rescue Errno::ESRCH, Errno::ENOENT
105
- # Process already gone or PID file doesn't exist
106
- end
107
-
108
- private def process_running?
109
- check_script = <<~APPLESCRIPT
110
- tell application "Terminal"
111
- try
112
- set theWindow to window id #{@window_id}
113
- return busy of theWindow
114
- on error
115
- return false
116
- end try
117
- end tell
118
- APPLESCRIPT
119
-
120
- result = `osascript -e '#{check_script}'`.strip
121
- result == "true"
122
- end
123
-
124
- private def contents
125
- read_script = <<~APPLESCRIPT
126
- tell application "Terminal"
127
- try
128
- set theWindow to window id #{@window_id}
129
- return contents of selected tab of theWindow
130
- on error
131
- return ""
132
- end try
133
- end tell
134
- APPLESCRIPT
135
-
136
- `osascript -e '#{read_script}'`
137
- end
138
- end
@@ -1,16 +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
- class WindowID < Data.define(:value)
9
- def valid?
10
- !value.empty? && value.match?(/^\d+$/)
11
- end
12
-
13
- def to_s
14
- value
15
- end
16
- end