blob: ca78acb0a3179a3273f746a0a7bc2eb33e8a1d0a [file] [log] [blame]
David Tolnay7db73692019-10-20 14:51:12 -04001use crate::gen::Error;
2use crate::syntax;
3use anyhow::anyhow;
David Tolnay7db73692019-10-20 14:51:12 -04004use codespan_reporting::diagnostic::{Diagnostic, Label};
David Tolnaye2e7bc32020-03-18 14:02:01 -07005use codespan_reporting::files::SimpleFiles;
David Tolnay7db73692019-10-20 14:51:12 -04006use codespan_reporting::term::termcolor::{ColorChoice, StandardStream, WriteColor};
7use codespan_reporting::term::{self, Config};
8use std::io::Write;
9use std::ops::Range;
10use std::path::Path;
11use std::process;
12
13pub(super) fn format_err(path: &Path, source: &str, error: Error) -> ! {
14 match error {
15 Error::Syn(syn_error) => {
16 let writer = StandardStream::stderr(ColorChoice::Auto);
17 let ref mut stderr = writer.lock();
18 for error in syn_error {
19 let _ = writeln!(stderr);
20 display_syn_error(stderr, path, source, error);
21 }
22 }
23 _ => eprintln!("cxxbridge: {:?}", anyhow!(error)),
24 }
25 process::exit(1);
26}
27
28fn display_syn_error(stderr: &mut dyn WriteColor, path: &Path, source: &str, error: syn::Error) {
29 let span = error.span();
30 let start = span.start();
31 let end = span.end();
32
33 let mut start_offset = 0;
34 for _ in 1..start.line {
35 start_offset += source[start_offset..].find('\n').unwrap() + 1;
36 }
37 start_offset += start.column;
38
39 let mut end_offset = start_offset;
40 if start.line == end.line {
41 end_offset -= start.column;
42 } else {
43 for _ in 0..end.line - start.line {
44 end_offset += source[end_offset..].find('\n').unwrap() + 1;
45 }
46 }
47 end_offset += end.column;
48
David Tolnaye2e7bc32020-03-18 14:02:01 -070049 let mut files = SimpleFiles::new();
David Tolnay7db73692019-10-20 14:51:12 -040050 let file = files.add(path.to_string_lossy(), source);
51
David Tolnaye2e7bc32020-03-18 14:02:01 -070052 let diagnostic = diagnose(file, start_offset..end_offset, error);
David Tolnay7db73692019-10-20 14:51:12 -040053
54 let config = Config::default();
55 let _ = term::emit(stderr, &config, &files, &diagnostic);
56}
57
David Tolnaye2e7bc32020-03-18 14:02:01 -070058fn diagnose(file: usize, range: Range<usize>, error: syn::Error) -> Diagnostic<usize> {
David Tolnay7db73692019-10-20 14:51:12 -040059 let message = error.to_string();
60 let info = syntax::error::ERRORS
61 .iter()
62 .find(|e| message.contains(e.msg));
David Tolnaye2e7bc32020-03-18 14:02:01 -070063 let mut diagnostic = Diagnostic::error().with_message(&message);
64 let mut label = Label::primary(file, range);
65 if let Some(info) = info {
66 label.message = info.label.map_or(message, str::to_owned);
67 diagnostic.labels.push(label);
68 diagnostic.notes.extend(info.note.map(str::to_owned));
David Tolnay7db73692019-10-20 14:51:12 -040069 } else {
David Tolnaye2e7bc32020-03-18 14:02:01 -070070 label.message = message;
71 diagnostic.labels.push(label);
72 }
David Tolnay7db73692019-10-20 14:51:12 -040073 diagnostic.code = Some("cxxbridge".to_owned());
74 diagnostic
75}