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        let mut run_history_map = crate::e_parser::read_run_history(&history_path);
123
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            if event::poll(Duration::from_millis(200))? {
196                match event::read()? {
197                    Event::Key(key) => {
198                        // Only process key-press events.
199                        if key.kind == KeyEventKind::Press {
200                            // Check if we might be starting an escape sequence for an arrow key.
201                            if key.code == KeyCode::Esc {
202                                // Try to collect the rest of the sequence.
203                                if let Some(arrow_code) = try_collect_arrow_sequence()? {
204                                    match arrow_code {
205                                        KeyCode::Up => {
206                                            let new_index = match list_state.selected() {
207                                                Some(0) | None => 0,
208                                                Some(i) => i.saturating_sub(1),
209                                            };
210                                            list_state.select(Some(new_index));
211                                        }
212                                        KeyCode::Down => {
213                                            let new_index = match list_state.selected() {
214                                                Some(i) if i >= exs.len() - 1 => i,
215                                                Some(i) => i + 1,
216                                                None => 0,
217                                            };
218                                            list_state.select(Some(new_index));
219                                        }
220                                        KeyCode::Left => {
221                                            // Handle left arrow if needed.
222                                        }
223                                        KeyCode::Right => {
224                                            // Handle right arrow if needed.
225                                        }
226                                        _ => {}
227                                    }
228                                    // We've handled the arrow, so skip further processing.
229                                    continue;
230                                } else {
231                                    // No follow-up sequence—treat it as a standalone Esc if needed.
232                                    // For example, you might decide not to exit on Esc now.
233                                    // println!("Standalone Esc detected (ignoring).");
234                                    continue;
235                                }
236                            }
237                            match key.code {
238                                KeyCode::Char('q') => {
239                                    // Exit the TUI mode when 'q' is pressed.
240                                    println!("Exiting TUI mode...");
241                                    break 'main_loop;
242                                }
243                                KeyCode::Down => {
244                                    let i = match list_state.selected() {
245                                        Some(i) if i >= exs.len() - 1 => i,
246                                        Some(i) => i + 1,
247                                        None => 0,
248                                    };
249                                    list_state.select(Some(i));
250                                    thread::sleep(Duration::from_millis(50));
251                                }
252                                KeyCode::Up => {
253                                    let i = match list_state.selected() {
254                                        Some(0) | None => 0,
255                                        Some(i) => i - 1,
256                                    };
257                                    list_state.select(Some(i));
258                                    thread::sleep(Duration::from_millis(50));
259                                }
260                                KeyCode::PageDown => {
261                                    // Compute page size based on the terminal's current height.
262                                    let page = terminal
263                                        .size()
264                                        .map(|r| r.height.saturating_sub(4)) // subtract borders/margins; adjust as needed
265                                        .unwrap_or(5)
266                                        as usize;
267                                    let current = list_state.selected().unwrap_or(0);
268                                    let new = std::cmp::min(current + page, exs.len() - 1);
269                                    list_state.select(Some(new));
270                                }
271                                KeyCode::PageUp => {
272                                    let page = terminal
273                                        .size()
274                                        .map(|r| r.height.saturating_sub(4))
275                                        .unwrap_or(5)
276                                        as usize;
277                                    let current = list_state.selected().unwrap_or(0);
278                                    let new = current.saturating_sub(page);
279                                    list_state.select(Some(new));
280                                }
281                                KeyCode::Char('b') => {
282                                    if let Some(selected) = list_state.selected() {
283                                        let sample = &examples[selected];
284                                        // Run bacon in detached mode. Extra arguments can be added if needed.
285                                        if let Err(e) = e_bacon::run_bacon(sample, &Vec::new()) {
286                                            eprintln!("Error running bacon: {}", e);
287                                        } else {
288                                            println!("Bacon launched for sample: {}", sample.name);
289                                        }
290                                        reinit_terminal(&mut terminal)?;
291                                    }
292                                }
293                                KeyCode::Char('e') => {
294                                    if let Some(selected) = list_state.selected() {
295                                        // Disable raw mode for debug printing.
296                                        crossterm::terminal::disable_raw_mode()?;
297                                        crossterm::execute!(
298                                            std::io::stdout(),
299                                            crossterm::terminal::LeaveAlternateScreen
300                                        )?;
301                                        // When 'e' is pressed, attempt to open the sample in VSCode.
302                                        let sample = &exs[selected];
303                                        println!(
304                                            "Opening VSCode for path: {}",
305                                            sample
306                                                .manifest_path
307                                                .to_str()
308                                                .unwrap_or_default()
309                                                .to_owned()
310                                        );
311                                        // Here we block on the asynchronous open_vscode call.
312                                        // futures::executor::block_on(open_vscode(Path::new(&sample.manifest_path)));
313                                        futures::executor::block_on(
314                                            e_findmain::open_vscode_for_sample(sample),
315                                        );
316                                        std::thread::sleep(std::time::Duration::from_secs(5));
317                                        reinit_terminal(&mut terminal)?;
318                                    }
319                                }
320                                KeyCode::Char('i') => {
321                                    if let Some(selected) = list_state.selected() {
322                                        // Disable raw mode for debug printing.
323                                        crossterm::terminal::disable_raw_mode()?;
324                                        crossterm::execute!(
325                                            std::io::stdout(),
326                                            crossterm::terminal::LeaveAlternateScreen
327                                        )?;
328                                        let target = &exs[selected];
329                                        println!("Target: {:?}", target);
330                                        futures::executor::block_on(
331                                            crate::e_runner::open_ai_summarize_for_target(target),
332                                        );
333                                        prompt_line("", 120).ok();
334                                        reinit_terminal(&mut terminal)?;
335                                    }
336                                }
337                                // KeyCode::Char('v') => {
338                                //     if let Some(selected) = list_state.selected() {
339                                //         // Disable raw mode for debug printing.
340                                //         crossterm::terminal::disable_raw_mode()?;
341                                //         crossterm::execute!(
342                                //             std::io::stdout(),
343                                //             crossterm::terminal::LeaveAlternateScreen
344                                //         )?;
345                                //         // When 'e' is pressed, attempt to open the sample in VSCode.
346                                //         let sample = &examples[selected];
347                                //         println!("Opening VIM for path: {}", sample.manifest_path);
348                                //         // Here we block on the asynchronous open_vscode call.
349                                //         // futures::executor::block_on(open_vscode(Path::new(&sample.manifest_path)));
350                                //         e_findmain::open_vim_for_sample(sample);
351                                //         std::thread::sleep(std::time::Duration::from_secs(5));
352                                //         reinit_terminal(&mut terminal)?;
353                                //     }
354                                // }
355                                KeyCode::Enter => {
356                                    if let Some(selected) = list_state.selected() {
357                                        run_piece(
358                                            &exs,
359                                            selected,
360                                            &history_path,
361                                            &mut run_history,
362                                            &mut terminal,
363                                            cli,
364                                        )?;
365                                        run_history_map =
366                                            crate::e_parser::read_run_history(&history_path);
367                                        reinit_terminal(&mut terminal)?;
368                                    }
369                                }
370                                _ => {
371                                    //println!("Unhandled key event: {:?}", key.code);
372                                }
373                            }
374                        }
375                    }
376                    Event::Mouse(mouse_event) => {
377                        let size = terminal.size()?;
378                        let area = Rect::new(0, 0, size.width, size.height);
379                        let chunks = Layout::default()
380                            .direction(Direction::Vertical)
381                            .margin(2)
382                            .constraints([Constraint::Min(0)].as_ref())
383                            .split(area);
384                        let list_area = chunks[0];
385                        let title_row = list_area.y;
386                        let title_start = list_area.x + 2;
387                        let left_text = format!("Select target ({} found)", exs.len());
388                        let separator = " ┃ ";
389                        let right_text = "q to EXIT";
390                        let offset = (left_text.len() + separator.len()) as u16;
391                        let right_region_start = title_start + offset;
392                        let right_region_end = right_region_start + (right_text.len() as u16);
393
394                        match mouse_event.kind {
395                            MouseEventKind::ScrollDown => {
396                                let current = list_state.selected().unwrap_or(0);
397                                let new = std::cmp::min(current + 1, exs.len() - 1);
398                                list_state.select(Some(new));
399                            }
400                            MouseEventKind::ScrollUp => {
401                                let current = list_state.selected().unwrap_or(0);
402                                let new = if current == 0 { 0 } else { current - 1 };
403                                list_state.select(Some(new));
404                            }
405
406                            MouseEventKind::Moved => {
407                                if mouse_event.row == title_row {
408                                    exit_hover = mouse_event.column >= right_region_start
409                                        && mouse_event.column < right_region_end;
410                                } else {
411                                    exit_hover = false;
412                                    let inner_y = list_area.y + 1;
413                                    let inner_height = list_area.height.saturating_sub(2);
414                                    if mouse_event.column > list_area.x + 1
415                                        && mouse_event.column < list_area.x + list_area.width - 1
416                                        && mouse_event.row >= inner_y
417                                        && mouse_event.row < inner_y + inner_height
418                                    {
419                                        let index = (mouse_event.row - inner_y) as usize;
420                                        if index < exs.len() {
421                                            list_state.select(Some(index));
422                                        }
423                                    }
424                                }
425                            }
426                            MouseEventKind::Down(_) => {
427                                if mouse_event.row == title_row
428                                    && mouse_event.column >= right_region_start
429                                    && mouse_event.column < right_region_end
430                                {
431                                    println!("Exiting TUI mode...");
432                                    break 'main_loop;
433                                }
434                                let inner_y = list_area.y + 1;
435                                let inner_height = list_area.height.saturating_sub(2);
436                                if mouse_event.column > list_area.x + 1
437                                    && mouse_event.column < list_area.x + list_area.width - 1
438                                    && mouse_event.row >= inner_y
439                                    && mouse_event.row < inner_y + inner_height
440                                {
441                                    let index = (mouse_event.row - inner_y) as usize;
442                                    if index < exs.len() {
443                                        list_state.select(Some(index));
444                                        run_piece(
445                                            &exs.clone(),
446                                            index,
447                                            &history_path,
448                                            &mut run_history,
449                                            &mut terminal,
450                                            cli,
451                                        )?;
452                                        run_history_map =
453                                            crate::e_parser::read_run_history(&history_path);
454                                    }
455                                }
456                            }
457                            _ => {}
458                        }
459                    }
460                    _ => {}
461                }
462            }
463        }
464
465        disable_raw_mode()?;
466        let mut stdout = io::stdout();
467        execute!(
468            stdout,
469            LeaveAlternateScreen,
470            DisableMouseCapture,
471            Clear(ClearType::All)
472        )?;
473        terminal.show_cursor()?;
474        Ok(())
475    }
476
477    /// Reinitializes the terminal: enables raw mode, enters the alternate screen,
478    /// enables mouse capture, clears the screen, and creates a new Terminal instance.
479    /// This function updates the provided terminal reference.
480    pub fn reinit_terminal(
481        terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
482    ) -> Result<(), Box<dyn Error>> {
483        enable_raw_mode()?;
484        let mut stdout = io::stdout();
485        execute!(
486            stdout,
487            EnterAlternateScreen,
488            EnableMouseCapture,
489            Clear(ClearType::All)
490        )?;
491        *terminal = Terminal::new(CrosstermBackend::new(stdout))?;
492        flush_input()?; // Clear any buffered input after reinitializing the terminal.
493        Ok(())
494    }
495
496    /// Runs the given example (or binary) target. It leaves TUI mode, spawns a cargo process,
497    /// installs a Ctrl+C handler to kill the process, waits for it to finish, updates history,
498    /// flushes stray input, and then reinitializes the terminal.
499    pub fn run_piece(
500        examples: &[CargoTarget],
501        index: usize,
502        history_path: &Path,
503        _run_history: &mut HashSet<String>,
504        terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
505        cli: &Cli,
506    ) -> Result<(), Box<dyn Error>> {
507        let target = &examples[index];
508        // Leave TUI mode before running the target.
509        disable_raw_mode()?;
510        execute!(
511            terminal.backend_mut(),
512            LeaveAlternateScreen,
513            crossterm::event::DisableMouseCapture
514        )?;
515        terminal.show_cursor()?;
516
517        let manifest_path = PathBuf::from(target.manifest_path.clone());
518        let builder = CargoCommandBuilder::new()
519            .with_target(target)
520            .with_required_features(&manifest_path, target)
521            .with_cli(cli);
522        let mut cmd = builder.build_command();
523
524        // Set current directory appropriately.
525        // if target.kind == TargetKind::ManifestTauri {
526        //     let manifest_dir = manifest_path.parent().expect("Expected parent directory");
527        //     cmd.current_dir(manifest_dir);
528        // } else if target.extended {
529        //     if let Some(dir) = manifest_path.parent() {
530        //         cmd.current_dir(dir);
531        //     }
532        // }
533
534        println!("Running command: {:?}", cmd);
535        // If the target is extended, we want to run it from its directory.
536        if target.extended {
537            Path::new(&manifest_path).parent().map(|p| p.to_owned())
538        } else {
539            None
540        };
541
542        // Before spawning, patch the manifest if needed.
543        let manifest_path_obj = Path::new(&manifest_path);
544        let backup = maybe_patch_manifest_for_run(manifest_path_obj)?;
545
546        // // // Build the command.
547        // // let mut cmd = Command::new("cargo");
548        // // cmd.args(&args);
549        // // if let Some(ref dir) = current_dir {
550        // //     cmd.current_dir(dir);
551        // // }
552        // // Convert command args into &str slices for spawn_cargo_process.
553        // // (Assuming spawn_cargo_process accepts a slice of &str.)
554        // let owned_args: Vec<String> = cmd
555        //     .get_args()
556        //     .map(|arg| arg.to_string_lossy().to_string())
557        //     .collect();
558        // // Now create a vector of &str references valid as long as `owned_args` is in scope:
559        // let args_ref: Vec<&str> = owned_args.iter().map(|s| s.as_str()).collect();
560
561        // // let args_ref: Vec<&str> = args.iter().map(|s| &**s).collect();
562        // let mut child = crate::e_runner::spawn_cargo_process(&args_ref)?;
563
564        let mut child = cmd.spawn()?;
565        if cli.print_instruction {
566            println!("Process started. Press Ctrl+C to terminate or 'd' to detach...");
567        }
568        let mut update_history = true;
569        let status_code: i32;
570        let mut detached = false;
571        // Now we enter an event loop, periodically checking if the child has exited
572        // and polling for keyboard input.
573        loop {
574            // // Check if the child process has finished.
575            if let Some(status) = child.try_wait()? {
576                status_code = status.code().unwrap_or(1);
577
578                println!("Process exited with status: {}", status_code);
579                break;
580            }
581            // Poll for input events with a 100ms timeout.
582            if event::poll(Duration::from_millis(100))? {
583                if let Event::Key(key_event) = event::read()? {
584                    if key_event.code == KeyCode::Char('c')
585                        && key_event.modifiers.contains(event::KeyModifiers::CONTROL)
586                    {
587                        if cli.print_instruction {
588                            println!("Ctrl+C detected in event loop, killing process...");
589                        }
590                        child.kill()?;
591                        update_history = false; // do not update history if cancelled
592                                                // Optionally, you can also wait for the child after killing.
593                        let status = child.wait()?;
594                        status_code = status.code().unwrap_or(1);
595                        break;
596                    } else if key_event.code == KeyCode::Char('d') && key_event.modifiers.is_empty()
597                    {
598                        if cli.print_instruction {
599                            println!(
600                                "'d' pressed; detaching process. Process will continue running."
601                            );
602                        }
603                        detached = true;
604                        update_history = false;
605                        // Do not kill or wait on the child.
606                        // Break out of the loop immediately.
607                        // We can optionally leave the process running.
608                        status_code = 0;
609                        break;
610                    }
611                }
612            }
613        }
614        // Restore the manifest if it was patched.
615        if let Some(original) = backup {
616            fs::write(manifest_path_obj, original)?;
617        }
618        // Wrap the child process so that we can share it with our Ctrl+C handler.
619        // let child_arc = Arc::new(Mutex::new(child));
620        // let child_for_handler = Arc::clone(&child_arc);
621
622        // Set up a Ctrl+C handler to kill the spawned process.
623        // ctrlc::set_handler(move || {
624        // eprintln!("Ctrl+C pressed, terminating process...");
625        // if let Ok(mut child) = child_for_handler.lock() {
626        // let _ = child.kill();
627        // }
628        // })?;
629
630        // Wait for the process to finish.
631        // let status = child_arc.lock().unwrap().wait()?;
632        // println!("Process exited with status: {:?}", status.code());
633
634        if !detached {
635            // Only update run history if update_history is true and exit code is zero.
636            if update_history && status_code == 0 {
637                use std::io::Write;
638                let mut file = fs::OpenOptions::new()
639                    .create(true)
640                    .append(true)
641                    .open(history_path)?;
642                // Append a newline-separated entry.
643                writeln!(file, "{}", target.name)?;
644            }
645            let message = if cli.print_exit_code {
646                format!("Exitcode {:?}. Press any key to continue...", status_code)
647            } else {
648                "".to_string()
649            };
650            let _ = crate::e_prompts::prompt(&message, cli.wait)?;
651        }
652
653        reinit_terminal(terminal)?; // Reinitialize the terminal after running the target.
654
655        // // Flush stray input events.
656        // while event::poll(std::time::Duration::from_millis(0))? {
657        //     let _ = event::read()?;
658        // }
659        // std::thread::sleep(std::time::Duration::from_millis(50));
660
661        // // // Reinitialize the terminal.
662        // enable_raw_mode()?;
663        // let mut stdout = io::stdout();
664        // execute!(
665        //     stdout,
666        //     EnterAlternateScreen,
667        //     crossterm::event::EnableMouseCapture,
668        //     Clear(ClearType::All)
669        // )?;
670        // *terminal = Terminal::new(CrosstermBackend::new(stdout))?;
671        Ok(())
672    }
673}