pub struct DiagnosticMessage {
pub code: Option<String>,
pub title: String,
pub kind: DiagnosticKind,
pub problem: Option<MessageContent>,
pub details: Vec<DetailItem>,
pub hints: Vec<MessageContent>,
pub location: Option<SourceInfo>,
}Expand description
A diagnostic message following tidyverse-style structure.
Structure:
- Code: Optional error code (e.g., “Q-1-1”) for searchability
- Title: Brief error message
- Kind: Error, Warning, Info
- Problem: What went wrong (the “must” or “can’t” statement)
- Details: Specific information (bulleted, max 5 per tidyverse)
- Hints: Optional guidance for fixing (ends with ?)
§Example
let msg = DiagnosticMessage {
code: Some("Q-1-2".to_string()), // quarto-error-code-audit-ignore
title: "Incompatible types".to_string(),
kind: DiagnosticKind::Error,
problem: Some("Cannot combine date and datetime types".into()),
details: vec![
DetailItem {
kind: DetailKind::Error,
content: "`x`{.arg} has type `date`{.type}".into(),
},
DetailItem {
kind: DetailKind::Error,
content: "`y`{.arg} has type `datetime`{.type}".into(),
},
],
hints: vec!["Convert both to the same type?".into()],
source_spans: vec![],
};Fields§
§code: Option<String>Optional error code (e.g., “Q-1-1”)
Error codes are optional but encouraged. They provide:
- Searchability (users can Google “Q-1-1”)
- Stability (codes don’t change even if message wording improves)
- Documentation (each code maps to a detailed explanation)
title: StringBrief title for the error
kind: DiagnosticKindThe kind of diagnostic (Error, Warning, Info)
problem: Option<MessageContent>The problem statement (the “what” - using “must” or “can’t”)
details: Vec<DetailItem>Specific error details (the “where/why” - max 5 per tidyverse)
hints: Vec<MessageContent>Optional hints for fixing (ends with ?)
location: Option<SourceInfo>Source location for this diagnostic
When present, this identifies where in the source code the issue occurred. The location may track transformation history, allowing the error to be mapped back through multiple processing steps to the original source file.
Implementations§
Source§impl DiagnosticMessage
impl DiagnosticMessage
Sourcepub fn builder() -> DiagnosticMessageBuilder
pub fn builder() -> DiagnosticMessageBuilder
Access the diagnostic message builder API.
This is the recommended way to create diagnostic messages, as the builder API encodes tidyverse-style guidelines and makes it easy to construct well-structured error messages.
§Example
use quarto_error_reporting::{DiagnosticMessage, DiagnosticMessageBuilder};
let error = DiagnosticMessageBuilder::error("Incompatible types")
.with_code("Q-1-2") // quarto-error-code-audit-ignore
.problem("Cannot combine date and datetime types")
.add_detail("`x` has type `date`")
.add_detail("`y` has type `datetime`")
.add_hint("Convert both to the same type?")
.build();Sourcepub fn new(kind: DiagnosticKind, title: impl Into<String>) -> Self
pub fn new(kind: DiagnosticKind, title: impl Into<String>) -> Self
Create a new diagnostic message with just a title and kind.
Note: Consider using DiagnosticMessage::builder() instead for better structure.
Sourcepub fn error(title: impl Into<String>) -> Self
pub fn error(title: impl Into<String>) -> Self
Create an error diagnostic.
Note: Consider using DiagnosticMessage::builder().error() instead for better structure.
Sourcepub fn warning(title: impl Into<String>) -> Self
pub fn warning(title: impl Into<String>) -> Self
Create a warning diagnostic.
Note: Consider using DiagnosticMessage::builder().warning() instead for better structure.
Sourcepub fn info(title: impl Into<String>) -> Self
pub fn info(title: impl Into<String>) -> Self
Create an info diagnostic.
Note: Consider using DiagnosticMessage::builder().info() instead for better structure.
Sourcepub fn with_code(self, code: impl Into<String>) -> Self
pub fn with_code(self, code: impl Into<String>) -> Self
Set the error code.
Error codes follow the format Q-<subsystem>-<number> (e.g., “Q-1-1”).
§Example
use quarto_error_reporting::DiagnosticMessage;
let msg = DiagnosticMessage::error("YAML Syntax Error")
.with_code("Q-1-1");Sourcepub fn docs_url(&self) -> Option<&str>
pub fn docs_url(&self) -> Option<&str>
Get the documentation URL for this error, if it has an error code.
§Example
Resolves the code against the installed [CatalogProvider]
(crate::catalog); returns None when no catalog is installed, the
code is unknown, or the entry has no docs URL.
use quarto_error_reporting::DiagnosticMessage;
let msg = DiagnosticMessage::error("Internal Error")
.with_code("Q-0-1");
// `Some(url)` iff a catalog mapping "Q-0-1" (with a docs URL) is installed.
let _ = msg.docs_url();Sourcepub fn to_text(&self, ctx: Option<&SourceContext>) -> String
pub fn to_text(&self, ctx: Option<&SourceContext>) -> String
Render this diagnostic message as text following tidyverse style.
This is a convenience method that uses default rendering options.
For more control over rendering, use Self::to_text_with_options.
§Example
use quarto_error_reporting::DiagnosticMessageBuilder;
let msg = DiagnosticMessageBuilder::error("Invalid input")
.problem("Values must be numeric")
.add_detail("Found text in column 3")
.add_hint("Convert to numbers first?")
.build();
let text = msg.to_text(None);
assert!(text.contains("Error: Invalid input"));
assert!(text.contains("Values must be numeric"));Sourcepub fn to_text_with_options(
&self,
ctx: Option<&SourceContext>,
options: &TextRenderOptions,
) -> String
pub fn to_text_with_options( &self, ctx: Option<&SourceContext>, options: &TextRenderOptions, ) -> String
Render this diagnostic message as text following tidyverse style with custom options.
Format:
Error: title
Problem statement here
✖ Error detail 1
✖ Error detail 2
ℹ Info detail
• Note detail
? Hint 1
? Hint 2§Example
use quarto_error_reporting::{DiagnosticMessageBuilder, TextRenderOptions};
let msg = DiagnosticMessageBuilder::error("Invalid input")
.problem("Values must be numeric")
.add_detail("Found text in column 3")
.add_hint("Convert to numbers first?")
.build();
// Disable hyperlinks for snapshot testing
let options = TextRenderOptions { enable_hyperlinks: false };
let text = msg.to_text_with_options(None, &options);
assert!(text.contains("Error: Invalid input"));Sourcepub fn to_text_with_renderer(
&self,
ctx: Option<&SourceContext>,
options: &TextRenderOptions,
renderer: Option<SourceRenderer>,
) -> String
pub fn to_text_with_renderer( &self, ctx: Option<&SourceContext>, options: &TextRenderOptions, renderer: Option<SourceRenderer>, ) -> String
Like Self::to_text_with_options, but explicitly selects which
source-context snippet renderer draws the visual code excerpt.
Pass Some(SourceRenderer::Ariadne) or
Some(SourceRenderer::AnnotateSnippets) to force a specific
renderer (the corresponding feature must be enabled), or None
to use SourceRenderer::default_for_features. This is the seam
for experimenting with diagnostic rendering styles without
changing the rest of the API: only the source-excerpt block
differs between renderers; the surrounding structured text
(unlocated details, hints) is identical.
When no renderer feature is enabled — or the diagnostic has no
location / source context — this falls back to the structured
tidyverse-style text block, exactly as Self::to_text_with_options.
§Example
use quarto_error_reporting::{DiagnosticMessageBuilder, TextRenderOptions};
let msg = DiagnosticMessageBuilder::error("Invalid input")
.problem("Values must be numeric")
.build();
// `None` picks the default renderer for the enabled features.
let text = msg.to_text_with_renderer(None, &TextRenderOptions::default(), None);
assert!(text.contains("Invalid input"));Sourcepub fn to_json(&self) -> Value
pub fn to_json(&self) -> Value
Render this diagnostic message as a JSON value.
Returns a structured JSON object with all fields:
{
"kind": "error",
"title": "Invalid input",
"code": "Q-1-2", // quarto-error-code-audit-ignore
"problem": "Values must be numeric",
"details": [{"kind": "error", "content": "Found text in column 3"}],
"hints": ["Convert to numbers first?"]
}§Example
use quarto_error_reporting::DiagnosticMessage;
let msg = DiagnosticMessage::error("Something went wrong");
let json = msg.to_json();
assert_eq!(json["kind"], "error");
assert_eq!(json["title"], "Something went wrong");Trait Implementations§
Source§impl Clone for DiagnosticMessage
impl Clone for DiagnosticMessage
Source§impl Debug for DiagnosticMessage
impl Debug for DiagnosticMessage
Source§impl<'de> Deserialize<'de> for DiagnosticMessage
impl<'de> Deserialize<'de> for DiagnosticMessage
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl PartialEq for DiagnosticMessage
impl PartialEq for DiagnosticMessage
Source§impl Serialize for DiagnosticMessage
impl Serialize for DiagnosticMessage
impl StructuralPartialEq for DiagnosticMessage
Auto Trait Implementations§
impl Freeze for DiagnosticMessage
impl RefUnwindSafe for DiagnosticMessage
impl Send for DiagnosticMessage
impl Sync for DiagnosticMessage
impl Unpin for DiagnosticMessage
impl UnsafeUnpin for DiagnosticMessage
impl UnwindSafe for DiagnosticMessage
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);