crates: vendor annotate-snippets crate

This merely adds the crate to our repository. Some cosmetic changes are
made to make it work in our repo and follow our conventions, such as
changing the name to `ruff_annotate_snippets`. We retain the original
license information. We do drop some things, such as benchmarks, but
keep tests and examples.
This commit is contained in:
Andrew Gallant 2024-12-20 12:55:16 -05:00 committed by Andrew Gallant
parent 4f3209a3ec
commit 9c27c57b5b
58 changed files with 6171 additions and 8 deletions

View file

@ -0,0 +1,37 @@
#[test]
fn expected_type() {
let target = "expected_type";
let expected = snapbox::file!["../examples/expected_type.svg": TermSvg];
assert_example(target, expected);
}
#[test]
fn footer() {
let target = "footer";
let expected = snapbox::file!["../examples/footer.svg": TermSvg];
assert_example(target, expected);
}
#[test]
fn format() {
let target = "format";
let expected = snapbox::file!["../examples/format.svg": TermSvg];
assert_example(target, expected);
}
#[test]
fn multislice() {
let target = "multislice";
let expected = snapbox::file!["../examples/multislice.svg": TermSvg];
assert_example(target, expected);
}
#[track_caller]
fn assert_example(target: &str, expected: snapbox::Data) {
let bin_path = snapbox::cmd::compile_example(target, ["--features=testing-colors"]).unwrap();
snapbox::cmd::Command::new(bin_path)
.env("CLICOLOR_FORCE", "1")
.assert()
.success()
.stdout_eq(expected.raw());
}

View file

@ -0,0 +1,36 @@
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan><tspan>: </tspan><tspan class="bold">expected `.`, `=`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> Cargo.toml:1:5</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">1 |</tspan><tspan> asdf</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,15 @@
[message]
level = "Error"
title = "expected `.`, `=`"
[[message.snippets]]
source = "asdf"
line_start = 1
origin = "Cargo.toml"
[[message.snippets.annotations]]
label = ""
level = "Error"
range = [4, 4]
[renderer]
color = true

View file

@ -0,0 +1,36 @@
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan><tspan>: </tspan><tspan class="bold">expected `.`, `=`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> Cargo.toml:1:3</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">1 |</tspan><tspan> asf</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">'d' belongs here</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,15 @@
[message]
level = "Error"
title = "expected `.`, `=`"
[[message.snippets]]
source = "asf"
line_start = 1
origin = "Cargo.toml"
[[message.snippets.annotations]]
label = "'d' belongs here"
level = "Error"
range = [2, 2]
[renderer]
color = true

View file

@ -0,0 +1,42 @@
<svg width="740px" height="182px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error[E0027]</tspan><tspan>: </tspan><tspan class="bold">pattern does not mention fields `lineno`, `content`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> src/display_list.rs:139:32</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">139 |</tspan><tspan> if let DisplayLine::Source {</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">________________________________^</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold">140 |</tspan><tspan> </tspan><tspan class="fg-bright-red bold">|</tspan><tspan> ref mut inline_marks,</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan class="fg-bright-blue bold">141 |</tspan><tspan> </tspan><tspan class="fg-bright-red bold">|</tspan><tspan> } = body[body_idx]</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">|_________________________^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">missing fields `lineno`, `content`</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,21 @@
[message]
level = "Error"
id = "E0027"
title = "pattern does not mention fields `lineno`, `content`"
[[message.snippets]]
source = """
if let DisplayLine::Source {
ref mut inline_marks,
} = body[body_idx]
"""
line_start = 139
origin = "src/display_list.rs"
fold = false
[[message.snippets.annotations]]
label = "missing fields `lineno`, `content`"
level = "Error"
range = [31, 128]
[renderer]
color = true

View file

@ -0,0 +1,40 @@
<svg width="740px" height="164px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error[E####]</tspan><tspan>: </tspan><tspan class="bold">spacing error found</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> foo.txt:26:12</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">26 |</tspan><tspan> This is an example</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^^^^^^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">this should not be on separate lines</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold">27 |</tspan><tspan> of an edge case of an annotation overflowing</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan class="fg-bright-blue bold">28 |</tspan><tspan> to exactly one character on next line.</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,21 @@
[message]
level = "Error"
id = "E####"
title = "spacing error found"
[[message.snippets]]
source = """
This is an example
of an edge case of an annotation overflowing
to exactly one character on next line.
"""
line_start = 26
origin = "foo.txt"
fold = false
[[message.snippets.annotations]]
label = "this should not be on separate lines"
level = "Error"
range = [11, 19]
[renderer]
color = true

View file

@ -0,0 +1,36 @@
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan><tspan>: </tspan><tspan class="bold">expected `.`, `=`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> Cargo.toml:1:5</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">1 |</tspan><tspan> asdf</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,15 @@
[message]
level = "Error"
title = "expected `.`, `=`"
[[message.snippets]]
source = "asdf"
line_start = 1
origin = "Cargo.toml"
[[message.snippets.annotations]]
label = ""
level = "Error"
range = [4, 5]
[renderer]
color = true

View file

@ -0,0 +1,36 @@
<svg width="1356px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan><tspan>: </tspan><tspan class="bold">invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> &lt;file&gt;:7:1</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">7 |</tspan><tspan> "haha this isn't a valid name 🐛" = { package = "libc", version = "0.1" }</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,18 @@
[message]
title = "invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)"
level = "Error"
[[message.snippets]]
source = """
"haha this isn't a valid name 🐛" = { package = "libc", version = "0.1" }
"""
line_start = 7
origin = "<file>"
[[message.snippets.annotations]]
label = ""
level = "Error"
range = [0, 35]
[renderer]
color = true

View file

