use crate::app::window_state::WindowState;
use crate::tmux::TmuxWindowId;
use super::layout::BoundsInfo;
impl WindowState {
pub(super) fn handle_same_pane_layout_update(
&mut self,
tab_id: crate::tab::TabId,
parsed_layout: &crate::tmux::TmuxLayout,
bounds_info: BoundsInfo,
) {
crate::debug_info!(
"TMUX",
"Layout change with same panes - preserving terminals, updating layout"
);
let Some(tab) = self.tab_manager.get_tab_mut(tab_id) else {
return;
};
if let Some(pm) = tab.pane_manager_mut() {
pm.update_layout_from_tmux(parsed_layout, &self.tmux_state.tab_mappings(tab_id));
pm.recalculate_bounds();
if let Some((_, _, _, _, cell_width, cell_height, _)) = bounds_info {
pm.resize_all_terminals(cell_width, cell_height);
}
}
self.focus_state.needs_redraw = true;
}
pub(super) fn handle_pane_removal(
&mut self,
tab_id: crate::tab::TabId,
parsed_layout: &crate::tmux::TmuxLayout,
panes_to_keep: &std::collections::HashSet<crate::tmux::TmuxPaneId>,
panes_to_remove: &[crate::tmux::TmuxPaneId],
bounds_info: BoundsInfo,
) {
crate::debug_info!(
"TMUX",
"Layout change: keeping {:?}, removing {:?}",
panes_to_keep,
panes_to_remove
);
let current_focused = self
.tmux_state
.tmux_session
.as_ref()
.and_then(|s| s.focused_pane());
let focused_pane_removed = current_focused
.map(|fp| panes_to_remove.contains(&fp))
.unwrap_or(false);
let Some(tab) = self.tab_manager.get_tab_mut(tab_id) else {
return;
};
if let Some(pm) = tab.pane_manager_mut() {
for tmux_pane_id in panes_to_remove {
if let Some((_, native_pane_id)) = self.tmux_state.tmux_pane_owner(*tmux_pane_id) {
crate::debug_info!(
"TMUX",
"Removing native pane {} for closed tmux pane %{}",
native_pane_id,
tmux_pane_id
);
pm.close_pane(native_pane_id);
}
}
let kept_mappings: std::collections::HashMap<_, _> = self
.tmux_state
.tab_mappings(tab_id)
.iter()
.filter(|(tmux_id, _)| panes_to_keep.contains(tmux_id))
.map(|(k, v)| (*k, *v))
.collect();
pm.update_layout_from_tmux(parsed_layout, &kept_mappings);
pm.recalculate_bounds();
if let Some((_, _, _, _, cell_width, cell_height, _)) = bounds_info {
pm.resize_all_terminals(cell_width, cell_height);
}
}
for tmux_pane_id in panes_to_remove {
self.tmux_state.remove_tmux_pane_mapping(*tmux_pane_id);
}
#[cfg(feature = "mux")]
self.tmux_state.agent_roster.remove_panes(panes_to_remove);
if focused_pane_removed && let Some(new_focus) = panes_to_keep.iter().next().copied() {
crate::debug_info!(
"TMUX",
"Focused pane was removed, updating tmux session focus to %{}",
new_focus
);
if let Some(session) = &mut self.tmux_state.tmux_session {
session.set_focused_pane(Some(new_focus));
}
}
crate::debug_info!(
"TMUX",
"After pane removal, mappings: {:?}",
self.tmux_state.tmux_pane_owners
);
self.focus_state.needs_redraw = true;
self.request_redraw();
}
pub(super) fn handle_pane_addition(
&mut self,
tab_id: crate::tab::TabId,
parsed_layout: &crate::tmux::TmuxLayout,
panes_to_keep: &std::collections::HashSet<crate::tmux::TmuxPaneId>,
panes_to_add: &[crate::tmux::TmuxPaneId],
bounds_info: BoundsInfo,
) {
crate::debug_info!(
"TMUX",
"Layout change: keeping {:?}, adding {:?}",
panes_to_keep,
panes_to_add
);
let Some(tab) = self.tab_manager.get_tab_mut(tab_id) else {
return;
};
if let Some(pm) = tab.pane_manager_mut() {
let existing_mappings: std::collections::HashMap<_, _> = panes_to_keep
.iter()
.filter_map(|tmux_id| {
self.tmux_state
.tmux_pane_owner(*tmux_id)
.map(|(_, native_id)| (*tmux_id, native_id))
})
.collect();
match pm.rebuild_from_tmux_layout(
parsed_layout,
&existing_mappings,
panes_to_add,
&self.config.load(),
std::sync::Arc::clone(&self.runtime),
) {
Ok(new_mappings) => {
self.tmux_state.set_tab_pane_mappings(tab_id, &new_mappings);
crate::debug_info!(
"TMUX",
"Rebuilt layout with {} panes: {:?}",
new_mappings.len(),
new_mappings
);
if let Some((_, _, _, _, cell_width, cell_height, _)) = bounds_info {
pm.resize_all_terminals(cell_width, cell_height);
}
}
Err(e) => {
crate::debug_error!("TMUX", "Failed to rebuild layout: {}", e);
}
}
}
if let Some(tab) = self.tab_manager.get_tab_mut(tab_id) {
tab.attach_session_logging_to_panes();
}
self.request_pane_refresh(panes_to_add);
crate::debug_info!(
"TMUX",
"After pane addition, mappings: {:?}",
self.tmux_state.tmux_pane_owners
);
self.focus_state.needs_redraw = true;
self.request_redraw();
}
pub(super) fn handle_full_layout_recreation(
&mut self,
tab_id: crate::tab::TabId,
window_id: TmuxWindowId,
parsed_layout: &crate::tmux::TmuxLayout,
pane_ids: &[crate::tmux::TmuxPaneId],
bounds_info: BoundsInfo,
) {
let existing_tmux_ids: std::collections::HashSet<_> =
self.tmux_state.tab_tmux_pane_ids(tab_id);
let new_tmux_ids: std::collections::HashSet<crate::tmux::TmuxPaneId> =
pane_ids.iter().copied().collect();
crate::debug_info!(
"TMUX",
"Full layout recreation: existing={:?}, new={:?}",
existing_tmux_ids,
new_tmux_ids
);
let Some(tab) = self.tab_manager.get_tab_mut(tab_id) else {
return;
};
if let Some(pm) = tab.pane_manager_mut() {
match pm.set_from_tmux_layout(
parsed_layout,
&self.config.load(),
std::sync::Arc::clone(&self.runtime),
) {
Ok(pane_mappings) => {
crate::debug_info!("TMUX", "Storing pane mappings: {:?}", pane_mappings);
self.tmux_state
.set_tab_pane_mappings(tab_id, &pane_mappings);
crate::debug_info!(
"TMUX",
"Applied tmux layout to tab {}: {} pane mappings created",
tab_id,
pane_mappings.len()
);
if let Some((_, _, _, _, cell_width, cell_height, _)) = bounds_info {
pm.resize_all_terminals(cell_width, cell_height);
}
if !pane_ids.is_empty() && tab.tmux.tmux_pane_id.is_none() {
tab.tmux.tmux_pane_id = Some(pane_ids[0]);
}
tab.attach_session_logging_to_panes();
self.request_pane_refresh(pane_ids);
self.focus_state.needs_redraw = true;
}
Err(e) => {
crate::debug_error!(
"TMUX",
"Failed to apply tmux layout to tab {}: {}",
tab_id,
e
);
if !pane_ids.is_empty() && tab.tmux.tmux_pane_id.is_none() {
tab.tmux.tmux_pane_id = Some(pane_ids[0]);
}
}
}
} else {
if !pane_ids.is_empty() && tab.tmux.tmux_pane_id.is_none() {
tab.tmux.tmux_pane_id = Some(pane_ids[0]);
crate::debug_info!(
"TMUX",
"Set tab {} tmux_pane_id to %{} for output routing (no pane manager)",
tab_id,
pane_ids[0]
);
}
}
let _ = window_id; }
}