Skip to content

Compute widths properly when displaying spans in error messages #21499

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 58 additions & 23 deletions src/libsyntax/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,42 +483,61 @@ fn highlight_lines(err: &mut EmitterWriter,
// how many digits must be indent past?
while num > 0 { num /= 10; digits += 1; }

// indent past |name:## | and the 0-offset column location
let left = fm.name.len() + digits + lo.col.to_usize() + 3;
let mut s = String::new();
// Skip is the number of characters we need to skip because they are
// part of the 'filename:line ' part of the previous line.
let skip = fm.name.len() + digits + 3;
let skip = fm.name.width(false) + digits + 3;
for _ in 0..skip {
s.push(' ');
}
if let Some(orig) = fm.get_line(lines.lines[0]) {
for pos in 0..left - skip {
let cur_char = orig.as_bytes()[pos] as char;
let mut col = skip;
let mut lastc = ' ';
let mut iter = orig.chars().enumerate();
for (pos, ch) in iter.by_ref() {
lastc = ch;
if pos >= lo.col.to_usize() { break; }
// Whenever a tab occurs on the previous line, we insert one on
// the error-point-squiggly-line as well (instead of a space).
// That way the squiggly line will usually appear in the correct
// position.
match cur_char {
'\t' => s.push('\t'),
_ => s.push(' '),
};
match ch {
'\t' => {
col += 8 - col%8;
s.push('\t');
},
c => for _ in 0..c.width(false).unwrap_or(0) {
col += 1;
s.push(' ');
},
}
}
}

try!(write!(&mut err.dst, "{}", s));
let mut s = String::from_str("^");
let hi = cm.lookup_char_pos(sp.hi);
if hi.col != lo.col {
// the ^ already takes up one space
let num_squigglies = hi.col.to_usize() - lo.col.to_usize() - 1;
for _ in 0..num_squigglies {
s.push('~');
try!(write!(&mut err.dst, "{}", s));
let mut s = String::from_str("^");
let count = match lastc {
// Most terminals have a tab stop every eight columns by default
'\t' => 8 - col%8,
_ => lastc.width(false).unwrap_or(1),
};
col += count;
s.extend(::std::iter::repeat('~').take(count - 1));
let hi = cm.lookup_char_pos(sp.hi);
if hi.col != lo.col {
for (pos, ch) in iter {
if pos >= hi.col.to_usize() { break; }
let count = match ch {
'\t' => 8 - col%8,
_ => ch.width(false).unwrap_or(0),
};
col += count;
s.extend(::std::iter::repeat('~').take(count));
}
}
try!(print_maybe_styled(err,
&format!("{}\n", s)[],
term::attr::ForegroundColor(lvl.color())));
}
try!(print_maybe_styled(err,
&format!("{}\n", s)[],
term::attr::ForegroundColor(lvl.color())));
}
Ok(())
}
Expand Down Expand Up @@ -559,12 +578,28 @@ fn custom_highlight_lines(w: &mut EmitterWriter,
}
let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1]+1);
let hi = cm.lookup_char_pos(sp.hi);
// Span seems to use half-opened interval, so subtract 1
let skip = last_line_start.len() + hi.col.to_usize() - 1;
let skip = last_line_start.width(false);
let mut s = String::new();
for _ in 0..skip {
s.push(' ');
}
if let Some(orig) = fm.get_line(lines[0]) {
let iter = orig.chars().enumerate();
for (pos, ch) in iter {
// Span seems to use half-opened interval, so subtract 1
if pos >= hi.col.to_usize() - 1 { break; }
// Whenever a tab occurs on the previous line, we insert one on
// the error-point-squiggly-line as well (instead of a space).
// That way the squiggly line will usually appear in the correct
// position.
match ch {
'\t' => s.push('\t'),
c => for _ in 0..c.width(false).unwrap_or(0) {
s.push(' ');
},
}
}
}
s.push('^');
s.push('\n');
print_maybe_styled(w,
Expand Down
32 changes: 32 additions & 0 deletions src/test/run-make/unicode-input/span_length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,36 @@ fn main() {
.collect::<String>());
assert!(err.contains(expected_span.as_slice()));
}

// Test multi-column characters and tabs
{
let _ = write!(&mut File::create(&main_file).unwrap(),
r#"extern "路濫狼á́́" fn foo() {{}} extern "路濫狼á́" fn bar() {{}}"#);
}

// Extra characters. Every line is preceded by `filename:lineno <actual code>`
let offset = main_file.as_str().unwrap().len() + 3;

let result = Command::new("sh")
.arg("-c")
.arg(format!("{} {}",
rustc,
main_file.as_str()
.unwrap()).as_slice())
.output().unwrap();

let err = String::from_utf8_lossy(result.error.as_slice());

// Test both the length of the snake and the leading spaces up to it

// First snake is 8 ~s long, with 7 preceding spaces (excluding file name/line offset)
let expected_span = format!("\n{}^{}\n",
repeat(" ").take(offset + 7).collect::<String>(),
repeat("~").take(8).collect::<String>());
assert!(err.contains(expected_span.as_slice()));
// Second snake is 8 ~s long, with 36 preceding spaces
let expected_span = format!("\n{}^{}\n",
repeat(" ").take(offset + 36).collect::<String>(),
repeat("~").take(8).collect::<String>());
assert!(err.contains(expected_span.as_slice()));
}