@ -0,0 +1,49 @@
<svg width="869px" height="236px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.fg-yellow { fill: #AA5500 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error[E0308]</tspan><tspan>: </tspan><tspan class="bold">mismatched types</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> src/format.rs:51:6</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">51 |</tspan><tspan> ) -&gt; Option&lt;String&gt; {</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-yellow bold">--------------</tspan><tspan> </tspan><tspan class="fg-yellow bold">expected `std::option::Option&lt;std::string::String&gt;` because of return type</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold">52 |</tspan><tspan> </tspan><tspan class="fg-bright-red bold">/</tspan><tspan> for ann in annotations {</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan class="fg-bright-blue bold">53 |</tspan><tspan> </tspan><tspan class="fg-bright-red bold">|</tspan><tspan> match (ann.range.0, ann.range.1) {</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan class="fg-bright-blue bold">...</tspan><tspan> </tspan><tspan class="fg-bright-red bold">|</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan class="fg-bright-blue bold">71 |</tspan><tspan> </tspan><tspan class="fg-bright-red bold">|</tspan><tspan> }</tspan>
</tspan>
<tspan x="10px" y="190px"><tspan class="fg-bright-blue bold">72 |</tspan><tspan> </tspan><tspan class="fg-bright-red bold">|</tspan><tspan> }</tspan>
</tspan>
<tspan x="10px" y="208px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">|_____^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">expected enum `std::option::Option`, found ()</tspan>
</tspan>
<tspan x="10px" y="226px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,44 @@
[message]
level = "Error"
id = "E0308"
title = "mismatched types"
[[message.snippets]]
source = """
) -> Option<String> {
for ann in annotations {
match (ann.range.0, ann.range.1) {
(None, None) => continue,
(Some(start), Some(end)) if start > end_index || end < start_index => continue,
(Some(start), Some(end)) if start >= start_index && end <= end_index => {
let label = if let Some(ref label) = ann.label {
format!(" {}", label)
} else {
String::from("")
};
return Some(format!(
"{}{}{}",
" ".repeat(start - start_index),
"^".repeat(end - start),
label
));
}
_ => continue,
}
}
"""
line_start = 51
origin = "src/format.rs"
fold = true
[[message.snippets.annotations]]
label = "expected `std::option::Option<std::string::String>` because of return type"
level = "Warning"
range = [5, 19]
[[message.snippets.annotations]]
label = "expected enum `std::option::Option`, found ()"
level = "Error"
range = [22, 766]
[renderer]
color = true

View file

@ -0,0 +1,37 @@
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.fg-yellow { fill: #AA5500 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> path/to/error.rs:3:1</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">3 |</tspan><tspan> invalid syntax</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-yellow bold">--------------</tspan><tspan> </tspan><tspan class="fg-yellow bold">error here</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,20 @@
[message]
level = "Error"
title = ""
[[message.snippets]]
source = """
invalid syntax
"""
line_start = 1
origin = "path/to/error.rs"
fold = true
[[message.snippets.annotations]]
label = "error here"
level = "Warning"
range = [2,16]
[renderer]
color = true

View file

@ -0,0 +1,36 @@
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error[E0308]</tspan><tspan>: </tspan><tspan class="bold">invalid type: integer `20`, expected a bool</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> Cargo.toml:11:13</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">11 |</tspan><tspan> workspace = 20</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,29 @@
[message]
level = "Error"
id = "E0308"
title = "invalid type: integer `20`, expected a bool"
[[message.snippets]]
source = """
[workspace]
[package]
name = "hello"
version = "1.0.0"
license = "MIT"
rust-version = "1.70"
edition = "2021"
[lints]
workspace = 20
"""
line_start = 1
origin = "Cargo.toml"
fold = true
[[message.snippets.annotations]]
label = ""
level = "Error"
range = [132, 134]
[renderer]
color = true

View file

@ -0,0 +1,36 @@
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error[E0308]</tspan><tspan>: </tspan><tspan class="bold">invalid type: integer `20`, expected a lints table</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> Cargo.toml:1:9</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">1 |</tspan><tspan> lints = 20</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,28 @@
[message]
level = "Error"
id = "E0308"
title = "invalid type: integer `20`, expected a lints table"
[[message.snippets]]
source = """
lints = 20
[workspace]
[package]
name = "hello"
version = "1.0.0"
license = "MIT"
rust-version = "1.70"
edition = "2021"
"""
line_start = 1
origin = "Cargo.toml"
fold = true
[[message.snippets.annotations]]
label = ""
level = "Error"
range = [8, 10]
[renderer]
color = true

View file

@ -0,0 +1,49 @@
<svg width="911px" height="236px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.fg-yellow { fill: #AA5500 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan><tspan>: </tspan><tspan class="bold">expected one of `.`, `;`, `?`, or an operator, found `for`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> /code/rust/src/test/ui/annotate-snippet/suggestion.rs:4:5</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">4 |</tspan><tspan> let x = vec![1];</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-yellow bold">-</tspan><tspan> </tspan><tspan class="fg-yellow bold">move occurs because `x` has type `std::vec::Vec&lt;i32&gt;`, which does not implement the `Copy` trait</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan class="fg-bright-blue bold">7 |</tspan><tspan> let y = x;</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-yellow bold">-</tspan><tspan> </tspan><tspan class="fg-yellow bold">value moved here</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="190px"><tspan class="fg-bright-blue bold">9 |</tspan><tspan> x;</tspan>
</tspan>
<tspan x="10px" y="208px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">value used here after move</tspan>
</tspan>
<tspan x="10px" y="226px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1,31 @@
[message]
level = "Error"
title = "expected one of `.`, `;`, `?`, or an operator, found `for`"
[[message.snippets]]
source = "let x = vec![1];"
line_start = 4
origin = "/code/rust/src/test/ui/annotate-snippet/suggestion.rs"
[[message.snippets.annotations]]
label = "move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait"
level = "Warning"
range = [4, 5]
[[message.snippets]]
source = "let y = x;"
line_start = 7
[[message.snippets.annotations]]
label = "value moved here"
level = "Warning"
range = [8, 9]
[[message.snippets]]
source = "x;"
line_start = 9
[[message.snippets.annotations]]
label = "value used here after move"
level = "Error"
range = [0, 1]
[renderer]
color = true

View file

@ -0,0 +1,54 @@
<svg width="768px" height="290px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan class="fg-bright-blue bold"> 96 |</tspan><tspan> fn add_title_line(result: &amp;mut Vec&lt;String&gt;, main_annotation: Option&lt;&amp;Annotation&gt;) {</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold"> 97 |</tspan><tspan> if let Some(annotation) = main_annotation {</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">Variable defined here</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> 98 |</tspan><tspan> result.push(format_title_line(</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan class="fg-bright-blue bold"> 99 |</tspan><tspan> &amp;annotation.annotation_type,</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">Referenced here</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan class="fg-bright-blue bold">100 |</tspan><tspan> None,</tspan>
</tspan>
<tspan x="10px" y="190px"><tspan class="fg-bright-blue bold">101 |</tspan><tspan> &amp;annotation.label,</tspan>
</tspan>
<tspan x="10px" y="208px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">Referenced again here</tspan>
</tspan>
<tspan x="10px" y="226px"><tspan class="fg-bright-blue bold">102 |</tspan><tspan> ));</tspan>
</tspan>
<tspan x="10px" y="244px"><tspan class="fg-bright-blue bold">103 |</tspan><tspan> }</tspan>
</tspan>
<tspan x="10px" y="262px"><tspan class="fg-bright-blue bold">104 |</tspan><tspan> }</tspan>
</tspan>
<tspan x="10px" y="280px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,32 @@
[message]
level = "Error"
title = ""
[[message.snippets]]
source = """
fn add_title_line(result: &mut Vec<String>, main_annotation: Option<&Annotation>) {
if let Some(annotation) = main_annotation {
result.push(format_title_line(
&annotation.annotation_type,
None,
&annotation.label,
));
}
}
"""
line_start = 96
[[message.snippets.annotations]]
label = "Variable defined here"
level = "Error"
range = [100, 110]
[[message.snippets.annotations]]
label = "Referenced here"
level = "Error"
range = [184, 194]
[[message.snippets.annotations]]
label = "Referenced again here"
level = "Error"
range = [243, 253]
[renderer]
color = true

