1use super::*;
6
7impl Editor {
8 pub fn should_quit(&self) -> bool {
10 self.should_quit
11 }
12
13 pub fn should_detach(&self) -> bool {
15 self.should_detach
16 }
17
18 pub fn clear_detach(&mut self) {
20 self.should_detach = false;
21 }
22
23 pub fn set_session_mode(&mut self, session_mode: bool) {
25 self.session_mode = session_mode;
26 self.clipboard.set_session_mode(session_mode);
27 if session_mode {
29 self.active_window_mut()
30 .active_custom_contexts
31 .insert(crate::types::context_keys::SESSION_MODE.to_string());
32 } else {
33 self.active_window_mut()
34 .active_custom_contexts
35 .remove(crate::types::context_keys::SESSION_MODE);
36 }
37 }
38
39 pub fn is_session_mode(&self) -> bool {
41 self.session_mode
42 }
43
44 pub fn set_software_cursor_only(&mut self, enabled: bool) {
47 self.software_cursor_only = enabled;
48 }
49
50 pub fn set_session_name(&mut self, name: Option<String>) {
56 if let Some(ref session_name) = name {
57 let base_recovery_dir = self.dir_context.recovery_dir();
58 let scope = crate::services::recovery::RecoveryScope::Session {
59 name: session_name.clone(),
60 };
61 let recovery_config = RecoveryConfig {
62 enabled: self.recovery_service.is_enabled(),
63 ..RecoveryConfig::default()
64 };
65 self.recovery_service =
66 RecoveryService::with_scope(recovery_config, &base_recovery_dir, &scope);
67 }
68 self.session_name = name;
69 }
70
71 pub fn session_name(&self) -> Option<&str> {
73 self.session_name.as_deref()
74 }
75
76 pub fn queue_escape_sequences(&mut self, sequences: &[u8]) {
78 self.pending_escape_sequences.extend_from_slice(sequences);
79 }
80
81 pub fn take_pending_escape_sequences(&mut self) -> Vec<u8> {
83 std::mem::take(&mut self.pending_escape_sequences)
84 }
85
86 pub fn take_pending_clipboard(
88 &mut self,
89 ) -> Option<crate::services::clipboard::PendingClipboard> {
90 self.clipboard.take_pending_clipboard()
91 }
92
93 pub fn should_restart(&self) -> bool {
95 self.restart_with_dir.is_some()
96 }
97
98 pub fn take_restart_dir(&mut self) -> Option<PathBuf> {
101 self.restart_with_dir.take()
102 }
103
104 pub fn request_full_redraw(&mut self) {
109 self.full_redraw_requested = true;
110 }
111
112 pub fn take_full_redraw_request(&mut self) -> bool {
114 let requested = self.full_redraw_requested;
115 self.full_redraw_requested = false;
116 requested
117 }
118
119 pub fn request_suspend(&mut self) {
123 self.suspend_requested = true;
124 }
125
126 pub fn take_suspend_request(&mut self) -> bool {
128 let requested = self.suspend_requested;
129 self.suspend_requested = false;
130 requested
131 }
132
133 pub fn request_restart(&mut self, new_working_dir: PathBuf) {
134 tracing::info!(
135 "Restart requested with new working directory: {}",
136 new_working_dir.display()
137 );
138 self.restart_with_dir = Some(new_working_dir);
139 self.should_quit = true;
141 }
142
143 pub fn theme(&self) -> std::sync::RwLockReadGuard<'_, crate::view::theme::Theme> {
145 self.theme.read().unwrap()
146 }
147
148 pub fn is_settings_open(&self) -> bool {
150 self.settings_state.as_ref().is_some_and(|s| s.visible)
151 }
152
153 pub fn quit(&mut self) {
155 let modified_count = self.count_modified_buffers_needing_prompt();
157 if modified_count > 0 {
158 let save_key = t!("prompt.key.save").to_string();
159 let cancel_key = t!("prompt.key.cancel").to_string();
160 let hot_exit = self.config.editor.hot_exit;
161
162 let discard_key = t!("prompt.key.discard").to_string();
163 let msg = if hot_exit {
164 let quit_key = t!("prompt.key.quit").to_string();
166 if modified_count == 1 {
167 t!(
168 "prompt.quit_modified_hot_one",
169 save_key = save_key,
170 discard_key = discard_key,
171 quit_key = quit_key,
172 cancel_key = cancel_key
173 )
174 .to_string()
175 } else {
176 t!(
177 "prompt.quit_modified_hot_many",
178 count = modified_count,
179 save_key = save_key,
180 discard_key = discard_key,
181 quit_key = quit_key,
182 cancel_key = cancel_key
183 )
184 .to_string()
185 }
186 } else {
187 if modified_count == 1 {
189 t!(
190 "prompt.quit_modified_one",
191 save_key = save_key,
192 discard_key = discard_key,
193 cancel_key = cancel_key
194 )
195 .to_string()
196 } else {
197 t!(
198 "prompt.quit_modified_many",
199 count = modified_count,
200 save_key = save_key,
201 discard_key = discard_key,
202 cancel_key = cancel_key
203 )
204 .to_string()
205 }
206 };
207 self.start_prompt(msg, PromptType::ConfirmQuitWithModified);
208 } else {
209 self.should_quit = true;
210 }
211 }
212
213 fn count_modified_buffers_needing_prompt(&self) -> usize {
221 let hot_exit = self.config.editor.hot_exit;
222 let auto_save = self.config.editor.auto_save_enabled;
223
224 self.windows
225 .get(&self.active_window)
226 .map(|w| &w.buffers)
227 .expect("active window present")
228 .iter()
229 .filter(|(buffer_id, state)| {
230 if !state.buffer.is_modified() {
231 return false;
232 }
233 if let Some(meta) = self.active_window().buffer_metadata.get(buffer_id) {
234 if let Some(path) = meta.file_path() {
235 let is_unnamed = path.as_os_str().is_empty();
236 if is_unnamed && hot_exit {
237 return false; }
239 if !is_unnamed && auto_save {
240 return false; }
242 }
243 }
244 true
245 })
246 .count()
247 }
248
249 pub fn focus_gained(&mut self) {
251 self.plugin_manager.read().unwrap().run_hook(
252 "focus_gained",
253 crate::services::plugins::hooks::HookArgs::FocusGained {},
254 );
255 }
256
257 pub fn resize(&mut self, width: u16, height: u16) {
262 self.terminal_width = width;
264 self.terminal_height = height;
265
266 for window in self.windows.values_mut() {
267 window.resize(width, height);
268 }
269
270 self.plugin_manager.read().unwrap().run_hook(
272 "resize",
273 fresh_core::hooks::HookArgs::Resize { width, height },
274 );
275 }
276}
277
278impl crate::app::window::Window {
279 pub fn resize(&mut self, width: u16, height: u16) {
283 self.terminal_width = width;
284 self.terminal_height = height;
285
286 if let Some(view_states) = self.split_view_states_mut() {
287 for view_state in view_states.values_mut() {
288 view_state.viewport.resize(width, height);
289 }
290 }
291
292 self.resize_visible_terminals();
293 }
294}