rusty_repl 0.3.0

REPL library with customisable prompts and clean terminal management.
Documentation
use crate::{KeywordStyle, repl::prompt::CleanPrompt};
use reedline::Prompt;
use std::sync::Arc;

/// Configuration for the REPL (Read-Eval-Print Loop).
///
/// `ReplConfig` defines how the REPL behaves — including its title,
/// the command-line prompt, and keyword styling preferences.
///
/// It uses a *builder-style API* for flexible and readable construction:
///
/// ```
/// use mycrate::{ReplConfig, KeywordStyle};
/// use mycrate::repl::prompt::MyPrompt;
///
/// let cfg = ReplConfig::new("Rusty Shell")
///     .with_prompt(MyPrompt::default())
///     .with_kw_style(KeywordStyle::default());
/// ```
///
/// The configuration stores its prompt behind an `Arc<dyn Prompt>`,
/// allowing it to be cloned and shared safely across threads or subsystems.
pub struct ReplConfig {
    /// REPL window title.
    title: String,

    /// The input prompt displayed to the user.
    ///
    /// Stored as an `Arc<dyn Prompt>` so multiple components can share it.
    prompt: Option<Arc<dyn Prompt>>,

    /// Optional keyword style used for syntax highlighting.
    kw_style: Option<KeywordStyle>,
}

impl Default for ReplConfig {
    /// Creates a default REPL configuration.
    ///
    /// The default title is `"Rusty REPL"`, the default prompt
    /// is [`CleanPrompt::default()`], and no keyword style is applied.
    fn default() -> Self {
        Self {
            title: "Rusty REPL".into(),
            prompt: Some(Arc::new(CleanPrompt::default())),
            kw_style: None,
        }
    }
}

impl ReplConfig {
    /// Creates a new configuration with a custom title.
    ///
    /// Other fields default to `None` until configured with
    /// [`with_prompt`](#method.with_prompt) or
    /// [`with_kw_style`](#method.with_kw_style).
    pub fn new(title: impl Into<String>) -> Self {
        Self {
            title: title.into(),
            prompt: None,
            kw_style: None,
        }
    }

    /// Sets the REPL’s input prompt.
    ///
    /// The prompt type must implement [`Prompt`] and have a `'static` lifetime,
    /// meaning it owns all its data and doesn’t contain borrowed references.
    ///
    /// # Example
    /// ```
    /// use mycrate::repl::prompt::MyPrompt;
    /// let cfg = ReplConfig::new("My REPL")
    ///     .with_prompt(MyPrompt::default());
    /// ```
    pub fn with_prompt<P: Prompt + 'static>(mut self, prompt: P) -> Self {
        self.prompt = Some(Arc::new(prompt));
        self
    }

    /// Sets the keyword style for syntax highlighting.
    pub fn with_kw_style(mut self, kw_style: KeywordStyle) -> Self {
        self.kw_style = Some(kw_style);
        self
    }

    /// Returns the configured REPL title.
    pub fn title(&self) -> &str {
        &self.title
    }

    /// Returns the configured prompt, if any.
    ///
    /// Clones the underlying `Arc` so the caller receives a new reference.
    pub fn prompt(&self) -> Option<Arc<dyn Prompt>> {
        self.prompt.clone()
    }

    /// Returns a reference to the keyword style, if set.
    pub fn kw_style(&self) -> Option<&KeywordStyle> {
        self.kw_style.as_ref()
    }
}