cargo_e/
e_tui.rs

1#[cfg(feature = "tui")]
2pub mod tui_interactive {
3    use crate::e_command_builder::CargoCommandBuilder;
4    use crate::e_manifest::maybe_patch_manifest_for_run;
5    use crate::e_processmanager::ProcessManager;
6    use crate::e_prompts::prompt_line;
7    use crate::e_target::CargoTarget;
8    use crate::prelude::*;
9    use crate::{e_bacon, e_findmain, Cli};
10    use crossterm::event::KeyEventKind;
11    use crossterm::event::{poll, read};
12    use crossterm::{
13        event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, MouseEventKind},
14        execute,
15        terminal::{
16            disable_raw_mode, enable_raw_mode, Clear, ClearType, EnterAlternateScreen,
17            LeaveAlternateScreen,
18        },
19    };
20    use ratatui::{
21        backend::CrosstermBackend,
22        layout::{Constraint, Direction, Layout, Rect},
23        style::{Color, Style},
24        text::{Line, Span},
25        widgets::{Block, Borders, List, ListItem, ListState},
26        Terminal,
27    };
28    use std::{collections::HashSet, thread, time::Duration};
29    use sysinfo::{ProcessRefreshKind, ProcessesToUpdate, System};
30
31    /// Flushes the input event queue, ignoring any stray Enter key events.
32    pub fn flush_input() -> Result<(), Box<dyn std::error::Error>> {
33        while poll(Duration::from_millis(0))? {
34            if let Event::Key(key_event) = read()? {
35                // Optionally, log or ignore specific keys.
36                if key_event.code == KeyCode::Enter {
37                    // Filtering out stray Return keys.
38                    continue;
39                }
40                // You can also choose to ignore all events:
41                continue;
42            }
43        }
44        Ok(())
45    }
46
47    /// Try to collect an escape sequence if the first event is Esc.
48    /// Returns Some(arrow) if the sequence matches an arrow key, otherwise None.
49    fn try_collect_arrow_sequence() -> Result<Option<KeyCode>, Box<dyn std::error::Error>> {
50        // Buffer to hold the sequence. We already know the first event is Esc.
51        let mut sequence = vec![];
52        let start = Instant::now();
53        // Give a short window (e.g. 50 ms) to collect additional events.
54        while start.elapsed() < Duration::from_millis(50) {
55            if poll(Duration::from_millis(0))? {
56                if let Event::Key(key) = read()? {
57                    // Only consider Press events.
58                    if key.kind == KeyEventKind::Press {
59                        sequence.push(key);
60                    }
61                }
62            }
63        }
64        // Now, an arrow key should have a sequence like: Esc, '[' and then 'A' (or 'B', 'C', 'D').
65        if sequence.len() >= 2 && sequence[0].code == KeyCode::Char('[') {
66            // Check the third element if available.
67            if let Some(third) = sequence.get(1) {
68                // Compare the character case-insensitively (to handle unexpected modifiers).
69                if let KeyCode::Char(ch) = third.code {
70                    let ch = ch.to_ascii_uppercase();
71                    return Ok(match ch {
72                        'A' => Some(KeyCode::Up),
73                        'B' => Some(KeyCode::Down),
74                        'C' => Some(KeyCode::Right),
75                        'D' => Some(KeyCode::Left),
76                        _ => None,
77                    });
78                }
79            }
80        }
81        Ok(None)
82    }
83
84    /// Launches an interactive terminal UI for selecting an example.
85    pub fn launch_tui(
86        manager: Arc<ProcessManager>,
87        cli: &Cli,
88        examples: &[CargoTarget],
89    ) -> Result<(), Box<dyn std::error::Error>> {
90        flush_input()?; // Clear any buffered input (like stray Return keys)
91        let mut exs = examples.to_vec();
92        if exs.is_empty() {
93            println!("No examples found!");
94            return Ok(());
95        }
96        exs.sort_by(|a, b| a.display_name.cmp(&b.display_name));
97        // Determine the directory containing the Cargo.toml at runtime.
98        let manifest_dir = crate::e_manifest::find_manifest_dir()?;
99        let history_path = manifest_dir.join("run_history.txt");
100        let mut run_history: HashSet<String> = HashSet::new();
101        if let Ok(contents) = fs::read_to_string(&history_path) {
102            for line in contents.lines() {
103                if !line.trim().is_empty() {
104                    run_history.insert(line.trim().to_string());
105                }
106            }
107        }
108
109        enable_raw_mode()?;
110        let mut stdout = io::stdout();
111        execute!(
112            stdout,
113            EnterAlternateScreen,
114            EnableMouseCapture,
115            Clear(ClearType::All)
116        )?;
117        let backend = CrosstermBackend::new(stdout);
118        let mut terminal = Terminal::new(backend)?;
119
120        let mut list_state = ListState::default();
121        list_state.select(Some(0));
122        let mut exit_hover = false;
123        let mut run_history_map = crate::e_parser::read_run_history(&history_path);
124        'main_loop: loop {
125            terminal.draw(|f| {
126                let size = f.area();
127                let area = Rect::new(0, 0, size.width, size.height);
128                let chunks = Layout::default()
129                    .direction(Direction::Vertical)
130                    .margin(2)
131                    .constraints([Constraint::Min(0)].as_ref())
132                    .split(area);
133                let list_area = chunks[0];
134
135                let left_text = format!("Select target ({} found)", exs.len());
136                let separator = " ┃ ";
137                let right_text = "q to EXIT";
138                let title_line = if exit_hover {
139                    Line::from(vec![
140                        Span::raw(left_text),
141                        Span::raw(separator),
142                        Span::styled(right_text, Style::default().fg(Color::Yellow)),
143                    ])
144                } else {
145                    Line::from(vec![
146                        Span::raw(left_text),
147                        Span::raw(separator),
148                        Span::styled("q to ", Style::default().fg(Color::White)),
149                        Span::styled("EXIT", Style::default().fg(Color::Red)),
150                    ])
151                };
152                let pad_width = exs.len().to_string().len();
153                // Compute the maximum width for the ex.kind values.
154                let max_kind_width = exs
155                    .iter()
156                    .map(|ex| format!("{:?}", ex.kind).len())
157                    .max()
158                    .unwrap_or(0);
159                let mut line_number = 0;
160                let block = Block::default().borders(Borders::ALL).title(title_line);
161                let items: Vec<ListItem> = exs
162                    .iter()
163                    .map(|ex| {
164                        let kind_str = format!("{:?}", ex.kind);
165                        let mut display = format!(
166                            "{:>width$}: [{:>max_kind_width$}] {}",
167                            line_number,
168                            kind_str,
169                            &ex.display_name,
170                            width = pad_width,
171                            max_kind_width = max_kind_width
172                        );
173                        if let Some(count) = run_history_map.get(&ex.name) {
174                            display.push_str(&format!(
175                                "({} run{})",
176                                count,
177                                if *count == 1 { "" } else { "s" }
178                            ));
179                        }
180                        line_number = line_number + 1;
181                        let mut item = ListItem::new(display);
182                        if run_history_map.get(&ex.name).is_some() {
183                            item = item.style(Style::default().fg(Color::Blue));
184                        }
185                        item
186                    })
187                    .collect();
188                let list = List::new(items)
189                    .block(block)
190                    .highlight_style(Style::default().fg(Color::Yellow))
191                    .highlight_symbol(">> ");
192                f.render_stateful_widget(list, list_area, &mut list_state);
193            })?;
194
195            {
196                match event::read()? {
197                    Event::Key(key) => {
198                        // Only process key-press events.
199                        if key.kind == KeyEventKind::Press {
200                            if key.code == KeyCode::Char('c')
201                                && key.modifiers.contains(event::KeyModifiers::CONTROL)
202                            {
203                                eprintln!(
204                                    "CTRL-C detected within TUI event loop. Terminating processes."
205                                );
206                                manager.kill_all();
207                                // Optionally, exit the TUI or perform additional cleanup.
208                            }
209                            // Check if we might be starting an escape sequence for an arrow key.
210                            if key.code == KeyCode::Esc {
211                                // Try to collect the rest of the sequence.
212                                if let Some(arrow_code) = try_collect_arrow_sequence()? {
213                                    match arrow_code {
214                                        KeyCode::Up => {
215                                            let new_index = match list_state.selected() {
216                                                Some(0) | None => 0,
217                                                Some(i) => i.saturating_sub(1),
218                                            };
219                                            list_state.select(Some(new_index));
220                                        }
221                                        KeyCode::Down => {
222                                            let new_index = match list_state.selected() {
223                                                Some(i) if i >= exs.len() - 1 => i,
224                                                Some(i) => i + 1,
225                                                None => 0,
226                                            };
227                                            list_state.select(Some(new_index));
228                                        }
229                                        KeyCode::Left => {
230                                            // Handle left arrow if needed.
231                                        }
232                                        KeyCode::Right => {
233                                            // Handle right arrow if needed.
234                                        }
235                                        _ => {}
236                                    }
237                                    // We've handled the arrow, so skip further processing.
238                                    continue;
239                                } else {
240                                    // No follow-up sequence—treat it as a standalone Esc if needed.
241                                    // For example, you might decide not to exit on Esc now.
242                                    // println!("Standalone Esc detected (ignoring).");
243                                    continue;
244                                }
245                            }
246                            match key.code {
247                                KeyCode::Char('q') => {
248                                    // Exit the TUI mode when 'q' is pressed.
249                                    println!("Exiting TUI mode...");
250                                    break 'main_loop;
251                                }
252                                KeyCode::Down => {
253                                    let i = match list_state.selected() {
254                                        Some(i) if i >= exs.len() - 1 => i,
255                                        Some(i) => i + 1,
256                                        None => 0,
257                                    };
258                                    list_state.select(Some(i));
259                                    thread::sleep(Duration::from_millis(50));
260                                }
261                                KeyCode::Up => {
262                                    let i = match list_state.selected() {
263                                        Some(0) | None => 0,
264                                        Some(i) => i - 1,
265                                    };
266                                    list_state.select(Some(i));
267                                    thread::sleep(Duration::from_millis(50));
268                                }
269                                KeyCode::PageDown => {
270                                    // Compute page size based on the terminal's current height.
271                                    let page = terminal
272                                        .size()
273                                        .map(|r| r.height.saturating_sub(4)) // subtract borders/margins; adjust as needed
274                                        .unwrap_or(5)
275                                        as usize;
276                                    let current = list_state.selected().unwrap_or(0);
277                                    let new = std::cmp::min(current + page, exs.len() - 1);
278                                    list_state.select(Some(new));
279                                }
280                                KeyCode::PageUp => {
281                                    let page = terminal
282                                        .size()
283                                        .map(|r| r.height.saturating_sub(4))
284                                        .unwrap_or(5)
285                                        as usize;
286                                    let current = list_state.selected().unwrap_or(0);
287                                    let new = current.saturating_sub(page);
288                                    list_state.select(Some(new));
289                                }
290                                KeyCode::Char('b') => {
291                                    if let Some(selected) = list_state.selected() {
292                                        let sample = &examples[selected];
293                                        // Run bacon in detached mode. Extra arguments can be added if needed.
294                                        if let Err(e) = e_bacon::run_bacon(sample, &Vec::new()) {
295                                            eprintln!("Error running bacon: {}", e);
296                                        } else {
297                                            println!("Bacon launched for sample: {}", sample.name);
298                                        }
299                                        reinit_terminal(&mut terminal)?;
300                                    }
301                                }
302                                KeyCode::Char('e') => {
303                                    if let Some(selected) = list_state.selected() {
304                                        // Disable raw mode for debug printing.
305                                        crossterm::terminal::disable_raw_mode()?;
306                                        crossterm::execute!(
307                                            std::io::stdout(),
308                                            crossterm::terminal::LeaveAlternateScreen
309                                        )?;
310                                        // When 'e' is pressed, attempt to open the sample in VSCode.
311                                        let sample = &exs[selected];
312                                        println!(
313                                            "Opening VSCode for path: {}",
314                                            sample
315                                                .manifest_path
316                                                .to_str()
317                                                .unwrap_or_default()
318                                                .to_owned()
319                                        );
320                                        // Here we block on the asynchronous open_vscode call.
321                                        // futures::executor::block_on(open_vscode(Path::new(&sample.manifest_path)));
322                                        futures::executor::block_on(
323                                            e_findmain::open_vscode_for_sample(sample),
324                                        );
325                                        std::thread::sleep(std::time::Duration::from_secs(5));
326                                        reinit_terminal(&mut terminal)?;
327                                    }
328                                }
329                                KeyCode::Char('i') => {
330                                    if let Some(selected) = list_state.selected() {
331                                        // Disable raw mode for debug printing.
332                                        crossterm::terminal::disable_raw_mode()?;
333                                        crossterm::execute!(
334                                            std::io::stdout(),
335                                            crossterm::terminal::LeaveAlternateScreen
336                                        )?;
337                                        let target = &exs[selected];
338                                        println!("Target: {:?}", target);
339                                        futures::executor::block_on(
340                                            crate::e_runner::open_ai_summarize_for_target(target),
341                                        );
342                                        prompt_line("", 120).ok();
343                                        reinit_terminal(&mut terminal)?;
344                                    }
345                                }
346                                // KeyCode::Char('v') => {
347                                //     if let Some(selected) = list_state.selected() {
348                                //         // Disable raw mode for debug printing.
349                                //         crossterm::terminal::disable_raw_mode()?;
350                                //         crossterm::execute!(
351                                //             std::io::stdout(),
352                                //             crossterm::terminal::LeaveAlternateScreen
353                                //         )?;
354                                //         // When 'e' is pressed, attempt to open the sample in VSCode.
355                                //         let sample = &examples[selected];
356                                //         println!("Opening VIM for path: {}", sample.manifest_path);
357                                //         // Here we block on the asynchronous open_vscode call.
358                                //         // futures::executor::block_on(open_vscode(Path::new(&sample.manifest_path)));
359                                //         e_findmain::open_vim_for_sample(sample);
360                                //         std::thread::sleep(std::time::Duration::from_secs(5));
361                                //         reinit_terminal(&mut terminal)?;
362                                //     }
363                                // }
364                                KeyCode::Enter => {
365                                    if let Some(selected) = list_state.selected() {
366                                        run_piece(
367                                            manager.clone(),
368                                            &exs,
369                                            selected,
370                                            &history_path,
371                                            &mut run_history,
372                                            &mut terminal,
373                                            cli,
374                                        )?;
375                                        run_history_map =
376                                            crate::e_parser::read_run_history(&history_path);
377                                        reinit_terminal(&mut terminal)?;
378                                    }
379                                }
380                                _ => {
381                                    //println!("Unhandled key event: {:?}", key.code);
382                                }
383                            }
384                        }
385                    }
386                    Event::Mouse(mouse_event) => {
387                        let size = terminal.size()?;
388                        let area = Rect::new(0, 0, size.width, size.height);
389                        let chunks = Layout::default()
390                            .direction(Direction::Vertical)
391                            .margin(2)
392                            .constraints([Constraint::Min(0)].as_ref())
393                            .split(area);
394                        let list_area = chunks[0];
395                        let title_row = list_area.y;
396                        let title_start = list_area.x + 2;
397                        let left_text = format!("Select target ({} found)", exs.len());
398                        let separator = " ┃ ";
399                        let right_text = "q to EXIT";
400                        let offset = (left_text.len() + separator.len()) as u16;
401                        let right_region_start = title_start + offset;
402                        let right_region_end = right_region_start + (right_text.len() as u16);
403
404                        match mouse_event.kind {
405                            MouseEventKind::ScrollDown => {
406                                let current = list_state.selected().unwrap_or(0);
407                                let new = std::cmp::min(current + 1, exs.len() - 1);
408                                list_state.select(Some(new));
409                            }
410                            MouseEventKind::ScrollUp => {
411                                let current = list_state.selected().unwrap_or(0);
412                                let new = if current == 0 { 0 } else { current - 1 };
413                                list_state.select(Some(new));
414                            }
415
416                            MouseEventKind::Moved => {
417                                if mouse_event.row == title_row {
418                                    exit_hover = mouse_event.column >= right_region_start
419                                        && mouse_event.column < right_region_end;
420                                } else {
421                                    exit_hover = false;
422                                    let inner_y = list_area.y + 1;
423                                    let inner_height = list_area.height.saturating_sub(2);
424                                    if mouse_event.column > list_area.x + 1
425                                        && mouse_event.column < list_area.x + list_area.width - 1
426                                        && mouse_event.row >= inner_y
427                                        && mouse_event.row < inner_y + inner_height
428                                    {
429                                        let index = (mouse_event.row - inner_y) as usize;
430                                        if index < exs.len() {
431                                            list_state.select(Some(index));
432                                        }
433                                    }
434                                }
435                            }
436                            MouseEventKind::Down(_) => {
437                                if mouse_event.row == title_row
438                                    && mouse_event.column >= right_region_start
439                                    && mouse_event.column < right_region_end
440                                {
441                                    println!("Exiting TUI mode...");
442                                    break 'main_loop;
443                                }
444                                let inner_y = list_area.y + 1;
445                                let inner_height = list_area.height.saturating_sub(2);
446                                if mouse_event.column > list_area.x + 1
447                                    && mouse_event.column < list_area.x + list_area.width - 1
448                                    && mouse_event.row >= inner_y
449                                    && mouse_event.row < inner_y + inner_height
450                                {
451                                    let index = (mouse_event.row - inner_y) as usize;
452                                    if index < exs.len() {
453                                        list_state.select(Some(index));
454                                        run_piece(
455                                            manager.clone(),
456                                            &exs.clone(),
457                                            index,
458                                            &history_path,
459                                            &mut run_history,
460                                            &mut terminal,
461                                            cli,
462                                        )?;
463                                        run_history_map =
464                                            crate::e_parser::read_run_history(&history_path);
465                                    }
466                                }
467                            }
468                            _ => {}
469                        }
470                    }
471                    _ => {}
472                }
473            }
474        }
475
476        disable_raw_mode()?;
477        let mut stdout = io::stdout();
478        execute!(
479            stdout,
480            LeaveAlternateScreen,
481            DisableMouseCapture,
482            Clear(ClearType::All)
483        )?;
484        terminal.show_cursor()?;
485        manager.generate_report(cli.gist);
486        Ok(())
487    }
488
489    /// Reinitializes the terminal: enables raw mode, enters the alternate screen,
490    /// enables mouse capture, clears the screen, and creates a new Terminal instance.
491    /// This function updates the provided terminal reference.
492    pub fn reinit_terminal(
493        terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
494    ) -> Result<(), Box<dyn Error>> {
495        enable_raw_mode()?;
496        let mut stdout = io::stdout();
497        execute!(
498            stdout,
499            EnterAlternateScreen,
500            EnableMouseCapture,
501            Clear(ClearType::All)
502        )?;
503        *terminal = Terminal::new(CrosstermBackend::new(stdout))?;
504        flush_input()?; // Clear any buffered input after reinitializing the terminal.
505        Ok(())
506    }
507
508    /// Runs the given example (or binary) target. It leaves TUI mode, spawns a cargo process,
509    /// installs a Ctrl+C handler to kill the process, waits for it to finish, updates history,
510    /// flushes stray input, and then reinitializes the terminal.
511    pub fn run_piece(
512        manager: Arc<crate::e_processmanager::ProcessManager>,
513        examples: &[CargoTarget],
514        index: usize,
515        history_path: &Path,
516        _run_history: &mut HashSet<String>,
517        terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
518        cli: &Cli,
519    ) -> Result<(), Box<dyn Error>> {
520        let target = &examples[index];
521        // Leave TUI mode before running the target.
522        disable_raw_mode()?;
523        execute!(
524            terminal.backend_mut(),
525            LeaveAlternateScreen,
526            crossterm::event::DisableMouseCapture
527        )?;
528        terminal.show_cursor()?;
529
530        let manifest_path = PathBuf::from(target.manifest_path.clone());
531        let builder =
532            CargoCommandBuilder::new(&target.name, &manifest_path, &cli.subcommand, cli.filter)
533                .with_target(target)
534                .with_required_features(&manifest_path, target)
535                .with_cli(cli);
536        let cmd = builder.build_command();
537
538        // Set current directory appropriately.
539        // if target.kind == TargetKind::ManifestTauri {
540        //     let manifest_dir = manifest_path.parent().expect("Expected parent directory");
541        //     cmd.current_dir(manifest_dir);
542        // } else if target.extended {
543        //     if let Some(dir) = manifest_path.parent() {
544        //         cmd.current_dir(dir);
545        //     }
546        // }
547
548        println!("Running command: {:?}", cmd);
549        // If the target is extended, we want to run it from its directory.
550        if target.extended {
551            Path::new(&manifest_path).parent().map(|p| p.to_owned())
552        } else {
553            None
554        };
555
556        // Before spawning, patch the manifest if needed.
557        let manifest_path_obj = Path::new(&manifest_path);
558        let backup = maybe_patch_manifest_for_run(manifest_path_obj)?;
559
560        // // // Build the command.
561        // // let mut cmd = Command::new("cargo");
562        // // cmd.args(&args);
563        // // if let Some(ref dir) = current_dir {
564        // //     cmd.current_dir(dir);
565        // // }
566        // // Convert command args into &str slices for spawn_cargo_process.
567        // // (Assuming spawn_cargo_process accepts a slice of &str.)
568        // let owned_args: Vec<String> = cmd
569        //     .get_args()
570        //     .map(|arg| arg.to_string_lossy().to_string())
571        //     .collect();
572        // // Now create a vector of &str references valid as long as `owned_args` is in scope:
573        // let args_ref: Vec<&str> = owned_args.iter().map(|s| s.as_str()).collect();
574
575        // // let args_ref: Vec<&str> = args.iter().map(|s| &**s).collect();
576        // let mut child = crate::e_runner::spawn_cargo_process(&args_ref)?;
577
578        let pid = Arc::new(builder).run(|_pid, handle| {
579            manager.register(handle);
580        })?;
581        // let ret=manager.wait(pid, None)?;
582        let handle = manager.get(pid).unwrap().clone();
583        let start_time = handle.lock().unwrap().start_time;
584        // let mut child = cmd.spawn()?;
585        // if cli.print_instruction {
586        //     println!("Process started. Press Ctrl+C to terminate or 'd' to detach...");
587        // }
588        let mut update_history = true;
589        let mut status_code: i32 = -255;
590        let mut detached = false;
591        let shared_child = handle.clone();
592        let system = Arc::new(Mutex::new(System::new_all()));
593        std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
594        // Refresh CPU usage to get actual value.
595        let mut system_guard = system.lock().unwrap();
596        system_guard.refresh_processes_specifics(
597            ProcessesToUpdate::All,
598            true,
599            ProcessRefreshKind::nothing().with_cpu(),
600        );
601        drop(system_guard);
602        // Now we enter an event loop, periodically checking if the child has exited
603        // and polling for keyboard input.
604        {
605            let mut stdout = std::io::stdout();
606            crossterm::execute!(stdout, crossterm::cursor::Hide)?;
607        }
608        let _cursor_guard = crate::e_processmanager::CursorGuard;
609
610        const SAMPLE_INTERVAL: usize = 10; // Update status every 10 iterations
611
612        let mut sample_count: usize = 0;
613        loop {
614            sample_count += 1;
615
616            // Check if the process has finished.
617            {
618                let mut child_guard = shared_child.lock().unwrap();
619                if let Some(status) = child_guard.child.try_wait()? {
620                    let status_code = status.code().unwrap_or(1);
621                    println!("Process exited with status: {}", status_code);
622                    break;
623                }
624            }
625            // // Check if the child process has finished.
626            if let Some(status) = handle.clone().lock().unwrap().child.try_wait()? {
627                status_code = status.code().unwrap_or(1);
628
629                println!("Process exited with status: {}", status_code);
630                // println!("HERE IS THE RESULT!{} {:?}",pid,manager.get(pid));
631                // manager.print_shortened_output();
632                manager.print_compact();
633                break;
634            }
635            // Poll for input events with a 100ms timeout.
636            if event::poll(Duration::from_millis(100))? {
637                if let Event::Key(key_event) = event::read()? {
638                    if key_event.code == KeyCode::Char('c')
639                        && key_event.modifiers.contains(event::KeyModifiers::CONTROL)
640                    {
641                        if cli.print_instruction {
642                            println!("Ctrl+C detected in event loop, killing process...");
643                        }
644                        shared_child.lock().expect("expected child").child.kill()?;
645                        update_history = false; // do not update history if cancelled
646                                                // Optionally, you can also wait for the child after killing.
647                        let status = shared_child
648                            .lock()
649                            .expect("shared child can't lock")
650                            .child
651                            .wait()?;
652                        status_code = status.code().unwrap_or(1);
653                        break;
654                    } else if key_event.code == KeyCode::Char('d') && key_event.modifiers.is_empty()
655                    {
656                        if cli.print_instruction {
657                            println!(
658                                "'d' pressed; detaching process. Process will continue running."
659                            );
660                        }
661                        detached = true;
662                        update_history = false;
663                        // Do not kill or wait on the child.
664                        // Break out of the loop immediately.
665                        // We can optionally leave the process running.
666                        status_code = 0;
667                        break;
668                    }
669                }
670            }
671
672            // Only update the status display every SAMPLE_INTERVAL iterations.
673            if sample_count % SAMPLE_INTERVAL == 0 {
674                // system.refresh_all();
675                let mut system_guard = system.lock().unwrap();
676                system_guard.refresh_processes_specifics(
677                    ProcessesToUpdate::All,
678                    true,
679                    ProcessRefreshKind::nothing().with_cpu(),
680                );
681                drop(system_guard);
682                // Refresh CPU usage to get actual value.
683                let status_display = ProcessManager::format_process_status(
684                    pid,
685                    Some(start_time),
686                    system.clone(),
687                    &target,
688                    (index + 1, examples.len()),
689                );
690                ProcessManager::update_status_line(&status_display, true).ok();
691            }
692        }
693        // Restore the manifest if it was patched.
694        if let Some(original) = backup {
695            fs::write(manifest_path_obj, original)?;
696        }
697        // Wrap the child process so that we can share it with our Ctrl+C handler.
698        // let child_arc = Arc::new(Mutex::new(child));
699        // let child_for_handler = Arc::clone(&child_arc);
700
701        // Set up a Ctrl+C handler to kill the spawned process.
702        // ctrlc::set_handler(move || {
703        // eprintln!("Ctrl+C pressed, terminating process...");
704        // if let Ok(mut child) = child_for_handler.lock() {
705        // let _ = child.kill();
706        // }
707        // })?;
708
709        // Wait for the process to finish.
710        // let status = child_arc.lock().unwrap().wait()?;
711        // println!("Process exited with status: {:?}", status.code());
712
713        if !detached {
714            // Only update run history if update_history is true and exit code is zero.
715            if update_history && status_code == 0 {
716                use std::io::Write;
717                let mut file = fs::OpenOptions::new()
718                    .create(true)
719                    .append(true)
720                    .open(history_path)?;
721                // Append a newline-separated entry.
722                writeln!(file, "{}", target.name)?;
723            }
724            // let message = if cli.print_exit_code {
725            //     format!("Exitcode {:?}. Press any key to continue...", status_code)
726            // } else {
727            //     "".to_string()
728            // };
729            // PROMPT let _ = crate::e_prompts::prompt(&message, cli.wait)?;
730        }
731
732        reinit_terminal(terminal)?; // Reinitialize the terminal after running the target.
733
734        // // Flush stray input events.
735        // while event::poll(std::time::Duration::from_millis(0))? {
736        //     let _ = event::read()?;
737        // }
738        // std::thread::sleep(std::time::Duration::from_millis(50));
739
740        // // // Reinitialize the terminal.
741        // enable_raw_mode()?;
742        // let mut stdout = io::stdout();
743        // execute!(
744        //     stdout,
745        //     EnterAlternateScreen,
746        //     crossterm::event::EnableMouseCapture,
747        //     Clear(ClearType::All)
748        // )?;
749        // *terminal = Terminal::new(CrosstermBackend::new(stdout))?;
750        Ok(())
751    }
752}