Skip to content

Commit 4909d78

Browse files
committed
fix(frontmatter): Report script manifest errors for the right line number
1 parent 578ab7c commit 4909d78

File tree

4 files changed

+42
-12
lines changed

4 files changed

+42
-12
lines changed

src/cargo/util/frontmatter.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ type Span = std::ops::Range<usize>;
66
pub struct ScriptSource<'s> {
77
raw: &'s str,
88
shebang: Option<Span>,
9+
open: Option<Span>,
910
info: Option<Span>,
1011
frontmatter: Option<Span>,
12+
close: Option<Span>,
1113
content: Span,
1214
}
1315

@@ -22,8 +24,10 @@ impl<'s> ScriptSource<'s> {
2224
let mut source = Self {
2325
raw,
2426
shebang: None,
27+
open: None,
2528
info: None,
2629
frontmatter: None,
30+
close: None,
2731
content: 0..content_end,
2832
};
2933

@@ -61,7 +65,10 @@ impl<'s> ScriptSource<'s> {
6165
}
6266
_ => {}
6367
}
68+
let open_start = input.current_token_start();
6469
let fence_pattern = input.next_slice(fence_length);
70+
let open_end = input.current_token_start();
71+
source.open = Some(open_start..open_end);
6572
let Some(info_nl) = input.find_slice("\n") else {
6673
anyhow::bail!("no closing `{fence_pattern}` found for frontmatter");
6774
};
@@ -82,7 +89,10 @@ impl<'s> ScriptSource<'s> {
8289
let _ = input.next_slice(frontmatter_nl.start + 1);
8390
let frontmatter_end = input.current_token_start();
8491
source.frontmatter = Some(frontmatter_start..frontmatter_end);
92+
let close_start = input.current_token_start();
8593
let _ = input.next_slice(fence_length);
94+
let close_end = input.current_token_start();
95+
source.close = Some(close_start..close_end);
8696

8797
let nl = input.find_slice("\n");
8898
let after_closing_fence = input.next_slice(
@@ -114,6 +124,10 @@ impl<'s> ScriptSource<'s> {
114124
self.shebang.clone()
115125
}
116126

127+
pub fn open_span(&self) -> Option<Span> {
128+
self.open.clone()
129+
}
130+
117131
pub fn info(&self) -> Option<&'s str> {
118132
self.info.clone().map(|span| &self.raw[span])
119133
}
@@ -130,6 +144,10 @@ impl<'s> ScriptSource<'s> {
130144
self.frontmatter.clone()
131145
}
132146

147+
pub fn close_span(&self) -> Option<Span> {
148+
self.close.clone()
149+
}
150+
133151
pub fn content(&self) -> &'s str {
134152
&self.raw[self.content.clone()]
135153
}

src/cargo/util/toml/embedded.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::util::restricted_names;
66

77
pub(super) fn expand_manifest(content: &str) -> CargoResult<String> {
88
let source = ScriptSource::parse(content)?;
9-
if let Some(frontmatter) = source.frontmatter() {
9+
if let Some(span) = source.frontmatter_span() {
1010
match source.info() {
1111
Some("cargo") | None => {}
1212
Some(other) => {
@@ -22,10 +22,21 @@ pub(super) fn expand_manifest(content: &str) -> CargoResult<String> {
2222
}
2323
}
2424

25-
Ok(frontmatter.to_owned())
25+
// Include from file start to frontmatter end when we parse the TOML to get line numbers
26+
// correct and so if a TOML error says "entire file", it shows the existing content, rather
27+
// than blank lines.
28+
//
29+
// HACK: Since frontmatter open isn't valid TOML, we insert a comment
30+
let mut frontmatter = content[0..span.end].to_owned();
31+
let open_span = source.open_span().unwrap();
32+
frontmatter.insert(open_span.start, '#');
33+
Ok(frontmatter)
2634
} else {
27-
let frontmatter = "";
28-
Ok(frontmatter.to_owned())
35+
// Consider the shebang to be part of the frontmatter
36+
// so if a TOML error says "entire file", it shows the existing content, rather
37+
// than blank lines.
38+
let span = source.shebang_span().unwrap_or(0..0);
39+
Ok(content[span].to_owned())
2940
}
3041
}
3142

@@ -88,11 +99,12 @@ time="0.1.25"
8899
fn main() {}
89100
"#
90101
),
91-
str![[r#"
102+
str![[r##"
103+
#---cargo
92104
[dependencies]
93105
time="0.1.25"
94106
95-
"#]]
107+
"##]]
96108
);
97109
}
98110
}

tests/testsuite/script/cargo.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,9 @@ fn main() {
209209
.with_stdout_data(str![""])
210210
.with_stderr_data(str![[r#"
211211
[ERROR] invalid type: integer `3`, expected a version string like "0.9.8" or a detailed dependency like { version = "0.9.8" }
212-
--> script.rs:2:7
212+
--> script.rs:9:7
213213
|
214-
2 | bar = 3
214+
9 | bar = 3
215215
| ^
216216
217217
"#]])
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[ERROR] invalid multi-line basic string, expected `/`, characters
2-
--> script:8:2
3-
|
4-
8 | 4␌+
5-
| ^
2+
--> script:10:2
3+
|
4+
10 | 4␌+
5+
| ^

0 commit comments

Comments
 (0)