mirror of https://github.com/astral-sh/ruff
Set the diagnostic URL for lint errors (#21514)
Summary -- This PR wires up the `Diagnostic::set_documentation_url` method from #21502 to Ruff's lint diagnostics. This enables the links for the full and concise output formats without any other changes. I considered also including the URLs for the grouped and pylint output formats, but the grouped format is still in `ruff_linter` instead of `ruff_db`, so we'd have to export some additional functionality to wire it up with `fmt_with_hyperlink`; and the pylint format doesn't currently render with color, so I think it might actually be machine readable rather than human readable? The other ouput formats (json, json-lines, junit, github, gitlab, rdjson, azure, sarif) seem more clearly not to need the links. Test Plan -- I guess you can't see my cursor or the browser opening, but it works for lint rules, which have links, and doesn't include a link for syntax errors, which don't have valid links. 
This commit is contained in:
parent
62343a101a
commit
0645418f00
|
|
@ -452,28 +452,6 @@ impl Diagnostic {
|
||||||
.map(|sub| sub.inner.message.as_str())
|
.map(|sub| sub.inner.message.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the URL for the rule documentation, if it exists.
|
|
||||||
pub fn to_ruff_url(&self) -> Option<String> {
|
|
||||||
match self.id() {
|
|
||||||
DiagnosticId::Panic
|
|
||||||
| DiagnosticId::Io
|
|
||||||
| DiagnosticId::InvalidSyntax
|
|
||||||
| DiagnosticId::RevealedType
|
|
||||||
| DiagnosticId::UnknownRule
|
|
||||||
| DiagnosticId::InvalidGlob
|
|
||||||
| DiagnosticId::EmptyInclude
|
|
||||||
| DiagnosticId::UnnecessaryOverridesSection
|
|
||||||
| DiagnosticId::UselessOverridesSection
|
|
||||||
| DiagnosticId::DeprecatedSetting
|
|
||||||
| DiagnosticId::Unformatted
|
|
||||||
| DiagnosticId::InvalidCliOption
|
|
||||||
| DiagnosticId::InternalError => None,
|
|
||||||
DiagnosticId::Lint(lint_name) => {
|
|
||||||
Some(format!("{}/rules/{lint_name}", env!("CARGO_PKG_HOMEPAGE")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the filename for the message.
|
/// Returns the filename for the message.
|
||||||
///
|
///
|
||||||
/// Panics if the diagnostic has no primary span, or if its file is not a `SourceFile`.
|
/// Panics if the diagnostic has no primary span, or if its file is not a `SourceFile`.
|
||||||
|
|
|
||||||
|
|
@ -2881,6 +2881,12 @@ watermelon
|
||||||
self.diag.help(message);
|
self.diag.help(message);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the documentation URL for the diagnostic.
|
||||||
|
pub(super) fn documentation_url(mut self, url: impl Into<String>) -> DiagnosticBuilder<'e> {
|
||||||
|
self.diag.set_documentation_url(Some(url.into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper builder for tersely populating a `SubDiagnostic`.
|
/// A helper builder for tersely populating a `SubDiagnostic`.
|
||||||
|
|
@ -2995,6 +3001,7 @@ def fibonacci(n):
|
||||||
TextSize::from(10),
|
TextSize::from(10),
|
||||||
))))
|
))))
|
||||||
.noqa_offset(TextSize::from(7))
|
.noqa_offset(TextSize::from(7))
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/unused-import")
|
||||||
.build(),
|
.build(),
|
||||||
env.builder(
|
env.builder(
|
||||||
"unused-variable",
|
"unused-variable",
|
||||||
|
|
@ -3009,11 +3016,13 @@ def fibonacci(n):
|
||||||
TextSize::from(99),
|
TextSize::from(99),
|
||||||
)))
|
)))
|
||||||
.noqa_offset(TextSize::from(94))
|
.noqa_offset(TextSize::from(94))
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/unused-variable")
|
||||||
.build(),
|
.build(),
|
||||||
env.builder("undefined-name", Severity::Error, "Undefined name `a`")
|
env.builder("undefined-name", Severity::Error, "Undefined name `a`")
|
||||||
.primary("undef.py", "1:3", "1:4", "")
|
.primary("undef.py", "1:3", "1:4", "")
|
||||||
.secondary_code("F821")
|
.secondary_code("F821")
|
||||||
.noqa_offset(TextSize::from(3))
|
.noqa_offset(TextSize::from(3))
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/undefined-name")
|
||||||
.build(),
|
.build(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -3128,6 +3137,7 @@ if call(foo
|
||||||
TextSize::from(19),
|
TextSize::from(19),
|
||||||
))))
|
))))
|
||||||
.noqa_offset(TextSize::from(16))
|
.noqa_offset(TextSize::from(16))
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/unused-import")
|
||||||
.build(),
|
.build(),
|
||||||
env.builder(
|
env.builder(
|
||||||
"unused-import",
|
"unused-import",
|
||||||
|
|
@ -3142,6 +3152,7 @@ if call(foo
|
||||||
TextSize::from(40),
|
TextSize::from(40),
|
||||||
))))
|
))))
|
||||||
.noqa_offset(TextSize::from(35))
|
.noqa_offset(TextSize::from(35))
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/unused-import")
|
||||||
.build(),
|
.build(),
|
||||||
env.builder(
|
env.builder(
|
||||||
"unused-variable",
|
"unused-variable",
|
||||||
|
|
@ -3156,6 +3167,7 @@ if call(foo
|
||||||
TextSize::from(104),
|
TextSize::from(104),
|
||||||
))))
|
))))
|
||||||
.noqa_offset(TextSize::from(98))
|
.noqa_offset(TextSize::from(98))
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/unused-variable")
|
||||||
.build(),
|
.build(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ pub(super) fn diagnostic_to_json<'a>(
|
||||||
if config.preview {
|
if config.preview {
|
||||||
JsonDiagnostic {
|
JsonDiagnostic {
|
||||||
code: diagnostic.secondary_code_or_id(),
|
code: diagnostic.secondary_code_or_id(),
|
||||||
url: diagnostic.to_ruff_url(),
|
url: diagnostic.documentation_url(),
|
||||||
message: diagnostic.body(),
|
message: diagnostic.body(),
|
||||||
fix,
|
fix,
|
||||||
cell: notebook_cell_index,
|
cell: notebook_cell_index,
|
||||||
|
|
@ -112,7 +112,7 @@ pub(super) fn diagnostic_to_json<'a>(
|
||||||
} else {
|
} else {
|
||||||
JsonDiagnostic {
|
JsonDiagnostic {
|
||||||
code: diagnostic.secondary_code_or_id(),
|
code: diagnostic.secondary_code_or_id(),
|
||||||
url: diagnostic.to_ruff_url(),
|
url: diagnostic.documentation_url(),
|
||||||
message: diagnostic.body(),
|
message: diagnostic.body(),
|
||||||
fix,
|
fix,
|
||||||
cell: notebook_cell_index,
|
cell: notebook_cell_index,
|
||||||
|
|
@ -228,7 +228,7 @@ pub(crate) struct JsonDiagnostic<'a> {
|
||||||
location: Option<JsonLocation>,
|
location: Option<JsonLocation>,
|
||||||
message: &'a str,
|
message: &'a str,
|
||||||
noqa_row: Option<OneIndexed>,
|
noqa_row: Option<OneIndexed>,
|
||||||
url: Option<String>,
|
url: Option<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|
@ -294,7 +294,10 @@ mod tests {
|
||||||
env.format(DiagnosticFormat::Json);
|
env.format(DiagnosticFormat::Json);
|
||||||
env.preview(false);
|
env.preview(false);
|
||||||
|
|
||||||
let diag = env.err().build();
|
let diag = env
|
||||||
|
.err()
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/test-diagnostic")
|
||||||
|
.build();
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
env.render(&diag),
|
env.render(&diag),
|
||||||
|
|
@ -328,7 +331,10 @@ mod tests {
|
||||||
env.format(DiagnosticFormat::Json);
|
env.format(DiagnosticFormat::Json);
|
||||||
env.preview(true);
|
env.preview(true);
|
||||||
|
|
||||||
let diag = env.err().build();
|
let diag = env
|
||||||
|
.err()
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/test-diagnostic")
|
||||||
|
.build();
|
||||||
|
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
env.render(&diag),
|
env.render(&diag),
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ fn diagnostic_to_rdjson<'a>(
|
||||||
value: diagnostic
|
value: diagnostic
|
||||||
.secondary_code()
|
.secondary_code()
|
||||||
.map_or_else(|| diagnostic.name(), |code| code.as_str()),
|
.map_or_else(|| diagnostic.name(), |code| code.as_str()),
|
||||||
url: diagnostic.to_ruff_url(),
|
url: diagnostic.documentation_url(),
|
||||||
},
|
},
|
||||||
suggestions: rdjson_suggestions(
|
suggestions: rdjson_suggestions(
|
||||||
edits,
|
edits,
|
||||||
|
|
@ -182,7 +182,7 @@ impl RdjsonRange {
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct RdjsonCode<'a> {
|
struct RdjsonCode<'a> {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
url: Option<String>,
|
url: Option<&'a str>,
|
||||||
value: &'a str,
|
value: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,7 +217,10 @@ mod tests {
|
||||||
env.format(DiagnosticFormat::Rdjson);
|
env.format(DiagnosticFormat::Rdjson);
|
||||||
env.preview(false);
|
env.preview(false);
|
||||||
|
|
||||||
let diag = env.err().build();
|
let diag = env
|
||||||
|
.err()
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/test-diagnostic")
|
||||||
|
.build();
|
||||||
|
|
||||||
insta::assert_snapshot!(env.render(&diag));
|
insta::assert_snapshot!(env.render(&diag));
|
||||||
}
|
}
|
||||||
|
|
@ -228,7 +231,10 @@ mod tests {
|
||||||
env.format(DiagnosticFormat::Rdjson);
|
env.format(DiagnosticFormat::Rdjson);
|
||||||
env.preview(true);
|
env.preview(true);
|
||||||
|
|
||||||
let diag = env.err().build();
|
let diag = env
|
||||||
|
.err()
|
||||||
|
.documentation_url("https://docs.astral.sh/ruff/rules/test-diagnostic")
|
||||||
|
.build();
|
||||||
|
|
||||||
insta::assert_snapshot!(env.render(&diag));
|
insta::assert_snapshot!(env.render(&diag));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
diagnostic.set_secondary_code(SecondaryCode::new(rule.noqa_code().to_string()));
|
diagnostic.set_secondary_code(SecondaryCode::new(rule.noqa_code().to_string()));
|
||||||
|
diagnostic.set_documentation_url(rule.url());
|
||||||
|
|
||||||
diagnostic
|
diagnostic
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -301,9 +301,9 @@ fn to_lsp_diagnostic(
|
||||||
severity,
|
severity,
|
||||||
tags,
|
tags,
|
||||||
code,
|
code,
|
||||||
code_description: diagnostic.to_ruff_url().and_then(|url| {
|
code_description: diagnostic.documentation_url().and_then(|url| {
|
||||||
Some(lsp_types::CodeDescription {
|
Some(lsp_types::CodeDescription {
|
||||||
href: lsp_types::Url::parse(&url).ok()?,
|
href: lsp_types::Url::parse(url).ok()?,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
source: Some(DIAGNOSTIC_NAME.into()),
|
source: Some(DIAGNOSTIC_NAME.into()),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue