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.
- checksums.yaml +7 -0
- data/LICENSE +15 -0
- data/LICENSES/AGPL-3.0-or-later.txt +661 -0
- data/LICENSES/CC-BY-SA-4.0.txt +427 -0
- data/LICENSES/CC0-1.0.txt +121 -0
- data/LICENSES/LGPL-3.0-or-later.txt +304 -0
- data/LICENSES/MIT-0.txt +16 -0
- data/LICENSES/MIT.txt +21 -0
- data/REUSE.toml +42 -0
- data/exe/.gitkeep +0 -0
- data/ext/ratatui_ruby/.cargo/config.toml +13 -0
- data/ext/ratatui_ruby/.gitignore +4 -0
- data/ext/ratatui_ruby/Cargo.lock +1737 -0
- data/ext/ratatui_ruby/Cargo.toml +24 -0
- data/ext/ratatui_ruby/clippy.toml +7 -0
- data/ext/ratatui_ruby/extconf.rb +21 -0
- data/ext/ratatui_ruby/src/color.rs +82 -0
- data/ext/ratatui_ruby/src/errors.rs +28 -0
- data/ext/ratatui_ruby/src/events.rs +700 -0
- data/ext/ratatui_ruby/src/frame.rs +241 -0
- data/ext/ratatui_ruby/src/lib.rs +343 -0
- data/ext/ratatui_ruby/src/lib_header.rs +11 -0
- data/ext/ratatui_ruby/src/rendering.rs +158 -0
- data/ext/ratatui_ruby/src/string_width.rs +101 -0
- data/ext/ratatui_ruby/src/style.rs +469 -0
- data/ext/ratatui_ruby/src/terminal/capabilities.rs +46 -0
- data/ext/ratatui_ruby/src/terminal/init.rs +233 -0
- data/ext/ratatui_ruby/src/terminal/mod.rs +42 -0
- data/ext/ratatui_ruby/src/terminal/mutations.rs +158 -0
- data/ext/ratatui_ruby/src/terminal/queries.rs +231 -0
- data/ext/ratatui_ruby/src/terminal/query.rs +400 -0
- data/ext/ratatui_ruby/src/terminal/storage.rs +109 -0
- data/ext/ratatui_ruby/src/terminal/wrapper.rs +16 -0
- data/ext/ratatui_ruby/src/text.rs +225 -0
- data/ext/ratatui_ruby/src/widgets/barchart.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/block.rs +41 -0
- data/ext/ratatui_ruby/src/widgets/calendar.rs +84 -0
- data/ext/ratatui_ruby/src/widgets/canvas.rs +183 -0
- data/ext/ratatui_ruby/src/widgets/center.rs +79 -0
- data/ext/ratatui_ruby/src/widgets/chart.rs +222 -0
- data/ext/ratatui_ruby/src/widgets/clear.rs +39 -0
- data/ext/ratatui_ruby/src/widgets/cursor.rs +32 -0
- data/ext/ratatui_ruby/src/widgets/gauge.rs +65 -0
- data/ext/ratatui_ruby/src/widgets/layout.rs +379 -0
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +100 -0
- data/ext/ratatui_ruby/src/widgets/list.rs +378 -0
- data/ext/ratatui_ruby/src/widgets/list_state.rs +173 -0
- data/ext/ratatui_ruby/src/widgets/mod.rs +26 -0
- data/ext/ratatui_ruby/src/widgets/overlay.rs +24 -0
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +87 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +40 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +55 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +214 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +127 -0
- data/ext/ratatui_ruby/src/widgets/table.rs +415 -0
- data/ext/ratatui_ruby/src/widgets/table_state.rs +203 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +194 -0
- data/lib/ratatui_ruby/backend/window_size.rb +50 -0
- data/lib/ratatui_ruby/backend.rb +59 -0
- data/lib/ratatui_ruby/buffer/cell.rb +212 -0
- data/lib/ratatui_ruby/buffer.rb +149 -0
- data/lib/ratatui_ruby/cell.rb +208 -0
- data/lib/ratatui_ruby/debug.rb +215 -0
- data/lib/ratatui_ruby/draw.rb +63 -0
- data/lib/ratatui_ruby/event/focus_gained.rb +125 -0
- data/lib/ratatui_ruby/event/focus_lost.rb +127 -0
- data/lib/ratatui_ruby/event/key/character.rb +53 -0
- data/lib/ratatui_ruby/event/key/dwim.rb +301 -0
- data/lib/ratatui_ruby/event/key/media.rb +46 -0
- data/lib/ratatui_ruby/event/key/modifier.rb +107 -0
- data/lib/ratatui_ruby/event/key/navigation.rb +72 -0
- data/lib/ratatui_ruby/event/key/system.rb +47 -0
- data/lib/ratatui_ruby/event/key.rb +479 -0
- data/lib/ratatui_ruby/event/mouse.rb +291 -0
- data/lib/ratatui_ruby/event/none.rb +53 -0
- data/lib/ratatui_ruby/event/paste.rb +130 -0
- data/lib/ratatui_ruby/event/resize.rb +221 -0
- data/lib/ratatui_ruby/event/sync.rb +52 -0
- data/lib/ratatui_ruby/event.rb +163 -0
- data/lib/ratatui_ruby/frame.rb +257 -0
- data/lib/ratatui_ruby/labs/a11y.rb +182 -0
- data/lib/ratatui_ruby/labs/frame_a11y_capture.rb +50 -0
- data/lib/ratatui_ruby/labs.rb +47 -0
- data/lib/ratatui_ruby/layout/alignment.rb +91 -0
- data/lib/ratatui_ruby/layout/constraint.rb +337 -0
- data/lib/ratatui_ruby/layout/layout.rb +258 -0
- data/lib/ratatui_ruby/layout/position.rb +81 -0
- data/lib/ratatui_ruby/layout/rect.rb +733 -0
- data/lib/ratatui_ruby/layout/size.rb +62 -0
- data/lib/ratatui_ruby/layout.rb +29 -0
- data/lib/ratatui_ruby/list_state.rb +201 -0
- data/lib/ratatui_ruby/output_guard.rb +171 -0
- data/lib/ratatui_ruby/ratatui_ruby.so +0 -0
- data/lib/ratatui_ruby/scrollbar_state.rb +122 -0
- data/lib/ratatui_ruby/style/color.rb +149 -0
- data/lib/ratatui_ruby/style/style.rb +147 -0
- data/lib/ratatui_ruby/style.rb +19 -0
- data/lib/ratatui_ruby/symbols.rb +435 -0
- data/lib/ratatui_ruby/synthetic_events.rb +106 -0
- data/lib/ratatui_ruby/table_state.rb +251 -0
- data/lib/ratatui_ruby/terminal/capabilities.rb +316 -0
- data/lib/ratatui_ruby/terminal/viewport.rb +80 -0
- data/lib/ratatui_ruby/terminal.rb +66 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb +303 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb.bak +197 -0
- data/lib/ratatui_ruby/test_helper/event_injection.rb +241 -0
- data/lib/ratatui_ruby/test_helper/global_state.rb +111 -0
- data/lib/ratatui_ruby/test_helper/snapshot.rb +568 -0
- data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.ansi +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.txt +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.ansi +5 -0
- data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.txt +5 -0
- data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.ansi +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.txt +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/my_snapshot.txt +1 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.ansi +10 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.txt +10 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.ansi +10 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.txt +10 -0
- data/lib/ratatui_ruby/test_helper/style_assertions.rb +449 -0
- data/lib/ratatui_ruby/test_helper/subprocess_timeout.rb +35 -0
- data/lib/ratatui_ruby/test_helper/terminal.rb +187 -0
- data/lib/ratatui_ruby/test_helper/test_doubles.rb +86 -0
- data/lib/ratatui_ruby/test_helper.rb +115 -0
- data/lib/ratatui_ruby/text/line.rb +245 -0
- data/lib/ratatui_ruby/text/span.rb +158 -0
- data/lib/ratatui_ruby/text.rb +99 -0
- data/lib/ratatui_ruby/tui/buffer_factories.rb +22 -0
- data/lib/ratatui_ruby/tui/canvas_factories.rb +149 -0
- data/lib/ratatui_ruby/tui/core.rb +67 -0
- data/lib/ratatui_ruby/tui/layout_factories.rb +153 -0
- data/lib/ratatui_ruby/tui/state_factories.rb +77 -0
- data/lib/ratatui_ruby/tui/style_factories.rb +22 -0
- data/lib/ratatui_ruby/tui/text_factories.rb +86 -0
- data/lib/ratatui_ruby/tui/widget_factories.rb +272 -0
- data/lib/ratatui_ruby/tui.rb +106 -0
- data/lib/ratatui_ruby/version.rb +12 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +51 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +29 -0
- data/lib/ratatui_ruby/widgets/bar_chart.rb +308 -0
- data/lib/ratatui_ruby/widgets/block.rb +266 -0
- data/lib/ratatui_ruby/widgets/calendar.rb +88 -0
- data/lib/ratatui_ruby/widgets/canvas.rb +297 -0
- data/lib/ratatui_ruby/widgets/cell.rb +59 -0
- data/lib/ratatui_ruby/widgets/center.rb +71 -0
- data/lib/ratatui_ruby/widgets/chart.rb +172 -0
- data/lib/ratatui_ruby/widgets/clear.rb +66 -0
- data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
- data/lib/ratatui_ruby/widgets/cursor.rb +54 -0
- data/lib/ratatui_ruby/widgets/gauge.rb +146 -0
- data/lib/ratatui_ruby/widgets/line_gauge.rb +158 -0
- data/lib/ratatui_ruby/widgets/list.rb +252 -0
- data/lib/ratatui_ruby/widgets/list_item.rb +55 -0
- data/lib/ratatui_ruby/widgets/overlay.rb +55 -0
- data/lib/ratatui_ruby/widgets/paragraph.rb +113 -0
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +35 -0
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +40 -0
- data/lib/ratatui_ruby/widgets/row.rb +123 -0
- data/lib/ratatui_ruby/widgets/scrollbar.rb +147 -0
- data/lib/ratatui_ruby/widgets/shape/label.rb +80 -0
- data/lib/ratatui_ruby/widgets/sparkline.rb +153 -0
- data/lib/ratatui_ruby/widgets/table.rb +213 -0
- data/lib/ratatui_ruby/widgets/tabs.rb +91 -0
- data/lib/ratatui_ruby/widgets.rb +43 -0
- data/lib/ratatui_ruby.rb +555 -0
- data/sig/examples/app_all_events/app.rbs +11 -0
- data/sig/examples/app_all_events/model/app_model.rbs +23 -0
- data/sig/examples/app_all_events/model/event_entry.rbs +23 -0
- data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
- data/sig/examples/app_all_events/view/app_view.rbs +8 -0
- data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
- data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
- data/sig/examples/app_all_events/view/live_view.rbs +6 -0
- data/sig/examples/app_all_events/view/log_view.rbs +6 -0
- data/sig/examples/app_all_events/view.rbs +14 -0
- data/sig/examples/app_cli_rich_moments/app.rbs +12 -0
- data/sig/examples/app_color_picker/app.rbs +17 -0
- data/sig/examples/app_external_editor/app.rbs +12 -0
- data/sig/examples/app_login_form/app.rbs +11 -0
- data/sig/examples/app_stateful_interaction/app.rbs +39 -0
- data/sig/examples/verify_quickstart_dsl/app.rbs +17 -0
- data/sig/examples/verify_quickstart_lifecycle/app.rbs +17 -0
- data/sig/examples/verify_readme_usage/app.rbs +17 -0
- data/sig/examples/widget_block_demo/app.rbs +38 -0
- data/sig/examples/widget_box_demo/app.rbs +17 -0
- data/sig/examples/widget_calendar_demo/app.rbs +17 -0
- data/sig/examples/widget_cell_demo/app.rbs +17 -0
- data/sig/examples/widget_chart_demo/app.rbs +17 -0
- data/sig/examples/widget_gauge_demo/app.rbs +17 -0
- data/sig/examples/widget_layout_split/app.rbs +16 -0
- data/sig/examples/widget_line_gauge_demo/app.rbs +17 -0
- data/sig/examples/widget_list_demo/app.rbs +17 -0
- data/sig/examples/widget_map_demo/app.rbs +17 -0
- data/sig/examples/widget_popup_demo/app.rbs +17 -0
- data/sig/examples/widget_ratatui_logo_demo/app.rbs +17 -0
- data/sig/examples/widget_ratatui_mascot_demo/app.rbs +17 -0
- data/sig/examples/widget_rect/app.rbs +18 -0
- data/sig/examples/widget_render/app.rbs +16 -0
- data/sig/examples/widget_rich_text/app.rbs +17 -0
- data/sig/examples/widget_scroll_text/app.rbs +17 -0
- data/sig/examples/widget_scrollbar_demo/app.rbs +17 -0
- data/sig/examples/widget_sparkline_demo/app.rbs +16 -0
- data/sig/examples/widget_style_colors/app.rbs +20 -0
- data/sig/examples/widget_table_demo/app.rbs +17 -0
- data/sig/examples/widget_text_width/app.rbs +16 -0
- data/sig/generated/event_key_predicates.rbs +1348 -0
- data/sig/manifest.yaml +5 -0
- data/sig/patches/data.rbs +26 -0
- data/sig/patches/debugger__.rbs +8 -0
- data/sig/ratatui_ruby/backend/window_size.rbs +17 -0
- data/sig/ratatui_ruby/backend.rbs +12 -0
- data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
- data/sig/ratatui_ruby/buffer.rbs +18 -0
- data/sig/ratatui_ruby/cell.rbs +44 -0
- data/sig/ratatui_ruby/clear.rbs +18 -0
- data/sig/ratatui_ruby/constraint.rbs +26 -0
- data/sig/ratatui_ruby/debug.rbs +45 -0
- data/sig/ratatui_ruby/draw.rbs +30 -0
- data/sig/ratatui_ruby/event.rbs +249 -0
- data/sig/ratatui_ruby/frame.rbs +23 -0
- data/sig/ratatui_ruby/interfaces.rbs +25 -0
- data/sig/ratatui_ruby/labs.rbs +90 -0
- data/sig/ratatui_ruby/layout/alignment.rbs +26 -0
- data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
- data/sig/ratatui_ruby/layout/layout.rbs +45 -0
- data/sig/ratatui_ruby/layout/position.rbs +18 -0
- data/sig/ratatui_ruby/layout/rect.rbs +64 -0
- data/sig/ratatui_ruby/layout/size.rbs +18 -0
- data/sig/ratatui_ruby/list_state.rbs +23 -0
- data/sig/ratatui_ruby/output_guard.rbs +23 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +113 -0
- data/sig/ratatui_ruby/rect.rbs +17 -0
- data/sig/ratatui_ruby/scrollbar_state.rbs +24 -0
- data/sig/ratatui_ruby/session.rbs +93 -0
- data/sig/ratatui_ruby/style/color.rbs +22 -0
- data/sig/ratatui_ruby/style/style.rbs +29 -0
- data/sig/ratatui_ruby/symbols.rbs +141 -0
- data/sig/ratatui_ruby/synthetic_events.rbs +24 -0
- data/sig/ratatui_ruby/table_state.rbs +27 -0
- data/sig/ratatui_ruby/terminal/capabilities.rbs +38 -0
- data/sig/ratatui_ruby/terminal/viewport.rbs +33 -0
- data/sig/ratatui_ruby/terminal_lifecycle.rbs +39 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +22 -0
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +37 -0
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +77 -0
- data/sig/ratatui_ruby/test_helper/terminal.rbs +20 -0
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +32 -0
- data/sig/ratatui_ruby/test_helper.rbs +18 -0
- data/sig/ratatui_ruby/text/line.rbs +27 -0
- data/sig/ratatui_ruby/text/span.rbs +23 -0
- data/sig/ratatui_ruby/text.rbs +12 -0
- data/sig/ratatui_ruby/tui/buffer_factories.rbs +16 -0
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +38 -0
- data/sig/ratatui_ruby/tui/core.rbs +23 -0
- data/sig/ratatui_ruby/tui/layout_factories.rbs +39 -0
- data/sig/ratatui_ruby/tui/state_factories.rbs +23 -0
- data/sig/ratatui_ruby/tui/style_factories.rbs +18 -0
- data/sig/ratatui_ruby/tui/text_factories.rbs +23 -0
- data/sig/ratatui_ruby/tui/widget_factories.rbs +138 -0
- data/sig/ratatui_ruby/tui.rbs +25 -0
- data/sig/ratatui_ruby/version.rbs +12 -0
- data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
- data/sig/ratatui_ruby/widgets/block.rbs +51 -0
- data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
- data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
- data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
- data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
- data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
- data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
- data/sig/ratatui_ruby/widgets/list.rbs +63 -0
- data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
- data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
- data/sig/ratatui_ruby/widgets/row.rbs +43 -0
- data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
- data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
- data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
- data/sig/ratatui_ruby/widgets/table.rbs +78 -0
- data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
- data/sig/ratatui_ruby/widgets.rbs +16 -0
- data/vendor/goodcop/base.yml +1047 -0
- metadata +729 -0
|
@@ -0,0 +1,47 @@
|
|
|
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 system and function keys.
|
|
12
|
+
module System
|
|
13
|
+
# Returns true if this is a system key.
|
|
14
|
+
#
|
|
15
|
+
# System keys include: Esc, CapsLock, ScrollLock, NumLock, PrintScreen, Pause, Menu, KeypadBegin.
|
|
16
|
+
#
|
|
17
|
+
# event.system? # => true for pause, esc, caps_lock, etc.
|
|
18
|
+
def system?
|
|
19
|
+
@kind == :system
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns true if this is a function key (F1-F24).
|
|
23
|
+
#
|
|
24
|
+
# event.function? # => true for f1, f2, ..., f24
|
|
25
|
+
def function?
|
|
26
|
+
@kind == :function
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Handles system-specific DWIM logic for method_missing.
|
|
30
|
+
private def match_system_dwim?(key_name, key_sym)
|
|
31
|
+
system_aliases = {
|
|
32
|
+
scrlk: "scroll_lock",
|
|
33
|
+
scroll: "scroll_lock",
|
|
34
|
+
prtsc: "print_screen",
|
|
35
|
+
print: "print_screen",
|
|
36
|
+
escape: "esc",
|
|
37
|
+
}.freeze
|
|
38
|
+
|
|
39
|
+
target_code = system_aliases[key_sym]
|
|
40
|
+
return true if target_code && @code == target_code && @modifiers.empty?
|
|
41
|
+
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,479 @@
|
|
|
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
|
+
require_relative "key/character"
|
|
9
|
+
require_relative "key/dwim"
|
|
10
|
+
require_relative "key/media"
|
|
11
|
+
require_relative "key/modifier"
|
|
12
|
+
require_relative "key/navigation"
|
|
13
|
+
require_relative "key/system"
|
|
14
|
+
|
|
15
|
+
module RatatuiRuby
|
|
16
|
+
class Event
|
|
17
|
+
# Captures a keyboard interaction.
|
|
18
|
+
#
|
|
19
|
+
# The keyboard is the primary interface for your terminal application. Raw key codes are often cryptic,
|
|
20
|
+
# and handling modifiers manually is error-prone.
|
|
21
|
+
#
|
|
22
|
+
# This event creates clarity. It encapsulates the interaction, providing a normalized +code+ and
|
|
23
|
+
# a list of active +modifiers+.
|
|
24
|
+
#
|
|
25
|
+
# Compare it directly to strings or symbols for rapid development, or use pattern matching for
|
|
26
|
+
# complex control schemes.
|
|
27
|
+
#
|
|
28
|
+
# === Examples
|
|
29
|
+
#
|
|
30
|
+
# Using predicates:
|
|
31
|
+
#--
|
|
32
|
+
# SPDX-SnippetBegin
|
|
33
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
34
|
+
# SPDX-License-Identifier: MIT-0
|
|
35
|
+
#++
|
|
36
|
+
# if event.key? && event.ctrl? && event.code == "c"
|
|
37
|
+
# exit
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
#--
|
|
41
|
+
# SPDX-SnippetEnd
|
|
42
|
+
#++
|
|
43
|
+
# Using symbol comparison:
|
|
44
|
+
#--
|
|
45
|
+
# SPDX-SnippetBegin
|
|
46
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
47
|
+
# SPDX-License-Identifier: MIT-0
|
|
48
|
+
#++
|
|
49
|
+
# if event == :ctrl_c
|
|
50
|
+
# exit
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
#--
|
|
54
|
+
# SPDX-SnippetEnd
|
|
55
|
+
#++
|
|
56
|
+
# Using pattern matching:
|
|
57
|
+
#--
|
|
58
|
+
# SPDX-SnippetBegin
|
|
59
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
60
|
+
# SPDX-License-Identifier: MIT-0
|
|
61
|
+
#++
|
|
62
|
+
# case event
|
|
63
|
+
# in type: :key, code: "c", modifiers: ["ctrl"]
|
|
64
|
+
# exit
|
|
65
|
+
# end
|
|
66
|
+
#
|
|
67
|
+
#--
|
|
68
|
+
# SPDX-SnippetEnd
|
|
69
|
+
#++
|
|
70
|
+
# === Terminal Compatibility
|
|
71
|
+
#
|
|
72
|
+
# Some key combinations never reach your application. Terminal emulators intercept them for
|
|
73
|
+
# built-in features like tab switching. Common culprits:
|
|
74
|
+
#
|
|
75
|
+
# * Ctrl+PageUp/PageDown (tab switching in Terminal.app, iTerm2)
|
|
76
|
+
# * Ctrl+Tab (tab switching)
|
|
77
|
+
# * Cmd+key combinations (macOS system shortcuts)
|
|
78
|
+
#
|
|
79
|
+
# If modifiers appear missing, test with a different terminal. Kitty, WezTerm, and Alacritty
|
|
80
|
+
# pass more keys through. See <tt>doc/terminal_limitations.md</tt> for details.
|
|
81
|
+
#
|
|
82
|
+
# === Enhanced Keys (Kitty Protocol)
|
|
83
|
+
#
|
|
84
|
+
# Terminals supporting the Kitty keyboard protocol report additional keys:
|
|
85
|
+
#
|
|
86
|
+
# * Media keys: <tt>:play</tt>, <tt>:play_pause</tt>, <tt>:track_next</tt>, <tt>:mute_volume</tt>
|
|
87
|
+
# * Individual modifiers: <tt>:left_shift</tt>, <tt>:right_control</tt>, <tt>:left_super</tt>
|
|
88
|
+
#
|
|
89
|
+
# These keys will not work in Terminal.app, iTerm2, or GNOME Terminal.
|
|
90
|
+
class Key < Event
|
|
91
|
+
include Character
|
|
92
|
+
include Dwim
|
|
93
|
+
include Media
|
|
94
|
+
include Modifier
|
|
95
|
+
include Navigation
|
|
96
|
+
include System
|
|
97
|
+
|
|
98
|
+
# The key code (e.g., <tt>"a"</tt>, <tt>"enter"</tt>, <tt>"up"</tt>).
|
|
99
|
+
#
|
|
100
|
+
# puts event.code # => "enter"
|
|
101
|
+
attr_reader :code
|
|
102
|
+
|
|
103
|
+
# List of active modifiers (<tt>"ctrl"</tt>, <tt>"alt"</tt>, <tt>"shift"</tt>).
|
|
104
|
+
#
|
|
105
|
+
# puts event.modifiers # => ["ctrl", "shift"]
|
|
106
|
+
attr_reader :modifiers
|
|
107
|
+
|
|
108
|
+
# The category of the key.
|
|
109
|
+
#
|
|
110
|
+
# One of: <tt>:standard</tt>, <tt>:function</tt>, <tt>:media</tt>, <tt>:modifier</tt>, <tt>:system</tt>.
|
|
111
|
+
#
|
|
112
|
+
# This allows grouping keys by their logical type without parsing the code string.
|
|
113
|
+
#
|
|
114
|
+
# event.kind # => :media
|
|
115
|
+
attr_reader :kind
|
|
116
|
+
|
|
117
|
+
# Returns true for Key events.
|
|
118
|
+
#
|
|
119
|
+
#--
|
|
120
|
+
# SPDX-SnippetBegin
|
|
121
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
122
|
+
# SPDX-License-Identifier: MIT-0
|
|
123
|
+
#++
|
|
124
|
+
# event.key? # => true
|
|
125
|
+
# event.mouse? # => false
|
|
126
|
+
# event.resize? # => false
|
|
127
|
+
#--
|
|
128
|
+
# SPDX-SnippetEnd
|
|
129
|
+
#++
|
|
130
|
+
def key?
|
|
131
|
+
true
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Creates a new Key event.
|
|
135
|
+
#
|
|
136
|
+
# [code]
|
|
137
|
+
# The key code (String).
|
|
138
|
+
# [modifiers]
|
|
139
|
+
# List of modifiers (Array<String>).
|
|
140
|
+
# [kind]
|
|
141
|
+
#--
|
|
142
|
+
# SPDX-SnippetBegin
|
|
143
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
144
|
+
# SPDX-License-Identifier: MIT-0
|
|
145
|
+
#++
|
|
146
|
+
# The key category (Symbol). One of: <tt>:standard</tt>, <tt>:function</tt>,
|
|
147
|
+
# <tt>:media</tt>, <tt>:modifier</tt>, <tt>:system</tt>. Defaults to <tt>:standard</tt>.
|
|
148
|
+
#--
|
|
149
|
+
# SPDX-SnippetEnd
|
|
150
|
+
#++
|
|
151
|
+
def initialize(code:, modifiers: [], kind: :standard)
|
|
152
|
+
@code = code.freeze
|
|
153
|
+
@modifiers = modifiers.map(&:freeze).sort.freeze
|
|
154
|
+
@kind = kind
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Compares the event with another object.
|
|
158
|
+
#
|
|
159
|
+
# - If +other+ is a +Symbol+, compares against #to_sym.
|
|
160
|
+
# - If +other+ is a +String+, compares against #to_s.
|
|
161
|
+
# - If +other+ is a +Key+, compares as a value object.
|
|
162
|
+
# - Otherwise, compares using standard equality.
|
|
163
|
+
def ==(other)
|
|
164
|
+
case other
|
|
165
|
+
when Symbol
|
|
166
|
+
to_sym == other
|
|
167
|
+
when String
|
|
168
|
+
to_s == other
|
|
169
|
+
when Key
|
|
170
|
+
code == other.code && modifiers == other.modifiers
|
|
171
|
+
else
|
|
172
|
+
super
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Converts the event to a Symbol representation.
|
|
177
|
+
#
|
|
178
|
+
# The format is <tt>[modifiers_]code</tt>. Modifiers are sorted alphabetically (alt, ctrl, shift)
|
|
179
|
+
# and joined by underscores.
|
|
180
|
+
#
|
|
181
|
+
# === Supported Keys
|
|
182
|
+
#
|
|
183
|
+
# [Standard]
|
|
184
|
+
# <tt>:enter</tt>, <tt>:backspace</tt>, <tt>:tab</tt>, <tt>:back_tab</tt>, <tt>:esc</tt>, <tt>:null</tt>
|
|
185
|
+
# [Navigation]
|
|
186
|
+
#--
|
|
187
|
+
# SPDX-SnippetBegin
|
|
188
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
189
|
+
# SPDX-License-Identifier: MIT-0
|
|
190
|
+
#++
|
|
191
|
+
# <tt>:up</tt>, <tt>:down</tt>, <tt>:left</tt>, <tt>:right</tt>, <tt>:home</tt>, <tt>:end</tt>,
|
|
192
|
+
# <tt>:page_up</tt>, <tt>:page_down</tt>, <tt>:insert</tt>, <tt>:delete</tt>
|
|
193
|
+
#--
|
|
194
|
+
# SPDX-SnippetEnd
|
|
195
|
+
#++
|
|
196
|
+
# [Function Keys]
|
|
197
|
+
# <tt>:f1</tt> through <tt>:f12</tt> (and beyond, e.g. <tt>:f24</tt>)
|
|
198
|
+
# [Lock Keys]
|
|
199
|
+
# <tt>:caps_lock</tt>, <tt>:scroll_lock</tt>, <tt>:num_lock</tt>
|
|
200
|
+
# [System Keys]
|
|
201
|
+
# <tt>:print_screen</tt>, <tt>:pause</tt>, <tt>:menu</tt>, <tt>:keypad_begin</tt>
|
|
202
|
+
# [Media Keys]
|
|
203
|
+
#--
|
|
204
|
+
# SPDX-SnippetBegin
|
|
205
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
206
|
+
# SPDX-License-Identifier: MIT-0
|
|
207
|
+
#++
|
|
208
|
+
# <tt>:play</tt>, <tt>:media_pause</tt>, <tt>:play_pause</tt>, <tt>:reverse</tt>, <tt>:stop</tt>,
|
|
209
|
+
# <tt>:fast_forward</tt>, <tt>:rewind</tt>, <tt>:track_next</tt>, <tt>:track_previous</tt>,
|
|
210
|
+
# <tt>:record</tt>, <tt>:lower_volume</tt>, <tt>:raise_volume</tt>, <tt>:mute_volume</tt>
|
|
211
|
+
#--
|
|
212
|
+
# SPDX-SnippetEnd
|
|
213
|
+
#++
|
|
214
|
+
# [Modifier Keys]
|
|
215
|
+
#--
|
|
216
|
+
# SPDX-SnippetBegin
|
|
217
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
218
|
+
# SPDX-License-Identifier: MIT-0
|
|
219
|
+
#++
|
|
220
|
+
# <tt>:left_shift</tt>, <tt>:left_control</tt>, <tt>:left_alt</tt>, <tt>:left_super</tt>,
|
|
221
|
+
# <tt>:left_hyper</tt>, <tt>:left_meta</tt>, <tt>:right_shift</tt>, <tt>:right_control</tt>,
|
|
222
|
+
# <tt>:right_alt</tt>, <tt>:right_super</tt>, <tt>:right_hyper</tt>, <tt>:right_meta</tt>,
|
|
223
|
+
# <tt>:iso_level3_shift</tt>, <tt>:iso_level5_shift</tt>
|
|
224
|
+
#--
|
|
225
|
+
# SPDX-SnippetEnd
|
|
226
|
+
#++
|
|
227
|
+
# [Characters]
|
|
228
|
+
#--
|
|
229
|
+
# SPDX-SnippetBegin
|
|
230
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
231
|
+
# SPDX-License-Identifier: MIT-0
|
|
232
|
+
#++
|
|
233
|
+
# <tt>:a</tt>, <tt>:b</tt>, <tt>:1</tt>, <tt>:space</tt>, etc.
|
|
234
|
+
#
|
|
235
|
+
#--
|
|
236
|
+
# SPDX-SnippetEnd
|
|
237
|
+
#++
|
|
238
|
+
# === Modifier Examples
|
|
239
|
+
#
|
|
240
|
+
# * <tt>:ctrl_c</tt>
|
|
241
|
+
# * <tt>:alt_enter</tt>
|
|
242
|
+
# * <tt>:shift_left</tt>
|
|
243
|
+
# * <tt>:ctrl_alt_delete</tt>
|
|
244
|
+
def to_sym
|
|
245
|
+
mods = @modifiers.join("_")
|
|
246
|
+
if mods.empty?
|
|
247
|
+
@code.to_sym
|
|
248
|
+
else
|
|
249
|
+
:"#{mods}_#{@code}"
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Converts the event to its String representation.
|
|
254
|
+
#
|
|
255
|
+
# [Printable Characters]
|
|
256
|
+
# Returns the character itself (e.g., <tt>"a"</tt>, <tt>"1"</tt>, <tt>" "</tt>).
|
|
257
|
+
# [Special Keys]
|
|
258
|
+
# Returns an empty string (e.g., <tt>"enter"</tt>, <tt>"up"</tt>, <tt>"f1"</tt> all return <tt>""</tt>).
|
|
259
|
+
# [Modifiers]
|
|
260
|
+
#--
|
|
261
|
+
# SPDX-SnippetBegin
|
|
262
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
263
|
+
# SPDX-License-Identifier: MIT-0
|
|
264
|
+
#++
|
|
265
|
+
# Returns the character if printable, ignoring modifiers unless they alter the character code itself.
|
|
266
|
+
# Note that <tt>ctrl+c</tt> typically returns <tt>"c"</tt> as the code, so +to_s+ will return <tt>"c"</tt>.
|
|
267
|
+
#--
|
|
268
|
+
# SPDX-SnippetEnd
|
|
269
|
+
#++
|
|
270
|
+
def to_s
|
|
271
|
+
if text?
|
|
272
|
+
@code
|
|
273
|
+
else
|
|
274
|
+
""
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# Returns inspection string.
|
|
279
|
+
def inspect
|
|
280
|
+
"#<#{self.class} code=#{@code.inspect} modifiers=#{@modifiers.inspect} kind=#{@kind.inspect}>"
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Supports dynamic key predicate methods via method_missing.
|
|
284
|
+
#
|
|
285
|
+
# Allows convenient checking for specific keys or key combinations:
|
|
286
|
+
#
|
|
287
|
+
#--
|
|
288
|
+
# SPDX-SnippetBegin
|
|
289
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long
|
|
290
|
+
# SPDX-License-Identifier: MIT-0
|
|
291
|
+
#++
|
|
292
|
+
# event.ctrl_c? # => true if Ctrl+C
|
|
293
|
+
# event.enter? # => true if Enter
|
|
294
|
+
# event.shift_up? # => true if Shift+Up
|
|
295
|
+
# event.q? # => true if "q"
|
|
296
|
+
#
|
|
297
|
+
#--
|
|
298
|
+
# SPDX-SnippetEnd
|
|
299
|
+
#++
|
|
300
|
+
# The method name is converted to a symbol and compared against the event.
|
|
301
|
+
# This works for any key code or modifier+key combination.
|
|
302
|
+
#
|
|
303
|
+
# === Smart Predicates (DWIM)
|
|
304
|
+
#
|
|
305
|
+
# For convenience, generic predicates match both system and media variants:
|
|
306
|
+
#
|
|
307
|
+
#--
|
|
308
|
+
# SPDX-SnippetBegin
|
|
309
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
310
|
+
# SPDX-License-Identifier: MIT-0
|
|
311
|
+
#++
|
|
312
|
+
# event.pause? # => true for BOTH system "pause" AND "media_pause"
|
|
313
|
+
# event.play? # => true for "media_play"
|
|
314
|
+
# event.stop? # => true for "media_stop"
|
|
315
|
+
#
|
|
316
|
+
#--
|
|
317
|
+
# SPDX-SnippetEnd
|
|
318
|
+
#++
|
|
319
|
+
# This "Do What I Mean" behavior reduces boilerplate when you just want to
|
|
320
|
+
# respond to a conceptual action (e.g., "pause the playback") regardless of
|
|
321
|
+
# whether the user pressed a keyboard key or a media button.
|
|
322
|
+
#
|
|
323
|
+
# For strict matching, use the full predicate or compare the code directly:
|
|
324
|
+
#
|
|
325
|
+
#--
|
|
326
|
+
# SPDX-SnippetBegin
|
|
327
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
328
|
+
# SPDX-License-Identifier: MIT-0
|
|
329
|
+
#++
|
|
330
|
+
# event.media_pause? # => true ONLY for media pause
|
|
331
|
+
# event.code == "pause" # => true ONLY for system pause
|
|
332
|
+
#
|
|
333
|
+
#--
|
|
334
|
+
# SPDX-SnippetEnd
|
|
335
|
+
#++
|
|
336
|
+
# === Arrow Key Aliases
|
|
337
|
+
#
|
|
338
|
+
# Arrow keys respond to <tt>arrow_up?</tt> and <tt>up_arrow?</tt> variants.
|
|
339
|
+
# This disambiguates from Mouse events, which also respond to <tt>up?</tt>
|
|
340
|
+
# and <tt>down?</tt>:
|
|
341
|
+
#
|
|
342
|
+
#--
|
|
343
|
+
# SPDX-SnippetBegin
|
|
344
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
345
|
+
# SPDX-License-Identifier: MIT-0
|
|
346
|
+
#++
|
|
347
|
+
# event.arrow_up? # => true for up arrow key
|
|
348
|
+
# event.up_arrow? # => true for up arrow key
|
|
349
|
+
# event.arrow_down? # => true for down arrow key
|
|
350
|
+
#
|
|
351
|
+
#--
|
|
352
|
+
# SPDX-SnippetEnd
|
|
353
|
+
#++
|
|
354
|
+
# === Key Prefix and Suffix
|
|
355
|
+
#
|
|
356
|
+
# Predicates accept <tt>key_</tt> prefix or <tt>_key</tt> suffix for explicit
|
|
357
|
+
# key event matching in mixed event contexts:
|
|
358
|
+
#
|
|
359
|
+
#--
|
|
360
|
+
# SPDX-SnippetBegin
|
|
361
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
362
|
+
# SPDX-License-Identifier: MIT-0
|
|
363
|
+
#++
|
|
364
|
+
# event.key_up? # => true for up arrow key
|
|
365
|
+
# event.key_q? # => true for "q" key
|
|
366
|
+
# event.q_key? # => true for "q" key
|
|
367
|
+
# event.enter_key? # => true for enter key
|
|
368
|
+
#
|
|
369
|
+
#--
|
|
370
|
+
# SPDX-SnippetEnd
|
|
371
|
+
#++
|
|
372
|
+
# === Capital Letters and Shift
|
|
373
|
+
#
|
|
374
|
+
# Capital letter predicates match shifted keys naturally. The terminal reports
|
|
375
|
+
# the produced character with shift in the modifiers:
|
|
376
|
+
#
|
|
377
|
+
#--
|
|
378
|
+
# SPDX-SnippetBegin
|
|
379
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
380
|
+
# SPDX-License-Identifier: MIT-0
|
|
381
|
+
#++
|
|
382
|
+
# event.G? # => true for code="G" modifiers=["shift"]
|
|
383
|
+
# event.shift_g? # => true for code="G" modifiers=["shift"]
|
|
384
|
+
# event.alt_B? # => true for code="B" modifiers=["alt", "shift"]
|
|
385
|
+
#
|
|
386
|
+
#--
|
|
387
|
+
# SPDX-SnippetEnd
|
|
388
|
+
#++
|
|
389
|
+
def method_missing(name, *args, **kwargs, &block)
|
|
390
|
+
if name.to_s.end_with?("?")
|
|
391
|
+
name_str = name.to_s
|
|
392
|
+
key_name = name_str.chop # Returns String, never nil for non-empty string
|
|
393
|
+
key_sym = key_name.to_sym
|
|
394
|
+
|
|
395
|
+
# Fast path: Exact match (e.g., media_pause? for media_pause)
|
|
396
|
+
return true if self == key_sym
|
|
397
|
+
|
|
398
|
+
# Delegate category-specific DWIM logic to mixins
|
|
399
|
+
return true if match_media_dwim?(key_name)
|
|
400
|
+
return true if match_modifier_dwim?(key_name, key_sym)
|
|
401
|
+
return true if match_navigation_dwim?(key_name, key_sym)
|
|
402
|
+
return true if match_system_dwim?(key_name, key_sym)
|
|
403
|
+
|
|
404
|
+
# DWIM: key_ prefix and _key suffix (disambiguate from mouse events)
|
|
405
|
+
# key_up? → up?, q_key? → q?, etc.
|
|
406
|
+
key_name = key_name.delete_prefix("key_").delete_suffix("_key")
|
|
407
|
+
|
|
408
|
+
# Fast path after prefix/suffix stripping
|
|
409
|
+
return true if self == key_name.to_sym
|
|
410
|
+
|
|
411
|
+
# DWIM: Single character codes match even with shift modifier present
|
|
412
|
+
# G? matches code="G" modifiers=["shift"], B? matches code="B" modifiers=["alt","shift"]
|
|
413
|
+
# @? matches code="@" modifiers=["shift"]
|
|
414
|
+
# The terminal reports the produced character, shift is implicit for these
|
|
415
|
+
if key_name.length == 1 && @code == key_name && @modifiers.include?("shift")
|
|
416
|
+
return true
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# DWIM: Uppercase in predicate implies shift, so alt_B? matches alt_shift_B
|
|
420
|
+
# Parse predicate to extract modifiers and final letter
|
|
421
|
+
if key_name.match?(/\A([a-z_]+_)?([A-Z])\z/)
|
|
422
|
+
pred_letter = key_name[-1]
|
|
423
|
+
pred_mods = key_name.chop.delete_suffix("_").split("_").reject(&:empty?)
|
|
424
|
+
expected_mods = (pred_mods + ["shift"]).sort
|
|
425
|
+
return true if @code == pred_letter && @modifiers == expected_mods
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# DWIM: Case-insensitive letter matching with modifiers
|
|
429
|
+
# shift_g? matches code="G" modifiers=["shift"]
|
|
430
|
+
if @code.length == 1 && @code.match?(/[A-Za-z]/) && (to_sym.to_s.downcase == key_name.downcase)
|
|
431
|
+
return true
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
# DWIM: Universal underscore-insensitivity
|
|
435
|
+
# Normalize both predicate and code by stripping underscores
|
|
436
|
+
normalized_predicate = key_name.delete("_")
|
|
437
|
+
normalized_code = @code.delete("_")
|
|
438
|
+
return true if normalized_predicate == normalized_code && @modifiers.empty?
|
|
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
|
+
|
|
447
|
+
false
|
|
448
|
+
else
|
|
449
|
+
super
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# Declares that this class responds to dynamic predicate methods.
|
|
454
|
+
def respond_to_missing?(name, *args)
|
|
455
|
+
name.to_s.end_with?("?") || super
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
# Deconstructs the event for pattern matching.
|
|
459
|
+
#
|
|
460
|
+
#--
|
|
461
|
+
# SPDX-SnippetBegin
|
|
462
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
463
|
+
# SPDX-License-Identifier: MIT-0
|
|
464
|
+
#++
|
|
465
|
+
# case event
|
|
466
|
+
# in type: :key, code: "c", modifiers: ["ctrl"]
|
|
467
|
+
# puts "Ctrl+C pressed"
|
|
468
|
+
# in type: :key, kind: :media
|
|
469
|
+
# puts "Media key pressed"
|
|
470
|
+
# end
|
|
471
|
+
#--
|
|
472
|
+
# SPDX-SnippetEnd
|
|
473
|
+
#++
|
|
474
|
+
def deconstruct_keys(keys)
|
|
475
|
+
{ type: :key, code: @code, modifiers: @modifiers, kind: @kind }
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
end
|