Class: Charming::Controller
- Inherits:
-
Object
- Object
- Charming::Controller
- Extended by:
- ClassMethods
- Includes:
- ActionHooks, CommandPalette, ComponentDispatching, Dispatching, FocusManagement, Rendering, SessionState, SidebarNavigation
- Defined in:
- lib/charming/controller.rb,
lib/charming/controller/focus.rb,
lib/charming/controller/rendering.rb,
lib/charming/controller/dispatching.rb,
lib/charming/controller/action_hooks.rb,
lib/charming/controller/class_methods.rb,
lib/charming/controller/session_state.rb,
lib/charming/controller/command_palette.rb,
lib/charming/controller/focus_management.rb,
lib/charming/controller/sidebar_navigation.rb,
lib/charming/controller/component_dispatching.rb
Overview
Controller is the base class for all controller implementations in a Charming application. It provides the action dispatch pipeline, key/command/timer/task bindings, sidebar navigation, command palette management, and view rendering with layout composition.
Defined Under Namespace
Modules: ActionHooks, ClassMethods, CommandPalette, ComponentDispatching, Dispatching, FocusManagement, Rendering, SessionState, SidebarNavigation Classes: Focus, TaskBinding, TimerBinding
Instance Attribute Summary collapse
-
#application ⇒ Object
readonly
Returns the value of attribute application.
-
#event ⇒ Object
readonly
Returns the value of attribute event.
-
#params ⇒ Object
readonly
Returns the value of attribute params.
-
#route ⇒ Object
readonly
Returns the value of attribute route.
-
#screen ⇒ Object
readonly
Returns the value of attribute screen.
Instance Method Summary collapse
-
#dispatch(action) ⇒ Object
Dispatches a named action on this controller (e.g. :show), running all before/around/after hooks and rescue_from handlers.
-
#dispatch_key ⇒ Object
Key event dispatch, in priority order: 1.
-
#dispatch_mouse ⇒ Object
Mouse event dispatcher: command palette (if open) wins, then sidebar clicks (route rows navigate directly), then named layout panes/components.
-
#dispatch_paste ⇒ Object
Paste event dispatcher: forwards pasted text to the focused component’s ‘handle_paste` (TextInput, TextArea, and form fields support it).
-
#dispatch_task ⇒ Object
Task event dispatcher: looks up the handler in task bindings.
-
#dispatch_task_progress ⇒ Object
Task progress dispatcher: looks up the handler in task progress bindings.
-
#dispatch_timer ⇒ Object
Timer event dispatcher: looks up the named action in timer bindings.
-
#initialize(application:, event: nil, params: {}, screen: nil, route: nil) ⇒ Controller
constructor
Initializes the controller with its parent application and optional event.
-
#logger ⇒ Object
Returns the application logger.
-
#navigate_to(path) ⇒ Object
Navigates to the given URL path.
-
#open_theme_palette ⇒ Object
Opens the theme picker (a CommandPalette populated with the registered themes) and renders.
-
#quit ⇒ Object
Exits the application — sets a quit response that terminates the event loop.
-
#render(body = "", **assigns) ⇒ Object
Renders a body or template wrapped in the controller’s layout.
-
#render_template(name, **assigns) ⇒ Object
Renders a template from ‘app/views` by name, applying the controller’s layout.
- #render_view(view_class, **assigns) ⇒ Object
-
#theme ⇒ Object
Returns the active theme for this request, delegated to the application.
-
#use_theme(name) ⇒ Object
Switches the active theme to name and persists the choice in the application session.
Methods included from ClassMethods
auto_render, auto_render_action, command, command_bindings, focus_ring, focus_ring_slots, key, key_binding_scopes, key_bindings, layout, on_task, on_task_progress, task_bindings, task_progress_bindings, timer, timer_bindings
Methods included from CommandPalette
#close_command_palette, #command_palette, #command_palette_open?, #open_command_palette
Methods included from SidebarNavigation
#content_focused?, #current_route?, #focus_content, #focus_sidebar, #sidebar_focused?, #sidebar_index, #sidebar_routes
Methods included from FocusManagement
Methods included from SessionState
#cancel_task, #form, #mouse_targets, #register_mouse_targets, #run_task, #session, #state
Methods included from ActionHooks
Constructor Details
#initialize(application:, event: nil, params: {}, screen: nil, route: nil) ⇒ Controller
Initializes the controller with its parent application and optional event. Defaults to an 80x24 screen when no backend size is available.
25 26 27 28 29 30 31 32 |
# File 'lib/charming/controller.rb', line 25 def initialize(application:, event: nil, params: {}, screen: nil, route: nil) @application = application @event = event @params = params @screen = screen || Screen.new(width: 80, height: 24) @route = route @response = nil end |
Instance Attribute Details
#application ⇒ Object (readonly)
Returns the value of attribute application.
21 22 23 |
# File 'lib/charming/controller.rb', line 21 def application @application end |
#event ⇒ Object (readonly)
Returns the value of attribute event.
21 22 23 |
# File 'lib/charming/controller.rb', line 21 def event @event end |
#params ⇒ Object (readonly)
Returns the value of attribute params.
21 22 23 |
# File 'lib/charming/controller.rb', line 21 def params @params end |
#route ⇒ Object (readonly)
Returns the value of attribute route.
21 22 23 |
# File 'lib/charming/controller.rb', line 21 def route @route end |
#screen ⇒ Object (readonly)
Returns the value of attribute screen.
21 22 23 |
# File 'lib/charming/controller.rb', line 21 def screen @screen end |
Instance Method Details
#dispatch(action) ⇒ Object
Dispatches a named action on this controller (e.g. :show), running all before/around/after hooks and rescue_from handlers.
36 37 38 39 40 |
# File 'lib/charming/controller.rb', line 36 def dispatch(action) run_action_with_hooks(action) render_default_action if response.nil? && auto_render_after?(action) response || render("") end |
#dispatch_key ⇒ Object
Key event dispatch, in priority order:
-
Command palette (when open) consumes everything.
-
A focused text-capturing component (TextInput, TextArea, Form, …) gets printable characters BEFORE key bindings — typing “q” into a field must insert a q, not quit the app.
-
Global key bindings.
-
An overlay focus scope (a pushed modal) captures all remaining keys.
-
Sidebar keys (when focused), content bindings, then the focused component —which sees Tab before ring traversal so forms can do field navigation.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/charming/controller.rb', line 51 def dispatch_key return dispatch_command_palette_key if command_palette_open? if printable_text_event? && focused_component_captures_text? return response if dispatch_to_focused_component == :handled end return dispatch(global_key_action) if global_key_action if focus. dispatch_to_focused_component return response end return if return dispatch(content_key_action) if content_key_action # Text-capturing components (forms, editors) own their remaining keys — Tab # included, so forms do field navigation. Everything else keeps ring traversal # ahead of the component. if focused_component_captures_text? return response if dispatch_to_focused_component == :handled return response if dispatch_tab_traversal == :handled else return response if dispatch_tab_traversal == :handled return response if dispatch_to_focused_component == :handled end nil end |
#dispatch_mouse ⇒ Object
Mouse event dispatcher: command palette (if open) wins, then sidebar clicks (route rows navigate directly), then named layout panes/components.
120 121 122 123 124 125 126 127 |
# File 'lib/charming/controller.rb', line 120 def dispatch_mouse return dispatch_command_palette_mouse if command_palette_open? = return if dispatch_component_mouse end |
#dispatch_paste ⇒ Object
Paste event dispatcher: forwards pasted text to the focused component’s ‘handle_paste` (TextInput, TextArea, and form fields support it).
104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/charming/controller.rb', line 104 def dispatch_paste slot = focus.current return nil unless slot && respond_to?(slot, true) component = send(slot) return nil unless component.respond_to?(:handle_paste) result = component.handle_paste(event) return nil if result.nil? dispatch_component_result(slot, result) response end |
#dispatch_task ⇒ Object
Task event dispatcher: looks up the handler in task bindings.
91 92 93 94 |
# File 'lib/charming/controller.rb', line 91 def dispatch_task b = self.class.task_bindings[event.name.to_sym] b ? dispatch(b.action) : nil end |
#dispatch_task_progress ⇒ Object
Task progress dispatcher: looks up the handler in task progress bindings.
97 98 99 100 |
# File 'lib/charming/controller.rb', line 97 def dispatch_task_progress b = self.class.task_progress_bindings[event.name.to_sym] b ? dispatch(b.action) : nil end |
#dispatch_timer ⇒ Object
Timer event dispatcher: looks up the named action in timer bindings.
82 83 84 85 86 87 88 |
# File 'lib/charming/controller.rb', line 82 def dispatch_timer b = self.class.timer_bindings[event.name.to_sym] return nil unless b public_send(b.action) response end |
#logger ⇒ Object
Returns the application logger. The default logger writes to File::NULL, so logging calls are safe in TUI code unless the app explicitly configures a file or custom logger.
157 158 159 |
# File 'lib/charming/controller.rb', line 157 def logger application.logger end |
#navigate_to(path) ⇒ Object
Navigates to the given URL path.
169 170 171 |
# File 'lib/charming/controller.rb', line 169 def navigate_to(path) @response = Response.navigate(path) end |
#open_theme_palette ⇒ Object
Opens the theme picker (a CommandPalette populated with the registered themes) and renders.
162 163 164 165 166 |
# File 'lib/charming/controller.rb', line 162 def open_theme_palette session[:command_palette] = command_palette_state(:themes) focus.push_scope([:command_palette], origin: :command_palette) render_default_action end |
#quit ⇒ Object
Exits the application — sets a quit response that terminates the event loop.
174 175 176 |
# File 'lib/charming/controller.rb', line 174 def quit @response = Response.quit end |
#render(body = "", **assigns) ⇒ Object
Renders a body or template wrapped in the controller’s layout.
130 131 132 133 |
# File 'lib/charming/controller.rb', line 130 def render(body = "", **assigns) body = view_body(default_template_name(body), **assigns) if body.is_a?(Symbol) @response = Response.render(render_with_layout(body)) end |
#render_template(name, **assigns) ⇒ Object
Renders a template from ‘app/views` by name, applying the controller’s layout. name is the template path (e.g., “home/show”) and additional keyword assigns are forwarded to the view.
141 142 143 |
# File 'lib/charming/controller.rb', line 141 def render_template(name, **assigns) @response = Response.render(render_with_layout(template_body(name, **assigns))) end |
#render_view(view_class, **assigns) ⇒ Object
135 136 137 |
# File 'lib/charming/controller.rb', line 135 def render_view(view_class, **assigns) @response = Response.render(render_with_layout(view_class.new(**template_assigns(assigns)))) end |
#theme ⇒ Object
Returns the active theme for this request, delegated to the application.
146 147 148 |
# File 'lib/charming/controller.rb', line 146 def theme application.theme end |
#use_theme(name) ⇒ Object
Switches the active theme to name and persists the choice in the application session.
151 152 153 |
# File 'lib/charming/controller.rb', line 151 def use_theme(name) application.use_theme(name) end |