Class: Charming::Controller

Inherits:
Object
  • Object
show all
Extended by:
ClassMethods
Includes:
ActionHooks, CommandPalette, ComponentDispatching, Dispatching, FocusManagement, Rendering, SessionState, SidebarNavigation, Terminal, Timers
Defined in:
lib/charming/controller.rb,
lib/charming/controller/focus.rb,
lib/charming/controller/timers.rb,
lib/charming/controller/terminal.rb,
lib/charming/controller/rendering.rb,
lib/charming/controller/dispatching.rb,
lib/charming/controller/action_hooks.rb,
lib/charming/controller/key_dispatch.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.

Direct Known Subclasses

Welcome::Controller

Defined Under Namespace

Modules: ActionHooks, ClassMethods, CommandPalette, ComponentDispatching, Dispatching, FocusManagement, Rendering, SessionState, SidebarNavigation, Terminal, Timers Classes: Focus, KeyDispatch, TaskBinding, TimerBinding

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ClassMethods

animate, 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 Timers

#start_timer, #stop_timer, #timer_running?

Methods included from Terminal

#bell, #copy, #notify, #set_title

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

#focus, #focused?

Methods included from SessionState

#cancel_task, #component_state, #form, #mouse_targets, #register_mouse_targets, #run_task, #session, #state

Methods included from ActionHooks

included

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.



31
32
33
34
35
36
37
38
# File 'lib/charming/controller.rb', line 31

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

#applicationObject (readonly)

Returns the value of attribute application.



27
28
29
# File 'lib/charming/controller.rb', line 27

def application
  @application
end

#eventObject (readonly)

Returns the value of attribute event.



27
28
29
# File 'lib/charming/controller.rb', line 27

def event
  @event
end

#paramsObject (readonly)

Returns the value of attribute params.



27
28
29
# File 'lib/charming/controller.rb', line 27

def params
  @params
end

#routeObject (readonly)

Returns the value of attribute route.



27
28
29
# File 'lib/charming/controller.rb', line 27

def route
  @route
end

#screenObject (readonly)

Returns the value of attribute screen.



27
28
29
# File 'lib/charming/controller.rb', line 27

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.



42
43
44
45
46
# File 'lib/charming/controller.rb', line 42

def dispatch(action)
  run_action_with_hooks(action)
  render_default_action if response.nil? && auto_render_after?(action)
  response || render("")
end

#dispatch_keyObject

Key event dispatch. The precedence ladder (palette → focused text capture → global bindings → overlay → sidebar/content/component) lives in KeyDispatch.



50
51
52
# File 'lib/charming/controller.rb', line 50

def dispatch_key
  KeyDispatch.new(self).call
end

#dispatch_mouseObject

Mouse event dispatcher: command palette (if open) wins, then sidebar clicks (route rows navigate directly), then named layout panes/components.



96
97
98
99
100
101
102
103
# File 'lib/charming/controller.rb', line 96

def dispatch_mouse
  return dispatch_command_palette_mouse if command_palette_open?

  sidebar_response = dispatch_sidebar_mouse
  return sidebar_response if sidebar_response

  dispatch_component_mouse
end

#dispatch_pasteObject

Paste event dispatcher: forwards pasted text to the focused component's handle_paste (TextInput, TextArea, Form text fields, and Autocomplete support it).



80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/charming/controller.rb', line 80

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_taskObject

Task event dispatcher: looks up the handler in task bindings.



67
68
69
70
# File 'lib/charming/controller.rb', line 67

def dispatch_task
  b = self.class.task_bindings[event.name.to_sym]
  b ? dispatch(b.action) : nil
end

#dispatch_task_progressObject

Task progress dispatcher: looks up the handler in task progress bindings.



73
74
75
76
# File 'lib/charming/controller.rb', line 73

def dispatch_task_progress
  b = self.class.task_progress_bindings[event.name.to_sym]
  b ? dispatch(b.action) : nil
end

#dispatch_timerObject

Timer event dispatcher: looks up the named action in timer bindings and runs it with the full hook chain. Unlike #dispatch there is no render("") fallback — a timer action that renders nothing yields a nil response, so silent ticks skip the repaint instead of blanking the screen.



58
59
60
61
62
63
64
# File 'lib/charming/controller.rb', line 58

def dispatch_timer
  b = self.class.timer_bindings[event.name.to_sym]
  return nil unless b

  run_action_with_hooks(b.action)
  response
end

#loggerObject

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.



135
136
137
# File 'lib/charming/controller.rb', line 135

def logger
  application.logger
end

Navigates to the given URL path.



147
148
149
# File 'lib/charming/controller.rb', line 147

def navigate_to(path)
  @response = Response.navigate(path)
end

#open_theme_paletteObject

Opens the theme picker (a CommandPalette populated with the registered themes) and renders.



140
141
142
143
144
# File 'lib/charming/controller.rb', line 140

def open_theme_palette
  session[:command_palette] = command_palette_state(:themes)
  focus.push_scope([:command_palette], origin: :command_palette)
  render_default_action
end

#quitObject

Exits the application — sets a quit response that terminates the event loop.



152
153
154
# File 'lib/charming/controller.rb', line 152

def quit
  @response = Response.quit
end

#render(body = "", **assigns) ⇒ Object

Renders a body or template wrapped in the controller's layout. Out-of-band escape sequences registered while rendering (e.g. image transmissions) are collected by the Runtime around the whole dispatch and attached to the response.



108
109
110
111
# File 'lib/charming/controller.rb', line 108

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.



119
120
121
# File 'lib/charming/controller.rb', line 119

def render_template(name, **assigns)
  @response = Response.render(render_with_layout(template_body(name, **assigns)))
end

#render_view(view_class, **assigns) ⇒ Object



113
114
115
# File 'lib/charming/controller.rb', line 113

def render_view(view_class, **assigns)
  @response = Response.render(render_with_layout(view_class.new(**template_assigns(assigns))))
end

#themeObject

Returns the active theme for this request, delegated to the application.



124
125
126
# File 'lib/charming/controller.rb', line 124

def theme
  application.theme
end

#use_theme(name) ⇒ Object

Switches the active theme to name and persists the choice in the application session.



129
130
131
# File 'lib/charming/controller.rb', line 129

def use_theme(name)
  application.use_theme(name)
end