Skip to main content

cc_switch_lib/cli/interactive/
mod.rs

1use std::io::IsTerminal;
2
3use crate::app_config::AppType;
4use crate::error::AppError;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7enum InteractivePath {
8    Ratatui,
9}
10
11fn decide_interactive_path(
12    legacy_tui_requested: bool,
13    stdin_is_tty: bool,
14    stdout_is_tty: bool,
15) -> Result<InteractivePath, AppError> {
16    if legacy_tui_requested {
17        return Err(AppError::Message(
18            crate::cli::i18n::texts::interactive_legacy_tui_removed().to_string(),
19        ));
20    }
21
22    if !stdin_is_tty || !stdout_is_tty {
23        return Err(AppError::Message(
24            crate::cli::i18n::texts::interactive_requires_tty().to_string(),
25        ));
26    }
27
28    Ok(InteractivePath::Ratatui)
29}
30
31pub fn run(app: Option<AppType>) -> Result<(), AppError> {
32    let path = decide_interactive_path(
33        std::env::var("CC_SWITCH_LEGACY_TUI").ok().as_deref() == Some("1"),
34        std::io::stdin().is_terminal(),
35        std::io::stdout().is_terminal(),
36    )?;
37
38    match path {
39        InteractivePath::Ratatui => crate::cli::tui::run(app),
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::{decide_interactive_path, InteractivePath};
46    use crate::cli::i18n::texts;
47    use crate::error::AppError;
48
49    #[test]
50    fn non_tty_returns_direct_tty_error() {
51        let err = decide_interactive_path(false, true, false)
52            .expect_err("non-tty interactive mode should fail fast");
53
54        match err {
55            AppError::Message(message) => {
56                assert_eq!(message, texts::interactive_requires_tty());
57            }
58            other => panic!("unexpected error variant: {other:?}"),
59        }
60    }
61
62    #[test]
63    fn legacy_env_flag_returns_removed_error() {
64        let err = decide_interactive_path(true, true, true)
65            .expect_err("legacy env flag should no longer enable removed tui");
66
67        match err {
68            AppError::Message(message) => {
69                assert_eq!(message, texts::interactive_legacy_tui_removed());
70            }
71            other => panic!("unexpected error variant: {other:?}"),
72        }
73    }
74
75    #[test]
76    fn tty_without_legacy_flag_uses_new_tui() {
77        let path = decide_interactive_path(false, true, true)
78            .expect("tty interactive mode should enter ratatui");
79
80        assert_eq!(path, InteractivePath::Ratatui);
81    }
82}