zesterer/ariadne

A fancy compiler diagnostics crate

examples/ for more examples

Ariadne

.

Example

See examples/ for more examples.

About

ariadne is a sister project of chumsky. Neither are dependent on one-another, but I'm working on both simultaneously and like to think that their features compliment each other. If you're thinking of using ariadne to process your compiler's output, why not try using chumsky to process its input?

Features

  • Inline and multi-line labels capable of handling arbitrary configurations of spans
  • Multi-file errors
  • Generic across custom spans and file caches
  • A choice of character sets to ensure compatibility
  • Coloured labels & highlighting with 8-bit and 24-bit color support (thanks to yansi)
  • Label priority and ordering
  • Compact mode for smaller diagnostics
  • Correct handling of variable-width characters such as tabs
  • A ColorGenerator type that generates distinct colours for visual elements.
  • A plethora of other options (tab width, label attach points, underlines, etc.)
  • Built-in ordering/overlap heuristics that come up with the best way to avoid overlapping & label crossover

Planned Features

  • Improved layout planning & space usage
  • Non-ANSI terminal support
  • More accessibility options (screenreader-friendly mode, textured highlighting as an alternative to color, etc.)
  • More color options
  • Better support for layout restrictions (maximum terminal width, for example)

Stability

The API (should) follow semver. However, this does not apply to the layout of final error messages. Minor tweaks to the internal layout heuristics can often result in the exact format of error messages changing with labels moving slightly. If you experience a change in layout that you believe to be a regression (either the change is incorrect, or makes your diagnostics harder to read) then please open an issue.

Credit

Thanks to:

  • @brendanzab for their beautiful codespan crate that inspired me to try pushing the envelope of error diagnostics.

  • @estebank for showing innumerable people just how good compiler diagnostics can be through their work on Rust.

Issues

Collection of the latest Issues

ccgauche

ccgauche

Comment Icon0

This is quite important since in most cases we don't know at the top of our project from which file originated the error and we don't want to pass all the files imported. So we definitely need a way to get back the location so we can give the correct file while printing.

cswinter

cswinter

Comment Icon1

The first _ is labeling the right character, but it's unclear what the floating __ on line 6 signifies. Produced by the following code:

cswinter

cswinter

Comment Icon0

It would be nice to be able to clone ReportBuilder to make it possible to print it with different configs. E.g. when writing tests for error messages, I would like to compare the report against a simple string without ANSI codes, but print out the report with colors if it doesn't match.

rhysd

rhysd

bug
Comment Icon2

Repro

Run the example:

Expected results

All characters are rendered as expected

Actual results

Up arrow character 🭯 (U+1FB6F) is rendered as '?'.

screenshot

Additional info

I tried the following famous terminals but all did not display the character as expected.

  • Terminal.app
  • iTerm2
  • Alacritty

And I also tried several famous fonts but they did not help to solve this issue too.

  • SF Mono
  • Courier
  • Menlo
  • Monaco
  • JetBrains Mono NL

My enviornment

  • macOS 11
  • Rust 1.56.1
robojeb

robojeb

Comment Icon2

I recently switched my parsing from going over a stream of characters produced by str::chars() to parsing over a stream of characters from ariadne::Source::chars(). This makes it a lot easier to load all of my source files through a cache which can be directly used by ariadne for printing reports.

Unfortunately it isn't well documented that str::char() and ariadne::Source::chars() don't produce the same, or even roughly equivalent, output.

I spent some time debugging why none of my line-ending parsers were succeeding before I realized that ariadne::Source::chars() doesn't produce any line-endings (or even whitespace).

It would be nice if ariadne::Source::chars() were documented as not producing any white-space.

It would also be nice if ariadne::Source provided another method which could get a stream of characters including line-endings with appropriate spans.

I mocked up an adapter which can re-engineer a character stream which is mostly equivalent to str::chars() as long as your parser doesn't care about white-space. It returns all the characters in the file with their correct indices, and then also injects newline characters using the index at the end of the line span. This works as a replacement for str::chars().enumerate() in my parsing code.

bestouff

bestouff

Comment Icon0

