Copyright | (c) 2020 comp |
---|---|
License | MIT |
Maintainer | onecomputer00@gmail.com |
Stability | stable |
Portability | portable |
Safe Haskell | Safe |
Language | Haskell2010 |
This module is for creating pretty error messages. We assume very little about the format you want to use, so much of this module is to allow you to customize your error messages.
To get started, see the documentation for prettyErrors
. When using this module, we recommend you turn on the
OverloadedStrings
extension and import Data.Text at the very least due to the use of Text
(strict).
The overall workflow to use the printer is to convert your error type to Errata
, which entails converting your errors
to Errata
by filling in messages and Block
s. You can create Errata
and Block
from their constructors, or use
the convenience functions for common usecases, like errataSimple
and blockSimple
.
Synopsis
- data Errata = Errata {
- errataHeader :: Maybe Text
- errataBlock :: Block
- errataBlocks :: [Block]
- errataBody :: Maybe Text
- errataSimple :: Maybe Text -> Block -> Maybe Text -> Errata
- data Block = Block {
- blockStyle :: Style
- blockLocation :: (FilePath, Int, Int)
- blockPointers :: [Pointer]
- blockBody :: Maybe Text
- blockSimple :: Style -> FilePath -> Int -> (Int, Int) -> Maybe Text -> Maybe Text -> Block
- blockSimple' :: Style -> FilePath -> Int -> Int -> Maybe Text -> Maybe Text -> Block
- blockConnected :: Style -> FilePath -> (Int, Int, Int, Maybe Text) -> (Int, Int, Int, Maybe Text) -> Maybe Text -> Block
- blockConnected' :: Style -> FilePath -> (Int, Int, Maybe Text) -> (Int, Int, Maybe Text) -> Maybe Text -> Block
- blockMerged :: Style -> FilePath -> (Int, Int, Int, Maybe Text) -> (Int, Int, Int, Maybe Text) -> Maybe Text -> Maybe Text -> Block
- blockMerged' :: Style -> FilePath -> (Int, Int, Maybe Text) -> (Int, Int, Maybe Text) -> Maybe Text -> Maybe Text -> Block
- data Pointer = Pointer {}
- data Style = Style {
- styleLocation :: (FilePath, Int, Int) -> Text
- styleNumber :: Int -> Text
- styleLine :: [(Int, Int)] -> Text -> Text
- styleEllipsis :: Text
- styleLinePrefix :: Text
- styleUnderline :: Text
- styleVertical :: Text
- styleHorizontal :: Text
- styleDownRight :: Text
- styleUpRight :: Text
- styleUpDownRight :: Text
- basicStyle :: Style
- fancyStyle :: Style
- fancyRedStyle :: Style
- fancyYellowStyle :: Style
- prettyErrors :: Source source => source -> [Errata] -> Text
- prettyErrorsNE :: Source source => source -> NonEmpty Errata -> Text
Error format data
A collection of information for pretty printing an error.
Errata | |
|
Creates a simple error that has a single block, with an optional header or body.
Blocks and pointers
Information about a block in the source code, such as pointers and messages.
Each block has a style associated with it.
Block | |
|
:: Style | The style of the pointer. |
-> FilePath | The filepath. |
-> Int | The line number starting at 1. |
-> (Int, Int) | The column span. These start at 1. |
-> Maybe Text | The label. |
-> Maybe Text | The body message. |
-> Block |
A simple block that points to only one line and optionally has a label or a body message.
:: Style | The style of the pointer. |
-> FilePath | The filepath. |
-> Int | The line number starting at 1. |
-> Int | The column number starting at 1. |
-> Maybe Text | The label. |
-> Maybe Text | The body message. |
-> Block |
A variant of blockSimple
that only points at one column.
:: Style | The style of the pointer. |
-> FilePath | The filepath. |
-> (Int, Int, Int, Maybe Text) | The first line number and column span, starting at 1, as well as a label. |
-> (Int, Int, Int, Maybe Text) | The second line number and column span, starting at 1, as well as a label. |
-> Maybe Text | The body message. |
-> Block |
A block that points to two parts of the source that are visually connected together.
:: Style | The style of the pointer. |
-> FilePath | The filepath. |
-> (Int, Int, Maybe Text) | The first line number and column, starting at 1, as well as a label. |
-> (Int, Int, Maybe Text) | The second line number and column, starting at 1, as well as a label. |
-> Maybe Text | The body message. |
-> Block |
A variant of blockConnected
where the pointers point at only one column.
:: Style | The style of the pointer. |
-> FilePath | The filepath. |
-> (Int, Int, Int, Maybe Text) | The first line number and column span, starting at 1, as well as a label. |
-> (Int, Int, Int, Maybe Text) | The second line number and column span, starting at 1, as well as a label. |
-> Maybe Text | The label for when the two pointers are merged into one. |
-> Maybe Text | The body message. |
-> Block |
A block that points to two parts of the source that are visually connected together.
If the two parts of the source happen to be on the same line, the pointers are merged into one.
:: Style | The style of the pointer. |
-> FilePath | The filepath. |
-> (Int, Int, Maybe Text) | The first line number and column, starting at 1, as well as a label. |
-> (Int, Int, Maybe Text) | The second line number and column, starting at 1, as well as a label. |
-> Maybe Text | The label for when the two pointers are merged into one. |
-> Maybe Text | The body message. |
-> Block |
A variant of blockMerged
where the pointers point at only one column.
A pointer is the span of the source code at a line, from one column to another. Each of the positions start at 1.
A pointer may also have a label that will display inline.
A pointer may also be connected to all the other pointers within the same block.
Pointer | |
|
Styling options
Stylization options for a block, e.g. characters to use.
Style | |
|
basicStyle :: Style Source #
A basic style using only ASCII characters.
Errors should look like so:
error header message --> file.ext:1:16 | 1 | line 1 foo bar do | ________________^^ start label 2 | | line 2 | | ^ unconnected label 3 | | line 3 . | |______^ middle label 6 | | line 6 7 | | line 7 baz end | |______^_____^^^ end label | | | | inner label block body message error body message
fancyStyle :: Style Source #
A fancy style using Unicode characters.
Errors should look like so:
error header message → file.ext:1:16 │ 1 │ line 1 foo bar do │ ┌────────────────^^ start label 2 │ │ line 2 │ │ ^ unconnected label 3 │ │ line 3 . │ ├──────^ middle label 6 │ │ line 6 7 │ │ line 7 baz end │ └──────^─────^^^ end label │ │ │ └ inner label block body message error body message
fancyRedStyle :: Style Source #
A fancy style using Unicode characters and ANSI colors, similar to fancyStyle
. Most things are colored red.
fancyYellowStyle :: Style Source #
A fancy style using Unicode characters and ANSI colors, similar to fancyStyle
. Most things are colored yellow.
Pretty printer
prettyErrors :: Source source => source -> [Errata] -> Text Source #
Pretty prints errors. The original source is required. Returns Text
(lazy). If the list is empty,
an empty string is returned.
Suppose we had an error of this type:
data ParseError = ParseError { peFile :: FilePath , peLine :: Int , peCol :: Int , peUnexpected :: T.Text , peExpected :: [T.Text] }
Then we can create a simple pretty printer like so:
import qualified Data.List.NonEmpty as N import qualified Data.Text as T import qualified Data.Text.Lazy.IO as TL import Errata toErrata :: ParseError -> Errata toErrata (ParseError fp l c unexpected expected) = errataSimple (Just "error: invalid syntax") (blockSimple basicStyle fp l (c, c + T.length unexpected) Nothing (Just $ "unexpected " <> unexpected <> "\nexpected " <> T.intercalate ", " expected)) Nothing printErrors :: T.Text -> [ParseError] -> IO () printErrors source es = TL.putStrLn $ prettyErrors source (toErrata <$> es)
Note that in the above example, we have OverloadedStrings
enabled to reduce uses of pack
.
An example error message from this might be:
error: invalid syntax --> ./comma.json:2:18 | 2 | "bad": [1, 2,] | ^ unexpected ] expected null, true, false, ", -, digit, [, {
prettyErrorsNE :: Source source => source -> NonEmpty Errata -> Text Source #
A variant of prettyErrors
for non-empty lists. You can ensure the output is never an empty string.