use super::WindowManager;
impl WindowManager {
pub fn start_coprocess(&mut self, config_index: usize) {
log::debug!("start_coprocess called with index {}", config_index);
let focused = self.get_focused_window_id();
if let Some(window_id) = focused
&& let Some(ws) = self.windows.get_mut(&window_id)
&& let Some(tab) = ws.tab_manager.active_tab_mut()
{
if config_index >= ws.config.coprocesses.len() {
log::warn!("Coprocess config index {} out of range", config_index);
return;
}
let coproc_config = &ws.config.coprocesses[config_index];
let core_config = par_term_emu_core_rust::coprocess::CoprocessConfig {
command: coproc_config.command.clone(),
args: coproc_config.args.clone(),
cwd: None,
env: crate::terminal::coprocess_env(),
copy_terminal_output: coproc_config.copy_terminal_output,
restart_policy: coproc_config.restart_policy.to_core(),
restart_delay_ms: coproc_config.restart_delay_ms,
};
let term = tab.terminal.blocking_write();
match term.start_coprocess(core_config) {
Ok(id) => {
log::info!("Started coprocess '{}' (id={})", coproc_config.name, id);
while tab.scripting.coprocess_ids.len() <= config_index {
tab.scripting.coprocess_ids.push(None);
}
tab.scripting.coprocess_ids[config_index] = Some(id);
}
Err(e) => {
let err_msg = format!("Failed to start: {}", e);
log::error!("Failed to start coprocess '{}': {}", coproc_config.name, e);
if let Some(sw) = &mut self.settings_window {
let errors = &mut sw.settings_ui.coprocess_errors;
while errors.len() <= config_index {
errors.push(String::new());
}
errors[config_index] = err_msg;
sw.request_redraw();
}
return;
}
}
drop(term);
self.sync_coprocess_running_state();
} else {
log::warn!("start_coprocess: no focused window or active tab found");
}
}
pub fn stop_coprocess(&mut self, config_index: usize) {
log::debug!("stop_coprocess called with index {}", config_index);
let focused = self.get_focused_window_id();
if let Some(window_id) = focused
&& let Some(ws) = self.windows.get_mut(&window_id)
&& let Some(tab) = ws.tab_manager.active_tab_mut()
{
if let Some(Some(id)) = tab.scripting.coprocess_ids.get(config_index).copied() {
let term = tab.terminal.blocking_write();
if let Err(e) = term.stop_coprocess(id) {
log::error!("Failed to stop coprocess at index {}: {}", config_index, e);
} else {
log::info!("Stopped coprocess at index {} (id={})", config_index, id);
}
drop(term);
tab.scripting.coprocess_ids[config_index] = None;
}
self.sync_coprocess_running_state();
}
}
const COPROCESS_OUTPUT_MAX_LINES: usize = 200;
pub fn sync_coprocess_running_state(&mut self) {
let focused = self.get_focused_window_id();
let (running_state, error_state, new_output): (Vec<bool>, Vec<String>, Vec<Vec<String>>) =
if let Some(window_id) = focused
&& let Some(ws) = self.windows.get(&window_id)
&& let Some(tab) = ws.tab_manager.active_tab()
{
if let Ok(term) = tab.terminal.try_write() {
let mut running = Vec::new();
let mut errors = Vec::new();
let mut output = Vec::new();
for (i, _) in ws.config.coprocesses.iter().enumerate() {
let has_id = tab
.scripting
.coprocess_ids
.get(i)
.and_then(|opt| opt.as_ref());
let is_running =
has_id.is_some_and(|id| term.coprocess_status(*id).unwrap_or(false));
let err_text = if let Some(id) = has_id {
if is_running {
String::new()
} else {
term.read_coprocess_errors(*id)
.unwrap_or_default()
.join("\n")
}
} else if let Some(sw) = &self.settings_window
&& let Some(existing) = sw.settings_ui.coprocess_errors.get(i)
&& !existing.is_empty()
{
existing.clone()
} else {
String::new()
};
let lines = if let Some(id) = has_id {
term.read_from_coprocess(*id).unwrap_or_default()
} else {
Vec::new()
};
running.push(is_running);
errors.push(err_text);
output.push(lines);
}
(running, errors, output)
} else {
(Vec::new(), Vec::new(), Vec::new())
}
} else {
(Vec::new(), Vec::new(), Vec::new())
};
if let Some(sw) = &mut self.settings_window {
let running_changed = sw.settings_ui.coprocess_running != running_state;
let errors_changed = sw.settings_ui.coprocess_errors != error_state;
let has_new_output = new_output.iter().any(|lines| !lines.is_empty());
let count = running_state.len();
sw.settings_ui.coprocess_output.resize_with(count, Vec::new);
sw.settings_ui
.coprocess_output_expanded
.resize(count, false);
for (i, lines) in new_output.into_iter().enumerate() {
if !lines.is_empty() {
let buf = &mut sw.settings_ui.coprocess_output[i];
buf.extend(lines);
let overflow = buf.len().saturating_sub(Self::COPROCESS_OUTPUT_MAX_LINES);
if overflow > 0 {
buf.drain(..overflow);
}
}
}
if running_changed || errors_changed || has_new_output {
sw.settings_ui.coprocess_running = running_state;
sw.settings_ui.coprocess_errors = error_state;
sw.request_redraw();
}
}
}
}