Here's my christmas wishlist for the API overhaul:

  • allow working with non-str data (#8)
  • get rid of initial location in Report::build() (#3)
  • pass Cache by shared reference to allow several threads to access it (#10)
  • allow SourceId (which may be e.g. a reference or an index) to only be interpreted by Cache (don't require it to be Display) and maybe this one would be nice:
  • allow somehow to print differently to use the errors in a TUI(#11)

Feel free to edit or comment.

bestouff

bestouff

Comment Icon8

I've got some troubles trying to implement Cache; trying to compile this:

Errors like this:

Shouldn't the Cache trait have an explicit lifetime ? Otherwise I don't know how to reconcile 'p and 'a in my example.FileId (what stands for an SourceId) is just an usize indexing into the right File structure, in my Project structure.

jjl

jjl

enhancement
Comment Icon1

I have been thinking about how to make nice errors for using builtins in the lisp for my in-progress build tool, dull. At first i copied the structure of the example output image (in wonderfully shit ascii art lol), but it occurred to me that it would be nice to put the reasons above so that they read in order.

How does this fit into your plans for layout?

Spu7Nix

Spu7Nix

enhancement
Comment Icon0

Right now, the error drawer seems to assume that span.start() and span.end() are character indices rather than byte indices. This might be useful for manually choosing the error position, but most lexers use byte positions instead of character positions.

This makes a difference when you use Unicode characters in the source. This is a language that is lexed using logos, which uses byte indices:

The error gets offset because of some Unicode characters before the error position:

I am not sure what the most idiomatic API for this is, but one way could be to have an optional function in the Span trait that looks something like fn uses_bytes() -> bool, where the default implementation just returns false. Another way is to add the option to the Config struct.

eaglgenes101

eaglgenes101

enhancement
Comment Icon3

In codespan-reporting crate, it is possible to attach multiple notes to a diagnostic message. In ariadne, there is only one message and only one note available to provide, limiting the diagnostic messages that I can create with an Ariadne report. It'd be a nice feature if I could associate multiple formatted messages or notes to any given Ariadne report.

gamma-delta

gamma-delta

bug
Comment Icon7

Hello, I am trying to use ariadne for error reporting for a crate. I am getting a problem with printing Reports that span multiple lines.

Here is some example code:

and it produces this:

What should happen: The start and end lines are displayed along with both labels

What actually happens: Only the start line is displayed; the second label is completely absent.


I cannot figure out what causes it to go wrong but my hunch is that the span from 5..6 is the problem because 6 is "out of bounds" of the string (even though it's used as the exclusive endpoint).

eaglgenes101

eaglgenes101

Comment Icon3

In the method to create a report builder, there are two arguments corresponding to a source ID and a location. From reading the source code, these correspond to a location field inside the report builder struct, which is only ever used in https://github.com/zesterer/ariadne/blob/e3cb394cb56ecda116a0a1caecd385a49e7f6662/src/write.rs#L137 and following lines for determining a source location in certain cases. Am I missing something, or am I correct in thinking that this initial location could (and for ease of end usage, should) be made optional?

Information - Updated Nov 23, 2021

Stars: 509
Forks: 10
Issues: 16

Repositories & Extras

A fantasy deathcrawl in Rust

To run, with Rust compiler and Cargo package manager installed:

A fantasy deathcrawl in Rust

MIRAI is an abstract interpreter for the Rust compiler's mid-level intermediate

MIRAI is an abstract interpreter for the mid-level intermediate

MIRAI is an abstract interpreter for the Rust compiler's mid-level intermediate

Rust compiler toolkit for WebAssembly apps in the WasmEdge Runtime

Developers: Getting started with the Tencent Serverless Functions for AI inference, or WasmEdge Runtime

Rust compiler toolkit for WebAssembly apps in the WasmEdge Runtime

guessing_game_rust

A repo used to learn rust using the Rust compiler

guessing_game_rust

owner-thing-rust

A repo used to learn rust using the Rust compiler

owner-thing-rust

enums_thing_rust

A repo used to learn rust using the Rust compiler

enums_thing_rust

collections-rust

A repo used to learn rust using the Rust compiler

collections-rust

A snake game written in Rust

Download Rust compiler from

A snake game written in Rust

C Compiler in Rust

A basic C compiler written in Rust, roughly following the tutorial official Rust compiler was taken as inspiration

C Compiler in Rust

It is rust bindings and wrapper around libconfig library

It is rust bindings and wrapper around Rust Compiler

It is rust bindings and wrapper around libconfig library

Toy Rust Compiler

A compiler can be broken down into 4 parts

Toy Rust Compiler
Facebook Instagram Twitter GitHub Dribbble
Privacy