termcinema-cli 0.1.0

🎬 Animated terminal-to-SVG renderer CLI for the termcinema project
Documentation
use crate::args::CliArgs;
use crate::utils::stdin_has_data;
use anyhow::{Result, anyhow, bail};
use std::fs::read_to_string;
use std::io::{Read, stdin};

/// Load input content and detect whether script mode should be used.
///
/// Priority order:
/// 1. `--input`      → treated as raw single-frame plain text
/// 2. `--script`     → loads a multi-frame structured script file
/// 3. Piped `stdin`  → treated as plain text
///
/// Returns:
/// - `String` → content to render
/// - `bool`   → `true` if script mode is active (from `--script`)
///
/// # Errors
/// - If more than one source is specified at once
/// - If the script file cannot be read
/// - If no input source is provided
pub(crate) fn load_input(args: &CliArgs) -> Result<(String, bool)> {
    let has_stdin = stdin_has_data();
    let has_input = args.input.is_some();
    let has_script = args.script.is_some();

    if has_input && has_script {
        bail!("❌ Cannot use both --input and --script at the same time.");
    }
    if has_stdin && has_input {
        bail!("❌ Cannot use both stdin and --input at the same time.");
    }
    if has_stdin && has_script {
        bail!("❌ Cannot use both stdin and --script at the same time.");
    }

    if let Some(s) = &args.input {
        Ok((s.clone(), false))
    } else if let Some(path) = &args.script {
        let content = read_to_string(path)
            .map_err(|_| anyhow!("Failed to read script file: {}", path.display()))?;
        Ok((content, true))
    } else if has_stdin {
        let mut buf = String::new();
        stdin().read_to_string(&mut buf)?;
        Ok((buf, false))
    } else {
        bail!("❌ No input source detected. Please use --input, --script, or provide piped stdin.");
    }
}