Skip to content

Commit ac134f7

Browse files
committed
Auto merge of #21499 - P1start:issue-8706, r=huonw
Closes #8706.
2 parents c3e1f77 + d244f09 commit ac134f7

File tree

2 files changed

+90
-23
lines changed

2 files changed

+90
-23
lines changed

src/libsyntax/diagnostic.rs

+58-23
Original file line numberDiff line numberDiff line change
@@ -483,42 +483,61 @@ fn highlight_lines(err: &mut EmitterWriter,
483483
// how many digits must be indent past?
484484
while num > 0 { num /= 10; digits += 1; }
485485

486-
// indent past |name:## | and the 0-offset column location
487-
let left = fm.name.len() + digits + lo.col.to_usize() + 3;
488486
let mut s = String::new();
489487
// Skip is the number of characters we need to skip because they are
490488
// part of the 'filename:line ' part of the previous line.
491-
let skip = fm.name.len() + digits + 3;
489+
let skip = fm.name.width(false) + digits + 3;
492490
for _ in 0..skip {
493491
s.push(' ');
494492
}
495493
if let Some(orig) = fm.get_line(lines.lines[0]) {
496-
for pos in 0..left - skip {
497-
let cur_char = orig.as_bytes()[pos] as char;
494+
let mut col = skip;
495+
let mut lastc = ' ';
496+
let mut iter = orig.chars().enumerate();
497+
for (pos, ch) in iter.by_ref() {
498+
lastc = ch;
499+
if pos >= lo.col.to_usize() { break; }
498500
// Whenever a tab occurs on the previous line, we insert one on
499501
// the error-point-squiggly-line as well (instead of a space).
500502
// That way the squiggly line will usually appear in the correct
501503
// position.
502-
match cur_char {
503-
'\t' => s.push('\t'),
504-
_ => s.push(' '),
505-
};
504+
match ch {
505+
'\t' => {
506+
col += 8 - col%8;
507+
s.push('\t');
508+
},
509+
c => for _ in 0..c.width(false).unwrap_or(0) {
510+
col += 1;
511+
s.push(' ');
512+
},
513+
}
506514
}
507-
}
508515

509-
try!(write!(&mut err.dst, "{}", s));
510-
let mut s = String::from_str("^");
511-
let hi = cm.lookup_char_pos(sp.hi);
512-
if hi.col != lo.col {
513-
// the ^ already takes up one space
514-
let num_squigglies = hi.col.to_usize() - lo.col.to_usize() - 1;
515-
for _ in 0..num_squigglies {
516-
s.push('~');
516+
try!(write!(&mut err.dst, "{}", s));
517+
let mut s = String::from_str("^");
518+
let count = match lastc {
519+
// Most terminals have a tab stop every eight columns by default
520+
'\t' => 8 - col%8,
521+
_ => lastc.width(false).unwrap_or(1),
522+
};
523+
col += count;
524+
s.extend(::std::iter::repeat('~').take(count - 1));
525+
let hi = cm.lookup_char_pos(sp.hi);
526+
if hi.col != lo.col {
527+
for (pos, ch) in iter {
528+
if pos >= hi.col.to_usize() { break; }
529+
let count = match ch {
530+
'\t' => 8 - col%8,
531+
_ => ch.width(false).unwrap_or(0),
532+
};
533+
col += count;
534+
s.extend(::std::iter::repeat('~').take(count));
535+
}
517536
}
537+
try!(print_maybe_styled(err,
538+
&format!("{}\n", s)[],
539+
term::attr::ForegroundColor(lvl.color())));
518540
}
519-
try!(print_maybe_styled(err,
520-
&format!("{}\n", s)[],
521-
term::attr::ForegroundColor(lvl.color())));
522541
}
523542
Ok(())
524543
}
@@ -559,12 +578,28 @@ fn custom_highlight_lines(w: &mut EmitterWriter,
559578
}
560579
let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1]+1);
561580
let hi = cm.lookup_char_pos(sp.hi);
562-
// Span seems to use half-opened interval, so subtract 1
563-
let skip = last_line_start.len() + hi.col.to_usize() - 1;
581+
let skip = last_line_start.width(false);
564582
let mut s = String::new();
565583
for _ in 0..skip {
566584
s.push(' ');
567585
}
586+
if let Some(orig) = fm.get_line(lines[0]) {
587+
let iter = orig.chars().enumerate();
588+
for (pos, ch) in iter {
589+
// Span seems to use half-opened interval, so subtract 1
590+
if pos >= hi.col.to_usize() - 1 { break; }
591+
// Whenever a tab occurs on the previous line, we insert one on
592+
// the error-point-squiggly-line as well (instead of a space).
593+
// That way the squiggly line will usually appear in the correct
594+
// position.
595+
match ch {
596+
'\t' => s.push('\t'),
597+
c => for _ in 0..c.width(false).unwrap_or(0) {
598+
s.push(' ');
599+
},
600+
}
601+
}
602+
}
568603
s.push('^');
569604
s.push('\n');
570605
print_maybe_styled(w,

src/test/run-make/unicode-input/span_length.rs

+32
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,36 @@ fn main() {
6565
.collect::<String>());
6666
assert!(err.contains(expected_span.as_slice()));
6767
}
68+
69+
// Test multi-column characters and tabs
70+
{
71+
let _ = write!(&mut File::create(&main_file).unwrap(),
72+
r#"extern "路濫狼á́́" fn foo() {{}} extern "路濫狼á́" fn bar() {{}}"#);
73+
}
74+
75+
// Extra characters. Every line is preceded by `filename:lineno <actual code>`
76+
let offset = main_file.as_str().unwrap().len() + 3;
77+
78+
let result = Command::new("sh")
79+
.arg("-c")
80+
.arg(format!("{} {}",
81+
rustc,
82+
main_file.as_str()
83+
.unwrap()).as_slice())
84+
.output().unwrap();
85+
86+
let err = String::from_utf8_lossy(result.error.as_slice());
87+
88+
// Test both the length of the snake and the leading spaces up to it
89+
90+
// First snake is 8 ~s long, with 7 preceding spaces (excluding file name/line offset)
91+
let expected_span = format!("\n{}^{}\n",
92+
repeat(" ").take(offset + 7).collect::<String>(),
93+
repeat("~").take(8).collect::<String>());
94+
assert!(err.contains(expected_span.as_slice()));
95+
// Second snake is 8 ~s long, with 36 preceding spaces
96+
let expected_span = format!("\n{}^{}\n",
97+
repeat(" ").take(offset + 36).collect::<String>(),
98+
repeat("~").take(8).collect::<String>());
99+
assert!(err.contains(expected_span.as_slice()));
68100
}

0 commit comments

Comments
 (0)