1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
mod colored;
mod non_colored;

pub use self::colored::Colored;
pub use self::non_colored::NonColored;
use core::{self, Context, ContextItem};
use core::errors::*;
use log;
use std::io::{self, Write};

pub trait LockableWrite
where
    Self: Sync + Send,
{
    fn open_new(&self) -> Self;

    fn lock<'a>(&'a self) -> Box<Write + 'a>;
}

impl LockableWrite for io::Stdout {
    fn open_new(&self) -> Self {
        io::stdout()
    }

    fn lock<'a>(&'a self) -> Box<Write + 'a> {
        Box::new(self.lock())
    }
}

pub trait Output {
    fn lock<'a>(&'a self) -> Box<Write + 'a>;

    fn handle_context(&self, ctx: &Context) -> Result<()> {
        let errors = ctx.errors()?;

        for e in errors.iter() {
            match *e {
                ContextItem::ErrorPos(ref pos, ref message) => {
                    self.print_error(message.as_str(), pos)?;
                }
                ContextItem::InfoPos(ref pos, ref message) => {
                    self.print_info(message.as_str(), pos)?;
                }
            }
        }

        Ok(())
    }

    /// Handle any errors.
    fn handle_error(&self, e: &Error) -> Result<()> {
        for e in e.causes() {
            if let Some(pos) = e.pos() {
                self.print_error(e.message(), pos)?;
            } else {
                self.error(e)?;
            }

            for e in e.suppressed() {
                self.handle_error(e)?;
            }
        }

        Ok(())
    }

    fn error(&self, e: &Error) -> Result<()> {
        let mut o = self.lock();

        if let Some(p) = e.pos() {
            self.print_error(e.message(), p)?;
        } else {
            writeln!(o, "{}", self.error_message(e.message())?)?;
        }

        for e in e.causes().skip(1) {
            let msg = self.error_message(format!("  caused by: {}", e.message()).as_str())?;

            if let Some(p) = e.pos() {
                self.print_error(msg.as_str(), p)?;
            } else {
                writeln!(o, "{}", msg.as_str())?;
            }
        }

        if let Some(backtrace) = e.backtrace() {
            writeln!(o, "{:?}", backtrace)?;
        }

        Ok(())
    }

    fn error_message(&self, m: &str) -> Result<String> {
        Ok(m.to_string())
    }

    fn logger(&self) -> Box<log::Log + 'static>;

    fn print(&self, m: &str) -> Result<()>;

    fn print_info(&self, m: &str, p: &core::ErrorPos) -> Result<()>;

    fn print_error(&self, m: &str, p: &core::ErrorPos) -> Result<()>;
}