What's in 0.2
- Multi-file diagnostics — labels in different files render as separate sections.
- Suggestions / fix-its —
with_suggestion(Suggestion::new(span, replacement))plusApplicability(auto-applicable / review / placeholders). Severity::Bug— for ICEs; counted separately, distinct color.- JSON output mode —
engine.format_all_json()(stable schema, opt-in via defaultjsonfeature). Span::from_zero_based(file, line, col, len)— drop-in for parsers that emit 0-based positions.Label::with_note(s)— span-local note rendered under the caret.- Tab + Unicode-width aware — carets line up under emoji / CJK / tab-indented sources.
SourceCache— split source once, reuse across many diagnostics.RenderOptions— tab width, context lines, max line width, color toggle.diag!macro — short formdiag!(MyError::Foo, span, "msg").- Long-line truncation —
RenderOptions::max_line_widthclamps with ellipsis. - Error code URLs —
DiagnosticCode::url()rendered after the code.
Quick start
[]
= "0.2"
use *;
Output:
error: [E0001]: unexpected `;`
--> main.lang:1:8
|
1 | let x = ;
| ^ expected expression before `;`
|
= help: try `let x = <value>;`
How it works
You define an enum with your error codes and implement DiagnosticCode on it. That's it. The engine handles collecting, counting, and rendering.
DiagnosticEngine<C> collects diagnostics, tracks counts, renders output
Diagnostic<C> single error/warning with labels, notes, help
C: DiagnosticCode your enum
Label points at source code (span + message + style)
Span file + line + column + length
notes: Vec<String>
help: Option<String>
DiagnosticCode trait
Severity variants: Bug (ICE), Error, Warning, Note, Help.
API
Span
new
Just a location. Not tied to any lexer or parser.
Label
primary // ^^^^ main error site
secondary // ---- related context
Diagnostic
new
.with_label
.with_note
.with_help
Builder methods take impl Into<String>, so both &str and String work.
DiagnosticEngine
let mut engine = new;
engine.emit;
engine.emit_errors; // batch emit
engine.emit_warnings;
engine.extend; // merge two engines
engine.has_errors;
engine.has_warnings;
engine.error_count;
engine.warning_count;
engine.print_all; // colored terminal output
engine.format_all; // colored string (no print)
engine.format_all_plain; // plain text for logs/CI
engine.get_diagnostics; // &[Diagnostic<C>]
engine.get_errors; // Vec<&Diagnostic<C>>
engine.get_warnings;
engine.len;
engine.is_empty;
engine.clear;
Examples
Compiler - scanner/parser/semantic errors: examples/compiler.rs
SQL engine - unknown columns, division by zero, missing indexes: examples/sql_engine.rs
Config linter - duplicate keys, invalid values, deprecated fields: examples/config_linter.rs
API validator - missing fields, bad formats, deprecated endpoints: examples/api_validator.rs
Suggestion / fix-it - auto-applicable rewrites: examples/suggestion.rs
Multi-file - labels across two files: examples/multi_file.rs
JSON output - LSP/IDE-friendly: examples/json_output.rs
All at once: cargo run --example demo
Advanced API
Render options
let opts = RenderOptions ;
let s = engine.format_all_with;
Source cache (reuse across diagnostics)
let cache = new;
for d in engine.get_diagnostics
from_zero_based
// Parser emits 0-based line+column? No problem.
let span = from_zero_based;
assert_eq!;
assert_eq!;
Suggestions
new
.with_suggestion;
diag! macro
let d = diag!
.with_help;
JSON
let json = engine.format_all_json; // schema-stable, IDE-ready
Contributing
See CONTRIBUTING.md for guidelines.
Security
See SECURITY.md for reporting vulnerabilities.
License
MIT - Copyright (c) 2024 @gentleduck