Inscribe 0.0.3

A markdown preprocessor that executes code fences and embeds their output.
//! Defines configuration structures and default settings for language runners.
//!
//! This module contains the `Runner` struct, which specifies how to execute
//! code for a particular language, and the `default_runners` function, which
//! provides a pre-configured map of common languages to their runners.

use std::collections::HashMap;

/// A constant for the delimiter used to separate outputs from different code blocks.
///
/// This unique string is printed by the runner's `delimiter_command` between
/// each code snippet. This allows the engine to split the combined stdout of a
/// batch execution back into individual results for each code block.
pub const DELIMITER: &str = "__INSCRIBE_DELIMITER_FINAL__";

/// Defines the configuration for a language runner.
///
/// It holds the necessary commands to execute a script and to print a delimiter
/// for separating outputs in batch processing.
/// It must derive Hash and Eq to be used as a key in the execution batch map.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Runner {
    /// The base command to execute (e.g., "python -u", "bash").
    /// This string will be split by whitespace to separate the command from its arguments.
    pub command: String,
    /// The exact, language-specific code snippet to print the stream delimiter.
    /// This is crucial for batching multiple code blocks into a single execution.
    pub delimiter_command: String,
}

/// Provides a map of language names to their default runner configurations.
///
/// This function is the source of truth for built-in language support.
/// It includes configurations for common scripting languages like Python, Bash,
/// and Node.js.
pub fn default_runners() -> HashMap<String, Runner> {
    let mut runners = HashMap::new();

    // Python: `-u` flag is used for unbuffered binary stdout and stderr.
    runners.insert(
        "python".to_string(),
        Runner {
            command: "python -u".to_string(),
            delimiter_command: format!("import sys;print('{}');sys.stdout.flush()", DELIMITER),
        },
    );

    // Bash: A standard shell, straightforward execution.
    runners.insert(
        "bash".to_string(),
        Runner {
            command: "bash".to_string(),
            delimiter_command: format!("echo '{}'", DELIMITER),
        },
    );

    // JavaScript/Node: Both "javascript" and "node" map to the Node.js runtime.
    runners.insert(
        "javascript".to_string(),
        Runner {
            command: "node".to_string(),
            delimiter_command: format!("console.log('{}')", DELIMITER),
        },
    );
    runners.insert(
        "node".to_string(),
        Runner {
            command: "node".to_string(),
            delimiter_command: format!("console.log('{}')", DELIMITER),
        },
    );

    // Ruby: Standard execution.
    runners.insert(
        "ruby".to_string(),
        Runner {
            command: "ruby".to_string(),
            delimiter_command: format!("puts '{}'", DELIMITER),
        },
    );

    // Use conditional compilation for platform-specific shell commands.
    #[cfg(unix)]
    runners.insert(
        "sh".to_string(),
        Runner {
            command: "sh".to_string(),
            delimiter_command: format!("echo '{}'", DELIMITER),
        },
    );

    #[cfg(windows)]
    runners.insert(
        "sh".to_string(),
        Runner {
            command: "cmd /C".to_string(),
            delimiter_command: format!("echo {}", DELIMITER),
        },
    );

    runners
}