ratatui_ruby-tea 0.2.0 → 0.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 +4 -4
- data/AGENTS.md +8 -0
- data/CHANGELOG.md +41 -0
- data/README.md +1 -1
- data/doc/concepts/application_architecture.md +182 -3
- data/examples/app_fractal_dashboard/README.md +60 -0
- data/examples/app_fractal_dashboard/app.rb +67 -0
- data/examples/app_fractal_dashboard/bags/custom_shell_input.rb +77 -0
- data/examples/app_fractal_dashboard/bags/custom_shell_modal.rb +73 -0
- data/examples/app_fractal_dashboard/bags/custom_shell_output.rb +86 -0
- data/examples/app_fractal_dashboard/bags/disk_usage.rb +44 -0
- data/examples/app_fractal_dashboard/bags/network_panel.rb +45 -0
- data/examples/app_fractal_dashboard/bags/ping.rb +43 -0
- data/examples/app_fractal_dashboard/bags/stats_panel.rb +45 -0
- data/examples/app_fractal_dashboard/bags/system_info.rb +43 -0
- data/examples/app_fractal_dashboard/bags/uptime.rb +43 -0
- data/examples/app_fractal_dashboard/dashboard/base.rb +74 -0
- data/examples/app_fractal_dashboard/dashboard/update_helpers.rb +86 -0
- data/examples/app_fractal_dashboard/dashboard/update_manual.rb +87 -0
- data/examples/app_fractal_dashboard/dashboard/update_router.rb +43 -0
- data/examples/verify_readme_usage/README.md +1 -1
- data/examples/verify_readme_usage/app.rb +1 -1
- data/examples/{widget_cmd_exec → widget_command_system}/app.rb +18 -18
- data/lib/ratatui_ruby/tea/command.rb +145 -0
- data/lib/ratatui_ruby/tea/router.rb +337 -0
- data/lib/ratatui_ruby/tea/runtime.rb +99 -39
- data/lib/ratatui_ruby/tea/shortcuts.rb +51 -0
- data/lib/ratatui_ruby/tea/version.rb +1 -1
- data/lib/ratatui_ruby/tea.rb +59 -1
- data/sig/ratatui_ruby/tea/command.rbs +47 -0
- data/sig/ratatui_ruby/tea/router.rbs +99 -0
- metadata +26 -8
- data/lib/ratatui_ruby/tea/cmd.rb +0 -88
- data/sig/ratatui_ruby/tea/cmd.rbs +0 -32
- /data/examples/{widget_cmd_exec → widget_command_system}/README.md +0 -0
- /data/sig/examples/{widget_cmd_exec → widget_command_system}/app.rbs +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
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 "command"
|
|
9
|
+
|
|
10
|
+
module RatatuiRuby
|
|
11
|
+
module Tea
|
|
12
|
+
# Convenient short aliases for Tea APIs.
|
|
13
|
+
#
|
|
14
|
+
# The library uses intention-revealing names that match Ruby built-ins:
|
|
15
|
+
# +Command+, +System+, +Exit+. These are great for readability.
|
|
16
|
+
#
|
|
17
|
+
# This module provides the short aliases common in TEA-style code:
|
|
18
|
+
#
|
|
19
|
+
# === Example
|
|
20
|
+
#
|
|
21
|
+
# require "ratatui_ruby/tea/shortcuts"
|
|
22
|
+
# include RatatuiRuby::Tea::Shortcuts
|
|
23
|
+
#
|
|
24
|
+
# # Now use short names freely:
|
|
25
|
+
# Cmd.exit # → Command.exit
|
|
26
|
+
# Cmd.sh("ls", :files) # → Command.system("ls", :files)
|
|
27
|
+
# Cmd.map(child) { ... } # → Command.map(child) { ... }
|
|
28
|
+
module Shortcuts
|
|
29
|
+
# Short alias for +Command+.
|
|
30
|
+
module Cmd
|
|
31
|
+
# Creates an exit command.
|
|
32
|
+
# Alias for +Command.exit+.
|
|
33
|
+
def self.exit
|
|
34
|
+
Command.exit
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Creates a shell execution command.
|
|
38
|
+
# Short alias for +Command.system+.
|
|
39
|
+
def self.sh(command, tag)
|
|
40
|
+
Command.system(command, tag)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Creates a mapped command.
|
|
44
|
+
# Short alias for +Command.map+.
|
|
45
|
+
def self.map(inner_command, &mapper)
|
|
46
|
+
Command.map(inner_command, &mapper)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/ratatui_ruby/tea.rb
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
#++
|
|
7
7
|
|
|
8
8
|
require_relative "tea/version"
|
|
9
|
-
require_relative "tea/
|
|
9
|
+
require_relative "tea/command"
|
|
10
10
|
require_relative "tea/runtime"
|
|
11
|
+
require_relative "tea/router"
|
|
11
12
|
|
|
12
13
|
module RatatuiRuby # :nodoc: Documented in the ratatui_ruby gem.
|
|
13
14
|
# The Elm Architecture for RatatuiRuby.
|
|
@@ -26,5 +27,62 @@ module RatatuiRuby # :nodoc: Documented in the ratatui_ruby gem.
|
|
|
26
27
|
def self.run(...)
|
|
27
28
|
Runtime.run(...)
|
|
28
29
|
end
|
|
30
|
+
|
|
31
|
+
# Wraps a command with a routing prefix.
|
|
32
|
+
#
|
|
33
|
+
# Parent bags trigger child bag commands. The results need routing back
|
|
34
|
+
# to the correct child bag. Manually wrapping every command is tedious.
|
|
35
|
+
#
|
|
36
|
+
# This method prefixes command results automatically. Use it to route
|
|
37
|
+
# child bag command results in Fractal Architecture.
|
|
38
|
+
#
|
|
39
|
+
# [command] The child bag command to wrap.
|
|
40
|
+
# [prefix] Symbol prepended to results (e.g., <tt>:stats</tt>).
|
|
41
|
+
#
|
|
42
|
+
# === Example
|
|
43
|
+
#
|
|
44
|
+
# # Verbose:
|
|
45
|
+
# Command.map(child_bag.fetch_command) { |r| [:stats, *r] }
|
|
46
|
+
#
|
|
47
|
+
# # Concise:
|
|
48
|
+
# Tea.route(child_bag.fetch_command, :stats)
|
|
49
|
+
def self.route(command, prefix)
|
|
50
|
+
Command.map(command) { |result| [prefix, *result] }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Delegates a prefixed message to a child bag's UPDATE.
|
|
54
|
+
#
|
|
55
|
+
# Parent bag UPDATE functions route messages to child bags. Each route
|
|
56
|
+
# requires pattern matching, calling the child, and rewrapping any returned
|
|
57
|
+
# command. The boilerplate adds up fast.
|
|
58
|
+
#
|
|
59
|
+
# This method handles the dispatch. It checks the prefix, calls the child,
|
|
60
|
+
# and wraps any command. Returns <tt>nil</tt> if the prefix does not match.
|
|
61
|
+
#
|
|
62
|
+
# [message] Incoming message (e.g., <tt>[:stats, :system_info, {...}]</tt>).
|
|
63
|
+
# [prefix] Expected prefix symbol (e.g., <tt>:stats</tt>).
|
|
64
|
+
# [child_update] The child's UPDATE callable.
|
|
65
|
+
# [child_model] The child's current model.
|
|
66
|
+
#
|
|
67
|
+
# === Example
|
|
68
|
+
#
|
|
69
|
+
# # Verbose:
|
|
70
|
+
# case message
|
|
71
|
+
# in [:stats, *rest]
|
|
72
|
+
# new_child, cmd = StatsPanel::UPDATE.call(rest, model.stats)
|
|
73
|
+
# mapped = cmd ? Command.map(cmd) { |r| [:stats, *r] } : nil
|
|
74
|
+
# [new_child, mapped]
|
|
75
|
+
# end
|
|
76
|
+
#
|
|
77
|
+
# # Concise:
|
|
78
|
+
# Tea.delegate(message, :stats, StatsPanel::UPDATE, model.stats)
|
|
79
|
+
def self.delegate(message, prefix, child_update, child_model)
|
|
80
|
+
return nil unless message.is_a?(Array) && message.first == prefix
|
|
81
|
+
|
|
82
|
+
rest = message[1..]
|
|
83
|
+
new_child, command = child_update.call(rest, child_model)
|
|
84
|
+
wrapped = command ? route(command, prefix) : nil
|
|
85
|
+
[new_child, wrapped]
|
|
86
|
+
end
|
|
29
87
|
end
|
|
30
88
|
end
|
|
@@ -0,0 +1,47 @@
|
|
|
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 Command
|
|
9
|
+
# Sentinel value for application termination.
|
|
10
|
+
class Exit < Data
|
|
11
|
+
def self.new: () -> instance
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Command to run a shell command via Open3.
|
|
15
|
+
class System < Data
|
|
16
|
+
attr_reader command: String
|
|
17
|
+
attr_reader tag: Symbol | Class
|
|
18
|
+
attr_reader stream: bool
|
|
19
|
+
|
|
20
|
+
# Returns true if streaming mode is enabled.
|
|
21
|
+
def stream?: () -> bool
|
|
22
|
+
|
|
23
|
+
def self.new: (command: String, tag: (Symbol | Class), stream: bool) -> instance
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Command that wraps another command's result with a transformation.
|
|
27
|
+
class Mapped < Data
|
|
28
|
+
attr_reader inner_command: execution
|
|
29
|
+
attr_reader mapper: ^(untyped) -> untyped
|
|
30
|
+
|
|
31
|
+
def self.new: (inner_command: execution, mapper: ^(untyped) -> untyped) -> instance
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Union type for all valid commands
|
|
35
|
+
type execution = Execute | Mapped
|
|
36
|
+
|
|
37
|
+
# Creates a quit command.
|
|
38
|
+
def self.exit: () -> Quit
|
|
39
|
+
|
|
40
|
+
# Creates a shell execution command.
|
|
41
|
+
def self.system: (String command, (Symbol | Class) tag, ?stream: bool) -> System
|
|
42
|
+
|
|
43
|
+
# Creates a mapped command for Fractal Architecture composition.
|
|
44
|
+
def self.map: (execution inner_command) { (untyped) -> untyped } -> Mapped
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
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
|
+
# 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
|
+
# Declarative DSL for Fractal Architecture.
|
|
15
|
+
module Router
|
|
16
|
+
def self.included: (Class base) -> void
|
|
17
|
+
|
|
18
|
+
# Guard callable: receives model, returns truthy/falsy.
|
|
19
|
+
type guard[M] = ^(M model) -> boolish
|
|
20
|
+
|
|
21
|
+
# Handler callable: returns a command or nil.
|
|
22
|
+
type handler = ^() -> Command::execution?
|
|
23
|
+
|
|
24
|
+
# Click handler: receives x, y coordinates.
|
|
25
|
+
type click_handler = ^(Integer x, Integer y) -> Command::execution?
|
|
26
|
+
|
|
27
|
+
# Key handler config stored in handlers hash.
|
|
28
|
+
type key_config[M] = {
|
|
29
|
+
handler: handler?,
|
|
30
|
+
action: Symbol?,
|
|
31
|
+
route: Symbol?,
|
|
32
|
+
guard: guard[M]?
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Mouse handler config.
|
|
36
|
+
type mouse_config = {
|
|
37
|
+
handler: handler | click_handler,
|
|
38
|
+
action: Symbol?
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Class methods added when Router is included.
|
|
42
|
+
module ClassMethods
|
|
43
|
+
def route: [M] (Symbol | String prefix, to: _Bag[M]) -> void
|
|
44
|
+
def routes: () -> Hash[Symbol, Module]
|
|
45
|
+
|
|
46
|
+
def action: (Symbol | String name, handler) -> void
|
|
47
|
+
def actions: () -> Hash[Symbol, handler]
|
|
48
|
+
|
|
49
|
+
def keymap: () { () -> void } -> void
|
|
50
|
+
def key_handlers: [M] () -> Hash[String, key_config[M]]
|
|
51
|
+
|
|
52
|
+
def mousemap: () { () -> void } -> void
|
|
53
|
+
def mouse_handlers: () -> Hash[Symbol, mouse_config]
|
|
54
|
+
|
|
55
|
+
# Generates an UPDATE lambda from routes, keymap, and mousemap.
|
|
56
|
+
def from_router: [M, Msg] () -> ^(Msg message, M model) -> [M, Command::execution?]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Builder for keymap DSL.
|
|
60
|
+
class KeymapBuilder
|
|
61
|
+
@handlers: Hash[String, key_config[top]]
|
|
62
|
+
|
|
63
|
+
attr_reader handlers: Hash[String, key_config[top]]
|
|
64
|
+
|
|
65
|
+
def initialize: () -> void
|
|
66
|
+
|
|
67
|
+
# Registers a key handler with optional guards.
|
|
68
|
+
def key: [M] (
|
|
69
|
+
String | Symbol key_name,
|
|
70
|
+
handler | Symbol handler_or_action,
|
|
71
|
+
?route: Symbol?,
|
|
72
|
+
?when: guard[M]?,
|
|
73
|
+
?if: guard[M]?,
|
|
74
|
+
?only: guard[M]?,
|
|
75
|
+
?guard: guard[M]?,
|
|
76
|
+
?unless: guard[M]?,
|
|
77
|
+
?except: guard[M]?,
|
|
78
|
+
?skip: guard[M]?
|
|
79
|
+
) -> void
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Builder for mousemap DSL.
|
|
83
|
+
class MousemapBuilder
|
|
84
|
+
@handlers: Hash[Symbol, mouse_config]
|
|
85
|
+
|
|
86
|
+
attr_reader handlers: Hash[Symbol, mouse_config]
|
|
87
|
+
|
|
88
|
+
def initialize: () -> void
|
|
89
|
+
|
|
90
|
+
def click: (click_handler | Symbol handler_or_action) -> void
|
|
91
|
+
def scroll: (:up | :down direction, handler | Symbol handler_or_action) -> void
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def register: (Symbol key, handler | click_handler | Symbol handler_or_action) -> void
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
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.3.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:
|
|
18
|
+
version: 0.9.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:
|
|
25
|
+
version: 0.9.1
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: ostruct
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -101,20 +101,38 @@ files:
|
|
|
101
101
|
- doc/images/verify_readme_usage.png
|
|
102
102
|
- doc/images/widget_cmd_exec.png
|
|
103
103
|
- doc/index.md
|
|
104
|
+
- examples/app_fractal_dashboard/README.md
|
|
105
|
+
- 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
|
+
- examples/app_fractal_dashboard/dashboard/base.rb
|
|
116
|
+
- examples/app_fractal_dashboard/dashboard/update_helpers.rb
|
|
117
|
+
- examples/app_fractal_dashboard/dashboard/update_manual.rb
|
|
118
|
+
- examples/app_fractal_dashboard/dashboard/update_router.rb
|
|
104
119
|
- examples/verify_readme_usage/README.md
|
|
105
120
|
- examples/verify_readme_usage/app.rb
|
|
106
|
-
- examples/
|
|
107
|
-
- examples/
|
|
121
|
+
- examples/widget_command_system/README.md
|
|
122
|
+
- examples/widget_command_system/app.rb
|
|
108
123
|
- exe/.gitkeep
|
|
109
124
|
- lib/ratatui_ruby/tea.rb
|
|
110
|
-
- lib/ratatui_ruby/tea/
|
|
125
|
+
- lib/ratatui_ruby/tea/command.rb
|
|
126
|
+
- lib/ratatui_ruby/tea/router.rb
|
|
111
127
|
- lib/ratatui_ruby/tea/runtime.rb
|
|
128
|
+
- lib/ratatui_ruby/tea/shortcuts.rb
|
|
112
129
|
- lib/ratatui_ruby/tea/version.rb
|
|
113
130
|
- mise.toml
|
|
114
131
|
- sig/examples/verify_readme_usage/app.rbs
|
|
115
|
-
- sig/examples/
|
|
132
|
+
- sig/examples/widget_command_system/app.rbs
|
|
116
133
|
- sig/ratatui_ruby/tea.rbs
|
|
117
|
-
- sig/ratatui_ruby/tea/
|
|
134
|
+
- sig/ratatui_ruby/tea/command.rbs
|
|
135
|
+
- sig/ratatui_ruby/tea/router.rbs
|
|
118
136
|
- sig/ratatui_ruby/tea/runtime.rbs
|
|
119
137
|
- tasks/example_viewer.html.erb
|
|
120
138
|
- tasks/resources/build.yml.erb
|
data/lib/ratatui_ruby/tea/cmd.rb
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
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
|
-
module Tea
|
|
10
|
-
# Commands represent side effects.
|
|
11
|
-
#
|
|
12
|
-
# The MVU pattern separates logic from effects. Your update function returns a pure
|
|
13
|
-
# model transformation. Side effects go in commands. The runtime executes them.
|
|
14
|
-
#
|
|
15
|
-
# Commands produce **messages**, not callbacks. The +tag+ argument names the message
|
|
16
|
-
# so your update function can pattern-match on it. This keeps all logic in +update+
|
|
17
|
-
# and ensures messages are Ractor-shareable.
|
|
18
|
-
#
|
|
19
|
-
# === Examples
|
|
20
|
-
#
|
|
21
|
-
# # Terminate the application
|
|
22
|
-
# [model, Cmd.quit]
|
|
23
|
-
#
|
|
24
|
-
# # Run a shell command; produces [:got_files, {stdout:, stderr:, status:}]
|
|
25
|
-
# [model, Cmd.exec("ls -la", :got_files)]
|
|
26
|
-
#
|
|
27
|
-
# # No side effect
|
|
28
|
-
# [model, nil]
|
|
29
|
-
module Cmd
|
|
30
|
-
# Sentinel value for application termination.
|
|
31
|
-
#
|
|
32
|
-
# The runtime detects this before dispatching. It breaks the loop immediately.
|
|
33
|
-
Quit = Data.define
|
|
34
|
-
|
|
35
|
-
# Creates a quit command.
|
|
36
|
-
#
|
|
37
|
-
# Returns a sentinel the runtime detects to terminate the application.
|
|
38
|
-
#
|
|
39
|
-
# === Example
|
|
40
|
-
#
|
|
41
|
-
# def update(msg, model)
|
|
42
|
-
# case msg
|
|
43
|
-
# in { type: :key, code: "q" }
|
|
44
|
-
# [model, Cmd.quit]
|
|
45
|
-
# else
|
|
46
|
-
# [model, nil]
|
|
47
|
-
# end
|
|
48
|
-
# end
|
|
49
|
-
def self.quit
|
|
50
|
-
Quit.new
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Command to run a shell command via Open3.
|
|
54
|
-
#
|
|
55
|
-
# The runtime executes the command and produces a message:
|
|
56
|
-
# <tt>[tag, {stdout:, stderr:, status:}]</tt>
|
|
57
|
-
#
|
|
58
|
-
# The +status+ is the integer exit code (0 = success).
|
|
59
|
-
Exec = Data.define(:command, :tag)
|
|
60
|
-
|
|
61
|
-
# Creates a shell execution command.
|
|
62
|
-
#
|
|
63
|
-
# [command] Shell command string to execute.
|
|
64
|
-
# [tag] Symbol or class to tag the result message.
|
|
65
|
-
#
|
|
66
|
-
# When the command completes, the runtime sends
|
|
67
|
-
# <tt>[tag, {stdout:, stderr:, status:}]</tt> to update.
|
|
68
|
-
#
|
|
69
|
-
# === Example
|
|
70
|
-
#
|
|
71
|
-
# # Return this from update:
|
|
72
|
-
# [model.with(loading: true), Cmd.exec("ls -la", :got_files)]
|
|
73
|
-
#
|
|
74
|
-
# # Then handle it later:
|
|
75
|
-
# def update(msg, model)
|
|
76
|
-
# case msg
|
|
77
|
-
# in [:got_files, {stdout:, status: 0}]
|
|
78
|
-
# [model.with(files: stdout.lines), nil]
|
|
79
|
-
# in [:got_files, {stderr:, status:}]
|
|
80
|
-
# [model.with(error: stderr), nil]
|
|
81
|
-
# end
|
|
82
|
-
# end
|
|
83
|
-
def self.exec(command, tag)
|
|
84
|
-
Exec.new(command:, tag:)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
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 Cmd
|
|
9
|
-
# Sentinel value for application termination.
|
|
10
|
-
class Quit < Data
|
|
11
|
-
def self.new: () -> instance
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# Command to run a shell command via Open3.
|
|
15
|
-
class Exec < Data
|
|
16
|
-
attr_reader command: String
|
|
17
|
-
attr_reader tag: Symbol | Class
|
|
18
|
-
|
|
19
|
-
def self.new: (command: String, tag: (Symbol | Class)) -> instance
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Union type for all valid commands
|
|
23
|
-
type execution = Exec
|
|
24
|
-
|
|
25
|
-
# Creates a quit command.
|
|
26
|
-
def self.quit: () -> Quit
|
|
27
|
-
|
|
28
|
-
# Creates a shell execution command.
|
|
29
|
-
def self.exec: (String command, (Symbol | Class) tag) -> Exec
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
File without changes
|
|
File without changes
|