View file

@ -0,0 +1,43 @@
<svg width="740px" height="182px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.fg-yellow { fill: #AA5500 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan><tspan>: </tspan><tspan class="bold">expected one of `.`, `;`, `?`, or an operator, found `for`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> src/format_color.rs:171:9</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">169 |</tspan><tspan> })</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-yellow bold">-</tspan><tspan> </tspan><tspan class="fg-yellow bold">expected one of `.`, `;`, `?`, or an operator here</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold">170 |</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan class="fg-bright-blue bold">171 |</tspan><tspan> for line in &amp;self.body {</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">unexpected token</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,22 @@
[message]
level = "Error"
title = "expected one of `.`, `;`, `?`, or an operator, found `for`"
[[message.snippets]]
source = """
})
for line in &self.body {"""
line_start = 169
origin = "src/format_color.rs"
[[message.snippets.annotations]]
label = "unexpected token"
level = "Error"
range = [20, 23]
[[message.snippets.annotations]]
label = "expected one of `.`, `;`, `?`, or an operator here"
level = "Warning"
range = [10, 11]
[renderer]
color = true

View file

@ -0,0 +1,36 @@
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error[E0308]</tspan><tspan>: </tspan><tspan class="bold">mismatched types</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> $DIR/whitespace-trimming.rs:4:193</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">LL |</tspan><tspan> </tspan><tspan class="fg-bright-blue bold">...</tspan><tspan> let _: () = 42;</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">expected (), found integer</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,18 @@
[message]
level = "Error"
id = "E0308"
title = "mismatched types"
[[message.snippets]]
source = " let _: () = 42;"
line_start = 4
origin = "$DIR/whitespace-trimming.rs"
[[message.snippets.annotations]]
label = "expected (), found integer"
level = "Error"
range = [192, 194]
[renderer]
color = true
anonymized_line_numbers = true

View file

@ -0,0 +1,36 @@
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error[E0308]</tspan><tspan>: </tspan><tspan class="bold">mismatched types</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> $DIR/whitespace-trimming.rs:4:193</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">LL |</tspan><tspan> </tspan><tspan class="fg-bright-blue bold">...</tspan><tspan> let _: () = 42ñ</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">expected (), found integer</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,18 @@
[message]
level = "Error"
id = "E0308"
title = "mismatched types"
[[message.snippets]]
source = " let _: () = 42ñ"
line_start = 4
origin = "$DIR/whitespace-trimming.rs"
[[message.snippets.annotations]]
label = "expected (), found integer"
level = "Error"
range = [192, 194]
[renderer]
color = true
anonymized_line_numbers = true

View file

@ -0,0 +1,40 @@
<svg width="1196px" height="164px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-bright-blue { fill: #5555FF }
.fg-bright-red { fill: #FF5555 }
.container {
padding: 0 10px;
line-height: 18px;
}
.bold { font-weight: bold; }
tspan {
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
white-space: pre;
line-height: 18px;
}
</style>
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error[E0308]</tspan><tspan>: </tspan><tspan class="bold">mismatched types</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--&gt;</tspan><tspan> $DIR/non-whitespace-trimming.rs:4:242</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">LL |</tspan><tspan> </tspan><tspan class="fg-bright-blue bold">...</tspan><tspan> = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () </tspan><tspan class="fg-bright-blue bold">...</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">^^</tspan><tspan> </tspan><tspan class="fg-bright-red bold">expected `()`, found integer</tspan>
</tspan>
<tspan x="10px" y="118px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">|</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan><tspan> </tspan><tspan class="fg-bright-red bold">expected due to this</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> </tspan><tspan class="fg-bright-blue bold">|</tspan>
</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,26 @@
[message]
level = "Error"
id = "E0308"
title = "mismatched types"
[[message.snippets]]
source = """
let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = ();
"""
line_start = 4
origin = "$DIR/non-whitespace-trimming.rs"
[[message.snippets.annotations]]
label = "expected `()`, found integer"
level = "Error"
range = [241, 243]
[[message.snippets.annotations]]
label = "expected due to this"
level = "Error"
range = [236, 238]
[renderer]
anonymized_line_numbers = true
color = true

View file

@ -0,0 +1,130 @@
use serde::Deserialize;
use std::ops::Range;
use ruff_annotate_snippets::renderer::DEFAULT_TERM_WIDTH;
use ruff_annotate_snippets::{Annotation, Level, Message, Renderer, Snippet};
#[derive(Deserialize)]
pub(crate) struct Fixture {
#[serde(default)]
pub(crate) renderer: RendererDef,
pub(crate) message: MessageDef,
}
#[derive(Deserialize)]
pub struct MessageDef {
#[serde(with = "LevelDef")]
pub level: Level,
pub title: String,
#[serde(default)]
pub id: Option<String>,
#[serde(default)]
pub footer: Vec<MessageDef>,
pub snippets: Vec<SnippetDef>,
}
impl<'a> From<&'a MessageDef> for Message<'a> {
fn from(val: &'a MessageDef) -> Self {
let MessageDef {
level,
title,
id,
footer,
snippets,
} = val;
let mut message = level.title(title);
if let Some(id) = id {
message = message.id(id);
}
message = message.snippets(snippets.iter().map(Snippet::from));
message = message.footers(footer.iter().map(Into::into));
message
}
}
#[derive(Deserialize)]
pub struct SnippetDef {
pub source: String,
pub line_start: usize,
pub origin: Option<String>,
pub annotations: Vec<AnnotationDef>,
#[serde(default)]
pub fold: bool,
}
impl<'a> From<&'a SnippetDef> for Snippet<'a> {
fn from(val: &'a SnippetDef) -> Self {
let SnippetDef {
source,
line_start,
origin,
annotations,
fold,
} = val;
let mut snippet = Snippet::source(source).line_start(*line_start).fold(*fold);
if let Some(origin) = origin {
snippet = snippet.origin(origin);
}
snippet = snippet.annotations(annotations.iter().map(Into::into));
snippet
}
}
#[derive(Deserialize)]
pub struct AnnotationDef {
pub range: Range<usize>,
pub label: String,
#[serde(with = "LevelDef")]
pub level: Level,
}
impl<'a> From<&'a AnnotationDef> for Annotation<'a> {
fn from(val: &'a AnnotationDef) -> Self {
let AnnotationDef {
range,
label,
level,
} = val;
level.span(range.start..range.end).label(label)
}
}
#[allow(dead_code)]
#[derive(Deserialize)]
#[serde(remote = "Level")]
enum LevelDef {
Error,
Warning,
Info,
Note,
Help,
}
#[derive(Default, Deserialize)]
pub struct RendererDef {
#[serde(default)]
anonymized_line_numbers: bool,
#[serde(default)]
term_width: Option<usize>,
#[serde(default)]
color: bool,
}
impl From<RendererDef> for Renderer {
fn from(val: RendererDef) -> Self {
let RendererDef {
anonymized_line_numbers,
term_width,
color,
} = val;
let renderer = if color {
Renderer::styled()
} else {
Renderer::plain()
};
renderer
.anonymized_line_numbers(anonymized_line_numbers)
.term_width(term_width.unwrap_or(DEFAULT_TERM_WIDTH))
}
}

