1use crate::{impl_clone_box, CloneBox, parse::tokens::Site};
2use std::{convert, error::Error, fmt::{self, Debug}};
3
4use colored::*;
5use unicode_width::UnicodeWidthStr;
6
7#[derive(Debug, Clone)]
10pub struct GenerationError<'a> {
11 pub markup: &'static str,
12 pub message: String,
13 pub site: Site<'a>,
14}
15
16impl<'a> GenerationError<'a> {
17 pub fn new(ml: &'static str, msg: &str, site: &Site<'a>) -> Self {
19 Self {
20 markup: ml,
21 message: msg.to_owned(),
22 site: site.to_owned(),
23 }
24 }
25}
26
27impl<'a> fmt::Display for GenerationError<'a> {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 let line_prefix = format!(" {} |", self.site.line);
31 let line_view = self.site.line_slice();
32 writeln!(f, "{} {}", line_prefix, line_view)?;
33 writeln!(f, "{:>prefix_offset$} {:~>text_offset$}{:^>length$}", "|", "", "",
34 prefix_offset=UnicodeWidthStr::width(line_prefix.as_str()),
35 text_offset=self.site.line_column() - 1,
36 length=self.site.width())?;
37 write!(f, "{}: {}",
38 format!("[{}] Error Generating {} ({}:{}:{})",
39 "**".red().bold(),
40 self.markup.bold(),
41 self.site.source,
42 self.site.line,
43 self.site.line_column(),
44 ).black(),
45 self.message)
46 }
47}
48
49impl<'a> Error for GenerationError<'a> { }
51
52impl<'a> From<std::io::Error> for GenerationError<'a> {
54 fn from(e: std::io::Error) -> Self {
55 Self {
56 markup: "<markup>",
57 message: format!("IO error: {}", e),
58 site: Site::unknown(),
59 }
60 }
61}
62
63impl<'a> convert::From<fmt::Error> for GenerationError<'a> {
66 fn from(e: fmt::Error) -> Self {
67 Self {
68 markup: "<markup>",
69 message: format!("Format buffer error: {}", e),
70 site: Site::unknown(),
71 }
72 }
73}
74
75pub type Formatter<'a> = &'a mut dyn fmt::Write;
76
77pub trait MarkupFormatter: Debug + CloneBox {
80 fn generate(&self, buf: Formatter) -> Result<(), GenerationError>;
85 fn document(&self) -> Result<String, GenerationError>;
90 fn display(&self) -> Result<String, GenerationError> {
94 let mut buf = String::new();
95 self.generate(&mut buf)?;
96 Ok(buf)
97 }
98}
99
100impl_clone_box! { 'a; dyn MarkupFormatter + 'a}
101
102impl fmt::Display for dyn MarkupFormatter {
105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106 self.generate(f).map_err(|_| fmt::Error)
107 }
108}
109
110pub fn escape_xml(string: &str) -> String {
117 let mut bytes = string.bytes();
118 let mut byte_builder: Vec<u8> = Vec::with_capacity(bytes.len());
119 while let Some(byte) = bytes.next() {
120 match byte {
121 b'<' => byte_builder.extend(b"<"),
122 b'>' => byte_builder.extend(b">"),
123 b'"' => byte_builder.extend(b"""),
124 b'\'' => byte_builder.extend(b"'"),
125 b'&' => byte_builder.extend(b"&"),
126 _ => byte_builder.push(byte)
127 }
128 }
129 unsafe {
130 String::from_utf8_unchecked(byte_builder)
131 }
132}
133
134pub mod sexp;
136pub mod text;
138pub mod xml;
140pub mod css;
142pub mod html;