Class: Ace::Assign::Molecules::TmuxControlSurfaceRunner

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/assign/molecules/tmux_control_surface_runner.rb

Overview

Shared ace-tmux backed runtime helper for tmux fork launches.

Instance Method Summary collapse

Constructor Details

#initialize(executor: Ace::Tmux::Molecules::TmuxExecutor.new, resolver: nil, control_surface: nil, tmux: "tmux", env: ENV) ⇒ TmuxControlSurfaceRunner

Returns a new instance of TmuxControlSurfaceRunner.



13
14
15
16
17
18
19
20
21
22
23
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 13

def initialize(executor: Ace::Tmux::Molecules::TmuxExecutor.new, resolver: nil, control_surface: nil, tmux: "tmux", env: ENV)
  @executor = executor
  @tmux = tmux
  @env = env
  @resolver = resolver || Ace::Tmux::Molecules::RuntimeTargetResolver.new(executor: executor, tmux: tmux, env: env)
  @control_surface = control_surface || Ace::Tmux::Organisms::ControlSurface.new(
    executor: executor,
    resolver: @resolver,
    tmux: tmux
  )
end

Instance Method Details

#capture_recent_output(pane_target:, lines: 40) ⇒ Object



121
122
123
124
125
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 121

def capture_recent_output(pane_target:, lines: 40)
  control_surface.capture_recent_output(pane: pane_target, lines: lines)
rescue Ace::Tmux::Error => e
  raise Error, "Failed to capture pane #{pane_target}: #{e.message}"
end

#current_paneObject



44
45
46
47
48
49
50
51
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 44

def current_pane
  explicit = env["ACE_ASSIGN_CALLBACK_PANE"].to_s.strip
  return explicit unless explicit.empty?

  resolver.resolve_pane(session: current_session, window: current_window).pane_target
rescue Ace::Tmux::TargetResolutionError
  nil
end

#current_sessionObject



29
30
31
32
33
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 29

def current_session
  resolver.resolve_session.session
rescue Ace::Tmux::TargetResolutionError
  nil
end

#current_windowObject



35
36
37
38
39
40
41
42
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 35

def current_window
  explicit = env["ACE_ASSIGN_FORK_WINDOW"].to_s.strip
  return explicit unless explicit.empty?

  resolver.resolve_window(session: current_session).window
rescue Ace::Tmux::TargetResolutionError
  nil
end

#ensure_window(session:, name:, root:) ⇒ Object

Raises:



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 60

def ensure_window(session:, name:, root:)
  if (window_id = find_window_id(session: session, name: name))
    return {created: false, target: window_id, window_id: window_id, name: name}
  end

  result = executor.capture(
    Ace::Tmux::Atoms::TmuxCommandBuilder.new_window(
      session,
      name: name,
      root: root,
      print_format: '#{window_id}',
      tmux: tmux
    )
  )
  raise Error, "Failed to create tmux fork window #{name}: #{result.stderr}" unless result.success?

  window_id = result.stdout.to_s.strip
  raise Error, "Failed to create tmux fork window #{name}: empty window id" if window_id.empty?

  {created: true, target: window_id, window_id: window_id, name: name}
end

#fork_window_name(base_window) ⇒ Object



53
54
55
56
57
58
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 53

def fork_window_name(base_window)
  base = base_window.to_s.strip.sub(/-fs\z/, "")
  sanitized = Ace::Tmux::Atoms::WindowNameSanitizer.call(base, fallback: "fork")

  "#{sanitized}-fs"
end

#merge_tmux_metadata(session_meta_file:, session:, window:, pane:, window_id: nil, callback_pane: nil) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 127

def (session_meta_file:, session:, window:, pane:, window_id: nil, callback_pane: nil)
  data = if File.exist?(session_meta_file)
    YAML.safe_load_file(session_meta_file) || {}
  else
    {}
  end
  data["launch_mode"] = "tmux"
  data["tmux_session"] = session
  data["tmux_window"] = window
  data["tmux_window_id"] = window_id if window_id
  data["tmux_pane_id"] = pane
  data["callback_pane"] = callback_pane if callback_pane && !callback_pane.empty?
  File.write(session_meta_file, data.to_yaml)
end

#prepare_pane(session:, window:, root:, keep_existing:, window_target: nil) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 82

def prepare_pane(session:, window:, root:, keep_existing:, window_target: nil)
  target = window_target || "#{session}:#{window}"
  pane = if keep_existing
    first_pane(target)
  else
    create_pane(target, root)
  end

  set_pane_remain_on_exit(pane)
  select_layout(target)
  pane
end

#run_invocation_in_pane(pane_target:, command:, env: nil, working_dir: nil, visible_handoff: nil) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 103

def run_invocation_in_pane(pane_target:, command:, env: nil, working_dir: nil, visible_handoff: nil)
  shell_command = build_pane_shell_command(
    command: command,
    env: env,
    working_dir: working_dir,
    visible_handoff: visible_handoff
  )
  control_surface.send_command(pane: pane_target, command: shell_command)
rescue Ace::Tmux::Error => e
  raise Error, "Failed to send tmux fork command: #{e.message}"
end

#run_script_in_pane(pane_target:, script_path:) ⇒ Object



115
116
117
118
119
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 115

def run_script_in_pane(pane_target:, script_path:)
  control_surface.send_command(pane: pane_target, command: "bash #{File.expand_path(script_path).shellescape}")
rescue Ace::Tmux::Error => e
  raise Error, "Failed to send tmux fork command: #{e.message}"
end

#select_window(session:, window:, window_target: nil) ⇒ Object



95
96
97
98
99
100
101
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 95

def select_window(session:, window:, window_target: nil)
  target = window_target || "#{session}:#{window}"
  run!(
    Ace::Tmux::Atoms::TmuxCommandBuilder.select_window(target, tmux: tmux),
    "select tmux fork window #{window}"
  )
end

#tmux_context?Boolean

Returns:

  • (Boolean)


25
26
27
# File 'lib/ace/assign/molecules/tmux_control_surface_runner.rb', line 25

def tmux_context?
  !current_session.to_s.strip.empty?
end