Replace tabs earlier in diagnostics

This replaces tabs earlier in the diagnostics emitting process, which allows
various margin calculations to ignore the existence of tabs. It does add a
string copy for the source lines that are emitted.
This commit is contained in:
J. Ryan Stinnett 2020-12-06 00:39:07 +00:00
parent 8ca8b7724f
commit 3537bd80ff
2 changed files with 23 additions and 29 deletions

View File

@ -644,6 +644,8 @@ impl EmitterWriter {
code_offset: usize,
margin: Margin,
) {
// Tabs are assumed to have been replaced by spaces in calling code.
assert!(!source_string.contains('\t'));
let line_len = source_string.len();
// Create the source line we will highlight.
let left = margin.left(line_len);
@ -707,7 +709,7 @@ impl EmitterWriter {
}
let source_string = match file.get_line(line.line_index - 1) {
Some(s) => s,
Some(s) => replace_tabs(&*s),
None => return Vec::new(),
};
@ -1376,8 +1378,17 @@ impl EmitterWriter {
let file = annotated_file.file.clone();
let line = &annotated_file.lines[line_idx];
if let Some(source_string) = file.get_line(line.line_index - 1) {
let leading_whitespace =
source_string.chars().take_while(|c| c.is_whitespace()).count();
let leading_whitespace = source_string
.chars()
.take_while(|c| c.is_whitespace())
.map(|c| {
match c {
// Tabs are displayed as 4 spaces
'\t' => 4,
_ => 1,
}
})
.sum();
if source_string.chars().any(|c| !c.is_whitespace()) {
whitespace_margin = min(whitespace_margin, leading_whitespace);
}
@ -1502,7 +1513,7 @@ impl EmitterWriter {
self.draw_line(
&mut buffer,
&unannotated_line,
&replace_tabs(&unannotated_line),
annotated_file.lines[line_idx + 1].line_index - 1,
last_buffer_line_num,
width_offset,
@ -1598,7 +1609,7 @@ impl EmitterWriter {
);
// print the suggestion
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
buffer.append(row_num, line, Style::NoStyle);
buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
row_num += 1;
}
@ -1930,6 +1941,10 @@ impl FileWithAnnotatedLines {
}
}
fn replace_tabs(str: &str) -> String {
str.replace('\t', " ")
}
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
buffer.puts(line, col, "| ", Style::LineNumber);
}

View File

@ -13,34 +13,13 @@ impl StyledBuffer {
StyledBuffer { text: vec![], styles: vec![] }
}
fn replace_tabs(&mut self) {
for (line_pos, line) in self.text.iter_mut().enumerate() {
let mut tab_pos = vec![];
for (pos, c) in line.iter().enumerate() {
if *c == '\t' {
tab_pos.push(pos);
}
}
// start with the tabs at the end of the line to replace them with 4 space chars
for pos in tab_pos.iter().rev() {
assert_eq!(line.remove(*pos), '\t');
// fix the position of the style to match up after replacing the tabs
let s = self.styles[line_pos].remove(*pos);
for _ in 0..4 {
line.insert(*pos, ' ');
self.styles[line_pos].insert(*pos, s);
}
}
}
}
pub fn render(&self) -> Vec<Vec<StyledString>> {
// Tabs are assumed to have been replaced by spaces in calling code.
assert!(self.text.iter().all(|r| !r.contains(&'\t')));
pub fn render(&mut self) -> Vec<Vec<StyledString>> {
let mut output: Vec<Vec<StyledString>> = vec![];
let mut styled_vec: Vec<StyledString> = vec![];
// before we render, replace tabs with spaces
self.replace_tabs();
for (row, row_style) in self.text.iter().zip(&self.styles) {
let mut current_style = Style::NoStyle;
let mut current_text = String::new();