seam

Symbolic-Expressions As Markup.
git clone git://git.knutsen.co/seam
Log | Files | Refs | README | LICENSE

mod.rs (3129B)


use crate::parse::tokens::Site;
use std::{convert, fmt, error::Error};

use colored::*;

/// Error type for specific errors with generating
/// each type of markup.
#[derive(Debug, Clone)]
pub struct GenerationError {
    pub markup : String,
    pub message : String,
    pub site : Site
}

impl GenerationError {
    /// Create a new error given the ML, the message, and the site.
    pub fn new(ml : &str, msg : &str, site : &Site) -> Self {
        Self {
            markup: ml.to_owned(),
            message: msg.to_owned(),
            site: site.to_owned()
        }
    }
    /// When an error cannot be given a location,
    /// or exact point of failure.
    pub fn unknown(ml : &str) -> Self {
        Self {
            markup: ml.to_owned(),
            message: String::from("Unknown generation error (bug)."),
            site: Site::fake()
        }
    }
}

/// Implement fmt::Display for user-facing error output.
impl fmt::Display for GenerationError {
    fn fmt(&self, f : &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}",
            format!("[{}] Error Generating {} {}",
                "**".red().bold(),
                self.markup.bold(), self.site).white(),
            self.message)
    }
}

/// Implements std::error::Error.
impl Error for GenerationError { }

/// An fmt::Error can be cast to an equally horribly
/// ambiguous GenerationError.
impl convert::From<fmt::Error> for GenerationError {
    fn from(_ : fmt::Error) -> Self {
        Self {
            markup: String::from("Unknown"),
            message: String::from(
                "Unknown error while writing to format buffer"),
            site: Site::fake()
        }
    }
}

pub type Formatter<'a> = &'a mut dyn fmt::Write;

/// Trait for all structs that can generate specific markup
/// for the s-expression tree.
pub trait MarkupDisplay {
    // Required definitions:
    /// Similar to fmt in Display/Debug traits, takes in a
    /// mutable writable buffer, returns success or a specifc
    /// error while generating the markup.
    fn generate(&self, buf : Formatter)
        -> Result<(), GenerationError>;
    /// Documentises the input, that's to say, it adds any
    /// extra meta-information to the generated markup, if
    /// the s-expressions your wrote ommited it.
    /// e.g. All XML gets a `<?xml ... ?>` tag added to it.
    fn document(&self) -> Result<String, GenerationError>;
    // Default definitions:
    /// Directly converts the s-expressions into a string
    /// containing the markup, unless there was an error.
    fn display(&self) -> Result<String, GenerationError> {
        let mut buf = String::new();
        self.generate(&mut buf)?;
        Ok(buf)
    }
}

/// Automatically implement fmt::Display as a wrapper around
/// MarkupDisplay::generate, but throws away the useful error message.
impl fmt::Display for dyn MarkupDisplay {
    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
        self.generate(f).map_err(|_| fmt::Error)
    }
}
/// XML generation.
pub mod xml;

/// HTML5 CSS generation.
pub mod css;
/// HTML5 HTML generation.
pub mod html;