ratatui_ruby 1.2.0 → 1.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df3052d1e97ee4b1fcb97693be22ad3f15a593f3c6fffe139e2758f2282bb44e
4
- data.tar.gz: '01178a70dc0e6c35da3d6dedde2b5e83826f054cb930dce773e6323ecdf1e2fc'
3
+ metadata.gz: 65cec825c4cedc983b69cfa150cf30bfc295b1aff70c4866dc18161e97207da0
4
+ data.tar.gz: '085eef207a3cb0d29e0992c1885ff788867387a725925d596bba309086ce6c2d'
5
5
  SHA512:
6
- metadata.gz: 96b4aae8eb4c72cccef740f701556a86a59f11c43eb5a432c9715dbfe5f80c05002727a2cd567d16f84d995a3357810b2bbeb29c577b06fd505fd8361b213199
7
- data.tar.gz: f833305d63b0def8e357ce8fbed452c3da62cf49afdd1d4ced9a1f1f1e181bc44fe628f8271c8be71e82440ef92a639a4cd035a010bdba3a98474fd02343ef95
6
+ metadata.gz: c3e69e5096a3d8790d6b81ec6a3fa0589565d5cbf3661f6bc78070c2ee91d29bd068fb5a31fe84e81364544e127e629f080faf6cb533d729fda58a18ed862ba1
7
+ data.tar.gz: 5deeb497d1c9663d7c35efee84f8d2ca8b501810772eaf57750f2d452939e0d45c7847b13d18f59943872e3c46f649141b1e9cce09fa2242f6593168c83d3922
data/.builds/ruby-3.2.yml CHANGED
@@ -16,7 +16,7 @@ packages:
16
16
  - clang
17
17
  - git
18
18
  artifacts:
19
- - ratatui_ruby/pkg/ratatui_ruby-1.2.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-1.3.0.gem
20
20
  sources:
21
21
  - https://git.sr.ht/~kerrick/ratatui_ruby
22
22
  tasks:
data/.builds/ruby-3.3.yml CHANGED
@@ -16,7 +16,7 @@ packages:
16
16
  - clang
17
17
  - git
18
18
  artifacts:
19
- - ratatui_ruby/pkg/ratatui_ruby-1.2.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-1.3.0.gem
20
20
  sources:
21
21
  - https://git.sr.ht/~kerrick/ratatui_ruby
22
22
  tasks:
data/.builds/ruby-3.4.yml CHANGED
@@ -16,7 +16,7 @@ packages:
16
16
  - clang
17
17
  - git
18
18
  artifacts:
19
- - ratatui_ruby/pkg/ratatui_ruby-1.2.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-1.3.0.gem
20
20
  sources:
21
21
  - https://git.sr.ht/~kerrick/ratatui_ruby
22
22
  tasks:
@@ -16,7 +16,7 @@ packages:
16
16
  - clang
17
17
  - git
18
18
  artifacts:
19
- - ratatui_ruby/pkg/ratatui_ruby-1.2.0.gem
19
+ - ratatui_ruby/pkg/ratatui_ruby-1.3.0.gem
20
20
  sources:
21
21
  - https://git.sr.ht/~kerrick/ratatui_ruby
22
22
  tasks:
data/CHANGELOG.md CHANGED
@@ -12,6 +12,23 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
12
12
 
13
13
  ### Added
14
14
 
