Module: Ace::Tmux::Atoms::PresetResolver

Defined in:
lib/ace/tmux/atoms/preset_resolver.rb

Overview

Resolves ‘preset:` references in configuration hashes

Pure function: takes a hash and a lookup proc, returns a resolved hash. Uses DeepMerger for overlay merging.

Resolution order:

1. Load base preset via lookup proc
2. Deep-merge overlay (the hash minus `preset` key) on top
3. Recurse for nested presets (windows contain pane presets, etc.)

Constant Summary collapse

MAX_DEPTH =
10

Class Method Summary collapse

Class Method Details

.normalize_pane(pane) ⇒ Hash

Normalize pane entry: string shorthand becomes commands array

Parameters:

  • pane (Hash, String)

    Pane config or string shorthand

Returns:

  • (Hash)

    Normalized pane hash



87
88
89
90
91
# File 'lib/ace/tmux/atoms/preset_resolver.rb', line 87

def normalize_pane(pane)
  return pane if pane.is_a?(Hash)

  {"commands" => [pane.to_s]}
end

.normalize_window(window) ⇒ Hash

Normalize window entry: string shorthand becomes a pane command

Parameters:

  • window (Hash, String)

    Window config or string shorthand

Returns:

  • (Hash)

    Normalized window hash



77
78
79
80
81
# File 'lib/ace/tmux/atoms/preset_resolver.rb', line 77

def normalize_window(window)
  return window if window.is_a?(Hash)

  {"panes" => [window.to_s]}
end

.resolve_panes_recursive(panes, pane_lookup:) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Recursively resolve panes, handling nested containers with “direction” key.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/ace/tmux/atoms/preset_resolver.rb', line 105

def resolve_panes_recursive(panes, pane_lookup:)
  panes.map do |entry|
    entry = normalize_pane(entry)

    if entry.is_a?(Hash) && entry.key?("direction")
      # Container node: recurse into its children
      resolved = entry.dup
      if resolved["panes"].is_a?(Array)
        resolved["panes"] = resolve_panes_recursive(resolved["panes"], pane_lookup: pane_lookup)
      end
      resolved
    else
      # Leaf pane: resolve preset as before
      resolve_preset(entry, lookup: pane_lookup)
    end
  end
end

.resolve_preset(hash, lookup:, depth: 0) ⇒ Hash

Resolve a single preset reference in a hash

Parameters:

  • hash (Hash)

    Hash that may contain a “preset” key

  • lookup (Proc)

    Proc that takes a preset name and returns a hash

  • depth (Integer) (defaults to: 0)

    Current recursion depth (for circular reference guard)

Returns:

  • (Hash)

    Resolved hash with preset merged

Raises:



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/ace/tmux/atoms/preset_resolver.rb', line 57

def resolve_preset(hash, lookup:, depth: 0)
  raise CircularPresetError, "Preset resolution exceeded max depth (#{MAX_DEPTH})" if depth >= MAX_DEPTH
  return hash unless hash.is_a?(Hash) && hash.key?("preset")

  preset_name = hash["preset"]
  base = lookup.call(preset_name)

  return hash.reject { |k, _| k == "preset" } unless base

  # The base preset may itself reference another preset — resolve recursively
  base = resolve_preset(base, lookup: lookup, depth: depth + 1)

  overlay = hash.reject { |k, _| k == "preset" }
  Ace::Support::Config::Atoms::DeepMerger.merge(base, overlay)
end

.resolve_session(hash, window_lookup:, pane_lookup:) ⇒ Hash

Resolve a session hash: resolve window presets, then pane presets within each window

Parameters:

  • hash (Hash)

    Session configuration hash (may contain windows with preset: refs)

  • window_lookup (Proc)

    Proc that takes a name and returns window preset hash

  • pane_lookup (Proc)

    Proc that takes a name and returns pane preset hash

Returns:

  • (Hash)

    Fully resolved session hash



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/ace/tmux/atoms/preset_resolver.rb', line 28

def resolve_session(hash, window_lookup:, pane_lookup:)
  result = hash.dup
  return result unless result["windows"].is_a?(Array)

  result["windows"] = result["windows"].map do |window|
    window = normalize_window(window)
    resolved = resolve_preset(window, lookup: window_lookup)
    resolve_window_panes(resolved, pane_lookup: pane_lookup)
  end

  result
end

.resolve_window(hash, pane_lookup:) ⇒ Hash

Resolve a window hash: resolve pane presets within it

Parameters:

  • hash (Hash)

    Window configuration hash

  • pane_lookup (Proc)

    Proc that takes a name and returns pane preset hash

Returns:

  • (Hash)

    Resolved window hash



46
47
48
49
# File 'lib/ace/tmux/atoms/preset_resolver.rb', line 46

def resolve_window(hash, pane_lookup:)
  result = hash.dup
  resolve_window_panes(result, pane_lookup: pane_lookup)
end

.resolve_window_panes(window_hash, pane_lookup:) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



94
95
96
97
98
99
100
101
# File 'lib/ace/tmux/atoms/preset_resolver.rb', line 94

def resolve_window_panes(window_hash, pane_lookup:)
  return window_hash unless window_hash["panes"].is_a?(Array)

  window_hash = window_hash.dup
  window_hash["panes"] = resolve_panes_recursive(window_hash["panes"], pane_lookup: pane_lookup)

  window_hash
end