DCE and fixing some internal tests
This commit is contained in:
parent
f481879d2a
commit
2f2c3e1783
4 changed files with 132 additions and 1213 deletions
|
@ -14,13 +14,12 @@ use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, LineInfo,
|
|||
use registry;
|
||||
|
||||
use check_old_skool;
|
||||
use {Level, RenderSpan, CodeSuggestion, DiagnosticBuilder, CodeMapper};
|
||||
use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper};
|
||||
use RenderSpan::*;
|
||||
use Level::*;
|
||||
use snippet::{SnippetData, StyledString, Style, FormatMode, Annotation, Line};
|
||||
use snippet::{StyledString, Style, FormatMode, Annotation, Line};
|
||||
use styled_buffer::StyledBuffer;
|
||||
|
||||
use std::{cmp, fmt};
|
||||
use std::cmp;
|
||||
use std::io::prelude::*;
|
||||
use std::io;
|
||||
use std::rc::Rc;
|
||||
|
@ -73,10 +72,6 @@ pub struct EmitterWriter {
|
|||
registry: Option<registry::Registry>,
|
||||
cm: Option<Rc<CodeMapper>>,
|
||||
|
||||
/// Is this the first error emitted thus far? If not, we emit a
|
||||
/// `\n` before the top-level errors.
|
||||
first: bool,
|
||||
|
||||
// For now, allow an old-school mode while we transition
|
||||
format_mode: FormatMode
|
||||
}
|
||||
|
@ -112,13 +107,11 @@ impl EmitterWriter {
|
|||
EmitterWriter { dst: dst,
|
||||
registry: registry,
|
||||
cm: code_map,
|
||||
first: true,
|
||||
format_mode: format_mode.clone() }
|
||||
} else {
|
||||
EmitterWriter { dst: Raw(Box::new(io::stderr())),
|
||||
registry: registry,
|
||||
cm: code_map,
|
||||
first: true,
|
||||
format_mode: format_mode.clone() }
|
||||
}
|
||||
}
|
||||
|
@ -131,23 +124,9 @@ impl EmitterWriter {
|
|||
EmitterWriter { dst: Raw(dst),
|
||||
registry: registry,
|
||||
cm: code_map,
|
||||
first: true,
|
||||
format_mode: format_mode.clone() }
|
||||
}
|
||||
|
||||
fn emit_message(&mut self,
|
||||
rsp: &RenderSpan,
|
||||
msg: &str,
|
||||
code: Option<&str>,
|
||||
lvl: Level,
|
||||
is_header: bool,
|
||||
show_snippet: bool) {
|
||||
match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) {
|
||||
Ok(()) => { }
|
||||
Err(e) => panic!("failed to emit error: {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> {
|
||||
fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
|
||||
file: Rc<FileMap>,
|
||||
|
@ -187,7 +166,7 @@ impl EmitterWriter {
|
|||
|
||||
if let Some(ref cm) = self.cm {
|
||||
for span_label in msp.span_labels() {
|
||||
let mut lo = cm.lookup_char_pos(span_label.span.lo);
|
||||
let lo = cm.lookup_char_pos(span_label.span.lo);
|
||||
let mut hi = cm.lookup_char_pos(span_label.span.hi);
|
||||
let mut is_minimized = false;
|
||||
|
||||
|
@ -478,7 +457,7 @@ impl EmitterWriter {
|
|||
|
||||
if msp.primary_spans().is_empty() && msp.span_labels().is_empty() && is_secondary {
|
||||
// This is a secondary message with no span info
|
||||
for i in 0..max_line_num_len {
|
||||
for _ in 0..max_line_num_len {
|
||||
buffer.prepend(0, " ", Style::NoStyle);
|
||||
}
|
||||
draw_note_separator(&mut buffer, 0, max_line_num_len + 1);
|
||||
|
@ -511,7 +490,7 @@ impl EmitterWriter {
|
|||
cm.lookup_char_pos(primary_span.lo)
|
||||
} else {
|
||||
// If we don't have span information, emit and exit
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst);
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
|
||||
return Ok(());
|
||||
};
|
||||
if let Ok(pos) =
|
||||
|
@ -526,19 +505,19 @@ impl EmitterWriter {
|
|||
let is_primary = primary_lo.file.name == annotated_file.file.name;
|
||||
if is_primary {
|
||||
// remember where we are in the output buffer for easy reference
|
||||
let mut buffer_msg_line_offset = buffer.num_lines();
|
||||
let buffer_msg_line_offset = buffer.num_lines();
|
||||
|
||||
buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber);
|
||||
let loc = primary_lo.clone();
|
||||
buffer.append(buffer_msg_line_offset,
|
||||
&format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1),
|
||||
Style::LineAndColumn);
|
||||
for i in 0..max_line_num_len {
|
||||
for _ in 0..max_line_num_len {
|
||||
buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle);
|
||||
}
|
||||
} else {
|
||||
// remember where we are in the output buffer for easy reference
|
||||
let mut buffer_msg_line_offset = buffer.num_lines();
|
||||
let buffer_msg_line_offset = buffer.num_lines();
|
||||
|
||||
// Add spacing line
|
||||
draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
|
||||
|
@ -548,13 +527,13 @@ impl EmitterWriter {
|
|||
buffer.append(buffer_msg_line_offset + 1,
|
||||
&annotated_file.file.name,
|
||||
Style::LineAndColumn);
|
||||
for i in 0..max_line_num_len {
|
||||
for _ in 0..max_line_num_len {
|
||||
buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle);
|
||||
}
|
||||
}
|
||||
|
||||
// Put in the spacer between the location and annotated source
|
||||
let mut buffer_msg_line_offset = buffer.num_lines();
|
||||
let buffer_msg_line_offset = buffer.num_lines();
|
||||
draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
|
||||
|
||||
// Next, output the annotate source for this file
|
||||
|
@ -599,7 +578,7 @@ impl EmitterWriter {
|
|||
}
|
||||
|
||||
// final step: take our styled buffer, render it, then output it
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst);
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -624,12 +603,6 @@ impl EmitterWriter {
|
|||
assert!(!lines.lines.is_empty());
|
||||
|
||||
let complete = suggestion.splice_lines(cm.borrow());
|
||||
let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES);
|
||||
let display_lines = &lines.lines[..line_count];
|
||||
|
||||
let fm = &*lines.file;
|
||||
// Calculate the widest number to format evenly
|
||||
let max_digits = line_num_max_digits(display_lines.last().unwrap());
|
||||
|
||||
// print the suggestion without any line numbers, but leave
|
||||
// space for them. This helps with lining up with previous
|
||||
|
@ -646,7 +619,7 @@ impl EmitterWriter {
|
|||
if let Some(_) = lines.next() {
|
||||
buffer.append(row_num, "...", Style::NoStyle);
|
||||
}
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst);
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -664,7 +637,10 @@ impl EmitterWriter {
|
|||
if !db.children.is_empty() {
|
||||
let mut buffer = StyledBuffer::new();
|
||||
draw_col_separator(&mut buffer, 0, max_line_num_len + 1);
|
||||
emit_to_destination(&buffer.render(), &db.level, &mut self.dst);
|
||||
match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) {
|
||||
Ok(()) => (),
|
||||
Err(e) => panic!("failed to emit error: {}", e)
|
||||
}
|
||||
}
|
||||
for child in &db.children {
|
||||
match child.render_span {
|
||||
|
@ -704,7 +680,10 @@ impl EmitterWriter {
|
|||
}
|
||||
Err(e) => panic!("failed to emit error: {}", e)
|
||||
}
|
||||
write!(&mut self.dst, "\n");
|
||||
match write!(&mut self.dst, "\n") {
|
||||
Err(e) => panic!("failed to emit error: {}", e),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
fn emit_message_old_school(&mut self,
|
||||
msp: &MultiSpan,
|
||||
|
@ -744,7 +723,7 @@ impl EmitterWriter {
|
|||
}
|
||||
|
||||
if !show_snippet {
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst);
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -752,13 +731,13 @@ impl EmitterWriter {
|
|||
// print any filename or anything for those.
|
||||
match msp.primary_span() {
|
||||
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => {
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst);
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
|
||||
return Ok(());
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
||||
let mut annotated_files = self.preprocess_annotations(msp);
|
||||
let annotated_files = self.preprocess_annotations(msp);
|
||||
|
||||
if let (Some(ref cm), Some(ann_file), Some(ref primary_span)) =
|
||||
(self.cm.as_ref(), annotated_files.first(), msp.primary_span().as_ref()) {
|
||||
|
@ -781,7 +760,7 @@ impl EmitterWriter {
|
|||
buffer.puts(line_offset, 0, &file_pos, Style::FileNameStyle);
|
||||
buffer.puts(line_offset, file_pos_len, &source_string, Style::Quotation);
|
||||
// Sort the annotations by (start, end col)
|
||||
let mut annotations = ann_file.lines[0].annotations.clone();
|
||||
let annotations = ann_file.lines[0].annotations.clone();
|
||||
|
||||
// Next, create the highlight line.
|
||||
for annotation in &annotations {
|
||||
|
@ -830,7 +809,7 @@ impl EmitterWriter {
|
|||
}
|
||||
|
||||
// final step: take our styled buffer, render it, then output it
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst);
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
|
||||
Ok(())
|
||||
}
|
||||
fn emit_suggestion_old_school(&mut self,
|
||||
|
@ -874,7 +853,7 @@ impl EmitterWriter {
|
|||
let mut row_num = 1;
|
||||
for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
|
||||
buffer.append(row_num, &fm.name, Style::FileNameStyle);
|
||||
for i in 0..max_digits+2 {
|
||||
for _ in 0..max_digits+2 {
|
||||
buffer.append(row_num, &" ", Style::NoStyle);
|
||||
}
|
||||
buffer.append(row_num, line, Style::NoStyle);
|
||||
|
@ -885,7 +864,7 @@ impl EmitterWriter {
|
|||
if let Some(_) = lines.next() {
|
||||
buffer.append(row_num, "...", Style::NoStyle);
|
||||
}
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst);
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -905,7 +884,7 @@ impl EmitterWriter {
|
|||
};
|
||||
|
||||
match child.render_span {
|
||||
Some(FullSpan(ref msp)) => {
|
||||
Some(FullSpan(_)) => {
|
||||
match self.emit_message_old_school(&span,
|
||||
&child.message,
|
||||
&None,
|
||||
|
@ -940,235 +919,6 @@ impl EmitterWriter {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit_message_(&mut self,
|
||||
rsp: &RenderSpan,
|
||||
msg: &str,
|
||||
code: Option<&str>,
|
||||
lvl: Level,
|
||||
is_header: bool,
|
||||
show_snippet: bool)
|
||||
-> io::Result<()> {
|
||||
let old_school = match self.format_mode {
|
||||
FormatMode::NewErrorFormat => false,
|
||||
FormatMode::OriginalErrorFormat => true,
|
||||
FormatMode::EnvironmentSelected => check_old_skool()
|
||||
};
|
||||
|
||||
if is_header {
|
||||
if self.first {
|
||||
self.first = false;
|
||||
} else {
|
||||
if !old_school {
|
||||
write!(self.dst, "\n")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match code {
|
||||
Some(code) if self.registry.as_ref()
|
||||
.and_then(|registry| registry.find_description(code))
|
||||
.is_some() => {
|
||||
let code_with_explain = String::from("--explain ") + code;
|
||||
if old_school {
|
||||
let loc = match rsp.span().primary_span() {
|
||||
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
|
||||
Some(ps) => if let Some(ref cm) = self.cm {
|
||||
cm.span_to_string(ps)
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
None => "".to_string()
|
||||
};
|
||||
print_diagnostic(&mut self.dst, &loc, lvl, msg, Some(code))?
|
||||
}
|
||||
else {
|
||||
print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))?
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if old_school {
|
||||
let loc = match rsp.span().primary_span() {
|
||||
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
|
||||
Some(ps) => if let Some(ref cm) = self.cm {
|
||||
cm.span_to_string(ps)
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
None => "".to_string()
|
||||
};
|
||||
print_diagnostic(&mut self.dst, &loc, lvl, msg, code)?
|
||||
}
|
||||
else {
|
||||
print_diagnostic(&mut self.dst, "", lvl, msg, code)?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !show_snippet {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Watch out for various nasty special spans; don't try to
|
||||
// print any filename or anything for those.
|
||||
match rsp.span().primary_span() {
|
||||
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => {
|
||||
return Ok(());
|
||||
}
|
||||
_ => { }
|
||||
}
|
||||
|
||||
// Otherwise, print out the snippet etc as needed.
|
||||
match *rsp {
|
||||
FullSpan(ref msp) => {
|
||||
self.highlight_lines(msp, lvl)?;
|
||||
if let Some(primary_span) = msp.primary_span() {
|
||||
self.print_macro_backtrace(primary_span)?;
|
||||
}
|
||||
}
|
||||
Suggestion(ref suggestion) => {
|
||||
self.highlight_suggestion(suggestion)?;
|
||||
if let Some(primary_span) = rsp.span().primary_span() {
|
||||
self.print_macro_backtrace(primary_span)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if old_school {
|
||||
match code {
|
||||
Some(code) if self.registry.as_ref()
|
||||
.and_then(|registry| registry.find_description(code))
|
||||
.is_some() => {
|
||||
let loc = match rsp.span().primary_span() {
|
||||
Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(),
|
||||
Some(ps) => if let Some(ref cm) = self.cm {
|
||||
cm.span_to_string(ps)
|
||||
} else {
|
||||
"".to_string()
|
||||
},
|
||||
None => "".to_string()
|
||||
};
|
||||
let msg = "run `rustc --explain ".to_string() + &code.to_string() +
|
||||
"` to see a detailed explanation";
|
||||
print_diagnostic(&mut self.dst, &loc, Level::Help, &msg,
|
||||
None)?
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()>
|
||||
{
|
||||
use std::borrow::Borrow;
|
||||
|
||||
let primary_span = suggestion.msp.primary_span().unwrap();
|
||||
if let Some(ref cm) = self.cm {
|
||||
let lines = cm.span_to_lines(primary_span).unwrap();
|
||||
|
||||
assert!(!lines.lines.is_empty());
|
||||
|
||||
let complete = suggestion.splice_lines(cm.borrow());
|
||||
let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES);
|
||||
let display_lines = &lines.lines[..line_count];
|
||||
|
||||
let fm = &*lines.file;
|
||||
// Calculate the widest number to format evenly
|
||||
let max_digits = line_num_max_digits(display_lines.last().unwrap());
|
||||
|
||||
// print the suggestion without any line numbers, but leave
|
||||
// space for them. This helps with lining up with previous
|
||||
// snippets from the actual error being reported.
|
||||
let mut lines = complete.lines();
|
||||
for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
|
||||
write!(&mut self.dst, "{0}:{1:2$} {3}\n",
|
||||
fm.name, "", max_digits, line)?;
|
||||
}
|
||||
|
||||
// if we elided some lines, add an ellipsis
|
||||
if let Some(_) = lines.next() {
|
||||
write!(&mut self.dst, "{0:1$} {0:2$} ...\n",
|
||||
"", fm.name.len(), max_digits)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn highlight_lines(&mut self,
|
||||
msp: &MultiSpan,
|
||||
lvl: Level)
|
||||
-> io::Result<()>
|
||||
{
|
||||
// Check to see if we have any lines to highlight, exit early if not
|
||||
match self.cm {
|
||||
None => return Ok(()),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
let old_school = match self.format_mode {
|
||||
FormatMode::NewErrorFormat => false,
|
||||
FormatMode::OriginalErrorFormat => true,
|
||||
FormatMode::EnvironmentSelected => check_old_skool()
|
||||
};
|
||||
|
||||
let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(),
|
||||
msp.primary_span(),
|
||||
self.format_mode.clone());
|
||||
if old_school {
|
||||
let mut output_vec = vec![];
|
||||
|
||||
for span_label in msp.span_labels() {
|
||||
let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(),
|
||||
Some(span_label.span),
|
||||
self.format_mode.clone());
|
||||
|
||||
snippet_data.push(span_label.span,
|
||||
span_label.is_primary,
|
||||
span_label.label);
|
||||
if span_label.is_primary {
|
||||
output_vec.insert(0, snippet_data);
|
||||
}
|
||||
else {
|
||||
output_vec.push(snippet_data);
|
||||
}
|
||||
}
|
||||
|
||||
for snippet_data in output_vec.iter() {
|
||||
/*
|
||||
let rendered_lines = snippet_data.render_lines();
|
||||
for rendered_line in &rendered_lines {
|
||||
for styled_string in &rendered_line.text {
|
||||
self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
|
||||
write!(&mut self.dst, "{}", styled_string.text)?;
|
||||
self.dst.reset_attrs()?;
|
||||
}
|
||||
write!(&mut self.dst, "\n")?;
|
||||
}
|
||||
*/
|
||||
emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for span_label in msp.span_labels() {
|
||||
snippet_data.push(span_label.span,
|
||||
span_label.is_primary,
|
||||
span_label.label);
|
||||
}
|
||||
emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst);
|
||||
/*
|
||||
let rendered_lines = snippet_data.render_lines();
|
||||
for rendered_line in &rendered_lines {
|
||||
for styled_string in &rendered_line.text {
|
||||
self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
|
||||
write!(&mut self.dst, "{}", styled_string.text)?;
|
||||
self.dst.reset_attrs()?;
|
||||
}
|
||||
write!(&mut self.dst, "\n")?;
|
||||
}
|
||||
*/
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn render_macro_backtrace_old_school(&mut self,
|
||||
sp: &Span,
|
||||
buffer: &mut StyledBuffer) -> io::Result<()> {
|
||||
|
@ -1192,24 +942,6 @@ impl EmitterWriter {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
fn print_macro_backtrace(&mut self,
|
||||
sp: Span)
|
||||
-> io::Result<()> {
|
||||
if let Some(ref cm) = self.cm {
|
||||
for trace in cm.macro_backtrace(sp) {
|
||||
let mut diag_string =
|
||||
format!("in this expansion of {}", trace.macro_decl_name);
|
||||
if let Some(def_site_span) = trace.def_site_span {
|
||||
diag_string.push_str(
|
||||
&format!(" (defined in {})",
|
||||
cm.span_to_filename(def_site_span)));
|
||||
}
|
||||
let snippet = cm.span_to_string(trace.call_site);
|
||||
print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
|
||||
|
@ -1230,11 +962,11 @@ fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
|
|||
dst: &mut Destination) -> io::Result<()> {
|
||||
for line in rendered_buffer {
|
||||
for part in line {
|
||||
dst.apply_style(lvl.clone(), part.style);
|
||||
write!(dst, "{}", part.text);
|
||||
dst.apply_style(lvl.clone(), part.style)?;
|
||||
write!(dst, "{}", part.text)?;
|
||||
dst.reset_attrs()?;
|
||||
}
|
||||
write!(dst, "\n");
|
||||
write!(dst, "\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1249,40 +981,6 @@ fn line_num_max_digits(line: &LineInfo) -> usize {
|
|||
digits
|
||||
}
|
||||
|
||||
fn print_diagnostic(dst: &mut Destination,
|
||||
topic: &str,
|
||||
lvl: Level,
|
||||
msg: &str,
|
||||
code: Option<&str>)
|
||||
-> io::Result<()> {
|
||||
if !topic.is_empty() {
|
||||
let old_school = check_old_skool();
|
||||
if !old_school {
|
||||
write!(dst, "{}: ", topic)?;
|
||||
}
|
||||
else {
|
||||
write!(dst, "{} ", topic)?;
|
||||
}
|
||||
dst.reset_attrs()?;
|
||||
}
|
||||
dst.start_attr(term::Attr::Bold)?;
|
||||
dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
|
||||
write!(dst, "{}", lvl.to_string())?;
|
||||
dst.reset_attrs()?;
|
||||
write!(dst, ": ")?;
|
||||
dst.start_attr(term::Attr::Bold)?;
|
||||
write!(dst, "{}", msg)?;
|
||||
|
||||
if let Some(code) = code {
|
||||
let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
|
||||
print_maybe_styled!(dst, style, " [{}]", code.clone())?;
|
||||
}
|
||||
|
||||
dst.reset_attrs()?;
|
||||
write!(dst, "\n")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn stderr_isatty() -> bool {
|
||||
use libc;
|
||||
|
@ -1374,46 +1072,6 @@ impl Destination {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_maybe_styled(&mut self,
|
||||
args: fmt::Arguments,
|
||||
color: term::Attr,
|
||||
print_newline_at_end: bool)
|
||||
-> io::Result<()> {
|
||||
match *self {
|
||||
Terminal(ref mut t) => {
|
||||
t.attr(color)?;
|
||||
// If `msg` ends in a newline, we need to reset the color before
|
||||
// the newline. We're making the assumption that we end up writing
|
||||
// to a `LineBufferedWriter`, which means that emitting the reset
|
||||
// after the newline ends up buffering the reset until we print
|
||||
// another line or exit. Buffering the reset is a problem if we're
|
||||
// sharing the terminal with any other programs (e.g. other rustc
|
||||
// instances via `make -jN`).
|
||||
//
|
||||
// Note that if `msg` contains any internal newlines, this will
|
||||
// result in the `LineBufferedWriter` flushing twice instead of
|
||||
// once, which still leaves the opportunity for interleaved output
|
||||
// to be miscolored. We assume this is rare enough that we don't
|
||||
// have to worry about it.
|
||||
t.write_fmt(args)?;
|
||||
t.reset()?;
|
||||
if print_newline_at_end {
|
||||
t.write_all(b"\n")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Raw(ref mut w) => {
|
||||
w.write_fmt(args)?;
|
||||
if print_newline_at_end {
|
||||
w.write_all(b"\n")
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Destination {
|
||||
|
|
|
@ -82,16 +82,6 @@ pub trait CodeMapper {
|
|||
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
|
||||
}
|
||||
|
||||
impl RenderSpan {
|
||||
fn span(&self) -> &MultiSpan {
|
||||
match *self {
|
||||
FullSpan(ref msp) |
|
||||
Suggestion(CodeSuggestion { ref msp, .. }) =>
|
||||
msp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CodeSuggestion {
|
||||
/// Returns the assembled code suggestion.
|
||||
pub fn splice_lines(&self, cm: &CodeMapper) -> String {
|
||||
|
|
|
@ -10,13 +10,9 @@
|
|||
|
||||
// Code for annotating snippets.
|
||||
|
||||
use syntax_pos::{Span, FileMap, CharPos, LineInfo};
|
||||
use check_old_skool;
|
||||
use syntax_pos::{Span, FileMap};
|
||||
use CodeMapper;
|
||||
use styled_buffer::StyledBuffer;
|
||||
use std::cmp;
|
||||
use std::rc::Rc;
|
||||
use std::mem;
|
||||
use {Level};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -78,14 +74,6 @@ pub struct Annotation {
|
|||
pub label: Option<String>,
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Debug)]
|
||||
pub struct RenderedLine {
|
||||
pub text: Vec<StyledString>,
|
||||
pub kind: RenderedLineKind,
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StyledString {
|
||||
pub text: String,
|
||||
|
@ -109,720 +97,3 @@ pub enum Style {
|
|||
ErrorCode,
|
||||
Level(Level),
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RenderedLineKind {
|
||||
PrimaryFileName,
|
||||
OtherFileName,
|
||||
SourceText {
|
||||
file: Rc<FileMap>,
|
||||
line_index: usize,
|
||||
},
|
||||
Annotations,
|
||||
Elision,
|
||||
}
|
||||
*/
|
||||
|
||||
impl SnippetData {
|
||||
pub fn new(codemap: Rc<CodeMapper>,
|
||||
primary_span: Option<Span>,
|
||||
format_mode: FormatMode) // (*)
|
||||
-> Self {
|
||||
// (*) The primary span indicates the file that must appear
|
||||
// first, and which will have a line number etc in its
|
||||
// name. Outside of tests, this is always `Some`, but for many
|
||||
// tests it's not relevant to test this portion of the logic,
|
||||
// and it's tedious to pick a primary span (read: tedious to
|
||||
// port older tests that predate the existence of a primary
|
||||
// span).
|
||||
|
||||
debug!("SnippetData::new(primary_span={:?})", primary_span);
|
||||
|
||||
let mut data = SnippetData {
|
||||
codemap: codemap.clone(),
|
||||
files: vec![],
|
||||
format_mode: format_mode.clone()
|
||||
};
|
||||
if let Some(primary_span) = primary_span {
|
||||
let lo = codemap.lookup_char_pos(primary_span.lo);
|
||||
data.files.push(
|
||||
FileInfo {
|
||||
file: lo.file,
|
||||
primary_span: Some(primary_span),
|
||||
lines: vec![],
|
||||
format_mode: format_mode.clone(),
|
||||
});
|
||||
}
|
||||
data
|
||||
}
|
||||
|
||||
pub fn push(&mut self, span: Span, is_primary: bool, label: Option<String>) {
|
||||
debug!("SnippetData::push(span={:?}, is_primary={}, label={:?})",
|
||||
span, is_primary, label);
|
||||
|
||||
let file_lines = match self.codemap.span_to_lines(span) {
|
||||
Ok(file_lines) => file_lines,
|
||||
Err(_) => {
|
||||
// ignore unprintable spans completely.
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
self.file(&file_lines.file)
|
||||
.push_lines(&file_lines.lines, is_primary, label);
|
||||
}
|
||||
|
||||
fn file(&mut self, file_map: &Rc<FileMap>) -> &mut FileInfo {
|
||||
let index = self.files.iter().position(|f| f.file.name == file_map.name);
|
||||
if let Some(index) = index {
|
||||
return &mut self.files[index];
|
||||
}
|
||||
|
||||
self.files.push(
|
||||
FileInfo {
|
||||
file: file_map.clone(),
|
||||
lines: vec![],
|
||||
primary_span: None,
|
||||
format_mode: self.format_mode.clone()
|
||||
});
|
||||
self.files.last_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn render_lines(&self) -> Vec<Vec<StyledString>> {
|
||||
debug!("SnippetData::render_lines()");
|
||||
|
||||
let mut rendered_lines: Vec<_> =
|
||||
self.files.iter()
|
||||
.flat_map(|f| f.render_file_lines(&self.codemap))
|
||||
.collect();
|
||||
//prepend_prefixes(&mut rendered_lines, &self.format_mode);
|
||||
//trim_lines(&mut rendered_lines);
|
||||
rendered_lines
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StringSource {
|
||||
fn make_string(self) -> String;
|
||||
}
|
||||
|
||||
impl StringSource for String {
|
||||
fn make_string(self) -> String {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl StringSource for Vec<char> {
|
||||
fn make_string(self) -> String {
|
||||
self.into_iter().collect()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<S> From<(S, Style, RenderedLineKind)> for RenderedLine
|
||||
where S: StringSource
|
||||
{
|
||||
fn from((text, style, kind): (S, Style, RenderedLineKind)) -> Self {
|
||||
RenderedLine {
|
||||
text: vec![StyledString {
|
||||
text: text.make_string(),
|
||||
style: style,
|
||||
}],
|
||||
kind: kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S1,S2> From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine
|
||||
where S1: StringSource, S2: StringSource
|
||||
{
|
||||
fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) -> Self {
|
||||
let (text1, style1, text2, style2, kind) = tuple;
|
||||
RenderedLine {
|
||||
text: vec![
|
||||
StyledString {
|
||||
text: text1.make_string(),
|
||||
style: style1,
|
||||
},
|
||||
StyledString {
|
||||
text: text2.make_string(),
|
||||
style: style2,
|
||||
}
|
||||
],
|
||||
kind: kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderedLine {
|
||||
fn trim_last(&mut self) {
|
||||
if let Some(last_text) = self.text.last_mut() {
|
||||
let len = last_text.text.trim_right().len();
|
||||
last_text.text.truncate(len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderedLineKind {
|
||||
fn prefix(&self) -> StyledString {
|
||||
match *self {
|
||||
RenderedLineKind::SourceText { file: _, line_index } =>
|
||||
StyledString {
|
||||
text: format!("{}", line_index + 1),
|
||||
style: Style::LineNumber,
|
||||
},
|
||||
RenderedLineKind::Elision =>
|
||||
StyledString {
|
||||
text: String::from("..."),
|
||||
style: Style::LineNumber,
|
||||
},
|
||||
RenderedLineKind::PrimaryFileName |
|
||||
RenderedLineKind::OtherFileName |
|
||||
RenderedLineKind::Annotations =>
|
||||
StyledString {
|
||||
text: String::from(""),
|
||||
style: Style::LineNumber,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl FileInfo {
|
||||
fn get_max_line_num(&self) -> usize {
|
||||
let mut max = 0;
|
||||
|
||||
for line in &self.lines {
|
||||
if line.line_index > max {
|
||||
max = line.line_index;
|
||||
}
|
||||
}
|
||||
max
|
||||
}
|
||||
|
||||
fn push_lines(&mut self,
|
||||
lines: &[LineInfo],
|
||||
is_primary: bool,
|
||||
label: Option<String>) {
|
||||
assert!(lines.len() > 0);
|
||||
|
||||
// If a span covers multiple lines, we reduce it to a single
|
||||
// point at the start of the span. This means that instead
|
||||
// of producing output like this:
|
||||
//
|
||||
// ```
|
||||
// --> foo.rs:2:1
|
||||
// 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
|
||||
// |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// 3 |> -> Set<LR0Item<'grammar>>
|
||||
// |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// (and so on)
|
||||
// ```
|
||||
//
|
||||
// we produce:
|
||||
//
|
||||
// ```
|
||||
// --> foo.rs:2:1
|
||||
// 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>)
|
||||
// ^
|
||||
// ```
|
||||
//
|
||||
// Basically, although this loses information, multi-line spans just
|
||||
// never look good.
|
||||
|
||||
let (line, start_col, mut end_col, is_minimized) = if lines.len() == 1 {
|
||||
(lines[0].line_index, lines[0].start_col, lines[0].end_col, false)
|
||||
} else {
|
||||
(lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1), true)
|
||||
};
|
||||
|
||||
// Watch out for "empty spans". If we get a span like 6..6, we
|
||||
// want to just display a `^` at 6, so convert that to
|
||||
// 6..7. This is degenerate input, but it's best to degrade
|
||||
// gracefully -- and the parser likes to suply a span like
|
||||
// that for EOF, in particular.
|
||||
if start_col == end_col {
|
||||
end_col.0 += 1;
|
||||
}
|
||||
|
||||
let index = self.ensure_source_line(line);
|
||||
self.lines[index].push_annotation(start_col,
|
||||
end_col,
|
||||
is_primary,
|
||||
is_minimized,
|
||||
label);
|
||||
}
|
||||
|
||||
/// Ensure that we have a `Line` struct corresponding to
|
||||
/// `line_index` in the file. If we already have some other lines,
|
||||
/// then this will add the intervening lines to ensure that we
|
||||
/// have a complete snippet. (Note that when we finally display,
|
||||
/// some of those lines may be elided.)
|
||||
fn ensure_source_line(&mut self, line_index: usize) -> usize {
|
||||
if self.lines.is_empty() {
|
||||
self.lines.push(Line::new(line_index));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Find the range of lines we have thus far.
|
||||
let first_line_index = self.lines.first().unwrap().line_index;
|
||||
let last_line_index = self.lines.last().unwrap().line_index;
|
||||
assert!(first_line_index <= last_line_index);
|
||||
|
||||
// If the new line is lower than all the lines we have thus
|
||||
// far, then insert the new line and any intervening lines at
|
||||
// the front. In a silly attempt at micro-optimization, we
|
||||
// don't just call `insert` repeatedly, but instead make a new
|
||||
// (empty) vector, pushing the new lines onto it, and then
|
||||
// appending the old vector.
|
||||
if line_index < first_line_index {
|
||||
let lines = mem::replace(&mut self.lines, vec![]);
|
||||
self.lines.extend(
|
||||
(line_index .. first_line_index)
|
||||
.map(|line| Line::new(line))
|
||||
.chain(lines));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the new line comes after the ones we have so far, insert
|
||||
// lines for it.
|
||||
if line_index > last_line_index {
|
||||
self.lines.extend(
|
||||
(last_line_index+1 .. line_index+1)
|
||||
.map(|line| Line::new(line)));
|
||||
return self.lines.len() - 1;
|
||||
}
|
||||
|
||||
// Otherwise it should already exist.
|
||||
return line_index - first_line_index;
|
||||
}
|
||||
|
||||
fn render_file_lines(&self, codemap: &Rc<CodeMapper>) -> Vec<Vec<StyledString>> {
|
||||
let old_school = match self.format_mode {
|
||||
FormatMode::OriginalErrorFormat => true,
|
||||
FormatMode::NewErrorFormat => false,
|
||||
FormatMode::EnvironmentSelected => check_old_skool()
|
||||
};
|
||||
|
||||
let mut lines_iter = self.lines.iter();
|
||||
let mut output = vec![];
|
||||
|
||||
// First insert the name of the file.
|
||||
if !old_school {
|
||||
match self.primary_span {
|
||||
Some(span) => {
|
||||
let lo = codemap.lookup_char_pos(span.lo);
|
||||
output.push(vec![StyledString {
|
||||
text: lo.file.name.clone(),
|
||||
style: Style::FileNameStyle,
|
||||
}, StyledString {
|
||||
text: format!(":{}:{}", lo.line, lo.col.0 + 1),
|
||||
style: Style::LineAndColumn,
|
||||
}]);
|
||||
output.push(vec![StyledString {
|
||||
text: "".to_string(),
|
||||
style: Style::FileNameStyle,
|
||||
}]);
|
||||
}
|
||||
None => {
|
||||
output.push(vec![StyledString {
|
||||
text: self.file.name.clone(),
|
||||
style: Style::FileNameStyle,
|
||||
}]);
|
||||
output.push(vec![StyledString {
|
||||
text: "".to_string(),
|
||||
style: Style::FileNameStyle,
|
||||
}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut next_line = lines_iter.next();
|
||||
while next_line.is_some() {
|
||||
// Consume lines with annotations.
|
||||
while let Some(line) = next_line {
|
||||
if line.annotations.is_empty() { break; }
|
||||
|
||||
let mut rendered_lines = self.render_line(line);
|
||||
assert!(!rendered_lines.is_empty());
|
||||
if old_school {
|
||||
match self.primary_span {
|
||||
Some(span) => {
|
||||
let lo = codemap.lookup_char_pos(span.lo);
|
||||
let hi = codemap.lookup_char_pos(span.hi);
|
||||
//Before each secondary line in old skool-mode, print the label
|
||||
//as an old-style note
|
||||
if !line.annotations[0].is_primary {
|
||||
if let Some(ann) = line.annotations[0].label.clone() {
|
||||
output.push(vec![StyledString {
|
||||
text: lo.file.name.clone(),
|
||||
style: Style::FileNameStyle,
|
||||
}, StyledString {
|
||||
text: format!(":{}:{}: {}:{} ", lo.line, lo.col.0 + 1,
|
||||
hi.line, hi.col.0+1),
|
||||
style: Style::LineAndColumn,
|
||||
}, StyledString {
|
||||
text: format!("note: "),
|
||||
style: Style::OldSchoolNote,
|
||||
}, StyledString {
|
||||
text: format!("{}", ann),
|
||||
style: Style::OldSchoolNoteText,
|
||||
}]);
|
||||
}
|
||||
}
|
||||
rendered_lines[0].insert(0, StyledString {
|
||||
text: format!(":{} ", lo.line),
|
||||
style: Style::LineAndColumn,
|
||||
});
|
||||
rendered_lines[0].insert(0, StyledString {
|
||||
text: lo.file.name.clone(),
|
||||
style: Style::FileNameStyle,
|
||||
});
|
||||
let gap_amount =
|
||||
rendered_lines[0][0].text.len() +
|
||||
rendered_lines[0][1].text.len();
|
||||
assert!(rendered_lines.len() >= 2,
|
||||
"no annotations resulted from: {:?}",
|
||||
line);
|
||||
for i in 1..rendered_lines.len() {
|
||||
rendered_lines[i].insert(0, StyledString {
|
||||
text: vec![" "; gap_amount].join(""),
|
||||
style: Style::NoStyle
|
||||
});
|
||||
}
|
||||
}
|
||||
_ =>()
|
||||
}
|
||||
}
|
||||
output.append(&mut rendered_lines);
|
||||
next_line = lines_iter.next();
|
||||
}
|
||||
|
||||
// Emit lines without annotations, but only if they are
|
||||
// followed by a line with an annotation.
|
||||
let unannotated_line = next_line;
|
||||
let mut unannotated_lines = 0;
|
||||
while let Some(line) = next_line {
|
||||
if !line.annotations.is_empty() { break; }
|
||||
unannotated_lines += 1;
|
||||
next_line = lines_iter.next();
|
||||
}
|
||||
if unannotated_lines > 1 {
|
||||
output.push(vec![StyledString{ text: String::new(), style: Style::NoStyle}]);
|
||||
} else if let Some(line) = unannotated_line {
|
||||
output.append(&mut self.render_line(line));
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn render_line(&self, line: &Line) -> Vec<Vec<StyledString>> {
|
||||
let old_school = match self.format_mode {
|
||||
FormatMode::OriginalErrorFormat => true,
|
||||
FormatMode::NewErrorFormat => false,
|
||||
FormatMode::EnvironmentSelected => check_old_skool()
|
||||
};
|
||||
|
||||
let source_string = self.file.get_line(line.line_index)
|
||||
.unwrap_or("");
|
||||
/*
|
||||
let source_kind = RenderedLineKind::SourceText {
|
||||
file: self.file.clone(),
|
||||
line_index: line.line_index,
|
||||
};
|
||||
*/
|
||||
|
||||
let mut styled_buffer = StyledBuffer::new();
|
||||
|
||||
// First create the source line we will highlight.
|
||||
styled_buffer.append(0, &source_string, Style::Quotation);
|
||||
|
||||
if line.annotations.is_empty() {
|
||||
return styled_buffer.render();
|
||||
}
|
||||
|
||||
// We want to display like this:
|
||||
//
|
||||
// vec.push(vec.pop().unwrap());
|
||||
// --- ^^^ _ previous borrow ends here
|
||||
// | |
|
||||
// | error occurs here
|
||||
// previous borrow of `vec` occurs here
|
||||
//
|
||||
// But there are some weird edge cases to be aware of:
|
||||
//
|
||||
// vec.push(vec.pop().unwrap());
|
||||
// -------- - previous borrow ends here
|
||||
// ||
|
||||
// |this makes no sense
|
||||
// previous borrow of `vec` occurs here
|
||||
//
|
||||
// For this reason, we group the lines into "highlight lines"
|
||||
// and "annotations lines", where the highlight lines have the `~`.
|
||||
|
||||
//let mut highlight_line = Self::whitespace(&source_string);
|
||||
|
||||
// Sort the annotations by (start, end col)
|
||||
let mut annotations = line.annotations.clone();
|
||||
annotations.sort();
|
||||
|
||||
// Next, create the highlight line.
|
||||
for annotation in &annotations {
|
||||
if old_school {
|
||||
for p in annotation.start_col .. annotation.end_col {
|
||||
if p == annotation.start_col {
|
||||
styled_buffer.putc(1, p, '^',
|
||||
if annotation.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
Style::OldSchoolNote
|
||||
});
|
||||
}
|
||||
else {
|
||||
styled_buffer.putc(1, p, '~',
|
||||
if annotation.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
Style::OldSchoolNote
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for p in annotation.start_col .. annotation.end_col {
|
||||
if annotation.is_primary {
|
||||
styled_buffer.putc(1, p, '^', Style::UnderlinePrimary);
|
||||
if !annotation.is_minimized {
|
||||
styled_buffer.set_style(0, p, Style::UnderlinePrimary);
|
||||
}
|
||||
} else {
|
||||
styled_buffer.putc(1, p, '-', Style::UnderlineSecondary);
|
||||
if !annotation.is_minimized {
|
||||
styled_buffer.set_style(0, p, Style::UnderlineSecondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we are going to write labels in. To start, we'll exclude
|
||||
// the annotations with no labels.
|
||||
let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) =
|
||||
annotations.into_iter()
|
||||
.partition(|a| a.label.is_some());
|
||||
|
||||
// If there are no annotations that need text, we're done.
|
||||
if labeled_annotations.is_empty() {
|
||||
return styled_buffer.render();
|
||||
}
|
||||
if old_school {
|
||||
return styled_buffer.render();
|
||||
}
|
||||
|
||||
// Now add the text labels. We try, when possible, to stick the rightmost
|
||||
// annotation at the end of the highlight line:
|
||||
//
|
||||
// vec.push(vec.pop().unwrap());
|
||||
// --- --- - previous borrow ends here
|
||||
//
|
||||
// But sometimes that's not possible because one of the other
|
||||
// annotations overlaps it. For example, from the test
|
||||
// `span_overlap_label`, we have the following annotations
|
||||
// (written on distinct lines for clarity):
|
||||
//
|
||||
// fn foo(x: u32) {
|
||||
// --------------
|
||||
// -
|
||||
//
|
||||
// In this case, we can't stick the rightmost-most label on
|
||||
// the highlight line, or we would get:
|
||||
//
|
||||
// fn foo(x: u32) {
|
||||
// -------- x_span
|
||||
// |
|
||||
// fn_span
|
||||
//
|
||||
// which is totally weird. Instead we want:
|
||||
//
|
||||
// fn foo(x: u32) {
|
||||
// --------------
|
||||
// | |
|
||||
// | x_span
|
||||
// fn_span
|
||||
//
|
||||
// which is...less weird, at least. In fact, in general, if
|
||||
// the rightmost span overlaps with any other span, we should
|
||||
// use the "hang below" version, so we can at least make it
|
||||
// clear where the span *starts*.
|
||||
let mut labeled_annotations = &labeled_annotations[..];
|
||||
match labeled_annotations.split_last().unwrap() {
|
||||
(last, previous) => {
|
||||
if previous.iter()
|
||||
.chain(&unlabeled_annotations)
|
||||
.all(|a| !overlaps(a, last))
|
||||
{
|
||||
// append the label afterwards; we keep it in a separate
|
||||
// string
|
||||
let highlight_label: String = format!(" {}", last.label.as_ref().unwrap());
|
||||
if last.is_primary {
|
||||
styled_buffer.append(1, &highlight_label, Style::LabelPrimary);
|
||||
} else {
|
||||
styled_buffer.append(1, &highlight_label, Style::LabelSecondary);
|
||||
}
|
||||
labeled_annotations = previous;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If that's the last annotation, we're done
|
||||
if labeled_annotations.is_empty() {
|
||||
return styled_buffer.render();
|
||||
}
|
||||
|
||||
for (index, annotation) in labeled_annotations.iter().enumerate() {
|
||||
// Leave:
|
||||
// - 1 extra line
|
||||
// - One line for each thing that comes after
|
||||
let comes_after = labeled_annotations.len() - index - 1;
|
||||
let blank_lines = 3 + comes_after;
|
||||
|
||||
// For each blank line, draw a `|` at our column. The
|
||||
// text ought to be long enough for this.
|
||||
for index in 2..blank_lines {
|
||||
if annotation.is_primary {
|
||||
styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlinePrimary);
|
||||
} else {
|
||||
styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlineSecondary);
|
||||
}
|
||||
}
|
||||
|
||||
if annotation.is_primary {
|
||||
styled_buffer.puts(blank_lines, annotation.start_col,
|
||||
annotation.label.as_ref().unwrap(), Style::LabelPrimary);
|
||||
} else {
|
||||
styled_buffer.puts(blank_lines, annotation.start_col,
|
||||
annotation.label.as_ref().unwrap(), Style::LabelSecondary);
|
||||
}
|
||||
}
|
||||
|
||||
styled_buffer.render()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn prepend_prefixes(rendered_lines: &mut [RenderedLine], format_mode: &FormatMode) {
|
||||
let old_school = match *format_mode {
|
||||
FormatMode::OriginalErrorFormat => true,
|
||||
FormatMode::NewErrorFormat => false,
|
||||
FormatMode::EnvironmentSelected => check_old_skool()
|
||||
};
|
||||
if old_school {
|
||||
return;
|
||||
}
|
||||
|
||||
let prefixes: Vec<_> =
|
||||
rendered_lines.iter()
|
||||
.map(|rl| rl.kind.prefix())
|
||||
.collect();
|
||||
|
||||
// find the max amount of spacing we need; add 1 to
|
||||
// p.text.len() to leave space between the prefix and the
|
||||
// source text
|
||||
let padding_len =
|
||||
prefixes.iter()
|
||||
.map(|p| if p.text.len() == 0 { 0 } else { p.text.len() + 1 })
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
// Ensure we insert at least one character of padding, so that the
|
||||
// `-->` arrows can fit etc.
|
||||
let padding_len = cmp::max(padding_len, 1);
|
||||
|
||||
for (mut prefix, line) in prefixes.into_iter().zip(rendered_lines) {
|
||||
let extra_spaces = (prefix.text.len() .. padding_len).map(|_| ' ');
|
||||
prefix.text.extend(extra_spaces);
|
||||
match line.kind {
|
||||
RenderedLineKind::Elision => {
|
||||
line.text.insert(0, prefix);
|
||||
}
|
||||
RenderedLineKind::PrimaryFileName => {
|
||||
// --> filename
|
||||
// 22 |>
|
||||
// ^
|
||||
// padding_len
|
||||
let dashes = (0..padding_len - 1).map(|_| ' ')
|
||||
.chain(Some('-'))
|
||||
.chain(Some('-'))
|
||||
.chain(Some('>'))
|
||||
.chain(Some(' '));
|
||||
line.text.insert(0, StyledString {text: dashes.collect(),
|
||||
style: Style::LineNumber})
|
||||
}
|
||||
RenderedLineKind::OtherFileName => {
|
||||
// ::: filename
|
||||
// 22 |>
|
||||
// ^
|
||||
// padding_len
|
||||
let dashes = (0..padding_len - 1).map(|_| ' ')
|
||||
.chain(Some(':'))
|
||||
.chain(Some(':'))
|
||||
.chain(Some(':'))
|
||||
.chain(Some(' '));
|
||||
line.text.insert(0, StyledString {text: dashes.collect(),
|
||||
style: Style::LineNumber})
|
||||
}
|
||||
_ => {
|
||||
line.text.insert(0, prefix);
|
||||
line.text.insert(1, StyledString {text: String::from("|> "),
|
||||
style: Style::LineNumber})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trim_lines(rendered_lines: &mut [RenderedLine]) {
|
||||
for line in rendered_lines {
|
||||
while !line.text.is_empty() {
|
||||
line.trim_last();
|
||||
if line.text.last().unwrap().text.is_empty() {
|
||||
line.text.pop();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl Line {
|
||||
fn new(line_index: usize) -> Line {
|
||||
Line {
|
||||
line_index: line_index,
|
||||
annotations: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
fn push_annotation(&mut self,
|
||||
start: CharPos,
|
||||
end: CharPos,
|
||||
is_primary: bool,
|
||||
is_minimized: bool,
|
||||
label: Option<String>) {
|
||||
self.annotations.push(Annotation {
|
||||
start_col: start.0,
|
||||
end_col: end.0,
|
||||
is_primary: is_primary,
|
||||
is_minimized: is_minimized,
|
||||
label: label,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn overlaps(a1: &Annotation,
|
||||
a2: &Annotation)
|
||||
-> bool
|
||||
{
|
||||
(a2.start_col .. a2.end_col).contains(a1.start_col) ||
|
||||
(a1.start_col .. a1.end_col).contains(a2.start_col)
|
||||
}
|
||||
|
|
|
@ -1265,9 +1265,9 @@ r"blork2.rs:2:1: 2:12
|
|||
println!("r#\"\n{}\"#", str);
|
||||
assert_eq!(str, &r#"
|
||||
--> dummy.txt:11:1
|
||||
|>
|
||||
11 |> e-lä-vän
|
||||
|> ^
|
||||
|
|
||||
11 | e-lä-vän
|
||||
| ^
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1333,9 +1333,9 @@ r"blork2.rs:2:1: 2:12
|
|||
|
||||
let expect_start = &r#"
|
||||
--> dummy.txt:1:6
|
||||
|>
|
||||
1 |> _____aaaaaa____bbbbbb__cccccdd_
|
||||
|> ^^^^^^ ^^^^^^ ^^^^^^^
|
||||
|
|
||||
1 | _____aaaaaa____bbbbbb__cccccdd_
|
||||
| ^^^^^^ ^^^^^^ ^^^^^^^
|
||||
"#[1..];
|
||||
|
||||
let span = |sp, expected| {
|
||||
|
@ -1409,28 +1409,28 @@ r"blork2.rs:2:1: 2:12
|
|||
|
||||
let expect0 = &r#"
|
||||
--> dummy.txt:5:1
|
||||
|>
|
||||
5 |> ccccc
|
||||
|> ^
|
||||
|
|
||||
5 | ccccc
|
||||
| ^
|
||||
...
|
||||
9 |> ddd__eee_
|
||||
|> ^^^ ^^^
|
||||
10 |> elided
|
||||
11 |> __f_gg
|
||||
|> ^ ^^
|
||||
9 | ddd__eee_
|
||||
| ^^^ ^^^
|
||||
10 | elided
|
||||
11 | __f_gg
|
||||
| ^ ^^
|
||||
"#[1..];
|
||||
|
||||
let expect = &r#"
|
||||
--> dummy.txt:1:1
|
||||
|>
|
||||
1 |> aaaaa
|
||||
|> ^
|
||||
|
|
||||
1 | aaaaa
|
||||
| ^
|
||||
...
|
||||
9 |> ddd__eee_
|
||||
|> ^^^ ^^^
|
||||
10 |> elided
|
||||
11 |> __f_gg
|
||||
|> ^ ^^
|
||||
9 | ddd__eee_
|
||||
| ^^^ ^^^
|
||||
10 | elided
|
||||
11 | __f_gg
|
||||
| ^ ^^
|
||||
"#[1..];
|
||||
|
||||
macro_rules! test {
|
||||
|
@ -1477,9 +1477,9 @@ fn foo() {
|
|||
let text = make_string(&lines);
|
||||
assert_eq!(&text[..], &"
|
||||
--> foo.rs:3:2
|
||||
|>
|
||||
3 |> \tbar;
|
||||
|> \t^^^
|
||||
|
|
||||
3 | \tbar;
|
||||
| \t^^^
|
||||
"[1..]);
|
||||
}
|
||||
|
||||
|
@ -1510,12 +1510,12 @@ fn foo() {
|
|||
println!("text=\n{}", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> --- --- - previous borrow ends here
|
||||
|> | |
|
||||
|> | error occurs here
|
||||
|> previous borrow of `vec` occurs here
|
||||
|
|
||||
3 | vec.push(vec.pop().unwrap());
|
||||
| --- --- - previous borrow ends here
|
||||
| | |
|
||||
| | error occurs here
|
||||
| previous borrow of `vec` occurs here
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1577,24 +1577,24 @@ fn bar() {
|
|||
|
||||
println!("text=\n{}", text);
|
||||
|
||||
// Note that the `|>` remain aligned across both files:
|
||||
// Note that the `|` remain aligned across both files:
|
||||
assert_eq!(&text[..], &r#"
|
||||
--> foo.rs:3:14
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> --- ^^^ - c
|
||||
|> | |
|
||||
|> | b
|
||||
|> a
|
||||
|
|
||||
3 | vec.push(vec.pop().unwrap());
|
||||
| --- ^^^ - c
|
||||
| | |
|
||||
| | b
|
||||
| a
|
||||
::: bar.rs
|
||||
|>
|
||||
17 |> vec.push();
|
||||
|> --- - f
|
||||
|> |
|
||||
|> d
|
||||
|
|
||||
17 | vec.push();
|
||||
| --- - f
|
||||
| |
|
||||
| d
|
||||
...
|
||||
21 |> vec.pop().unwrap());
|
||||
|> --- e
|
||||
21 | vec.pop().unwrap());
|
||||
| --- e
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1632,15 +1632,15 @@ fn foo() {
|
|||
println!("text=\n{}", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> let name = find_id(&data, 22).unwrap();
|
||||
|> ---- immutable borrow begins here
|
||||
|
|
||||
3 | let name = find_id(&data, 22).unwrap();
|
||||
| ---- immutable borrow begins here
|
||||
...
|
||||
6 |> data.push(Data { name: format!("Hera"), id: 66 });
|
||||
|> ---- mutable borrow occurs here
|
||||
6 | data.push(Data { name: format!("Hera"), id: 66 });
|
||||
| ---- mutable borrow occurs here
|
||||
...
|
||||
11 |> }
|
||||
|> - immutable borrow ends here
|
||||
11 | }
|
||||
| - immutable borrow ends here
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1672,13 +1672,13 @@ fn foo() {
|
|||
println!("text=r#\"\n{}\".trim_left()", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> -------- ------ D
|
||||
|> ||
|
||||
|> |C
|
||||
|> A
|
||||
|> B
|
||||
|
|
||||
3 | vec.push(vec.pop().unwrap());
|
||||
| -------- ------ D
|
||||
| ||
|
||||
| |C
|
||||
| A
|
||||
| B
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1709,12 +1709,12 @@ fn foo() {
|
|||
println!("text=r#\"\n{}\".trim_left()", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> --- --- - previous borrow ends here
|
||||
|> | |
|
||||
|> | error occurs here
|
||||
|> previous borrow of `vec` occurs here
|
||||
|
|
||||
3 | vec.push(vec.pop().unwrap());
|
||||
| --- --- - previous borrow ends here
|
||||
| | |
|
||||
| | error occurs here
|
||||
| previous borrow of `vec` occurs here
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1748,12 +1748,12 @@ fn foo() {
|
|||
println!("text=r#\"\n{}\".trim_left()", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
4 |> let mut vec2 = vec;
|
||||
|> --- `vec` moved here because it has type `collections::vec::Vec<i32>`
|
||||
|
|
||||
4 | let mut vec2 = vec;
|
||||
| --- `vec` moved here because it has type `collections::vec::Vec<i32>`
|
||||
...
|
||||
9 |> vec.push(7);
|
||||
|> --- use of moved value: `vec`
|
||||
9 | vec.push(7);
|
||||
| --- use of moved value: `vec`
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1785,11 +1785,11 @@ fn foo() {
|
|||
println!("text=&r#\"\n{}\n\"#[1..]", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> let mut vec = vec![0, 1, 2];
|
||||
|> --- ---
|
||||
4 |> let mut vec2 = vec;
|
||||
|> --- ---
|
||||
|
|
||||
3 | let mut vec = vec![0, 1, 2];
|
||||
| --- ---
|
||||
4 | let mut vec2 = vec;
|
||||
| --- ---
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1817,9 +1817,9 @@ impl SomeTrait for () {
|
|||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> fn foo(x: u32) {
|
||||
|> -
|
||||
|
|
||||
3 | fn foo(x: u32) {
|
||||
| -
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1847,12 +1847,12 @@ impl SomeTrait for () {
|
|||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
2 |> fn foo(x: u32) {
|
||||
|> --------------
|
||||
|> | |
|
||||
|> | x_span
|
||||
|> fn_span
|
||||
|
|
||||
2 | fn foo(x: u32) {
|
||||
| --------------
|
||||
| | |
|
||||
| | x_span
|
||||
| fn_span
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1882,12 +1882,12 @@ impl SomeTrait for () {
|
|||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
2 |> fn foo(x: u32) {
|
||||
|> --------------
|
||||
|> | |
|
||||
|> | x_span
|
||||
|> fn_span
|
||||
|
|
||||
2 | fn foo(x: u32) {
|
||||
| --------------
|
||||
| | |
|
||||
| | x_span
|
||||
| fn_span
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1928,11 +1928,11 @@ impl SomeTrait for () {
|
|||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> let closure = || {
|
||||
|> - foo
|
||||
4 |> inner
|
||||
|> ----- bar
|
||||
|
|
||||
3 | let closure = || {
|
||||
| - foo
|
||||
4 | inner
|
||||
| ----- bar
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
|
@ -1971,9 +1971,9 @@ fn main() {
|
|||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
--> foo.rs:11:2
|
||||
|>
|
||||
11 |> }
|
||||
|> -
|
||||
|
|
||||
11 | }
|
||||
| -
|
||||
"#[1..]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue