Class: Charming::Controller

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

Defined Under Namespace

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

Instance Attribute Summary collapse

Instance Method Summary collapse

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 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.



26
27
28
29
30
31
32
33
# File 'lib/charming/controller.rb', line 26

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.



22
23
24
# File 'lib/charming/controller.rb', line 22

def application
  @application
end

#eventObject (readonly)

Returns the value of attribute event.



22
23
24
# File 'lib/charming/controller.rb', line 22

def event
  @event
end

#paramsObject (readonly)

Returns the value of attribute params.



22
23
24
# File 'lib/charming/controller.rb', line 22

def params
  @params
end

#routeObject (readonly)

Returns the value of attribute route.



22
23
24
# File 'lib/charming/controller.rb', line 22

def route
  @route
end

#screenObject (readonly)

Returns the value of attribute screen.



22
23
24
# File 'lib/charming/controller.rb', line 22

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.



37
38
39
40
41
# File 'lib/charming/controller.rb', line 37

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.



45
46
47
# File 'lib/charming/controller.rb', line 45

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.



91
92
93
94
95
96
97
98
# File 'lib/charming/controller.rb', line 91

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, and form fields support it).



75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/charming/controller.rb', line 75

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.



62
63
64
65
# File 'lib/charming/controller.rb', line 62

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.



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

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.



53
54
55
56
57
58
59
# File 'lib/charming/controller.rb', line 53

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.



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

def logger
  application.logger
end

Navigates to the given URL path.



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

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.



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

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.



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

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.



103
104
105
106
# File 'lib/charming/controller.rb', line 103

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.



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

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

#render_view(view_class, **assigns) ⇒ Object



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

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.



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

def theme
  application.theme
end

#use_theme(name) ⇒ Object

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



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

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