Move diagnostic format dispatch into Ruff and ty (#29647)

Summary
--

This addresses the suggestion from [#29635]. `DisplayDiagnosticConfig`
previously determined the
`DiagnosticFormat` for diagnostics coming from both Ruff and ty, which
meant that it had to have a
shared enum between the two, despite each program supporting a different
subset of the available
formats. This PR eliminates the shared `DiagnosticFormat` and dispatch
through `DisplayDiagnostics`,
leaving Ruff and ty to construct `Renderer`s directly and do their own
dispatch on the output
formats they actually support. This will be especially helpful in
#29635, where we want to provide
slightly different arguments to each new `SarifRenderer`.

The `Renderer` trait itself isn't strictly necessary, but it made the
calls on the Ruff side a lot
neater since the trait provides a default `write` method based on the
required `render` method.
Codex also threw in a default `display` method that helps in a couple of
places too.

Test Plan
--

Existing tests

[#29635]:
https://github.com/astral-sh/ruff/pull/29635#discussion_r4352505588
This commit is contained in:
Brent Westbrook authored and GitHub committed 2026-10-23 09:38:24 -04:00
1 parent 2fa2ecbbf7
commit c8589d0eb1
30 files changed
+331 -515

No files matched your search

+6 -10
View File
@@ -224,7 +224,8 @@ mod test {
use rustc_hash::FxHashMap;
use tempfile::TempDir;
use ruff_db::diagnostic::{DiagnosticFormat, DisplayDiagnosticConfig, DisplayDiagnostics};
use ruff_db::diagnostic::DisplayDiagnosticConfig;
use ruff_db::diagnostic::render::{ConciseRenderer, Renderer};
use ruff_linter::message::EmitterContext;
use ruff_linter::registry::Rule;
use ruff_linter::settings::types::UnsafeFixes;
@@ -279,15 +280,10 @@ mod test {
)
.unwrap();
let config = DisplayDiagnosticConfig::new("ruff")
.format(DiagnosticFormat::Concise)
.hide_severity(true);
let messages = DisplayDiagnostics::new(
&EmitterContext::new(&FxHashMap::default()),
&config,
&diagnostics.inner,
)
.to_string();
let config = DisplayDiagnosticConfig::new("ruff").hide_severity(true);
let messages = ConciseRenderer::new(&EmitterContext::new(&FxHashMap::default()), &config)
.display(&diagnostics.inner)
.to_string();
insta::with_settings!({
omit_expression => true,
+1 -1
View File
@@ -603,7 +603,7 @@ impl<'a> FormatResults<'a> {
.hide_severity(true)
.color(!cfg!(test) && colored::control::SHOULD_COLORIZE.should_colorize());
render_diagnostics(f, output_format, config, &context, &diagnostics)
render_diagnostics(f, output_format, &config, &context, &diagnostics)
}
/// Write a summary of the formatting results to the given writer.
+2 -2
View File
@@ -250,7 +250,7 @@ impl Printer {
.with_show_fix_status(show_fix_status(self.fix_mode, fixables.as_ref()))
.with_fix_applicability(self.unsafe_fixes.required_applicability());
render_diagnostics(writer, self.format, config, &context, &diagnostics.inner)?;
render_diagnostics(writer, self.format, &config, &context, &diagnostics.inner)?;
if matches!(
self.format,
@@ -435,7 +435,7 @@ impl Printer {
.color(!cfg!(test) && colored::control::SHOULD_COLORIZE.should_colorize())
.with_show_fix_status(show_fix_status(self.fix_mode, fixables.as_ref()))
.with_fix_applicability(self.unsafe_fixes.required_applicability());
render_diagnostics(writer, self.format, config, &context, &diagnostics.inner)?;
render_diagnostics(writer, self.format, &config, &context, &diagnostics.inner)?;
}
writer.flush()?;
+9 -78
View File
@@ -1,4 +1,4 @@
use std::fmt::{Display, Formatter};
use std::fmt::{self, Display, Formatter};
use std::{borrow::Cow, path::Path, sync::Arc};
use ruff_diagnostics::{Applicability, Fix};
@@ -9,14 +9,13 @@ use ruff_text_size::{Ranged, TextRange, TextSize};
#[cfg(feature = "serde")]
use serde::Serialize;
pub use self::render::{
DisplayDiagnostic, DisplayDiagnostics, DummyFileResolver, FileResolver, Input,
};
pub use self::render::{DummyFileResolver, FileResolver, Input};
use self::render::{FullRenderer, Renderer};
pub use self::stylesheet::{DiagnosticStylesheet, fmt_with_hyperlink};
use crate::cancellation::CancellationToken;
use crate::{Db, files::File};
mod render;
pub mod render;
mod stylesheet;
/// A collection of information that can be rendered into a diagnostic.
@@ -206,7 +205,7 @@ impl Diagnostic {
}
/// Return a `std::fmt::Display` implementation that renders this
/// diagnostic into a human readable format.
/// diagnostic in the full, human-readable format.
///
/// Note that this `Display` impl includes a trailing line terminator, so
/// callers should prefer using this with `write!` instead of `writeln!`.
@@ -214,8 +213,10 @@ impl Diagnostic {
&'a self,
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
) -> DisplayDiagnostic<'a> {
DisplayDiagnostic::new(resolver, config, self)
) -> impl Display + 'a {
fmt::from_fn(move |f| {
FullRenderer::new(resolver, config).render(f, std::slice::from_ref(self))
})
}
/// Returns the identifier for this diagnostic.
@@ -1422,10 +1423,6 @@ pub enum HyperlinkMode {
pub struct DisplayDiagnosticConfig {
/// The program name used in structured output formats (e.g., JUnit, GitHub).
program: &'static str,
/// The format to use for diagnostic rendering.
///
/// This uses the "full" format by default.
format: DiagnosticFormat,
/// Whether to enable colors or not.
///
/// Disabled by default.
@@ -1473,7 +1470,6 @@ impl DisplayDiagnosticConfig {
pub fn new(program: &'static str) -> DisplayDiagnosticConfig {
DisplayDiagnosticConfig {
program,
format: DiagnosticFormat::default(),
color: false,
hyperlinks: HyperlinkMode::Auto,
anonymized_line_numbers: false,
@@ -1488,11 +1484,6 @@ impl DisplayDiagnosticConfig {
}
}
/// Whether to enable concise diagnostic output or not.
pub fn format(self, format: DiagnosticFormat) -> DisplayDiagnosticConfig {
DisplayDiagnosticConfig { format, ..self }
}
/// Whether to enable colors or not.
pub fn color(self, yes: bool) -> DisplayDiagnosticConfig {
DisplayDiagnosticConfig { color: yes, ..self }
@@ -1609,66 +1600,6 @@ impl DisplayDiagnosticConfig {
}
}
/// The diagnostic output format.
#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum DiagnosticFormat {
/// The default full mode will print "pretty" diagnostics.
///
/// That is, color will be used when printing to a `tty`.
/// Moreover, diagnostic messages may include additional
/// context and annotations on the input to help understand
/// the message.
#[default]
Full,
/// Print diagnostics in a concise mode.
///
/// This will guarantee that each diagnostic is printed on
/// a single line. Only the most important or primary aspects
/// of the diagnostic are included. Contextual information is
/// dropped.
///
/// This may use color when printing to a `tty`.
Concise,
/// Print diagnostics in the [Azure Pipelines] format.
///
/// [Azure Pipelines]: https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#logissue-log-an-error-or-warning
Azure,
/// Print diagnostics in JSON format.
///
/// Unlike `json-lines`, this prints all of the diagnostics as a JSON array.
#[cfg(feature = "serde")]
Json,
/// Print diagnostics in JSON format, one per line.
///
/// This will print each diagnostic as a separate JSON object on its own line. See the `json`
/// format for an array of all diagnostics. See <https://jsonlines.org/> for more details.
#[cfg(feature = "serde")]
JsonLines,
/// Print diagnostics in the JSON format expected by [reviewdog].
///
/// [reviewdog]: https://github.com/reviewdog/reviewdog
#[cfg(feature = "serde")]
Rdjson,
/// Print diagnostics in the format emitted by Pylint.
Pylint,
/// Print diagnostics in the format expected by JUnit.
#[cfg(feature = "junit")]
Junit,
/// Print diagnostics in the JSON format used by GitLab [Code Quality] reports.
///
/// [Code Quality]: https://docs.gitlab.com/ci/testing/code_quality/#code-quality-report-format
#[cfg(feature = "serde")]
Gitlab,
/// Print diagnostics in the format used by [GitHub Actions] workflow error annotations.
///
/// [GitHub Actions]: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-commands#setting-an-error-message
Github,
}
/// A representation of the kinds of messages inside a diagnostic.
pub enum ConciseMessage<'a> {
/// A diagnostic contains a non-empty headline message and an empty
+93 -118
View File
@@ -6,7 +6,6 @@ use annotate_snippets::{
Annotation as AnnotateAnnotation, AnnotationKind, Group as AnnotateGroup,
Level as AnnotateLevel, Snippet as AnnotateSnippet,
};
use full::FullRenderer;
use ruff_notebook::{Notebook, NotebookIndex};
use ruff_source_file::{LineIndex, OneIndexed, SourceCode};
use ruff_text_size::{TextLen, TextRange, TextSize};
@@ -18,19 +17,29 @@ use crate::{
};
use super::{
Annotation, Diagnostic, DiagnosticFormat, DiagnosticSource, DisplayDiagnosticConfig,
SubDiagnostic, UnifiedFile,
Annotation, Diagnostic, DiagnosticSource, DisplayDiagnosticConfig, SubDiagnostic, UnifiedFile,
};
use azure::AzureRenderer;
use concise::ConciseRenderer;
use github::GithubRenderer;
use pylint::PylintRenderer;
pub use azure::AzureRenderer;
pub use concise::ConciseRenderer;
pub use full::FullRenderer;
pub use github::GithubRenderer;
#[cfg(feature = "serde")]
pub use gitlab::GitlabRenderer;
#[cfg(feature = "serde")]
pub use json::JsonRenderer;
#[cfg(feature = "serde")]
pub use json_lines::JsonLinesRenderer;
#[cfg(feature = "junit")]
pub use junit::JunitRenderer;
pub use pylint::PylintRenderer;
#[cfg(feature = "serde")]
pub use rdjson::RdjsonRenderer;
mod azure;
mod concise;
mod full;
pub mod github;
mod github;
#[cfg(feature = "serde")]
mod gitlab;
#[cfg(feature = "serde")]
@@ -43,115 +52,23 @@ mod pylint;
#[cfg(feature = "serde")]
mod rdjson;
/// A type that implements `std::fmt::Display` for diagnostic rendering.
///
/// It is created via [`Diagnostic::display`].
///
/// The lifetime parameter, `'a`, refers to the shorter of:
///
/// * The lifetime of the rendering configuration.
/// * The lifetime of the resolver used to load the contents of `Span`
/// values. When using Salsa, this most commonly corresponds to the lifetime
/// of a Salsa `Db`.
/// * The lifetime of the diagnostic being rendered.
pub struct DisplayDiagnostic<'a> {
config: &'a DisplayDiagnosticConfig,
resolver: &'a dyn FileResolver,
diag: &'a Diagnostic,
}
/// Renders diagnostics in a particular output format.
pub trait Renderer {
/// Renders diagnostics to a formatter.
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result;
impl<'a> DisplayDiagnostic<'a> {
pub(crate) fn new(
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
diag: &'a Diagnostic,
) -> DisplayDiagnostic<'a> {
DisplayDiagnostic {
config,
resolver,
diag,
}
/// Returns a display implementation for these diagnostics.
fn display<'a>(&'a self, diagnostics: &'a [Diagnostic]) -> impl std::fmt::Display + 'a {
std::fmt::from_fn(move |f| self.render(f, diagnostics))
}
}
impl std::fmt::Display for DisplayDiagnostic<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
DisplayDiagnostics::new(self.resolver, self.config, std::slice::from_ref(self.diag)).fmt(f)
}
}
/// A type that implements `std::fmt::Display` for rendering a collection of diagnostics.
///
/// It is intended for collections of diagnostics that need to be serialized together, as is the
/// case for JSON, for example.
///
/// See [`DisplayDiagnostic`] for rendering individual `Diagnostic`s and details about the lifetime
/// constraints.
pub struct DisplayDiagnostics<'a> {
config: &'a DisplayDiagnosticConfig,
resolver: &'a dyn FileResolver,
diagnostics: &'a [Diagnostic],
}
impl<'a> DisplayDiagnostics<'a> {
pub fn new(
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
diagnostics: &'a [Diagnostic],
) -> DisplayDiagnostics<'a> {
DisplayDiagnostics {
config,
resolver,
diagnostics,
}
}
}
impl std::fmt::Display for DisplayDiagnostics<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self.config.format {
DiagnosticFormat::Concise => {
ConciseRenderer::new(self.resolver, self.config).render(f, self.diagnostics)?;
}
DiagnosticFormat::Full => {
FullRenderer::new(self.resolver, self.config).render(f, self.diagnostics)?;
}
DiagnosticFormat::Azure => {
AzureRenderer::new(self.resolver, self.config).render(f, self.diagnostics)?;
}
#[cfg(feature = "serde")]
DiagnosticFormat::Json => {
json::JsonRenderer::new(self.resolver, self.config).render(f, self.diagnostics)?;
}
#[cfg(feature = "serde")]
DiagnosticFormat::JsonLines => {
json_lines::JsonLinesRenderer::new(self.resolver, self.config)
.render(f, self.diagnostics)?;
}
#[cfg(feature = "serde")]
DiagnosticFormat::Rdjson => {
rdjson::RdjsonRenderer::new(self.resolver, self.config)
.render(f, self.diagnostics)?;
}
DiagnosticFormat::Pylint => {
PylintRenderer::new(self.resolver, self.config).render(f, self.diagnostics)?;
}
#[cfg(feature = "junit")]
DiagnosticFormat::Junit => {
junit::JunitRenderer::new(self.resolver, self.config)
.render(f, self.diagnostics)?;
}
#[cfg(feature = "serde")]
DiagnosticFormat::Gitlab => {
gitlab::GitlabRenderer::new(self.resolver, self.config)
.render(f, self.diagnostics)?;
}
DiagnosticFormat::Github => {
GithubRenderer::new(self.resolver, self.config).render(f, self.diagnostics)?;
}
}
Ok(())
/// Writes diagnostics to an I/O writer.
fn write(
&self,
writer: &mut dyn std::io::Write,
diagnostics: &[Diagnostic],
) -> std::io::Result<()> {
write!(writer, "{}", self.display(diagnostics))
}
}
@@ -2537,11 +2454,32 @@ watermelon
);
}
#[derive(Default)]
pub(super) enum DiagnosticFormat {
#[default]
Full,
Concise,
Azure,
Github,
Pylint,
#[cfg(feature = "serde")]
Json,
#[cfg(feature = "serde")]
JsonLines,
#[cfg(feature = "serde")]
Rdjson,
#[cfg(feature = "serde")]
Gitlab,
#[cfg(feature = "junit")]
Junit,
}
/// A small harness for setting up an environment specifically for testing
/// diagnostic rendering.
pub(super) struct TestEnvironment {
db: TestDb,
config: DisplayDiagnosticConfig,
format: DiagnosticFormat,
}
impl TestEnvironment {
@@ -2552,6 +2490,7 @@ watermelon
let mut env = TestEnvironment {
db: TestDb::new(),
config: DisplayDiagnosticConfig::new("ty"),
format: DiagnosticFormat::default(),
};
// Default to a merge window of 0 for testing purposes,
// even though this is not the default for user-facing diagnostics.
@@ -2581,8 +2520,7 @@ watermelon
/// Set the output format to use in diagnostic rendering.
pub(super) fn format(&mut self, format: DiagnosticFormat) {
let config = self.config.clone();
self.config = config.format(format);
self.format = format;
}
/// Enable preview functionality for diagnostic rendering.
@@ -2710,7 +2648,7 @@ watermelon
///
/// (This will set the "printed" flag on `Diagnostic`.)
pub(super) fn render(&self, diag: &Diagnostic) -> String {
diag.display(&self.db, &self.config).to_string()
self.render_diagnostics(std::slice::from_ref(diag))
}
/// Render the given diagnostics into a `String`.
@@ -2719,7 +2657,44 @@ watermelon
///
/// (This will set the "printed" flag on `Diagnostic`.)
pub(super) fn render_diagnostics(&self, diagnostics: &[Diagnostic]) -> String {
DisplayDiagnostics::new(&self.db, &self.config, diagnostics).to_string()
std::fmt::from_fn(|f| match self.format {
DiagnosticFormat::Full => {
FullRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
DiagnosticFormat::Concise => {
ConciseRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
DiagnosticFormat::Azure => {
AzureRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
DiagnosticFormat::Github => {
GithubRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
DiagnosticFormat::Pylint => {
PylintRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
#[cfg(feature = "serde")]
DiagnosticFormat::Json => {
JsonRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
#[cfg(feature = "serde")]
DiagnosticFormat::JsonLines => {
JsonLinesRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
#[cfg(feature = "serde")]
DiagnosticFormat::Rdjson => {
RdjsonRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
#[cfg(feature = "serde")]
DiagnosticFormat::Gitlab => {
GitlabRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
#[cfg(feature = "junit")]
DiagnosticFormat::Junit => {
JunitRenderer::new(&self.db, &self.config).render(f, diagnostics)
}
})
.to_string()
}
}
+10 -12
View File
@@ -2,25 +2,24 @@ use ruff_source_file::LineColumn;
use crate::diagnostic::{Diagnostic, DisplayDiagnosticConfig, Severity};
use super::FileResolver;
use super::{FileResolver, Renderer};
pub(super) struct AzureRenderer<'a> {
/// Print diagnostics in the [Azure Pipelines] format.
///
/// [Azure Pipelines]: https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#logissue-log-an-error-or-warning
pub struct AzureRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> AzureRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
impl AzureRenderer<'_> {
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for AzureRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
for diag in diagnostics {
let severity = match diag.severity() {
Severity::Info | Severity::Warning => "warning",
@@ -63,9 +62,8 @@ impl AzureRenderer<'_> {
#[cfg(test)]
mod tests {
use crate::diagnostic::{
DiagnosticFormat,
render::tests::{create_diagnostics, create_syntax_error_diagnostics},
use crate::diagnostic::render::tests::{
DiagnosticFormat, create_diagnostics, create_syntax_error_diagnostics,
};
#[test]
@@ -3,23 +3,21 @@ use crate::diagnostic::{
stylesheet::{DiagnosticStylesheet, fmt_styled, fmt_with_hyperlink},
};
use super::FileResolver;
use super::{FileResolver, Renderer};
pub(super) struct ConciseRenderer<'a> {
pub struct ConciseRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> ConciseRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for ConciseRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
let stylesheet = if self.config.color {
DiagnosticStylesheet::styled().hyperlinks(self.config.hyperlinks)
} else {
@@ -132,12 +130,9 @@ impl<'a> ConciseRenderer<'a> {
mod tests {
use ruff_diagnostics::Applicability;
use crate::diagnostic::{
DiagnosticFormat,
render::tests::{
TestEnvironment, create_diagnostics, create_notebook_diagnostics,
create_syntax_error_diagnostics,
},
use crate::diagnostic::render::tests::{
DiagnosticFormat, TestEnvironment, create_diagnostics, create_notebook_diagnostics,
create_syntax_error_diagnostics,
};
#[test]
+9 -11
View File
@@ -11,25 +11,23 @@ use ruff_notebook::NotebookIndex;
use ruff_source_file::OneIndexed;
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::diagnostic::render::{FileResolver, Resolved};
use crate::diagnostic::render::{FileResolver, Renderer, Resolved};
use crate::diagnostic::stylesheet::{DiagnosticStylesheet, fmt_styled};
use crate::diagnostic::{Diagnostic, DiagnosticSource, DisplayDiagnosticConfig};
pub(super) struct FullRenderer<'a> {
pub struct FullRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> FullRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for FullRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
let stylesheet = if self.config.color {
DiagnosticStylesheet::styled().hyperlinks(self.config.hyperlinks)
} else {
@@ -385,10 +383,10 @@ mod tests {
use ruff_text_size::{TextLen, TextRange, TextSize};
use crate::diagnostic::{
Annotation, DiagnosticFormat, Severity,
Annotation, Severity,
render::tests::{
NOTEBOOK, TestEnvironment, create_diagnostics, create_notebook_diagnostics,
create_syntax_error_diagnostics,
DiagnosticFormat, NOTEBOOK, TestEnvironment, create_diagnostics,
create_notebook_diagnostics, create_syntax_error_diagnostics,
},
};
+9 -10
View File
@@ -5,21 +5,21 @@ use crate::diagnostic::{
UnifiedFile,
};
pub(super) struct GithubRenderer<'a> {
use super::Renderer;
pub struct GithubRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> GithubRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for GithubRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
for diagnostic in diagnostics {
let severity = match diagnostic.severity() {
Severity::Info => "notice",
@@ -190,9 +190,8 @@ impl std::fmt::Display for GithubAnnotation<'_> {
#[cfg(test)]
mod tests {
use crate::diagnostic::{
DiagnosticFormat,
render::tests::{TestEnvironment, create_diagnostics, create_syntax_error_diagnostics},
use crate::diagnostic::render::tests::{
DiagnosticFormat, TestEnvironment, create_diagnostics, create_syntax_error_diagnostics,
};
#[test]
+7 -12
View File
@@ -9,25 +9,21 @@ use serde::{Serialize, Serializer, ser::SerializeSeq};
use crate::diagnostic::{Diagnostic, DisplayDiagnosticConfig, Severity};
use super::FileResolver;
use super::{FileResolver, Renderer};
pub(super) struct GitlabRenderer<'a> {
pub struct GitlabRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> GitlabRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
impl GitlabRenderer<'_> {
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for GitlabRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
write!(
f,
"{}",
@@ -184,9 +180,8 @@ fn relativize_path_to<P: AsRef<Path>, R: AsRef<Path>>(path: P, project_root: R)
#[cfg(test)]
mod tests {
use crate::diagnostic::{
DiagnosticFormat,
render::tests::{create_diagnostics, create_syntax_error_diagnostics},
use crate::diagnostic::render::tests::{
DiagnosticFormat, create_diagnostics, create_syntax_error_diagnostics,
};
const FINGERPRINT_FILTERS: [(&str, &str); 1] = [(
+11 -15
View File
@@ -10,25 +10,24 @@ use crate::diagnostic::{
ConciseMessage, Diagnostic, DiagnosticSource, DisplayDiagnosticConfig, Severity,
};
use super::FileResolver;
use super::{FileResolver, Renderer};
pub(super) struct JsonRenderer<'a> {
/// Print diagnostics in JSON format.
///
/// Unlike [`JsonLinesRenderer`](super::JsonLinesRenderer), this prints all diagnostics as a JSON array.
pub struct JsonRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> JsonRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
impl JsonRenderer<'_> {
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for JsonRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
write!(
f,
"{:#}",
@@ -252,12 +251,9 @@ struct JsonEdit<'a> {
#[cfg(test)]
mod tests {
use crate::diagnostic::{
DiagnosticFormat,
render::tests::{
TestEnvironment, create_diagnostics, create_notebook_diagnostics,
create_syntax_error_diagnostics,
},
use crate::diagnostic::render::tests::{
DiagnosticFormat, TestEnvironment, create_diagnostics, create_notebook_diagnostics,
create_syntax_error_diagnostics,
};
#[test]
@@ -1,24 +1,25 @@
use crate::diagnostic::{Diagnostic, DisplayDiagnosticConfig, render::json::diagnostic_to_json};
use super::FileResolver;
use super::{FileResolver, Renderer};
pub(super) struct JsonLinesRenderer<'a> {
/// Print diagnostics in JSON format, one per line.
///
/// This prints each diagnostic as a separate JSON object on its own line. See
/// [`JsonRenderer`](super::JsonRenderer) for an array of all diagnostics.
/// See <https://jsonlines.org/> for more details.
pub struct JsonLinesRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> JsonLinesRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
impl JsonLinesRenderer<'_> {
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for JsonLinesRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
for diag in diagnostics {
writeln!(
f,
@@ -32,11 +33,9 @@ impl JsonLinesRenderer<'_> {
}
#[cfg(test)]
mod tests {
use crate::diagnostic::{
DiagnosticFormat,
render::tests::{
create_diagnostics, create_notebook_diagnostics, create_syntax_error_diagnostics,
},
use crate::diagnostic::render::tests::{
DiagnosticFormat, create_diagnostics, create_notebook_diagnostics,
create_syntax_error_diagnostics,
};
#[test]
+11 -11
View File
@@ -5,7 +5,10 @@ use quick_junit::{NonSuccessKind, Report, TestCase, TestCaseStatus, TestSuite, X
use ruff_source_file::LineColumn;
use crate::diagnostic::{Diagnostic, DisplayDiagnosticConfig, Severity, render::FileResolver};
use crate::diagnostic::{
Diagnostic, DisplayDiagnosticConfig, Severity,
render::{FileResolver, Renderer},
};
/// Print diagnostics as a JUnit-style XML report.
///
@@ -15,21 +18,19 @@ use crate::diagnostic::{Diagnostic, DisplayDiagnosticConfig, Severity, render::F
/// [`junit.xsd`]: https://github.com/junit-team/junit-framework/blob/2870b7d8fd5bf7c1efe489d3991d3ed3900e82bb/platform-tests/src/test/resources/jenkins-junit.xsd
/// [version]: https://llg.cubic.org/docs/junit/
/// [`quick_junit`]: https://docs.rs/quick-junit/latest/quick_junit/
pub(super) struct JunitRenderer<'a> {
pub struct JunitRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> JunitRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for JunitRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
let package = format!("org.{}", self.config.program);
let mut report = Report::new(self.config.program);
@@ -195,9 +196,8 @@ impl std::io::Write for FmtAdapter<'_> {
#[cfg(test)]
mod tests {
use crate::diagnostic::{
DiagnosticFormat,
render::tests::{create_diagnostics, create_syntax_error_diagnostics},
use crate::diagnostic::render::tests::{
DiagnosticFormat, create_diagnostics, create_syntax_error_diagnostics,
};
#[test]
+10 -12
View File
@@ -1,4 +1,7 @@
use crate::diagnostic::{Diagnostic, DisplayDiagnosticConfig, render::FileResolver};
use crate::diagnostic::{
Diagnostic, DisplayDiagnosticConfig,
render::{FileResolver, Renderer},
};
/// Generate violations in Pylint format.
///
@@ -9,23 +12,19 @@ use crate::diagnostic::{Diagnostic, DisplayDiagnosticConfig, render::FileResolve
/// ```
///
/// See: [Flake8 documentation](https://flake8.pycqa.org/en/latest/internal/formatters.html#pylint-formatter)
pub(super) struct PylintRenderer<'a> {
pub struct PylintRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> PylintRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
impl PylintRenderer<'_> {
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for PylintRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
for diagnostic in diagnostics {
let (filename, row) = diagnostic
.primary_span_ref()
@@ -68,9 +67,8 @@ impl PylintRenderer<'_> {
#[cfg(test)]
mod tests {
use crate::diagnostic::{
DiagnosticFormat,
render::tests::{TestEnvironment, create_diagnostics, create_syntax_error_diagnostics},
use crate::diagnostic::render::tests::{
DiagnosticFormat, TestEnvironment, create_diagnostics, create_syntax_error_diagnostics,
};
#[test]
+10 -10
View File
@@ -7,23 +7,24 @@ use ruff_text_size::Ranged;
use crate::diagnostic::{ConciseMessage, Diagnostic, DisplayDiagnosticConfig};
use super::FileResolver;
use super::{FileResolver, Renderer};
/// Print diagnostics in the JSON format expected by [reviewdog].
///
/// [reviewdog]: https://github.com/reviewdog/reviewdog
pub struct RdjsonRenderer<'a> {
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
}
impl<'a> RdjsonRenderer<'a> {
pub(super) fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
pub fn new(resolver: &'a dyn FileResolver, config: &'a DisplayDiagnosticConfig) -> Self {
Self { resolver, config }
}
}
pub(super) fn render(
&self,
f: &mut std::fmt::Formatter,
diagnostics: &[Diagnostic],
) -> std::fmt::Result {
impl Renderer for RdjsonRenderer<'_> {
fn render(&self, f: &mut std::fmt::Formatter, diagnostics: &[Diagnostic]) -> std::fmt::Result {
write!(
f,
"{:#}",
@@ -208,9 +209,8 @@ struct RdjsonSuggestion<'a> {
#[cfg(test)]
mod tests {
use crate::diagnostic::{
DiagnosticFormat,
render::tests::{TestEnvironment, create_diagnostics, create_syntax_error_diagnostics},
use crate::diagnostic::render::tests::{
DiagnosticFormat, TestEnvironment, create_diagnostics, create_syntax_error_diagnostics,
};
#[test]
+30 -26
View File
@@ -6,10 +6,13 @@ use std::path::Path;
use ruff_db::panic::PanicError;
use rustc_hash::FxHashMap;
use ruff_db::diagnostic::render::{
AzureRenderer, ConciseRenderer, FullRenderer, GithubRenderer, GitlabRenderer,
JsonLinesRenderer, JsonRenderer, JunitRenderer, PylintRenderer, RdjsonRenderer, Renderer,
};
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticFormat, DiagnosticId, DisplayDiagnosticConfig,
DisplayDiagnostics, FileResolver, Input, LintName, SecondaryCode, Severity, Span,
SubDiagnostic, SubDiagnosticSeverity, UnifiedFile,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, FileResolver, Input, LintName,
SecondaryCode, Severity, Span, SubDiagnostic, SubDiagnosticSeverity, UnifiedFile,
};
use ruff_db::files::File;
@@ -21,7 +24,7 @@ pub(crate) use sarif::SarifEmitter;
use crate::Fix;
use crate::registry::Rule;
use crate::settings::types::{OutputFormat, RuffOutputFormat};
use crate::settings::types::OutputFormat;
mod grouped;
mod sarif;
@@ -196,33 +199,34 @@ impl<'a> EmitterContext<'a> {
pub fn render_diagnostics(
writer: &mut dyn Write,
format: OutputFormat,
config: DisplayDiagnosticConfig,
config: &DisplayDiagnosticConfig,
context: &EmitterContext<'_>,
diagnostics: &[Diagnostic],
) -> std::io::Result<()> {
match DiagnosticFormat::try_from(format) {
Ok(format) => {
let config = config.format(format);
let value = DisplayDiagnostics::new(context, &config, diagnostics);
write!(writer, "{value}")?;
}
Err(RuffOutputFormat::Grouped) => {
GroupedEmitter::default()
.with_show_fix_status(config.show_fix_status())
.with_applicability(config.fix_applicability())
.with_preview(config.preview_enabled())
.with_prefer_rule_codes(config.is_prefer_rule_codes_enabled())
.emit(writer, diagnostics, context)
.map_err(std::io::Error::other)?;
}
Err(RuffOutputFormat::Sarif) => {
SarifEmitter::new(&config)
.emit(writer, diagnostics, context)
.map_err(std::io::Error::other)?;
match format {
OutputFormat::Concise => ConciseRenderer::new(context, config).write(writer, diagnostics),
OutputFormat::Full => FullRenderer::new(context, config).write(writer, diagnostics),
OutputFormat::Json => JsonRenderer::new(context, config).write(writer, diagnostics),
OutputFormat::JsonLines => {
JsonLinesRenderer::new(context, config).write(writer, diagnostics)
}
OutputFormat::Junit => JunitRenderer::new(context, config).write(writer, diagnostics),
OutputFormat::Github => GithubRenderer::new(context, config).write(writer, diagnostics),
OutputFormat::Gitlab => GitlabRenderer::new(context, config).write(writer, diagnostics),
OutputFormat::Pylint => PylintRenderer::new(context, config).write(writer, diagnostics),
OutputFormat::Rdjson => RdjsonRenderer::new(context, config).write(writer, diagnostics),
OutputFormat::Azure => AzureRenderer::new(context, config).write(writer, diagnostics),
OutputFormat::Grouped => GroupedEmitter::default()
.with_show_fix_status(config.show_fix_status())
.with_applicability(config.fix_applicability())
.with_preview(config.preview_enabled())
.with_prefer_rule_codes(config.is_prefer_rule_codes_enabled())
.emit(writer, diagnostics, context)
.map_err(std::io::Error::other),
OutputFormat::Sarif => SarifEmitter::new(config)
.emit(writer, diagnostics, context)
.map_err(std::io::Error::other),
}
Ok(())
}
#[cfg(test)]
-28
View File
@@ -10,7 +10,6 @@ use anyhow::{Context, Result, bail};
use globset::{Candidate, Glob, GlobMatcher, GlobSet, GlobSetBuilder};
use log::debug;
use pep440_rs::{VersionSpecifier, VersionSpecifiers};
use ruff_db::diagnostic::DiagnosticFormat;
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
use strum_macros::EnumIter;
@@ -601,33 +600,6 @@ impl Display for OutputFormat {
}
}
/// The subset of output formats only implemented in Ruff, not in `ruff_db` via `DisplayDiagnostics`.
pub enum RuffOutputFormat {
Grouped,
Sarif,
}
impl TryFrom<OutputFormat> for DiagnosticFormat {
type Error = RuffOutputFormat;
fn try_from(format: OutputFormat) -> std::result::Result<Self, Self::Error> {
match format {
OutputFormat::Concise => Ok(DiagnosticFormat::Concise),
OutputFormat::Full => Ok(DiagnosticFormat::Full),
OutputFormat::Json => Ok(DiagnosticFormat::Json),
OutputFormat::JsonLines => Ok(DiagnosticFormat::JsonLines),
OutputFormat::Junit => Ok(DiagnosticFormat::Junit),
OutputFormat::Gitlab => Ok(DiagnosticFormat::Gitlab),
OutputFormat::Pylint => Ok(DiagnosticFormat::Pylint),
OutputFormat::Rdjson => Ok(DiagnosticFormat::Rdjson),
OutputFormat::Azure => Ok(DiagnosticFormat::Azure),
OutputFormat::Github => Ok(DiagnosticFormat::Github),
OutputFormat::Grouped => Err(RuffOutputFormat::Grouped),
OutputFormat::Sarif => Err(RuffOutputFormat::Sarif),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(try_from = "String")]
pub struct RequiredVersion(VersionSpecifiers);
+7 -13
View File
@@ -9,9 +9,8 @@ use anyhow::Result;
use itertools::Itertools;
use rustc_hash::FxHashMap;
use ruff_db::diagnostic::{
Diagnostic, DiagnosticFormat, DisplayDiagnosticConfig, DisplayDiagnostics, Span,
};
use ruff_db::diagnostic::render::{FullRenderer, Renderer};
use ruff_db::diagnostic::{Diagnostic, DisplayDiagnosticConfig, Span};
use ruff_notebook::Notebook;
#[cfg(test)]
use ruff_notebook::NotebookError;
@@ -486,35 +485,30 @@ pub(crate) fn print_jupyter_messages(
notebook: &Notebook,
) -> String {
let config = DisplayDiagnosticConfig::new("ruff")
.format(DiagnosticFormat::Full)
.hide_severity(true)
.with_show_fix_status(true)
.with_fix_applicability(Applicability::DisplayOnly);
DisplayDiagnostics::new(
FullRenderer::new(
&EmitterContext::new(&FxHashMap::from_iter([(
path.file_name().unwrap().to_string_lossy().to_string(),
notebook.index().clone(),
)])),
&config,
diagnostics,
)
.display(diagnostics)
.to_string()
}
pub(crate) fn print_messages(diagnostics: &[Diagnostic]) -> String {
let config = DisplayDiagnosticConfig::new("ruff")
.format(DiagnosticFormat::Full)
.hide_severity(true)
.with_show_fix_status(true)
.with_fix_applicability(Applicability::DisplayOnly);
DisplayDiagnostics::new(
&EmitterContext::new(&FxHashMap::default()),
&config,
diagnostics,
)
.to_string()
FullRenderer::new(&EmitterContext::new(&FxHashMap::default()), &config)
.display(diagnostics)
.to_string()
}
#[macro_export]
+9 -17
View File
@@ -2,9 +2,10 @@ use crate::normalizer::Normalizer;
use anyhow::anyhow;
use datatest_stable::Utf8Path;
use insta::assert_snapshot;
use ruff_db::diagnostic::render::{FullRenderer, Renderer};
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticFormat, DiagnosticId, DisplayDiagnosticConfig,
DisplayDiagnostics, DummyFileResolver, Severity, Span, SubDiagnostic, SubDiagnosticSeverity,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, DummyFileResolver, Severity,
Span, SubDiagnostic, SubDiagnosticSeverity,
};
use ruff_formatter::FormatOptions;
use ruff_python_ast::Mod;
@@ -164,11 +165,8 @@ fn black_compatibility(input_path: &Utf8Path, content: String) -> datatest_stabl
writeln!(
snapshot,
"{}",
DisplayDiagnostics::new(
&DummyFileResolver,
&DisplayDiagnosticConfig::new("ruff").format(DiagnosticFormat::Full),
&unsupported_syntax_errors
)
FullRenderer::new(&DummyFileResolver, &DisplayDiagnosticConfig::new("ruff"))
.display(&unsupported_syntax_errors)
)
.unwrap();
}
@@ -243,11 +241,8 @@ fn format(input_path: &Utf8Path, content: String) -> datatest_stable::Result<()>
writeln!(
snapshot,
"### Unsupported Syntax Errors\n{}",
DisplayDiagnostics::new(
&DummyFileResolver,
&DisplayDiagnosticConfig::new("ruff").format(DiagnosticFormat::Full),
&unsupported_syntax_errors
)
FullRenderer::new(&DummyFileResolver, &DisplayDiagnosticConfig::new("ruff"))
.display(&unsupported_syntax_errors)
)
.unwrap();
}
@@ -289,11 +284,8 @@ fn format(input_path: &Utf8Path, content: String) -> datatest_stable::Result<()>
writeln!(
snapshot,
"## Unsupported Syntax Errors\n{}",
DisplayDiagnostics::new(
&DummyFileResolver,
&DisplayDiagnosticConfig::new("ruff").format(DiagnosticFormat::Full),
&unsupported_syntax_errors
)
FullRenderer::new(&DummyFileResolver, &DisplayDiagnosticConfig::new("ruff"))
.display(&unsupported_syntax_errors)
)
.unwrap();
}
+4 -5
View File
@@ -18,9 +18,7 @@ use colored::Colorize;
use crossbeam::channel as crossbeam_channel;
use rayon::ThreadPoolBuilder;
use ruff_db::cancellation::{Canceled, CancellationToken, CancellationTokenSource};
use ruff_db::diagnostic::{
Diagnostic, DiagnosticId, DisplayDiagnosticConfig, DisplayDiagnostics, Severity,
};
use ruff_db::diagnostic::{Diagnostic, DiagnosticId, DisplayDiagnosticConfig, Severity};
use ruff_db::files::File;
use ruff_db::system::{OsSystem, System, SystemPath, SystemPathBuf};
use ruff_db::{STACK_SIZE, max_parallelism};
@@ -632,7 +630,6 @@ impl MainLoop {
if stdout.is_enabled() {
let mut stdout = BufWriter::new(stdout);
let display_config = DisplayDiagnosticConfig::new("ty")
.format(terminal_settings.output_format.into())
.color(colored::control::SHOULD_COLORIZE.should_colorize())
.with_cancellation_token(Some(self.cancellation_token.clone()))
.context(0);
@@ -640,7 +637,9 @@ impl MainLoop {
write!(
stdout,
"{}",
DisplayDiagnostics::new(db, &display_config, diagnostics)
terminal_settings
.output_format
.display(db, &display_config, diagnostics)
)?;
stdout.flush()?;
}
+5 -10
View File
@@ -7,9 +7,7 @@ use insta::assert_snapshot;
#[cfg(feature = "test-uv")]
use insta::internals::SettingsBindDropGuard;
use ruff_db::Db as _;
use ruff_db::diagnostic::{
Diagnostic, DiagnosticFormat, DisplayDiagnosticConfig, DisplayDiagnostics,
};
use ruff_db::diagnostic::{Diagnostic, DisplayDiagnosticConfig};
use ruff_db::files::{File, FileError, system_path_to_file};
use ruff_db::source::source_text;
use ruff_db::system::{
@@ -20,7 +18,7 @@ use ruff_python_ast::PythonVersion;
use ruff_python_trivia::textwrap::dedent;
use ruff_ranged_value::{RangedValue, ValueSource};
use ty_module_resolver::{Module, ModuleName};
use ty_project::metadata::options::{EnvironmentOptions, Options, SrcOptions};
use ty_project::metadata::options::{EnvironmentOptions, Options, OutputFormat, SrcOptions};
use ty_project::metadata::pyproject::{PyProject, Tool};
use ty_project::metadata::python_version::SupportedPythonVersion;
use ty_project::metadata::value::{RelativeGlobPattern, RelativePathBuf};
@@ -318,12 +316,9 @@ impl TestCase {
}
fn render_diagnostics(&self, diagnostics: &[Diagnostic]) -> String {
DisplayDiagnostics::new(
self.db(),
&DisplayDiagnosticConfig::new("ty").format(DiagnosticFormat::Concise),
diagnostics,
)
.to_string()
OutputFormat::Concise
.display(self.db(), &DisplayDiagnosticConfig::new("ty"), diagnostics)
.to_string()
}
}
+3 -6
View File
@@ -76,8 +76,8 @@ mod tests {
use insta::assert_snapshot;
use ruff_db::{
diagnostic::{
Annotation, Diagnostic, DiagnosticFormat, DiagnosticId, DisplayDiagnosticConfig,
LintName, Span, SubDiagnostic,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, LintName, Span,
SubDiagnostic,
},
files::{File, system_path_to_file},
system::{DbWithWritableSystem, SystemPathBuf},
@@ -966,10 +966,7 @@ mod tests {
let mut buf = String::new();
let config = DisplayDiagnosticConfig::new("ty")
.color(false)
.context(0)
.format(DiagnosticFormat::Full);
let config = DisplayDiagnosticConfig::new("ty").color(false).context(0);
for mut action in code_actions(
&self.db,
+2 -6
View File
@@ -507,8 +507,7 @@ mod tests {
use insta::assert_snapshot;
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticFormat, DiagnosticId, DisplayDiagnosticConfig, LintName,
Severity, Span,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, LintName, Severity, Span,
};
use ruff_python_ast::PythonVersion;
use ruff_text_size::{Ranged, TextRange};
@@ -7451,10 +7450,7 @@ type U<CURSOR> = MyType
)
.unwrap();
let config = DisplayDiagnosticConfig::new("ty")
.color(false)
.context(0)
.format(DiagnosticFormat::Full);
let config = DisplayDiagnosticConfig::new("ty").color(false).context(0);
let mut diagnostic = Diagnostic::new(
DiagnosticId::Lint(LintName::of("hover")),
+3 -6
View File
@@ -852,8 +852,8 @@ mod tests {
use itertools::Itertools;
use ruff_db::{
diagnostic::{
Annotation, Diagnostic, DiagnosticFormat, DiagnosticId, DisplayDiagnosticConfig,
LintName, Severity, Span, SubDiagnostic, SubDiagnosticSeverity,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, LintName, Severity,
Span, SubDiagnostic, SubDiagnosticSeverity,
},
files::{File, FileRange, system_path_to_file},
source::source_text,
@@ -1406,10 +1406,7 @@ Source with applied edits:
let mut buf = String::new();
let config = DisplayDiagnosticConfig::new("ty")
.color(false)
.context(0)
.format(DiagnosticFormat::Full);
let config = DisplayDiagnosticConfig::new("ty").color(false).context(0);
let diag = diagnostic.into_diagnostic();
let config =
+2 -7
View File
@@ -407,9 +407,7 @@ mod tests {
use insta::internals::SettingsBindDropGuard;
use ruff_db::Db;
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticFormat, DisplayDiagnosticConfig, UnifiedFile,
};
use ruff_db::diagnostic::{Annotation, Diagnostic, DisplayDiagnosticConfig, UnifiedFile};
use ruff_db::files::{File, FileRootKind, system_path_to_file};
use ruff_db::parsed::{ParsedModuleRef, parsed_module};
use ruff_db::source::{SourceText, source_text};
@@ -462,10 +460,7 @@ mod tests {
let mut buf = String::new();
let config = DisplayDiagnosticConfig::new("ty")
.color(false)
.context(0)
.format(DiagnosticFormat::Full);
let config = DisplayDiagnosticConfig::new("ty").color(false).context(0);
for diagnostic in diagnostics {
let diag = diagnostic.into_diagnostic();
let config = config
+27 -18
View File
@@ -9,9 +9,14 @@ use crate::metadata::value::{RelativeGlobPattern, RelativePathBuf};
use ordermap::OrderMap;
use pep440_rs::VersionSpecifiers;
use ruff_db::RustDoc;
#[cfg(feature = "junit")]
use ruff_db::diagnostic::render::JunitRenderer;
use ruff_db::diagnostic::render::{
ConciseRenderer, FileResolver, FullRenderer, GithubRenderer, GitlabRenderer, Renderer,
};
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticFormat, DiagnosticId, DisplayDiagnosticConfig, Severity,
Span, SubDiagnostic, SubDiagnosticSeverity,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, Severity, Span, SubDiagnostic,
SubDiagnosticSeverity,
};
use ruff_db::system::{System, SystemPath, SystemPathBuf};
use ruff_db::vendored::VendoredFileSystem;
@@ -1473,18 +1478,22 @@ impl OutputFormat {
pub const fn is_human_readable(&self) -> bool {
matches!(self, OutputFormat::Full | OutputFormat::Concise)
}
}
impl From<OutputFormat> for DiagnosticFormat {
fn from(value: OutputFormat) -> Self {
match value {
OutputFormat::Full => Self::Full,
OutputFormat::Concise => Self::Concise,
OutputFormat::Gitlab => Self::Gitlab,
OutputFormat::Github => Self::Github,
/// Display diagnostics in this output format.
pub fn display<'a>(
self,
resolver: &'a dyn FileResolver,
config: &'a DisplayDiagnosticConfig,
diagnostics: &'a [Diagnostic],
) -> impl Display + use<'a> {
fmt::from_fn(move |f| match self {
Self::Full => FullRenderer::new(resolver, config).render(f, diagnostics),
Self::Concise => ConciseRenderer::new(resolver, config).render(f, diagnostics),
Self::Gitlab => GitlabRenderer::new(resolver, config).render(f, diagnostics),
Self::Github => GithubRenderer::new(resolver, config).render(f, diagnostics),
#[cfg(feature = "junit")]
OutputFormat::Junit => Self::Junit,
}
Self::Junit => JunitRenderer::new(resolver, config).render(f, diagnostics),
})
}
}
@@ -2276,16 +2285,16 @@ impl ToSettingsError {
let db: &dyn ruff_db::Db = db;
fmt::from_fn(move |f| {
let display_config = DisplayDiagnosticConfig::new("ty")
.format(self.output_format.into())
.color(self.color);
let display_config = DisplayDiagnosticConfig::new("ty").color(self.color);
write!(
f,
"{}",
self.diagnostic
.to_diagnostic()
.display(&db, &display_config)
self.output_format.display(
&db,
&display_config,
&[self.diagnostic.to_diagnostic()]
)
)
})
}
+10 -18
View File
@@ -1,7 +1,8 @@
use crate::{SuppressFix, is_unused_ignore_comment_lint, suppress_all};
use ruff_db::PythonFile;
use ruff_db::cancellation::{Canceled, CancellationToken};
use ruff_db::diagnostic::{DisplayDiagnosticConfig, DisplayDiagnostics};
use ruff_db::diagnostic::DisplayDiagnosticConfig;
use ruff_db::diagnostic::render::{FullRenderer, Renderer};
use ruff_db::parsed::{ParsedModuleRef, parsed_module};
use ruff_db::source::SourceText;
use ruff_db::system::{SystemPath, SystemPathBuf, WritableSystem};
@@ -315,11 +316,8 @@ fn create_fix_introduced_syntax_error_diagnostic(
diag.info(format_args!(
"Introduced syntax errors:\n\n{}",
DisplayDiagnostics::new(
&file_db,
&DisplayDiagnosticConfig::new("ty"),
&parse_diagnostics
)
FullRenderer::new(&file_db, &DisplayDiagnosticConfig::new("ty"))
.display(&parse_diagnostics)
));
diag
@@ -807,9 +805,9 @@ where
mod tests {
use insta::assert_snapshot;
use ruff_db::cancellation::CancellationTokenSource;
use ruff_db::diagnostic::render::{FullRenderer, Renderer};
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, DisplayDiagnostics,
Severity, Span,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, Severity, Span,
};
use ruff_db::files::{File, system_path_to_file};
use ruff_db::parsed::parsed_module;
@@ -2073,11 +2071,8 @@ class B(A):
writeln!(
output,
"## Diagnostics after applying fixes\n\n{diagnostics}\n",
diagnostics = DisplayDiagnostics::new(
&db,
&DisplayDiagnosticConfig::new("ty"),
&fixes.diagnostics
)
diagnostics = FullRenderer::new(&db, &DisplayDiagnosticConfig::new("ty"))
.display(&fixes.diagnostics)
)
.unwrap();
}
@@ -2094,11 +2089,8 @@ class B(A):
writeln!(
&mut output,
"## New diagnostics after re-checking file\n\n{diagnostics}\n",
diagnostics = DisplayDiagnostics::new(
&db,
&DisplayDiagnosticConfig::new("ty"),
&new_diagnostics
)
diagnostics = FullRenderer::new(&db, &DisplayDiagnosticConfig::new("ty"))
.display(&new_diagnostics)
)
.unwrap();
}
@@ -498,8 +498,9 @@ fn is_default_pytest_test_file(db: &dyn Db, file: ProgramFile<'_>) -> bool {
#[cfg(test)]
mod tests {
use insta::assert_snapshot;
use ruff_db::diagnostic::render::{FullRenderer, Renderer};
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, DisplayDiagnostics, Severity,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, Severity,
};
use ruff_db::files::{FileRange, system_path_to_file};
use ruff_db::parsed::parsed_module;
@@ -1320,13 +1321,10 @@ mark: MarkGenerator
})
.collect::<Vec<_>>();
DisplayDiagnostics::new(
db,
&DisplayDiagnosticConfig::new("ty").context(0),
&diagnostics,
)
.to_string()
.replace('\\', "/")
FullRenderer::new(db, &DisplayDiagnosticConfig::new("ty").context(0))
.display(&diagnostics)
.to_string()
.replace('\\', "/")
}
fn program_file<'db>(db: &'db TestDb, path: &str) -> ProgramFile<'db> {
@@ -1582,9 +1582,10 @@ fn end_of_scope_definition<'db>(
#[cfg(test)]
mod tests {
use insta::assert_snapshot;
use ruff_db::diagnostic::render::{FullRenderer, Renderer};
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, DisplayDiagnostics,
Severity, SubDiagnostic, SubDiagnosticSeverity,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, Severity, SubDiagnostic,
SubDiagnosticSeverity,
};
use ruff_db::files::system_path_to_file;
use ruff_db::parsed::parsed_module;
@@ -3527,13 +3528,10 @@ resource = None
}
diagnostic.sub(resolved);
DisplayDiagnostics::new(
db,
&DisplayDiagnosticConfig::new("ty").context(0),
&[diagnostic],
)
.to_string()
.replace('\\', "/")
FullRenderer::new(db, &DisplayDiagnosticConfig::new("ty").context(0))
.display(&[diagnostic])
.to_string()
.replace('\\', "/")
}
fn parameter_definition<'db>(&'db self, parameter_name: &str) -> Definition<'db> {
@@ -94,8 +94,9 @@ mod tests {
use super::{UnreachableKind, unreachable_ranges};
use crate::db::tests::{TestDb, TestDbBuilder};
use insta::assert_snapshot;
use ruff_db::diagnostic::render::{FullRenderer, Renderer};
use ruff_db::diagnostic::{
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, DisplayDiagnostics, Severity,
Annotation, Diagnostic, DiagnosticId, DisplayDiagnosticConfig, Severity,
};
use ruff_db::files::{FileRange, system_path_to_file};
use ruff_python_ast::PythonVersion;
@@ -168,13 +169,10 @@ mod tests {
})
.collect::<Vec<_>>();
DisplayDiagnostics::new(
db,
&DisplayDiagnosticConfig::new("ty").context(0),
&diagnostics,
)
.to_string()
.replace('\\', "/")
FullRenderer::new(db, &DisplayDiagnosticConfig::new("ty").context(0))
.display(&diagnostics)
.to_string()
.replace('\\', "/")
}
#[test]