15
+ ### Changed
16
+
17
+ ### Fixed
18
+
19
+ ### Removed
20
+
21
+ ## [1.3.0] - 2026-01-27
22
+
23
+ ### Added
24
+
25
+ - **Punctuation Name Predicates**: `Event::Key` now supports intuitive name-based predicates for symbol keys. Use `tilde?`, `slash?`, `backslash?`, `comma?`, `period?`/`dot?`, `colon?`, `semicolon?`, `question?`, `exclamation?`/`bang?`, `at?`, `hash?`/`pound?`, `dollar?`, `percent?`, `caret?`, `ampersand?`, `asterisk?`/`star?`, `underscore?`, `hyphen?`/`dash?`/`minus?`, `plus?`, `equals?`, `pipe?`/`bar?`, `lessthan?`/`lt?`, `greaterthan?`/`gt?`, bracket predicates (`lparen?`, `rparen?`, `lbracket?`, `rbracket?`, `lbrace?`, `rbrace?` and spelled-out variants like `left_parenthesis?`), and quote predicates (`backtick?`/`grave?`, `singlequote?`/`apostrophe?`, `doublequote?`, `quote?`). The `quote?` predicate matches both single and double quotes. Underscore variants (e.g., `at_sign?`, `less_than?`) are handled automatically via method normalization.
26
+ - **Mouse Event DWIM Predicates**: `Event::Mouse` now supports platform-neutral button predicates (`primary?`, `secondary?`, `context_menu?`, `aux?`/`auxiliary?`), wheel aliases (`wheel_up?`, `wheel_down?`, `scroll?`), movement predicates (`moved?`, `hover?`, `hovering?`, `move?`), press/release aliases (`press?`/`pressed?`, `release?`/`released?`), and a drag predicate (`dragging?`).
27
+ - **Resize Event DWIM Predicates**: `Event::Resize` now supports Unix signal aliases (`sigwinch?`, `winch?`, `sig_winch?`), orientation predicates (`landscape?`, `portrait?`), and VT100 terminal size predicates (`vt100?`, `at_least_vt100?`, `over_vt100?`, `cramped?`, `constrained?`).
28
+ - **Focus Event DWIM Predicates**: `Event::FocusGained` and `Event::FocusLost` now support symmetric predicates for intuitive focus handling. Both respond to `focus?`, `blur?`, `gained?`, `lost?`, `active?`, `inactive?`, `foreground?`, and `background?` with semantically correct boolean values.
29
+ - **Paste Event DWIM Predicates**: `Event::Paste` now supports content predicates (`empty?`, `blank?`, `multiline?`/`multi_line?`, `single_line?`/`singleline?`), clipboard aliases (`clipboard?`, `pasteboard?`), and a confirmation predicate (`pasted?`).
30
+
31
+
15
32
  ### Changed
16
33
 
17
34
  ### Fixed
@@ -30,6 +47,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
30
47
 
31
48
  ### Removed
32
49
 
50
+
51
+
33
52
  ## [1.1.0] - 2026-01-25
34
53
 
35
54
  ### Added
@@ -725,6 +744,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
725
744
  - **Testing Support**: Included `RatatuiRuby::TestHelper` and RSpec integration to make testing your TUI applications possible.
726
745
 
727
746
  [Unreleased]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/HEAD
