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