1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Tab bar action handlers.
//!
//! Contains [`WindowState::handle_tab_bar_action_after_render`], dispatching
//! all [`TabBarAction`] variants produced during egui rendering.
use crate::app::window_state::WindowState;
use crate::tab_bar_ui::TabBarAction;
impl WindowState {
/// Handle tab bar actions collected during egui rendering (called after renderer borrow released).
pub(crate) fn handle_tab_bar_action_after_render(
&mut self,
action: crate::tab_bar_ui::TabBarAction,
) {
// Handle tab bar actions collected during egui rendering
// (done here to avoid borrow conflicts with renderer)
match action {
TabBarAction::SwitchTo(id) => {
self.tab_manager.switch_to(id);
// Clear renderer cells and invalidate cache to ensure clean switch
self.clear_and_invalidate();
}
TabBarAction::Close(id) => {
// Switch to the tab first so close_current_tab() operates on it.
// This routes through the full close path: running-jobs confirmation,
// session undo capture, and preserve-shell logic.
self.tab_manager.switch_to(id);
let was_last = self.close_current_tab();
if was_last {
self.is_shutting_down = true;
}
self.request_redraw();
}
TabBarAction::NewTab => {
self.new_tab();
self.request_redraw();
}
TabBarAction::SetColor(id, color) => {
if let Some(tab) = self.tab_manager.get_tab_mut(id) {
tab.set_custom_color(color);
log::info!(
"Set custom color for tab {}: RGB({}, {}, {})",
id,
color[0],
color[1],
color[2]
);
}
self.request_redraw();
}
TabBarAction::ClearColor(id) => {
if let Some(tab) = self.tab_manager.get_tab_mut(id) {
tab.clear_custom_color();
log::info!("Cleared custom color for tab {}", id);
}
self.request_redraw();
}
TabBarAction::Reorder(id, target_index) => {
if self.tab_manager.move_tab_to_index(id, target_index) {
self.focus_state.needs_redraw = true;
self.request_redraw();
}
}
TabBarAction::NewTabWithProfile(profile_id) => {
self.open_profile(profile_id);
self.request_redraw();
}
TabBarAction::RenameTab(id, name) => {
if let Some(tab) = self.tab_manager.get_tab_mut(id) {
if name.is_empty() {
// Blank name: revert to auto title mode
tab.user_named = false;
tab.has_default_title = true;
// Reset focused pane so the per-pane loop re-derives its title from scratch
if let Some(pane) = tab
.pane_manager
.as_mut()
.and_then(|pm| pm.focused_pane_mut())
{
pane.title = String::new();
pane.has_default_title = true;
}
// Trigger immediate title update
tab.update_title(
self.config.tab_title_mode,
self.config.remote_tab_title_format,
self.config.remote_tab_title_osc_priority,
);
} else {
tab.set_title(&name);
tab.user_named = true;
// has_default_title = false is already set by set_title()
}
}
self.request_redraw();
}
TabBarAction::Duplicate(id) => {
self.duplicate_tab_by_id(id);
self.request_redraw();
}
TabBarAction::ToggleAssistantPanel => {
let just_opened = self.overlay_ui.ai_inspector.toggle();
self.sync_ai_inspector_width();
if just_opened {
self.try_auto_connect_agent();
}
self.request_redraw();
}
TabBarAction::SetTabIcon(tab_id, icon) => {
if let Some(tab) = self.tab_manager.get_tab_mut(tab_id) {
tab.custom_icon = icon;
}
self.request_redraw();
}
TabBarAction::None => {}
TabBarAction::MoveTabToNewWindow(tab_id) => {
self.overlay_ui.pending_move_tab_request =
Some(crate::app::window_manager::MoveTabRequest {
tab_id,
destination: crate::app::window_manager::MoveDestination::NewWindow,
});
}
TabBarAction::MoveTabToExistingWindow(tab_id, dest_id) => {
self.overlay_ui.pending_move_tab_request =
Some(crate::app::window_manager::MoveTabRequest {
tab_id,
destination: crate::app::window_manager::MoveDestination::ExistingWindow(
dest_id,
),
});
}
}
}
}