package grace

  1. Overview
  2. Docs
A fancy diagnostics library that allows your compilers to exit with grace

Install

dune-project
 Dependency

Authors

Maintainers

Sources

grace-0.3.0.tbz
sha256=6948979d6ffb5e596773baead81e9ceef36726d6956261bdd62abb2666a45bfc
sha512=db8b39cc9a77d919ab3123bb4047bb6c672c61db9fc6810951e267b2b113c4ac07266ef57188c6db0c02cb4d43d054204cd66ebc91648dbd1da1228022b0e67b

Description

Published: 16 Feb 2026

README

Grace ๐Ÿ’…

Grace is an OCaml ๐Ÿช library that includes a series of interfaces for building, reporting, and rendering beautiful compiler errors ๐Ÿ“œ.

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's style) 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.ansi_renderer ...))

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 the codespan crate which heavily influenced the design of grace'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.

Dependencies (7)

  1. ppx_sexp_conv
  2. sexplib
  3. uutf
  4. iter
  5. fmt >= "0.8.7"
  6. dune >= "3.4"
  7. ocaml >= "4.14.0"

Dev Dependencies (4)

  1. odoc with-doc
  2. ppx_jane with-test
  3. core with-test
  4. dedent with-test

Used by

None

Conflicts

None