Class: Charming::Components::Tree

Inherits:
Charming::Component show all
Includes:
KeyboardHandler
Defined in:
lib/charming/presentation/components/tree.rb

Overview

Tree renders a collapsible hierarchy (file explorers, nested data). Nodes are hashes: ‘“src”, children: […], expanded: true` — `children` and `expanded` are optional. Navigation: up/down move the cursor through visible nodes, right expands, left collapses (or jumps to the parent), Enter returns `[:selected, node]` for leaves and toggles branches. Mouse clicks move the cursor and toggle branches.

Constant Summary collapse

KEY_ACTIONS =
{
  up: :move_up,
  down: :move_down,
  left: :collapse_or_parent,
  right: :expand,
  home: :move_home,
  end: :move_end
}.freeze

Constants included from KeyboardHandler

KeyboardHandler::VIM_KEYMAP

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Charming::Component

#captures_text?

Methods inherited from View

#focused?, #layout_assigns

Constructor Details

#initialize(nodes:, cursor_index: 0, height: nil, keymap: :vim, theme: nil) ⇒ Tree

nodes is the array of root node hashes (mutated in place to track expansion). height optionally constrains the visible window.



28
29
30
31
32
33
34
35
# File 'lib/charming/presentation/components/tree.rb', line 28

def initialize(nodes:, cursor_index: 0, height: nil, keymap: :vim, theme: nil)
  super(theme: theme)
  @nodes = nodes
  @cursor_index = cursor_index
  @height = height
  @keymap = keymap
  clamp_cursor
end

Instance Attribute Details

#cursor_indexObject (readonly)

The root node list and the cursor index into the visible-node list.



24
25
26
# File 'lib/charming/presentation/components/tree.rb', line 24

def cursor_index
  @cursor_index
end

#nodesObject (readonly)

The root node list and the cursor index into the visible-node list.



24
25
26
# File 'lib/charming/presentation/components/tree.rb', line 24

def nodes
  @nodes
end

Instance Method Details

#current_nodeObject

The node under the cursor (a node hash), or nil for an empty tree.



61
62
63
# File 'lib/charming/presentation/components/tree.rb', line 61

def current_node
  visible_nodes[cursor_index]&.fetch(:node)
end

#handle_key(event) ⇒ Object

Enter selects a leaf (‘[:selected, node]`) or toggles a branch. Navigation keys are handled by KeyboardHandler.



39
40
41
42
43
44
45
# File 'lib/charming/presentation/components/tree.rb', line 39

def handle_key(event)
  node = current_node
  return nil unless node
  return select_or_toggle(node) if Charming.key_of(event) == :enter

  super
end

#handle_mouse(event) ⇒ Object

A click moves the cursor to the clicked row; clicking a branch toggles it.



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/charming/presentation/components/tree.rb', line 48

def handle_mouse(event)
  return nil unless event.respond_to?(:click?) && event.click?

  clicked = viewport_start + event.y
  return nil if clicked >= visible_nodes.length || event.y.negative?

  @cursor_index = clicked
  node = current_node
  toggle(node) if branch?(node)
  :handled
end

#renderObject

Renders the visible window of the flattened tree.



66
67
68
69
70
71
# File 'lib/charming/presentation/components/tree.rb', line 66

def render
  window = visible_nodes[viewport_start, viewport_height] || []
  window.each_with_index.map do |entry, index|
    render_node(entry, viewport_start + index)
  end.join("\n")
end