ratatui_ruby-tea 0.3.0 → 0.4.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 +4 -4
- data/AGENTS.md +51 -7
- data/CHANGELOG.md +109 -0
- data/README.md +25 -5
- data/Rakefile +1 -1
- data/Steepfile +3 -3
- data/doc/concepts/async_work.md +164 -0
- data/doc/concepts/commands.md +528 -0
- data/doc/concepts/message_processing.md +51 -0
- data/doc/contributors/WIP/decomposition_strategies_analysis.md +258 -0
- data/doc/contributors/WIP/implementation_plan.md +405 -0
- data/doc/contributors/WIP/init_callable_proposal.md +341 -0
- data/doc/contributors/WIP/mvu_tea_implementations_research.md +372 -0
- data/doc/contributors/WIP/runtime_refactoring_status.md +47 -0
- data/doc/contributors/WIP/task.md +36 -0
- data/doc/contributors/WIP/v0.4.0_todo.md +468 -0
- data/doc/contributors/design/commands_and_outlets.md +214 -0
- data/doc/contributors/kit-no-outlet.md +237 -0
- data/doc/contributors/priorities.md +22 -24
- data/examples/app_fractal_dashboard/app.rb +3 -7
- data/examples/app_fractal_dashboard/dashboard/base.rb +15 -16
- data/examples/app_fractal_dashboard/dashboard/update_helpers.rb +8 -8
- data/examples/app_fractal_dashboard/dashboard/update_manual.rb +11 -11
- data/examples/app_fractal_dashboard/dashboard/update_router.rb +4 -4
- data/examples/app_fractal_dashboard/{bags → fragments}/custom_shell_input.rb +8 -4
- data/examples/app_fractal_dashboard/fragments/custom_shell_modal.rb +82 -0
- data/examples/app_fractal_dashboard/{bags → fragments}/custom_shell_output.rb +8 -4
- data/examples/app_fractal_dashboard/{bags → fragments}/disk_usage.rb +13 -10
- data/examples/app_fractal_dashboard/{bags → fragments}/network_panel.rb +12 -12
- data/examples/app_fractal_dashboard/{bags → fragments}/ping.rb +12 -8
- data/examples/app_fractal_dashboard/{bags → fragments}/stats_panel.rb +12 -12
- data/examples/app_fractal_dashboard/{bags → fragments}/system_info.rb +11 -7
- data/examples/app_fractal_dashboard/{bags → fragments}/uptime.rb +11 -7
- data/examples/verify_readme_usage/README.md +7 -4
- data/examples/verify_readme_usage/app.rb +7 -4
- data/lib/ratatui_ruby/tea/command/all.rb +71 -0
- data/lib/ratatui_ruby/tea/command/batch.rb +79 -0
- data/lib/ratatui_ruby/tea/command/custom.rb +106 -0
- data/lib/ratatui_ruby/tea/command/http.rb +194 -0
- data/lib/ratatui_ruby/tea/command/lifecycle.rb +136 -0
- data/lib/ratatui_ruby/tea/command/outlet.rb +159 -0
- data/lib/ratatui_ruby/tea/command/wait.rb +82 -0
- data/lib/ratatui_ruby/tea/command.rb +416 -13
- data/lib/ratatui_ruby/tea/message/all.rb +47 -0
- data/lib/ratatui_ruby/tea/message/http_response.rb +63 -0
- data/lib/ratatui_ruby/tea/message/system/batch.rb +63 -0
- data/lib/ratatui_ruby/tea/message/system/stream.rb +69 -0
- data/lib/ratatui_ruby/tea/message/timer.rb +48 -0
- data/lib/ratatui_ruby/tea/message.rb +40 -0
- data/lib/ratatui_ruby/tea/router.rb +155 -87
- data/lib/ratatui_ruby/tea/runtime.rb +329 -150
- data/lib/ratatui_ruby/tea/shortcuts.rb +2 -2
- data/lib/ratatui_ruby/tea/test_helper.rb +58 -0
- data/lib/ratatui_ruby/tea/version.rb +1 -1
- data/lib/ratatui_ruby/tea.rb +44 -10
- data/rbs_collection.lock.yaml +108 -0
- data/rbs_collection.yaml +15 -0
- data/sig/concurrent.rbs +72 -0
- data/sig/examples/verify_readme_usage/app.rbs +1 -1
- data/sig/examples/widget_command_system/app.rbs +1 -1
- data/sig/open3.rbs +17 -0
- data/sig/ratatui_ruby/tea/command.rbs +226 -6
- data/sig/ratatui_ruby/tea/message.rbs +123 -0
- data/sig/ratatui_ruby/tea/router.rbs +110 -54
- data/sig/ratatui_ruby/tea/runtime.rbs +63 -12
- data/sig/ratatui_ruby/tea/shortcuts.rbs +18 -0
- data/sig/ratatui_ruby/tea/test_helper.rbs +12 -0
- data/sig/ratatui_ruby/tea/version.rbs +10 -0
- data/sig/ratatui_ruby/tea.rbs +39 -7
- data/tasks/steep.rake +11 -0
- metadata +75 -12
- data/examples/app_fractal_dashboard/bags/custom_shell_modal.rb +0 -73
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
module RatatuiRuby
|
|
7
|
+
module Tea
|
|
8
|
+
# Messages sent from commands to update functions.
|
|
9
|
+
module Message
|
|
10
|
+
# Fallback predicate mixin.
|
|
11
|
+
module Predicates
|
|
12
|
+
# Returns false for unknown predicate methods.
|
|
13
|
+
def method_missing: (Symbol name, *untyped args, **untyped kwargs) ?{ () -> untyped } -> bool
|
|
14
|
+
|
|
15
|
+
# Responds to all predicate methods.
|
|
16
|
+
def respond_to_missing?: (Symbol name, ?bool include_private) -> bool
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# System command response types.
|
|
20
|
+
module System
|
|
21
|
+
# Response from a system command (batch mode).
|
|
22
|
+
class Batch
|
|
23
|
+
include Predicates
|
|
24
|
+
|
|
25
|
+
attr_reader envelope: Symbol
|
|
26
|
+
attr_reader stdout: String
|
|
27
|
+
attr_reader stderr: String
|
|
28
|
+
attr_reader status: Integer
|
|
29
|
+
|
|
30
|
+
def initialize: (
|
|
31
|
+
envelope: Symbol,
|
|
32
|
+
stdout: String,
|
|
33
|
+
stderr: String,
|
|
34
|
+
status: Integer
|
|
35
|
+
) -> void
|
|
36
|
+
|
|
37
|
+
def system?: () -> bool
|
|
38
|
+
def success?: () -> bool
|
|
39
|
+
def error?: () -> bool
|
|
40
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Streaming message from a system command.
|
|
44
|
+
class Stream
|
|
45
|
+
include Predicates
|
|
46
|
+
|
|
47
|
+
attr_reader envelope: Symbol
|
|
48
|
+
attr_reader stream: Symbol
|
|
49
|
+
attr_reader content: String?
|
|
50
|
+
attr_reader status: Integer?
|
|
51
|
+
|
|
52
|
+
def initialize: (
|
|
53
|
+
envelope: Symbol,
|
|
54
|
+
stream: Symbol,
|
|
55
|
+
content: String?,
|
|
56
|
+
status: Integer?
|
|
57
|
+
) -> void
|
|
58
|
+
|
|
59
|
+
def system?: () -> bool
|
|
60
|
+
def stdout?: () -> bool
|
|
61
|
+
def stderr?: () -> bool
|
|
62
|
+
def complete?: () -> bool
|
|
63
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Response from a timer command.
|
|
68
|
+
class Timer
|
|
69
|
+
include Predicates
|
|
70
|
+
|
|
71
|
+
attr_reader envelope: Symbol
|
|
72
|
+
attr_reader elapsed: Float
|
|
73
|
+
|
|
74
|
+
def initialize: (envelope: Symbol, elapsed: Float) -> void
|
|
75
|
+
|
|
76
|
+
def timer?: () -> bool
|
|
77
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Response from an HTTP command.
|
|
81
|
+
class HttpResponse
|
|
82
|
+
include Predicates
|
|
83
|
+
|
|
84
|
+
attr_reader envelope: Symbol
|
|
85
|
+
attr_reader status: Integer?
|
|
86
|
+
attr_reader body: String?
|
|
87
|
+
attr_reader headers: Hash[String, String]?
|
|
88
|
+
attr_reader error: String?
|
|
89
|
+
|
|
90
|
+
def initialize: (
|
|
91
|
+
envelope: Symbol,
|
|
92
|
+
status: Integer?,
|
|
93
|
+
body: String?,
|
|
94
|
+
headers: Hash[String, String]?,
|
|
95
|
+
error: String?
|
|
96
|
+
) -> void
|
|
97
|
+
|
|
98
|
+
def http?: () -> bool
|
|
99
|
+
def success?: () -> bool
|
|
100
|
+
def error?: () -> bool
|
|
101
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Response from Command.all aggregating parallel execution.
|
|
105
|
+
class All
|
|
106
|
+
include Predicates
|
|
107
|
+
|
|
108
|
+
attr_reader envelope: Symbol
|
|
109
|
+
attr_reader results: Array[untyped]
|
|
110
|
+
attr_reader nested: bool
|
|
111
|
+
|
|
112
|
+
def initialize: (
|
|
113
|
+
envelope: Symbol,
|
|
114
|
+
results: Array[untyped],
|
|
115
|
+
nested: bool
|
|
116
|
+
) -> void
|
|
117
|
+
|
|
118
|
+
def all?: () -> bool
|
|
119
|
+
def deconstruct_keys: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -5,94 +5,150 @@
|
|
|
5
5
|
|
|
6
6
|
module RatatuiRuby
|
|
7
7
|
module Tea
|
|
8
|
-
# Interface for child bag modules (required by route).
|
|
9
|
-
interface _Bag[M]
|
|
10
|
-
def self.UPDATE: ^(top, M) -> [M, Command::execution?]
|
|
11
|
-
def self.INITIAL: M
|
|
12
|
-
end
|
|
13
|
-
|
|
14
8
|
# Declarative DSL for Fractal Architecture.
|
|
15
9
|
module Router
|
|
16
10
|
def self.included: (Class base) -> void
|
|
17
11
|
|
|
18
|
-
#
|
|
19
|
-
|
|
12
|
+
# Duck type for Data-like models that support `with`.
|
|
13
|
+
interface _DataModel
|
|
14
|
+
def public_send: (Symbol, *Object) -> Object
|
|
15
|
+
def with: (**Object) -> self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Interface for fractal child modules (fragments).
|
|
19
|
+
# Routed modules must have an UPDATE constant that handles child messages.
|
|
20
|
+
# NOTE: We use Module here because RBS interfaces can't declare class methods.
|
|
20
21
|
|
|
21
|
-
#
|
|
22
|
-
|
|
22
|
+
# Configuration for key handlers.
|
|
23
|
+
class KeyHandlerConfig < Data
|
|
24
|
+
attr_reader handler: (^() -> Command::execution?)?
|
|
25
|
+
attr_reader action: Symbol?
|
|
26
|
+
attr_reader route: Symbol?
|
|
27
|
+
attr_reader guard: (^(_DataModel) -> bool)?
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
def initialize: (?handler: (^() -> Command::execution?)?, ?action: Symbol?, ?route: Symbol?, ?guard: (^(_DataModel) -> bool)?) -> void
|
|
30
|
+
end
|
|
26
31
|
|
|
27
|
-
#
|
|
28
|
-
|
|
29
|
-
handler:
|
|
30
|
-
action: Symbol
|
|
31
|
-
route: Symbol?,
|
|
32
|
-
guard: guard[M]?
|
|
33
|
-
}
|
|
32
|
+
# Configuration for scroll handlers (no coordinates).
|
|
33
|
+
class ScrollHandlerConfig < Data
|
|
34
|
+
attr_reader handler: (^() -> Command::execution?)?
|
|
35
|
+
attr_reader action: Symbol?
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
def initialize: (?handler: (^() -> Command::execution?)?, ?action: Symbol?) -> void
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Configuration for click handlers (x, y coordinates).
|
|
41
|
+
class ClickHandlerConfig < Data
|
|
42
|
+
attr_reader handler: (^(Integer, Integer) -> Command::execution?)?
|
|
43
|
+
attr_reader action: Symbol?
|
|
44
|
+
|
|
45
|
+
def initialize: (?handler: (^(Integer, Integer) -> Command::execution?)?, ?action: Symbol?) -> void
|
|
46
|
+
end
|
|
40
47
|
|
|
41
48
|
# Class methods added when Router is included.
|
|
42
|
-
module ClassMethods
|
|
43
|
-
|
|
49
|
+
module ClassMethods : Module
|
|
50
|
+
@routes: Hash[Symbol, Module]
|
|
51
|
+
@actions: Hash[Symbol, ^() -> Command::execution?]
|
|
52
|
+
@key_handlers: Hash[String, KeyHandlerConfig]
|
|
53
|
+
@scroll_handlers: Hash[Symbol, ScrollHandlerConfig]
|
|
54
|
+
@click_handler: ClickHandlerConfig?
|
|
55
|
+
|
|
56
|
+
def route: (Symbol | String prefix, to: Module) -> void
|
|
44
57
|
def routes: () -> Hash[Symbol, Module]
|
|
45
58
|
|
|
46
|
-
def action: (Symbol | String name, handler) -> void
|
|
47
|
-
def actions: () -> Hash[Symbol,
|
|
59
|
+
def action: (Symbol | String name, ^() -> Command::execution? handler) -> void
|
|
60
|
+
def actions: () -> Hash[Symbol, ^() -> Command::execution?]
|
|
48
61
|
|
|
49
|
-
def keymap: () { () -> void } -> void
|
|
50
|
-
def key_handlers:
|
|
62
|
+
def keymap: () { (KeymapBuilder) [self: KeymapBuilder] -> void } -> void
|
|
63
|
+
def key_handlers: () -> Hash[String, KeyHandlerConfig]
|
|
51
64
|
|
|
52
|
-
def mousemap: () { () -> void } -> void
|
|
53
|
-
def
|
|
65
|
+
def mousemap: () { (MousemapBuilder) [self: MousemapBuilder] -> void } -> void
|
|
66
|
+
def scroll_handlers: () -> Hash[Symbol, ScrollHandlerConfig]
|
|
67
|
+
def click_handler: () -> ClickHandlerConfig?
|
|
54
68
|
|
|
55
|
-
#
|
|
56
|
-
|
|
69
|
+
# Returns UPDATE callable that handles routing.
|
|
70
|
+
# Uses is_a? checks for Event::Key and Event::Mouse type narrowing.
|
|
71
|
+
# Model must be Data-like with `with` and field accessors.
|
|
72
|
+
def from_router: () -> RouterUpdate
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# UPDATE callable returned by from_router with proper typing.
|
|
76
|
+
# Implements #call to satisfy Proc-like interfaces.
|
|
77
|
+
class RouterUpdate
|
|
78
|
+
@routes: Hash[Symbol, Module]
|
|
79
|
+
@actions: Hash[Symbol, ^() -> Command::execution?]
|
|
80
|
+
@key_handlers: Hash[String, KeyHandlerConfig]
|
|
81
|
+
@scroll_handlers: Hash[Symbol, ScrollHandlerConfig]
|
|
82
|
+
@click_handler: ClickHandlerConfig?
|
|
83
|
+
|
|
84
|
+
def initialize: (
|
|
85
|
+
routes: Hash[Symbol, Module],
|
|
86
|
+
actions: Hash[Symbol, ^() -> Command::execution?],
|
|
87
|
+
key_handlers: Hash[String, KeyHandlerConfig],
|
|
88
|
+
scroll_handlers: Hash[Symbol, ScrollHandlerConfig],
|
|
89
|
+
click_handler: ClickHandlerConfig?
|
|
90
|
+
) -> void
|
|
91
|
+
|
|
92
|
+
# Process message and return [model, command] tuple.
|
|
93
|
+
def call: (
|
|
94
|
+
(RatatuiRuby::Event::Key | RatatuiRuby::Event::Mouse | Array[Object]) message,
|
|
95
|
+
_DataModel model
|
|
96
|
+
) -> [_DataModel, Command::execution?]
|
|
57
97
|
end
|
|
58
98
|
|
|
59
99
|
# Builder for keymap DSL.
|
|
60
100
|
class KeymapBuilder
|
|
61
|
-
@handlers: Hash[String,
|
|
101
|
+
@handlers: Hash[String, KeyHandlerConfig]
|
|
102
|
+
@guard_stack: Array[^(_DataModel) -> bool]
|
|
62
103
|
|
|
63
|
-
attr_reader handlers: Hash[String,
|
|
104
|
+
attr_reader handlers: Hash[String, KeyHandlerConfig]
|
|
64
105
|
|
|
65
106
|
def initialize: () -> void
|
|
66
107
|
|
|
67
|
-
|
|
68
|
-
def key: [M] (
|
|
108
|
+
def key: (
|
|
69
109
|
String | Symbol key_name,
|
|
70
|
-
|
|
110
|
+
(^() -> Command::execution?) | Symbol handler_or_action,
|
|
71
111
|
?route: Symbol?,
|
|
72
|
-
?when:
|
|
73
|
-
?if:
|
|
74
|
-
?only:
|
|
75
|
-
?guard:
|
|
76
|
-
?unless:
|
|
77
|
-
?except:
|
|
78
|
-
?skip:
|
|
112
|
+
?when: (^(_DataModel) -> bool)?,
|
|
113
|
+
?if: (^(_DataModel) -> bool)?,
|
|
114
|
+
?only: (^(_DataModel) -> bool)?,
|
|
115
|
+
?guard: (^(_DataModel) -> bool)?,
|
|
116
|
+
?unless: (^(_DataModel) -> bool)?,
|
|
117
|
+
?except: (^(_DataModel) -> bool)?,
|
|
118
|
+
?skip: (^(_DataModel) -> bool)?
|
|
79
119
|
) -> void
|
|
120
|
+
|
|
121
|
+
def only: (
|
|
122
|
+
?when: (^(_DataModel) -> bool)?,
|
|
123
|
+
?if: (^(_DataModel) -> bool)?,
|
|
124
|
+
?only: (^(_DataModel) -> bool)?,
|
|
125
|
+
?guard: (^(_DataModel) -> bool)?
|
|
126
|
+
) { () -> void } -> void
|
|
127
|
+
|
|
128
|
+
def skip: (
|
|
129
|
+
?when: (^(_DataModel) -> bool)?,
|
|
130
|
+
?if: (^(_DataModel) -> bool)?,
|
|
131
|
+
?skip: (^(_DataModel) -> bool)?,
|
|
132
|
+
?guard: (^(_DataModel) -> bool)?
|
|
133
|
+
) { () -> void } -> void
|
|
134
|
+
|
|
135
|
+
private
|
|
136
|
+
|
|
137
|
+
def with_guard: ((^(_DataModel) -> bool)?) { () -> void } -> void
|
|
80
138
|
end
|
|
81
139
|
|
|
82
140
|
# Builder for mousemap DSL.
|
|
83
141
|
class MousemapBuilder
|
|
84
|
-
@
|
|
142
|
+
@scroll_handlers: Hash[Symbol, ScrollHandlerConfig]
|
|
143
|
+
@click_handler: ClickHandlerConfig?
|
|
85
144
|
|
|
86
|
-
attr_reader
|
|
145
|
+
attr_reader scroll_handlers: Hash[Symbol, ScrollHandlerConfig]
|
|
146
|
+
attr_reader click_handler: ClickHandlerConfig?
|
|
87
147
|
|
|
88
148
|
def initialize: () -> void
|
|
89
149
|
|
|
90
|
-
def click: (
|
|
91
|
-
def scroll: (:up | :down direction,
|
|
92
|
-
|
|
93
|
-
private
|
|
94
|
-
|
|
95
|
-
def register: (Symbol key, handler | click_handler | Symbol handler_or_action) -> void
|
|
150
|
+
def click: ((^(Integer, Integer) -> Command::execution?) | Symbol handler_or_action) -> void
|
|
151
|
+
def scroll: (:up | :down direction, (^() -> Command::execution?) | Symbol handler_or_action) -> void
|
|
96
152
|
end
|
|
97
153
|
end
|
|
98
154
|
end
|
|
@@ -5,22 +5,73 @@
|
|
|
5
5
|
|
|
6
6
|
module RatatuiRuby
|
|
7
7
|
module Tea
|
|
8
|
+
# MVU runtime event loop.
|
|
8
9
|
class Runtime
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
# Active command tracking entry.
|
|
11
|
+
type active_entry = { future: Concurrent::Promises::Future[void], origin: Concurrent::Promises::ResolvableEvent }
|
|
12
|
+
|
|
13
|
+
# Widget type accepted by view functions.
|
|
14
|
+
type renderable = RatatuiRuby::_CustomWidget | RatatuiRuby::widget
|
|
15
|
+
|
|
16
|
+
# Duck type for update result that can be normalized.
|
|
17
|
+
# Steep needs a union type (not interface) for is_a? narrowing.
|
|
18
|
+
type update_result = [Object, Command::execution?] | Command::execution | Object
|
|
19
|
+
|
|
20
|
+
# Duck type for init result that can be normalized.
|
|
21
|
+
type init_result = [Object, Command::execution?] | Command::execution | Object
|
|
22
|
+
|
|
23
|
+
# Duck type for values that can be queried for command-ness.
|
|
24
|
+
interface _MaybeCommand
|
|
25
|
+
def nil?: () -> bool
|
|
26
|
+
def class: () -> Class
|
|
27
|
+
def respond_to?: (Symbol, ?bool) -> bool
|
|
28
|
+
def tea_command?: () -> bool
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Starts the MVU event loop (positional fragment).
|
|
32
|
+
def self.run: [Model] (
|
|
33
|
+
?Module? root_fragment,
|
|
34
|
+
?fps: Integer
|
|
35
|
+
) -> Model
|
|
36
|
+
|
|
37
|
+
# Starts the MVU event loop (explicit parameters).
|
|
38
|
+
| [Model] (
|
|
39
|
+
?Module? root_fragment,
|
|
40
|
+
?fps: Integer,
|
|
41
|
+
model: Model,
|
|
42
|
+
view: ^(Model, RatatuiRuby::TUI) -> renderable,
|
|
43
|
+
update: ^(RatatuiRuby::Event, Model) -> update_result?,
|
|
44
|
+
?command: Command::execution?
|
|
45
|
+
) -> Model
|
|
46
|
+
|
|
47
|
+
# Starts the MVU event loop (explicit parameters without fps).
|
|
48
|
+
| [Model] (
|
|
49
|
+
?Module? root_fragment,
|
|
50
|
+
model: Model,
|
|
51
|
+
view: ^(Model, RatatuiRuby::TUI) -> renderable,
|
|
52
|
+
update: ^(RatatuiRuby::Event, Model) -> update_result?,
|
|
53
|
+
?command: Command::execution?
|
|
54
|
+
) -> Model
|
|
55
|
+
|
|
56
|
+
# Normalizes Init callable return value to [model, command] tuple.
|
|
57
|
+
def self.normalize_init: [Model] (init_result result) -> [Model?, Command::execution?]
|
|
58
|
+
QUIT: Object
|
|
16
59
|
|
|
17
60
|
private
|
|
18
61
|
|
|
19
|
-
def self.
|
|
20
|
-
def self.
|
|
21
|
-
def self.
|
|
22
|
-
def self.
|
|
23
|
-
def self.
|
|
62
|
+
def self.validate_view_return!: (renderable? widget) -> void
|
|
63
|
+
def self.normalize_update_return: [Model] (update_result? result, Model? previous_model) -> [Model?, Command::execution?]
|
|
64
|
+
def self.validate_ractor_shareable!: [T] (T object, String name) -> void
|
|
65
|
+
def self.fragment_from_kwargs: (Module? root_fragment, ?model: untyped, ?view: untyped, ?update: untyped, ?command: untyped) -> Module
|
|
66
|
+
def self.fragment_invariant!: (String param) -> void
|
|
67
|
+
def self.init_callable: [Model] () -> ^() -> [Model?, Command::execution?]
|
|
68
|
+
def self.start_runtime: () -> untyped
|
|
69
|
+
def self.draw_view: () -> void
|
|
70
|
+
def self.handle_ratatui_event: () -> void
|
|
71
|
+
def self.handle_sync: () -> void
|
|
72
|
+
QUEUE_EMPTY: Object
|
|
73
|
+
def self.send_pending_messages: (?dispatch: bool) -> void
|
|
74
|
+
def self.dispatch_command: () -> void
|
|
24
75
|
end
|
|
25
76
|
end
|
|
26
77
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
module RatatuiRuby
|
|
7
|
+
module Tea
|
|
8
|
+
# Convenient short aliases for Tea APIs.
|
|
9
|
+
module Shortcuts
|
|
10
|
+
# Short alias for Command.
|
|
11
|
+
module Cmd
|
|
12
|
+
def self.exit: () -> Command::Exit
|
|
13
|
+
def self.sh: (String command, Symbol | Class tag) -> Command::System
|
|
14
|
+
def self.map: (Command::execution inner_command) { (Array[untyped]) -> Array[untyped] } -> Command::Mapped
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
4
|
+
#++
|
|
5
|
+
|
|
6
|
+
module RatatuiRuby
|
|
7
|
+
module Tea
|
|
8
|
+
module TestHelper
|
|
9
|
+
def validate_tea_command!: (Runtime::_MaybeCommand) -> nil
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/sig/ratatui_ruby/tea.rbs
CHANGED
|
@@ -4,13 +4,45 @@
|
|
|
4
4
|
#++
|
|
5
5
|
|
|
6
6
|
module RatatuiRuby
|
|
7
|
+
# The Elm Architecture for RatatuiRuby.
|
|
7
8
|
module Tea
|
|
8
|
-
#
|
|
9
|
-
def self.run: [
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
# Starts the MVU event loop (positional fragment).
|
|
10
|
+
def self.run: [Model] (
|
|
11
|
+
?Module? root_fragment,
|
|
12
|
+
?fps: Integer
|
|
13
|
+
) -> Model
|
|
14
|
+
|
|
15
|
+
# Starts the MVU event loop (explicit parameters).
|
|
16
|
+
| [Model] (
|
|
17
|
+
?Module? root_fragment,
|
|
18
|
+
?fps: Integer,
|
|
19
|
+
model: Model,
|
|
20
|
+
view: ^(Model, RatatuiRuby::TUI) -> Runtime::renderable,
|
|
21
|
+
update: ^(RatatuiRuby::Event, Model) -> Runtime::update_result?,
|
|
22
|
+
?command: Command::execution?
|
|
23
|
+
) -> Model
|
|
24
|
+
|
|
25
|
+
# Starts the MVU event loop (explicit parameters without fps).
|
|
26
|
+
| [Model] (
|
|
27
|
+
?Module? root_fragment,
|
|
28
|
+
model: Model,
|
|
29
|
+
view: ^(Model, RatatuiRuby::TUI) -> Runtime::renderable,
|
|
30
|
+
update: ^(RatatuiRuby::Event, Model) -> Runtime::update_result?,
|
|
31
|
+
?command: Command::execution?
|
|
32
|
+
) -> Model
|
|
33
|
+
|
|
34
|
+
# Wraps a command with a routing prefix.
|
|
35
|
+
def self.route: (Command::execution command, Symbol prefix) -> Command::Mapped
|
|
36
|
+
|
|
37
|
+
# Delegates a prefixed message to a child fragment's UPDATE.
|
|
38
|
+
def self.delegate: (
|
|
39
|
+
untyped message,
|
|
40
|
+
Symbol prefix,
|
|
41
|
+
^(Array[untyped]?, untyped) -> [untyped, Command::execution?] child_update,
|
|
42
|
+
untyped child_model
|
|
43
|
+
) -> ([untyped, Command::execution?] | nil)
|
|
44
|
+
|
|
45
|
+
# Normalizes Init callable return value to [model, command] tuple.
|
|
46
|
+
def self.normalize_init: [Model] (Runtime::init_result result) -> [Model?, Command::execution?]
|
|
15
47
|
end
|
|
16
48
|
end
|
data/tasks/steep.rake
ADDED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ratatui_ruby-tea
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kerrick Long
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.10.1
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.10.1
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: ostruct
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -37,6 +37,34 @@ dependencies:
|
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '0.6'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: concurrent-ruby
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.3'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '1.3'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: concurrent-ruby-edge
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0.7'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0.7'
|
|
40
68
|
- !ruby/object:Gem::Dependency
|
|
41
69
|
name: rdoc
|
|
42
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,6 +122,18 @@ files:
|
|
|
94
122
|
- Steepfile
|
|
95
123
|
- doc/concepts/application_architecture.md
|
|
96
124
|
- doc/concepts/application_testing.md
|
|
125
|
+
- doc/concepts/async_work.md
|
|
126
|
+
- doc/concepts/commands.md
|
|
127
|
+
- doc/concepts/message_processing.md
|
|
128
|
+
- doc/contributors/WIP/decomposition_strategies_analysis.md
|
|
129
|
+
- doc/contributors/WIP/implementation_plan.md
|
|
130
|
+
- doc/contributors/WIP/init_callable_proposal.md
|
|
131
|
+
- doc/contributors/WIP/mvu_tea_implementations_research.md
|
|
132
|
+
- doc/contributors/WIP/runtime_refactoring_status.md
|
|
133
|
+
- doc/contributors/WIP/task.md
|
|
134
|
+
- doc/contributors/WIP/v0.4.0_todo.md
|
|
135
|
+
- doc/contributors/design/commands_and_outlets.md
|
|
136
|
+
- doc/contributors/kit-no-outlet.md
|
|
97
137
|
- doc/contributors/priorities.md
|
|
98
138
|
- doc/custom.css
|
|
99
139
|
- doc/getting_started/quickstart.md
|
|
@@ -103,19 +143,19 @@ files:
|
|
|
103
143
|
- doc/index.md
|
|
104
144
|
- examples/app_fractal_dashboard/README.md
|
|
105
145
|
- examples/app_fractal_dashboard/app.rb
|
|
106
|
-
- examples/app_fractal_dashboard/bags/custom_shell_input.rb
|
|
107
|
-
- examples/app_fractal_dashboard/bags/custom_shell_modal.rb
|
|
108
|
-
- examples/app_fractal_dashboard/bags/custom_shell_output.rb
|
|
109
|
-
- examples/app_fractal_dashboard/bags/disk_usage.rb
|
|
110
|
-
- examples/app_fractal_dashboard/bags/network_panel.rb
|
|
111
|
-
- examples/app_fractal_dashboard/bags/ping.rb
|
|
112
|
-
- examples/app_fractal_dashboard/bags/stats_panel.rb
|
|
113
|
-
- examples/app_fractal_dashboard/bags/system_info.rb
|
|
114
|
-
- examples/app_fractal_dashboard/bags/uptime.rb
|
|
115
146
|
- examples/app_fractal_dashboard/dashboard/base.rb
|
|
116
147
|
- examples/app_fractal_dashboard/dashboard/update_helpers.rb
|
|
117
148
|
- examples/app_fractal_dashboard/dashboard/update_manual.rb
|
|
118
149
|
- examples/app_fractal_dashboard/dashboard/update_router.rb
|
|
150
|
+
- examples/app_fractal_dashboard/fragments/custom_shell_input.rb
|
|
151
|
+
- examples/app_fractal_dashboard/fragments/custom_shell_modal.rb
|
|
152
|
+
- examples/app_fractal_dashboard/fragments/custom_shell_output.rb
|
|
153
|
+
- examples/app_fractal_dashboard/fragments/disk_usage.rb
|
|
154
|
+
- examples/app_fractal_dashboard/fragments/network_panel.rb
|
|
155
|
+
- examples/app_fractal_dashboard/fragments/ping.rb
|
|
156
|
+
- examples/app_fractal_dashboard/fragments/stats_panel.rb
|
|
157
|
+
- examples/app_fractal_dashboard/fragments/system_info.rb
|
|
158
|
+
- examples/app_fractal_dashboard/fragments/uptime.rb
|
|
119
159
|
- examples/verify_readme_usage/README.md
|
|
120
160
|
- examples/verify_readme_usage/app.rb
|
|
121
161
|
- examples/widget_command_system/README.md
|
|
@@ -123,21 +163,44 @@ files:
|
|
|
123
163
|
- exe/.gitkeep
|
|
124
164
|
- lib/ratatui_ruby/tea.rb
|
|
125
165
|
- lib/ratatui_ruby/tea/command.rb
|
|
166
|
+
- lib/ratatui_ruby/tea/command/all.rb
|
|
167
|
+
- lib/ratatui_ruby/tea/command/batch.rb
|
|
168
|
+
- lib/ratatui_ruby/tea/command/custom.rb
|
|
169
|
+
- lib/ratatui_ruby/tea/command/http.rb
|
|
170
|
+
- lib/ratatui_ruby/tea/command/lifecycle.rb
|
|
171
|
+
- lib/ratatui_ruby/tea/command/outlet.rb
|
|
172
|
+
- lib/ratatui_ruby/tea/command/wait.rb
|
|
173
|
+
- lib/ratatui_ruby/tea/message.rb
|
|
174
|
+
- lib/ratatui_ruby/tea/message/all.rb
|
|
175
|
+
- lib/ratatui_ruby/tea/message/http_response.rb
|
|
176
|
+
- lib/ratatui_ruby/tea/message/system/batch.rb
|
|
177
|
+
- lib/ratatui_ruby/tea/message/system/stream.rb
|
|
178
|
+
- lib/ratatui_ruby/tea/message/timer.rb
|
|
126
179
|
- lib/ratatui_ruby/tea/router.rb
|
|
127
180
|
- lib/ratatui_ruby/tea/runtime.rb
|
|
128
181
|
- lib/ratatui_ruby/tea/shortcuts.rb
|
|
182
|
+
- lib/ratatui_ruby/tea/test_helper.rb
|
|
129
183
|
- lib/ratatui_ruby/tea/version.rb
|
|
130
184
|
- mise.toml
|
|
185
|
+
- rbs_collection.lock.yaml
|
|
186
|
+
- rbs_collection.yaml
|
|
187
|
+
- sig/concurrent.rbs
|
|
131
188
|
- sig/examples/verify_readme_usage/app.rbs
|
|
132
189
|
- sig/examples/widget_command_system/app.rbs
|
|
190
|
+
- sig/open3.rbs
|
|
133
191
|
- sig/ratatui_ruby/tea.rbs
|
|
134
192
|
- sig/ratatui_ruby/tea/command.rbs
|
|
193
|
+
- sig/ratatui_ruby/tea/message.rbs
|
|
135
194
|
- sig/ratatui_ruby/tea/router.rbs
|
|
136
195
|
- sig/ratatui_ruby/tea/runtime.rbs
|
|
196
|
+
- sig/ratatui_ruby/tea/shortcuts.rbs
|
|
197
|
+
- sig/ratatui_ruby/tea/test_helper.rbs
|
|
198
|
+
- sig/ratatui_ruby/tea/version.rbs
|
|
137
199
|
- tasks/example_viewer.html.erb
|
|
138
200
|
- tasks/resources/build.yml.erb
|
|
139
201
|
- tasks/resources/index.html.erb
|
|
140
202
|
- tasks/resources/rubies.yml
|
|
203
|
+
- tasks/steep.rake
|
|
141
204
|
- vendor/goodcop/base.yml
|
|
142
205
|
homepage: https://sr.ht/~kerrick/ratatui_ruby/
|
|
143
206
|
licenses:
|