747
+ [1.3.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v1.3.0
728
748
  [1.2.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v1.2.0
729
749
  [1.1.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v1.1.0
730
750
  [1.0.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v1.0.0
@@ -1059,7 +1059,7 @@ dependencies = [
1059
1059
 
1060
1060
  [[package]]
1061
1061
  name = "ratatui_ruby"
1062
- version = "1.2.0"
1062
+ version = "1.3.0"
1063
1063
  dependencies = [
1064
1064
  "bumpalo",
1065
1065
  "lazy_static",
@@ -3,7 +3,7 @@
3
3
 
4
4
  [package]
5
5
  name = "ratatui_ruby"
6
- version = "1.2.0"
6
+ version = "1.3.0"
7
7
  edition = "2021"
8
8
 
9
9
  [lib]
@@ -70,6 +70,56 @@ module RatatuiRuby
70
70
  def ==(other)
71
71
  other.is_a?(FocusGained)
72
72
  end
73
+
74
+ # =========================================================================
75
+ # DWIM Predicates
76
+ # =========================================================================
77
+
78
+ # Returns true. The terminal window is now in focus.
79
+ #
80
+ # event.focus? # => true
81
+ def focus?
82
+ true
83
+ end
84
+ alias focused? focus?
85
+
86
+ # Returns true. The application gained focus.
87
+ #
88
+ # event.gained? # => true
89
+ def gained?
90
+ true
91
+ end
92
+
93
+ # Returns false. This is not a focus lost event.
94
+ #
95
+ # event.lost? # => false
96
+ def lost?
97
+ false
98
+ end
99
+
100
+ # Returns false. Blur is the opposite of focus gained.
101
+ #
102
+ # event.blur? # => false
103
+ def blur?
104
+ false
105
+ end
106
+ alias blurred? blur?
107
+
108
+ # Returns true. The application is active.
109
+ #
110
+ # event.active? # => true
111
+ def active?
112
+ true
113
+ end
114
+ alias foreground? active?
115
+
116
+ # Returns false. The application is not inactive.
117
+ #
118
+ # event.inactive? # => false
119
+ def inactive?
120
+ false
121
+ end
122
+ alias background? inactive?
73
123
  end
74
124
  end
75
125
  end
@@ -71,6 +71,57 @@ module RatatuiRuby
71
71
  def ==(other)
72
72
  other.is_a?(FocusLost)
73
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?
74
125
  end
75
126
  end
76
127
  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
@@ -40,6 +40,8 @@ module RatatuiRuby
40
40
  # Alias for {#super?}.
41
41
  alias win? super?
42
42
  # Alias for {#super?}.
43
+ alias windows? super?
44
+ # Alias for {#super?}.
43
45
  alias command? super?
44
46
  # Alias for {#super?}.
45
47
  alias cmd? super?
@@ -6,6 +6,7 @@
6
6
  #++
7
7
 
8
8
  require_relative "key/character"
9
+ require_relative "key/dwim"
9
10
  require_relative "key/media"
10
11
  require_relative "key/modifier"
11
12
  require_relative "key/navigation"
@@ -88,6 +89,7 @@ module RatatuiRuby
88
89
  # These keys will not work in Terminal.app, iTerm2, or GNOME Terminal.
89
90
  class Key < Event
90
91
  include Character
92
+ include Dwim
91
93
  include Media
92
94
  include Modifier
93
95
  include Navigation
@@ -435,6 +437,13 @@ module RatatuiRuby
435
437
  normalized_code = @code.delete("_")
436
438
  return true if normalized_predicate == normalized_code && @modifiers.empty?
437
439
 
440
+ # DWIM: Underscore variants delegate to existing methods
441
+ # space_bar? → spacebar? → space?, sig_int? → sigint?
442
+ normalized_method = :"#{normalized_predicate}?"
443
+ if normalized_method != name && respond_to?(normalized_method)
444
+ return public_send(normalized_method)
445
+ end
446
+
438
447
  false
439
448
  else
440
449
  super
@@ -253,6 +253,39 @@ module RatatuiRuby
253
253
  else false
254
254
  end
255
255
  end
256
+
257
+ alias wheel_up? scroll_up?
258
+ alias wheel_down? scroll_down?
259
+
260
+ # Returns true for any scroll event.
261
+ #
262
+ # event.scroll? # => true for scroll_up or scroll_down
263
+ def scroll?
264
+ scroll_up? || scroll_down?
265
+ end
266
+
267
+ alias primary? left?
268
+ alias secondary? right?
269
+ alias context_menu? right?
270
+ alias aux? middle?
271
+ alias auxiliary? aux?
272
+
273
+ # Returns true for mouse movement without button press.
274
+ #
275
+ # event.moved? # => true for moved (no button)
276
+ def moved?
277
+ @kind == "moved"
278
+ end
279
+
280
+ alias hover? moved?
281
+ alias hovering? moved?
282
+ alias move? moved?
283
+ alias dragging? drag?
284
+
285
+ alias release? up?
286
+ alias released? up?
287
+ alias press? down?
288
+ alias pressed? down?
256
289
  end
257
290
  end
258
291
  end
@@ -67,6 +67,9 @@ module RatatuiRuby
67
67
  def paste?
68
68
  true
69
69
  end
70
+ alias clipboard? paste?
71
+ alias pasteboard? paste?
72
+ alias pasted? paste?
70
73
 
71
74
  # Creates a new Paste event.
72
75
  #
@@ -100,6 +103,28 @@ module RatatuiRuby
100
103
  return false unless other.is_a?(Paste)
101
104
  content == other.content
102
105
  end
106
+
107
+ # Returns true if the pasted content is empty.
108
+ def empty?
109
+ @content.empty?
110
+ end
111
+
112
+ # Returns true if the pasted content is empty or whitespace-only.
113
+ def blank?
114
+ @content.strip.empty?
115
+ end
116
+
117
+ # Returns true if the pasted content spans multiple lines.
118
+ def multiline?
119
+ @content.include?("\n")
120
+ end
121
+ alias multi_line? multiline?
122
+
123
+ # Returns true if the pasted content is a single line.
124
+ def single_line?
125
+ !multiline?
126
+ end
127
+ alias singleline? single_line?
103
128
  end
104
129
  end
105
130
  end
@@ -151,6 +151,71 @@ module RatatuiRuby
151
151
  else false
152
152
  end
153
153
  end
154
+
155
+ # Returns true. Unix <tt>SIGWINCH</tt> triggers terminal resize.
156
+ #
157
+ # event.sigwinch? # => true
158
+ def sigwinch?
159
+ true
160
+ end
161
+
162
+ alias winch? sigwinch?
163
+ alias sig_winch? sigwinch?
164
+
165
+ alias terminal_resize? resize?
166
+ alias window_resize? resize?
167
+ alias window_change? resize?
168
+ alias viewport_resize? resize?
169
+ alias viewport_change? resize?
170
+ alias size_change? resize?
171
+ alias resized? resize?
172
+
173
+ VT100_WIDTH = 80 # :nodoc:
174
+ VT100_HEIGHT = 24 # :nodoc:
175
+
176
+ # Returns true if width exceeds height.
177
+ #
178
+ # Event::Resize.new(width: 120, height: 24).landscape? # => true
179
+ def landscape?
180
+ @width > @height
181
+ end
182
+
183
+ # Returns true if height exceeds or equals width.
184
+ #
185
+ # Event::Resize.new(width: 40, height: 80).portrait? # => true
186
+ def portrait?
187
+ @height >= @width
188
+ end
189
+
190
+ # Returns true if dimensions are exactly 80x24.
191
+ #
192
+ # Event::Resize.new(width: 80, height: 24).vt100? # => true
193
+ def vt100?
194
+ @width == VT100_WIDTH && @height == VT100_HEIGHT
195
+ end
196
+
197
+ # Returns true if both dimensions meet or exceed 80x24.
198
+ #
199
+ # Event::Resize.new(width: 120, height: 40).at_least_vt100? # => true
200
+ def at_least_vt100?
201
+ @width >= VT100_WIDTH && @height >= VT100_HEIGHT
202
+ end
203
+
204
+ # Returns true if both dimensions exceed 80x24.
205
+ #
206
+ # Event::Resize.new(width: 81, height: 25).over_vt100? # => true
207
+ def over_vt100?
208
+ @width > VT100_WIDTH && @height > VT100_HEIGHT
209
+ end
210
+
211
+ # Returns true if either dimension falls below VT100 standard.
212
+ #
213
+ # Event::Resize.new(width: 60, height: 24).cramped? # => true
214
+ def cramped?
215
+ @width < VT100_WIDTH || @height < VT100_HEIGHT
216
+ end
217
+
218
+ alias constrained? cramped?
154
219
  end
155
220
  end
156
221
  end
@@ -8,5 +8,5 @@
8
8
  module RatatuiRuby
9
9
  # The version of the ratatui_ruby gem.
10
10
  # See https://semver.org/spec/v2.0.0.html
11
- VERSION = "1.2.0"
11
+ VERSION = "1.3.0"
12
12
  end
@@ -67,11 +67,46 @@ module RatatuiRuby
67
67
  private def match_system_dwim?: (String key_name, Symbol key_sym) -> bool
68
68
  end
69
69
 
70
+ # DWIM predicates for common key patterns
71
+ module Dwim
72
+ NAVIGATION_KEYS: Array[String]
73
+ ARROW_KEYS: Array[String]
74
+ VIM_MOVEMENT_KEYS: Array[String]
75
+ PUNCTUATION_NAMES: Hash[Symbol, String]
76
+
77
+ def space?: () -> bool
78
+ def cr?: () -> bool
79
+ def letter?: () -> bool
80
+ def digit?: () -> bool
81
+ def alphanumeric?: () -> bool
82
+ def punctuation?: () -> bool
83
+ def whitespace?: () -> bool
84
+ def interrupt?: () -> bool
85
+ def eof?: () -> bool
86
+ def cancel?: () -> bool
87
+ def sigint?: () -> bool
88
+ def suspend?: () -> bool
89
+ def quit?: () -> bool
90
+ def navigation?: () -> bool
91
+ def arrow?: () -> bool
92
+ def vim?: () -> bool
93
+ def vim_left?: () -> bool
94
+ def vim_down?: () -> bool
95
+ def vim_up?: () -> bool
96
+ def vim_right?: () -> bool
97
+ def vim_word_forward?: () -> bool
98
+ def vim_word_backward?: () -> bool
99
+ def vim_top?: () -> bool
100
+ def vim_bottom?: () -> bool
101
+ def quote?: () -> bool
102
+ end
103
+
70
104
  include Character
71
105
  include Modifier
72
106
  include Media
73
107
  include Navigation
74
108
  include System
109
+ include Dwim
75
110
 
76
111
  attr_reader code: String
77
112
  attr_reader modifiers: Array[String]
@@ -114,6 +149,23 @@ module RatatuiRuby
114
149
  def left?: () -> bool
115
150
  def right?: () -> bool
116
151
  def middle?: () -> bool
152
+ def scroll?: () -> bool
153
+ def moved?: () -> bool
154
+ def hover?: () -> bool
155
+ def hovering?: () -> bool
156
+ def move?: () -> bool
157
+ def primary?: () -> bool
158
+ def secondary?: () -> bool
159
+ def context_menu?: () -> bool
160
+ def aux?: () -> bool
161
+ def auxiliary?: () -> bool
162
+ def wheel_up?: () -> bool
163
+ def wheel_down?: () -> bool
164
+ def release?: () -> bool
165
+ def released?: () -> bool
166
+ def press?: () -> bool
167
+ def pressed?: () -> bool
168
+ def dragging?: () -> bool
117
169
  def to_sym: () -> Symbol
118
170
  def ==: (top other) -> bool
119
171
  def deconstruct_keys: (Array[Symbol]?) -> { type: :mouse, kind: String, x: Integer, y: Integer, button: String, modifiers: Array[String] }
@@ -127,6 +179,20 @@ module RatatuiRuby
127
179
  def to_sym: () -> Symbol
128
180
  def ==: (top other) -> bool
129
181
  def deconstruct_keys: (Array[Symbol]?) -> { type: :resize, width: Integer, height: Integer }
182
+
183
+ # DWIM predicates
184
+ VT100_WIDTH: Integer
185
+ VT100_HEIGHT: Integer
186
+ def sigwinch?: () -> bool
187
+ def winch?: () -> bool
188
+ def sig_winch?: () -> bool
189
+ def landscape?: () -> bool
190
+ def portrait?: () -> bool
191
+ def vt100?: () -> bool
192
+ def at_least_vt100?: () -> bool
193
+ def over_vt100?: () -> bool
194
+ def cramped?: () -> bool
195
+ def constrained?: () -> bool
130
196
  end
131
197
 
132
198
  class Paste < Event
@@ -134,14 +200,45 @@ module RatatuiRuby
134
200
 
135
201
  def initialize: (content: String) -> void
136
202
  def deconstruct_keys: (Array[Symbol]?) -> { type: :paste, content: String }
203
+
204
+ # DWIM predicates
205
+ def clipboard?: () -> bool
206
+ def pasteboard?: () -> bool
207
+ def pasted?: () -> bool
208
+ def empty?: () -> bool
209
+ def blank?: () -> bool
210
+ def multiline?: () -> bool
211
+ def multi_line?: () -> bool
212
+ def single_line?: () -> bool
213
+ def singleline?: () -> bool
137
214
  end
138
215
 
139
216
  class FocusGained < Event
140
217
  def deconstruct_keys: (Array[Symbol]?) -> { type: :focus_gained }
218
+
219
+ # DWIM predicates
220
+ def focus?: () -> bool
221
+ def gained?: () -> bool
222
+ def lost?: () -> bool
223
+ def blur?: () -> bool
224
+ def active?: () -> bool
225
+ def inactive?: () -> bool
226
+ def foreground?: () -> bool
227
+ def background?: () -> bool
141
228
  end
142
229
 
143
230
  class FocusLost < Event
144
231
  def deconstruct_keys: (Array[Symbol]?) -> { type: :focus_lost }
232
+
233
+ # DWIM predicates
234
+ def focus?: () -> bool
235
+ def gained?: () -> bool
236
+ def lost?: () -> bool
237
+ def blur?: () -> bool
238
+ def active?: () -> bool
239
+ def inactive?: () -> bool
240
+ def foreground?: () -> bool
241
+ def background?: () -> bool
145
242
  end
146
243
 
147
244
  class None < Event
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ratatui_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kerrick Long
@@ -660,6 +660,7 @@ files:
660
660
  - lib/ratatui_ruby/event/focus_lost.rb
661
661
  - lib/ratatui_ruby/event/key.rb
662
662
  - lib/ratatui_ruby/event/key/character.rb
663
+ - lib/ratatui_ruby/event/key/dwim.rb
663
664
  - lib/ratatui_ruby/event/key/media.rb
664
665
  - lib/ratatui_ruby/event/key/modifier.rb
665
666
  - lib/ratatui_ruby/event/key/navigation.rb