charming 0.2.0 → 0.2.1
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/README.md +2 -2
- data/lib/charming/application.rb +96 -9
- data/lib/charming/audio/player.rb +104 -0
- data/lib/charming/audio/system.rb +69 -0
- data/lib/charming/cli.rb +63 -7
- data/lib/charming/controller/action_hooks.rb +124 -0
- data/lib/charming/controller/class_methods.rb +15 -1
- data/lib/charming/controller/dispatching.rb +31 -5
- data/lib/charming/controller/focus.rb +9 -0
- data/lib/charming/controller/focus_management.rb +0 -7
- data/lib/charming/controller/session_state.rb +16 -1
- data/lib/charming/controller/sidebar_navigation.rb +63 -28
- data/lib/charming/controller.rb +62 -10
- data/lib/charming/database/commands.rb +123 -11
- data/lib/charming/events/focus_event.rb +12 -0
- data/lib/charming/events/paste_event.rb +11 -0
- data/lib/charming/events/task_progress_event.rb +21 -0
- data/lib/charming/generators/app_generator.rb +38 -1
- data/lib/charming/generators/database_installer.rb +4 -15
- data/lib/charming/generators/migration_generator.rb +116 -0
- data/lib/charming/generators/migration_timestamp.rb +29 -0
- data/lib/charming/generators/model_generator.rb +4 -2
- data/lib/charming/generators/templates/app/application_controller.template +1 -1
- data/lib/charming/generators/templates/app/database_config.template +3 -1
- data/lib/charming/generators/templates/app/layout.template +1 -1
- data/lib/charming/generators/templates/app/spec_helper.template +2 -1
- data/lib/charming/generators/templates/app/view.template +1 -1
- data/lib/charming/internal/terminal/memory_backend.rb +6 -0
- data/lib/charming/internal/terminal/tty_backend.rb +64 -2
- data/lib/charming/presentation/component.rb +7 -0
- data/lib/charming/presentation/components/audio.rb +31 -0
- data/lib/charming/presentation/components/autocomplete.rb +108 -0
- data/lib/charming/presentation/components/badge.rb +31 -0
- data/lib/charming/presentation/components/breadcrumbs.rb +29 -0
- data/lib/charming/presentation/components/command_palette.rb +8 -5
- data/lib/charming/presentation/components/error_screen.rb +72 -0
- data/lib/charming/presentation/components/form.rb +9 -0
- data/lib/charming/presentation/components/fuzzy_matcher.rb +83 -0
- data/lib/charming/presentation/components/help_overlay.rb +65 -0
- data/lib/charming/presentation/components/markdown.rb +6 -2
- data/lib/charming/presentation/components/modal.rb +45 -5
- data/lib/charming/presentation/components/multi_select_list.rb +85 -0
- data/lib/charming/presentation/components/progressbar.rb +0 -1
- data/lib/charming/presentation/components/status_bar.rb +75 -0
- data/lib/charming/presentation/components/tab_bar.rb +103 -0
- data/lib/charming/presentation/components/table.rb +40 -9
- data/lib/charming/presentation/components/text_area.rb +47 -10
- data/lib/charming/presentation/components/text_input.rb +79 -4
- data/lib/charming/presentation/components/toast.rb +51 -0
- data/lib/charming/presentation/components/tree.rb +176 -0
- data/lib/charming/presentation/components/viewport/content_lines.rb +55 -0
- data/lib/charming/presentation/components/viewport/line_window.rb +71 -0
- data/lib/charming/presentation/components/viewport/position.rb +67 -0
- data/lib/charming/presentation/components/viewport.rb +37 -122
- data/lib/charming/presentation/layout/builder.rb +4 -1
- data/lib/charming/presentation/layout/overlay.rb +6 -4
- data/lib/charming/presentation/layout/pane.rb +2 -1
- data/lib/charming/presentation/layout/pane_geometry.rb +16 -8
- data/lib/charming/presentation/layout/screen_layout.rb +12 -3
- data/lib/charming/presentation/layout/split.rb +37 -3
- data/lib/charming/presentation/markdown/renderer.rb +99 -63
- data/lib/charming/presentation/markdown/style_config.rb +10 -5
- data/lib/charming/presentation/markdown/syntax_highlighter.rb +11 -1
- data/lib/charming/presentation/markdown/table_renderer.rb +60 -0
- data/lib/charming/presentation/markdown/text_wrapper.rb +40 -0
- data/lib/charming/presentation/markdown/url_resolver.rb +27 -0
- data/lib/charming/presentation/templates/erb_handler.rb +35 -2
- data/lib/charming/presentation/ui/ansi_codes.rb +11 -0
- data/lib/charming/presentation/ui/ansi_slicer.rb +20 -13
- data/lib/charming/presentation/ui/color_support.rb +129 -0
- data/lib/charming/presentation/ui/theme.rb +7 -0
- data/lib/charming/presentation/ui/themes/catppuccin-latte.json +35 -0
- data/lib/charming/presentation/ui/themes/catppuccin-mocha.json +35 -0
- data/lib/charming/presentation/ui/themes/gruvbox-dark.json +33 -0
- data/lib/charming/presentation/ui/themes/nord.json +32 -0
- data/lib/charming/presentation/ui/themes/tokyonight.json +34 -0
- data/lib/charming/presentation/ui/width.rb +27 -2
- data/lib/charming/router.rb +1 -1
- data/lib/charming/runtime.rb +122 -15
- data/lib/charming/tasks/cancelled.rb +11 -0
- data/lib/charming/tasks/inline_executor.rb +10 -4
- data/lib/charming/tasks/progress.rb +30 -0
- data/lib/charming/tasks/task.rb +24 -4
- data/lib/charming/tasks/threaded_executor.rb +35 -11
- data/lib/charming/test_helper.rb +120 -0
- data/lib/charming/version.rb +1 -1
- data/lib/charming.rb +43 -1
- metadata +36 -49
data/lib/charming/tasks/task.rb
CHANGED
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "timeout"
|
|
4
|
+
|
|
3
5
|
module Charming
|
|
4
6
|
module Tasks
|
|
5
7
|
# Task is the unit of work submitted to a task executor. It pairs a *name* (used by
|
|
6
|
-
# `on_task` handlers to route the result) with a *block* to invoke on the executor
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def
|
|
8
|
+
# `on_task` handlers to route the result) with a *block* to invoke on the executor,
|
|
9
|
+
# plus an optional *timeout* in seconds.
|
|
10
|
+
Task = Data.define(:name, :block, :timeout) do
|
|
11
|
+
def initialize(name:, block:, timeout: nil)
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Invokes the task's block, passing *progress* when the block accepts an argument.
|
|
16
|
+
# Enforces the timeout (raising Tasks::Cancelled) when one was configured.
|
|
17
|
+
def call(progress = nil)
|
|
18
|
+
return invoke(progress) unless timeout
|
|
19
|
+
|
|
20
|
+
Timeout.timeout(timeout, Cancelled, "task #{name} timed out after #{timeout}s") do
|
|
21
|
+
invoke(progress)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def invoke(progress)
|
|
28
|
+
block.arity.zero? ? block.call : block.call(progress)
|
|
29
|
+
end
|
|
10
30
|
end
|
|
11
31
|
end
|
|
12
32
|
end
|
|
@@ -5,30 +5,53 @@ module Charming
|
|
|
5
5
|
# ThreadedExecutor runs submitted tasks on background Ruby threads. Each submission
|
|
6
6
|
# creates a new thread that invokes the block and pushes the resulting TaskEvent
|
|
7
7
|
# onto the shared *queue*. Threads are tracked so `shutdown` can wait (or kill)
|
|
8
|
-
# in-flight work.
|
|
8
|
+
# in-flight work, and tracked by name so `cancel` can interrupt a specific task.
|
|
9
9
|
class ThreadedExecutor
|
|
10
10
|
# *queue* is the thread-safe Queue (typically `runtime.@task_queue`) into which
|
|
11
11
|
# completed TaskEvents are pushed.
|
|
12
12
|
def initialize(queue)
|
|
13
13
|
@queue = queue
|
|
14
14
|
@threads = []
|
|
15
|
+
@threads_by_name = {}
|
|
15
16
|
@mutex = Mutex.new
|
|
17
|
+
@shutting_down = false
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
# Wraps *block* in a Task and spawns a new thread to invoke it. The thread's
|
|
19
21
|
# return value (or rescued exception) is pushed onto the queue as a TaskEvent.
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
# Blocks that accept an argument receive a Progress reporter. *timeout* (seconds)
|
|
23
|
+
# cancels the task when exceeded. Returns nil immediately. Raises if called after
|
|
24
|
+
# shutdown has begun.
|
|
25
|
+
def submit(name, timeout: nil, &block)
|
|
26
|
+
task = Task.new(name: name.to_sym, block: block, timeout: timeout)
|
|
27
|
+
@mutex.synchronize do
|
|
28
|
+
raise "cannot submit task after shutdown" if @shutting_down
|
|
29
|
+
|
|
30
|
+
thread = Thread.new(task) { |t| @queue << run(t) }
|
|
31
|
+
@threads << thread
|
|
32
|
+
@threads_by_name[task.name] = thread
|
|
33
|
+
end
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Cancels the named in-flight task by raising Tasks::Cancelled in its thread.
|
|
38
|
+
# The task completes with a TaskEvent whose error is the Cancelled exception.
|
|
39
|
+
# No-op when the task isn't running.
|
|
40
|
+
def cancel(name)
|
|
41
|
+
thread = @mutex.synchronize { @threads_by_name[name.to_sym] }
|
|
42
|
+
return unless thread&.alive?
|
|
43
|
+
|
|
44
|
+
thread.raise(Cancelled, "task #{name} cancelled")
|
|
25
45
|
nil
|
|
26
46
|
end
|
|
27
47
|
|
|
28
48
|
# Waits up to *timeout* seconds for in-flight threads to finish, then kills any
|
|
29
|
-
# remaining live threads.
|
|
30
|
-
def shutdown(timeout:
|
|
31
|
-
threads = @mutex.synchronize
|
|
49
|
+
# remaining live threads. Refuses new submissions once called.
|
|
50
|
+
def shutdown(timeout: 2.0)
|
|
51
|
+
threads = @mutex.synchronize do
|
|
52
|
+
@shutting_down = true
|
|
53
|
+
@threads.dup
|
|
54
|
+
end
|
|
32
55
|
threads.each { |thread| thread.join(timeout) }
|
|
33
56
|
threads.each do |thread|
|
|
34
57
|
next unless thread.alive?
|
|
@@ -40,9 +63,10 @@ module Charming
|
|
|
40
63
|
|
|
41
64
|
private
|
|
42
65
|
|
|
43
|
-
# Invokes the task's block and wraps the result
|
|
66
|
+
# Invokes the task's block (passing a Progress reporter) and wraps the result
|
|
67
|
+
# (or rescued exception) in a TaskEvent.
|
|
44
68
|
def run(task)
|
|
45
|
-
Events::TaskEvent.new(name: task.name, value: task.call)
|
|
69
|
+
Events::TaskEvent.new(name: task.name, value: task.call(Progress.new(@queue, task.name)))
|
|
46
70
|
rescue StandardError, ScriptError => e
|
|
47
71
|
Events::TaskEvent.new(name: task.name, error: e)
|
|
48
72
|
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "charming"
|
|
4
|
+
|
|
5
|
+
module Charming
|
|
6
|
+
# TestHelper provides controller- and component-level test ergonomics for Charming apps,
|
|
7
|
+
# in the spirit of Rails' ActionController::TestCase:
|
|
8
|
+
#
|
|
9
|
+
# require "charming/test_helper"
|
|
10
|
+
#
|
|
11
|
+
# RSpec.describe HomeController do
|
|
12
|
+
# include Charming::TestHelper
|
|
13
|
+
#
|
|
14
|
+
# let(:ctrl) { build_controller(HomeController) }
|
|
15
|
+
#
|
|
16
|
+
# it "renders a greeting" do
|
|
17
|
+
# expect(ctrl.dispatch(:show)).to render_text("Welcome")
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# it "quits on q" do
|
|
21
|
+
# expect(press(ctrl_class: HomeController, key: "q")).to be_quit
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# Helpers:
|
|
26
|
+
# - `build_controller(klass, app:, screen:, route:)` — controller instance wired to an app
|
|
27
|
+
# - `key_event("ctrl+p")` — build a KeyEvent from a human-readable string
|
|
28
|
+
# - `press(controller_or_class, "down")` — dispatch a key press, returns the Response
|
|
29
|
+
# - `press_sequence(klass, ["down", "down", "enter"], app:)` — dispatch several presses
|
|
30
|
+
#
|
|
31
|
+
# RSpec matchers (when RSpec is loaded):
|
|
32
|
+
# - `expect(response).to render_text("...")` / `render_match(/.../)`
|
|
33
|
+
# - `expect(response).to be_quit` / `be_navigate` (predicate matchers on Response)
|
|
34
|
+
# - `expect(response).to navigate_to("/path")`
|
|
35
|
+
module TestHelper
|
|
36
|
+
# Builds a controller instance with sensible test defaults: a fresh Application,
|
|
37
|
+
# an 80x24 screen, and no event.
|
|
38
|
+
def build_controller(controller_class, app: nil, screen: nil, route: nil, event: nil)
|
|
39
|
+
app ||= Charming::Application.new
|
|
40
|
+
screen ||= Charming::Screen.new(width: 80, height: 24)
|
|
41
|
+
controller_class.new(application: app, event: event, screen: screen, route: route)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Builds a KeyEvent from a human-readable string like "q", "down", "ctrl+p",
|
|
45
|
+
# or "shift+tab". Modifier order is irrelevant.
|
|
46
|
+
def key_event(description)
|
|
47
|
+
parts = description.to_s.split("+")
|
|
48
|
+
key = parts.pop
|
|
49
|
+
modifiers = parts.map(&:downcase)
|
|
50
|
+
char = (key.length == 1) ? key : nil
|
|
51
|
+
Charming::Events::KeyEvent.new(
|
|
52
|
+
key: key.to_sym,
|
|
53
|
+
char: char,
|
|
54
|
+
ctrl: modifiers.include?("ctrl") || modifiers.include?("control"),
|
|
55
|
+
alt: modifiers.include?("alt"),
|
|
56
|
+
shift: modifiers.include?("shift")
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Dispatches a single key press against *controller_class* and returns the Response.
|
|
61
|
+
# Pass `app:` to share session state across presses.
|
|
62
|
+
def press(controller_class, key, app:, screen: nil, route: nil)
|
|
63
|
+
controller = build_controller(controller_class, app: app, screen: screen, route: route, event: key_event(key))
|
|
64
|
+
controller.dispatch_key
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Dispatches each key in *keys* in order against fresh controller instances sharing
|
|
68
|
+
# *app*'s session (mirroring the runtime's controller-per-event model). Returns the
|
|
69
|
+
# last Response.
|
|
70
|
+
def press_sequence(controller_class, keys, app:, screen: nil, route: nil)
|
|
71
|
+
keys.map { |key| press(controller_class, key, app: app, screen: screen, route: route) }.last
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Builds a MemoryBackend pre-seeded with KeyEvents parsed from *keys*, ready to be
|
|
75
|
+
# passed to Charming::Runtime for integration-style tests.
|
|
76
|
+
def memory_backend(*keys, width: 80, height: 24)
|
|
77
|
+
events = keys.map { |key| key.is_a?(String) ? key_event(key) : key }
|
|
78
|
+
Charming::Internal::Terminal::MemoryBackend.new(events: events, width: width, height: height)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
if defined?(RSpec)
|
|
84
|
+
# Both matchers compare against the ANSI-stripped body: styled output interleaves
|
|
85
|
+
# escape codes mid-phrase (each styled segment emits its own codes), so raw
|
|
86
|
+
# substring matching would fail on any text spanning two styles.
|
|
87
|
+
RSpec::Matchers.define :render_text do |expected|
|
|
88
|
+
match do |response|
|
|
89
|
+
response.respond_to?(:body) &&
|
|
90
|
+
Charming::UI::Width.strip_ansi(response.body.to_s).include?(expected)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
failure_message do |response|
|
|
94
|
+
body = response.respond_to?(:body) ? Charming::UI::Width.strip_ansi(response.body.to_s) : response.inspect
|
|
95
|
+
"expected response body to include #{expected.inspect}, got:\n#{body}"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
RSpec::Matchers.define :render_match do |pattern|
|
|
100
|
+
match do |response|
|
|
101
|
+
response.respond_to?(:body) &&
|
|
102
|
+
Charming::UI::Width.strip_ansi(response.body.to_s).match?(pattern)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
failure_message do |response|
|
|
106
|
+
body = response.respond_to?(:body) ? Charming::UI::Width.strip_ansi(response.body.to_s) : response.inspect
|
|
107
|
+
"expected response body to match #{pattern.inspect}, got:\n#{body}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
RSpec::Matchers.define :navigate_to do |expected_path|
|
|
112
|
+
match do |response|
|
|
113
|
+
response.respond_to?(:navigate?) && response.navigate? && response.path == expected_path
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
failure_message do |response|
|
|
117
|
+
"expected a navigation response to #{expected_path.inspect}, got: #{response.inspect}"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
data/lib/charming/version.rb
CHANGED
data/lib/charming.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_support/inflector"
|
|
4
|
+
require "active_support/string_inquirer"
|
|
4
5
|
require "logger"
|
|
5
6
|
require "zeitwerk"
|
|
6
7
|
|
|
@@ -15,7 +16,8 @@ loader.inflector.inflect(
|
|
|
15
16
|
"erb_handler" => "ErbHandler",
|
|
16
17
|
"key_normalizer" => "KeyNormalizer",
|
|
17
18
|
"mouse_parser" => "MouseParser",
|
|
18
|
-
"tty_backend" => "TTYBackend"
|
|
19
|
+
"tty_backend" => "TTYBackend",
|
|
20
|
+
"url_resolver" => "URLResolver"
|
|
19
21
|
)
|
|
20
22
|
loader.collapse("#{__dir__}/charming/presentation")
|
|
21
23
|
loader.setup
|
|
@@ -24,6 +26,17 @@ module Charming
|
|
|
24
26
|
# Base error class for all Charming-specific exceptions (used by templates, generators, runtime, etc.).
|
|
25
27
|
class Error < StandardError; end
|
|
26
28
|
|
|
29
|
+
# The current environment, read from CHARMING_ENV (default "development"). Returns a
|
|
30
|
+
# StringInquirer so callers can write `Charming.env.test?` / `Charming.env.production?`.
|
|
31
|
+
def self.env
|
|
32
|
+
@env ||= ActiveSupport::StringInquirer.new(ENV["CHARMING_ENV"] || "development")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Overrides the environment (used by tests and the CLI).
|
|
36
|
+
def self.env=(value)
|
|
37
|
+
@env = value.nil? ? nil : ActiveSupport::StringInquirer.new(value.to_s)
|
|
38
|
+
end
|
|
39
|
+
|
|
27
40
|
# Entry point for running a Charming application. Instantiates a Runtime for *application* and starts
|
|
28
41
|
# the event loop. *backend* defaults to TTYBackend; tests pass MemoryBackend directly via `Charming::Runtime.new`.
|
|
29
42
|
def self.run(application, backend: nil)
|
|
@@ -36,6 +49,35 @@ module Charming
|
|
|
36
49
|
key = event.respond_to?(:key) ? event.key : event
|
|
37
50
|
key.to_sym
|
|
38
51
|
end
|
|
52
|
+
|
|
53
|
+
# Returns the key signature used for controller bindings, including modifier flags.
|
|
54
|
+
def self.key_signature(event)
|
|
55
|
+
key = key_of(event)
|
|
56
|
+
modifiers = []
|
|
57
|
+
modifiers << "ctrl" if event.respond_to?(:ctrl) && event.ctrl
|
|
58
|
+
modifiers << "alt" if event.respond_to?(:alt) && event.alt
|
|
59
|
+
modifiers << "shift" if event.respond_to?(:shift) && event.shift
|
|
60
|
+
|
|
61
|
+
return key if modifiers.empty?
|
|
62
|
+
|
|
63
|
+
:"#{modifiers.join("+")}+#{key}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Normalizes key declarations so `control+p` and `ctrl+p` resolve to the same binding.
|
|
67
|
+
def self.key_binding_name(name)
|
|
68
|
+
parts = name.to_s.split("+")
|
|
69
|
+
return name.to_sym if parts.size == 1
|
|
70
|
+
|
|
71
|
+
key = parts.pop.downcase
|
|
72
|
+
modifiers = parts.map do |part|
|
|
73
|
+
modifier = part.downcase
|
|
74
|
+
(modifier == "control") ? "ctrl" : modifier
|
|
75
|
+
end
|
|
76
|
+
ordered_modifiers = %w[ctrl alt shift].select { |modifier| modifiers.include?(modifier) }
|
|
77
|
+
ordered_modifiers += modifiers - ordered_modifiers
|
|
78
|
+
|
|
79
|
+
:"#{(ordered_modifiers + [key]).join("+")}"
|
|
80
|
+
end
|
|
39
81
|
end
|
|
40
82
|
|
|
41
83
|
Charming::Templates.register ".tui.erb", Charming::Templates::ErbHandler
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: charming
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- pando
|
|
@@ -29,26 +29,6 @@ dependencies:
|
|
|
29
29
|
- - ">="
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
31
|
version: 8.1.2
|
|
32
|
-
- !ruby/object:Gem::Dependency
|
|
33
|
-
name: activerecord
|
|
34
|
-
requirement: !ruby/object:Gem::Requirement
|
|
35
|
-
requirements:
|
|
36
|
-
- - "~>"
|
|
37
|
-
- !ruby/object:Gem::Version
|
|
38
|
-
version: '8.1'
|
|
39
|
-
- - ">="
|
|
40
|
-
- !ruby/object:Gem::Version
|
|
41
|
-
version: 8.1.2
|
|
42
|
-
type: :runtime
|
|
43
|
-
prerelease: false
|
|
44
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
-
requirements:
|
|
46
|
-
- - "~>"
|
|
47
|
-
- !ruby/object:Gem::Version
|
|
48
|
-
version: '8.1'
|
|
49
|
-
- - ">="
|
|
50
|
-
- !ruby/object:Gem::Version
|
|
51
|
-
version: 8.1.2
|
|
52
32
|
- !ruby/object:Gem::Dependency
|
|
53
33
|
name: activesupport
|
|
54
34
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -111,20 +91,6 @@ dependencies:
|
|
|
111
91
|
- - "~>"
|
|
112
92
|
- !ruby/object:Gem::Version
|
|
113
93
|
version: '5.0'
|
|
114
|
-
- !ruby/object:Gem::Dependency
|
|
115
|
-
name: sqlite3
|
|
116
|
-
requirement: !ruby/object:Gem::Requirement
|
|
117
|
-
requirements:
|
|
118
|
-
- - "~>"
|
|
119
|
-
- !ruby/object:Gem::Version
|
|
120
|
-
version: '2.0'
|
|
121
|
-
type: :runtime
|
|
122
|
-
prerelease: false
|
|
123
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
124
|
-
requirements:
|
|
125
|
-
- - "~>"
|
|
126
|
-
- !ruby/object:Gem::Version
|
|
127
|
-
version: '2.0'
|
|
128
94
|
- !ruby/object:Gem::Dependency
|
|
129
95
|
name: tty-cursor
|
|
130
96
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -153,20 +119,6 @@ dependencies:
|
|
|
153
119
|
- - "~>"
|
|
154
120
|
- !ruby/object:Gem::Version
|
|
155
121
|
version: '2.6'
|
|
156
|
-
- !ruby/object:Gem::Dependency
|
|
157
|
-
name: tty-progressbar
|
|
158
|
-
requirement: !ruby/object:Gem::Requirement
|
|
159
|
-
requirements:
|
|
160
|
-
- - "~>"
|
|
161
|
-
- !ruby/object:Gem::Version
|
|
162
|
-
version: '0.18'
|
|
163
|
-
type: :runtime
|
|
164
|
-
prerelease: false
|
|
165
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
166
|
-
requirements:
|
|
167
|
-
- - "~>"
|
|
168
|
-
- !ruby/object:Gem::Version
|
|
169
|
-
version: '0.18'
|
|
170
122
|
- !ruby/object:Gem::Dependency
|
|
171
123
|
name: tty-table
|
|
172
124
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -238,8 +190,11 @@ files:
|
|
|
238
190
|
- lib/charming.rb
|
|
239
191
|
- lib/charming/application.rb
|
|
240
192
|
- lib/charming/application_state.rb
|
|
193
|
+
- lib/charming/audio/player.rb
|
|
194
|
+
- lib/charming/audio/system.rb
|
|
241
195
|
- lib/charming/cli.rb
|
|
242
196
|
- lib/charming/controller.rb
|
|
197
|
+
- lib/charming/controller/action_hooks.rb
|
|
243
198
|
- lib/charming/controller/class_methods.rb
|
|
244
199
|
- lib/charming/controller/command_palette.rb
|
|
245
200
|
- lib/charming/controller/component_dispatching.rb
|
|
@@ -250,10 +205,13 @@ files:
|
|
|
250
205
|
- lib/charming/controller/session_state.rb
|
|
251
206
|
- lib/charming/controller/sidebar_navigation.rb
|
|
252
207
|
- lib/charming/database/commands.rb
|
|
208
|
+
- lib/charming/events/focus_event.rb
|
|
253
209
|
- lib/charming/events/key_event.rb
|
|
254
210
|
- lib/charming/events/mouse_event.rb
|
|
211
|
+
- lib/charming/events/paste_event.rb
|
|
255
212
|
- lib/charming/events/resize_event.rb
|
|
256
213
|
- lib/charming/events/task_event.rb
|
|
214
|
+
- lib/charming/events/task_progress_event.rb
|
|
257
215
|
- lib/charming/events/timer_event.rb
|
|
258
216
|
- lib/charming/generators/app_file_generator.rb
|
|
259
217
|
- lib/charming/generators/app_generator.rb
|
|
@@ -262,6 +220,8 @@ files:
|
|
|
262
220
|
- lib/charming/generators/controller_generator.rb
|
|
263
221
|
- lib/charming/generators/database_installer.rb
|
|
264
222
|
- lib/charming/generators/error.rb
|
|
223
|
+
- lib/charming/generators/migration_generator.rb
|
|
224
|
+
- lib/charming/generators/migration_timestamp.rb
|
|
265
225
|
- lib/charming/generators/model_generator.rb
|
|
266
226
|
- lib/charming/generators/name.rb
|
|
267
227
|
- lib/charming/generators/screen_generator.rb
|
|
@@ -310,9 +270,14 @@ files:
|
|
|
310
270
|
- lib/charming/internal/terminal/tty_backend.rb
|
|
311
271
|
- lib/charming/presentation/component.rb
|
|
312
272
|
- lib/charming/presentation/components/activity_indicator.rb
|
|
273
|
+
- lib/charming/presentation/components/audio.rb
|
|
274
|
+
- lib/charming/presentation/components/autocomplete.rb
|
|
275
|
+
- lib/charming/presentation/components/badge.rb
|
|
276
|
+
- lib/charming/presentation/components/breadcrumbs.rb
|
|
313
277
|
- lib/charming/presentation/components/command_palette.rb
|
|
314
278
|
- lib/charming/presentation/components/command_palette_modal.rb
|
|
315
279
|
- lib/charming/presentation/components/empty_state.rb
|
|
280
|
+
- lib/charming/presentation/components/error_screen.rb
|
|
316
281
|
- lib/charming/presentation/components/form.rb
|
|
317
282
|
- lib/charming/presentation/components/form/builder.rb
|
|
318
283
|
- lib/charming/presentation/components/form/confirm.rb
|
|
@@ -321,16 +286,26 @@ files:
|
|
|
321
286
|
- lib/charming/presentation/components/form/note.rb
|
|
322
287
|
- lib/charming/presentation/components/form/select.rb
|
|
323
288
|
- lib/charming/presentation/components/form/textarea.rb
|
|
289
|
+
- lib/charming/presentation/components/fuzzy_matcher.rb
|
|
290
|
+
- lib/charming/presentation/components/help_overlay.rb
|
|
324
291
|
- lib/charming/presentation/components/keyboard_handler.rb
|
|
325
292
|
- lib/charming/presentation/components/list.rb
|
|
326
293
|
- lib/charming/presentation/components/markdown.rb
|
|
327
294
|
- lib/charming/presentation/components/modal.rb
|
|
295
|
+
- lib/charming/presentation/components/multi_select_list.rb
|
|
328
296
|
- lib/charming/presentation/components/progressbar.rb
|
|
329
297
|
- lib/charming/presentation/components/spinner.rb
|
|
298
|
+
- lib/charming/presentation/components/status_bar.rb
|
|
299
|
+
- lib/charming/presentation/components/tab_bar.rb
|
|
330
300
|
- lib/charming/presentation/components/table.rb
|
|
331
301
|
- lib/charming/presentation/components/text_area.rb
|
|
332
302
|
- lib/charming/presentation/components/text_input.rb
|
|
303
|
+
- lib/charming/presentation/components/toast.rb
|
|
304
|
+
- lib/charming/presentation/components/tree.rb
|
|
333
305
|
- lib/charming/presentation/components/viewport.rb
|
|
306
|
+
- lib/charming/presentation/components/viewport/content_lines.rb
|
|
307
|
+
- lib/charming/presentation/components/viewport/line_window.rb
|
|
308
|
+
- lib/charming/presentation/components/viewport/position.rb
|
|
334
309
|
- lib/charming/presentation/layout.rb
|
|
335
310
|
- lib/charming/presentation/layout/builder.rb
|
|
336
311
|
- lib/charming/presentation/layout/overlay.rb
|
|
@@ -346,6 +321,9 @@ files:
|
|
|
346
321
|
- lib/charming/presentation/markdown/renderer.rb
|
|
347
322
|
- lib/charming/presentation/markdown/style_config.rb
|
|
348
323
|
- lib/charming/presentation/markdown/syntax_highlighter.rb
|
|
324
|
+
- lib/charming/presentation/markdown/table_renderer.rb
|
|
325
|
+
- lib/charming/presentation/markdown/text_wrapper.rb
|
|
326
|
+
- lib/charming/presentation/markdown/url_resolver.rb
|
|
349
327
|
- lib/charming/presentation/template_view.rb
|
|
350
328
|
- lib/charming/presentation/templates.rb
|
|
351
329
|
- lib/charming/presentation/templates/erb_handler.rb
|
|
@@ -355,18 +333,27 @@ files:
|
|
|
355
333
|
- lib/charming/presentation/ui/border.rb
|
|
356
334
|
- lib/charming/presentation/ui/border_painter.rb
|
|
357
335
|
- lib/charming/presentation/ui/canvas.rb
|
|
336
|
+
- lib/charming/presentation/ui/color_support.rb
|
|
358
337
|
- lib/charming/presentation/ui/style.rb
|
|
359
338
|
- lib/charming/presentation/ui/theme.rb
|
|
339
|
+
- lib/charming/presentation/ui/themes/catppuccin-latte.json
|
|
340
|
+
- lib/charming/presentation/ui/themes/catppuccin-mocha.json
|
|
341
|
+
- lib/charming/presentation/ui/themes/gruvbox-dark.json
|
|
342
|
+
- lib/charming/presentation/ui/themes/nord.json
|
|
360
343
|
- lib/charming/presentation/ui/themes/phosphor.json
|
|
344
|
+
- lib/charming/presentation/ui/themes/tokyonight.json
|
|
361
345
|
- lib/charming/presentation/ui/width.rb
|
|
362
346
|
- lib/charming/presentation/view.rb
|
|
363
347
|
- lib/charming/response.rb
|
|
364
348
|
- lib/charming/router.rb
|
|
365
349
|
- lib/charming/runtime.rb
|
|
366
350
|
- lib/charming/screen.rb
|
|
351
|
+
- lib/charming/tasks/cancelled.rb
|
|
367
352
|
- lib/charming/tasks/inline_executor.rb
|
|
353
|
+
- lib/charming/tasks/progress.rb
|
|
368
354
|
- lib/charming/tasks/task.rb
|
|
369
355
|
- lib/charming/tasks/threaded_executor.rb
|
|
356
|
+
- lib/charming/test_helper.rb
|
|
370
357
|
- lib/charming/version.rb
|
|
371
358
|
- sig/charming.rbs
|
|
372
359
|
homepage: https://github.com/pandorocks/charming
|