ratatui_ruby 1.4.0-x86_64-linux

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 (292) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +15 -0
  3. data/LICENSES/AGPL-3.0-or-later.txt +661 -0
  4. data/LICENSES/CC-BY-SA-4.0.txt +427 -0
  5. data/LICENSES/CC0-1.0.txt +121 -0
  6. data/LICENSES/LGPL-3.0-or-later.txt +304 -0
  7. data/LICENSES/MIT-0.txt +16 -0
  8. data/LICENSES/MIT.txt +21 -0
  9. data/REUSE.toml +42 -0
  10. data/exe/.gitkeep +0 -0
  11. data/ext/ratatui_ruby/.cargo/config.toml +13 -0
  12. data/ext/ratatui_ruby/.gitignore +4 -0
  13. data/ext/ratatui_ruby/Cargo.lock +1737 -0
  14. data/ext/ratatui_ruby/Cargo.toml +24 -0
  15. data/ext/ratatui_ruby/clippy.toml +7 -0
  16. data/ext/ratatui_ruby/extconf.rb +21 -0
  17. data/ext/ratatui_ruby/src/color.rs +82 -0
  18. data/ext/ratatui_ruby/src/errors.rs +28 -0
  19. data/ext/ratatui_ruby/src/events.rs +700 -0
  20. data/ext/ratatui_ruby/src/frame.rs +241 -0
  21. data/ext/ratatui_ruby/src/lib.rs +343 -0
  22. data/ext/ratatui_ruby/src/lib_header.rs +11 -0
  23. data/ext/ratatui_ruby/src/rendering.rs +158 -0
  24. data/ext/ratatui_ruby/src/string_width.rs +101 -0
  25. data/ext/ratatui_ruby/src/style.rs +469 -0
  26. data/ext/ratatui_ruby/src/terminal/capabilities.rs +46 -0
  27. data/ext/ratatui_ruby/src/terminal/init.rs +233 -0
  28. data/ext/ratatui_ruby/src/terminal/mod.rs +42 -0
  29. data/ext/ratatui_ruby/src/terminal/mutations.rs +158 -0
  30. data/ext/ratatui_ruby/src/terminal/queries.rs +231 -0
  31. data/ext/ratatui_ruby/src/terminal/query.rs +400 -0
  32. data/ext/ratatui_ruby/src/terminal/storage.rs +109 -0
  33. data/ext/ratatui_ruby/src/terminal/wrapper.rs +16 -0
  34. data/ext/ratatui_ruby/src/text.rs +225 -0
  35. data/ext/ratatui_ruby/src/widgets/barchart.rs +169 -0
  36. data/ext/ratatui_ruby/src/widgets/block.rs +41 -0
  37. data/ext/ratatui_ruby/src/widgets/calendar.rs +84 -0
  38. data/ext/ratatui_ruby/src/widgets/canvas.rs +183 -0
  39. data/ext/ratatui_ruby/src/widgets/center.rs +79 -0
  40. data/ext/ratatui_ruby/src/widgets/chart.rs +222 -0
  41. data/ext/ratatui_ruby/src/widgets/clear.rs +39 -0
  42. data/ext/ratatui_ruby/src/widgets/cursor.rs +32 -0
  43. data/ext/ratatui_ruby/src/widgets/gauge.rs +65 -0
  44. data/ext/ratatui_ruby/src/widgets/layout.rs +379 -0
  45. data/ext/ratatui_ruby/src/widgets/line_gauge.rs +100 -0
  46. data/ext/ratatui_ruby/src/widgets/list.rs +378 -0
  47. data/ext/ratatui_ruby/src/widgets/list_state.rs +173 -0
  48. data/ext/ratatui_ruby/src/widgets/mod.rs +26 -0
  49. data/ext/ratatui_ruby/src/widgets/overlay.rs +24 -0
  50. data/ext/ratatui_ruby/src/widgets/paragraph.rs +87 -0
  51. data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +40 -0
  52. data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +55 -0
  53. data/ext/ratatui_ruby/src/widgets/scrollbar.rs +214 -0
  54. data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
  55. data/ext/ratatui_ruby/src/widgets/sparkline.rs +127 -0
  56. data/ext/ratatui_ruby/src/widgets/table.rs +415 -0
  57. data/ext/ratatui_ruby/src/widgets/table_state.rs +203 -0
  58. data/ext/ratatui_ruby/src/widgets/tabs.rs +194 -0
  59. data/lib/ratatui_ruby/backend/window_size.rb +50 -0
  60. data/lib/ratatui_ruby/backend.rb +59 -0
  61. data/lib/ratatui_ruby/buffer/cell.rb +212 -0
  62. data/lib/ratatui_ruby/buffer.rb +149 -0
  63. data/lib/ratatui_ruby/cell.rb +208 -0
  64. data/lib/ratatui_ruby/debug.rb +215 -0
  65. data/lib/ratatui_ruby/draw.rb +63 -0
  66. data/lib/ratatui_ruby/event/focus_gained.rb +125 -0
  67. data/lib/ratatui_ruby/event/focus_lost.rb +127 -0
  68. data/lib/ratatui_ruby/event/key/character.rb +53 -0
  69. data/lib/ratatui_ruby/event/key/dwim.rb +301 -0
  70. data/lib/ratatui_ruby/event/key/media.rb +46 -0
  71. data/lib/ratatui_ruby/event/key/modifier.rb +107 -0
  72. data/lib/ratatui_ruby/event/key/navigation.rb +72 -0
  73. data/lib/ratatui_ruby/event/key/system.rb +47 -0
  74. data/lib/ratatui_ruby/event/key.rb +479 -0
  75. data/lib/ratatui_ruby/event/mouse.rb +291 -0
  76. data/lib/ratatui_ruby/event/none.rb +53 -0
  77. data/lib/ratatui_ruby/event/paste.rb +130 -0
  78. data/lib/ratatui_ruby/event/resize.rb +221 -0
  79. data/lib/ratatui_ruby/event/sync.rb +52 -0
  80. data/lib/ratatui_ruby/event.rb +163 -0
  81. data/lib/ratatui_ruby/frame.rb +257 -0
  82. data/lib/ratatui_ruby/labs/a11y.rb +182 -0
  83. data/lib/ratatui_ruby/labs/frame_a11y_capture.rb +50 -0
  84. data/lib/ratatui_ruby/labs.rb +47 -0
  85. data/lib/ratatui_ruby/layout/alignment.rb +91 -0
  86. data/lib/ratatui_ruby/layout/constraint.rb +337 -0
  87. data/lib/ratatui_ruby/layout/layout.rb +258 -0
  88. data/lib/ratatui_ruby/layout/position.rb +81 -0
  89. data/lib/ratatui_ruby/layout/rect.rb +733 -0
  90. data/lib/ratatui_ruby/layout/size.rb +62 -0
  91. data/lib/ratatui_ruby/layout.rb +29 -0
  92. data/lib/ratatui_ruby/list_state.rb +201 -0
  93. data/lib/ratatui_ruby/output_guard.rb +171 -0
  94. data/lib/ratatui_ruby/ratatui_ruby.so +0 -0
  95. data/lib/ratatui_ruby/scrollbar_state.rb +122 -0
  96. data/lib/ratatui_ruby/style/color.rb +149 -0
  97. data/lib/ratatui_ruby/style/style.rb +147 -0
  98. data/lib/ratatui_ruby/style.rb +19 -0
  99. data/lib/ratatui_ruby/symbols.rb +435 -0
  100. data/lib/ratatui_ruby/synthetic_events.rb +106 -0
  101. data/lib/ratatui_ruby/table_state.rb +251 -0
  102. data/lib/ratatui_ruby/terminal/capabilities.rb +316 -0
  103. data/lib/ratatui_ruby/terminal/viewport.rb +80 -0
  104. data/lib/ratatui_ruby/terminal.rb +66 -0
  105. data/lib/ratatui_ruby/terminal_lifecycle.rb +303 -0
  106. data/lib/ratatui_ruby/terminal_lifecycle.rb.bak +197 -0
  107. data/lib/ratatui_ruby/test_helper/event_injection.rb +241 -0
  108. data/lib/ratatui_ruby/test_helper/global_state.rb +111 -0
  109. data/lib/ratatui_ruby/test_helper/snapshot.rb +568 -0
  110. data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.ansi +24 -0
  111. data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.txt +24 -0
  112. data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.ansi +5 -0
  113. data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.txt +5 -0
  114. data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.ansi +24 -0
  115. data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.txt +24 -0
  116. data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.ansi +12 -0
  117. data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.txt +12 -0
  118. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.ansi +12 -0
  119. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.txt +12 -0
  120. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.ansi +12 -0
  121. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.txt +12 -0
  122. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.ansi +12 -0
  123. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.txt +12 -0
  124. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.ansi +12 -0
  125. data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.txt +12 -0
  126. data/lib/ratatui_ruby/test_helper/snapshots/my_snapshot.txt +1 -0
  127. data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.ansi +10 -0
  128. data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.txt +10 -0
  129. data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.ansi +10 -0
  130. data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.txt +10 -0
  131. data/lib/ratatui_ruby/test_helper/style_assertions.rb +449 -0
  132. data/lib/ratatui_ruby/test_helper/subprocess_timeout.rb +35 -0
  133. data/lib/ratatui_ruby/test_helper/terminal.rb +187 -0
  134. data/lib/ratatui_ruby/test_helper/test_doubles.rb +86 -0
  135. data/lib/ratatui_ruby/test_helper.rb +115 -0
  136. data/lib/ratatui_ruby/text/line.rb +245 -0
  137. data/lib/ratatui_ruby/text/span.rb +158 -0
  138. data/lib/ratatui_ruby/text.rb +99 -0
  139. data/lib/ratatui_ruby/tui/buffer_factories.rb +22 -0
  140. data/lib/ratatui_ruby/tui/canvas_factories.rb +149 -0
  141. data/lib/ratatui_ruby/tui/core.rb +67 -0
  142. data/lib/ratatui_ruby/tui/layout_factories.rb +153 -0
  143. data/lib/ratatui_ruby/tui/state_factories.rb +77 -0
  144. data/lib/ratatui_ruby/tui/style_factories.rb +22 -0
  145. data/lib/ratatui_ruby/tui/text_factories.rb +86 -0
  146. data/lib/ratatui_ruby/tui/widget_factories.rb +272 -0
  147. data/lib/ratatui_ruby/tui.rb +106 -0
  148. data/lib/ratatui_ruby/version.rb +12 -0
  149. data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +51 -0
  150. data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +29 -0
  151. data/lib/ratatui_ruby/widgets/bar_chart.rb +308 -0
  152. data/lib/ratatui_ruby/widgets/block.rb +266 -0
  153. data/lib/ratatui_ruby/widgets/calendar.rb +88 -0
  154. data/lib/ratatui_ruby/widgets/canvas.rb +297 -0
  155. data/lib/ratatui_ruby/widgets/cell.rb +59 -0
  156. data/lib/ratatui_ruby/widgets/center.rb +71 -0
  157. data/lib/ratatui_ruby/widgets/chart.rb +172 -0
  158. data/lib/ratatui_ruby/widgets/clear.rb +66 -0
  159. data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
  160. data/lib/ratatui_ruby/widgets/cursor.rb +54 -0
  161. data/lib/ratatui_ruby/widgets/gauge.rb +146 -0
  162. data/lib/ratatui_ruby/widgets/line_gauge.rb +158 -0
  163. data/lib/ratatui_ruby/widgets/list.rb +252 -0
  164. data/lib/ratatui_ruby/widgets/list_item.rb +55 -0
  165. data/lib/ratatui_ruby/widgets/overlay.rb +55 -0
  166. data/lib/ratatui_ruby/widgets/paragraph.rb +113 -0
  167. data/lib/ratatui_ruby/widgets/ratatui_logo.rb +35 -0
  168. data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +40 -0
  169. data/lib/ratatui_ruby/widgets/row.rb +123 -0
  170. data/lib/ratatui_ruby/widgets/scrollbar.rb +147 -0
  171. data/lib/ratatui_ruby/widgets/shape/label.rb +80 -0
  172. data/lib/ratatui_ruby/widgets/sparkline.rb +153 -0
  173. data/lib/ratatui_ruby/widgets/table.rb +213 -0
  174. data/lib/ratatui_ruby/widgets/tabs.rb +91 -0
  175. data/lib/ratatui_ruby/widgets.rb +43 -0
  176. data/lib/ratatui_ruby.rb +555 -0
  177. data/sig/examples/app_all_events/app.rbs +11 -0
  178. data/sig/examples/app_all_events/model/app_model.rbs +23 -0
  179. data/sig/examples/app_all_events/model/event_entry.rbs +23 -0
  180. data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
  181. data/sig/examples/app_all_events/view/app_view.rbs +8 -0
  182. data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
  183. data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
  184. data/sig/examples/app_all_events/view/live_view.rbs +6 -0
  185. data/sig/examples/app_all_events/view/log_view.rbs +6 -0
  186. data/sig/examples/app_all_events/view.rbs +14 -0
  187. data/sig/examples/app_cli_rich_moments/app.rbs +12 -0
  188. data/sig/examples/app_color_picker/app.rbs +17 -0
  189. data/sig/examples/app_external_editor/app.rbs +12 -0
  190. data/sig/examples/app_login_form/app.rbs +11 -0
  191. data/sig/examples/app_stateful_interaction/app.rbs +39 -0
  192. data/sig/examples/verify_quickstart_dsl/app.rbs +17 -0
  193. data/sig/examples/verify_quickstart_lifecycle/app.rbs +17 -0
  194. data/sig/examples/verify_readme_usage/app.rbs +17 -0
  195. data/sig/examples/widget_block_demo/app.rbs +38 -0
  196. data/sig/examples/widget_box_demo/app.rbs +17 -0
  197. data/sig/examples/widget_calendar_demo/app.rbs +17 -0
  198. data/sig/examples/widget_cell_demo/app.rbs +17 -0
  199. data/sig/examples/widget_chart_demo/app.rbs +17 -0
  200. data/sig/examples/widget_gauge_demo/app.rbs +17 -0
  201. data/sig/examples/widget_layout_split/app.rbs +16 -0
  202. data/sig/examples/widget_line_gauge_demo/app.rbs +17 -0
  203. data/sig/examples/widget_list_demo/app.rbs +17 -0
  204. data/sig/examples/widget_map_demo/app.rbs +17 -0
  205. data/sig/examples/widget_popup_demo/app.rbs +17 -0
  206. data/sig/examples/widget_ratatui_logo_demo/app.rbs +17 -0
  207. data/sig/examples/widget_ratatui_mascot_demo/app.rbs +17 -0
  208. data/sig/examples/widget_rect/app.rbs +18 -0
  209. data/sig/examples/widget_render/app.rbs +16 -0
  210. data/sig/examples/widget_rich_text/app.rbs +17 -0
  211. data/sig/examples/widget_scroll_text/app.rbs +17 -0
  212. data/sig/examples/widget_scrollbar_demo/app.rbs +17 -0
  213. data/sig/examples/widget_sparkline_demo/app.rbs +16 -0
  214. data/sig/examples/widget_style_colors/app.rbs +20 -0
  215. data/sig/examples/widget_table_demo/app.rbs +17 -0
  216. data/sig/examples/widget_text_width/app.rbs +16 -0
  217. data/sig/generated/event_key_predicates.rbs +1348 -0
  218. data/sig/manifest.yaml +5 -0
  219. data/sig/patches/data.rbs +26 -0
  220. data/sig/patches/debugger__.rbs +8 -0
  221. data/sig/ratatui_ruby/backend/window_size.rbs +17 -0
  222. data/sig/ratatui_ruby/backend.rbs +12 -0
  223. data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
  224. data/sig/ratatui_ruby/buffer.rbs +18 -0
  225. data/sig/ratatui_ruby/cell.rbs +44 -0
  226. data/sig/ratatui_ruby/clear.rbs +18 -0
  227. data/sig/ratatui_ruby/constraint.rbs +26 -0
  228. data/sig/ratatui_ruby/debug.rbs +45 -0
  229. data/sig/ratatui_ruby/draw.rbs +30 -0
  230. data/sig/ratatui_ruby/event.rbs +249 -0
  231. data/sig/ratatui_ruby/frame.rbs +23 -0
  232. data/sig/ratatui_ruby/interfaces.rbs +25 -0
  233. data/sig/ratatui_ruby/labs.rbs +90 -0
  234. data/sig/ratatui_ruby/layout/alignment.rbs +26 -0
  235. data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
  236. data/sig/ratatui_ruby/layout/layout.rbs +45 -0
  237. data/sig/ratatui_ruby/layout/position.rbs +18 -0
  238. data/sig/ratatui_ruby/layout/rect.rbs +64 -0
  239. data/sig/ratatui_ruby/layout/size.rbs +18 -0
  240. data/sig/ratatui_ruby/list_state.rbs +23 -0
  241. data/sig/ratatui_ruby/output_guard.rbs +23 -0
  242. data/sig/ratatui_ruby/ratatui_ruby.rbs +113 -0
  243. data/sig/ratatui_ruby/rect.rbs +17 -0
  244. data/sig/ratatui_ruby/scrollbar_state.rbs +24 -0
  245. data/sig/ratatui_ruby/session.rbs +93 -0
  246. data/sig/ratatui_ruby/style/color.rbs +22 -0
  247. data/sig/ratatui_ruby/style/style.rbs +29 -0
  248. data/sig/ratatui_ruby/symbols.rbs +141 -0
  249. data/sig/ratatui_ruby/synthetic_events.rbs +24 -0
  250. data/sig/ratatui_ruby/table_state.rbs +27 -0
  251. data/sig/ratatui_ruby/terminal/capabilities.rbs +38 -0
  252. data/sig/ratatui_ruby/terminal/viewport.rbs +33 -0
  253. data/sig/ratatui_ruby/terminal_lifecycle.rbs +39 -0
  254. data/sig/ratatui_ruby/test_helper/event_injection.rbs +22 -0
  255. data/sig/ratatui_ruby/test_helper/snapshot.rbs +37 -0
  256. data/sig/ratatui_ruby/test_helper/style_assertions.rbs +77 -0
  257. data/sig/ratatui_ruby/test_helper/terminal.rbs +20 -0
  258. data/sig/ratatui_ruby/test_helper/test_doubles.rbs +32 -0
  259. data/sig/ratatui_ruby/test_helper.rbs +18 -0
  260. data/sig/ratatui_ruby/text/line.rbs +27 -0
  261. data/sig/ratatui_ruby/text/span.rbs +23 -0
  262. data/sig/ratatui_ruby/text.rbs +12 -0
  263. data/sig/ratatui_ruby/tui/buffer_factories.rbs +16 -0
  264. data/sig/ratatui_ruby/tui/canvas_factories.rbs +38 -0
  265. data/sig/ratatui_ruby/tui/core.rbs +23 -0
  266. data/sig/ratatui_ruby/tui/layout_factories.rbs +39 -0
  267. data/sig/ratatui_ruby/tui/state_factories.rbs +23 -0
  268. data/sig/ratatui_ruby/tui/style_factories.rbs +18 -0
  269. data/sig/ratatui_ruby/tui/text_factories.rbs +23 -0
  270. data/sig/ratatui_ruby/tui/widget_factories.rbs +138 -0
  271. data/sig/ratatui_ruby/tui.rbs +25 -0
  272. data/sig/ratatui_ruby/version.rbs +12 -0
  273. data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
  274. data/sig/ratatui_ruby/widgets/block.rbs +51 -0
  275. data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
  276. data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
  277. data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
  278. data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
  279. data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
  280. data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
  281. data/sig/ratatui_ruby/widgets/list.rbs +63 -0
  282. data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
  283. data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
  284. data/sig/ratatui_ruby/widgets/row.rbs +43 -0
  285. data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
  286. data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
  287. data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
  288. data/sig/ratatui_ruby/widgets/table.rbs +78 -0
  289. data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
  290. data/sig/ratatui_ruby/widgets.rbs +16 -0
  291. data/vendor/goodcop/base.yml +1047 -0
  292. metadata +729 -0
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ class Event
10
+ # Signals that the application is in the background.
11
+ #
12
+ # The user has switched context. Your application is no longer the primary focus.
13
+ #
14
+ # This event warns of inactivity. It fires when the terminal window loses focus.
15
+ #
16
+ # Respond by conserving resources. Pause animations. Stop heavy polling. dim the UI to
17
+ # indicate a background state.
18
+ #
19
+ # Only supported by some terminals (e.g. iTerm2, Kitty, newer xterm).
20
+ #
21
+ # === Example
22
+ #
23
+ #--
24
+ # SPDX-SnippetBegin
25
+ # SPDX-FileCopyrightText: 2025 Kerrick Long
26
+ # SPDX-License-Identifier: MIT-0
27
+ #++
28
+ # if event.focus_lost?
29
+ # puts "Focus lost"
30
+ # end
31
+ #--
32
+ # SPDX-SnippetEnd
33
+ #++
34
+ class FocusLost < Event
35
+ # Returns true for FocusLost events.
36
+ #
37
+ #--
38
+ # SPDX-SnippetBegin
39
+ # SPDX-FileCopyrightText: 2025 Kerrick Long
40
+ # SPDX-License-Identifier: MIT-0
41
+ #++
42
+ # event.focus_lost? # => true
43
+ # event.key? # => false
44
+ #--
45
+ # SPDX-SnippetEnd
46
+ #++
47
+ def focus_lost?
48
+ true
49
+ end
50
+
51
+ # Deconstructs the event for pattern matching.
52
+ #
53
+ #--
54
+ # SPDX-SnippetBegin
55
+ # SPDX-FileCopyrightText: 2025 Kerrick Long
56
+ # SPDX-License-Identifier: MIT-0
57
+ #++
58
+ # case event
59
+ # in type: :focus_lost
60
+ # puts "Application lost focus"
61
+ # end
62
+ #--
63
+ # SPDX-SnippetEnd
64
+ #++
65
+ def deconstruct_keys(keys)
66
+ { type: :focus_lost }
67
+ end
68
+
69
+ ##
70
+ # Compares this event with another for equality.
71
+ def ==(other)
72
+ other.is_a?(FocusLost)
73
+ end
74
+
75
+ # =========================================================================
76
+ # DWIM Predicates
77
+ # =========================================================================
78
+
79
+ # Returns true. The terminal has lost focus (blur).
80
+ #
81
+ # event.blur? # => true
82
+ def blur?
83
+ true
84
+ end
85
+ alias blurred? blur?
86
+
87
+ # Returns true. The application lost focus.
88
+ #
89
+ # event.lost? # => true
90
+ def lost?
91
+ true
92
+ end
93
+ alias unfocused? lost?
94
+
95
+ # Returns false. This is not a focus gained event.
96
+ #
97
+ # event.focus? # => false
98
+ def focus?
99
+ false
100
+ end
101
+ alias focused? focus?
102
+
103
+ # Returns false. This is not a gained event.
104
+ #
105
+ # event.gained? # => false
106
+ def gained?
107
+ false
108
+ end
109
+
110
+ # Returns true. The application is inactive.
111
+ #
112
+ # event.inactive? # => true
113
+ def inactive?
114
+ true
115
+ end
116
+ alias background? inactive?
117
+
118
+ # Returns false. The application is not active.
119
+ #
120
+ # event.active? # => false
121
+ def active?
122
+ false
123
+ end
124
+ alias foreground? active?
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ class Event
10
+ class Key < Event
11
+ # Methods for handling printable characters.
12
+ module Character
13
+ # Returns true if the key represents a single printable character.
14
+ #
15
+ #--
16
+ # SPDX-SnippetBegin
17
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
18
+ # SPDX-License-Identifier: MIT-0
19
+ #++
20
+ # RatatuiRuby::Event::Key.new(code: "a").text? # => true
21
+ # RatatuiRuby::Event::Key.new(code: "enter").text? # => false
22
+ # RatatuiRuby::Event::Key.new(code: "space").text? # => false ("space" is not 1 char, " " is)
23
+ #--
24
+ # SPDX-SnippetEnd
25
+ #++
26
+ def text?
27
+ @code.length == 1
28
+ end
29
+
30
+ # Returns the key as a printable character (if applicable).
31
+ #
32
+ # [Printable Characters]
33
+ # Returns the character itself (e.g., <tt>"a"</tt>, <tt>"1"</tt>, <tt>" "</tt>).
34
+ # [Special Keys]
35
+ #--
36
+ # SPDX-SnippetBegin
37
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
38
+ # SPDX-License-Identifier: MIT-0
39
+ #++
40
+ # Returns <tt>nil</tt> (e.g., <tt>"enter"</tt>, <tt>"up"</tt>, <tt>"f1"</tt>).
41
+ #
42
+ # RatatuiRuby::Event::Key.new(code: "a").char # => "a"
43
+ # RatatuiRuby::Event::Key.new(code: "enter").char # => nil
44
+ #--
45
+ # SPDX-SnippetEnd
46
+ #++
47
+ def char
48
+ text? ? @code : nil
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,301 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ class Event
10
+ class Key < Event
11
+ # DWIM predicates for common key patterns.
12
+ #
13
+ # These predicates anticipate what developers intuitively try. Space bars,
14
+ # character categories, Unix signals, and Vim-style navigation.
15
+ module Dwim
16
+ # Returns true if the key is a space character.
17
+ #
18
+ # event.space? # => true for " "
19
+ def space?
20
+ @code == " " && @modifiers.empty?
21
+ end
22
+
23
+ alias spacebar? space?
24
+
25
+ # Returns true if the key is Enter. Alias for carriage return.
26
+ #
27
+ # event.cr? # => true for enter
28
+ def cr?
29
+ @code == "enter" && @modifiers.empty?
30
+ end
31
+
32
+ alias carriagereturn? cr?
33
+ alias linefeed? cr?
34
+ alias newline? cr?
35
+ alias lf? cr?
36
+
37
+ # Returns true if the key is a single letter (a-z, A-Z).
38
+ #
39
+ # Event::Key.new(code: "a").letter? # => true
40
+ def letter?
41
+ @code.length == 1 && @code.match?(/\A[A-Za-z]\z/)
42
+ end
43
+
44
+ # Returns true if the key is a digit (0-9).
45
+ #
46
+ # Event::Key.new(code: "5").digit? # => true
47
+ def digit?
48
+ @code.length == 1 && @code.match?(/\A[0-9]\z/)
49
+ end
50
+
51
+ # Returns true if the key is alphanumeric.
52
+ #
53
+ # Event::Key.new(code: "a").alphanumeric? # => true
54
+ def alphanumeric?
55
+ letter? || digit?
56
+ end
57
+
58
+ # Returns true if the key is punctuation.
59
+ #
60
+ # Event::Key.new(code: "@", modifiers: ["shift"]).punctuation? # => true
61
+ def punctuation?
62
+ return false unless @code.length == 1
63
+ !letter? && !digit? && !whitespace?
64
+ end
65
+
66
+ # Returns true if the key is whitespace (space, enter, tab).
67
+ #
68
+ # Event::Key.new(code: " ").whitespace? # => true
69
+ def whitespace?
70
+ @code == " " || @code == "enter" || @code == "tab"
71
+ end
72
+
73
+ # Returns true for interrupt (Ctrl+C).
74
+ #
75
+ # event.interrupt? # => true for Ctrl+C
76
+ def interrupt?
77
+ @code == "c" && @modifiers == ["ctrl"]
78
+ end
79
+
80
+ # Returns true for end-of-file (Ctrl+D).
81
+ #
82
+ # event.eof? # => true for Ctrl+D
83
+ def eof?
84
+ @code == "d" && @modifiers == ["ctrl"]
85
+ end
86
+
87
+ # Returns true for cancel (Esc or Ctrl+C).
88
+ #
89
+ # event.cancel? # => true for Esc or Ctrl+C
90
+ def cancel?
91
+ (@code == "esc" && @modifiers.empty?) || interrupt?
92
+ end
93
+
94
+ # Returns true for SIGINT (Ctrl+C).
95
+ #
96
+ # event.sigint? # => true for Ctrl+C
97
+ def sigint?
98
+ interrupt?
99
+ end
100
+
101
+ alias int? sigint?
102
+
103
+ # Returns true for SIGTSTP (Ctrl+Z) - suspend/stop.
104
+ #
105
+ # event.suspend? # => true for Ctrl+Z
106
+ def suspend?
107
+ @code == "z" && @modifiers == ["ctrl"]
108
+ end
109
+
110
+ alias sigtstp? suspend?
111
+ alias tstp? suspend?
112
+
113
+ # Returns true for SIGQUIT (Ctrl+\).
114
+ #
115
+ # event.quit? # => true for Ctrl+\
116
+ def quit?
117
+ @code == "\\" && @modifiers == ["ctrl"]
118
+ end
119
+
120
+ alias sigquit? quit?
121
+
122
+ NAVIGATION_KEYS = %w[up down left right home end page_up page_down].freeze # :nodoc:
123
+
124
+ # Returns true if key is a navigation key.
125
+ #
126
+ # Event::Key.new(code: "up").navigation? # => true
127
+ def navigation?
128
+ NAVIGATION_KEYS.include?(@code) && @modifiers.empty?
129
+ end
130
+
131
+ ARROW_KEYS = %w[up down left right].freeze # :nodoc:
132
+
133
+ # Returns true if key is an arrow key.
134
+ #
135
+ # Event::Key.new(code: "up").arrow? # => true
136
+ def arrow?
137
+ ARROW_KEYS.include?(@code) && @modifiers.empty?
138
+ end
139
+
140
+ VIM_MOVEMENT_KEYS = %w[h j k l w b g G].freeze # :nodoc:
141
+
142
+ # Returns true if key is a Vim movement key.
143
+ #
144
+ # Event::Key.new(code: "j").vim? # => true
145
+ def vim?
146
+ return true if VIM_MOVEMENT_KEYS.include?(@code) && @modifiers.empty?
147
+ @code == "G" && @modifiers == ["shift"]
148
+ end
149
+
150
+ # Returns true for Vim left (h).
151
+ def vim_left?
152
+ @code == "h" && @modifiers.empty?
153
+ end
154
+
155
+ # Returns true for Vim down (j).
156
+ def vim_down?
157
+ @code == "j" && @modifiers.empty?
158
+ end
159
+
160
+ # Returns true for Vim up (k).
161
+ def vim_up?
162
+ @code == "k" && @modifiers.empty?
163
+ end
164
+
165
+ # Returns true for Vim right (l).
166
+ def vim_right?
167
+ @code == "l" && @modifiers.empty?
168
+ end
169
+
170
+ # Returns true for Vim word forward (w).
171
+ def vim_word_forward?
172
+ @code == "w" && @modifiers.empty?
173
+ end
174
+
175
+ # Returns true for Vim word backward (b).
176
+ def vim_word_backward?
177
+ @code == "b" && @modifiers.empty?
178
+ end
179
+
180
+ # Returns true for Vim go to top (gg pattern, here just g).
181
+ def vim_top?
182
+ @code == "g" && @modifiers.empty?
183
+ end
184
+
185
+ # Returns true for Vim go to bottom (G).
186
+ def vim_bottom?
187
+ @code == "G" && @modifiers == ["shift"]
188
+ end
189
+
190
+ # Punctuation name predicates - generated at load time for performance.
191
+ # Maps intuitive names to their symbol characters.
192
+ # :nodoc:
193
+ PUNCTUATION_NAMES = {
194
+ # Navigation shortcuts (the original use case!)
195
+ tilde: "~",
196
+ slash: "/",
197
+ forwardslash: "/",
198
+ backslash: "\\",
199
+
200
+ # Common punctuation
201
+ comma: ",",
202
+ period: ".",
203
+ dot: ".",
204
+ colon: ":",
205
+ semicolon: ";",
206
+
207
+ # Question and exclamation
208
+ question: "?",
209
+ questionmark: "?",
210
+ exclamation: "!",
211
+ exclamationmark: "!",
212
+ exclamationpoint: "!",
213
+ bang: "!",
214
+
215
+ # Programming symbols
216
+ at: "@",
217
+ atsign: "@",
218
+ hash: "#",
219
+ pound: "#",
220
+ numbersign: "#",
221
+ dollar: "$",
222
+ dollarsign: "$",
223
+ percent: "%",
224
+ caret: "^",
225
+ circumflex: "^",
226
+ ampersand: "&",
227
+ asterisk: "*",
228
+ star: "*",
229
+
230
+ # Arithmetic and comparison
231
+ underscore: "_",
232
+ hyphen: "-",
233
+ dash: "-",
234
+ minus: "-",
235
+ plus: "+",
236
+ equals: "=",
237
+ equalsign: "=",
238
+ pipe: "|",
239
+ bar: "|",
240
+ lessthan: "<",
241
+ lt: "<",
242
+ greaterthan: ">",
243
+ gt: ">",
244
+
245
+ # Brackets and parens
246
+ lparen: "(",
247
+ leftparen: "(",
248
+ openparen: "(",
249
+ leftparenthesis: "(",
250
+ openparenthesis: "(",
251
+ rparen: ")",
252
+ rightparen: ")",
253
+ closeparen: ")",
254
+ rightparenthesis: ")",
255
+ closeparenthesis: ")",
256
+ lbracket: "[",
257
+ leftbracket: "[",
258
+ openbracket: "[",
259
+ leftsquarebracket: "[",
260
+ opensquarebracket: "[",
261
+ rbracket: "]",
262
+ rightbracket: "]",
263
+ closebracket: "]",
264
+ rightsquarebracket: "]",
265
+ closesquarebracket: "]",
266
+ lbrace: "{",
267
+ leftbrace: "{",
268
+ openbrace: "{",
269
+ leftcurlybrace: "{",
270
+ opencurlybrace: "{",
271
+ rbrace: "}",
272
+ rightbrace: "}",
273
+ closebrace: "}",
274
+ rightcurlybrace: "}",
275
+ closecurlybrace: "}",
276
+
277
+ # Quotes
278
+ backtick: "`",
279
+ grave: "`",
280
+ singlequote: "'",
281
+ apostrophe: "'",
282
+ doublequote: "\"",
283
+ }.freeze
284
+
285
+ # Generate predicate methods at load time (faster than method_missing)
286
+ PUNCTUATION_NAMES.each do |name, char|
287
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
288
+ def #{name}?
289
+ @code == #{char.inspect}
290
+ end
291
+ RUBY
292
+ end
293
+
294
+ # quote? matches both single and double quotes
295
+ def quote?
296
+ @code == "'" || @code == "\""
297
+ end
298
+ end
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ class Event
10
+ class Key < Event
11
+ # Methods and logic for media keys.
12
+ module Media
13
+ # Returns true if this is a media key.
14
+ #
15
+ # Media keys include: play, pause, stop, track controls, volume controls.
16
+ # These are only available in terminals supporting the Kitty keyboard protocol.
17
+ #
18
+ # event.media? # => true for media_play, media_pause, etc.
19
+ def media?
20
+ @kind == :media
21
+ end
22
+
23
+ # Handles media-specific DWIM logic for method_missing.
24
+ private def match_media_dwim?(key_name)
25
+ return false unless @kind == :media
26
+
27
+ # Allow unprefixed predicate
28
+ # e.g., pause? returns true for media_pause
29
+ if @code.start_with?("media_")
30
+ base_code = @code.delete_prefix("media_")
31
+ return true if key_name == base_code
32
+ end
33
+
34
+ # Bidirectional media overlaps
35
+ # e.g., play? and pause? both match media_play_pause
36
+ return true if @code == "media_play_pause" && (key_name == "play" || key_name == "pause")
37
+
38
+ # e.g., play_pause? matches media_play or media_pause
39
+ return true if key_name == "play_pause" && (@code == "media_play" || @code == "media_pause")
40
+
41
+ false
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ class Event
10
+ class Key < Event
11
+ # Methods and logic for modifier keys.
12
+ module Modifier
13
+ # Returns true if CTRL is held OR if this is a left_control/right_control key event.
14
+ def ctrl?
15
+ @modifiers.include?("ctrl") || @code == "left_control" || @code == "right_control"
16
+ end
17
+
18
+ # Alias for {#ctrl?}.
19
+ alias control? ctrl?
20
+
21
+ # Returns true if ALT is held OR if this is a left_alt/right_alt key event.
22
+ def alt?
23
+ @modifiers.include?("alt") || @code == "left_alt" || @code == "right_alt"
24
+ end
25
+
26
+ # Alias for {#alt?}.
27
+ alias option? alt?
28
+
29
+ # Returns true if SHIFT is held OR if this is a left_shift/right_shift key event.
30
+ def shift?
31
+ @modifiers.include?("shift") || @code == "left_shift" || @code == "right_shift"
32
+ end
33
+
34
+ # Returns true if SUPER is held OR if this is a left_super/right_super key event.
35
+ # Also responds to platform aliases: win?, command?, cmd?, tux?
36
+ def super?
37
+ @modifiers.include?("super") || @code == "left_super" || @code == "right_super"
38
+ end
39
+
40
+ # Alias for {#super?}.
41
+ alias win? super?
42
+ # Alias for {#super?}.
43
+ alias windows? super?
44
+ # Alias for {#super?}.
45
+ alias command? super?
46
+ # Alias for {#super?}.
47
+ alias cmd? super?
48
+ # Alias for {#super?}.
49
+ alias tux? super?
50
+
51
+ # Returns true if HYPER is held OR if this is a left_hyper/right_hyper key event.
52
+ def hyper?
53
+ @modifiers.include?("hyper") || @code == "left_hyper" || @code == "right_hyper"
54
+ end
55
+
56
+ # Returns true if META is held OR if this is a left_meta/right_meta key event.
57
+ def meta?
58
+ @modifiers.include?("meta") || @code == "left_meta" || @code == "right_meta"
59
+ end
60
+
61
+ # Returns true if this is a modifier key event.
62
+ #
63
+ # Some applications need to know if an event represents a generic key
64
+ # press or a specific modifier key (like CTRL or ALT) being pressed on
65
+ # its own.
66
+ #
67
+ # This method identifies if the key event itself is a modifier key.
68
+ #
69
+ # === Example
70
+ #
71
+ #--
72
+ # SPDX-SnippetBegin
73
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
74
+ # SPDX-License-Identifier: MIT-0
75
+ #++
76
+ # if event.modifier?
77
+ # # Handle solo modifier key press
78
+ # end
79
+ #--
80
+ # SPDX-SnippetEnd
81
+ #++
82
+ def modifier?
83
+ @kind == :modifier
84
+ end
85
+
86
+ # Handles modifier-specific DWIM logic for method_missing.
87
+ private def match_modifier_dwim?(key_name, key_sym)
88
+ # Platform modifier aliases
89
+ modifier_aliases = {
90
+ win: "super",
91
+ command: "super",
92
+ cmd: "super",
93
+ tux: "super",
94
+ }.freeze
95
+
96
+ target_modifier = modifier_aliases[key_sym]
97
+ if target_modifier
98
+ return true if @modifiers.include?(target_modifier)
99
+ return true if @code == "left_#{target_modifier}" || @code == "right_#{target_modifier}"
100
+ end
101
+
102
+ false
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ module RatatuiRuby
9
+ class Event
10
+ class Key < Event
11
+ # Methods and logic for navigation keys.
12
+ module Navigation
13
+ # Returns true if this is a standard key.
14
+ #
15
+ # Standard keys include: characters, Enter, Tab, arrow keys, navigation keys.
16
+ #
17
+ # event.standard? # => true for "a", "enter", "up", etc.
18
+ def standard?
19
+ @kind == :standard
20
+ end
21
+
22
+ # Alias for {#standard?}.
23
+ #
24
+ # Provided for semantic clarity when checking if a key has no special category.
25
+ #
26
+ # event.unmodified? # => true for standard keys like "a", "enter", "up"
27
+ alias unmodified? standard?
28
+
29
+ # Handles navigation-specific DWIM logic for method_missing.
30
+ private def match_navigation_dwim?(key_name, key_sym)
31
+ # DWIM: back_tab?/backtab? matches back_tab code even with shift modifier
32
+ # (since back_tab semantically implies shift)
33
+ if (key_name == "back_tab" || key_name == "backtab") && @code == "back_tab" && (@modifiers.empty? || @modifiers == ["shift"])
34
+ return true
35
+ end
36
+
37
+ # DWIM: reverse_tab? matches both BackTab key and Shift+Tab combo
38
+ if key_name == "reverse_tab"
39
+ return true if @code == "back_tab"
40
+ return true if @code == "tab" && @modifiers.include?("shift")
41
+ end
42
+ # DWIM: Check explicit aliases
43
+ navigation_aliases = {
44
+ # Arrow key aliases (disambiguate from Mouse#up? and Mouse#down?)
45
+ arrow_up: "up",
46
+ up_arrow: "up",
47
+ arrow_down: "down",
48
+ down_arrow: "down",
49
+ arrow_left: "left",
50
+ left_arrow: "left",
51
+ arrow_right: "right",
52
+ right_arrow: "right",
53
+ # Other navigation aliases
54
+ return: "enter",
55
+ back: "backspace",
56
+ del: "delete",
57
+ ins: "insert",
58
+ pgup: "page_up",
59
+ pageup: "page_up",
60
+ pgdn: "page_down",
61
+ pagedown: "page_down",
62
+ }.freeze
63
+
64
+ target_code = navigation_aliases[key_sym]
65
+ return true if target_code && @code == target_code && @modifiers.empty?
66
+
67
+ false
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end