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/lint.rake DELETED
@@ -1,170 +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 "rubocop/rake_task"
9
- require "rubycritic/rake_task"
10
- require "inch/rake"
11
-
12
- RuboCop::RakeTask.new
13
-
14
- # Run rubycritic in a shell to prevent it from exiting the rake process
15
- task :rubycritic do
16
- sh "bundle exec rubycritic --no-browser exe lib sig"
17
- end
18
-
19
- Inch::Rake::Suggest.new("doc:suggest", "exe/**/*.rb", "lib/**/*.rb", "sig/**/*.rbs") do |suggest|
20
- suggest.args << ""
21
- end
22
-
23
- namespace :cargo do
24
- desc "Run cargo fmt"
25
- task :fmt do
26
- sh "cd ext/ratatui_ruby && cargo fmt --all -- --check"
27
- end
28
-
29
- desc "Run cargo clippy"
30
- task :clippy do
31
- sh "cd ext/ratatui_ruby && cargo clippy -- -D warnings"
32
- end
33
- end
34
-
35
- namespace :reuse do
36
- desc "Run the REUSE Tool to confirm REUSE compliance"
37
- task :lint do
38
- sh "reuse lint"
39
- end
40
-
41
- desc "Add SPDX headers to files missing them (per AGENTS.md standards)"
42
- task :fix do
43
- copyright = "Kerrick Long <me@kerricklong.com>"
44
-
45
- # Code files: AGPL-3.0-or-later
46
- code_extensions = %w[rb rs rake gemspec rbs toml yml yaml json lock].freeze
47
- code_license = "AGPL-3.0-or-later"
48
-
49
- # Documentation files: CC-BY-SA-4.0
50
- doc_extensions = %w[md txt].freeze
51
- doc_license = "CC-BY-SA-4.0"
52
-
53
- # Find files missing headers (listed after "no copyright and licensing" message)
54
- puts "Checking for files missing REUSE headers..."
55
- output = `reuse lint 2>&1`
56
- in_missing_section = false
57
- missing_files = output.lines.filter_map do |line|
58
- in_missing_section = true if line.include?("no copyright and licensing")
59
- in_missing_section = false if line.start_with?("# ") && !line.include?("copyright")
60
- next unless in_missing_section
61
-
62
- line.match(/^\* (.+)/)&.[](1)
63
- end
64
-
65
- if missing_files.empty?
66
- puts "All files have REUSE headers!"
67
- else
68
- missing_files.each do |file|
69
- ext = File.extname(file).delete(".")
70
- license = if code_extensions.include?(ext)
71
- code_license
72
- elsif doc_extensions.include?(ext)
73
- doc_license
74
- else
75
- puts " Skipping #{file} (unknown extension: .#{ext})"
76
- next
77
- end
78
-
79
- puts " Annotating #{file} with #{license}"
80
- sh "reuse annotate --license #{license} --copyright '#{copyright}' --skip-existing '#{file}'", verbose: false
81
- end
82
- end
83
- end
84
-
85
- desc "Normalize Ruby files: frozen_string_literal at top, SPDX in #--/#++ block"
86
- task :normalize_ruby do
87
- ruby_extensions = %w[rb rake gemspec].freeze
88
- # Exclude intentionally-formatted files
89
- excluded_files = %w[examples/verify_website_menu/app.rb].freeze
90
- ruby_files = Dir.glob("**/*.{#{ruby_extensions.join(',')}}")
91
- .reject { |f| f.start_with?("vendor/", "tmp/", ".") || excluded_files.include?(f) }
92
-
93
- fixed_count = 0
94
- ruby_files.each do |file|
95
- content = File.read(file)
96
- original = content.dup
97
-
98
- # Skip if no SPDX header
99
- next unless content.match?(/# SPDX-/)
100
-
101
- # Extract components
102
- frozen = content.match?(/^# frozen_string_literal: true/)
103
- spdx_match = content.match(/(# SPDX-FileCopyrightText:[^\n]+\n(?:#[^\n]*\n)*# SPDX-License-Identifier:[^\n]+\n)/m)
104
- next unless spdx_match
105
-
106
- spdx_block = spdx_match[1]
107
-
108
- # Remove existing frozen_string_literal and SPDX block (and any #--/#+++)
109
- cleaned = content
110
- .sub(/^# frozen_string_literal: true\n+/, "")
111
- .sub(/^#--\s*\n/, "")
112
- .sub(spdx_block, "")
113
- .sub(/^#\+\+\s*\n/, "")
114
- .sub(/\A\n+/, "") # Remove leading blank lines
115
-
116
- # Rebuild file in correct order: frozen, blank, #--, SPDX, #++, rest
117
- new_content = ""
118
- new_content += "# frozen_string_literal: true\n\n" if frozen
119
- new_content += "#--\n#{spdx_block}#++\n\n"
120
- new_content += cleaned.sub(/\A\n+/, "") # Ensure no double blank lines
121
-
122
- if new_content != original
123
- File.write(file, new_content)
124
- puts " Normalized #{file}"
125
- fixed_count += 1
126
- end
127
- end
128
-
129
- puts fixed_count.zero? ? "All Ruby files properly normalized!" : "Fixed #{fixed_count} files."
130
- end
131
- end
132
- task(:reuse) { Rake::Task["reuse:lint"].invoke }
133
-
134
- namespace :lint do
135
- task :safe_rdoc_coverage do
136
- sh "bundle exec rake rdoc:coverage"
137
- end
138
-
139
- task docs: %w[autodoc rubycritic safe_rdoc_coverage reuse:lint]
140
- task code: %w[rubocop rubycritic cargo:fmt cargo:clippy cargo:test]
141
- task licenses: %w[reuse:lint]
142
- task all: %w[docs code licenses]
143
-
144
- namespace :fix do
145
- desc "Auto-fix RuboCop offenses (most aggressive)"
146
- task :rubocop do
147
- sh "bundle exec rubocop --autocorrect-all"
148
- end
149
-
150
- desc "Auto-fix Clippy warnings (most aggressive: --fix --allow-dirty --allow-staged)"
151
- task :clippy do
152
- sh "cd ext/ratatui_ruby && cargo clippy --fix --allow-dirty --allow-staged"
153
- end
154
-
155
- desc "Add SPDX headers and normalize Ruby file structure"
156
- task reuse: %w[reuse:fix reuse:normalize_ruby]
157
-
158
- desc "Run all auto-fix tasks"
159
- task all: %w[lint:fix:rubocop lint:fix:clippy lint:fix:reuse]
160
- end
161
- end
162
-
163
- desc "Run all lint auto-fix tasks"
164
- task("lint:fix") { Rake::Task["lint:fix:all"].invoke }
165
-
166
- # Aliases for convenience
167
- task "rubocop:autocorrect_all" => "lint:fix:rubocop"
168
-
169
- desc "Run all lint tasks"
170
- task(:lint) { Rake::Task["lint:all"].invoke }
@@ -1,52 +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 "ratatui_ruby"
9
-
10
- # Catalog of all key predicates sourced from Rust + Ruby generation.
11
- class PredicateCatalog < Data.define(:base_keys, :media_keys, :modifier_keys, :keyboard_modifiers)
12
- # ASCII printable characters that can be RBS method names (with backtick escaping)
13
- # Excludes: space (0x20), backtick (`), and characters that break RBS parser (:, etc.)
14
- RBS_INCOMPATIBLE = %w[` :].freeze
15
- CHARACTERS = (0x21..0x7E).map(&:chr).reject { |c| RBS_INCOMPATIBLE.include?(c) }.freeze
16
- # Function keys F1-F24 (conventional terminal range)
17
- FUNCTION_KEYS = (1..24).map { |n| "f#{n}" }.freeze
18
-
19
- def self.new
20
- data = RatatuiRuby._all_key_codes
21
- super(
22
- base_keys: data[:base_keys],
23
- media_keys: data[:media_keys],
24
- modifier_keys: data[:modifier_keys],
25
- keyboard_modifiers: data[:keyboard_modifiers]
26
- )
27
- end
28
-
29
- def characters = CHARACTERS
30
- def function_keys = FUNCTION_KEYS
31
-
32
- def all_base_codes
33
- base_keys + media_keys + modifier_keys + characters + function_keys
34
- end
35
-
36
- def modifier_combinations
37
- mods = keyboard_modifiers.sort # Modifiers are stored sorted alphabetically
38
- one = mods.map { |m| [m] }
39
- two = mods.combination(2).map(&:sort)
40
- three = mods.combination(3).map(&:sort)
41
- one + two + three
42
- end
43
-
44
- def all_predicates
45
- simple = all_base_codes
46
- combined = modifier_combinations.flat_map do |combo|
47
- prefix = combo.join("_")
48
- all_base_codes.map { |key| "#{prefix}_#{key}" }
49
- end
50
- simple + combined
51
- end
52
- end
@@ -1,124 +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
-
10
- # The generated Minitest file for Event::Key predicates.
11
- # The tests know how to persist themselves to disk.
12
- class PredicateTests < Data.define(:catalog, :output_path)
13
- DEFAULT_OUTPUT = File.expand_path("../../test/generated/event_key_predicates_test.rb", __dir__)
14
-
15
- def initialize(catalog:, output_path: DEFAULT_OUTPUT)
16
- super
17
- end
18
-
19
- def persist!
20
- FileUtils.mkdir_p(File.dirname(output_path))
21
- File.write(output_path, to_ruby)
22
- puts "Generated #{test_methods.size} tests to #{output_path}"
23
- end
24
-
25
- def to_ruby
26
- <<~RUBY
27
- # frozen_string_literal: true
28
-
29
- #--
30
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
31
- # SPDX-License-Identifier: AGPL-3.0-or-later
32
- #++
33
-
34
- # \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
35
- # \u2551 \u26a0\ufe0f DO NOT EDIT THIS FILE \u26a0\ufe0f \u2551
36
- # \u2551 \u2551
37
- # \u2551 This file is auto-generated by: rake rbs:tests \u2551
38
- # \u2551 Any manual changes will be overwritten on next generation. \u2551
39
- # \u2551 \u2551
40
- # \u2551 To modify tests, edit: tasks/rbs_predicates/predicate_tests.rb \u2551
41
- # \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255d
42
-
43
- require "test_helper"
44
-
45
- class GeneratedEventKeyPredicatesTest < Minitest::Test
46
- include RatatuiRuby::TestHelper
47
-
48
- #{test_methods.map { |t| t.to_s.gsub(/^/, ' ') }.join("\n\n")}
49
- end
50
- RUBY
51
- end
52
-
53
- private def test_methods
54
- simple_tests + combo_tests
55
- end
56
-
57
- private def simple_tests
58
- catalog.all_base_codes.map { |code| SimplePredicateTest.new(code) }
59
- end
60
-
61
- private def combo_tests
62
- sampled_combos.map { |combo| ModifierComboTest.new(combo) }
63
- end
64
-
65
- private def sampled_combos
66
- sample_keys = %w[a enter up f1]
67
- catalog.modifier_combinations.product(sample_keys).map { |mods, key| mods + [key] }
68
- end
69
-
70
- # A single predicate test that knows how to render itself.
71
- class SimplePredicateTest < Data.define(:code)
72
- VALID_IDENTIFIER = /\A[a-z_][a-z0-9_]*\?\z/i
73
-
74
- def to_s
75
- <<~RUBY.chomp
76
- def test_#{method_name}_predicate
77
- RatatuiRuby.inject_test_event("key", { code: #{code.inspect} })
78
- event = RatatuiRuby.poll_event
79
- #{assertion}
80
- end
81
- RUBY
82
- end
83
-
84
- private def predicate = "#{code}?"
85
- private def method_name = code.gsub(/[^a-z0-9_]/i) { |c| "_#{c.ord}_" }
86
-
87
- private def assertion
88
- if predicate.match?(VALID_IDENTIFIER)
89
- "assert event.#{predicate}"
90
- else
91
- "assert event.public_send(#{predicate.inspect})"
92
- end
93
- end
94
- end
95
-
96
- # A modifier + key combo test that knows how to render itself.
97
- class ModifierComboTest < Data.define(:combo)
98
- VALID_IDENTIFIER = /\A[a-z_][a-z0-9_]*\?\z/i
99
-
100
- def to_s
101
- <<~RUBY.chomp
102
- def test_#{method_name}_predicate
103
- RatatuiRuby.inject_test_event("key", { code: #{key.inspect}, modifiers: [#{mods_array}] })
104
- event = RatatuiRuby.poll_event
105
- #{assertion}
106
- end
107
- RUBY
108
- end
109
-
110
- private def key = combo.last
111
- private def mods = combo[0...-1]
112
- private def mods_array = mods.map(&:inspect).join(", ")
113
- private def predicate = "#{combo.join('_')}?"
114
- private def method_name = combo.join("_").gsub(/[^a-z0-9_]/i) { |c| "_#{c.ord}_" }
115
-
116
- private def assertion
117
- if predicate.match?(VALID_IDENTIFIER)
118
- "assert event.#{predicate}"
119
- else
120
- "assert event.public_send(#{predicate.inspect})"
121
- end
122
- end
123
- end
124
- end
@@ -1,63 +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
- # RBS signature file for Event::Key predicates.
9
- class RbsSignature < Data.define(:catalog, :output_path)
10
- DEFAULT_OUTPUT = File.expand_path("../../sig/generated/event_key_predicates.rbs", __dir__)
11
-
12
- def initialize(catalog:, output_path: DEFAULT_OUTPUT)
13
- super
14
- end
15
-
16
- def write
17
- FileUtils.mkdir_p(File.dirname(output_path))
18
- File.write(output_path, content)
19
- puts "Generated #{catalog.all_predicates.size} predicates to #{output_path}"
20
- end
21
-
22
- def content
23
- <<~RBS
24
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
25
- # SPDX-License-Identifier: LGPL-3.0-or-later
26
- #
27
- # ╔═══════════════════════════════════════════════════════════════════╗
28
- # ║ ⚠️ DO NOT EDIT THIS FILE ⚠️ ║
29
- # ║ ║
30
- # ║ This file is auto-generated by: rake rbs:predicates ║
31
- # ║ Any manual changes will be overwritten on next generation. ║
32
- # ║ ║
33
- # ║ To modify predicates, edit the source in: ║
34
- # ║ - ext/ratatui_ruby/src/events.rs (key mappings) ║
35
- # ║ - tasks/rbs_predicates/predicate_catalog.rb ║
36
- # ╚═══════════════════════════════════════════════════════════════════╝
37
-
38
- module RatatuiRuby
39
- class Event
40
- class Key < Event
41
- #{predicate_declarations.map { |d| " #{d}" }.join("\n")}
42
- end
43
- end
44
- end
45
- RBS
46
- end
47
-
48
- private def predicate_declarations
49
- catalog.all_predicates.map { |name| rbs_method_def(name) }
50
- end
51
-
52
- # Valid Ruby method identifier: starts with letter/underscore, followed by word chars, optional ?
53
- VALID_PREDICATE_PATTERN = /\A[a-z_][a-z0-9_]*\?\z/i
54
-
55
- def rbs_method_def(name)
56
- method_name = "#{name}?"
57
- if method_name.match?(VALID_PREDICATE_PATTERN)
58
- "def #{method_name}: () -> bool"
59
- else
60
- "def `#{method_name}`: () -> bool"
61
- end
62
- end
63
- end
@@ -1,31 +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
- # NOTE: Do NOT require predicate_catalog here - it requires ratatui_ruby,
9
- # which needs the native extension to be compiled first. Require inside tasks.
10
-
11
- namespace :rbs do
12
- desc "Generate RBS declarations for Event::Key predicates"
13
- task predicates: :compile do
14
- require_relative "rbs_predicates/predicate_catalog"
15
- require_relative "rbs_predicates/rbs_signature"
16
-
17
- catalog = PredicateCatalog.new
18
- signature = RbsSignature.new(catalog)
19
- signature.write
20
- end
21
-
22
- desc "Generate Minitest assertions for Event::Key predicates"
23
- task tests: :compile do
24
- require_relative "rbs_predicates/predicate_catalog"
25
- require_relative "rbs_predicates/predicate_tests"
26
-
27
- catalog = PredicateCatalog.new
28
- tests = PredicateTests.new(catalog)
29
- tests.persist!
30
- end
31
- end
data/tasks/rdoc_config.rb DELETED
@@ -1,29 +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 RDocConfig
9
- MAX_FILE_SIZE = 100_000 # 100KB - skip large files like chat logs
10
-
11
- RDOC_FILES = Dir.glob(%w[
12
- doc/**/*.md
13
- examples/**/*.md
14
- *.md
15
- *.rdoc
16
- lib/**/*.rb
17
- exe/**/*
18
- ]).reject { |f|
19
- # Skip large files
20
- if File.size(f) > MAX_FILE_SIZE
21
- warn "RDoc: skipping #{f} (#{File.size(f) / 1024}KB > #{MAX_FILE_SIZE / 1024}KB limit)"
22
- next true
23
- end
24
- # Skip verification examples (internal testing, not user-facing)
25
- f.start_with?("examples/verify_")
26
- }.freeze
27
-
28
- MAIN = "README.md"
29
- end
@@ -1,60 +0,0 @@
1
- # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
2
- # SPDX-License-Identifier: AGPL-3.0-or-later
3
-
4
- image: archlinux
5
- packages:
6
- - bash
7
- - base-devel
8
- - curl
9
- - openssl
10
- - libyaml
11
- - zlib
12
- - readline
13
- - gdbm
14
- - ncurses
15
- - libffi
16
- <%- if has_rust -%>
17
- - clang
18
- <%- end -%>
19
- - git
20
- artifacts:
21
- - <%= gem_name %>/pkg/<%= gem_filename %>
22
- sources:
23
- - https://git.sr.ht/~kerrick/<%= gem_name %>
24
- tasks:
25
- - setup: |
26
- curl https://mise.jdx.dev/install.sh | sh
27
- echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.buildenv
28
- echo 'eval "$($HOME/.local/bin/mise activate bash)"' >> ~/.buildenv
29
- echo 'export LANG="en_US.UTF-8"' >> ~/.buildenv
30
- echo 'export LC_ALL="en_US.UTF-8"' >> ~/.buildenv
31
- <%- if has_rust -%>
32
- echo 'export BINDGEN_EXTRA_CLANG_ARGS="-include stdbool.h"' >> ~/.buildenv
33
- <%- end -%>
34
- . ~/.buildenv
35
- export CI="true"
36
- cd <%= gem_name %>
37
- sed -i 's/ruby = .*/ruby = "<%= ruby_version %>"/' mise.toml
38
- mise install
39
- mise x -- pip install reuse
40
- mise x -- gem install bundler:<%= bundler_version %>
41
- mise reshim
42
- mise x -- bundle config set --local frozen 'true'
43
- mise x -- bundle install
44
- <%- if has_rust -%>
45
- mise x -- bundle exec rake compile
46
- <%- end -%>
47
- - test: |
48
- . ~/.buildenv
49
- cd <%= gem_name %>
50
- echo "Testing Ruby <%= ruby_version %>"
51
- mise x -- bundle exec rake test
52
- - lint: |
53
- . ~/.buildenv
54
- cd <%= gem_name %>
55
- echo "Linting Ruby <%= ruby_version %>"
56
- mise x -- bundle exec rake lint
57
- - package: |
58
- . ~/.buildenv
59
- cd <%= gem_name %>
60
- mise x -- bundle exec rake build
@@ -1,141 +0,0 @@
1
- <!--
2
- SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
3
-
4
- SPDX-License-Identifier: AGPL-3.0-or-later
5
- -->
6
-
7
- <!DOCTYPE html>
8
- <html lang="en">
9
- <head>
10
- <meta charset="UTF-8">
11
- <title><%= project_name %> documentation</title>
12
- <meta name="viewport" content="width=device-width, initial-scale=1">
13
- <meta name="description" content="API documentation and guides for <%= project_name %>, organized by version.">
14
- <link rel="stylesheet" href="../styles.css">
15
- <link rel="preconnect" href="https://fonts.googleapis.com">
16
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
17
- <link
18
- href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300..900;1,9..144,300..900&family=Source+Sans+3:ital,wght@0,300..900;1,300..900&display=swap"
19
- rel="stylesheet">
20
- </head>
21
- <body>
22
- <header class="header">
23
- <div class="header__inner">
24
- <a href="/" class="header__brand">
25
- <img src="../logo-small.png" alt="RatatuiRuby Logo" class="header__logo" width="48" height="48">
26
- <span class="header__wordmark">RatatuiRuby</span>
27
- </a>
28
- <nav class="header__nav" aria-label="Primary">
29
- <a href="/#rich-moments">Better <abbr title="Command Line Interfaces">CLIs</abbr></a>
30
- <a href="/#build">Full <abbr title="Terminal User Interfaces">TUIs</abbr></a>
31
- <a href="/#frameworks">Frameworks</a>
32
- <a href="/docs/v0.10/" class="header__nav-external">API →</a>
33
- <a href="/docs/v0.10/doc/index_md.html" class="header__nav-external">Guides →</a>
34
- </nav>
35
- </div>
36
- </header>
37
-
38
- <main>
39
- <section class="section">
40
- <div class="section__inner">
41
- <header class="section__header">
42
- <span class="section__eyebrow">Reference</span>
43
- <h1 class="section__title">Documentation</h1>
44
- <p class="section__intro">API reference, guides, and examples for current and past versions of <%= project_name %>.</p>
45
- </header>
46
-
47
- <ul class="version-list">
48
- <% versions.each do |version| %>
49
- <li class="version-list__item<%= ' version-list__item--latest' if version.latest? %>">
50
- <a href="<%= version.slug %>/index.html" class="version-list__link">
51
- <span class="version-list__name"><%= version.name %></span>
52
- <span class="version-list__meta">
53
- <% if version.latest? %>
54
- Latest release via RubyGems
55
- <% elsif version.edge? %>
56
- Pre-release via git
57
- <% else %>
58
- Historical
59
- <% end %>
60
- </span>
61
- </a>
62
- </li>
63
- <% end %>
64
- </ul>
65
- </div>
66
- </section>
67
- </main>
68
-
69
- <footer class="footer">
70
- <div class="footer__inner">
71
- <!-- Megafooter columns -->
72
- <div class="footer__columns">
73
- <div class="footer__column">
74
- <h3 class="footer__heading">Get Started</h3>
75
- <ul class="footer__list">
76
- <li><a href="/docs/v0.10/doc/getting_started/quickstart_md.html">Quickstart <span
77
- class="footer__tag">Alpha</span></a>
78
- </li>
79
- <li><a href="/docs/v0.10/examples/app_cli_rich_moments/README_md.html">Examples</a></li>
80
- <li><a href="/docs/v0.10/"><abbr title="Application Programming Interface">API</abbr> Reference</a></li>
81
- <li><a href="/docs/v0.10/doc/index_md.html">Guides</a></li>
82
- </ul>
83
- </div>
84
-
85
- <div class="footer__column">
86
- <h3 class="footer__heading">Ecosystem</h3>
87
- <ul class="footer__list">
88
- <li><a href="https://git.sr.ht/~kerrick/ratatui_ruby-tea">Tea <span
89
- class="footer__tag">Alpha</span></a></li>
90
- <li><a href="https://sr.ht/~kerrick/ratatui_ruby/#chapter-3-the-object-path--kit">Kit <span
91
- class="footer__tag footer__tag--muted">Planned</span></a></li>
92
- <li><a href="https://sr.ht/~kerrick/ratatui_ruby/#chapter-5-the-framework">Framework <span
93
- class="footer__tag footer__tag--muted">Planned</span></a></li>
94
- <li><a href="https://sr.ht/~kerrick/ratatui_ruby/#chapter-6-licensing"><abbr
95
- title="User Interface">UI</abbr> Widgets
96
- <span class="footer__tag footer__tag--muted">Planned</span></a></li>
97
- </ul>
98
- </div>
99
-
100
- <div class="footer__column">
101
- <h3 class="footer__heading">Community</h3>
102
- <ul class="footer__list">
103
- <li><a href="https://lists.sr.ht/~kerrick/ratatui_ruby-discuss">Discuss and Chat</a></li>
104
- <li><a href="https://lists.sr.ht/~kerrick/ratatui_ruby-announce">Announcements</a></li>
105
- <li><a href="https://lists.sr.ht/~kerrick/ratatui_ruby-devel">Development</a></li>
106
- <li><a href="https://todo.sr.ht/~kerrick/ratatui_ruby">Bug Tracker</a></li>
107
- </ul>
108
- </div>
109
-
110
- <div class="footer__column">
111
- <h3 class="footer__heading">Contribute</h3>
112
- <ul class="footer__list">
113
- <li><a href="https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md">Contributing Guide</a></li>
114
- <li><a href="https://man.sr.ht/~kerrick/ratatui_ruby/code_of_conduct.md">Code of Conduct</a></li>
115
- <li><a href="https://man.sr.ht/~kerrick/ratatui_ruby/history/index.md">Project History</a></li>
116
- <li><a href="https://lists.sr.ht/~kerrick/ratatui_ruby-devel/patches">Pull Requests</a></li>
117
- </ul>
118
- </div>
119
- </div>
120
-
121
- <!-- Bottom bar -->
122
- <div class="footer__bottom">
123
- <div class="footer__brand">
124
- <img src="../logo-small.png" alt="" class="footer__logo" width="32" height="32" aria-hidden="true">
125
- <span class="footer__wordmark">RatatuiRuby</span>
126
- </div>
127
- <nav class="footer__meta" aria-label="Meta links">
128
- <a href="https://git.sr.ht/~kerrick/ratatui_ruby">Source</a>
129
- <a href="https://rubygems.org/gems/ratatui_ruby">RubyGems</a>
130
- <a href="https://ratatui.rs">Ratatui</a>
131
- <a href="https://builds.sr.ht/~kerrick/ratatui_ruby?">Build Status</a>
132
- </nav>
133
- <p class="footer__copy">© 2026&nbsp;Kerrick&nbsp;Long · Library:&nbsp;<a
134
- href="https://spdx.org/licenses/LGPL-3.0-or-later.html">LGPL-3.0-or-later</a> · Website:&nbsp;<a
135
- href="https://spdx.org/licenses/CC-BY-NC-ND-4.0.html">CC-BY-NC-ND-4.0</a> · Snippets:&nbsp;<a
136
- href="https://spdx.org/licenses/MIT-0.html">MIT-0</a></p>
137
- </div>
138
- </div>
139
- </footer>
140
- </body>
141
- </html>
@@ -1,7 +0,0 @@
1
- # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
2
- # SPDX-License-Identifier: AGPL-3.0-or-later
3
-
4
- - "3.2"
5
- - "3.3"
6
- - "3.4"
7
- - "4.0.0"