Implement latest rfc style using simpler rendering
This commit is contained in:
parent
a019c2c6ba
commit
71ec2867e3
5 changed files with 697 additions and 198 deletions
|
|
@ -10,14 +10,15 @@
|
|||
|
||||
use self::Destination::*;
|
||||
|
||||
use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, Span, MultiSpan, LineInfo};
|
||||
use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, LineInfo, CharPos};
|
||||
use registry;
|
||||
|
||||
use check_old_skool;
|
||||
use {Level, RenderSpan, CodeSuggestion, DiagnosticBuilder, CodeMapper};
|
||||
use RenderSpan::*;
|
||||
use Level::*;
|
||||
use snippet::{RenderedLineKind, SnippetData, Style, FormatMode};
|
||||
use snippet::{SnippetData, StyledString, Style, FormatMode, Annotation, Line};
|
||||
use styled_buffer::StyledBuffer;
|
||||
|
||||
use std::{cmp, fmt};
|
||||
use std::io::prelude::*;
|
||||
|
|
@ -33,14 +34,13 @@ pub trait Emitter {
|
|||
|
||||
impl Emitter for EmitterWriter {
|
||||
fn emit(&mut self, db: &DiagnosticBuilder) {
|
||||
self.emit_message(&FullSpan(db.span.clone()),
|
||||
&db.message,
|
||||
db.code.as_ref().map(|s| &**s),
|
||||
db.level,
|
||||
true,
|
||||
true);
|
||||
|
||||
if check_old_skool() {
|
||||
self.emit_message(&FullSpan(db.span.clone()),
|
||||
&db.message,
|
||||
db.code.as_ref().map(|s| &**s),
|
||||
db.level,
|
||||
true,
|
||||
true);
|
||||
let db_span = FullSpan(db.span.clone());
|
||||
|
||||
for child in &db.children {
|
||||
|
|
@ -60,18 +60,7 @@ impl Emitter for EmitterWriter {
|
|||
show_snippet);
|
||||
}
|
||||
} else {
|
||||
for child in &db.children {
|
||||
let render_span = child.render_span
|
||||
.clone()
|
||||
.unwrap_or_else(
|
||||
|| FullSpan(child.span.clone()));
|
||||
self.emit_message(&render_span,
|
||||
&child.message,
|
||||
None,
|
||||
child.level,
|
||||
false,
|
||||
true);
|
||||
}
|
||||
self.emit_messages_default(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -109,6 +98,12 @@ pub struct EmitterWriter {
|
|||
format_mode: FormatMode
|
||||
}
|
||||
|
||||
struct FileWithAnnotatedLines {
|
||||
file: Rc<FileMap>,
|
||||
lines: Vec<Line>,
|
||||
}
|
||||
|
||||
|
||||
/// Do not use this for messages that end in `\n` – use `println_maybe_styled` instead. See
|
||||
/// `EmitterWriter::print_maybe_styled` for details.
|
||||
macro_rules! print_maybe_styled {
|
||||
|
|
@ -170,6 +165,560 @@ impl EmitterWriter {
|
|||
}
|
||||
}
|
||||
|
||||
fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> {
|
||||
fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>,
|
||||
file: Rc<FileMap>,
|
||||
line_index: usize,
|
||||
ann: Annotation) {
|
||||
|
||||
for slot in file_vec.iter_mut() {
|
||||
// Look through each of our files for the one we're adding to
|
||||
if slot.file.name == file.name {
|
||||
// See if we already have a line for it
|
||||
for line_slot in &mut slot.lines {
|
||||
if line_slot.line_index == line_index {
|
||||
line_slot.annotations.push(ann);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// We don't have a line yet, create one
|
||||
slot.lines.push(Line {
|
||||
line_index: line_index,
|
||||
annotations: vec![ann],
|
||||
});
|
||||
slot.lines.sort();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// This is the first time we're seeing the file
|
||||
file_vec.push(FileWithAnnotatedLines {
|
||||
file: file,
|
||||
lines: vec![Line {
|
||||
line_index: line_index,
|
||||
annotations: vec![ann],
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
let mut output = vec![];
|
||||
|
||||
if let Some(ref cm) = self.cm {
|
||||
for span_label in msp.span_labels() {
|
||||
let lo = cm.lookup_char_pos(span_label.span.lo);
|
||||
let hi = cm.lookup_char_pos(span_label.span.hi);
|
||||
|
||||
// If the span is multi-line, simplify down to the span of one character
|
||||
let (start_col, mut end_col, is_minimized) = if lo.line != hi.line {
|
||||
(lo.col, CharPos(lo.col.0 + 1), true)
|
||||
} else {
|
||||
(lo.col, hi.col, false)
|
||||
};
|
||||
|
||||
// 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 supply a span like
|
||||
// that for EOF, in particular.
|
||||
if start_col == end_col {
|
||||
end_col.0 += 1;
|
||||
}
|
||||
|
||||
add_annotation_to_file(&mut output,
|
||||
lo.file,
|
||||
lo.line,
|
||||
Annotation {
|
||||
start_col: lo.col.0,
|
||||
end_col: hi.col.0,
|
||||
is_primary: span_label.is_primary,
|
||||
is_minimized: is_minimized,
|
||||
label: span_label.label.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
fn render_source_line(&self,
|
||||
buffer: &mut StyledBuffer,
|
||||
file: Rc<FileMap>,
|
||||
line: &Line,
|
||||
width_offset: usize) {
|
||||
let source_string = file.get_line(line.line_index - 1)
|
||||
.unwrap_or("");
|
||||
|
||||
let line_offset = buffer.num_lines();
|
||||
|
||||
// First create the source line we will highlight.
|
||||
buffer.puts(line_offset, width_offset, &source_string, Style::Quotation);
|
||||
buffer.puts(line_offset,
|
||||
0,
|
||||
&(line.line_index.to_string()),
|
||||
Style::LineNumber);
|
||||
|
||||
draw_col_separator(buffer, line_offset, width_offset - 2);
|
||||
|
||||
if line.annotations.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
let old_school = check_old_skool();
|
||||
|
||||
// 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 {
|
||||
buffer.putc(line_offset + 1,
|
||||
width_offset + p,
|
||||
'^',
|
||||
if annotation.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
Style::OldSchoolNote
|
||||
});
|
||||
} else {
|
||||
buffer.putc(line_offset + 1,
|
||||
width_offset + p,
|
||||
'~',
|
||||
if annotation.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
Style::OldSchoolNote
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for p in annotation.start_col..annotation.end_col {
|
||||
if annotation.is_primary {
|
||||
buffer.putc(line_offset + 1,
|
||||
width_offset + p,
|
||||
'^',
|
||||
Style::UnderlinePrimary);
|
||||
if !annotation.is_minimized {
|
||||
buffer.set_style(line_offset,
|
||||
width_offset + p,
|
||||
Style::UnderlinePrimary);
|
||||
}
|
||||
} else {
|
||||
buffer.putc(line_offset + 1,
|
||||
width_offset + p,
|
||||
'-',
|
||||
Style::UnderlineSecondary);
|
||||
if !annotation.is_minimized {
|
||||
buffer.set_style(line_offset,
|
||||
width_offset + p,
|
||||
Style::UnderlineSecondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
draw_col_separator(buffer, line_offset + 1, width_offset - 2);
|
||||
|
||||
// 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;
|
||||
}
|
||||
if old_school {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
buffer.append(line_offset + 1, &highlight_label, Style::LabelPrimary);
|
||||
} else {
|
||||
buffer.append(line_offset + 1, &highlight_label, Style::LabelSecondary);
|
||||
}
|
||||
labeled_annotations = previous;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If that's the last annotation, we're done
|
||||
if labeled_annotations.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
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 {
|
||||
buffer.putc(line_offset + index,
|
||||
width_offset + annotation.start_col,
|
||||
'|',
|
||||
Style::UnderlinePrimary);
|
||||
} else {
|
||||
buffer.putc(line_offset + index,
|
||||
width_offset + annotation.start_col,
|
||||
'|',
|
||||
Style::UnderlineSecondary);
|
||||
}
|
||||
draw_col_separator(buffer, line_offset + index, width_offset - 2);
|
||||
}
|
||||
|
||||
if annotation.is_primary {
|
||||
buffer.puts(line_offset + blank_lines,
|
||||
width_offset + annotation.start_col,
|
||||
annotation.label.as_ref().unwrap(),
|
||||
Style::LabelPrimary);
|
||||
} else {
|
||||
buffer.puts(line_offset + blank_lines,
|
||||
width_offset + annotation.start_col,
|
||||
annotation.label.as_ref().unwrap(),
|
||||
Style::LabelSecondary);
|
||||
}
|
||||
draw_col_separator(buffer, line_offset + blank_lines, width_offset - 2);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize {
|
||||
let mut max = 0;
|
||||
if let Some(ref cm) = self.cm {
|
||||
for primary_span in msp.primary_spans() {
|
||||
let hi = cm.lookup_char_pos(primary_span.hi);
|
||||
if hi.line > max {
|
||||
max = hi.line;
|
||||
}
|
||||
}
|
||||
for span_label in msp.span_labels() {
|
||||
let hi = cm.lookup_char_pos(span_label.span.hi);
|
||||
if hi.line > max {
|
||||
max = hi.line;
|
||||
}
|
||||
}
|
||||
}
|
||||
max
|
||||
}
|
||||
|
||||
fn get_max_line_num(&mut self, db: &DiagnosticBuilder) -> usize {
|
||||
let mut max = 0;
|
||||
|
||||
let primary = self.get_multispan_max_line_num(&db.span);
|
||||
max = if primary > max { primary } else { max };
|
||||
|
||||
for sub in &db.children {
|
||||
let sub_result = self.get_multispan_max_line_num(&sub.span);
|
||||
max = if sub_result > max { primary } else { max };
|
||||
}
|
||||
max
|
||||
}
|
||||
|
||||
fn emit_message_default(&mut self,
|
||||
msp: &MultiSpan,
|
||||
msg: &str,
|
||||
code: &Option<String>,
|
||||
level: &Level,
|
||||
max_line_num_len: usize,
|
||||
is_secondary: bool)
|
||||
-> io::Result<()> {
|
||||
let mut buffer = StyledBuffer::new();
|
||||
|
||||
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 {
|
||||
buffer.prepend(0, " ", Style::NoStyle);
|
||||
}
|
||||
draw_note_separator(&mut buffer, 0, max_line_num_len + 1);
|
||||
buffer.append(0, &level.to_string(), Style::HeaderMsg);
|
||||
buffer.append(0, ": ", Style::NoStyle);
|
||||
buffer.append(0, msg, Style::NoStyle);
|
||||
}
|
||||
else {
|
||||
buffer.append(0, &level.to_string(), Style::Level(level.clone()));
|
||||
match code {
|
||||
&Some(ref code) => {
|
||||
buffer.append(0, "[", Style::Level(level.clone()));
|
||||
buffer.append(0, &code, Style::Level(level.clone()));
|
||||
buffer.append(0, "]", Style::Level(level.clone()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
buffer.append(0, ": ", Style::HeaderMsg);
|
||||
buffer.append(0, msg, Style::HeaderMsg);
|
||||
}
|
||||
|
||||
// Preprocess all the annotations so that they are grouped by file and by line number
|
||||
// This helps us quickly iterate over the whole message (including secondary file spans)
|
||||
let mut annotated_files = self.preprocess_annotations(msp);
|
||||
|
||||
// Make sure our primary file comes first
|
||||
let primary_lo =
|
||||
if let (Some(ref cm), Some(ref primary_span)) = (self.cm.as_ref(),
|
||||
msp.primary_span().as_ref()) {
|
||||
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);
|
||||
return Ok(());
|
||||
};
|
||||
if let Ok(pos) =
|
||||
annotated_files.binary_search_by(|x| x.file.name.cmp(&primary_lo.file.name)) {
|
||||
annotated_files.swap(0, pos);
|
||||
}
|
||||
|
||||
// Print out the annotate source lines that correspond with the error
|
||||
for annotated_file in annotated_files {
|
||||
// print out the span location and spacer before we print the annotated source
|
||||
// to do this, we need to know if this span will be primary
|
||||
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();
|
||||
|
||||
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),
|
||||
Style::LineAndColumn);
|
||||
for i 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();
|
||||
|
||||
// Add spacing line
|
||||
draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
|
||||
|
||||
// Then, the secondary file indicator
|
||||
buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber);
|
||||
buffer.append(buffer_msg_line_offset + 1,
|
||||
&annotated_file.file.name,
|
||||
Style::LineAndColumn);
|
||||
for i 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();
|
||||
draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
|
||||
|
||||
// Next, output the annotate source for this file
|
||||
for line_idx in 0..annotated_file.lines.len() {
|
||||
self.render_source_line(&mut buffer,
|
||||
annotated_file.file.clone(),
|
||||
&annotated_file.lines[line_idx],
|
||||
3 + max_line_num_len);
|
||||
|
||||
// check to see if we need to print out or elide lines that come between
|
||||
// this annotated line and the next one
|
||||
if line_idx < (annotated_file.lines.len() - 1) {
|
||||
let line_idx_delta = annotated_file.lines[line_idx + 1].line_index -
|
||||
annotated_file.lines[line_idx].line_index;
|
||||
if line_idx_delta > 2 {
|
||||
let last_buffer_line_num = buffer.num_lines();
|
||||
buffer.puts(last_buffer_line_num, 0, "...", Style::LineNumber);
|
||||
} else if line_idx_delta == 2 {
|
||||
let unannotated_line = annotated_file.file
|
||||
.get_line(annotated_file.lines[line_idx].line_index)
|
||||
.unwrap_or("");
|
||||
|
||||
let last_buffer_line_num = buffer.num_lines();
|
||||
|
||||
buffer.puts(last_buffer_line_num,
|
||||
0,
|
||||
&(annotated_file.lines[line_idx + 1].line_index - 1)
|
||||
.to_string(),
|
||||
Style::LineNumber);
|
||||
draw_col_separator(&mut buffer, last_buffer_line_num, 1 + max_line_num_len);
|
||||
buffer.puts(last_buffer_line_num,
|
||||
3 + max_line_num_len,
|
||||
&unannotated_line,
|
||||
Style::Quotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// final step: take our styled buffer, render it, then output it
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn emit_suggestion_default(&mut self,
|
||||
suggestion: &CodeSuggestion,
|
||||
level: &Level,
|
||||
msg: &str,
|
||||
max_line_num_len: usize)
|
||||
-> io::Result<()> {
|
||||
use std::borrow::Borrow;
|
||||
|
||||
let primary_span = suggestion.msp.primary_span().unwrap();
|
||||
if let Some(ref cm) = self.cm {
|
||||
let mut buffer = StyledBuffer::new();
|
||||
|
||||
buffer.append(0, &level.to_string(), Style::Level(level.clone()));
|
||||
buffer.append(0, ": ", Style::HeaderMsg);
|
||||
buffer.append(0, msg, Style::HeaderMsg);
|
||||
|
||||
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();
|
||||
let mut row_num = 1;
|
||||
for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) {
|
||||
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
|
||||
buffer.append(row_num, line, Style::NoStyle);
|
||||
row_num += 1;
|
||||
}
|
||||
|
||||
// if we elided some lines, add an ellipsis
|
||||
if let Some(_) = lines.next() {
|
||||
buffer.append(row_num, "...", Style::NoStyle);
|
||||
}
|
||||
emit_to_destination(&buffer.render(), level, &mut self.dst);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn emit_messages_default(&mut self, db: &DiagnosticBuilder) {
|
||||
let max_line_num = self.get_max_line_num(db);
|
||||
let max_line_num_len = max_line_num.to_string().len();
|
||||
|
||||
match self.emit_message_default(&db.span,
|
||||
&db.message,
|
||||
&db.code,
|
||||
&db.level,
|
||||
max_line_num_len,
|
||||
false) {
|
||||
Ok(()) => {
|
||||
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);
|
||||
}
|
||||
for child in &db.children {
|
||||
match child.render_span {
|
||||
Some(FullSpan(ref msp)) => {
|
||||
match self.emit_message_default(msp,
|
||||
&child.message,
|
||||
&None,
|
||||
&child.level,
|
||||
max_line_num_len,
|
||||
true) {
|
||||
Err(e) => panic!("failed to emit error: {}", e),
|
||||
_ => ()
|
||||
}
|
||||
},
|
||||
Some(Suggestion(ref cs)) => {
|
||||
match self.emit_suggestion_default(cs,
|
||||
&child.level,
|
||||
&child.message,
|
||||
max_line_num_len) {
|
||||
Err(e) => panic!("failed to emit error: {}", e),
|
||||
_ => ()
|
||||
}
|
||||
},
|
||||
None => {
|
||||
match self.emit_message_default(&child.span,
|
||||
&child.message,
|
||||
&None,
|
||||
&child.level,
|
||||
max_line_num_len,
|
||||
true) {
|
||||
Err(e) => panic!("failed to emit error: {}", e),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => panic!("failed to emit error: {}", e)
|
||||
}
|
||||
write!(&mut self.dst, "\n");
|
||||
}
|
||||
|
||||
fn emit_message_(&mut self,
|
||||
rsp: &RenderSpan,
|
||||
msg: &str,
|
||||
|
|
@ -363,6 +912,7 @@ impl EmitterWriter {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
@ -372,6 +922,8 @@ impl EmitterWriter {
|
|||
}
|
||||
write!(&mut self.dst, "\n")?;
|
||||
}
|
||||
*/
|
||||
emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -380,6 +932,8 @@ impl EmitterWriter {
|
|||
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 {
|
||||
|
|
@ -389,6 +943,7 @@ impl EmitterWriter {
|
|||
}
|
||||
write!(&mut self.dst, "\n")?;
|
||||
}
|
||||
*/
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -413,6 +968,33 @@ impl EmitterWriter {
|
|||
}
|
||||
}
|
||||
|
||||
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
|
||||
buffer.puts(line, col, "| ", Style::LineNumber);
|
||||
}
|
||||
|
||||
fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
|
||||
buffer.puts(line, col, "= ", Style::LineNumber);
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
|
||||
lvl: &Level,
|
||||
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.reset_attrs()?;
|
||||
}
|
||||
write!(dst, "\n");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn line_num_max_digits(line: &LineInfo) -> usize {
|
||||
let mut max_line_num = line.line_index + 1;
|
||||
let mut digits = 0;
|
||||
|
|
@ -480,7 +1062,7 @@ fn stderr_isatty() -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
enum Destination {
|
||||
pub enum Destination {
|
||||
Terminal(Box<term::StderrTerminal>),
|
||||
Raw(Box<Write + Send>),
|
||||
}
|
||||
|
|
@ -495,35 +1077,39 @@ impl Destination {
|
|||
|
||||
fn apply_style(&mut self,
|
||||
lvl: Level,
|
||||
_kind: &RenderedLineKind,
|
||||
style: Style)
|
||||
-> io::Result<()> {
|
||||
match style {
|
||||
Style::FileNameStyle |
|
||||
Style::LineAndColumn => {
|
||||
}
|
||||
Style::FileNameStyle | Style::LineAndColumn => {}
|
||||
Style::LineNumber => {
|
||||
self.start_attr(term::Attr::Bold)?;
|
||||
self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
|
||||
try!(self.start_attr(term::Attr::Bold));
|
||||
try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE)));
|
||||
}
|
||||
Style::Quotation => {
|
||||
Style::ErrorCode => {
|
||||
try!(self.start_attr(term::Attr::Bold));
|
||||
//try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA)));
|
||||
}
|
||||
Style::OldSkoolNote => {
|
||||
self.start_attr(term::Attr::Bold)?;
|
||||
self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))?;
|
||||
Style::Quotation => {}
|
||||
Style::OldSchoolNote => {
|
||||
try!(self.start_attr(term::Attr::Bold));
|
||||
try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN)));
|
||||
}
|
||||
Style::OldSkoolNoteText => {
|
||||
self.start_attr(term::Attr::Bold)?;
|
||||
Style::OldSchoolNoteText | Style::HeaderMsg => {
|
||||
try!(self.start_attr(term::Attr::Bold));
|
||||
}
|
||||
Style::UnderlinePrimary | Style::LabelPrimary => {
|
||||
self.start_attr(term::Attr::Bold)?;
|
||||
self.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
|
||||
try!(self.start_attr(term::Attr::Bold));
|
||||
try!(self.start_attr(term::Attr::ForegroundColor(lvl.color())));
|
||||
}
|
||||
Style::UnderlineSecondary | Style::LabelSecondary => {
|
||||
self.start_attr(term::Attr::Bold)?;
|
||||
self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
|
||||
Style::UnderlineSecondary |
|
||||
Style::LabelSecondary => {
|
||||
try!(self.start_attr(term::Attr::Bold));
|
||||
try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE)));
|
||||
}
|
||||
Style::NoStyle => {
|
||||
Style::NoStyle => {}
|
||||
Style::Level(l) => {
|
||||
try!(self.start_attr(term::Attr::Bold));
|
||||
try!(self.start_attr(term::Attr::ForegroundColor(l.color())));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ use std::thread::panicking;
|
|||
pub mod emitter;
|
||||
pub mod snippet;
|
||||
pub mod registry;
|
||||
pub mod styled_buffer;
|
||||
|
||||
use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION };
|
||||
use syntax_pos::{MacroBacktrace};
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@
|
|||
use syntax_pos::{Span, FileMap, CharPos, LineInfo};
|
||||
use check_old_skool;
|
||||
use CodeMapper;
|
||||
use styled_buffer::StyledBuffer;
|
||||
use std::cmp;
|
||||
use std::rc::Rc;
|
||||
use std::mem;
|
||||
use {Level};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum FormatMode {
|
||||
|
|
@ -49,38 +51,40 @@ pub struct FileInfo {
|
|||
format_mode: FormatMode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Line {
|
||||
line_index: usize,
|
||||
annotations: Vec<Annotation>,
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub struct Line {
|
||||
pub line_index: usize,
|
||||
pub annotations: Vec<Annotation>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
struct Annotation {
|
||||
pub struct Annotation {
|
||||
/// Start column, 0-based indexing -- counting *characters*, not
|
||||
/// utf-8 bytes. Note that it is important that this field goes
|
||||
/// first, so that when we sort, we sort orderings by start
|
||||
/// column.
|
||||
start_col: usize,
|
||||
pub start_col: usize,
|
||||
|
||||
/// End column within the line (exclusive)
|
||||
end_col: usize,
|
||||
pub end_col: usize,
|
||||
|
||||
/// Is this annotation derived from primary span
|
||||
is_primary: bool,
|
||||
pub is_primary: bool,
|
||||
|
||||
/// Is this a large span minimized down to a smaller span
|
||||
is_minimized: bool,
|
||||
pub is_minimized: bool,
|
||||
|
||||
/// Optional label to display adjacent to the annotation.
|
||||
label: Option<String>,
|
||||
pub label: Option<String>,
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Debug)]
|
||||
pub struct RenderedLine {
|
||||
pub text: Vec<StyledString>,
|
||||
pub kind: RenderedLineKind,
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StyledString {
|
||||
|
|
@ -88,14 +92,9 @@ pub struct StyledString {
|
|||
pub style: Style,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StyledBuffer {
|
||||
text: Vec<Vec<char>>,
|
||||
styles: Vec<Vec<Style>>
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Style {
|
||||
HeaderMsg,
|
||||
FileNameStyle,
|
||||
LineAndColumn,
|
||||
LineNumber,
|
||||
|
|
@ -104,11 +103,14 @@ pub enum Style {
|
|||
UnderlineSecondary,
|
||||
LabelPrimary,
|
||||
LabelSecondary,
|
||||
OldSkoolNoteText,
|
||||
OldSkoolNote,
|
||||
OldSchoolNoteText,
|
||||
OldSchoolNote,
|
||||
NoStyle,
|
||||
ErrorCode,
|
||||
Level(Level),
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RenderedLineKind {
|
||||
PrimaryFileName,
|
||||
|
|
@ -120,6 +122,7 @@ pub enum RenderedLineKind {
|
|||
Annotations,
|
||||
Elision,
|
||||
}
|
||||
*/
|
||||
|
||||
impl SnippetData {
|
||||
pub fn new(codemap: Rc<CodeMapper>,
|
||||
|
|
@ -186,15 +189,15 @@ impl SnippetData {
|
|||
self.files.last_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn render_lines(&self) -> Vec<RenderedLine> {
|
||||
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);
|
||||
//prepend_prefixes(&mut rendered_lines, &self.format_mode);
|
||||
//trim_lines(&mut rendered_lines);
|
||||
rendered_lines
|
||||
}
|
||||
}
|
||||
|
|
@ -215,6 +218,7 @@ impl StringSource for Vec<char> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<S> From<(S, Style, RenderedLineKind)> for RenderedLine
|
||||
where S: StringSource
|
||||
{
|
||||
|
|
@ -282,96 +286,20 @@ impl RenderedLineKind {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StyledBuffer {
|
||||
fn new() -> StyledBuffer {
|
||||
StyledBuffer { text: vec![], styles: vec![] }
|
||||
}
|
||||
|
||||
fn render(&self, source_kind: RenderedLineKind) -> Vec<RenderedLine> {
|
||||
let mut output: Vec<RenderedLine> = vec![];
|
||||
let mut styled_vec: Vec<StyledString> = vec![];
|
||||
|
||||
for (row, row_style) in self.text.iter().zip(&self.styles) {
|
||||
let mut current_style = Style::NoStyle;
|
||||
let mut current_text = String::new();
|
||||
|
||||
for (&c, &s) in row.iter().zip(row_style) {
|
||||
if s != current_style {
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString { text: current_text, style: current_style });
|
||||
}
|
||||
current_style = s;
|
||||
current_text = String::new();
|
||||
}
|
||||
current_text.push(c);
|
||||
}
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString { text: current_text, style: current_style });
|
||||
}
|
||||
|
||||
if output.is_empty() {
|
||||
//We know our first output line is source and the rest are highlights and labels
|
||||
output.push(RenderedLine { text: styled_vec, kind: source_kind.clone() });
|
||||
} else {
|
||||
output.push(RenderedLine { text: styled_vec, kind: RenderedLineKind::Annotations });
|
||||
}
|
||||
styled_vec = vec![];
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
|
||||
while line >= self.text.len() {
|
||||
self.text.push(vec![]);
|
||||
self.styles.push(vec![]);
|
||||
}
|
||||
|
||||
if col < self.text[line].len() {
|
||||
self.text[line][col] = chr;
|
||||
self.styles[line][col] = style;
|
||||
} else {
|
||||
let mut i = self.text[line].len();
|
||||
while i < col {
|
||||
let s = match self.text[0].get(i) {
|
||||
Some(&'\t') => '\t',
|
||||
_ => ' '
|
||||
};
|
||||
self.text[line].push(s);
|
||||
self.styles[line].push(Style::NoStyle);
|
||||
i += 1;
|
||||
}
|
||||
self.text[line].push(chr);
|
||||
self.styles[line].push(style);
|
||||
}
|
||||
}
|
||||
|
||||
fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
|
||||
let mut n = col;
|
||||
for c in string.chars() {
|
||||
self.putc(line, n, c, style);
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_style(&mut self, line: usize, col: usize, style: Style) {
|
||||
if self.styles.len() > line && self.styles[line].len() > col {
|
||||
self.styles[line][col] = style;
|
||||
}
|
||||
}
|
||||
|
||||
fn append(&mut self, line: usize, string: &str, style: Style) {
|
||||
if line >= self.text.len() {
|
||||
self.puts(line, 0, string, style);
|
||||
} else {
|
||||
let col = self.text[line].len();
|
||||
self.puts(line, col, string, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
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,
|
||||
|
|
@ -469,16 +397,13 @@ impl FileInfo {
|
|||
return line_index - first_line_index;
|
||||
}
|
||||
|
||||
fn render_file_lines(&self, codemap: &Rc<CodeMapper>) -> Vec<RenderedLine> {
|
||||
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()
|
||||
};
|
||||
|
||||
// As a first step, we elide any instance of more than one
|
||||
// continuous unannotated line.
|
||||
|
||||
let mut lines_iter = self.lines.iter();
|
||||
let mut output = vec![];
|
||||
|
||||
|
|
@ -487,39 +412,27 @@ impl FileInfo {
|
|||
match self.primary_span {
|
||||
Some(span) => {
|
||||
let lo = codemap.lookup_char_pos(span.lo);
|
||||
output.push(RenderedLine {
|
||||
text: vec![StyledString {
|
||||
output.push(vec![StyledString {
|
||||
text: lo.file.name.clone(),
|
||||
style: Style::FileNameStyle,
|
||||
}, StyledString {
|
||||
text: format!(":{}:{}", lo.line, lo.col.0 + 1),
|
||||
style: Style::LineAndColumn,
|
||||
}],
|
||||
kind: RenderedLineKind::PrimaryFileName,
|
||||
});
|
||||
output.push(RenderedLine {
|
||||
text: vec![StyledString {
|
||||
}]);
|
||||
output.push(vec![StyledString {
|
||||
text: "".to_string(),
|
||||
style: Style::FileNameStyle,
|
||||
}],
|
||||
kind: RenderedLineKind::Annotations,
|
||||
});
|
||||
}]);
|
||||
}
|
||||
None => {
|
||||
output.push(RenderedLine {
|
||||
text: vec![StyledString {
|
||||
output.push(vec![StyledString {
|
||||
text: self.file.name.clone(),
|
||||
style: Style::FileNameStyle,
|
||||
}],
|
||||
kind: RenderedLineKind::OtherFileName,
|
||||
});
|
||||
output.push(RenderedLine {
|
||||
text: vec![StyledString {
|
||||
}]);
|
||||
output.push(vec![StyledString {
|
||||
text: "".to_string(),
|
||||
style: Style::FileNameStyle,
|
||||
}],
|
||||
kind: RenderedLineKind::Annotations,
|
||||
});
|
||||
}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -541,8 +454,7 @@ impl FileInfo {
|
|||
//as an old-style note
|
||||
if !line.annotations[0].is_primary {
|
||||
if let Some(ann) = line.annotations[0].label.clone() {
|
||||
output.push(RenderedLine {
|
||||
text: vec![StyledString {
|
||||
output.push(vec![StyledString {
|
||||
text: lo.file.name.clone(),
|
||||
style: Style::FileNameStyle,
|
||||
}, StyledString {
|
||||
|
|
@ -551,31 +463,29 @@ impl FileInfo {
|
|||
style: Style::LineAndColumn,
|
||||
}, StyledString {
|
||||
text: format!("note: "),
|
||||
style: Style::OldSkoolNote,
|
||||
style: Style::OldSchoolNote,
|
||||
}, StyledString {
|
||||
text: format!("{}", ann),
|
||||
style: Style::OldSkoolNoteText,
|
||||
}],
|
||||
kind: RenderedLineKind::Annotations,
|
||||
});
|
||||
style: Style::OldSchoolNoteText,
|
||||
}]);
|
||||
}
|
||||
}
|
||||
rendered_lines[0].text.insert(0, StyledString {
|
||||
rendered_lines[0].insert(0, StyledString {
|
||||
text: format!(":{} ", lo.line),
|
||||
style: Style::LineAndColumn,
|
||||
});
|
||||
rendered_lines[0].text.insert(0, StyledString {
|
||||
rendered_lines[0].insert(0, StyledString {
|
||||
text: lo.file.name.clone(),
|
||||
style: Style::FileNameStyle,
|
||||
});
|
||||
let gap_amount =
|
||||
rendered_lines[0].text[0].text.len() +
|
||||
rendered_lines[0].text[1].text.len();
|
||||
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].text.insert(0, StyledString {
|
||||
rendered_lines[i].insert(0, StyledString {
|
||||
text: vec![" "; gap_amount].join(""),
|
||||
style: Style::NoStyle
|
||||
});
|
||||
|
|
@ -598,9 +508,7 @@ impl FileInfo {
|
|||
next_line = lines_iter.next();
|
||||
}
|
||||
if unannotated_lines > 1 {
|
||||
output.push(RenderedLine::from((String::new(),
|
||||
Style::NoStyle,
|
||||
RenderedLineKind::Elision)));
|
||||
output.push(vec![StyledString{ text: String::new(), style: Style::NoStyle}]);
|
||||
} else if let Some(line) = unannotated_line {
|
||||
output.append(&mut self.render_line(line));
|
||||
}
|
||||
|
|
@ -609,7 +517,7 @@ impl FileInfo {
|
|||
output
|
||||
}
|
||||
|
||||
fn render_line(&self, line: &Line) -> Vec<RenderedLine> {
|
||||
fn render_line(&self, line: &Line) -> Vec<Vec<StyledString>> {
|
||||
let old_school = match self.format_mode {
|
||||
FormatMode::OriginalErrorFormat => true,
|
||||
FormatMode::NewErrorFormat => false,
|
||||
|
|
@ -618,10 +526,12 @@ impl FileInfo {
|
|||
|
||||
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();
|
||||
|
||||
|
|
@ -629,7 +539,7 @@ impl FileInfo {
|
|||
styled_buffer.append(0, &source_string, Style::Quotation);
|
||||
|
||||
if line.annotations.is_empty() {
|
||||
return styled_buffer.render(source_kind);
|
||||
return styled_buffer.render();
|
||||
}
|
||||
|
||||
// We want to display like this:
|
||||
|
|
@ -666,7 +576,7 @@ impl FileInfo {
|
|||
if annotation.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
Style::OldSkoolNote
|
||||
Style::OldSchoolNote
|
||||
});
|
||||
}
|
||||
else {
|
||||
|
|
@ -674,7 +584,7 @@ impl FileInfo {
|
|||
if annotation.is_primary {
|
||||
Style::UnderlinePrimary
|
||||
} else {
|
||||
Style::OldSkoolNote
|
||||
Style::OldSchoolNote
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -704,10 +614,10 @@ impl FileInfo {
|
|||
|
||||
// If there are no annotations that need text, we're done.
|
||||
if labeled_annotations.is_empty() {
|
||||
return styled_buffer.render(source_kind);
|
||||
return styled_buffer.render();
|
||||
}
|
||||
if old_school {
|
||||
return styled_buffer.render(source_kind);
|
||||
return styled_buffer.render();
|
||||
}
|
||||
|
||||
// Now add the text labels. We try, when possible, to stick the rightmost
|
||||
|
|
@ -767,7 +677,7 @@ impl FileInfo {
|
|||
|
||||
// If that's the last annotation, we're done
|
||||
if labeled_annotations.is_empty() {
|
||||
return styled_buffer.render(source_kind);
|
||||
return styled_buffer.render();
|
||||
}
|
||||
|
||||
for (index, annotation) in labeled_annotations.iter().enumerate() {
|
||||
|
|
@ -796,10 +706,11 @@ impl FileInfo {
|
|||
}
|
||||
}
|
||||
|
||||
styled_buffer.render(source_kind)
|
||||
styled_buffer.render()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn prepend_prefixes(rendered_lines: &mut [RenderedLine], format_mode: &FormatMode) {
|
||||
let old_school = match *format_mode {
|
||||
FormatMode::OriginalErrorFormat => true,
|
||||
|
|
@ -882,6 +793,7 @@ fn trim_lines(rendered_lines: &mut [RenderedLine]) {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl Line {
|
||||
fn new(line_index: usize) -> Line {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ use std::rc::Rc;
|
|||
|
||||
use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute};
|
||||
use errors;
|
||||
use errors::snippet::{RenderedLine, SnippetData};
|
||||
use errors::snippet::{SnippetData};
|
||||
use config;
|
||||
use entry::{self, EntryPointType};
|
||||
use ext::base::{ExtCtxt, DummyMacroLoader};
|
||||
|
|
|
|||
|
|
@ -568,7 +568,7 @@ impl Sub for CharPos {
|
|||
//
|
||||
|
||||
/// A source code location used for error reporting
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Loc {
|
||||
/// Information about the original source
|
||||
pub file: Rc<FileMap>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue