formatter: handle tabs

Transform these into whitespace so we can sensibly align the ^^ markers
with the text.

Change-Id: I151c0e55bc0a02c1cff6e381cb9839c9f9abdaf6
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48694
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Ben Clayton 2021-04-27 18:01:28 +00:00 committed by Commit Bot service account
parent 3fe2779402
commit 4c0b7807f8
3 changed files with 105 additions and 49 deletions

View File

@ -211,34 +211,53 @@ void Formatter::format(const Diagnostic& diag, State& state) const {
state.newline(); state.newline();
state.set_style({Color::kDefault, false}); state.set_style({Color::kDefault, false});
for (size_t line = rng.begin.line; line <= rng.end.line; line++) { for (size_t line_num = rng.begin.line;
if (line < src.file_content->lines.size() + 1) { (line_num <= rng.end.line) && (src.file_content->lines.size() + 1);
auto len = src.file_content->lines[line - 1].size(); line_num++) {
auto& line = src.file_content->lines[line_num - 1];
auto line_len = line.size();
state << src.file_content->lines[line - 1]; for (auto c : line) {
if (c == '\t') {
state.repeat(' ', style_.tab_width);
} else {
state << c;
}
}
state.newline(); state.newline();
state.set_style({Color::kCyan, false}); state.set_style({Color::kCyan, false});
if (line == rng.begin.line && line == rng.end.line) { // Count the number of glyphs in the line span.
// start and end use 1-based indexing .
auto num_glyphs = [&](size_t start, size_t end) {
size_t count = 0;
start = (start > 0) ? (start - 1) : 0;
end = (end > 0) ? (end - 1) : 0;
for (size_t i = start; (i < end) && (i < line_len); i++) {
count += (line[i] == '\t') ? style_.tab_width : 1;
}
return count;
};
if (line_num == rng.begin.line && line_num == rng.end.line) {
// Single line // Single line
state.repeat(' ', rng.begin.column - 1); state.repeat(' ', num_glyphs(1, rng.begin.column));
state.repeat('^', state.repeat('^', std::max<size_t>(
std::max<size_t>(rng.end.column - rng.begin.column, 1)); num_glyphs(rng.begin.column, rng.end.column), 1));
} else if (line == rng.begin.line) { } else if (line_num == rng.begin.line) {
// Start of multi-line // Start of multi-line
state.repeat(' ', rng.begin.column - 1); state.repeat(' ', num_glyphs(1, rng.begin.column));
state.repeat('^', len - (rng.begin.column - 1)); state.repeat('^', num_glyphs(rng.begin.column, line_len + 1));
} else if (line == rng.end.line) { } else if (line_num == rng.end.line) {
// End of multi-line // End of multi-line
state.repeat('^', rng.end.column - 1); state.repeat('^', num_glyphs(1, rng.end.column));
} else { } else {
// Middle of multi-line // Middle of multi-line
state.repeat('^', len); state.repeat('^', num_glyphs(1, line_len + 1));
} }
state.newline(); state.newline();
} }
}
state.set_style({}); state.set_style({});
} }

View File

@ -37,6 +37,8 @@ class Formatter {
bool print_line = true; bool print_line = true;
/// print a newline at the end of a diagnostic list /// print a newline at the end of a diagnostic list
bool print_newline_at_end = true; bool print_newline_at_end = true;
/// width of a tab character
size_t tab_width = 2u;
}; };
/// Constructor for the formatter using a default style. /// Constructor for the formatter using a default style.

View File

@ -21,7 +21,7 @@ namespace tint {
namespace diag { namespace diag {
namespace { namespace {
constexpr const char* content = constexpr const char* content = // Note: words are tab-delimited
R"(the cat says meow R"(the cat says meow
the dog says woof the dog says woof
the snake says quack the snake says quack
@ -136,11 +136,46 @@ TEST_F(DiagFormatterTest, BasicWithMultiLine) {
auto got = fmt.format(List{multiline}); auto got = fmt.format(List{multiline});
auto* expect = R"(2:9: multiline auto* expect = R"(2:9: multiline
the dog says woof the dog says woof
^^^^^^^^^ ^^^^^^^^^^
the snake says quack the snake says quack
^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
the snail says ??? the snail says ???
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
)";
ASSERT_EQ(expect, got);
}
TEST_F(DiagFormatterTest, BasicWithFileSeverityLineTab4) {
Formatter fmt{{true, true, true, false, 4u}};
auto got = fmt.format(List{diag_note, diag_warn, diag_err});
auto* expect = R"(file.name:1:14 note: purr
the cat says meow
^
file.name:2:14 warning: grrr
the dog says woof
^^^^
file.name:3:16 error abc123: hiss
the snake says quack
^^^^^
)";
ASSERT_EQ(expect, got);
}
TEST_F(DiagFormatterTest, BasicWithMultiLineTab4) {
Diagnostic multiline{Severity::Warning,
Source{Source::Range{{2, 9}, {4, 15}}, &file},
"multiline"};
Formatter fmt{{false, false, true, false, 4u}};
auto got = fmt.format(List{multiline});
auto* expect = R"(2:9: multiline
the dog says woof
^^^^^^^^^^^^
the snake says quack
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
the snail says ???
^^^^^^^^^^^^^^^^^^^^
)"; )";
ASSERT_EQ(expect, got); ASSERT_EQ(expect, got);
} }