1 //! Terminal back-end for emitting diagnostics.
2
3 use std::str::FromStr;
4 use termcolor::{ColorChoice, WriteColor};
5
6 use crate::diagnostic::Diagnostic;
7 use crate::files::Files;
8
9 mod config;
10 mod renderer;
11 mod views;
12
13 pub use termcolor;
14
15 pub use self::config::{Chars, Config, DisplayStyle, Styles};
16
17 /// A command line argument that configures the coloring of the output.
18 ///
19 /// This can be used with command line argument parsers like [`clap`] or [`structopt`].
20 ///
21 /// [`clap`]: https://crates.io/crates/clap
22 /// [`structopt`]: https://crates.io/crates/structopt
23 ///
24 /// # Example
25 ///
26 /// ```rust
27 /// use codespan_reporting::term::termcolor::StandardStream;
28 /// use codespan_reporting::term::ColorArg;
29 /// use structopt::StructOpt;
30 ///
31 /// #[derive(Debug, StructOpt)]
32 /// #[structopt(name = "groovey-app")]
33 /// pub struct Opts {
34 /// /// Configure coloring of output
35 /// #[structopt(
36 /// long = "color",
37 /// default_value = "auto",
38 /// possible_values = ColorArg::VARIANTS,
39 /// case_insensitive = true,
40 /// )]
41 /// pub color: ColorArg,
42 /// }
43 ///
44 /// let opts = Opts::from_args();
45 /// let writer = StandardStream::stderr(opts.color.into());
46 /// ```
47 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
48 pub struct ColorArg(pub ColorChoice);
49
50 impl ColorArg {
51 /// Allowed values the argument.
52 ///
53 /// This is useful for generating documentation via [`clap`] or `structopt`'s
54 /// `possible_values` configuration.
55 ///
56 /// [`clap`]: https://crates.io/crates/clap
57 /// [`structopt`]: https://crates.io/crates/structopt
58 pub const VARIANTS: &'static [&'static str] = &["auto", "always", "ansi", "never"];
59 }
60
61 impl FromStr for ColorArg {
62 type Err = &'static str;
63
from_str(src: &str) -> Result<ColorArg, &'static str>64 fn from_str(src: &str) -> Result<ColorArg, &'static str> {
65 match src {
66 _ if src.eq_ignore_ascii_case("auto") => Ok(ColorArg(ColorChoice::Auto)),
67 _ if src.eq_ignore_ascii_case("always") => Ok(ColorArg(ColorChoice::Always)),
68 _ if src.eq_ignore_ascii_case("ansi") => Ok(ColorArg(ColorChoice::AlwaysAnsi)),
69 _ if src.eq_ignore_ascii_case("never") => Ok(ColorArg(ColorChoice::Never)),
70 _ => Err("valid values: auto, always, ansi, never"),
71 }
72 }
73 }
74
75 impl Into<ColorChoice> for ColorArg {
into(self) -> ColorChoice76 fn into(self) -> ColorChoice {
77 self.0
78 }
79 }
80
81 /// Emit a diagnostic using the given writer, context, config, and files.
82 ///
83 /// The return value covers all error cases. These error case can arise if:
84 /// * a file was removed from the file database.
85 /// * a file was changed so that it is too small to have an index
86 /// * IO fails
emit<'files, F: Files<'files>>( writer: &mut dyn WriteColor, config: &Config, files: &'files F, diagnostic: &Diagnostic<F::FileId>, ) -> Result<(), super::files::Error>87 pub fn emit<'files, F: Files<'files>>(
88 writer: &mut dyn WriteColor,
89 config: &Config,
90 files: &'files F,
91 diagnostic: &Diagnostic<F::FileId>,
92 ) -> Result<(), super::files::Error> {
93 use self::renderer::Renderer;
94 use self::views::{RichDiagnostic, ShortDiagnostic};
95
96 let mut renderer = Renderer::new(writer, config);
97 match config.display_style {
98 DisplayStyle::Rich => RichDiagnostic::new(diagnostic, config).render(files, &mut renderer),
99 DisplayStyle::Medium => ShortDiagnostic::new(diagnostic, true).render(files, &mut renderer),
100 DisplayStyle::Short => ShortDiagnostic::new(diagnostic, false).render(files, &mut renderer),
101 }
102 }
103
104 #[cfg(test)]
105 mod tests {
106 use super::*;
107
108 use crate::diagnostic::Label;
109 use crate::files::SimpleFiles;
110
111 #[test]
unsized_emit()112 fn unsized_emit() {
113 let mut files = SimpleFiles::new();
114
115 let id = files.add("test", "");
116 let mut writer = termcolor::NoColor::new(Vec::<u8>::new());
117 let diagnostic = Diagnostic::bug().with_labels(vec![Label::primary(id, 0..0)]);
118
119 emit(&mut writer, &Config::default(), &files, &diagnostic).unwrap();
120 }
121 }
122