1use codespan_reporting::diagnostic::{Diagnostic, Label}; 2use codespan_reporting::files::SimpleFile; 3use codespan_reporting::term::termcolor::StandardStream; 4use codespan_reporting::term::{self, ColorArg}; 5use std::ops::Range; 6use structopt::StructOpt; 7 8#[derive(Debug, StructOpt)] 9#[structopt(name = "emit")] 10pub struct Opts { 11 #[structopt(long = "color", 12 parse(try_from_str), 13 default_value = "auto", 14 possible_values = ColorArg::VARIANTS, 15 case_insensitive = true 16 )] 17 color: ColorArg, 18} 19 20fn main() -> anyhow::Result<()> { 21 let file = SimpleFile::new( 22 "main.rs", 23 unindent::unindent( 24 r#" 25 fn main() { 26 let foo: i32 = "hello, world"; 27 foo += 1; 28 } 29 "#, 30 ), 31 ); 32 33 let errors = [ 34 Error::MismatchType( 35 Item::new(20..23, "i32"), 36 Item::new(31..45, "\"hello, world\""), 37 ), 38 Error::MutatingImmutable(Item::new(20..23, "foo"), Item::new(51..59, "foo += 1")), 39 ]; 40 41 let opts = Opts::from_args(); 42 let writer = StandardStream::stderr(opts.color.into()); 43 let config = codespan_reporting::term::Config::default(); 44 for diagnostic in errors.iter().map(Error::report) { 45 term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; 46 } 47 48 Ok(()) 49} 50 51/// An error enum that represent all possible errors within your program 52enum Error { 53 MismatchType(Item, Item), 54 MutatingImmutable(Item, Item), 55} 56 57impl Error { 58 fn report(&self) -> Diagnostic<()> { 59 match self { 60 Error::MismatchType(left, right) => Diagnostic::error() 61 .with_code("E0308") 62 .with_message("mismatch types") 63 .with_labels(vec![ 64 Label::primary((), right.range.clone()).with_message(format!( 65 "Expected `{}`, found: `{}`", 66 left.content, right.content, 67 )), 68 Label::secondary((), left.range.clone()).with_message("expected due to this"), 69 ]), 70 Error::MutatingImmutable(original, mutating) => Diagnostic::error() 71 .with_code("E0384") 72 .with_message(format!( 73 "cannot mutate immutable variable `{}`", 74 original.content, 75 )) 76 .with_labels(vec![ 77 Label::secondary((), original.range.clone()).with_message(unindent::unindent( 78 &format!( 79 r#" 80 first assignment to `{0}` 81 help: make this binding mutable: `mut {0}` 82 "#, 83 original.content, 84 ), 85 )), 86 Label::primary((), mutating.range.clone()) 87 .with_message("cannot assign twice to immutable variable"), 88 ]), 89 } 90 } 91} 92 93/// An item in the source code to be used in the `Error` enum. 94/// In a more complex program it could also contain a `files::FileId` to handle errors that occur inside multiple files. 95struct Item { 96 range: Range<usize>, 97 content: String, 98} 99 100impl Item { 101 fn new(range: Range<usize>, content: impl Into<String>) -> Item { 102 let content = content.into(); 103 Item { range, content } 104 } 105} 106