packages feed

diagnose 2.4.0 → 2.5.0

raw patch · 14 files changed

+371/−218 lines, 14 filesdep ~aesondep ~prettyprinter-ansi-terminaldep ~unordered-containersPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: aeson, prettyprinter-ansi-terminal, unordered-containers

API changes (from Hackage documentation)

- Error.Diagnose.Compat.Megaparsec: class HasHints e msg
- Error.Diagnose.Compat.Megaparsec: diagnosticFromBundle :: forall msg s e. (IsString msg, Stream s, HasHints e msg, ShowErrorComponent e, VisualStream s, TraversableStream s) => (ParseError s e -> Bool) -> Maybe msg -> msg -> Maybe [Note msg] -> ParseErrorBundle s e -> Diagnostic msg
- Error.Diagnose.Compat.Megaparsec: errorDiagnosticFromBundle :: forall msg s e. (IsString msg, Stream s, HasHints e msg, ShowErrorComponent e, VisualStream s, TraversableStream s) => Maybe msg -> msg -> Maybe [Note msg] -> ParseErrorBundle s e -> Diagnostic msg
- Error.Diagnose.Compat.Megaparsec: hints :: HasHints e msg => e -> [Note msg]
- Error.Diagnose.Compat.Megaparsec: warningDiagnosticFromBundle :: forall msg s e. (IsString msg, Stream s, HasHints e msg, ShowErrorComponent e, VisualStream s, TraversableStream s) => Maybe msg -> msg -> Maybe [Note msg] -> ParseErrorBundle s e -> Diagnostic msg
- Error.Diagnose.Compat.Parsec: class HasHints e msg
- Error.Diagnose.Compat.Parsec: diagnosticFromParseError :: forall msg. (IsString msg, HasHints Void msg) => (ParseError -> Bool) -> Maybe msg -> msg -> Maybe [Note msg] -> ParseError -> Diagnostic msg
- Error.Diagnose.Compat.Parsec: errorDiagnosticFromParseError :: forall msg. (IsString msg, HasHints Void msg) => Maybe msg -> msg -> Maybe [Note msg] -> ParseError -> Diagnostic msg
- Error.Diagnose.Compat.Parsec: hints :: HasHints e msg => e -> [Note msg]
- Error.Diagnose.Compat.Parsec: warningDiagnosticFromParseError :: forall msg. (IsString msg, HasHints Void msg) => Maybe msg -> msg -> Maybe [Note msg] -> ParseError -> Diagnostic msg
- Error.Diagnose.Diagnostic: def :: Default a => a
- Error.Diagnose.Diagnostic: diagnosticToJson :: ToJSON msg => Diagnostic msg -> ByteString
- Error.Diagnose.Position: instance Data.Aeson.Types.ToJSON.ToJSON Error.Diagnose.Position.Position
- Error.Diagnose.Style: reAnnotate :: (ann -> ann') -> Doc ann -> Doc ann'
+ Error.Diagnose.Diagnostic: TabSize :: Int -> TabSize
+ Error.Diagnose.Diagnostic: WithUnicode :: WithUnicode
+ Error.Diagnose.Diagnostic: WithoutUnicode :: WithUnicode
+ Error.Diagnose.Diagnostic: data WithUnicode
+ Error.Diagnose.Diagnostic: newtype TabSize
+ Error.Diagnose.Diagnostic: prettyDiagnostic' :: WithUnicode -> TabSize -> Diagnostic (Doc ann) -> Doc (Annotation ann)
+ Error.Diagnose.Diagnostic: printDiagnostic' :: MonadIO m => Handle -> WithUnicode -> TabSize -> Style ann -> Diagnostic (Doc ann) -> m ()
+ Error.Diagnose.Style: OtherStyle :: a -> Annotation a
+ Error.Diagnose.Style: instance Data.Foldable.Foldable Error.Diagnose.Style.Annotation
+ Error.Diagnose.Style: instance Data.Traversable.Traversable Error.Diagnose.Style.Annotation
+ Error.Diagnose.Style: instance GHC.Base.Functor Error.Diagnose.Style.Annotation
+ Error.Diagnose.Style: instance GHC.Classes.Eq a => GHC.Classes.Eq (Error.Diagnose.Style.Annotation a)
+ Error.Diagnose.Style: instance GHC.Classes.Ord a => GHC.Classes.Ord (Error.Diagnose.Style.Annotation a)
+ Error.Diagnose.Style: instance GHC.Generics.Generic (Error.Diagnose.Style.Annotation a)
+ Error.Diagnose.Style: instance GHC.Show.Show a => GHC.Show.Show (Error.Diagnose.Style.Annotation a)
+ Error.Diagnose.Style: unadornedStyle :: Style a
- Error.Diagnose.Diagnostic: prettyDiagnostic :: Pretty msg => Bool -> Int -> Diagnostic msg -> Doc Annotation
+ Error.Diagnose.Diagnostic: prettyDiagnostic :: Pretty msg => WithUnicode -> TabSize -> Diagnostic msg -> Doc (Annotation ann)
- Error.Diagnose.Diagnostic: printDiagnostic :: (MonadIO m, Pretty msg) => Handle -> Bool -> Bool -> Int -> Style -> Diagnostic msg -> m ()
+ Error.Diagnose.Diagnostic: printDiagnostic :: (MonadIO m, Pretty msg) => Handle -> WithUnicode -> TabSize -> Style ann -> Diagnostic msg -> m ()
- Error.Diagnose.Style: CodeStyle :: Annotation
+ Error.Diagnose.Style: CodeStyle :: Annotation a
- Error.Diagnose.Style: FileColor :: Annotation
+ Error.Diagnose.Style: FileColor :: Annotation a
- Error.Diagnose.Style: HintColor :: Annotation
+ Error.Diagnose.Style: HintColor :: Annotation a
- Error.Diagnose.Style: KindColor :: Bool -> Annotation
+ Error.Diagnose.Style: KindColor :: Bool -> Annotation a
- Error.Diagnose.Style: MarkerStyle :: Annotation -> Annotation
+ Error.Diagnose.Style: MarkerStyle :: Annotation a -> Annotation a
- Error.Diagnose.Style: MaybeColor :: Annotation
+ Error.Diagnose.Style: MaybeColor :: Annotation a
- Error.Diagnose.Style: NoLineColor :: Annotation
+ Error.Diagnose.Style: NoLineColor :: Annotation a
- Error.Diagnose.Style: RuleColor :: Annotation
+ Error.Diagnose.Style: RuleColor :: Annotation a
- Error.Diagnose.Style: ThisColor :: Bool -> Annotation
+ Error.Diagnose.Style: ThisColor :: Bool -> Annotation a
- Error.Diagnose.Style: WhereColor :: Annotation
+ Error.Diagnose.Style: WhereColor :: Annotation a
- Error.Diagnose.Style: data Annotation
+ Error.Diagnose.Style: data Annotation a
- Error.Diagnose.Style: defaultStyle :: Style
+ Error.Diagnose.Style: defaultStyle :: Style AnsiStyle
- Error.Diagnose.Style: type Style = Doc Annotation -> Doc AnsiStyle
+ Error.Diagnose.Style: type Style a = Annotation a -> AnsiStyle

Files

README.md view
@@ -39,7 +39,8 @@ A diagnostic can be viewed as a collection of reports, spanning on files. This is what the `Diagnostic` type embodies. -It has a `Default` instance, which can be used to construct an empty diagnostic (contains no reports, and has no files).+It is an instance of `Monoid`, which can be used to construct an empty+diagnostic (contains no reports, and has no files).  The second step is to add some reports. There are two kinds of reports:@@ -99,11 +100,11 @@         -- ^^^^ This is a 'Note' not a 'Hint', as specified by its 'IsString' instance  -- Create the diagnostic-let diagnostic  = addFile def "somefile.zc" "let id<a>(x : a) : a := x\n  + 1"+let diagnostic  = addFile mempty "somefile.zc" "let id<a>(x : a) : a := x\n  + 1" let diagnostic' = addReport diagnostic beautifulExample --- Print with unicode characters, colors and the default style-printDiagnostic stdout True True 4 defaultStyle diagnostic'+-- Print with unicode characters, and the default (colorful) style+printDiagnostic stdout WithUnicode 4 defaultStyle diagnostic' ```  More examples are given in the [`test/rendering`](./test/rendering) folder (execute `stack test` to see the output).
diagnose.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.7.+-- This file has been generated from package.yaml by hpack version 0.35.2. -- -- see: https://github.com/sol/hpack  name:           diagnose-version:        2.4.0+version:        2.5.0 synopsis:       Beautiful error reporting done easily description:    This package provides a simple way of getting beautiful compiler/interpreter errors                 using a very simple interface for the programmer.@@ -71,14 +71,15 @@     , dlist ==1.0.*     , hashable >=1.3 && <2     , prettyprinter >=1.7.0 && <2-    , prettyprinter-ansi-terminal >=1.1.0 && <2+    , prettyprinter-ansi-terminal >=1.1.2 && <2     , text >=1.0.0.0 && <=2.0-    , unordered-containers ==0.2.*+    , unordered-containers >=0.2.11 && <0.3     , wcwidth >=0.0.1 && <1+  default-language: Haskell2010   if flag(json)     cpp-options: -DUSE_AESON     build-depends:-        aeson >=1.5 && <2+        aeson >=1.5 && <3       , bytestring >=0.9 && <1   if flag(megaparsec-compat)     build-depends:@@ -93,7 +94,6 @@   if flag(parsec-compat)     exposed-modules:         Error.Diagnose.Compat.Parsec-  default-language: Haskell2010  test-suite diagnose-megaparsec-tests   type: exitcode-stdio-1.0@@ -117,14 +117,15 @@     , dlist ==1.0.*     , hashable >=1.3 && <2     , prettyprinter >=1.7.0 && <2-    , prettyprinter-ansi-terminal >=1.1.0 && <2+    , prettyprinter-ansi-terminal >=1.1.2 && <2     , text >=1.2 && <3-    , unordered-containers ==0.2.*+    , unordered-containers >=0.2.11 && <0.3     , wcwidth >=0.0.1 && <1+  default-language: Haskell2010   if flag(json)     cpp-options: -DUSE_AESON     build-depends:-        aeson >=1.5 && <2+        aeson >=1.5 && <3       , bytestring >=0.9 && <1   if flag(megaparsec-compat)     build-depends:@@ -135,7 +136,6 @@         parsec >=3.1.14   if !(flag(megaparsec-compat))     buildable: False-  default-language: Haskell2010  test-suite diagnose-parsec-tests   type: exitcode-stdio-1.0@@ -158,14 +158,15 @@     , dlist ==1.0.*     , hashable >=1.3 && <2     , prettyprinter >=1.7.0 && <2-    , prettyprinter-ansi-terminal >=1.1.0 && <2+    , prettyprinter-ansi-terminal >=1.1.2 && <2     , text >=1.2 && <3-    , unordered-containers ==0.2.*+    , unordered-containers >=0.2.11 && <0.3     , wcwidth >=0.0.1 && <1+  default-language: Haskell2010   if flag(json)     cpp-options: -DUSE_AESON     build-depends:-        aeson >=1.5 && <2+        aeson >=1.5 && <3       , bytestring >=0.9 && <1   if flag(megaparsec-compat)     build-depends:@@ -176,7 +177,6 @@         parsec >=3.1.14   if !(flag(parsec-compat))     buildable: False-  default-language: Haskell2010  test-suite diagnose-rendering-tests   type: exitcode-stdio-1.0@@ -198,14 +198,15 @@     , dlist ==1.0.*     , hashable >=1.3 && <2     , prettyprinter >=1.7.0 && <2-    , prettyprinter-ansi-terminal >=1.1.0 && <2+    , prettyprinter-ansi-terminal >=1.1.2 && <2     , text >=1.0.0.0 && <=2.0-    , unordered-containers ==0.2.*+    , unordered-containers >=0.2.11 && <0.3     , wcwidth >=0.0.1 && <1+  default-language: Haskell2010   if flag(json)     cpp-options: -DUSE_AESON     build-depends:-        aeson >=1.5 && <2+        aeson >=1.5 && <3       , bytestring >=0.9 && <1   if flag(megaparsec-compat)     build-depends:@@ -214,4 +215,3 @@   if flag(parsec-compat)     build-depends:         parsec >=3.1.14-  default-language: Haskell2010
src/Error/Diagnose.hs view
@@ -241,7 +241,7 @@ --   >            --   Creates a new diagnostic with no default hints from the bundle returned by megaparsec --   >         diag' = addFile diag filename content --   >            --   Add the file used when parsing with the same filename given to 'MP.runParser'---   >     in printDiagnostic stderr True True 4 diag'+--   >     in printDiagnostic stderr True 4 diag' --   >   Right res   -> print res -- --   This example will return the following error message (assuming default instances for @'Error.Diagnose.Compat.Megaparsec.HasHints' 'Data.Void.Void' msg@):@@ -282,7 +282,7 @@ --   >            --   Creates a new diagnostic with no default hints from the bundle returned by megaparsec --   >         diag' = addFile diag filename content --   >            --   Add the file used when parsing with the same filename given to 'MP.runParser'---   >     in printDiagnostic stderr True True 4 diag'+--   >     in printDiagnostic stderr True 4 diag' --   >   Right res  -> print res -- --   This will output the following error on @stderr@:
src/Error/Diagnose/Diagnostic.hs view
@@ -20,12 +20,15 @@ #endif     addFile,     addReport,-    def,     errorsToWarnings,     hasReports,     reportsOf,     prettyDiagnostic,+    prettyDiagnostic',     printDiagnostic,+    printDiagnostic',     warningsToErrors,+    WithUnicode(..),+    TabSize(..),   ) import System.IO as Export (stderr, stdout)
src/Error/Diagnose/Diagnostic/Internal.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleInstances #-}  -- |@@ -13,7 +14,7 @@ --            It is also highly undocumented. -- --            Please limit yourself to the "Error.Diagnose.Diagnostic" module, which exports some of the useful functions defined here.-module Error.Diagnose.Diagnostic.Internal (module Error.Diagnose.Diagnostic.Internal, def) where+module Error.Diagnose.Diagnostic.Internal (module Error.Diagnose.Diagnostic.Internal, WithUnicode(..), TabSize(..)) where  import Control.Monad.IO.Class (MonadIO, liftIO) #ifdef USE_AESON@@ -24,21 +25,20 @@ import Data.Array (listArray) import Data.DList (DList) import qualified Data.DList as DL-import Data.Default (Default, def) import Data.Foldable (fold, toList) import qualified Data.HashMap.Lazy as HashMap import Data.List (intersperse) import Error.Diagnose.Report (Report)-import Error.Diagnose.Report.Internal (FileMap, errorToWarning, prettyReport, warningToError)+import Error.Diagnose.Report.Internal (FileMap, errorToWarning, prettyReport, warningToError, WithUnicode(..), TabSize(..)) import Error.Diagnose.Style (Annotation, Style)-import Prettyprinter (Doc, Pretty, hardline, unAnnotate)-import Prettyprinter.Render.Terminal (hPutDoc)+import Prettyprinter (Doc, Pretty, hardline, pretty, defaultLayoutOptions, reAnnotateS, layoutPretty)+import Prettyprinter.Render.Terminal (renderIO) import System.IO (Handle)  -- | The data type for diagnostic containing messages of an abstract type. -----   The constructors are private, but users can use 'def' from the 'Default' typeclass---   to create a new empty diagnostic, and 'addFile' and 'addReport' to alter its internal state.+--   Users can use 'mempty' to create a new empty diagnostic, and 'addFile' and+--   'addReport' to alter its internal state. data Diagnostic msg   = Diagnostic       (DList (Report msg))@@ -47,12 +47,13 @@       --   Reports are output one by one, without connections in between.       !FileMap       -- ^ A map associating files with their content as lists of lines.+  deriving (Functor, Foldable, Traversable) -instance Default (Diagnostic msg) where-  def = Diagnostic mempty mempty+instance Monoid (Diagnostic msg) where+  mempty = Diagnostic mempty mempty  instance Semigroup (Diagnostic msg) where-  Diagnostic rs1 file <> Diagnostic rs2 _ = Diagnostic (rs1 <> rs2) file+  Diagnostic rs1 files1 <> Diagnostic rs2 files2 = Diagnostic (rs1 <> rs2) (files1 <> files2)  #ifdef USE_AESON instance ToJSON msg => ToJSON (Diagnostic msg) where@@ -98,35 +99,69 @@ prettyDiagnostic ::   Pretty msg =>   -- | Should we use unicode when printing paths?-  Bool ->+  WithUnicode ->   -- | The number of spaces each TAB character will span.-  Int ->+  TabSize ->   -- | The diagnostic to print.   Diagnostic msg ->-  Doc Annotation-prettyDiagnostic withUnicode tabSize (Diagnostic reports file) =-  fold . intersperse hardline $ prettyReport file withUnicode tabSize <$> toList reports+  Doc (Annotation ann)+prettyDiagnostic withUnicode tabSize =+  prettyDiagnostic' withUnicode tabSize . fmap pretty {-# INLINE prettyDiagnostic #-} +-- | Like 'prettyDiagnostic' except that instead of requiring a 'pretty'+-- instance for messages, this allows passing in your own 'Doc'. Custom+-- annotations are retained in 'OtherStyle'+prettyDiagnostic' ::+  -- | Should we use unicode when printing paths?+  WithUnicode ->+  -- | The number of spaces each TAB character will span.+  TabSize ->+  -- | The diagnostic to print.+  Diagnostic (Doc ann) ->+  Doc (Annotation ann)+prettyDiagnostic' withUnicode tabSize (Diagnostic reports file) =+  fold . intersperse hardline $ prettyReport file withUnicode tabSize <$> toList reports+ -- | Prints a 'Diagnostic' onto a specific 'Handle'. printDiagnostic ::   (MonadIO m, Pretty msg) =>   -- | The handle onto which to output the diagnostic.   Handle ->   -- | Should we print with unicode characters?-  Bool ->-  -- | 'False' to disable colors.-  Bool ->+  WithUnicode ->   -- | The number of spaces each TAB character will span.-  Int ->+  TabSize ->   -- | The style in which to output the diagnostic.-  Style ->+  Style ann ->   -- | The diagnostic to output.   Diagnostic msg ->   m ()-printDiagnostic handle withUnicode withColors tabSize style diag =-  liftIO $ hPutDoc handle ((if withColors then style else unAnnotate) $ prettyDiagnostic withUnicode tabSize diag)+printDiagnostic handle withUnicode tabSize style =+  printDiagnostic' handle withUnicode tabSize style . fmap pretty {-# INLINE printDiagnostic #-}++-- | Like 'printDiagnostic' except that instead of requiring a 'pretty'+-- instance for messages, this allows passing in your own 'Doc'.+printDiagnostic' ::+  MonadIO m =>+  -- | The handle onto which to output the diagnostic.+  Handle ->+  -- | Should we print with unicode characters?+  WithUnicode ->+  -- | The number of spaces each TAB character will span.+  TabSize ->+  -- | The style in which to output the diagnostic.+  Style ann ->+  -- | The diagnostic to output.+  Diagnostic (Doc ann) ->+  m ()+printDiagnostic' handle withUnicode tabSize style =+  liftIO+    . renderIO handle+    . reAnnotateS style+    . layoutPretty defaultLayoutOptions+    . prettyDiagnostic' withUnicode tabSize  -- | Inserts a new referenceable file within the diagnostic. addFile ::
src/Error/Diagnose/Position.hs view
@@ -41,10 +41,7 @@     -- | The file this position spans in.     file :: FilePath   }-  deriving (Show, Eq, Generic)--instance Ord Position where-  Position b1 e1 _ `compare` Position b2 e2 _ = (b1, e1) `compare` (b2, e2)+  deriving (Show, Eq, Ord, Generic)  instance Pretty Position where   pretty (Position (bl, bc) (el, ec) f) = pretty f <> at <> pretty bl <> colon <> pretty bc <> dash <> pretty el <> colon <> pretty ec
src/Error/Diagnose/Pretty.hs view
@@ -1,4 +1,3 @@ module Error.Diagnose.Pretty (module Export) where  import qualified Prettyprinter as Export -import qualified Prettyprinter.Render.Terminal as Export 
src/Error/Diagnose/Report/Internal.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RecordWildCards #-}@@ -23,6 +24,8 @@ module Error.Diagnose.Report.Internal   ( module Error.Diagnose.Report.Internal   , Report(.., Warn, Err)+  , WithUnicode(..)+  , TabSize(..)   ) where  #ifdef USE_AESON@@ -36,19 +39,18 @@ import Data.Default (def) import Data.Foldable (fold) import Data.Function (on)-import Data.Functor ((<&>))+import Data.Functor ((<&>), void) import Data.HashMap.Lazy (HashMap) import qualified Data.HashMap.Lazy as HashMap import qualified Data.List as List import qualified Data.List.Safe as List import Data.Maybe-import Data.Ord (Down (Down)) import Data.String (IsString (fromString))-import qualified Data.Text as Text import Error.Diagnose.Position import Error.Diagnose.Style (Annotation (..))-import Prettyprinter (Doc, Pretty (..), align, annotate, colon, hardline, lbracket, rbracket, space, width, (<+>))-import Prettyprinter.Internal (Doc (..))+import Prettyprinter (Doc, Pretty (..), align, annotate, colon, hardline, lbracket, rbracket, space, width, (<+>), reAnnotate, SimpleDocStream (..), layoutCompact)+import Prettyprinter.Internal (Doc (..), textSpaces)+import Data.Bool (bool)  type FileMap = HashMap FilePath (Array Int String) @@ -67,6 +69,7 @@       -- ^ A map associating positions with marker to show under the source code.       [Note msg]       -- ^ A list of notes to add at the end of the report.+  deriving (Functor, Foldable, Traversable)  -- | Pattern synonym for a warning report. pattern Warn :: Maybe msg -> msg -> [(Position, Marker msg)] -> [Note msg] -> Report msg@@ -120,26 +123,12 @@     Maybe msg   | -- | An empty marker, whose sole purpose is to include a line of code in the report without markers under.     Blank--instance Eq (Marker msg) where-  This _ == This _ = True-  Where _ == Where _ = True-  Maybe _ == Maybe _ = True-  Blank == Blank = True-  _ == _ = False-  {-# INLINEABLE (==) #-}--instance Ord (Marker msg) where-  This _ < _ = False-  Where _ < This _ = True-  Where _ < _ = False-  Maybe _ < _ = True-  _ < Blank = True-  Blank < _ = False-  {-# INLINEABLE (<) #-}+  deriving (Eq, Ord, Functor, Foldable, Traversable) -  m1 <= m2 = m1 < m2 || m1 == m2-  {-# INLINEABLE (<=) #-}+isBlank :: Marker msg -> Bool+isBlank = \case+  Blank -> True+  _ -> False  -- | A note is a piece of information that is found at the end of a report. data Note msg@@ -147,6 +136,7 @@     Note msg   | -- | A hint, to propose potential fixes or help towards fixing the issue.     Hint msg+  deriving (Eq, Ord, Show, Functor, Foldable, Traversable)  #ifdef USE_AESON instance ToJSON msg => ToJSON (Note msg) where@@ -187,18 +177,21 @@ errorToWarning (Report True code msg markers notes) = Report False code msg markers notes errorToWarning r@(Report False _ _ _ _) = r +data WithUnicode = WithoutUnicode | WithUnicode++newtype TabSize = TabSize Int+ -- | Pretty prints a report to a 'Doc' handling colors. prettyReport ::-  Pretty msg =>   -- | The content of the file the reports are for   FileMap ->   -- | Should we print paths in unicode?-  Bool ->+  WithUnicode ->   -- | The number of spaces each TAB character will span-  Int ->+  TabSize ->   -- | The whole report to output-  Report msg ->-  Doc Annotation+  Report (Doc ann) ->+  Doc (Annotation ann) prettyReport fileContent withUnicode tabSize (Report isError code message markers hints) =   let sortedMarkers = List.sortOn (fst . begin . fst) markers       -- sort the markers so that the first lines of the reports are the first lines of the file@@ -219,7 +212,7 @@                  )               <> case code of                 Nothing -> rbracket-                Just code -> space <> pretty code <> rbracket+                Just code -> space <> annotated code <> rbracket           )    in {-               A report is of the form:@@ -234,7 +227,7 @@               (6)    -------+       -} -      {- (1) -} header <> colon <+> align (pretty message)+      {- (1) -} header <> colon <+> align (annotated message)         <> {- (2), (3), (4) -} fold (uncurry (prettySubReport fileContent withUnicode isError tabSize maxLineNumberLength) <$> groupedMarkers)         <> {- (5) -} ( if                            | null hints && null markers -> mempty@@ -246,7 +239,7 @@         <> {- (6) -} ( if null markers && null hints                          then mempty                          else-                           annotate RuleColor (pad (maxLineNumberLength + 2) (if withUnicode then '─' else '-') mempty <> if withUnicode then "╯" else "+")+                           annotate RuleColor (pad (maxLineNumberLength + 2) (unicode '-' '─' withUnicode) mempty <> unicode "+" "╯" withUnicode)                              <> hardline                      ) @@ -268,9 +261,11 @@   -- | The length of the left space before the bullet.   Int ->   -- | Whether to print with unicode characters or not.-  Bool ->-  Doc Annotation-dotPrefix leftLen withUnicode = pad leftLen ' ' mempty <+> annotate RuleColor (if withUnicode then "•" else ":")+  WithUnicode ->+  Doc (Annotation ann)+dotPrefix leftLen withUnicode =+  pad leftLen ' ' mempty+    <+> annotate RuleColor (unicode ":" "•" withUnicode) {-# INLINE dotPrefix #-}  -- | Creates a "pipe"-prefix for a report line where there is no code.@@ -283,9 +278,9 @@   -- | The length of the left space before the pipe.   Int ->   -- | Whether to print with unicode characters or not.-  Bool ->-  Doc Annotation-pipePrefix leftLen withUnicode = pad leftLen ' ' mempty <+> annotate RuleColor (if withUnicode then "│" else "|")+  WithUnicode ->+  Doc (Annotation ann)+pipePrefix leftLen withUnicode = pad leftLen ' ' mempty <+> annotate RuleColor (unicode "|" "│" withUnicode) {-# INLINE pipePrefix #-}  -- | Creates a line-prefix for a report line containing source code@@ -302,11 +297,11 @@   -- | The line number to show.   Int ->   -- | Whether to use unicode characters or not.-  Bool ->-  Doc Annotation+  WithUnicode ->+  Doc (Annotation ann) linePrefix leftLen lineNo withUnicode =   let lineNoLen = length (show lineNo)-   in annotate RuleColor $ mempty <+> pad (leftLen - lineNoLen) ' ' mempty <> pretty lineNo <+> if withUnicode then "│" else "|"+   in annotate RuleColor $ mempty <+> pad (leftLen - lineNoLen) ' ' mempty <> pretty lineNo <+> unicode "|" "│" withUnicode {-# INLINE linePrefix #-}  -- | Creates an ellipsis-prefix, when some line numbers are not consecutive.@@ -317,12 +312,11 @@ --   [without unicode] "@␣␣␣␣...@" ellipsisPrefix ::   Int ->-  Bool ->-  Doc Annotation-ellipsisPrefix leftLen withUnicode = pad leftLen ' ' mempty <> annotate RuleColor (if withUnicode then space <> "⋮" else "...")+  WithUnicode ->+  Doc (Annotation ann)+ellipsisPrefix leftLen withUnicode = pad leftLen ' ' mempty <> annotate RuleColor (unicode "..." (space <> "⋮") withUnicode)  groupMarkersPerFile ::-  Pretty msg =>   [(Position, Marker msg)] ->   [(Bool, [(Position, Marker msg)])] groupMarkersPerFile [] = []@@ -346,29 +340,28 @@  -- | Prettyprint a sub-report, which is a part of the report spanning across a single file prettySubReport ::-  Pretty msg =>   -- | The content of files in the diagnostics   FileMap ->   -- | Is the output done with Unicode characters?-  Bool ->+  WithUnicode ->   -- | Is the current report an error report?   Bool ->   -- | The number of spaces each TAB character will span-  Int ->+  TabSize ->   -- | The size of the biggest line number   Int ->   -- | Is this sub-report the first one in the list?   Bool ->   -- | The list of line-ordered markers appearing in a single file-  [(Position, Marker msg)] ->-  Doc Annotation+  [(Position, Marker (Doc ann))] ->+  Doc (Annotation ann) prettySubReport fileContent withUnicode isError tabSize maxLineNumberLength isFirst markers =   let (markersPerLine, multilineMarkers) = splitMarkersPerLine markers       -- split the list on whether markers are multiline or not        sortedMarkersPerLine = {- second (List.sortOn (first $ snd . begin)) <$> -} List.sortOn fst (HashMap.toList markersPerLine) -      reportFile = maybe (pretty @Position def) (pretty . fst) $ List.safeHead (List.sortOn (Down . snd) markers)+      reportFile = maybe (pretty @Position def) (pretty . fst) $ List.safeHead (List.sortOn (void . snd) markers)       -- the reported file is the file of the first 'This' marker (only one must be present)        allLineNumbers = List.sort $ List.nub $ (fst <$> sortedMarkersPerLine) <> (multilineMarkers >>= \(Position (bl, _) (el, _) _, _) -> [bl .. el])@@ -377,16 +370,16 @@         ( if isFirst             then               space <> pad maxLineNumberLength ' ' mempty-                <+> annotate RuleColor (if withUnicode then "╭──▶" else "+-->")+                <+> annotate RuleColor (unicode "+-->" "╭──▶" withUnicode)             else               space <> dotPrefix maxLineNumberLength withUnicode <> hardline-                <> annotate RuleColor (pad (maxLineNumberLength + 2) (if withUnicode then '─' else '-') mempty)-                <> annotate RuleColor (if withUnicode then "┼──▶" else "+-->")+                <> annotate RuleColor (pad (maxLineNumberLength + 2) (unicode '-' '─' withUnicode) mempty)+                <> annotate RuleColor (unicode "+-->" "┼──▶" withUnicode)         )           <+> annotate FileColor reportFile    in {- (2) -} hardline <> fileMarker         <> hardline-          <+> {- (3) -} pipePrefix maxLineNumberLength withUnicode+          <+> {- (3) -}  {- (3) -} pipePrefix maxLineNumberLength withUnicode         <> {- (4) -} prettyAllLines fileContent withUnicode isError tabSize maxLineNumberLength sortedMarkersPerLine multilineMarkers allLineNumbers  isThisMarker :: Marker msg -> Bool@@ -404,17 +397,16 @@  -- | prettyAllLines ::-  Pretty msg =>   FileMap ->-  Bool ->+  WithUnicode ->   Bool ->   -- | The number of spaces each TAB character will span-  Int ->+  TabSize ->   Int ->-  [(Int, [(Position, Marker msg)])] ->-  [(Position, Marker msg)] ->+  [(Int, [(Position, Marker (Doc ann))])] ->+  [(Position, Marker (Doc ann))] ->   [Int] ->-  Doc Annotation+  Doc (Annotation ann) prettyAllLines files withUnicode isError tabSize leftLen inline multiline lineNumbers =   case lineNumbers of     [] ->@@ -450,38 +442,35 @@           -- take the first multiline marker to color the entire line, if there is one            (multilineEndingOnLine, otherMultilines) = flip List.partition multiline \(Position _ (el, _) _, _) -> el == line+          shouldShowMultiLine = isLastLine+            || ((==) `on` fmap (fmap void)) (List.safeLast multilineEndingOnLine) (List.safeLast multiline)            !additionalPrefix = case allMultilineMarkersInLine of             [] ->               if not $ null multiline                 then                   if not $ null allMultilineMarkersSpanningLine-                    then colorOfFirstMultilineMarker if withUnicode then "│  " else "|  "+                    then colorOfFirstMultilineMarker (unicode "|  " "│  " withUnicode)                     else "   "                 else mempty             (p@(Position _ (el, _) _), marker) : _ ->               let hasPredecessor = el == line || maybe False ((/=) p . fst . fst) (List.safeUncons multiline)                in colorOfFirstMultilineMarker-                    ( if-                          | hasPredecessor && withUnicode -> "├"-                          | hasPredecessor -> "|"-                          | withUnicode -> "╭"-                          | otherwise -> "+"-                    )-                    <> annotate (markerColor isError marker) (if withUnicode then "┤" else ">")+                    (unicode (bool "+" "|" hasPredecessor ) (bool "╭" "├" hasPredecessor) withUnicode)+                    <> annotate (markerColor isError marker) (unicode ">" "┤" withUnicode)                     <> space            -- we need to remove all blank markers because they are irrelevant to the display-          allInlineMarkersInLine' = filter ((/=) Blank . snd) allInlineMarkersInLine-          allMultilineMarkersSpanningLine' = filter ((/=) Blank . snd) allMultilineMarkersSpanningLine+          allInlineMarkersInLine' = filter (not . isBlank . snd) allInlineMarkersInLine+          allMultilineMarkersSpanningLine' = filter (not . isBlank . snd) allMultilineMarkersSpanningLine            (widths, renderedCode) = getLine_ files (allInlineMarkersInLine <> allMultilineMarkersInLine <> allMultilineMarkersSpanningLine') line tabSize isError        in ( otherMultilines,             hardline-              <> {- (1) -} linePrefix leftLen line withUnicode <+> additionalPrefix+              <> {- (1) -} linePrefix leftLen line withUnicode <+>  additionalPrefix               <> renderedCode               <> {- (2) -} showAllMarkersInLine (not $ null multiline) inSpanOfMultiline colorOfFirstMultilineMarker withUnicode isError leftLen widths allInlineMarkersInLine'-              <> showMultiline (isLastLine || List.safeLast multilineEndingOnLine == List.safeLast multiline) multilineEndingOnLine+              <> showMultiline shouldShowMultiLine multilineEndingOnLine           )      showMultiline _ [] = mempty@@ -489,33 +478,33 @@       let colorOfFirstMultilineMarker = markerColor isError . snd <$> List.safeHead multiline           -- take the color of the last multiline marker in case we need to add additional bars -          prefix = hardline <+> dotPrefix leftLen withUnicode <> space+          prefix = space <> dotPrefix leftLen withUnicode <> space -          prefixWithBar color = prefix <> maybe id annotate color (if withUnicode then "│ " else "| ")+          prefixWithBar color = prefix <> maybe id annotate color (unicode "| " "│ " withUnicode)            showMultilineMarkerMessage (_, Blank) _ = mempty           showMultilineMarkerMessage (_, marker) isLast =             annotate (markerColor isError marker) $               ( if isLast && isLastMultiline-                  then if withUnicode then "╰╸ " else "`- "-                  else if withUnicode then "├╸ " else "|- "+                  then unicode "`- " "╰╸ " withUnicode+                  else unicode "|- " "├╸ " withUnicode               )-                <> replaceLinesWith (if isLast then prefix <> "   " else prefixWithBar (Just $ markerColor isError marker) <> space) (pretty $ markerMessage marker)+                <> replaceLinesWith (if isLast then prefix <> "   " else prefixWithBar (Just $ markerColor isError marker) <> space) 0 (annotated $ markerMessage marker)            showMultilineMarkerMessages [] = []           showMultilineMarkerMessages [m] = [showMultilineMarkerMessage m True]           showMultilineMarkerMessages (m : ms) = showMultilineMarkerMessage m False : showMultilineMarkerMessages ms-       in prefixWithBar colorOfFirstMultilineMarker <> prefix <> fold (List.intersperse prefix $ showMultilineMarkerMessages multiline)+       in hardline <> prefixWithBar colorOfFirstMultilineMarker <> hardline <> prefix <> fold (List.intersperse (hardline <> prefix) $ showMultilineMarkerMessages multiline)  -- | getLine_ ::   FileMap ->   [(Position, Marker msg)] ->   Int ->-  Int ->+  TabSize ->   Bool ->-  (WidthTable, Doc Annotation)-getLine_ files markers line tabSize isError =+  (WidthTable, Doc (Annotation ann))+getLine_ files markers line (TabSize tabSize) isError =   case safeArrayIndex (line - 1) =<< (HashMap.!?) files . file . fst =<< List.safeHead markers of     Nothing ->       ( mkWidthTable "",@@ -548,12 +537,12 @@     mkWidthTable s = listArray (1, length s) (ifTab tabSize wcwidth <$> s)  -- |-showAllMarkersInLine :: Pretty msg => Bool -> Bool -> (Doc Annotation -> Doc Annotation) -> Bool -> Bool -> Int -> WidthTable -> [(Position, Marker msg)] -> Doc Annotation+showAllMarkersInLine :: Bool -> Bool -> (Doc (Annotation ann) -> Doc (Annotation ann)) -> WithUnicode -> Bool -> Int -> WidthTable -> [(Position, Marker (Doc ann))] -> Doc (Annotation ann) showAllMarkersInLine _ _ _ _ _ _ _ [] = mempty showAllMarkersInLine hasMultilines inSpanOfMultiline colorMultilinePrefix withUnicode isError leftLen widths ms =   let maxMarkerColumn = snd $ end $ fst $ List.last $ List.sortOn (snd . end . fst) ms       specialPrefix-        | inSpanOfMultiline = colorMultilinePrefix (if withUnicode then "│ " else "| ") <> space+        | inSpanOfMultiline = colorMultilinePrefix (unicode "| " "│ " withUnicode) <> space         | hasMultilines = colorMultilinePrefix "  " <> space         | otherwise = mempty    in -- get the maximum end column, so that we know when to stop looking for other markers on the same line@@ -566,7 +555,7 @@     showMarkers n lineLen       | n > lineLen = mempty -- reached the end of the line       | otherwise =-        let allMarkers = flip filter ms \(Position (_, bc) (_, ec) _, mark) -> mark /= Blank && n >= bc && n < ec+        let allMarkers = flip filter ms \(Position (_, bc) (_, ec) _, mark) -> not (isBlank mark) && n >= bc && n < ec          in -- only consider markers which span onto the current column             case allMarkers of               [] -> fold (replicate (widthAt n) space) <> showMarkers (n + 1) lineLen@@ -574,15 +563,15 @@                 annotate                   (markerColor isError marker)                   ( if snd begin == n-                      then (if withUnicode then "┬" else "^") <> fold (replicate (widthAt n - 1) if withUnicode then "─" else "-")-                      else fold (replicate (widthAt n) if withUnicode then "─" else "-")+                      then unicode "^" "┬" withUnicode <> fold (replicate (widthAt n - 1) (unicode "-" "─" withUnicode))+                      else fold (replicate (widthAt n) (unicode "-" "─" withUnicode))                   )                   <> showMarkers (n + 1) lineLen      showMessages specialPrefix ms lineLen = case List.safeUncons ms of       Nothing -> mempty -- no more messages to show       Just ((Position b@(_, bc) _ _, msg), pipes) ->-        let filteredPipes = filter (uncurry (&&) . bimap ((/= b) . begin) (/= Blank)) pipes+        let filteredPipes = filter (uncurry (&&) . bimap ((/= b) . begin) (not . isBlank)) pipes             -- record only the pipes corresponding to markers on different starting positions             nubbedPipes = List.nubBy ((==) `on` (begin . fst)) filteredPipes             -- and then remove all duplicates@@ -606,7 +595,7 @@               let (pipesBefore, pipesAfter) = List.partition ((< bc) . snd . begin . fst) nubbedPipes                   -- split the list so that all pipes before can have `|`s but pipes after won't -                  pipesBeforeRendered = pipesBefore <&> second \marker -> annotate (markerColor isError marker) (if withUnicode then "│" else "|")+                  pipesBeforeRendered = pipesBefore <&> second \marker -> annotate (markerColor isError marker) (unicode "|" "│" withUnicode)                   -- pre-render pipes which are before because they will be shown                    lastBeginPosition = snd . begin . fst <$> List.safeLast (List.sortOn (snd . begin . fst) pipesAfter)@@ -615,49 +604,56 @@                     Nothing -> 0                     Just col -> widthsBetween bc col -                  currentPipe =-                    if-                        | withUnicode && hasSuccessor -> "├"-                        | withUnicode -> "╰"-                        | hasSuccessor -> "|"-                        | otherwise -> "`"+                  currentPipe = unicode (bool "`" "|" hasSuccessor) (bool "╰" "├" hasSuccessor) withUnicode -                  lineChar = if withUnicode then '─' else '-'-                  pointChar = if withUnicode then "╸" else "-"+                  lineChar = unicode '-' '─' withUnicode+                  pointChar = unicode "-" "╸" withUnicode                    bc' = bc + lineLen + 2                   pipesBeforeMessageStart = List.filter ((< bc') . snd . begin . fst) pipesAfter                   -- consider pipes before, as well as pipes which came before the text rectangle bounds-                  pipesBeforeMessageRendered = (pipesBefore <> pipesBeforeMessageStart) <&> second \marker -> annotate (markerColor isError marker) (if withUnicode then "│" else "|")+                  pipesBeforeMessageRendered = (pipesBefore <> pipesBeforeMessageStart) <&> second \marker -> annotate (markerColor isError marker) (unicode "|" "│" withUnicode)                in -- also pre-render pipes which are before the message text bounds, because they will be shown if the message is on                   -- multiple lines                    lineStart pipesBeforeRendered                     <> annotate (markerColor isError msg) (currentPipe <> pretty (replicate lineLen lineChar) <> pointChar)-                    <+> annotate (markerColor isError msg) (replaceLinesWith (hardline <+> lineStart pipesBeforeMessageRendered <+> if List.null pipesBeforeMessageStart then "  " else " ") $ pretty $ markerMessage msg)+                    <+> annotate (markerColor isError msg) (replaceLinesWith (space <> lineStart pipesBeforeMessageRendered <+> if List.null pipesBeforeMessageStart then "  " else " ") 0 $ annotated $ markerMessage msg)          in hardline <+> prefix <> showMessages specialPrefix pipes lineLen  -- WARN: uses the internal of the library -- --       DO NOT use a wildcard here, in case the internal API exposes one more constructor---- |-replaceLinesWith :: Doc ann -> Doc ann -> Doc ann-replaceLinesWith repl Line = repl-replaceLinesWith _ Fail = Fail-replaceLinesWith _ Empty = Empty-replaceLinesWith _ (Char c) = Char c-replaceLinesWith repl (Text _ s) =-  let lines = Text.split (== '\n') s <&> \txt -> Text (Text.length txt) txt-   in mconcat (List.intersperse repl lines)-replaceLinesWith repl (FlatAlt f d) = FlatAlt (replaceLinesWith repl f) (replaceLinesWith repl d)-replaceLinesWith repl (Cat c d) = Cat (replaceLinesWith repl c) (replaceLinesWith repl d)-replaceLinesWith repl (Nest n d) = Nest n (replaceLinesWith repl d)-replaceLinesWith repl (Union c d) = Union (replaceLinesWith repl c) (replaceLinesWith repl d)-replaceLinesWith repl (Column f) = Column (replaceLinesWith repl . f)-replaceLinesWith repl (Nesting f) = Nesting (replaceLinesWith repl . f)-replaceLinesWith repl (Annotated ann doc) = Annotated ann (replaceLinesWith repl doc)-replaceLinesWith repl (WithPageWidth f) = WithPageWidth (replaceLinesWith repl . f)+replaceLinesWith :: Doc ann -> Int -> Doc ann -> Doc ann+replaceLinesWith repl = go+ where+  replWidth = sdsWidth . layoutCompact $ repl+  sdsWidth = \case+    SFail -> 0+    SEmpty -> 0+    SChar _ sds -> 1 + sdsWidth sds+    SText l _ sds -> l + sdsWidth sds+    SLine _ _ -> error "replaceLinesWith was given a prefix with a line break"+    SAnnPush _ sds -> sdsWidth sds+    SAnnPop sds -> sdsWidth sds+  replWithNesting n = hardline <> repl <> pretty (textSpaces n)+  go n = \case+    Line -> replWithNesting n+    Fail -> Fail+    Empty -> Empty+    Char c -> Char c+    Text l txt -> Text l txt+    FlatAlt f d -> FlatAlt (go n f) (go n d)+    Cat c d -> Cat (go n c) (go n d)+    Nest n' d -> go (n + n') d+    Union c d -> Union (go n c) (go n d)+    Column f -> Column (go n . f)+    -- In this case we add both our fake nesting level (from the 'Nest'+    -- constructors we've eliminated) and the nesting level from the line+    -- prefixes+    Nesting f -> Nesting (go n . f . (+ replWidth) . (+ n))+    Annotated ann doc -> Annotated ann (go n doc)+    WithPageWidth f -> WithPageWidth (go n . f)  -- | Extracts the color of a marker as a 'Doc' coloring function. markerColor ::@@ -667,7 +663,7 @@   -- | The marker to extract the color from.   Marker msg ->   -- | A function used to color a 'Doc'.-  Annotation+  Annotation ann markerColor isError (This _) = ThisColor isError markerColor _ (Where _) = WhereColor markerColor _ (Maybe _) = MaybeColor@@ -683,15 +679,15 @@ {-# INLINE markerMessage #-}  -- | Pretty prints all hints.-prettyAllHints :: Pretty msg => [Note msg] -> Int -> Bool -> Doc Annotation+prettyAllHints :: [Note (Doc ann)] -> Int -> WithUnicode -> Doc (Annotation ann) prettyAllHints [] _ _ = mempty prettyAllHints (h : hs) leftLen withUnicode =   {-         A hint is composed of:         (1)         : Hint: <hint message>   -}-  let prefix = hardline <+> pipePrefix leftLen withUnicode-   in prefix <+> annotate HintColor (notePrefix h <+> replaceLinesWith (prefix <+> "      ") (pretty $ noteMessage h))+  let prefix = space <> pipePrefix leftLen withUnicode+   in hardline <> prefix <+> annotate HintColor (notePrefix h <+> replaceLinesWith prefix 7 (annotated $ noteMessage h))         <> prettyAllHints hs leftLen withUnicode   where     notePrefix (Note _) = "Note:"@@ -704,3 +700,11 @@ safeArrayIndex i a   | Array.inRange (Array.bounds a) i = Just (a ! i)   | otherwise = Nothing++annotated :: Doc ann -> Doc (Annotation ann)+annotated = reAnnotate OtherStyle++unicode :: a -> a -> WithUnicode -> a+unicode f t = \case+  WithoutUnicode -> f+  WithUnicode -> t
src/Error/Diagnose/Style.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE DeriveGeneric #-} -- | -- Module      : Error.Diagnose.Style -- Description : Custom style definitions@@ -11,15 +13,13 @@     Style,     -- $defining_new_styles -    -- * Default style specification+    -- * Styles     defaultStyle,--    -- * Re-exports-    reAnnotate,+    unadornedStyle,   ) where -import Prettyprinter (Doc, reAnnotate)+import GHC.Generics import Prettyprinter.Render.Terminal (AnsiStyle, Color (..), bold, color, colorDull)  -- $defining_new_styles@@ -41,7 +41,7 @@ -- For simplicity's sake, a default style is given as 'defaultStyle'.  -- | Some annotations as placeholders for colors in a 'Doc'.-data Annotation+data Annotation a   = -- | The color of 'Error.Diagnose.Report.This' markers, depending on whether the report is an error     --   report or a warning report.     ThisColor@@ -67,18 +67,25 @@   | -- | Additional style to apply to marker rules (e.g. bold) on top of some     --   already processed color annotation.     MarkerStyle-      Annotation+      (Annotation a)   | -- | The color of the code when no marker is present.     CodeStyle+  | -- | Something else, could be provided by the user+    OtherStyle a+  deriving (Eq, Ord, Show, Generic, Functor, Foldable, Traversable)  -- | A style is a function which can be applied using 'reAnnotate'. -- --   It transforms a 'Doc'ument containing 'Annotation's into a 'Doc'ument containing --   color information.-type Style = Doc Annotation -> Doc AnsiStyle+type Style a = Annotation a -> AnsiStyle  ------------------------------------------- +-- | A style which disregards all annotations+unadornedStyle :: Style a+unadornedStyle = const mempty+ -- | The default style for diagnostics, where: -- --   * 'Error.Diagnose.Report.This' markers are colored in red for errors and yellow for warnings@@ -90,21 +97,20 @@ --   * File names are output in dull green --   * The @[error]@/@[warning]@ at the top is colored in red for errors and yellow for warnings --   * The code is output in normal white-defaultStyle :: Style-defaultStyle = reAnnotate style-  where-    style = \case-      ThisColor isError -> color if isError then Red else Yellow-      MaybeColor -> color Magenta-      WhereColor -> colorDull Blue-      HintColor -> color Cyan-      FileColor -> bold <> colorDull Green-      RuleColor -> bold <> color Black-      KindColor isError -> bold <> style (ThisColor isError)-      NoLineColor -> bold <> colorDull Magenta-      MarkerStyle st ->-        let ann = style st-         in if ann == style CodeStyle-              then ann-              else bold <> ann-      CodeStyle -> color White+defaultStyle :: Style AnsiStyle+defaultStyle = \case+    ThisColor isError -> color if isError then Red else Yellow+    MaybeColor -> color Magenta+    WhereColor -> colorDull Blue+    HintColor -> color Cyan+    FileColor -> bold <> colorDull Green+    RuleColor -> bold <> color Black+    KindColor isError -> bold <> defaultStyle (ThisColor isError)+    NoLineColor -> bold <> colorDull Magenta+    MarkerStyle st ->+      let ann = defaultStyle st+       in if ann == defaultStyle CodeStyle+            then ann+            else bold <> ann+    CodeStyle -> color White+    OtherStyle s -> s
test/megaparsec/Repro6.hs view
@@ -44,12 +44,12 @@                 content3    case res1 of-    Left diag -> printDiagnostic stdout True True 4 defaultStyle (addFile diag filename (Text.unpack content1) :: Diagnostic String)+    Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content1) :: Diagnostic String)     Right res -> print res   case res2 of-    Left diag -> printDiagnostic stdout True True 4 defaultStyle (addFile diag filename (Text.unpack content2) :: Diagnostic String)+    Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content2) :: Diagnostic String)     Right res -> print res   putStrLn "------------- res3 ----------------"   case res3 of-    Left diag -> printDiagnostic stdout True True 4 defaultStyle (addFile diag filename (Text.unpack content3) :: Diagnostic String)+    Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content3) :: Diagnostic String)     Right res -> print res
test/megaparsec/Spec.hs view
@@ -16,7 +16,6 @@ import Instances () import qualified Repro6 import qualified Text.Megaparsec as MP-import qualified Text.Megaparsec.Char as MP import qualified Text.Megaparsec.Char.Lexer as MP  main :: IO ()@@ -29,11 +28,11 @@       res2 = first (errorDiagnosticFromBundle Nothing "Parse error on input" Nothing) $ MP.runParser @Void (MP.some MP.decimal <* MP.eof) filename content2    case res1 of-    Left diag -> printDiagnostic stdout True True 4 defaultStyle (addFile diag filename (Text.unpack content1) :: Diagnostic String)-    Right res -> print res+    Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content1) :: Diagnostic String)+    Right res -> print @[Integer] res   case res2 of-    Left diag -> printDiagnostic stdout True True 4 defaultStyle (addFile diag filename (Text.unpack content2) :: Diagnostic String)-    Right res -> print res+    Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content2) :: Diagnostic String)+    Right res -> print @[Integer] res    putStrLn "---------------------------------------------------" 
test/parsec/Repro2.hs view
@@ -29,8 +29,8 @@  main :: IO () main = do-  either (printDiagnostic stderr True True 4 defaultStyle) print $ diagParse parser1 "issues/2.txt" "\\1"-  either (printDiagnostic stderr True True 4 defaultStyle) print $ diagParse parser2 "issues/2.txt" "\\1"+  either (printDiagnostic stderr WithUnicode (TabSize 4) defaultStyle) print $ diagParse parser1 "issues/2.txt" "\\1"+  either (printDiagnostic stderr WithUnicode (TabSize 4) defaultStyle) print $ diagParse parser2 "issues/2.txt" "\\1"  -- smaller example op' :: String -> Parser String
test/parsec/Spec.hs view
@@ -3,7 +3,6 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}  {-# OPTIONS -Wno-orphans #-} @@ -32,13 +31,13 @@       res3 = first (errorDiagnosticFromParseError Nothing "Parse error on input" Nothing) $ P.parse (test1 <* P.eof) filename content3    case res1 of-    Left diag -> printDiagnostic stdout True True 4 defaultStyle (addFile diag filename (Text.unpack content1) :: Diagnostic String)+    Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content1) :: Diagnostic String)     Right res -> print res   case res2 of-    Left diag -> printDiagnostic stdout True True 4 defaultStyle (addFile diag filename (Text.unpack content2) :: Diagnostic String)+    Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content2) :: Diagnostic String)     Right res -> print res   case res3 of-    Left diag -> printDiagnostic stdout True True 4 defaultStyle (addFile diag filename (Text.unpack content3) :: Diagnostic String)+    Left diag -> printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle (addFile diag filename (Text.unpack content3) :: Diagnostic String)     Right res -> print res    -- all issue reproduction
test/rendering/Spec.hs view
@@ -1,24 +1,34 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE ParallelListComp #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}  #ifdef USE_AESON import qualified Data.ByteString.Lazy as BS+import Error.Diagnose(diagnosticToJson) #endif import Data.HashMap.Lazy (HashMap) import qualified Data.HashMap.Lazy as HashMap import Error.Diagnose   ( Marker (..),-    Note (Hint),+    Note (..),     Position (..),     Report(..),     addFile,     addReport,-    def,     defaultStyle,     printDiagnostic,+    printDiagnostic',     stdout,+    WithUnicode (..),+    TabSize (..),   ) import System.IO (hPutStrLn)+import Prettyprinter (Doc, annotate, pretty, hsep, indent, vsep, nest, (<+>), align, list)+import Prettyprinter.Util (reflow)+import Prettyprinter.Render.Terminal (AnsiStyle, Color (..), color, bold, italicized, underlined)+import Data.Traversable (mapAccumL)+import Data.Functor.Compose (Compose(..))  main :: IO () main = do@@ -73,18 +83,118 @@           errorWithBlankAndNormalMarkerInLine,           beautifulExample         ]+      customAnnReports =+        [ colorfulReport,+          indentedReport,+          nestingReport+        ] -  let diag = HashMap.foldlWithKey' addFile (foldl addReport def reports) files+  let diag = HashMap.foldlWithKey' addFile (foldl addReport mempty reports) files+      customDiag = HashMap.foldlWithKey' addFile (foldl addReport mempty customAnnReports) files    hPutStrLn stdout "\n\nWith unicode: ─────────────────────────\n"-  printDiagnostic stdout True True 4 defaultStyle diag+  printDiagnostic stdout WithUnicode (TabSize 4) defaultStyle diag   hPutStrLn stdout "\n\nWithout unicode: ----------------------\n"-  printDiagnostic stdout False True 4 defaultStyle diag+  printDiagnostic stdout WithoutUnicode (TabSize 4) defaultStyle diag+  hPutStrLn stdout "\n\nWith custom annotations: ----------------------\n"+  printDiagnostic' stdout WithUnicode (TabSize 4) defaultStyle customDiag #ifdef USE_AESON   hPutStrLn stdout "\n\nAs JSON: ------------------------------\n"   BS.hPutStr stdout (diagnosticToJson diag) #endif   hPutStrLn stdout "\n"++colorfulReport :: Report (Doc AnsiStyle)+colorfulReport =+  fmap hsep+    . getCompose+    . snd+    . mapAccumL+      (\(c : cs) s -> (cs, annotate c (pretty s)))+      styles+    . Compose+    . fmap words+    $ realWorldExample+ where+  styles = [ color fg <> e+      | fg <- cycle [Black, Red, Green, Yellow, Blue, Magenta, Cyan, White]+      | e <- cycle [bold, italicized, underlined]+      ]++indentedReport :: Report (Doc AnsiStyle)+indentedReport =+  Err+    Nothing+    ("Indent..." <> indent 3 (vsep ["foo", "bar", "baz"]))+    [ (Position (1, 15) (1, 16) "test.zc", Maybe a)+    , (Position (1, 11) (1, 12) "test.zc", This b)+    ]+    [Note c]+ where+  a =+    vsep+      [ "A woman’s face with Nature’s own hand painted"+      , "Hast thou, the master-mistress of my passion;"+      , "A woman’s gentle heart, but not acquainted"+      , "With shifting change, as is false women’s fashion;"+      ]+  b =+    vsep+      [ "An eye more bright than theirs, less false in rolling,"+      , "Gilding the object whereupon it gazeth;"+      , "A man in hue, all “hues” in his controlling,"+      , "Which steals men’s eyes and women’s souls amazeth."+      ]+  c =+    vsep+      [ "And for a woman wert thou first created;"+      , "Till Nature, as she wrought thee, fell a-doting,"+      , "And by addition me of thee defeated,"+      , "By adding one thing to my purpose nothing."+      , indent 4 "But since she prick’d thee out for women’s pleasure,"+      , indent 4 "Mine be thy love and thy love’s use their treasure."+      ]++nestingReport :: Report (Doc AnsiStyle)+nestingReport =+  Err+    Nothing+    (nest 4 $ vsep ["Nest...", "foo", "bar", "baz"])+    [ (Position (1, 15) (1, 16) "test.zc", Maybe a)+    ]+    [Note b, Hint c]+ where+  a =+    nest 3 $+      vsep+        [ "'What day is it?' asked Pooh."+        , "'It's today,' squeaked Piglet."+        , "'My favourite day,' said Pooh."+        ]+  b =+    foldr1+      (\p q -> nest 2 (vsep [p, q]))+      [ "It's a very funny thought that, if Bears were Bees,"+      , "They'd build their nests at the bottom of trees."+      , "And that being so (if the Bees were Bears),"+      , "We shouldn't have to climb up all these stairs."+      ]+  c =+    "The elements:"+      <+> align+        ( list+            [ "antimony"+            , "arsenic"+            , "aluminum"+            , "selenium"+            , "hydrogen"+            , "oxygen"+            , "nitrogen"+            , "rhenium"+            , align $ reflow "And there may be many others, but they haven't been discovered"+            ]+        )+  errorNoMarkersNoHints :: Report String errorNoMarkersNoHints =