charming 0.1.2 → 0.1.4
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/lib/charming/application.rb +22 -5
- data/lib/charming/cli.rb +3 -3
- data/lib/charming/controller/class_methods.rb +2 -2
- data/lib/charming/controller/command_palette.rb +2 -2
- data/lib/charming/controller/component_dispatching.rb +47 -3
- data/lib/charming/controller/focus.rb +123 -0
- data/lib/charming/controller/focus_management.rb +1 -1
- data/lib/charming/controller/rendering.rb +6 -17
- data/lib/charming/controller/session_state.rb +12 -1
- data/lib/charming/controller.rb +11 -2
- data/lib/charming/database/commands.rb +106 -0
- data/lib/charming/generators/component_generator.rb +1 -1
- data/lib/charming/generators/database_installer.rb +154 -0
- data/lib/charming/generators/model_generator.rb +2 -10
- data/lib/charming/generators/name.rb +1 -1
- data/lib/charming/generators/templates/app/application.template +1 -1
- data/lib/charming/generators/templates/app/layout.template +3 -6
- data/lib/charming/generators/templates/app/view.template +1 -1
- data/lib/charming/generators/templates/component/component.rb.template +1 -1
- data/lib/charming/generators/templates/screen/view.rb.template +1 -1
- data/lib/charming/generators/templates/view/view.rb.template +1 -1
- data/lib/charming/generators/view_generator.rb +1 -1
- data/lib/charming/internal/renderer/differential.rb +13 -5
- data/lib/charming/internal/terminal/tty_backend.rb +22 -2
- data/lib/charming/presentation/component.rb +3 -5
- data/lib/charming/presentation/components/activity_indicator.rb +173 -134
- data/lib/charming/presentation/components/command_palette.rb +94 -96
- data/lib/charming/presentation/components/command_palette_modal.rb +33 -0
- data/lib/charming/presentation/components/empty_state.rb +47 -49
- data/lib/charming/presentation/components/form/builder.rb +52 -54
- data/lib/charming/presentation/components/form/confirm.rb +49 -51
- data/lib/charming/presentation/components/form/field.rb +94 -96
- data/lib/charming/presentation/components/form/input.rb +53 -55
- data/lib/charming/presentation/components/form/note.rb +27 -29
- data/lib/charming/presentation/components/form/select.rb +84 -86
- data/lib/charming/presentation/components/form/textarea.rb +67 -69
- data/lib/charming/presentation/components/form.rb +120 -122
- data/lib/charming/presentation/components/keyboard_handler.rb +41 -43
- data/lib/charming/presentation/components/list.rb +123 -125
- data/lib/charming/presentation/components/markdown.rb +21 -23
- data/lib/charming/presentation/components/modal.rb +46 -48
- data/lib/charming/presentation/components/progressbar.rb +51 -53
- data/lib/charming/presentation/components/spinner.rb +40 -42
- data/lib/charming/presentation/components/table.rb +109 -111
- data/lib/charming/presentation/components/text_area.rb +219 -221
- data/lib/charming/presentation/components/text_input.rb +120 -122
- data/lib/charming/presentation/components/viewport.rb +218 -220
- data/lib/charming/presentation/layout/builder.rb +64 -66
- data/lib/charming/presentation/layout/overlay.rb +48 -50
- data/lib/charming/presentation/layout/pane.rb +129 -118
- data/lib/charming/presentation/layout/rect.rb +19 -16
- data/lib/charming/presentation/layout/screen_layout.rb +47 -42
- data/lib/charming/presentation/layout/split.rb +107 -102
- data/lib/charming/presentation/layout.rb +28 -30
- data/lib/charming/presentation/markdown/render_context.rb +30 -14
- data/lib/charming/presentation/markdown/renderer.rb +302 -79
- data/lib/charming/presentation/markdown/style_config.rb +215 -0
- data/lib/charming/presentation/markdown/syntax_highlighter.rb +58 -59
- data/lib/charming/presentation/markdown.rb +4 -6
- data/lib/charming/presentation/template_view.rb +22 -24
- data/lib/charming/presentation/templates/erb_handler.rb +4 -6
- data/lib/charming/presentation/templates.rb +47 -49
- data/lib/charming/presentation/ui/ansi_codes.rb +66 -68
- data/lib/charming/presentation/ui/ansi_slicer.rb +67 -69
- data/lib/charming/presentation/ui/border.rb +24 -26
- data/lib/charming/presentation/ui/border_painter.rb +37 -39
- data/lib/charming/presentation/ui/canvas.rb +59 -61
- data/lib/charming/presentation/ui/style.rb +173 -175
- data/lib/charming/presentation/ui/theme.rb +133 -135
- data/lib/charming/presentation/ui/width.rb +12 -14
- data/lib/charming/presentation/ui.rb +69 -71
- data/lib/charming/presentation/view.rb +110 -105
- data/lib/charming/router.rb +3 -8
- data/lib/charming/runtime.rb +25 -10
- data/lib/charming/version.rb +1 -1
- data/lib/charming.rb +5 -4
- metadata +43 -9
- data/lib/charming/database_commands.rb +0 -103
- data/lib/charming/database_installer.rb +0 -152
- data/lib/charming/focus.rb +0 -121
- data/lib/charming/presentation/markdown/block_renderers.rb +0 -120
- data/lib/charming/presentation/markdown/inline_renderers.rb +0 -68
|
@@ -1,135 +1,140 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Charming
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
end
|
|
4
|
+
# View is the base class for all screen view implementations. It provides assign injection (via `initialize`),
|
|
5
|
+
# rendering hooks, layout composition helpers (`row`, `column`, `render_component`, `yield_content`),
|
|
6
|
+
# and access to controller theme, style, and focus state from within views.
|
|
7
|
+
class View
|
|
8
|
+
# Initializes the view with named assigns injected as instance-local accessor methods via
|
|
9
|
+
# `define_singleton_method`. Called when a controller instantiates a view for rendering.
|
|
10
|
+
def initialize(**assigns)
|
|
11
|
+
@assigns = assigns
|
|
12
|
+
define_assign_readers
|
|
13
|
+
end
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
# Returns all view assigns as a hash, used by layouts to compose the full template (content + screen + controller).
|
|
16
|
+
def layout_assigns
|
|
17
|
+
assigns
|
|
18
|
+
end
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
# Renders the view's body. Default is empty — subclasses override to return visible text.
|
|
21
|
+
def render
|
|
22
|
+
""
|
|
23
|
+
end
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
# Delegates focus checking to the controller in assigns, allowing views to determine which slot (sidebar, content) has focus.
|
|
26
|
+
def focused?(slot)
|
|
27
|
+
ctrl = assigns[:focus_controller] || assigns[:controller]
|
|
28
|
+
ctrl ? ctrl.focused?(slot) : false
|
|
29
|
+
end
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
private
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
attr_reader :assigns
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
# Returns the shared UI style configuration used by components and views for visual rendering (colors, borders).
|
|
36
|
+
def style
|
|
37
|
+
UI.style
|
|
38
|
+
end
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
# Returns the active theme: uses `theme` from assigns or controller, falling back to `UI::Theme.default`.
|
|
41
|
+
def theme
|
|
42
|
+
assigns[:theme] || assigns[:controller]&.theme || UI::Theme.default
|
|
43
|
+
end
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
# Outputs styled text through the view's rendering pipeline. Accepts a named `style:` for inline formatting.
|
|
46
|
+
# Appends the rendered value to the output buffer and returns it.
|
|
47
|
+
def text(value, style: nil)
|
|
48
|
+
rendered = apply_style(value.to_s, style)
|
|
49
|
+
append_to_buffer(rendered)
|
|
50
|
+
rendered
|
|
51
|
+
end
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
# Renders a box with optional styling. Accepts an inline block for complex content or a plain value.
|
|
54
|
+
# Used for bordered containers and field groups in views.
|
|
55
|
+
def box(value = nil, style: nil, &)
|
|
56
|
+
content = block_given? ? capture(&) : value.to_s
|
|
57
|
+
apply_style(content, style)
|
|
58
|
+
end
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
# Joins items horizontally (side-by-side) using the UI rendering engine. Supports a `gap:` parameter.
|
|
61
|
+
def row(*items, gap: 0)
|
|
62
|
+
UI.join_horizontal(*items, gap: gap)
|
|
63
|
+
end
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
# Stacks items vertically using the UI rendering engine. Supports a `gap:` parameter for spacing.
|
|
66
|
+
def column(*items, gap: 0)
|
|
67
|
+
UI.join_vertical(*items, gap: gap)
|
|
68
|
+
end
|
|
70
69
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
# Renders a component (e.g., a ProgressBar, Spinner, Modal) and returns its string output.
|
|
71
|
+
def render_component(component)
|
|
72
|
+
component.render.to_s
|
|
73
|
+
end
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
# Renders a partial view component. An alias for `render_component` used in layout templates.
|
|
76
|
+
def render_partial(partial)
|
|
77
|
+
render_component(partial)
|
|
78
|
+
end
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
80
|
+
# Builds a declarative layout tree for the current terminal screen and renders it.
|
|
81
|
+
def screen_layout(background: nil, &)
|
|
82
|
+
layout = Layout::Builder.build(screen: layout_screen, view: self, background: background, &)
|
|
83
|
+
register_layout_focus(layout)
|
|
84
|
+
register_layout_mouse_targets(layout)
|
|
85
|
+
layout.render
|
|
86
|
+
end
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
# Yields the layout's `content` slot — used by view templates to inject their body into a layout wrapper (e.g., sidebar).
|
|
89
|
+
def yield_content
|
|
90
|
+
assigns.fetch(:content, "")
|
|
91
|
+
end
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
93
|
+
# Evaluates a block in the view's context with a clean output buffer. Captures text written via `text`/`box`
|
|
94
|
+
# and returns joined content. Resets buffer afterward for parent rendering.
|
|
95
|
+
def capture(&)
|
|
96
|
+
previous_buffer = @output_buffer
|
|
97
|
+
@output_buffer = []
|
|
98
|
+
result = instance_eval(&)
|
|
99
|
+
@output_buffer.empty? ? result.to_s : @output_buffer.join("\n")
|
|
100
|
+
ensure
|
|
101
|
+
@output_buffer = previous_buffer
|
|
102
|
+
end
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
# Appends a value to the current output buffer (if one is active). Used by rendering helpers.
|
|
105
|
+
def append_to_buffer(value)
|
|
106
|
+
@output_buffer << value if @output_buffer
|
|
107
|
+
end
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
# Applies a style object's `render` method to a string, returning styled output or raw text when style is nil.
|
|
110
|
+
def apply_style(value, style_object)
|
|
111
|
+
style_object ? style_object.render(value) : value
|
|
112
|
+
end
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
# Dynamically defines read-only accessor methods for each assign key as singleton methods on self.
|
|
115
|
+
# Skips keys where the view already responds (controller methods take precedence).
|
|
116
|
+
def define_assign_readers
|
|
117
|
+
assigns.each_key do |name|
|
|
118
|
+
next if respond_to?(name, true)
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
end
|
|
120
|
+
define_singleton_method(name) { assigns.fetch(name) }
|
|
122
121
|
end
|
|
122
|
+
end
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
def layout_screen
|
|
125
|
+
assigns[:screen] || assigns[:controller]&.screen || Charming::Screen.new(width: 80, height: 24)
|
|
126
|
+
end
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
def register_layout_focus(layout)
|
|
129
|
+
return unless assigns[:controller]
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
assigns[:controller].focus.define_layout(layout.focusable_names)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def register_layout_mouse_targets(layout)
|
|
135
|
+
return unless assigns[:controller]
|
|
136
|
+
|
|
137
|
+
assigns[:controller].register_mouse_targets(layout.mouse_targets)
|
|
133
138
|
end
|
|
134
139
|
end
|
|
135
140
|
end
|
data/lib/charming/router.rb
CHANGED
|
@@ -108,20 +108,15 @@ module Charming
|
|
|
108
108
|
end
|
|
109
109
|
end
|
|
110
110
|
|
|
111
|
-
# Splits a camel-case string into words for title derivation (e.g., "my_route" → ["my", "route"]).
|
|
112
|
-
def camelize(value)
|
|
113
|
-
value.split("_").map(&:capitalize).join
|
|
114
|
-
end
|
|
115
|
-
|
|
116
111
|
# Looks up a constant by name in Object. Used to resolve controller strings from route definitions.
|
|
117
112
|
def constantize(name)
|
|
118
|
-
|
|
113
|
+
ActiveSupport::Inflector.constantize(name)
|
|
119
114
|
end
|
|
120
115
|
|
|
121
116
|
# Builds the full controller constant name, prepending the namespace if present.
|
|
122
|
-
# For example: "
|
|
117
|
+
# For example: "home" with namespace "Admin" → "Admin::HomeController".
|
|
123
118
|
def controller_constant_name(controller_name)
|
|
124
|
-
name = "#{camelize(controller_name)}Controller"
|
|
119
|
+
name = "#{ActiveSupport::Inflector.camelize(controller_name)}Controller"
|
|
125
120
|
@namespace.to_s.empty? ? name : "#{@namespace}::#{name}"
|
|
126
121
|
end
|
|
127
122
|
|
data/lib/charming/runtime.rb
CHANGED
|
@@ -26,19 +26,21 @@ module Charming
|
|
|
26
26
|
# restores terminal state on exit.
|
|
27
27
|
def run
|
|
28
28
|
setup_terminal
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
with_raw_input do
|
|
30
|
+
render(resolve_response(dispatch(@route.action)))
|
|
31
|
+
loop do
|
|
32
|
+
event = next_task_event || next_timer_event || @backend.read_event(timeout: read_timeout)
|
|
33
|
+
next unless event
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
response = dispatch_event(event)
|
|
36
|
+
next unless response
|
|
37
|
+
break if response.quit?
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
response = resolve_response(response)
|
|
40
|
+
break if response.quit?
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
render(response)
|
|
43
|
+
end
|
|
42
44
|
end
|
|
43
45
|
ensure
|
|
44
46
|
@task_executor&.shutdown(timeout: 0.0)
|
|
@@ -93,8 +95,12 @@ module Charming
|
|
|
93
95
|
end
|
|
94
96
|
|
|
95
97
|
# Dispatches a resize event: updates screen dimensions and re-renders the current action.
|
|
98
|
+
# The renderer's cached previous frame is invalidated and the backend is cleared so the
|
|
99
|
+
# new-dimension frame paints onto a clean alt-screen instead of overlaying stale rows.
|
|
96
100
|
def dispatch_resize(event)
|
|
97
101
|
@screen = Screen.new(width: event.width, height: event.height)
|
|
102
|
+
@renderer.invalidate if @renderer.respond_to?(:invalidate)
|
|
103
|
+
@backend.clear if @backend.respond_to?(:clear)
|
|
98
104
|
dispatch(@route.action, event: event)
|
|
99
105
|
end
|
|
100
106
|
|
|
@@ -180,13 +186,22 @@ module Charming
|
|
|
180
186
|
def setup_terminal
|
|
181
187
|
@backend.enter_alt_screen
|
|
182
188
|
@backend.hide_cursor
|
|
189
|
+
@backend.enable_mouse_tracking if @backend.respond_to?(:enable_mouse_tracking)
|
|
183
190
|
@backend.install_resize_handler if @backend.respond_to?(:install_resize_handler)
|
|
184
191
|
end
|
|
185
192
|
|
|
193
|
+
# Keeps input raw/no-echo across rendering and dispatch, not just during reads.
|
|
194
|
+
def with_raw_input(&block)
|
|
195
|
+
return yield unless @backend.respond_to?(:with_raw_input)
|
|
196
|
+
|
|
197
|
+
@backend.with_raw_input(&block)
|
|
198
|
+
end
|
|
199
|
+
|
|
186
200
|
# Restores terminal state: reinstalls any previous resize handler, shows
|
|
187
201
|
# the cursor, and leaves the alternative screen buffer.
|
|
188
202
|
def restore_terminal
|
|
189
203
|
@backend.restore_resize_handler if @backend.respond_to?(:restore_resize_handler)
|
|
204
|
+
@backend.disable_mouse_tracking if @backend.respond_to?(:disable_mouse_tracking)
|
|
190
205
|
@backend.show_cursor
|
|
191
206
|
@backend.leave_alt_screen
|
|
192
207
|
end
|
data/lib/charming/version.rb
CHANGED
data/lib/charming.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/inflector"
|
|
4
|
+
require "logger"
|
|
3
5
|
require "zeitwerk"
|
|
4
6
|
|
|
5
7
|
loader = Zeitwerk::Loader.for_gem
|
|
@@ -9,14 +11,13 @@ loader.inflector.inflect(
|
|
|
9
11
|
"ansi_codes" => "ANSICodes",
|
|
10
12
|
"ansi_slicer" => "ANSISlicer",
|
|
11
13
|
"border_painter" => "BorderPainter",
|
|
12
|
-
"block_renderers" => "BlockRenderer",
|
|
13
|
-
"inline_renderers" => "InlineRenderer",
|
|
14
14
|
"render_context" => "RenderContext",
|
|
15
15
|
"erb_handler" => "ErbHandler",
|
|
16
16
|
"key_normalizer" => "KeyNormalizer",
|
|
17
17
|
"mouse_parser" => "MouseParser",
|
|
18
18
|
"tty_backend" => "TTYBackend"
|
|
19
19
|
)
|
|
20
|
+
loader.collapse("#{__dir__}/charming/presentation")
|
|
20
21
|
loader.setup
|
|
21
22
|
|
|
22
23
|
module Charming
|
|
@@ -37,5 +38,5 @@ module Charming
|
|
|
37
38
|
end
|
|
38
39
|
end
|
|
39
40
|
|
|
40
|
-
Charming::
|
|
41
|
-
Charming::
|
|
41
|
+
Charming::Templates.register ".tui.erb", Charming::Templates::ErbHandler
|
|
42
|
+
Charming::Templates.register ".txt.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.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- pando
|
|
@@ -50,19 +50,53 @@ dependencies:
|
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
51
|
version: 8.1.2
|
|
52
52
|
- !ruby/object:Gem::Dependency
|
|
53
|
-
name:
|
|
53
|
+
name: activesupport
|
|
54
54
|
requirement: !ruby/object:Gem::Requirement
|
|
55
55
|
requirements:
|
|
56
56
|
- - "~>"
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
|
-
version: '
|
|
58
|
+
version: '8.1'
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: 8.1.2
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '8.1'
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: 8.1.2
|
|
72
|
+
- !ruby/object:Gem::Dependency
|
|
73
|
+
name: commonmarker
|
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
|
75
|
+
requirements:
|
|
76
|
+
- - "~>"
|
|
77
|
+
- !ruby/object:Gem::Version
|
|
78
|
+
version: '2.0'
|
|
79
|
+
type: :runtime
|
|
80
|
+
prerelease: false
|
|
81
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
82
|
+
requirements:
|
|
83
|
+
- - "~>"
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '2.0'
|
|
86
|
+
- !ruby/object:Gem::Dependency
|
|
87
|
+
name: logger
|
|
88
|
+
requirement: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - "~>"
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '1.7'
|
|
59
93
|
type: :runtime
|
|
60
94
|
prerelease: false
|
|
61
95
|
version_requirements: !ruby/object:Gem::Requirement
|
|
62
96
|
requirements:
|
|
63
97
|
- - "~>"
|
|
64
98
|
- !ruby/object:Gem::Version
|
|
65
|
-
version: '
|
|
99
|
+
version: '1.7'
|
|
66
100
|
- !ruby/object:Gem::Dependency
|
|
67
101
|
name: rouge
|
|
68
102
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -210,23 +244,23 @@ files:
|
|
|
210
244
|
- lib/charming/controller/command_palette.rb
|
|
211
245
|
- lib/charming/controller/component_dispatching.rb
|
|
212
246
|
- lib/charming/controller/dispatching.rb
|
|
247
|
+
- lib/charming/controller/focus.rb
|
|
213
248
|
- lib/charming/controller/focus_management.rb
|
|
214
249
|
- lib/charming/controller/rendering.rb
|
|
215
250
|
- lib/charming/controller/session_state.rb
|
|
216
251
|
- lib/charming/controller/sidebar_navigation.rb
|
|
217
|
-
- lib/charming/
|
|
218
|
-
- lib/charming/database_installer.rb
|
|
252
|
+
- lib/charming/database/commands.rb
|
|
219
253
|
- lib/charming/events/key_event.rb
|
|
220
254
|
- lib/charming/events/mouse_event.rb
|
|
221
255
|
- lib/charming/events/resize_event.rb
|
|
222
256
|
- lib/charming/events/task_event.rb
|
|
223
257
|
- lib/charming/events/timer_event.rb
|
|
224
|
-
- lib/charming/focus.rb
|
|
225
258
|
- lib/charming/generators/app_file_generator.rb
|
|
226
259
|
- lib/charming/generators/app_generator.rb
|
|
227
260
|
- lib/charming/generators/base.rb
|
|
228
261
|
- lib/charming/generators/component_generator.rb
|
|
229
262
|
- lib/charming/generators/controller_generator.rb
|
|
263
|
+
- lib/charming/generators/database_installer.rb
|
|
230
264
|
- lib/charming/generators/error.rb
|
|
231
265
|
- lib/charming/generators/model_generator.rb
|
|
232
266
|
- lib/charming/generators/name.rb
|
|
@@ -277,6 +311,7 @@ files:
|
|
|
277
311
|
- lib/charming/presentation/component.rb
|
|
278
312
|
- lib/charming/presentation/components/activity_indicator.rb
|
|
279
313
|
- lib/charming/presentation/components/command_palette.rb
|
|
314
|
+
- lib/charming/presentation/components/command_palette_modal.rb
|
|
280
315
|
- lib/charming/presentation/components/empty_state.rb
|
|
281
316
|
- lib/charming/presentation/components/form.rb
|
|
282
317
|
- lib/charming/presentation/components/form/builder.rb
|
|
@@ -304,10 +339,9 @@ files:
|
|
|
304
339
|
- lib/charming/presentation/layout/screen_layout.rb
|
|
305
340
|
- lib/charming/presentation/layout/split.rb
|
|
306
341
|
- lib/charming/presentation/markdown.rb
|
|
307
|
-
- lib/charming/presentation/markdown/block_renderers.rb
|
|
308
|
-
- lib/charming/presentation/markdown/inline_renderers.rb
|
|
309
342
|
- lib/charming/presentation/markdown/render_context.rb
|
|
310
343
|
- lib/charming/presentation/markdown/renderer.rb
|
|
344
|
+
- lib/charming/presentation/markdown/style_config.rb
|
|
311
345
|
- lib/charming/presentation/markdown/syntax_highlighter.rb
|
|
312
346
|
- lib/charming/presentation/template_view.rb
|
|
313
347
|
- lib/charming/presentation/templates.rb
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "fileutils"
|
|
4
|
-
|
|
5
|
-
module Charming
|
|
6
|
-
# DatabaseCommands implements the runtime side of `charming db:COMMAND` (other than
|
|
7
|
-
# `db:install`, which lives in DatabaseInstaller). It loads the app's `config/database.rb`,
|
|
8
|
-
# delegates the actual work to ActiveRecord, and prints a short status line on success.
|
|
9
|
-
class DatabaseCommands
|
|
10
|
-
# *command* is the subcommand string (e.g., "db:create"). *out* is the status-output
|
|
11
|
-
# stream. *destination* is the app root for resolving `config/database.rb` and `db/`.
|
|
12
|
-
def initialize(command, out:, destination:)
|
|
13
|
-
@command = command
|
|
14
|
-
@out = out
|
|
15
|
-
@destination = destination
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# Dispatches the configured command. Raises Generators::Error for unknown commands.
|
|
19
|
-
def run
|
|
20
|
-
case command
|
|
21
|
-
when "db:create" then create
|
|
22
|
-
when "db:migrate" then migrate
|
|
23
|
-
when "db:rollback" then rollback
|
|
24
|
-
when "db:drop" then drop
|
|
25
|
-
when "db:seed" then seed
|
|
26
|
-
else raise Generators::Error, "Unknown database command: #{command}"
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private
|
|
31
|
-
|
|
32
|
-
# The subcommand, output stream, and app destination.
|
|
33
|
-
attr_reader :command, :out, :destination
|
|
34
|
-
|
|
35
|
-
# Creates the SQLite database file (touch) and establishes the connection.
|
|
36
|
-
def create
|
|
37
|
-
load_database
|
|
38
|
-
FileUtils.mkdir_p(File.dirname(database_path)) if database_path
|
|
39
|
-
FileUtils.touch(database_path) if database_path
|
|
40
|
-
ActiveRecord::Base.connection
|
|
41
|
-
out.puts "create #{relative_database_path}"
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Runs all pending migrations from `db/migrate`.
|
|
45
|
-
def migrate
|
|
46
|
-
load_database
|
|
47
|
-
migration_context.migrate
|
|
48
|
-
out.puts "migrate db/migrate"
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Rolls back the most recent migration.
|
|
52
|
-
def rollback
|
|
53
|
-
load_database
|
|
54
|
-
migration_context.rollback(1)
|
|
55
|
-
out.puts "rollback db/migrate"
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Disconnects ActiveRecord, then deletes the database file.
|
|
59
|
-
def drop
|
|
60
|
-
load_database
|
|
61
|
-
ActiveRecord::Base.connection.disconnect!
|
|
62
|
-
File.delete(database_path) if database_path && File.exist?(database_path)
|
|
63
|
-
out.puts "drop #{relative_database_path}"
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Loads `db/seeds.rb` (raises if missing).
|
|
67
|
-
def seed
|
|
68
|
-
load_database
|
|
69
|
-
seed_path = File.join(destination, "db", "seeds.rb")
|
|
70
|
-
raise Generators::Error, "Missing file: db/seeds.rb" unless File.exist?(seed_path)
|
|
71
|
-
|
|
72
|
-
load seed_path
|
|
73
|
-
out.puts "seed db/seeds.rb"
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# Loads the app's `config/database.rb` (raises if missing) which establishes the connection.
|
|
77
|
-
def load_database
|
|
78
|
-
database_config = File.join(destination, "config", "database.rb")
|
|
79
|
-
raise Generators::Error, "Database support is not configured. Missing config/database.rb." unless File.exist?(database_config)
|
|
80
|
-
|
|
81
|
-
require database_config
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# The ActiveRecord migration context rooted at `db/migrate` inside the app.
|
|
85
|
-
def migration_context
|
|
86
|
-
ActiveRecord::MigrationContext.new(File.join(destination, "db", "migrate"))
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# The configured database file path (nil when ActiveRecord isn't connected to a file).
|
|
90
|
-
def database_path
|
|
91
|
-
ActiveRecord::Base.connection_db_config.database
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# The database path relative to the app root, used for human-friendly status output.
|
|
95
|
-
def relative_database_path
|
|
96
|
-
return "database" unless database_path
|
|
97
|
-
|
|
98
|
-
base = File.realpath(destination)
|
|
99
|
-
path = File.expand_path(database_path)
|
|
100
|
-
path.start_with?("#{base}/") ? path.delete_prefix("#{base}/") : path
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|