View file

@ -0,0 +1,42 @@
mod deserialize;
use crate::deserialize::Fixture;
use ruff_annotate_snippets::{Message, Renderer};
use snapbox::data::DataFormat;
use snapbox::Data;
use std::error::Error;
fn main() {
#[cfg(not(windows))]
tryfn::Harness::new("tests/fixtures/", setup, test)
.select(["*/*.toml"])
.test();
}
fn setup(input_path: std::path::PathBuf) -> tryfn::Case {
let parent = input_path
.parent()
.unwrap()
.file_name()
.unwrap()
.to_str()
.unwrap();
let file_name = input_path.file_name().unwrap().to_str().unwrap();
let name = format!("{parent}/{file_name}");
let expected = Data::read_from(&input_path.with_extension("svg"), None);
tryfn::Case {
name,
fixture: input_path,
expected,
}
}
fn test(input_path: &std::path::Path) -> Result<Data, Box<dyn Error>> {
let src = std::fs::read_to_string(input_path)?;
let fixture: Fixture = toml::from_str(&src)?;
let renderer: Renderer = fixture.renderer.into();
let message: Message<'_> = (&fixture.message).into();
let actual = renderer.render(message).to_string();
Ok(Data::from(actual).coerce_to(DataFormat::TermSvg))
}

View file

