language_reporting/
lib.rs

1#![recursion_limit = "1024"]
2
3#[macro_use]
4extern crate render_tree;
5
6pub extern crate termcolor;
7
8#[cfg(test)]
9extern crate unindent;
10
11#[cfg(test)]
12extern crate pretty_env_logger;
13
14#[cfg(test)]
15extern crate term;
16
17#[cfg(test)]
18extern crate regex;
19
20use std::cmp::Ordering;
21use std::fmt;
22use std::str::FromStr;
23use termcolor::ColorChoice;
24use serde_derive::{Serialize, Deserialize};
25
26mod components;
27mod diagnostic;
28mod emitter;
29mod models;
30mod simple;
31mod span;
32
33pub use self::diagnostic::{Diagnostic, Label, LabelStyle};
34pub use self::emitter::{emit, format, Config, DefaultConfig};
35pub use self::render_tree::prelude::*;
36pub use self::render_tree::stylesheet::{Style, Stylesheet};
37pub use self::simple::{SimpleFile, SimpleReportingFiles, SimpleSpan};
38pub use self::span::{FileName, Location, ReportingFiles, ReportingSpan};
39pub use render_tree::macros::*;
40
41/// A severity level for diagnostic messages
42///
43/// These are ordered in the following way:
44///
45/// ```rust
46/// use language_reporting::Severity;
47///
48/// assert!(Severity::Bug > Severity::Error);
49/// assert!(Severity::Error > Severity::Warning);
50/// assert!(Severity::Warning > Severity::Note);
51/// assert!(Severity::Note > Severity::Help);
52/// ```
53#[derive(Copy, Clone, PartialEq, Hash, Debug, Serialize, Deserialize)]
54pub enum Severity {
55    /// An unexpected bug.
56    Bug,
57    /// An error.
58    Error,
59    /// A warning.
60    Warning,
61    /// A note.
62    Note,
63    /// A help message.
64    Help,
65}
66
67impl Severity {
68    /// We want bugs to be the maximum severity, errors next, etc...
69    fn to_cmp_int(self) -> u8 {
70        match self {
71            Severity::Bug => 5,
72            Severity::Error => 4,
73            Severity::Warning => 3,
74            Severity::Note => 2,
75            Severity::Help => 1,
76        }
77    }
78}
79
80impl PartialOrd for Severity {
81    fn partial_cmp(&self, other: &Severity) -> Option<Ordering> {
82        u8::partial_cmp(&self.to_cmp_int(), &other.to_cmp_int())
83    }
84}
85
86impl fmt::Display for Severity {
87    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88        self.to_str().fmt(f)
89    }
90}
91
92impl Severity {
93    /// A string that explains this diagnostic severity
94    pub fn to_str(self) -> &'static str {
95        match self {
96            Severity::Bug => "error: internal compiler error",
97            Severity::Error => "error",
98            Severity::Warning => "warning",
99            Severity::Note => "note",
100            Severity::Help => "help",
101        }
102    }
103}
104
105/// A command line argument that configures the coloring of the output
106///
107/// This can be used with command line argument parsers like `clap` or `structopt`.
108///
109/// # Example
110///
111/// ```rust
112/// extern crate language_reporting;
113/// #[macro_use]
114/// extern crate structopt;
115///
116/// use structopt::StructOpt;
117/// use termcolor::StandardStream;
118/// use language_reporting::ColorArg;
119///
120/// #[derive(Debug, StructOpt)]
121/// #[structopt(name = "groovey-app")]
122/// pub struct Opts {
123///     /// Configure coloring of output
124///     #[structopt(
125///         long = "color",
126///         parse(try_from_str),
127///         default_value = "auto",
128///         raw(possible_values = "ColorArg::VARIANTS", case_insensitive = "true")
129///     )]
130///     pub color: ColorArg,
131/// }
132///
133/// fn main() {
134///     let opts = Opts::from_args();
135///     let writer = StandardStream::stderr(opts.color.into());
136/// }
137/// ```
138#[derive(Copy, Clone, Debug, PartialEq, Eq)]
139pub struct ColorArg(pub ColorChoice);
140
141impl ColorArg {
142    /// Allowed values the argument
143    ///
144    /// This is useful for generating documentation via `clap` or `structopt`'s
145    /// `possible_values` configuration.
146    pub const VARIANTS: &'static [&'static str] = &["auto", "always", "ansi", "never"];
147}
148
149impl FromStr for ColorArg {
150    type Err = &'static str;
151
152    fn from_str(src: &str) -> Result<ColorArg, &'static str> {
153        match src {
154            _ if src.eq_ignore_ascii_case("auto") => Ok(ColorArg(ColorChoice::Auto)),
155            _ if src.eq_ignore_ascii_case("always") => Ok(ColorArg(ColorChoice::Always)),
156            _ if src.eq_ignore_ascii_case("ansi") => Ok(ColorArg(ColorChoice::AlwaysAnsi)),
157            _ if src.eq_ignore_ascii_case("never") => Ok(ColorArg(ColorChoice::Never)),
158            _ => Err("valid values: auto, always, ansi, never"),
159        }
160    }
161}
162
163impl Into<ColorChoice> for ColorArg {
164    fn into(self) -> ColorChoice {
165        self.0
166    }
167}