package grace
Install
Dune Dependency
Authors
Maintainers
Sources
sha256=821df54882c9253eac69f47bcf3a71ffdc61c77fdae42587c32aada5b56cfeae
sha512=007afa83251da3ddecd874e120ea89dce0253c387a64a5fece69069d3486ec5eb6c82d6bf0febaf23dd322bd9eaadc2f7882e33f05a2e1fa18a41294e7dc3ba1
Description
Published: 03 Jun 2024
README
Grace ๐
Grace is an OCaml ๐ช library that includes a series of interfaces for building, reporting, and rendering beautiful compiler errors ๐.
![](./assets/readme_example.png)
We're still actively working on Grace to support more use cases and improving the quality of the rendering engine. Contributions are very welcome!
Features
๐ Inline and multi-line error messages with associated priorities
๐ Multi-file errors
โ๏ธ Configurable rendering (styling and character set)
๐ฐ Rich and compact error rendering
๐ Colored messages (thanks to
Fmt
'sstyle
) for ANSI terminals๐ช Written in OCaml
๐ Unicode support
๐ฏ Error codes
Planned Features
[ ] LSP integration
[ ] Accessibility features (improved color options, narratable renderers)
[ ] HTML renderer
Installation
This library is available on opam
. To install
opam install grace
Users of dune
can then use this library by adding the appropriate libraries:
(library
...
(libraries grace grace.rendering ...))
Usage
open! Grace
(* Grace provides a [Source] API for in-memory representations of sources/files. *)
let fizz : Source.t =
`String
{ name = Some "fizz.ml"
; content =
{|
let fizz n =
match n mod 5, n mod 3 with
| 0, 0 -> `Fizz_buzz
| 0, _ -> `Fizz
| _, 0 -> `Buzz
| _, _ -> n
;;
|}
}
;;
(* Grace provides support for error codes.
Error codes are arbitrary types with an explicit [code_to_string] function
which converts the code into a short (googlable) error code. This allows
library users to inspect (and match on) certain types of diagnostics. *)
type code = Incompatible_types
let code_to_string = function
| Incompatible_types -> "E001"
;;
(* Normally locations (ranges) would be taken from AST nodes, but for sake of
this example we construct them directly. *)
let diagnostic =
let range start stop =
Range.create ~source:fizz (Byte_index.of_int start) (Byte_index.of_int stop)
in
Diagnostic.(
createf
~labels:
Label.
[ primaryf
~range:(range 116 117)
"expected `[> `Buzz | `Fizz | `Fizz_buzz]`, found `int`"
; secondaryf ~range:(range 17 117) "`match` cases have incompatible types"
; secondaryf ~range:(range 57 67) "this is found to be of type `[> `Fizz_buzz]`"
; secondaryf ~range:(range 80 85) "this is found to be of type `[> `Fizz]`"
; secondaryf ~range:(range 98 103) "this is found to be of type `[> `Buzz]`"
]
~code:Incompatible_types
Error
"`match` cases have incompatible types")
;;
let () =
Format.printf
"%a@."
Grace_ansi_renderer.(pp_diagnostic ())
diagnostic
;;
Authors and Acknowledgement
Authors:
Alistair O'Brien (
@johnyob
)
grace
was heavily inspired by all the work on compiler diagnostics in the Rust ecosystem:
@brendanzab
for thecodespan
crate which heavily influenced the design ofgrace
's rendering engine.ariadne
(@zesterer
) for pushing the boundary on diagnostic rendering.rustc
and@estebank
's work on the state-of-the-art work on compiler diagnostics
License
This code is free, under the MIT license.