@ -0,0 +1,963 @@
// Since this is a vendored copy of `annotate-snippets`, we squash Clippy
// warnings from upstream in order to the reduce the diff. If our copy drifts
// far from upstream such that patches become impractical to apply in both
// places, then we can get rid of these suppressions and fix the lints.
#![allow(clippy::redundant_clone, clippy::should_panic_without_expect)]
use ruff_annotate_snippets::{Level, Renderer, Snippet};
use snapbox::{assert_data_eq, str};
#[test]
fn test_i_29() {
let snippets = Level::Error.title("oops").snippet(
Snippet::source("First line\r\nSecond oops line")
.origin("<current file>")
.annotation(Level::Error.span(19..23).label("oops"))
.fold(true),
);
let expected = str![[r#"
error: oops
--> <current file>:2:8
|
2 | Second oops line
| ^^^^ oops
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(snippets).to_string(), expected);
}
#[test]
fn test_point_to_double_width_characters() {
let snippets = Level::Error.title("").snippet(
Snippet::source("こんにちは、世界")
.origin("<current file>")
.annotation(Level::Error.span(18..24).label("world")),
);
let expected = str![[r#"
error
--> <current file>:1:7
|
1 |
| ^^^^ world
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(snippets).to_string(), expected);
}
#[test]
fn test_point_to_double_width_characters_across_lines() {
let snippets = Level::Error.title("").snippet(
Snippet::source("おはよう\nございます")
.origin("<current file>")
.annotation(Level::Error.span(6..22).label("Good morning")),
);
let expected = str![[r#"
error
--> <current file>:1:3
|
1 |
| _____^
2 | |
| |______^ Good morning
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(snippets).to_string(), expected);
}
#[test]
fn test_point_to_double_width_characters_multiple() {
let snippets = Level::Error.title("").snippet(
Snippet::source("お寿司\n食べたい🍣")
.origin("<current file>")
.annotation(Level::Error.span(0..9).label("Sushi1"))
.annotation(Level::Note.span(16..22).label("Sushi2")),
);
let expected = str![[r#"
error
--> <current file>:1:1
|
1 | 寿
| ^^^^^^ Sushi1
2 | 🍣
| ---- note: Sushi2
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(snippets).to_string(), expected);
}
#[test]
fn test_point_to_double_width_characters_mixed() {
let snippets = Level::Error.title("").snippet(
Snippet::source("こんにちは、新しいWorld")
.origin("<current file>")
.annotation(Level::Error.span(18..32).label("New world")),
);
let expected = str![[r#"
error
--> <current file>:1:7
|
1 | World
| ^^^^^^^^^^^ New world
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(snippets).to_string(), expected);
}
#[test]
fn test_format_title() {
let input = Level::Error.title("This is a title").id("E0001");
let expected = str![r#"error[E0001]: This is a title"#];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn test_format_snippet_only() {
let source = "This is line 1\nThis is line 2";
let input = Level::Error
.title("")
.snippet(Snippet::source(source).line_start(5402));
let expected = str![[r#"
error
|
5402 | This is line 1
5403 | This is line 2
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn test_format_snippets_continuation() {
let src_0 = "This is slice 1";
let src_1 = "This is slice 2";
let input = Level::Error
.title("")
.snippet(Snippet::source(src_0).line_start(5402).origin("file1.rs"))
.snippet(Snippet::source(src_1).line_start(2).origin("file2.rs"));
let expected = str![[r#"
error
--> file1.rs
|
5402 | This is slice 1
|
::: file2.rs
|
2 | This is slice 2
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn test_format_snippet_annotation_standalone() {
let line_1 = "This is line 1";
let line_2 = "This is line 2";
let source = [line_1, line_2].join("\n");
// In line 2
let range = 22..24;
let input = Level::Error.title("").snippet(
Snippet::source(&source)
.line_start(5402)
.annotation(Level::Info.span(range.clone()).label("Test annotation")),
);
let expected = str![[r#"
error
|
5402 | This is line 1
5403 | This is line 2
| -- info: Test annotation
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn test_format_footer_title() {
let input = Level::Error
.title("")
.footer(Level::Error.title("This __is__ a title"));
let expected = str![[r#"
error
= error: This __is__ a title
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
#[should_panic]
fn test_i26() {
let source = "short";
let label = "label";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.line_start(0)
.annotation(Level::Error.span(0..source.len() + 2).label(label)),
);
let renderer = Renderer::plain();
let _ = renderer.render(input).to_string();
}
#[test]
fn test_source_content() {
let source = "This is an example\nof content lines";
let input = Level::Error
.title("")
.snippet(Snippet::source(source).line_start(56));
let expected = str![[r#"
error
|
56 | This is an example
57 | of content lines
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn test_source_annotation_standalone_singleline() {
let source = "tests";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.line_start(1)
.annotation(Level::Help.span(0..5).label("Example string")),
);
let expected = str![[r#"
error
|
1 | tests
| ----- help: Example string
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn test_source_annotation_standalone_multiline() {
let source = "tests";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.line_start(1)
.annotation(Level::Help.span(0..5).label("Example string"))
.annotation(Level::Help.span(0..5).label("Second line")),
);
let expected = str![[r#"
error
|
1 | tests
| -----
| |
| help: Example string
| help: Second line
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn test_only_source() {
let input = Level::Error
.title("")
.snippet(Snippet::source("").origin("file.rs"));
let expected = str![[r#"
error
--> file.rs
|
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn test_anon_lines() {
let source = "This is an example\nof content lines\n\nabc";
let input = Level::Error
.title("")
.snippet(Snippet::source(source).line_start(56));
let expected = str![[r#"
error
|
LL | This is an example
LL | of content lines
LL |
LL | abc
|
"#]];
let renderer = Renderer::plain().anonymized_line_numbers(true);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn issue_130() {
let input = Level::Error.title("dummy").snippet(
Snippet::source("foo\nbar\nbaz")
.origin("file/path")
.line_start(3)
.fold(true)
.annotation(Level::Error.span(4..11)), // bar\nbaz
);
let expected = str![[r#"
error: dummy
--> file/path:4:1
|
4 | / bar
5 | | baz
| |___^
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn unterminated_string_multiline() {
let source = "\
a\"
// ...
";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.fold(true)
.annotation(Level::Error.span(0..10)), // 1..10 works
);
let expected = str![[r#"
error
--> file/path:3:1
|
3 | / a"
4 | | // ...
| |_______^
|
"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn char_and_nl_annotate_char() {
let source = "a\r\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(0..2)), // a\r
);
let expected = str![[r#"
error
--> file/path:3:1
|
3 | a
| ^
4 | b
|"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn char_eol_annotate_char() {
let source = "a\r\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(0..3)), // a\r\n
);
let expected = str![[r#"
error
--> file/path:3:1
|
3 | a
| ^
4 | b
|"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn char_eol_annotate_char_double_width() {
let snippets = Level::Error.title("").snippet(
Snippet::source("こん\r\nにちは\r\n世界")
.origin("<current file>")
.annotation(Level::Error.span(3..8)), // ん\r\n
);
let expected = str![[r#"
error
--> <current file>:1:2
|
1 |
| ^^
2 |
3 |
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(snippets).to_string(), expected);
}
#[test]
fn annotate_eol() {
let source = "a\r\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(1..2)), // \r
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| ^
4 | b
|"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn annotate_eol2() {
let source = "a\r\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(1..3)), // \r\n
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| ^
4 | b
|"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn annotate_eol3() {
let source = "a\r\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(2..3)), // \n
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| ^
4 | b
|"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn annotate_eol4() {
let source = "a\r\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(2..2)), // \n
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| ^
4 | b
|"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn annotate_eol_double_width() {
let snippets = Level::Error.title("").snippet(
Snippet::source("こん\r\nにちは\r\n世界")
.origin("<current file>")
.annotation(Level::Error.span(7..8)), // \n
);
let expected = str![[r#"
error
--> <current file>:1:3
|
1 |
| ^
2 |
3 |
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(snippets).to_string(), expected);
}
#[test]
fn multiline_eol_start() {
let source = "a\r\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(1..4)), // \r\nb
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| __^
4 | | b
| |_^
|"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiline_eol_start2() {
let source = "a\r\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(2..4)), // \nb
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| __^
4 | | b
| |_^
|"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiline_eol_start3() {
let source = "a\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(1..3)), // \nb
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| __^
4 | | b
| |_^
|"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiline_eol_start_double_width() {
let snippets = Level::Error.title("").snippet(
Snippet::source("こん\r\nにちは\r\n世界")
.origin("<current file>")
.annotation(Level::Error.span(7..11)), // \r\nに
);
let expected = str![[r#"
error
--> <current file>:1:3
|
1 |
| _____^
2 | |
| |__^
3 |
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(snippets).to_string(), expected);
}
#[test]
fn multiline_eol_start_eol_end() {
let source = "a\nb\nc";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(1..4)), // \nb\n
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| __^
4 | | b
| |__^
5 | c
|
"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiline_eol_start_eol_end2() {
let source = "a\r\nb\r\nc";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(2..5)), // \nb\r
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| __^
4 | | b
| |__^
5 | c
|
"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiline_eol_start_eol_end3() {
let source = "a\r\nb\r\nc";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(2..6)), // \nb\r\n
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| __^
4 | | b
| |__^
5 | c
|
"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiline_eol_start_eof_end() {
let source = "a\r\nb";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(1..5)), // \r\nb(EOF)
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 | a
| __^
4 | | b
| |__^
|
"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiline_eol_start_eof_end_double_width() {
let source = "\r\n";
let input = Level::Error.title("").snippet(
Snippet::source(source)
.origin("file/path")
.line_start(3)
.annotation(Level::Error.span(3..9)), // \r\nに(EOF)
);
let expected = str![[r#"
error
--> file/path:3:2
|
3 |
| ___^
4 | |
| |___^
|
"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn two_single_line_same_line() {
let source = r#"bar = { version = "0.1.0", optional = true }"#;
let input = Level::Error.title("unused optional dependency").snippet(
Snippet::source(source)
.origin("Cargo.toml")
.line_start(4)
.annotation(
Level::Error
.span(0..3)
.label("I need this to be really long so I can test overlaps"),
)
.annotation(
Level::Info
.span(27..42)
.label("This should also be long but not too long"),
),
);
let expected = str![[r#"
error: unused optional dependency
--> Cargo.toml:4:1
|
4 | bar = { version = "0.1.0", optional = true }
| ^^^ --------------- info: This should also be long but not too long
| |
| I need this to be really long so I can test overlaps
|
"#]];
let renderer = Renderer::plain().anonymized_line_numbers(false);
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multi_and_single() {
let source = r#"bar = { version = "0.1.0", optional = true }
this is another line
so is this
bar = { version = "0.1.0", optional = true }
"#;
let input = Level::Error.title("unused optional dependency").snippet(
Snippet::source(source)
.line_start(4)
.annotation(
Level::Error
.span(41..119)
.label("I need this to be really long so I can test overlaps"),
)
.annotation(
Level::Info
.span(27..42)
.label("This should also be long but not too long"),
),
);
let expected = str![[r#"
error: unused optional dependency
|
4 | bar = { version = "0.1.0", optional = true }
| ____________________________--------------^
| | |
| | info: This should also be long but not too long
5 | | this is another line
6 | | so is this
7 | | bar = { version = "0.1.0", optional = true }
| |__________________________________________^ I need this to be really long so I can test overlaps
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn two_multi_and_single() {
let source = r#"bar = { version = "0.1.0", optional = true }
this is another line
so is this
bar = { version = "0.1.0", optional = true }
"#;
let input = Level::Error.title("unused optional dependency").snippet(
Snippet::source(source)
.line_start(4)
.annotation(
Level::Error
.span(41..119)
.label("I need this to be really long so I can test overlaps"),
)
.annotation(
Level::Error
.span(8..102)
.label("I need this to be really long so I can test overlaps"),
)
.annotation(
Level::Info
.span(27..42)
.label("This should also be long but not too long"),
),
);
let expected = str![[r#"
error: unused optional dependency
|
4 | bar = { version = "0.1.0", optional = true }
| _________^__________________--------------^
| | | |
| |_________| info: This should also be long but not too long
| ||
5 | || this is another line
6 | || so is this
7 | || bar = { version = "0.1.0", optional = true }
| ||_________________________^________________^ I need this to be really long so I can test overlaps
| |__________________________|
| I need this to be really long so I can test overlaps
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn three_multi_and_single() {
let source = r#"bar = { version = "0.1.0", optional = true }
this is another line
so is this
bar = { version = "0.1.0", optional = true }
this is another line
"#;
let input = Level::Error.title("unused optional dependency").snippet(
Snippet::source(source)
.line_start(4)
.annotation(
Level::Error
.span(41..119)
.label("I need this to be really long so I can test overlaps"),
)
.annotation(
Level::Error
.span(8..102)
.label("I need this to be really long so I can test overlaps"),
)
.annotation(
Level::Error
.span(48..126)
.label("I need this to be really long so I can test overlaps"),
)
.annotation(
Level::Info
.span(27..42)
.label("This should also be long but not too long"),
),
);
let expected = str![[r#"
error: unused optional dependency
|
4 | bar = { version = "0.1.0", optional = true }
| __________^__________________--------------^
| | | |
| |__________| info: This should also be long but not too long
| ||
5 | || this is another line
| || ____^
6 | ||| so is this
7 | ||| bar = { version = "0.1.0", optional = true }
| |||_________________________^________________^ I need this to be really long so I can test overlaps
| |_|_________________________|
| | I need this to be really long so I can test overlaps
8 | | this is another line
| |____^ I need this to be really long so I can test overlaps
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn origin_correct_start_line() {
let source = "aaa\nbbb\nccc\nddd\n";
let input = Level::Error.title("title").snippet(
Snippet::source(source)
.origin("origin.txt")
.fold(false)
.annotation(Level::Error.span(8..8 + 3).label("annotation")),
);
let expected = str![[r#"
error: title
--> origin.txt:3:1
|
1 | aaa
2 | bbb
3 | ccc
| ^^^ annotation
4 | ddd
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn origin_correct_mid_line() {
let source = "aaa\nbbb\nccc\nddd\n";
let input = Level::Error.title("title").snippet(
Snippet::source(source)
.origin("origin.txt")
.fold(false)
.annotation(Level::Error.span(8 + 1..8 + 3).label("annotation")),
);
let expected = str![[r#"
error: title
--> origin.txt:3:2
|
1 | aaa
2 | bbb
3 | ccc
| ^^ annotation
4 | ddd
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}

View file

@ -0,0 +1,783 @@
//! These tests have been adapted from [Rust's parser tests][parser-tests].
//!
//! [parser-tests]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_parse/src/parser/tests.rs
use ruff_annotate_snippets::{Level, Renderer, Snippet};
use snapbox::{assert_data_eq, str};
#[test]
fn ends_on_col0() {
let source = r#"
fn foo() {
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(10..13).label("test")),
);
let expected = str![[r#"
error: foo
--> test.rs:2:10
|
2 | fn foo() {
| __________^
3 | | }
| |_^ test
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn ends_on_col2() {
let source = r#"
fn foo() {
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(10..17).label("test")),
);
let expected = str![[r#"
error: foo
--> test.rs:2:10
|
2 | fn foo() {
| __________^
3 | |
4 | |
5 | | }
| |___^ test
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn non_nested() {
let source = r#"
fn foo() {
X0 Y0
X1 Y1
X2 Y2
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..32).label("`X` is a good letter"))
.annotation(
Level::Warning
.span(17..35)
.label("`Y` is a good letter too"),
),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | X0 Y0
| ____^ -
| | ______|
4 | || X1 Y1
5 | || X2 Y2
| ||____^__- `Y` is a good letter too
| |_____|
| `X` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn nested() {
let source = r#"
fn foo() {
X0 Y0
Y1 X1
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..27).label("`X` is a good letter"))
.annotation(
Level::Warning
.span(17..24)
.label("`Y` is a good letter too"),
),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | X0 Y0
| ____^ -
| | ______|
4 | || Y1 X1
| ||____-__^ `X` is a good letter
| |____|
| `Y` is a good letter too
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn different_overlap() {
let source = r#"
fn foo() {
X0 Y0 Z0
X1 Y1 Z1
X2 Y2 Z2
X3 Y3 Z3
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(17..38).label("`X` is a good letter"))
.annotation(
Level::Warning
.span(31..49)
.label("`Y` is a good letter too"),
),
);
let expected = str![[r#"
error: foo
--> test.rs:3:6
|
3 | X0 Y0 Z0
| _______^
4 | | X1 Y1 Z1
| | _________-
5 | || X2 Y2 Z2
| ||____^ `X` is a good letter
6 | | X3 Y3 Z3
| |____- `Y` is a good letter too
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn triple_overlap() {
let source = r#"
fn foo() {
X0 Y0 Z0
X1 Y1 Z1
X2 Y2 Z2
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..38).label("`X` is a good letter"))
.annotation(
Level::Warning
.span(17..41)
.label("`Y` is a good letter too"),
)
.annotation(Level::Warning.span(20..44).label("`Z` label")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | X0 Y0 Z0
| _____^ - -
| | _______| |
| || _________|
4 | ||| X1 Y1 Z1
5 | ||| X2 Y2 Z2
| |||____^__-__- `Z` label
| ||_____|__|
| |______| `Y` is a good letter too
| `X` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn triple_exact_overlap() {
let source = r#"
fn foo() {
X0 Y0 Z0
X1 Y1 Z1
X2 Y2 Z2
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..38).label("`X` is a good letter"))
.annotation(
Level::Warning
.span(14..38)
.label("`Y` is a good letter too"),
)
.annotation(Level::Warning.span(14..38).label("`Z` label")),
);
// This should have a `^` but we currently don't support the idea of a
// "primary" annotation, which would solve this
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | / X0 Y0 Z0
4 | | X1 Y1 Z1
5 | | X2 Y2 Z2
| | -
| |____|
| `X` is a good letter
| `Y` is a good letter too
| `Z` label
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn minimum_depth() {
let source = r#"
fn foo() {
X0 Y0 Z0
X1 Y1 Z1
X2 Y2 Z2
X3 Y3 Z3
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(17..27).label("`X` is a good letter"))
.annotation(
Level::Warning
.span(28..44)
.label("`Y` is a good letter too"),
)
.annotation(Level::Warning.span(36..52).label("`Z`")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:6
|
3 | X0 Y0 Z0
| _______^
4 | | X1 Y1 Z1
| | ____^_-
| ||____|
| | `X` is a good letter
5 | | X2 Y2 Z2
| |___-______- `Y` is a good letter too
| ___|
| |
6 | | X3 Y3 Z3
| |_______- `Z`
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn non_overlapping() {
let source = r#"
fn foo() {
X0 Y0 Z0
X1 Y1 Z1
X2 Y2 Z2
X3 Y3 Z3
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..27).label("`X` is a good letter"))
.annotation(
Level::Warning
.span(39..55)
.label("`Y` is a good letter too"),
),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | / X0 Y0 Z0
4 | | X1 Y1 Z1
| |____^ `X` is a good letter
5 | X2 Y2 Z2
| ______-
6 | | X3 Y3 Z3
| |__________- `Y` is a good letter too
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn overlapping_start_and_end() {
let source = r#"
fn foo() {
X0 Y0 Z0
X1 Y1 Z1
X2 Y2 Z2
X3 Y3 Z3
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(17..27).label("`X` is a good letter"))
.annotation(
Level::Warning
.span(31..55)
.label("`Y` is a good letter too"),
),
);
let expected = str![[r#"
error: foo
--> test.rs:3:6
|
3 | X0 Y0 Z0
| _______^
4 | | X1 Y1 Z1
| | ____^____-
| ||____|
| | `X` is a good letter
5 | | X2 Y2 Z2
6 | | X3 Y3 Z3
| |__________- `Y` is a good letter too
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiple_labels_primary_without_message() {
let source = r#"
fn foo() {
a { b { c } d }
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(18..25).label(""))
.annotation(Level::Warning.span(14..27).label("`a` is a good letter"))
.annotation(Level::Warning.span(22..23).label("")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:7
|
3 | a { b { c } d }
| ----^^^^-^^-- `a` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiple_labels_secondary_without_message() {
let source = r#"
fn foo() {
a { b { c } d }
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..27).label("`a` is a good letter"))
.annotation(Level::Warning.span(18..25).label("")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | a { b { c } d }
| ^^^^-------^^ `a` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiple_labels_primary_without_message_2() {
let source = r#"
fn foo() {
a { b { c } d }
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(18..25).label("`b` is a good letter"))
.annotation(Level::Warning.span(14..27).label(""))
.annotation(Level::Warning.span(22..23).label("")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:7
|
3 | a { b { c } d }
| ----^^^^-^^--
| |
| `b` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiple_labels_secondary_without_message_2() {
let source = r#"
fn foo() {
a { b { c } d }
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..27).label(""))
.annotation(Level::Warning.span(18..25).label("`b` is a good letter")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | a { b { c } d }
| ^^^^-------^^
| |
| `b` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiple_labels_secondary_without_message_3() {
let source = r#"
fn foo() {
a bc d
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..18).label("`a` is a good letter"))
.annotation(Level::Warning.span(18..22).label("")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | a bc d
| ^^^^----
| |
| `a` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiple_labels_without_message() {
let source = r#"
fn foo() {
a { b { c } d }
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..27).label(""))
.annotation(Level::Warning.span(18..25).label("")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | a { b { c } d }
| ^^^^-------^^
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiple_labels_without_message_2() {
let source = r#"
fn foo() {
a { b { c } d }
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(18..25).label(""))
.annotation(Level::Warning.span(14..27).label(""))
.annotation(Level::Warning.span(22..23).label("")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:7
|
3 | a { b { c } d }
| ----^^^^-^^--
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn multiple_labels_with_message() {
let source = r#"
fn foo() {
a { b { c } d }
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..27).label("`a` is a good letter"))
.annotation(Level::Warning.span(18..25).label("`b` is a good letter")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | a { b { c } d }
| ^^^^-------^^
| | |
| | `b` is a good letter
| `a` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn ingle_label_with_message() {
let source = r#"
fn foo() {
a { b { c } d }
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..27).label("`a` is a good letter")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | a { b { c } d }
| ^^^^^^^^^^^^^ `a` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn single_label_without_message() {
let source = r#"
fn foo() {
a { b { c } d }
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(14..27).label("")),
);
let expected = str![[r#"
error: foo
--> test.rs:3:3
|
3 | a { b { c } d }
| ^^^^^^^^^^^^^
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn long_snippet() {
let source = r#"
fn foo() {
X0 Y0 Z0
X1 Y1 Z1
1
2
3
4
5
6
7
8
9
10
X2 Y2 Z2
X3 Y3 Z3
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(17..27).label("`X` is a good letter"))
.annotation(
Level::Warning
.span(31..76)
.label("`Y` is a good letter too"),
),
);
let expected = str![[r#"
error: foo
--> test.rs:3:6
|
3 | X0 Y0 Z0
| _______^
4 | | X1 Y1 Z1
| | ____^____-
| ||____|
| | `X` is a good letter
5 | | 1
... |
15 | | X2 Y2 Z2
16 | | X3 Y3 Z3
| |__________- `Y` is a good letter too
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}
#[test]
fn long_snippet_multiple_spans() {
let source = r#"
fn foo() {
X0 Y0 Z0
1
2
3
X1 Y1 Z1
4
5
6
X2 Y2 Z2
7
8
9
10
X3 Y3 Z3
}
"#;
let input = Level::Error.title("foo").snippet(
Snippet::source(source)
.line_start(1)
.origin("test.rs")
.fold(true)
.annotation(Level::Error.span(17..73).label("`Y` is a good letter"))
.annotation(
Level::Warning
.span(37..56)
.label("`Z` is a good letter too"),
),
);
let expected = str![[r#"
error: foo
--> test.rs:3:6
|
3 | X0 Y0 Z0
| _______^
4 | | 1
5 | | 2
6 | | 3
7 | | X1 Y1 Z1
| | _________-
8 | || 4
9 | || 5
10 | || 6
11 | || X2 Y2 Z2
| ||__________- `Z` is a good letter too
12 | | 7
... |
15 | | 10
16 | | X3 Y3 Z3
| |________^ `Y` is a good letter
|
"#]];
let renderer = Renderer::plain();
assert_data_eq!(renderer.render(input).to_string(), expected);
}