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.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.pending_file_opens.push(super::PendingFileOpen {
39 path,
40 line,
41 column,
42 end_line,
43 end_column,
44 message,
45 wait_id,
46 });
47 }
48
49 /// Process pending file opens (called from the event loop).
50 ///
51 /// Opens files that were queued during startup, using the same error handling
52 /// as interactive file opens. Returns true if any files were processed.
53 pub fn process_pending_file_opens(&mut self) -> bool {
54 if self.pending_file_opens.is_empty() {
55 return false;
56 }
57
58 // Take all pending files to process
59 let pending = std::mem::take(&mut self.pending_file_opens);
60 let mut processed_any = false;
61
62 for pending_file in pending {
63 tracing::info!(
64 "[SYNTAX DEBUG] Processing pending file open: {:?}",
65 pending_file.path
66 );
67
68 match self.open_file(&pending_file.path) {
69 Ok(_) => {
70 // Navigate to line/column or select range if specified
71 if let (Some(line), Some(end_line)) = (pending_file.line, pending_file.end_line)
72 {
73 self.select_range(
74 line,
75 pending_file.column,
76 end_line,
77 pending_file.end_column,
78 );
79 } else if let Some(line) = pending_file.line {
80 self.goto_line_col(line, pending_file.column);
81 }
82 // Show hover message popup if specified
83 let has_popup = pending_file.message.is_some();
84 if let Some(ref msg) = pending_file.message {
85 self.show_file_message_popup(msg);
86 }
87 // Track wait ID for --wait support
88 if let Some(wait_id) = pending_file.wait_id {
89 let buffer_id = self.active_buffer();
90 self.wait_tracking.insert(buffer_id, (wait_id, has_popup));
91 }
92 processed_any = true;
93 }
94 Err(e) => {
95 // Check if this is a large file encoding confirmation error
96 // Show prompt instead of crashing
97 if let Some(confirmation) =
98 e.downcast_ref::<crate::model::buffer::LargeFileEncodingConfirmation>()
99 {
100 self.start_large_file_encoding_confirmation(confirmation);
101 } else {
102 // For other errors, show status message (consistent with file browser)
103 self.set_status_message(
104 t!("file.error_opening", error = e.to_string()).to_string(),
105 );
106 }
107 processed_any = true;
108 }
109 }
110 }
111
112 // Apply hot exit recovery if flagged (one-shot after CLI files are opened)
113 if processed_any && self.pending_hot_exit_recovery {
114 self.pending_hot_exit_recovery = false;
115 match self.apply_hot_exit_recovery() {
116 Ok(count) if count > 0 => {
117 tracing::info!("Hot exit: restored unsaved changes for {} buffer(s)", count);
118 }
119 Ok(_) => {}
120 Err(e) => {
121 tracing::warn!("Failed to apply hot exit recovery: {}", e);
122 }
123 }
124 }
125
126 processed_any
127 }
128
129 /// Take and return completed wait IDs (for --wait support).
130 pub fn take_completed_waits(&mut self) -> Vec<u64> {
131 std::mem::take(&mut self.completed_waits)
132 }
133
134 /// Remove wait tracking for a given wait_id (e.g., when waiting client disconnects).
135 pub fn remove_wait_tracking(&mut self, wait_id: u64) {
136 self.wait_tracking.retain(|_, (wid, _)| *wid != wait_id);
137 }
138}