fresh/app/file_open_queue.rs
1//! Pending-file-open queue and --wait tracking on `Editor`.
2//!
3//! CLI file arguments are queued and processed after the TUI starts so
4//! they go through the same code path as interactive opens (with proper
5//! encoding-prompt handling). Wait tracking lets the CLI block until
6//! a popup-based wait is dismissed.
7
8use std::path::PathBuf;
9
10use rust_i18n::t;
11
12use super::Editor;
13
14impl Editor {
15 /// Queue a file to be opened after the TUI starts.
16 ///
17 /// This is used for CLI file arguments to ensure they go through the same
18 /// code path as interactive file opens, providing consistent error handling
19 /// (e.g., encoding confirmation prompts are shown in the UI instead of crashing).
20 /// Schedule hot exit recovery to run after the next batch of pending file opens.
21 pub fn schedule_hot_exit_recovery(&mut self) {
22 if self.config.editor.hot_exit {
23 self.active_window_mut().pending_hot_exit_recovery = true;
24 }
25 }
26
27 #[allow(clippy::too_many_arguments)]
28 pub fn queue_file_open(
29 &mut self,
30 path: PathBuf,
31 line: Option<usize>,
32 column: Option<usize>,
33 end_line: Option<usize>,
34 end_column: Option<usize>,
35 message: Option<String>,
36 wait_id: Option<u64>,
37 ) {
38 self.active_window_mut()
39 .pending_file_opens
40 .push(super::PendingFileOpen {
41 path,
42 line,
43 column,
44 end_line,
45 end_column,
46 message,
47 wait_id,
48 });
49 }
50
51 /// Process pending file opens (called from the event loop).
52 ///
53 /// Opens files that were queued during startup, using the same error handling
54 /// as interactive file opens. Returns true if any files were processed.
55 pub fn process_pending_file_opens(&mut self) -> bool {
56 if self.active_window_mut().pending_file_opens.is_empty() {
57 return false;
58 }
59
60 // Take all pending files to process
61 let pending = std::mem::take(&mut self.active_window_mut().pending_file_opens);
62 let mut processed_any = false;
63
64 for pending_file in pending {
65 tracing::info!(
66 "[SYNTAX DEBUG] Processing pending file open: {:?}",
67 pending_file.path
68 );
69
70 match self.open_file(&pending_file.path) {
71 Ok(_) => {
72 // Navigate to line/column or select range if specified
73 if let (Some(line), Some(end_line)) = (pending_file.line, pending_file.end_line)
74 {
75 self.select_range(
76 line,
77 pending_file.column,
78 end_line,
79 pending_file.end_column,
80 );
81 } else if let Some(line) = pending_file.line {
82 self.goto_line_col(line, pending_file.column);
83 }
84 // Show hover message popup if specified
85 let has_popup = pending_file.message.is_some();
86 if let Some(ref msg) = pending_file.message {
87 self.show_file_message_popup(msg);
88 }
89 // Track wait ID for --wait support
90 if let Some(wait_id) = pending_file.wait_id {
91 let buffer_id = self.active_buffer();
92 self.active_window_mut()
93 .wait_tracking
94 .insert(buffer_id, (wait_id, has_popup));
95 }
96 processed_any = true;
97 }
98 Err(e) => {
99 // Check if this is a large file encoding confirmation error
100 // Show prompt instead of crashing
101 if let Some(confirmation) =
102 e.downcast_ref::<crate::model::buffer::LargeFileEncodingConfirmation>()
103 {
104 self.start_large_file_encoding_confirmation(confirmation);
105 } else {
106 // For other errors, show status message (consistent with file browser)
107 self.set_status_message(
108 t!("file.error_opening", error = e.to_string()).to_string(),
109 );
110 }
111 processed_any = true;
112 }
113 }
114 }
115
116 // Apply hot exit recovery if flagged (one-shot after CLI files are opened)
117 if processed_any && self.active_window_mut().pending_hot_exit_recovery {
118 self.active_window_mut().pending_hot_exit_recovery = false;
119 match self.apply_hot_exit_recovery() {
120 Ok(count) if count > 0 => {
121 tracing::info!("Hot exit: restored unsaved changes for {} buffer(s)", count);
122 }
123 Ok(_) => {}
124 Err(e) => {
125 tracing::warn!("Failed to apply hot exit recovery: {}", e);
126 }
127 }
128 }
129
130 processed_any
131 }
132
133 /// Take and return completed wait IDs (for --wait support).
134 pub fn take_completed_waits(&mut self) -> Vec<u64> {
135 std::mem::take(&mut self.active_window_mut().completed_waits)
136 }
137
138 /// Remove wait tracking for a given wait_id (e.g., when waiting client disconnects).
139 pub fn remove_wait_tracking(&mut self, wait_id: u64) {
140 self.active_window_mut()
141 .wait_tracking
142 .retain(|_, (wid, _)| *wid != wait_id);
143 }
144}