packages feed

rio-prettyprint 0.1.4.0 → 0.1.5.0

raw patch · 9 files changed

+1301/−1204 lines, 9 filesdep ~pathnew-uploader

Dependency ranges changed: path

Files

LICENSE view
@@ -1,24 +1,24 @@-Copyright (c) 2015-2019, Stack contributors-All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are met:-    * Redistributions of source code must retain the above copyright-      notice, this list of conditions and the following disclaimer.-    * Redistributions in binary form must reproduce the above copyright-      notice, this list of conditions and the following disclaimer in the-      documentation and/or other materials provided with the distribution.-    * Neither the name of Stack nor the-      names of its contributors may be used to endorse or promote products-      derived from this software without specific prior written permission.--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE-DISCLAIMED. IN NO EVENT SHALL STACK CONTRIBUTORS BE LIABLE FOR ANY-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+Copyright (c) 2015-2023, Stack contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of Stack nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL STACK CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
rio-prettyprint.cabal view
@@ -1,50 +1,50 @@-cabal-version: 1.12---- This file has been generated from package.yaml by hpack version 0.35.0.------ see: https://github.com/sol/hpack--name:           rio-prettyprint-version:        0.1.4.0-synopsis:       Pretty-printing for RIO-description:    Combine RIO's log capabilities with pretty printing-category:       Development-homepage:       https://github.com/commercialhaskell/rio-prettyprint#readme-bug-reports:    https://github.com/commercialhaskell/rio-prettyprint/issues-author:         Michael Snoyman-maintainer:     michael@snoyman.com-copyright:      2018-2019 FP Complete-license:        BSD3-license-file:   LICENSE-build-type:     Simple--source-repository head-  type: git-  location: https://github.com/commercialhaskell/rio-prettyprint--library-  exposed-modules:-      RIO.PrettyPrint-      RIO.PrettyPrint.DefaultStyles-      RIO.PrettyPrint.PrettyException-      RIO.PrettyPrint.Simple-      RIO.PrettyPrint.StylesUpdate-      RIO.PrettyPrint.Types-      Text.PrettyPrint.Leijen.Extended-  other-modules:-      Paths_rio_prettyprint-  hs-source-dirs:-      src/-  build-depends:-      Cabal-    , aeson-    , annotated-wl-pprint-    , ansi-terminal >=0.9-    , array-    , base >=4.10 && <5-    , colour-    , mtl-    , path-    , rio-    , text-  default-language: Haskell2010+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.35.4.
+--
+-- see: https://github.com/sol/hpack
+
+name:           rio-prettyprint
+version:        0.1.5.0
+synopsis:       Pretty-printing for RIO
+description:    Combine RIO's log capabilities with pretty printing
+category:       Development
+homepage:       https://github.com/commercialhaskell/rio-prettyprint#readme
+bug-reports:    https://github.com/commercialhaskell/rio-prettyprint/issues
+author:         Michael Snoyman
+maintainer:     michael@snoyman.com
+copyright:      2018-2019 FP Complete
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+
+source-repository head
+  type: git
+  location: https://github.com/commercialhaskell/rio-prettyprint
+
+library
+  exposed-modules:
+      RIO.PrettyPrint
+      RIO.PrettyPrint.DefaultStyles
+      RIO.PrettyPrint.PrettyException
+      RIO.PrettyPrint.Simple
+      RIO.PrettyPrint.StylesUpdate
+      RIO.PrettyPrint.Types
+      Text.PrettyPrint.Leijen.Extended
+  other-modules:
+      Paths_rio_prettyprint
+  hs-source-dirs:
+      src/
+  build-depends:
+      Cabal
+    , aeson
+    , annotated-wl-pprint
+    , ansi-terminal >=0.9
+    , array
+    , base >=4.10 && <5
+    , colour
+    , mtl
+    , path >0.9.1
+    , rio
+    , text
+  default-language: Haskell2010
src/RIO/PrettyPrint.hs view
@@ -1,215 +1,271 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE OverloadedStrings #-}--module RIO.PrettyPrint-    (-      -- * Type classes for optionally colored terminal output-      HasTerm (..), HasStylesUpdate (..)-      -- * Pretty printing functions-    , displayPlain, displayWithColor-      -- * Logging based on pretty-print typeclass-    , prettyDebug, prettyInfo, prettyNote, prettyWarn, prettyError, prettyWarnNoIndent, prettyErrorNoIndent-    , prettyDebugL, prettyInfoL, prettyNoteL, prettyWarnL, prettyErrorL, prettyWarnNoIndentL, prettyErrorNoIndentL-    , prettyDebugS, prettyInfoS, prettyNoteS, prettyWarnS, prettyErrorS, prettyWarnNoIndentS, prettyErrorNoIndentS-      -- * Semantic styling functions-      -- | These are used rather than applying colors or other styling directly,-      -- to provide consistency.-    , style-    , displayMilliseconds-    , logLevelToStyle-      -- * Formatting utils-    , bulletedList-    , mkNarrativeList-    , spacedBulletedList-    , debugBracket-      -- * Re-exports from "Text.PrettyPrint.Leijen.Extended"-    , Pretty (..), StyleDoc (..), StyleAnn (..)-    , nest, line, linebreak, group, softline, softbreak-    , align, hang, indent, encloseSep-    , (<+>)-    , hsep, vsep, fillSep, sep, hcat, vcat, fillCat, cat, punctuate-    , fill, fillBreak-    , enclose, squotes, dquotes, parens, angles, braces, brackets-    , string-    , indentAfterLabel, wordDocs, flow-      -- * Re-exports from "RIO.PrettyPrint.Types.PrettyPrint"-    , Style (..)-    ) where--import Data.List (intersperse)-import RIO-import RIO.PrettyPrint.StylesUpdate (HasStylesUpdate (..))-import RIO.PrettyPrint.Types (Style (..))-import Text.PrettyPrint.Leijen.Extended (Pretty (pretty),-                     StyleAnn (..), StyleDoc, (<+>), align,-                     angles, braces, brackets, cat,-                     displayAnsi, displayPlain, dquotes, enclose, encloseSep,-                     fill, fillBreak, fillCat, fillSep, group, hang, hcat, hsep,-                     indent, line, linebreak,-                     nest, parens, punctuate, sep, softbreak, softline, squotes,-                     string, styleAnn, vcat, vsep)--class (HasLogFunc env, HasStylesUpdate env) => HasTerm env where-  useColorL :: Lens' env Bool-  termWidthL :: Lens' env Int--displayWithColor-    :: (HasTerm env, Pretty a, MonadReader env m, HasCallStack)-    => a -> m Utf8Builder-displayWithColor x = do-    useAnsi <- view useColorL-    termWidth <- view termWidthL-    (if useAnsi then displayAnsi else displayPlain) termWidth x---- TODO: switch to using implicit callstacks once 7.8 support is dropped--prettyWith :: (HasTerm env, HasCallStack, Pretty b,-               MonadReader env m, MonadIO m)-           => LogLevel -> (a -> b) -> a -> m ()-prettyWith level f = logGeneric "" level . RIO.display <=< displayWithColor . f---- Note: I think keeping this section aligned helps spot errors, might be--- worth keeping the alignment in place.--prettyDebugWith, prettyInfoWith, prettyNoteWith, prettyWarnWith, prettyErrorWith, prettyWarnNoIndentWith, prettyErrorNoIndentWith-  :: (HasCallStack, HasTerm env, MonadReader env m, MonadIO m)-  => (a -> StyleDoc) -> a -> m ()-prettyDebugWith = prettyWith LevelDebug-prettyInfoWith  = prettyWith LevelInfo-prettyNoteWith f  = prettyWith LevelInfo-                          ((line <>) . (style Good "Note:" <+>) .-                           indentAfterLabel . f)-prettyWarnWith f  = prettyWith LevelWarn-                          ((line <>) . (style Warning "Warning:" <+>) .-                           indentAfterLabel . f)-prettyErrorWith f = prettyWith LevelError-                          ((line <>) . (style Error   "Error:" <+>) .-                           indentAfterLabel . f)-prettyWarnNoIndentWith f  = prettyWith LevelWarn-                                  ((line <>) . (style Warning "Warning:" <+>) . f)-prettyErrorNoIndentWith f = prettyWith LevelError-                                  ((line <>) . (style Error   "Error:" <+>) . f)--prettyDebug, prettyInfo, prettyNote, prettyWarn, prettyError, prettyWarnNoIndent, prettyErrorNoIndent-  :: (HasCallStack, HasTerm env, MonadReader env m, MonadIO m)-  => StyleDoc -> m ()-prettyDebug         = prettyDebugWith         id-prettyInfo          = prettyInfoWith          id-prettyNote          = prettyNoteWith          id-prettyWarn          = prettyWarnWith          id-prettyError         = prettyErrorWith         id-prettyWarnNoIndent  = prettyWarnNoIndentWith  id-prettyErrorNoIndent = prettyErrorNoIndentWith id--prettyDebugL, prettyInfoL, prettyNoteL, prettyWarnL, prettyErrorL, prettyWarnNoIndentL, prettyErrorNoIndentL-  :: (HasCallStack, HasTerm env, MonadReader env m, MonadIO m)-  => [StyleDoc] -> m ()-prettyDebugL         = prettyDebugWith         fillSep-prettyInfoL          = prettyInfoWith          fillSep-prettyNoteL          = prettyNoteWith          fillSep-prettyWarnL          = prettyWarnWith          fillSep-prettyErrorL         = prettyErrorWith         fillSep-prettyWarnNoIndentL  = prettyWarnNoIndentWith  fillSep-prettyErrorNoIndentL = prettyErrorNoIndentWith fillSep--prettyDebugS, prettyInfoS, prettyNoteS, prettyWarnS, prettyErrorS, prettyWarnNoIndentS, prettyErrorNoIndentS-  :: (HasCallStack, HasTerm env, MonadReader env m, MonadIO m)-  => String -> m ()-prettyDebugS         = prettyDebugWith         flow-prettyInfoS          = prettyInfoWith          flow-prettyNoteS          = prettyNoteWith          flow-prettyWarnS          = prettyWarnWith          flow-prettyErrorS         = prettyErrorWith         flow-prettyWarnNoIndentS  = prettyWarnNoIndentWith  flow-prettyErrorNoIndentS = prettyErrorNoIndentWith flow---- End of aligned section---- | Use after a label and before the rest of what's being labelled for---   consistent spacing/indenting/etc.------   For example this is used after "Warning:" in warning messages.-indentAfterLabel :: StyleDoc -> StyleDoc-indentAfterLabel = align---- | Make a 'Doc' from each word in a 'String'-wordDocs :: String -> [StyleDoc]-wordDocs = map fromString . words---- | Wordwrap a 'String'-flow :: String -> StyleDoc-flow = fillSep . wordDocs--debugBracket :: (HasCallStack, HasTerm env, MonadReader env m,-                 MonadIO m, MonadUnliftIO m) => StyleDoc -> m a -> m a-debugBracket msg f = do-  let output = logDebug . RIO.display <=< displayWithColor-  output $ "Start: " <> msg-  start <- getMonotonicTime-  x <- f `catch` \ex -> do-      end <- getMonotonicTime-      let diff = end - start-      output $ "Finished with exception in" <+> displayMilliseconds diff <> ":" <+>-          msg <> line <>-          "Exception thrown: " <> fromString (show ex)-      throwIO (ex :: SomeException)-  end <- getMonotonicTime-  let diff = end - start-  output $ "Finished in" <+> displayMilliseconds diff <> ":" <+> msg-  return x---- |Annotate a 'StyleDoc' with a 'Style'.-style :: Style -> StyleDoc -> StyleDoc-style = styleAnn---- Display milliseconds.-displayMilliseconds :: Double -> StyleDoc-displayMilliseconds t = style Good $-    fromString (show (round (t * 1000) :: Int)) <> "ms"---- | Display a bulleted list of 'StyleDoc'.-bulletedList :: [StyleDoc] -> StyleDoc-bulletedList = mconcat . intersperse line . map (("*" <+>) . align)---- | A helper function to yield a narrative list from a list of items, with a--- final fullstop. For example, helps produce the output--- @\"apple, ball and cat.\"@ (no serial comma) or @\"apple, ball, and cat.\"@--- (serial comma) from @[\"apple\", \"ball\", \"cat\"]@.------ @since 0.1.4.0-mkNarrativeList :: Pretty a-                => Maybe Style-                -- ^ Style the items in the list?-                -> Bool-                -- ^ Use a serial comma?-                -> [a]-                -> [StyleDoc]-mkNarrativeList _ _ [] = []-mkNarrativeList mStyle _ [x] = [maybe id style mStyle (pretty x) <> "."]-mkNarrativeList mStyle useSerialComma [x1, x2] =-      mStyle' (pretty x1) <> (if useSerialComma then "," else mempty)-    : "and"-    : mkNarrativeList mStyle useSerialComma [x2]-  where-    mStyle' = maybe id style mStyle-mkNarrativeList mStyle useSerialComma (x:xs) =-      maybe id style mStyle (pretty x) <> ","-    : mkNarrativeList mStyle useSerialComma xs---- | Display a bulleted list of 'StyleDoc' with a blank line between--- each.-spacedBulletedList :: [StyleDoc] -> StyleDoc-spacedBulletedList = mconcat . intersperse (line <> line) . map (("*" <+>) . align)---- | The 'Style' intended to be associated with a 'LogLevel'.------ @since 0.1.1.0-logLevelToStyle :: LogLevel -> Style-logLevelToStyle level = case level of-  LevelDebug   -> Debug-  LevelInfo    -> Info-  LevelWarn    -> Warning-  LevelError   -> Error-  LevelOther _ -> OtherLevel+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE FlexibleContexts  #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module RIO.PrettyPrint
+  (
+    -- * Type classes for optionally colored terminal output
+    HasTerm (..)
+  , HasStylesUpdate (..)
+    -- * Pretty printing functions
+  , displayPlain
+  , displayWithColor
+    -- * Logging based on pretty-print typeclass
+  , prettyDebug
+  , prettyInfo
+  , prettyNote
+  , prettyWarn
+  , prettyError
+  , prettyWarnNoIndent
+  , prettyErrorNoIndent
+  , prettyDebugL
+  , prettyInfoL
+  , prettyNoteL
+  , prettyWarnL
+  , prettyErrorL
+  , prettyWarnNoIndentL
+  , prettyErrorNoIndentL
+  , prettyDebugS
+  , prettyInfoS
+  , prettyNoteS
+  , prettyWarnS
+  , prettyErrorS
+  , prettyWarnNoIndentS
+  , prettyErrorNoIndentS
+    -- * Semantic styling functions
+    -- | These are used rather than applying colors or other styling directly,
+    -- to provide consistency.
+  , style
+  , displayMilliseconds
+  , logLevelToStyle
+    -- * Formatting utils
+  , bulletedList
+  , mkNarrativeList
+  , spacedBulletedList
+  , debugBracket
+    -- * Re-exports from "Text.PrettyPrint.Leijen.Extended"
+  , Pretty (..)
+  , StyleDoc (..)
+  , StyleAnn (..)
+  , nest
+  , line
+  , linebreak
+  , group
+  , softline
+  , softbreak
+  , align
+  , hang
+  , indent
+  , encloseSep
+  , (<+>)
+  , hsep
+  , vsep
+  , fillSep
+  , sep
+  , hcat
+  , vcat
+  , fillCat
+  , cat
+  , punctuate
+  , fill
+  , fillBreak
+  , enclose
+  , squotes
+  , dquotes
+  , parens
+  , angles
+  , braces
+  , brackets
+  , string
+  , indentAfterLabel
+  , wordDocs
+  , flow
+    -- * Re-exports from "RIO.PrettyPrint.Types.PrettyPrint"
+  , Style (..)
+  ) where
+
+import           Data.List ( intersperse )
+import           RIO
+import           RIO.PrettyPrint.StylesUpdate ( HasStylesUpdate (..) )
+import           RIO.PrettyPrint.Types ( Style (..) )
+import           Text.PrettyPrint.Leijen.Extended
+                   ( Pretty (pretty), StyleAnn (..), StyleDoc, (<+>), align
+                   , angles, braces, brackets, cat, displayAnsi, displayPlain
+                   , dquotes, enclose, encloseSep, fill, fillBreak, fillCat
+                   , fillSep, group, hang, hcat, hsep, indent, line, linebreak
+                   , nest, parens, punctuate, sep, softbreak, softline, squotes
+                   , string, styleAnn, vcat, vsep
+                   )
+
+class (HasLogFunc env, HasStylesUpdate env) => HasTerm env where
+  useColorL :: Lens' env Bool
+  termWidthL :: Lens' env Int
+
+displayWithColor ::
+     (HasTerm env, Pretty a, MonadReader env m, HasCallStack)
+  => a
+  -> m Utf8Builder
+displayWithColor x = do
+  useAnsi <- view useColorL
+  termWidth <- view termWidthL
+  (if useAnsi then displayAnsi else displayPlain) termWidth x
+
+-- TODO: switch to using implicit callstacks once 7.8 support is dropped
+
+prettyWith ::
+     (HasTerm env, HasCallStack, Pretty b, MonadReader env m, MonadIO m)
+  => LogLevel
+  -> (a -> b)
+  -> a
+  -> m ()
+prettyWith level f = logGeneric "" level . RIO.display <=< displayWithColor . f
+
+-- Note: I think keeping this section aligned helps spot errors, might be
+-- worth keeping the alignment in place.
+
+prettyDebugWith, prettyInfoWith, prettyNoteWith, prettyWarnWith, prettyErrorWith, prettyWarnNoIndentWith, prettyErrorNoIndentWith
+  :: (HasCallStack, HasTerm env, MonadReader env m, MonadIO m)
+  => (a -> StyleDoc) -> a -> m ()
+prettyDebugWith = prettyWith LevelDebug
+prettyInfoWith  = prettyWith LevelInfo
+prettyNoteWith f  = prettyWith LevelInfo
+                          ((line <>) . (style Good "Note:" <+>) .
+                           indentAfterLabel . f)
+prettyWarnWith f  = prettyWith LevelWarn
+                          ((line <>) . (style Warning "Warning:" <+>) .
+                           indentAfterLabel . f)
+prettyErrorWith f = prettyWith LevelError
+                          ((line <>) . (style Error   "Error:" <+>) .
+                           indentAfterLabel . f)
+prettyWarnNoIndentWith f  = prettyWith LevelWarn
+                                  ((line <>) . (style Warning "Warning:" <+>) . f)
+prettyErrorNoIndentWith f = prettyWith LevelError
+                                  ((line <>) . (style Error   "Error:" <+>) . f)
+
+prettyDebug, prettyInfo, prettyNote, prettyWarn, prettyError, prettyWarnNoIndent, prettyErrorNoIndent
+  :: (HasCallStack, HasTerm env, MonadReader env m, MonadIO m)
+  => StyleDoc -> m ()
+prettyDebug         = prettyDebugWith         id
+prettyInfo          = prettyInfoWith          id
+prettyNote          = prettyNoteWith          id
+prettyWarn          = prettyWarnWith          id
+prettyError         = prettyErrorWith         id
+prettyWarnNoIndent  = prettyWarnNoIndentWith  id
+prettyErrorNoIndent = prettyErrorNoIndentWith id
+
+prettyDebugL, prettyInfoL, prettyNoteL, prettyWarnL, prettyErrorL, prettyWarnNoIndentL, prettyErrorNoIndentL
+  :: (HasCallStack, HasTerm env, MonadReader env m, MonadIO m)
+  => [StyleDoc] -> m ()
+prettyDebugL         = prettyDebugWith         fillSep
+prettyInfoL          = prettyInfoWith          fillSep
+prettyNoteL          = prettyNoteWith          fillSep
+prettyWarnL          = prettyWarnWith          fillSep
+prettyErrorL         = prettyErrorWith         fillSep
+prettyWarnNoIndentL  = prettyWarnNoIndentWith  fillSep
+prettyErrorNoIndentL = prettyErrorNoIndentWith fillSep
+
+prettyDebugS, prettyInfoS, prettyNoteS, prettyWarnS, prettyErrorS, prettyWarnNoIndentS, prettyErrorNoIndentS
+  :: (HasCallStack, HasTerm env, MonadReader env m, MonadIO m)
+  => String -> m ()
+prettyDebugS         = prettyDebugWith         flow
+prettyInfoS          = prettyInfoWith          flow
+prettyNoteS          = prettyNoteWith          flow
+prettyWarnS          = prettyWarnWith          flow
+prettyErrorS         = prettyErrorWith         flow
+prettyWarnNoIndentS  = prettyWarnNoIndentWith  flow
+prettyErrorNoIndentS = prettyErrorNoIndentWith flow
+
+-- End of aligned section
+
+-- | Use after a label and before the rest of what's being labelled for
+--   consistent spacing/indenting/etc.
+--
+--   For example this is used after "Warning:" in warning messages.
+indentAfterLabel :: StyleDoc -> StyleDoc
+indentAfterLabel = align
+
+-- | Make a 'Doc' from each word in a 'String'
+wordDocs :: String -> [StyleDoc]
+wordDocs = map fromString . words
+
+-- | Wordwrap a 'String'
+flow :: String -> StyleDoc
+flow = fillSep . wordDocs
+
+debugBracket :: (HasCallStack, HasTerm env, MonadReader env m,
+                 MonadIO m, MonadUnliftIO m) => StyleDoc -> m a -> m a
+debugBracket msg f = do
+  let output = logDebug . RIO.display <=< displayWithColor
+  output $ "Start: " <> msg
+  start <- getMonotonicTime
+  x <- f `catch` \ex -> do
+    end <- getMonotonicTime
+    let diff = end - start
+    output $
+         "Finished with exception in"
+      <+> displayMilliseconds diff <> ":"
+      <+> msg
+      <> line
+      <> "Exception thrown: "
+      <> fromString (show ex)
+    throwIO (ex :: SomeException)
+  end <- getMonotonicTime
+  let diff = end - start
+  output $ "Finished in" <+> displayMilliseconds diff <> ":" <+> msg
+  return x
+
+-- |Annotate a 'StyleDoc' with a 'Style'.
+style :: Style -> StyleDoc -> StyleDoc
+style = styleAnn
+
+-- Display milliseconds.
+displayMilliseconds :: Double -> StyleDoc
+displayMilliseconds t = style Good $
+  fromString (show (round (t * 1000) :: Int)) <> "ms"
+
+-- | Display a bulleted list of 'StyleDoc'.
+bulletedList :: [StyleDoc] -> StyleDoc
+bulletedList = mconcat . intersperse line . map (("*" <+>) . align)
+
+-- | A helper function to yield a narrative list from a list of items, with a
+-- final fullstop. For example, helps produce the output
+-- @\"apple, ball and cat.\"@ (no serial comma) or @\"apple, ball, and cat.\"@
+-- (serial comma) from @[\"apple\", \"ball\", \"cat\"]@.
+--
+-- @since 0.1.4.0
+mkNarrativeList ::
+     Pretty a
+  => Maybe Style
+  -- ^ Style the items in the list?
+  -> Bool
+  -- ^ Use a serial comma?
+  -> [a]
+  -> [StyleDoc]
+mkNarrativeList _ _ [] = []
+mkNarrativeList mStyle _ [x] = [maybe id style mStyle (pretty x) <> "."]
+mkNarrativeList mStyle useSerialComma [x1, x2] =
+    mStyle' (pretty x1) <> (if useSerialComma then "," else mempty)
+  : "and"
+  : mkNarrativeList mStyle useSerialComma [x2]
+ where
+  mStyle' = maybe id style mStyle
+mkNarrativeList mStyle useSerialComma (x:xs) =
+    maybe id style mStyle (pretty x) <> ","
+  : mkNarrativeList mStyle useSerialComma xs
+
+-- | Display a bulleted list of 'StyleDoc' with a blank line between
+-- each.
+spacedBulletedList :: [StyleDoc] -> StyleDoc
+spacedBulletedList = mconcat . intersperse (line <> line) . map (("*" <+>) . align)
+
+-- | The 'Style' intended to be associated with a 'LogLevel'.
+--
+-- @since 0.1.1.0
+logLevelToStyle :: LogLevel -> Style
+logLevelToStyle level = case level of
+  LevelDebug   -> Debug
+  LevelInfo    -> Info
+  LevelWarn    -> Warning
+  LevelError   -> Error
+  LevelOther _ -> OtherLevel
src/RIO/PrettyPrint/DefaultStyles.hs view
@@ -1,39 +1,40 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}--module RIO.PrettyPrint.DefaultStyles-  (-    defaultStyles-  ) where--import Data.Array.IArray (array)-import RIO-import RIO.PrettyPrint.Types (Style (..), Styles)-import System.Console.ANSI.Codes (Color (..), ColorIntensity (..),-  ConsoleIntensity (..), ConsoleLayer (..), SGR (..))---- | Default styles for rio-prettyprint output.-defaultStyles :: Styles-defaultStyles = array (minBound, maxBound)-  [ (Error, ("error", [SetColor Foreground Vivid Red]))-  , (Warning, ("warning", [SetColor Foreground Dull Yellow]))-  , (Info, ("info", [SetColor Foreground Dull Blue]))-  , (Debug, ("debug", [SetColor Foreground Dull Green]))-  , (OtherLevel, ("other-level", [SetColor Foreground Dull Magenta]))-  , (Good, ("good", [SetColor Foreground Vivid Green]))-  , (Shell, ("shell", [SetColor Foreground Vivid Magenta]))-  , (File, ("file", [SetColor Foreground Dull Cyan]))-  -- For now 'Url' using the same style as 'File'-  , (Url, ("url", [SetColor Foreground Dull Cyan]))-  , (Dir, ("dir", [ SetConsoleIntensity BoldIntensity-                  , SetColor Foreground Vivid Blue ]))-  , (Recommendation, ("recommendation", [ SetConsoleIntensity BoldIntensity-                                      , SetColor Foreground Vivid Green]))-  , (Current, ("current", [SetColor Foreground Dull Yellow]))-  , (Target, ("target", [SetColor Foreground Vivid Cyan]))-  -- TODO: what color should Module be?-  , (Module, ("module", [SetColor Foreground Vivid Magenta]))-  , (PkgComponent, ("package-component", [SetColor Foreground Vivid Cyan]))-  , (Secondary, ("secondary", [SetColor Foreground Vivid Black]))-  , (Highlight, ("highlight", [SetColor Foreground Vivid Green]))-  ]+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module RIO.PrettyPrint.DefaultStyles
+  ( defaultStyles
+  ) where
+
+import           Data.Array.IArray ( array )
+import           RIO
+import           RIO.PrettyPrint.Types ( Style (..), Styles )
+import           System.Console.ANSI.Codes
+                   ( Color (..), ColorIntensity (..), ConsoleIntensity (..)
+                   , ConsoleLayer (..), SGR (..)
+                   )
+
+-- | Default styles for rio-prettyprint output.
+defaultStyles :: Styles
+defaultStyles = array (minBound, maxBound)
+  [ (Error, ("error", [SetColor Foreground Vivid Red]))
+  , (Warning, ("warning", [SetColor Foreground Dull Yellow]))
+  , (Info, ("info", [SetColor Foreground Dull Blue]))
+  , (Debug, ("debug", [SetColor Foreground Dull Green]))
+  , (OtherLevel, ("other-level", [SetColor Foreground Dull Magenta]))
+  , (Good, ("good", [SetColor Foreground Vivid Green]))
+  , (Shell, ("shell", [SetColor Foreground Vivid Magenta]))
+  , (File, ("file", [SetColor Foreground Dull Cyan]))
+    -- For now 'Url' using the same style as 'File'
+  , (Url, ("url", [SetColor Foreground Dull Cyan]))
+  , (Dir, ("dir", [ SetConsoleIntensity BoldIntensity
+                  , SetColor Foreground Vivid Blue ]))
+  , (Recommendation, ("recommendation", [ SetConsoleIntensity BoldIntensity
+                                      , SetColor Foreground Vivid Green]))
+  , (Current, ("current", [SetColor Foreground Dull Yellow]))
+  , (Target, ("target", [SetColor Foreground Vivid Cyan]))
+    -- TODO: what color should Module be?
+  , (Module, ("module", [SetColor Foreground Vivid Magenta]))
+  , (PkgComponent, ("package-component", [SetColor Foreground Vivid Cyan]))
+  , (Secondary, ("secondary", [SetColor Foreground Vivid Black]))
+  , (Highlight, ("highlight", [SetColor Foreground Vivid Green]))
+  ]
src/RIO/PrettyPrint/PrettyException.hs view
@@ -1,77 +1,77 @@-{-# LANGUAGE NoImplicitPrelude         #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE StandaloneDeriving        #-}---- | This module provides a type representing pretty exceptions. It can be used--- as in the example below:------ > {-# LANGUAGE NoImplicitPrelude #-}--- > {-# LANGUAGE OverloadedStrings #-}--- >--- > module Main (main) where--- >--- > import RIO--- >          ( Exception, Handler (..), IO, RIO, Show, SomeException (..), Typeable--- >          , ($), catches, displayException, exitFailure, fromString, logError--- >          , mempty, throwIO--- >          )--- > import RIO.PrettyPrint--- >          ( Pretty (..), Style (..), (<+>), prettyError, prettyInfo, style )--- > import RIO.PrettyPrint.PrettyException ( PrettyException (..) )--- > import RIO.PrettyPrint.Simple ( SimplePrettyApp, runSimplePrettyApp )--- >--- > main :: IO ()--- > main = runSimplePrettyApp 80 mempty (action `catches` handleExceptions)--- >  where--- >   action :: RIO SimplePrettyApp ()--- >   action = do--- >       prettyInfo "Running action!"--- >       throwIO (PrettyException MyPrettyException)--- >--- >  handleExceptions :: [Handler (RIO SimplePrettyApp) ()]--- >  handleExceptions =--- >    [ Handler handlePrettyException--- >    , Handler handleSomeException--- >    ]--- >--- >  handlePrettyException :: PrettyException -> RIO SimplePrettyApp ()--- >  handlePrettyException e = do--- >    prettyError $ pretty e--- >    exitFailure--- >--- >  handleSomeException :: SomeException -> RIO SimplePrettyApp ()--- >  handleSomeException (SomeException e) = do--- >    logError $ fromString $ displayException e--- >    exitFailure--- >--- > data MyPrettyException--- >   = MyPrettyException--- >   deriving (Show, Typeable)--- >--- > instance Pretty MyPrettyException where--- >   pretty MyPrettyException =--- >     "My" <+> style Highlight "pretty" <+> "exception!"--- >--- > instance Exception MyPrettyException----module RIO.PrettyPrint.PrettyException-  ( PrettyException (..)-  ) where--import RIO (Exception (..), Show, Typeable)-import Text.PrettyPrint.Leijen.Extended (Pretty (..))---- | Type representing pretty exceptions.------ @since 0.1.4.0-data PrettyException-  = forall e. (Exception e, Pretty e) => PrettyException e-  deriving Typeable--deriving instance Show PrettyException--instance Pretty PrettyException where-  pretty (PrettyException e) = pretty e--instance Exception PrettyException where-  displayException (PrettyException e) = displayException e+{-# LANGUAGE NoImplicitPrelude         #-}
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE StandaloneDeriving        #-}
+
+-- | This module provides a type representing pretty exceptions. It can be used
+-- as in the example below:
+--
+-- > {-# LANGUAGE NoImplicitPrelude #-}
+-- > {-# LANGUAGE OverloadedStrings #-}
+-- >
+-- > module Main (main) where
+-- >
+-- > import RIO
+-- >          ( Exception, Handler (..), IO, RIO, Show, SomeException (..), Typeable
+-- >          , ($), catches, displayException, exitFailure, fromString, logError
+-- >          , mempty, throwIO
+-- >          )
+-- > import RIO.PrettyPrint
+-- >          ( Pretty (..), Style (..), (<+>), prettyError, prettyInfo, style )
+-- > import RIO.PrettyPrint.PrettyException ( PrettyException (..) )
+-- > import RIO.PrettyPrint.Simple ( SimplePrettyApp, runSimplePrettyApp )
+-- >
+-- > main :: IO ()
+-- > main = runSimplePrettyApp 80 mempty (action `catches` handleExceptions)
+-- >  where
+-- >   action :: RIO SimplePrettyApp ()
+-- >   action = do
+-- >       prettyInfo "Running action!"
+-- >       throwIO (PrettyException MyPrettyException)
+-- >
+-- >  handleExceptions :: [Handler (RIO SimplePrettyApp) ()]
+-- >  handleExceptions =
+-- >    [ Handler handlePrettyException
+-- >    , Handler handleSomeException
+-- >    ]
+-- >
+-- >  handlePrettyException :: PrettyException -> RIO SimplePrettyApp ()
+-- >  handlePrettyException e = do
+-- >    prettyError $ pretty e
+-- >    exitFailure
+-- >
+-- >  handleSomeException :: SomeException -> RIO SimplePrettyApp ()
+-- >  handleSomeException (SomeException e) = do
+-- >    logError $ fromString $ displayException e
+-- >    exitFailure
+-- >
+-- > data MyPrettyException
+-- >   = MyPrettyException
+-- >   deriving (Show, Typeable)
+-- >
+-- > instance Pretty MyPrettyException where
+-- >   pretty MyPrettyException =
+-- >     "My" <+> style Highlight "pretty" <+> "exception!"
+-- >
+-- > instance Exception MyPrettyException
+--
+module RIO.PrettyPrint.PrettyException
+  ( PrettyException (..)
+  ) where
+
+import RIO ( Exception (..), Show, Typeable )
+import Text.PrettyPrint.Leijen.Extended ( Pretty (..) )
+
+-- | Type representing pretty exceptions.
+--
+-- @since 0.1.4.0
+data PrettyException
+  = forall e. (Exception e, Pretty e) => PrettyException e
+  deriving Typeable
+
+deriving instance Show PrettyException
+
+instance Pretty PrettyException where
+  pretty (PrettyException e) = pretty e
+
+instance Exception PrettyException where
+  displayException (PrettyException e) = displayException e
src/RIO/PrettyPrint/Simple.hs view
@@ -1,98 +1,100 @@-{-# LANGUAGE NoImplicitPrelude #-}--{-|-This module exports a 'SimplePrettyApp' type, for providing a basic environment-including pretty printing functionality.--}-module RIO.PrettyPrint.Simple-  ( SimplePrettyApp-  , mkSimplePrettyApp-  , runSimplePrettyApp-  ) where--import System.Environment (lookupEnv)--import RIO-         ( Bool (..), HasLogFunc (..), Int, LogFunc, Maybe (..), MonadIO, RIO-         , ($), (<$>), isJust, lens, liftIO, logOptionsHandle, maybe, pure-         , runRIO, setLogUseColor, stderr, withLogFunc-         )-import RIO.Process-         ( HasProcessContext (..), ProcessContext, mkDefaultProcessContext )--import RIO.PrettyPrint (HasTerm (..))-import RIO.PrettyPrint.StylesUpdate (HasStylesUpdate (..), StylesUpdate (..))---- | A simple, non-customizable environment type, which provides--- pretty printing functionality.------ @since 0.1.3.0-data SimplePrettyApp = SimplePrettyApp-  { spaLogFunc :: !LogFunc-  , spaProcessContext :: !ProcessContext-  , spaUseColor :: !Bool-  , spaTermWidth :: !Int-  , spaStylesUpdate :: !StylesUpdate-  }--instance HasLogFunc SimplePrettyApp where-  logFuncL = lens spaLogFunc (\x y -> x { spaLogFunc = y })--instance HasProcessContext SimplePrettyApp where-  processContextL = lens spaProcessContext (\x y -> x { spaProcessContext = y })--instance HasStylesUpdate SimplePrettyApp where-  stylesUpdateL = lens spaStylesUpdate (\x y -> x { spaStylesUpdate = y })--instance HasTerm SimplePrettyApp where-  useColorL = lens spaUseColor (\x y -> x { spaUseColor = y })-  termWidthL = lens spaTermWidth (\x y -> x { spaTermWidth = y })---- | Constructor for 'SimplePrettyApp'. If 'ProcessContext' is not supplied--- 'mkDefaultProcessContext' will be used to create it.------ @since 0.1.3.0-mkSimplePrettyApp-  :: MonadIO m-  => LogFunc-  -> Maybe ProcessContext-  -> Bool-     -- ^ Use color?-  -> Int-     -- ^ Terminal width-  -> StylesUpdate-  -> m SimplePrettyApp-mkSimplePrettyApp logFunc mProcessContext useColor termWidth stylesUpdate = do-  processContext <- maybe mkDefaultProcessContext pure mProcessContext-  pure $ SimplePrettyApp-    { spaLogFunc = logFunc-    , spaProcessContext = processContext-    , spaUseColor = useColor-    , spaTermWidth = termWidth-    , spaStylesUpdate = stylesUpdate-    }---- | Run with a default configured @SimplePrettyApp@, consisting of:------ * Logging to 'stderr'------ * If the @RIO_VERBOSE@ environment variable is set, turns on verbose logging------ * Default process context------ * Logging using color------ @since 0.1.3.0-runSimplePrettyApp-  :: MonadIO m-  => Int-     -- ^ Terminal width-  -> StylesUpdate-  -> RIO SimplePrettyApp a-  -> m a-runSimplePrettyApp termWidth stylesUpdate m = liftIO $ do-  verbose <- isJust <$> lookupEnv "RIO_VERBOSE"-  lo <- setLogUseColor True <$> logOptionsHandle stderr verbose-  withLogFunc lo $ \lf -> do-    simplePrettyApp <- mkSimplePrettyApp lf Nothing True termWidth stylesUpdate-    runRIO simplePrettyApp m+{-# LANGUAGE NoImplicitPrelude #-}
+
+{-|
+This module exports a 'SimplePrettyApp' type, for providing a basic environment
+including pretty printing functionality.
+-}
+module RIO.PrettyPrint.Simple
+  ( SimplePrettyApp
+  , mkSimplePrettyApp
+  , runSimplePrettyApp
+  ) where
+
+import           RIO
+                   ( Bool (..), HasLogFunc (..), Int, LogFunc, Maybe (..)
+                   , MonadIO, RIO, ($), (<$>), isJust, lens, liftIO
+                   , logOptionsHandle, maybe, pure, runRIO, setLogUseColor
+                   , stderr, withLogFunc
+                   )
+import           RIO.PrettyPrint ( HasTerm (..) )
+import           RIO.PrettyPrint.StylesUpdate
+                   ( HasStylesUpdate (..), StylesUpdate (..) )
+import           RIO.Process
+                   ( HasProcessContext (..), ProcessContext
+                   , mkDefaultProcessContext
+                   )
+import           System.Environment ( lookupEnv )
+
+-- | A simple, non-customizable environment type, which provides
+-- pretty printing functionality.
+--
+-- @since 0.1.3.0
+data SimplePrettyApp = SimplePrettyApp
+  { spaLogFunc :: !LogFunc
+  , spaProcessContext :: !ProcessContext
+  , spaUseColor :: !Bool
+  , spaTermWidth :: !Int
+  , spaStylesUpdate :: !StylesUpdate
+  }
+
+instance HasLogFunc SimplePrettyApp where
+  logFuncL = lens spaLogFunc (\x y -> x { spaLogFunc = y })
+
+instance HasProcessContext SimplePrettyApp where
+  processContextL = lens spaProcessContext (\x y -> x { spaProcessContext = y })
+
+instance HasStylesUpdate SimplePrettyApp where
+  stylesUpdateL = lens spaStylesUpdate (\x y -> x { spaStylesUpdate = y })
+
+instance HasTerm SimplePrettyApp where
+  useColorL = lens spaUseColor (\x y -> x { spaUseColor = y })
+  termWidthL = lens spaTermWidth (\x y -> x { spaTermWidth = y })
+
+-- | Constructor for 'SimplePrettyApp'. If 'ProcessContext' is not supplied
+-- 'mkDefaultProcessContext' will be used to create it.
+--
+-- @since 0.1.3.0
+mkSimplePrettyApp ::
+     MonadIO m
+  => LogFunc
+  -> Maybe ProcessContext
+  -> Bool
+     -- ^ Use color?
+  -> Int
+     -- ^ Terminal width
+  -> StylesUpdate
+  -> m SimplePrettyApp
+mkSimplePrettyApp logFunc mProcessContext useColor termWidth stylesUpdate = do
+  processContext <- maybe mkDefaultProcessContext pure mProcessContext
+  pure $ SimplePrettyApp
+    { spaLogFunc = logFunc
+    , spaProcessContext = processContext
+    , spaUseColor = useColor
+    , spaTermWidth = termWidth
+    , spaStylesUpdate = stylesUpdate
+    }
+
+-- | Run with a default configured @SimplePrettyApp@, consisting of:
+--
+-- * Logging to 'stderr'
+--
+-- * If the @RIO_VERBOSE@ environment variable is set, turns on verbose logging
+--
+-- * Default process context
+--
+-- * Logging using color
+--
+-- @since 0.1.3.0
+runSimplePrettyApp ::
+     MonadIO m
+  => Int
+     -- ^ Terminal width
+  -> StylesUpdate
+  -> RIO SimplePrettyApp a
+  -> m a
+runSimplePrettyApp termWidth stylesUpdate m = liftIO $ do
+  verbose <- isJust <$> lookupEnv "RIO_VERBOSE"
+  lo <- setLogUseColor True <$> logOptionsHandle stderr verbose
+  withLogFunc lo $ \lf -> do
+    simplePrettyApp <- mkSimplePrettyApp lf Nothing True termWidth stylesUpdate
+    runRIO simplePrettyApp m
src/RIO/PrettyPrint/StylesUpdate.hs view
@@ -1,165 +1,166 @@-{-# LANGUAGE NoImplicitPrelude          #-}--module RIO.PrettyPrint.StylesUpdate-  (-    StylesUpdate (..)-  , parseStylesUpdateFromString-  , HasStylesUpdate (..)-  ) where--import Data.Aeson (FromJSON(..), withText)-import Data.Array.IArray (assocs)-import Data.Colour.SRGB (Colour, sRGB24)-import Data.Text as T (pack, unpack)-import RIO-import RIO.PrettyPrint.DefaultStyles (defaultStyles)-import RIO.PrettyPrint.Types (Style, StyleSpec)-import System.Console.ANSI.Types (BlinkSpeed (..), Color (..),-         ColorIntensity (..), ConsoleIntensity (..), ConsoleLayer (..),-         SGR (..), Underlining (..))---- |Updates to 'Styles'-newtype StylesUpdate = StylesUpdate { stylesUpdate :: [(Style, StyleSpec)] }-  deriving (Eq, Show)---- |The first styles update overrides the second one.-instance Semigroup StylesUpdate where-  -- See module "Data.IArray.Array" of package @array@: this depends on GHC's-  -- implementation of '(//)' being such that the last value specified for a-  -- duplicated index is used.-  StylesUpdate s1 <> StylesUpdate s2 = StylesUpdate (s2 <> s1)--instance Monoid StylesUpdate where-  mempty = StylesUpdate []-  mappend = (<>) -- This needs to be specified as, before package-                 -- @base-4.11.0.0@ (GHC 8.4.2, March 2018), the default is-                 -- 'mappend = (++)'.--instance FromJSON StylesUpdate where-  parseJSON = withText "StylesUpdate" $-    return . parseStylesUpdateFromString . T.unpack---- |Parse a string that is a colon-delimited sequence of key=value, where 'key'--- is a style name and 'value' is a semicolon-delimited list of 'ANSI' SGR--- (Select Graphic Rendition) control codes (in decimal). Keys that are not--- present in 'defaultStyles' are ignored. Items in the semicolon-delimited--- list that are not recognised as valid control codes are ignored.-parseStylesUpdateFromString :: String -> StylesUpdate-parseStylesUpdateFromString s = StylesUpdate $ mapMaybe process table- where-  table = do-    w <- split ':' s-    let (k, v') = break (== '=') w-    case v' of-      '=' : v -> return (T.pack k, parseCodes v)-      _ -> []--  process :: StyleSpec -> Maybe (Style, StyleSpec)-  process (k, sgrs) = do-    style <- lookup k styles-    return (style, (k, sgrs))--styles :: [(Text, Style)]-styles = map (\(s, (k, _)) -> (k, s)) $ assocs defaultStyles--parseCodes :: String -> [SGR]-parseCodes [] = []-parseCodes s = parseCodes' c- where-  s' = split ';' s-  c :: [Word8]-  c = mapMaybe readMaybe s'--parseCodes' :: [Word8] -> [SGR]-parseCodes' c = case codeToSGR c of-  (Nothing, []) -> []-  (Just sgr, []) -> [sgr]-  (Nothing, cs) -> parseCodes' cs-  (Just sgr, cs) -> sgr : parseCodes' cs--split :: Char -> String -> [String]-split c s = case rest of-                []     -> [chunk]-                _:rest1 -> chunk : split c rest1-  where-    (chunk, rest) = break (==c) s---- |This function is, essentially, the inverse of 'sgrToCode' exported by--- module "System.Console.ANSI.Codes" of the @ansi-terminal@ package. The--- \'ANSI\' standards refer to (1) standard ECMA-48 \`Control Functions for--- Coded Character Sets\' (5th edition, 1991); (2) extensions in ITU-T--- Recommendation (previously CCITT Recommendation) T.416 (03/93) \'Information--- Technology – Open Document Architecture (ODA) and Interchange Format:--- Character Content Architectures\` (also published as ISO/IEC International--- Standard 8613-6); and (3) further extensions used by \'XTerm\', a terminal--- emulator for the X Window System. The escape codes are described in a--- Wikipedia article at <http://en.wikipedia.org/wiki/ANSI_escape_code> and--- those codes supported on current versions of Windows at--- <https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences>.-codeToSGR :: [Word8] -> (Maybe SGR, [Word8])-codeToSGR [] = (Nothing, [])-codeToSGR (c:cs)-  | c ==  0 = (Just Reset, cs)-  | c ==  1 = (Just $ SetConsoleIntensity BoldIntensity, cs)-  | c ==  2 = (Just $ SetConsoleIntensity FaintIntensity, cs)-  | c ==  3 = (Just $ SetItalicized True, cs)-  | c ==  4 = (Just $ SetUnderlining SingleUnderline, cs)-  | c ==  5 = (Just $ SetBlinkSpeed SlowBlink, cs)-  | c ==  6 = (Just $ SetBlinkSpeed RapidBlink, cs)-  | c ==  7 = (Just $ SetSwapForegroundBackground True, cs)-  | c ==  8 = (Just $ SetVisible False, cs)-  | c == 21 = (Just $ SetUnderlining DoubleUnderline, cs)-  | c == 22 = (Just $ SetConsoleIntensity NormalIntensity, cs)-  | c == 23 = (Just $ SetItalicized False, cs)-  | c == 24 = (Just $ SetUnderlining NoUnderline, cs)-  | c == 25 = (Just $ SetBlinkSpeed NoBlink, cs)-  | c == 27 = (Just $ SetSwapForegroundBackground False, cs)-  | c == 28 = (Just $ SetVisible True, cs)-  | c >= 30 && c <= 37 =-    (Just $ SetColor Foreground Dull $ codeToColor (c - 30), cs)-  | c == 38 = case codeToRGB cs of-    (Nothing, cs') -> (Nothing, cs')-    (Just color, cs') -> (Just $ SetRGBColor Foreground color, cs')-  | c >= 40 && c <= 47 =-    (Just $ SetColor Background Dull $ codeToColor (c - 40), cs)-  | c == 48 = case codeToRGB cs of-    (Nothing, cs') -> (Nothing, cs')-    (Just color, cs') -> (Just $ SetRGBColor Background color, cs')-  | c >= 90 && c <= 97 =-    (Just $ SetColor Foreground Vivid $ codeToColor (c - 90), cs)-  | c >= 100 && c <= 107 =-    (Just $ SetColor Background Vivid $ codeToColor (c - 100), cs)-  | otherwise = (Nothing, cs)---- |This function is, essentially, the inverse of 'colorToCode' exported by--- module "System.Console.ANSI.Codes" of the @ansi-terminal@ package. The--- \'ANSI\' standards refer to eight named colours in a specific order. The code--- is a 0-based index of those colours.-codeToColor :: Word8 -> Color-codeToColor c-  -- 'toEnum' is not used because the @ansi-terminal@ package does not-  -- /guarantee/ the order of the data constructors of type 'Color' will be the-  -- same as that of the \'ANSI\' standards (although it currently is). (The-  -- 'colorToCode' function itself does not use 'fromEnum'.)-  | c == 0 = Black-  | c == 1 = Red-  | c == 2 = Green-  | c == 3 = Yellow-  | c == 4 = Blue-  | c == 5 = Magenta-  | c == 6 = Cyan-  | c == 7 = White-  | otherwise = error "Error: codeToColor, code outside 0 to 7."--codeToRGB :: [Word8] -> (Maybe (Colour Float), [Word8])-codeToRGB [] = (Nothing, [])-codeToRGB (2:r:g:b:cs) = (Just $ sRGB24 r g b, cs)-codeToRGB cs = (Nothing, cs)---- | Environment values with a styles update.------ @since 0.1.0.0-class HasStylesUpdate env where-  stylesUpdateL :: Lens' env StylesUpdate-instance HasStylesUpdate StylesUpdate where-  stylesUpdateL = id+{-# LANGUAGE NoImplicitPrelude          #-}
+
+module RIO.PrettyPrint.StylesUpdate
+  ( StylesUpdate (..)
+  , parseStylesUpdateFromString
+  , HasStylesUpdate (..)
+  ) where
+
+import           Data.Aeson ( FromJSON (..), withText )
+import           Data.Array.IArray ( assocs )
+import           Data.Colour.SRGB ( Colour, sRGB24 )
+import           Data.Text as T ( pack, unpack )
+import           RIO
+import           RIO.PrettyPrint.DefaultStyles ( defaultStyles )
+import           RIO.PrettyPrint.Types ( Style, StyleSpec )
+import           System.Console.ANSI.Types
+                   ( BlinkSpeed (..), Color (..), ColorIntensity (..)
+                   , ConsoleIntensity (..), ConsoleLayer (..), SGR (..)
+                   , Underlining (..)
+                   )
+
+-- | Updates to 'Styles'
+newtype StylesUpdate = StylesUpdate { stylesUpdate :: [(Style, StyleSpec)] }
+  deriving (Eq, Show)
+
+-- | The first styles update overrides the second one.
+instance Semigroup StylesUpdate where
+  -- See module "Data.IArray.Array" of package @array@: this depends on GHC's
+  -- implementation of '(//)' being such that the last value specified for a
+  -- duplicated index is used.
+  StylesUpdate s1 <> StylesUpdate s2 = StylesUpdate (s2 <> s1)
+
+instance Monoid StylesUpdate where
+  mempty = StylesUpdate []
+  mappend = (<>) -- This needs to be specified as, before package
+                 -- @base-4.11.0.0@ (GHC 8.4.2, March 2018), the default is
+                 -- 'mappend = (++)'.
+
+instance FromJSON StylesUpdate where
+  parseJSON = withText "StylesUpdate" $
+    return . parseStylesUpdateFromString . T.unpack
+
+-- |Parse a string that is a colon-delimited sequence of key=value, where 'key'
+-- is a style name and 'value' is a semicolon-delimited list of 'ANSI' SGR
+-- (Select Graphic Rendition) control codes (in decimal). Keys that are not
+-- present in 'defaultStyles' are ignored. Items in the semicolon-delimited
+-- list that are not recognised as valid control codes are ignored.
+parseStylesUpdateFromString :: String -> StylesUpdate
+parseStylesUpdateFromString s = StylesUpdate $ mapMaybe process table
+ where
+  table = do
+    w <- split ':' s
+    let (k, v') = break (== '=') w
+    case v' of
+      '=' : v -> return (T.pack k, parseCodes v)
+      _ -> []
+
+  process :: StyleSpec -> Maybe (Style, StyleSpec)
+  process (k, sgrs) = do
+    style <- lookup k styles
+    return (style, (k, sgrs))
+
+styles :: [(Text, Style)]
+styles = map (\(s, (k, _)) -> (k, s)) $ assocs defaultStyles
+
+parseCodes :: String -> [SGR]
+parseCodes [] = []
+parseCodes s = parseCodes' c
+ where
+  s' = split ';' s
+  c :: [Word8]
+  c = mapMaybe readMaybe s'
+
+parseCodes' :: [Word8] -> [SGR]
+parseCodes' c = case codeToSGR c of
+  (Nothing, []) -> []
+  (Just sgr, []) -> [sgr]
+  (Nothing, cs) -> parseCodes' cs
+  (Just sgr, cs) -> sgr : parseCodes' cs
+
+split :: Char -> String -> [String]
+split c s = case rest of
+  []     -> [chunk]
+  _:rest1 -> chunk : split c rest1
+ where
+  (chunk, rest) = break (==c) s
+
+-- |This function is, essentially, the inverse of 'sgrToCode' exported by
+-- module "System.Console.ANSI.Codes" of the @ansi-terminal@ package. The
+-- \'ANSI\' standards refer to (1) standard ECMA-48 \`Control Functions for
+-- Coded Character Sets\' (5th edition, 1991); (2) extensions in ITU-T
+-- Recommendation (previously CCITT Recommendation) T.416 (03/93) \'Information
+-- Technology – Open Document Architecture (ODA) and Interchange Format:
+-- Character Content Architectures\` (also published as ISO/IEC International
+-- Standard 8613-6); and (3) further extensions used by \'XTerm\', a terminal
+-- emulator for the X Window System. The escape codes are described in a
+-- Wikipedia article at <http://en.wikipedia.org/wiki/ANSI_escape_code> and
+-- those codes supported on current versions of Windows at
+-- <https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences>.
+codeToSGR :: [Word8] -> (Maybe SGR, [Word8])
+codeToSGR [] = (Nothing, [])
+codeToSGR (c:cs)
+  | c ==  0 = (Just Reset, cs)
+  | c ==  1 = (Just $ SetConsoleIntensity BoldIntensity, cs)
+  | c ==  2 = (Just $ SetConsoleIntensity FaintIntensity, cs)
+  | c ==  3 = (Just $ SetItalicized True, cs)
+  | c ==  4 = (Just $ SetUnderlining SingleUnderline, cs)
+  | c ==  5 = (Just $ SetBlinkSpeed SlowBlink, cs)
+  | c ==  6 = (Just $ SetBlinkSpeed RapidBlink, cs)
+  | c ==  7 = (Just $ SetSwapForegroundBackground True, cs)
+  | c ==  8 = (Just $ SetVisible False, cs)
+  | c == 21 = (Just $ SetUnderlining DoubleUnderline, cs)
+  | c == 22 = (Just $ SetConsoleIntensity NormalIntensity, cs)
+  | c == 23 = (Just $ SetItalicized False, cs)
+  | c == 24 = (Just $ SetUnderlining NoUnderline, cs)
+  | c == 25 = (Just $ SetBlinkSpeed NoBlink, cs)
+  | c == 27 = (Just $ SetSwapForegroundBackground False, cs)
+  | c == 28 = (Just $ SetVisible True, cs)
+  | c >= 30 && c <= 37 =
+    (Just $ SetColor Foreground Dull $ codeToColor (c - 30), cs)
+  | c == 38 = case codeToRGB cs of
+    (Nothing, cs') -> (Nothing, cs')
+    (Just color, cs') -> (Just $ SetRGBColor Foreground color, cs')
+  | c >= 40 && c <= 47 =
+    (Just $ SetColor Background Dull $ codeToColor (c - 40), cs)
+  | c == 48 = case codeToRGB cs of
+    (Nothing, cs') -> (Nothing, cs')
+    (Just color, cs') -> (Just $ SetRGBColor Background color, cs')
+  | c >= 90 && c <= 97 =
+    (Just $ SetColor Foreground Vivid $ codeToColor (c - 90), cs)
+  | c >= 100 && c <= 107 =
+    (Just $ SetColor Background Vivid $ codeToColor (c - 100), cs)
+  | otherwise = (Nothing, cs)
+
+-- |This function is, essentially, the inverse of 'colorToCode' exported by
+-- module "System.Console.ANSI.Codes" of the @ansi-terminal@ package. The
+-- \'ANSI\' standards refer to eight named colours in a specific order. The code
+-- is a 0-based index of those colours.
+codeToColor :: Word8 -> Color
+codeToColor c
+  -- 'toEnum' is not used because the @ansi-terminal@ package does not
+  -- /guarantee/ the order of the data constructors of type 'Color' will be the
+  -- same as that of the \'ANSI\' standards (although it currently is). (The
+  -- 'colorToCode' function itself does not use 'fromEnum'.)
+  | c == 0 = Black
+  | c == 1 = Red
+  | c == 2 = Green
+  | c == 3 = Yellow
+  | c == 4 = Blue
+  | c == 5 = Magenta
+  | c == 6 = Cyan
+  | c == 7 = White
+  | otherwise = error "Error: codeToColor, code outside 0 to 7."
+
+codeToRGB :: [Word8] -> (Maybe (Colour Float), [Word8])
+codeToRGB [] = (Nothing, [])
+codeToRGB (2:r:g:b:cs) = (Just $ sRGB24 r g b, cs)
+codeToRGB cs = (Nothing, cs)
+
+-- | Environment values with a styles update.
+--
+-- @since 0.1.0.0
+class HasStylesUpdate env where
+  stylesUpdateL :: Lens' env StylesUpdate
+instance HasStylesUpdate StylesUpdate where
+  stylesUpdateL = id
src/RIO/PrettyPrint/Types.hs view
@@ -1,70 +1,69 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-|-For the most part, the data constructors of 'Style' do not clash with other-names. When they do, import the module qualified. For example:--> import qualified RIO.PrettyPrint.Types.PrettyPrint as PP--}-module RIO.PrettyPrint.Types-  (-    Style (..)-  , Styles-  , StyleSpec-  ) where--import Data.Array.IArray (Array)-import Data.Ix (Ix)-import Data.Text (Text)-import RIO-import System.Console.ANSI.Types (SGR)---- |A style of rio-prettyprint's output.-data Style-  = Error     -- Should be used sparingly, not to style entire long messages.-              -- For example, it's used to style the "Error:" or "[error]" label-              -- for an error message, not the entire message.-  | Warning   -- Should be used sparingly, not to style entire long messages.-              -- For example, it's used to style the "Warning:" or "[warn]"-              -- label for a warning message, not the entire message.-  | Info      -- Should be used sparingly, not to style entire long messages.-              -- For example, it's used to style the "[info]" label for an info-              -- message, not the entire message.-  | Debug     -- Should be used sparingly, not to style entire long messages.-              -- For example, it's used to style the "[debug]" label for a debug-              -- message, not the entire message.-  | OtherLevel      -- Should be used sparingly, not to style entire long-                    -- messages. For example, it's used to style the "[...]"-                    -- label for an other log level message, not the entire-                    -- message.-  | Good      -- Style in a way to emphasize that it is a particularly good-              -- thing.-  | Shell     -- Style as a shell command, i.e. when suggesting something to the-              -- user that should be typed in directly as written.-  | File      -- Style as a filename. See 'Dir' for directories.-  | Url       -- Style as a URL.-  | Dir       -- Style as a directory name. See 'File' for files.-  | Recommendation  -- Style used to highlight part of a recommended course of-                    -- action.-  | Current   -- Style in a way that emphasizes that it is related to a current-              -- thing. For example, could be used when talking about the current-              -- package we're processing when outputting the name of it.-  | Target    -- TODO: figure out how to describe this-  | Module    -- Style as a module name.-  | PkgComponent    -- Style used to highlight the named component of a package.-  | Secondary -- Style for secondary content. For example, it's used to style-              -- timestamps.-  | Highlight -- Should be used sparingly, not to style entire long messages.-              -- For example, it's used to style the duration in a "Finished-              -- process in ... ms" message.-  deriving (Bounded, Enum, Eq, Ix, Ord, Show)---- |The first style overrides the second.-instance Semigroup Style where-  s <> _ = s---- |A style specification, pairing its \'key\' with the corresponding list of--- 'SGR' codes.-type StyleSpec = (Text, [SGR])---- |Style specifications indexed by the style.-type Styles = Array Style StyleSpec+{-# LANGUAGE NoImplicitPrelude #-}
+{-|
+For the most part, the data constructors of 'Style' do not clash with other
+names. When they do, import the module qualified. For example:
+
+> import qualified RIO.PrettyPrint.Types.PrettyPrint as PP
+-}
+module RIO.PrettyPrint.Types
+  ( Style (..)
+  , Styles
+  , StyleSpec
+  ) where
+
+import           Data.Array.IArray ( Array )
+import           Data.Ix ( Ix )
+import           Data.Text ( Text )
+import           RIO
+import           System.Console.ANSI.Types ( SGR )
+
+-- | A style of rio-prettyprint's output.
+data Style
+  = Error     -- Should be used sparingly, not to style entire long messages.
+              -- For example, it's used to style the "Error:" or "[error]" label
+              -- for an error message, not the entire message.
+  | Warning   -- Should be used sparingly, not to style entire long messages.
+              -- For example, it's used to style the "Warning:" or "[warn]"
+              -- label for a warning message, not the entire message.
+  | Info      -- Should be used sparingly, not to style entire long messages.
+              -- For example, it's used to style the "[info]" label for an info
+              -- message, not the entire message.
+  | Debug     -- Should be used sparingly, not to style entire long messages.
+              -- For example, it's used to style the "[debug]" label for a debug
+              -- message, not the entire message.
+  | OtherLevel      -- Should be used sparingly, not to style entire long
+                    -- messages. For example, it's used to style the "[...]"
+                    -- label for an other log level message, not the entire
+                    -- message.
+  | Good      -- Style in a way to emphasize that it is a particularly good
+              -- thing.
+  | Shell     -- Style as a shell command, i.e. when suggesting something to the
+              -- user that should be typed in directly as written.
+  | File      -- Style as a filename. See 'Dir' for directories.
+  | Url       -- Style as a URL.
+  | Dir       -- Style as a directory name. See 'File' for files.
+  | Recommendation  -- Style used to highlight part of a recommended course of
+                    -- action.
+  | Current   -- Style in a way that emphasizes that it is related to a current
+              -- thing. For example, could be used when talking about the current
+              -- package we're processing when outputting the name of it.
+  | Target    -- TODO: figure out how to describe this
+  | Module    -- Style as a module name.
+  | PkgComponent    -- Style used to highlight the named component of a package.
+  | Secondary -- Style for secondary content. For example, it's used to style
+              -- timestamps.
+  | Highlight -- Should be used sparingly, not to style entire long messages.
+              -- For example, it's used to style the duration in a "Finished
+              -- process in ... ms" message.
+  deriving (Bounded, Enum, Eq, Ix, Ord, Show)
+
+-- | The first style overrides the second.
+instance Semigroup Style where
+  s <> _ = s
+
+-- | A style specification, pairing its \'key\' with the corresponding list of
+-- 'SGR' codes.
+type StyleSpec = (Text, [SGR])
+
+-- | Style specifications indexed by the style.
+type Styles = Array Style StyleSpec
src/Text/PrettyPrint/Leijen/Extended.hs view
@@ -1,466 +1,504 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}--{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE UndecidableInstances #-}--- | This module re-exports some of the interface for--- "Text.PrettyPrint.Annotated.Leijen" along with additional definitions--- useful for stack.------ It defines a 'Monoid' instance for 'Doc'.-module Text.PrettyPrint.Leijen.Extended-  (-  -- * Pretty-print typeclass-  Pretty (..),--  -- * Ansi terminal Doc-  ---  -- See "System.Console.ANSI" for 'SGR' values to use beyond the colors-  -- provided.-  StyleDoc (..), StyleAnn(..),-  -- hDisplayAnsi,-  displayAnsi, displayPlain, renderDefault,--  -- * Selective re-exports from "Text.PrettyPrint.Annotated.Leijen"-  ---  -- Documentation of omissions up-to-date with @annotated-wl-pprint-0.7.0@--  -- ** Documents, parametrized by their annotations-  ---  -- Omitted compared to original: @putDoc, hPutDoc@-  -- Doc,--  -- ** Basic combinators-  ---  -- Omitted compared to original: @empty, char, text, (<>)@-  ---  -- Instead of @text@ and @char@, use 'fromString'.-  ---  -- Instead of @empty@, use 'mempty'.-  nest, line, linebreak, group, softline, softbreak,--  -- ** Alignment-  ---  -- The combinators in this section can not be described by Wadler's-  -- original combinators. They align their output relative to the-  -- current output position - in contrast to @nest@ which always-  -- aligns to the current nesting level. This deprives these-  -- combinators from being \`optimal\'. In practice however they-  -- prove to be very useful. The combinators in this section should-  -- be used with care, since they are more expensive than the other-  -- combinators. For example, @align@ shouldn't be used to pretty-  -- print all top-level declarations of a language, but using @hang@-  -- for let expressions is fine.-  ---  -- Omitted compared to original: @list, tupled, semiBraces@-  align, hang, indent, encloseSep,--  -- ** Operators-  ---  -- Omitted compared to original: @(<$>), (</>), (<$$>), (<//>)@-  (<+>),--  -- ** List combinators-  hsep, vsep, fillSep, sep, hcat, vcat, fillCat, cat, punctuate,--  -- ** Fillers-  fill, fillBreak,--  -- ** Bracketing combinators-  enclose, squotes, dquotes, parens, angles, braces, brackets,--  -- ** Character documents-  -- Entirely omitted:-  ---  -- @-  -- lparen, rparen, langle, rangle, lbrace, rbrace, lbracket, rbracket,-  -- squote, dquote, semi, colon, comma, space, dot, backslash, equals,-  -- pipe-  -- @--  -- ** Primitive type documents-  -- Omitted compared to the original:-  ---  -- @-  -- int, integer, float, double, rational, bool,-  -- @-  string,--  -- ** Semantic annotations-  annotate, noAnnotate, styleAnn--  -- ** Rendering-  -- Original entirely omitted:-  -- @-  -- SimpleDoc(..), renderPretty, renderCompact, displayDecorated, displayDecoratedA, display, displayS, displayIO,-  -- SpanList(..), displaySpans-  -- @--  -- ** Undocumented-  -- Entirely omitted:-  -- @-  -- column, nesting, width-  -- @-  ) where--import Control.Monad.Reader (runReader, local)-import Data.Array.IArray ((!), (//))-import qualified Data.Text as T-import Distribution.ModuleName (ModuleName)-import qualified Distribution.Text (display)-import Path-import RIO-import qualified RIO.Map as M-import RIO.PrettyPrint.DefaultStyles (defaultStyles)-import RIO.PrettyPrint.Types (Style (Dir, File), Styles)-import RIO.PrettyPrint.StylesUpdate (StylesUpdate (..), HasStylesUpdate, stylesUpdateL)-import System.Console.ANSI (ConsoleLayer (..), SGR (..), setSGRCode)-import qualified Text.PrettyPrint.Annotated.Leijen as P-import Text.PrettyPrint.Annotated.Leijen-  ( Doc, SimpleDoc (..)-  )---- TODO: consider smashing together the code for wl-annotated-pprint and--- wl-pprint-text. The code here already handles doing the--- ansi-wl-pprint stuff (better!) atop wl-annotated-pprint. So the--- result would be a package unifying 3 different wl inspired packages.------ Perhaps it can still have native string support, by adding a type--- parameter to Doc?--instance Semigroup StyleDoc where-    StyleDoc x <> StyleDoc y = StyleDoc (x P.<> y)-instance Monoid StyleDoc where-    mappend = (<>)-    mempty = StyleDoc P.empty------------------------------------------------------------------------------------- Pretty-Print class--class Pretty a where-    pretty :: a -> StyleDoc-    default pretty :: Show a => a -> StyleDoc-    pretty = StyleDoc . fromString . show--instance Pretty StyleDoc where-    pretty = id--instance Pretty (Path b File) where-    pretty = styleAnn File . StyleDoc . fromString . toFilePath--instance Pretty (Path b Dir) where-    pretty = styleAnn Dir . StyleDoc . fromString . toFilePath--instance Pretty ModuleName where-    pretty = StyleDoc . fromString . Distribution.Text.display------------------------------------------------------------------------------------- Style Doc---- |A style annotation.-newtype StyleAnn = StyleAnn (Maybe Style)-    deriving (Eq, Show, Semigroup)--instance Monoid StyleAnn where-    mempty = StyleAnn Nothing-    mappend = (<>)---- |A document annotated by a style-newtype StyleDoc = StyleDoc { unStyleDoc :: Doc StyleAnn }-  deriving (IsString, Show)---- |An ANSI code(s) annotation.-newtype AnsiAnn = AnsiAnn [SGR]-    deriving (Eq, Show, Semigroup, Monoid)---- |Convert a 'SimpleDoc' annotated with 'StyleAnn' to one annotated with--- 'AnsiAnn', by reference to a 'Styles'.-toAnsiDoc :: Styles -> SimpleDoc StyleAnn -> SimpleDoc AnsiAnn-toAnsiDoc styles = go-  where-    go SEmpty        = SEmpty-    go (SChar c d)   = SChar c (go d)-    go (SText l s d) = SText l s (go d)-    go (SLine i d)   = SLine i (go d)-    go (SAnnotStart (StyleAnn (Just s)) d) =-        SAnnotStart (AnsiAnn (snd $ styles ! s)) (go d)-    go (SAnnotStart (StyleAnn Nothing) d) = SAnnotStart (AnsiAnn []) (go d)-    go (SAnnotStop d) = SAnnotStop (go d)--displayPlain-    :: (Pretty a, HasLogFunc env, HasStylesUpdate env,-        MonadReader env m, HasCallStack)-    => Int -> a -> m Utf8Builder-displayPlain w =-    displayAnsiSimple . renderDefault w . fmap (const mempty) . unStyleDoc . pretty---- TODO: tweak these settings more?--- TODO: options for settings if this is released as a lib--renderDefault :: Int -> Doc a -> SimpleDoc a-renderDefault = P.renderPretty 1--displayAnsi-    :: (Pretty a, HasLogFunc env, HasStylesUpdate env,-        MonadReader env m, HasCallStack)-    => Int -> a -> m Utf8Builder-displayAnsi w =-    displayAnsiSimple . renderDefault w . unStyleDoc . pretty--{- Not used ----------------------------------------------------------------------hDisplayAnsi-    :: (Display a, HasAnsiAnn (Ann a), MonadIO m)-    => Handle -> Int -> a -> m ()-hDisplayAnsi h w x = liftIO $ do-    useAnsi <- hSupportsANSI h-    T.hPutStr h $ if useAnsi then displayAnsi w x else displayPlain w x---}--displayAnsiSimple-    :: (HasLogFunc env, HasStylesUpdate env, MonadReader env m, HasCallStack)-    => SimpleDoc StyleAnn -> m Utf8Builder-displayAnsiSimple doc = do-    update <- view stylesUpdateL-    let styles = defaultStyles // stylesUpdate update-        doc' = toAnsiDoc styles doc-    return $-        flip runReader mempty $ displayDecoratedWrap go doc'-  where-    go (AnsiAnn sgrs) inner = do-        old <- ask-        let sgrs' = mapMaybe (\sgr -> if sgr == Reset-                                        then Nothing-                                        else Just (getSGRTag sgr, sgr)) sgrs-            new = if Reset `elem` sgrs-                      then M.fromList sgrs'-                      else foldl' (\mp (tag, sgr) -> M.insert tag sgr mp) old sgrs'-        (extra, contents) <- local (const new) inner-        return (extra, transitionCodes old new <> contents <> transitionCodes new old)-    transitionCodes old new =-        case (null removals, null additions) of-            (True, True) -> mempty-            (True, False) -> fromString (setSGRCode additions)-            (False, _) -> fromString (setSGRCode (Reset : M.elems new))-      where-        (removals, additions) = partitionEithers $ M.elems $-            M.mergeWithKey-               (\_ o n -> if o == n then Nothing else Just (Right n))-               (fmap Left)-               (fmap Right)-               old-               new--displayDecoratedWrap-    :: forall a m. Monad m-    => (forall b. a -> m (b, Utf8Builder) -> m (b, Utf8Builder))-    -> SimpleDoc a-    -> m Utf8Builder-displayDecoratedWrap f doc = do-    (mafter, result) <- go doc-    case mafter of-      Just _ -> error "Invariant violated by input to displayDecoratedWrap: no matching SAnnotStart for SAnnotStop."-      Nothing -> return result-  where-    spaces n = display (T.replicate n " ")--    go :: SimpleDoc a -> m (Maybe (SimpleDoc a), Utf8Builder)-    go SEmpty = return (Nothing, mempty)-    go (SChar c x) = fmap (fmap (display c <>)) (go x)-    -- NOTE: Could actually use the length to guess at an initial-    -- allocation.  Better yet would be to just use Text in pprint..-    go (SText _l s x) = fmap (fmap (fromString s <>)) (go x)-    go (SLine n x) = fmap (fmap ((display '\n' <>) . (spaces n <>))) (go x)-    go (SAnnotStart ann x) = do-        (mafter, contents) <- f ann (go x)-        case mafter of-            Just after -> fmap (fmap (contents <>)) (go after)-            Nothing -> error "Invariant violated by input to displayDecoratedWrap: no matching SAnnotStop for SAnnotStart."-    go (SAnnotStop x) = return (Just x, mempty)--{- Not used ------------------------------------------------------------------------ Foreground color combinators--black, red, green, yellow, blue, magenta, cyan, white,-    dullblack, dullred, dullgreen, dullyellow, dullblue, dullmagenta, dullcyan, dullwhite,-    onblack, onred, ongreen, onyellow, onblue, onmagenta, oncyan, onwhite,-    ondullblack, ondullred, ondullgreen, ondullyellow, ondullblue, ondullmagenta, ondullcyan, ondullwhite-    :: Doc AnsiAnn -> Doc AnsiAnn-(black, dullblack, onblack, ondullblack) = colorFunctions Black-(red, dullred, onred, ondullred) = colorFunctions Red-(green, dullgreen, ongreen, ondullgreen) = colorFunctions Green-(yellow, dullyellow, onyellow, ondullyellow) = colorFunctions Yellow-(blue, dullblue, onblue, ondullblue) = colorFunctions Blue-(magenta, dullmagenta, onmagenta, ondullmagenta) = colorFunctions Magenta-(cyan, dullcyan, oncyan, ondullcyan) = colorFunctions Cyan-(white, dullwhite, onwhite, ondullwhite) = colorFunctions White--type EndoAnsiDoc = Doc AnsiAnn -> Doc AnsiAnn--colorFunctions :: Color -> (EndoAnsiDoc, EndoAnsiDoc, EndoAnsiDoc, EndoAnsiDoc)-colorFunctions color =-    ( ansiAnn [SetColor Foreground Vivid color]-    , ansiAnn [SetColor Foreground Dull color]-    , ansiAnn [SetColor Background Vivid color]-    , ansiAnn [SetColor Background Dull color]-    )---}--styleAnn :: Style -> StyleDoc -> StyleDoc-styleAnn s = StyleDoc . P.annotate (StyleAnn (Just s)) . unStyleDoc--{- Not used ------------------------------------------------------------------------ Intensity combinators--bold, faint, normal :: Doc AnsiAnn -> Doc AnsiAnn-bold = ansiAnn [SetConsoleIntensity BoldIntensity]-faint = ansiAnn [SetConsoleIntensity FaintIntensity]-normal = ansiAnn [SetConsoleIntensity NormalIntensity]---}---- | Tags for each field of state in SGR (Select Graphics Rendition).------ It's a bit of a hack that 'TagReset' is included.-data SGRTag-    = TagReset-    | TagConsoleIntensity-    | TagItalicized-    | TagUnderlining-    | TagBlinkSpeed-    | TagVisible-    | TagSwapForegroundBackground-    | TagColorForeground-    | TagColorBackground-    | TagRGBColor-    | TagPaletteColor-    deriving (Eq, Ord)--getSGRTag :: SGR -> SGRTag-getSGRTag Reset{}                       = TagReset-getSGRTag SetConsoleIntensity{}         = TagConsoleIntensity-getSGRTag SetItalicized{}               = TagItalicized-getSGRTag SetUnderlining{}              = TagUnderlining-getSGRTag SetBlinkSpeed{}               = TagBlinkSpeed-getSGRTag SetVisible{}                  = TagVisible-getSGRTag SetSwapForegroundBackground{} = TagSwapForegroundBackground-getSGRTag (SetColor Foreground _ _)     = TagColorForeground-getSGRTag (SetColor Background _ _)     = TagColorBackground-getSGRTag SetRGBColor{}                 = TagRGBColor-getSGRTag SetPaletteColor{}             = TagPaletteColor--(<+>) :: StyleDoc -> StyleDoc -> StyleDoc-StyleDoc x <+> StyleDoc y = StyleDoc (x P.<+> y)--align :: StyleDoc -> StyleDoc-align = StyleDoc . P.align . unStyleDoc--noAnnotate :: StyleDoc -> StyleDoc-noAnnotate = StyleDoc . P.noAnnotate . unStyleDoc--braces :: StyleDoc -> StyleDoc-braces = StyleDoc . P.braces . unStyleDoc--angles :: StyleDoc -> StyleDoc-angles = StyleDoc . P.angles . unStyleDoc--parens :: StyleDoc -> StyleDoc-parens = StyleDoc . P.parens . unStyleDoc--dquotes :: StyleDoc -> StyleDoc-dquotes = StyleDoc . P.dquotes . unStyleDoc--squotes :: StyleDoc -> StyleDoc-squotes = StyleDoc . P.squotes . unStyleDoc--brackets :: StyleDoc -> StyleDoc-brackets = StyleDoc . P.brackets . unStyleDoc---- | The document @string s@ concatenates all characters in @s@ using @line@ for--- newline characters and @char@ for all other characters. It is used whenever--- the text contains newline characters.------ @since 0.1.4.0-string :: String -> StyleDoc-string "" = mempty-string ('\n':s) = line <> string s-string s        = let (xs, ys) = span (/='\n') s-                  in  fromString xs <> string ys--annotate :: StyleAnn -> StyleDoc -> StyleDoc-annotate a = StyleDoc . P.annotate a . unStyleDoc--nest :: Int -> StyleDoc -> StyleDoc-nest a = StyleDoc . P.nest a . unStyleDoc--line :: StyleDoc-line = StyleDoc P.line--linebreak :: StyleDoc-linebreak = StyleDoc P.linebreak--fill :: Int -> StyleDoc -> StyleDoc-fill a = StyleDoc . P.fill a . unStyleDoc--fillBreak :: Int -> StyleDoc -> StyleDoc-fillBreak a = StyleDoc . P.fillBreak a . unStyleDoc--enclose :: StyleDoc -> StyleDoc -> StyleDoc -> StyleDoc-enclose l r x = l <> x <> r--cat :: [StyleDoc] -> StyleDoc-cat = StyleDoc . P.cat . map unStyleDoc--punctuate :: StyleDoc -> [StyleDoc] -> [StyleDoc]-punctuate (StyleDoc x) = map StyleDoc . P.punctuate x . map unStyleDoc--fillCat :: [StyleDoc] -> StyleDoc-fillCat = StyleDoc . P.fillCat . map unStyleDoc--hcat :: [StyleDoc] -> StyleDoc-hcat = StyleDoc . P.hcat . map unStyleDoc--vcat :: [StyleDoc] -> StyleDoc-vcat = StyleDoc . P.vcat . map unStyleDoc--sep :: [StyleDoc] -> StyleDoc-sep = StyleDoc . P.sep . map unStyleDoc--vsep :: [StyleDoc] -> StyleDoc-vsep = StyleDoc . P.vsep . map unStyleDoc--hsep :: [StyleDoc] -> StyleDoc-hsep = StyleDoc . P.hsep . map unStyleDoc--fillSep :: [StyleDoc] -> StyleDoc-fillSep = StyleDoc . P.fillSep . map unStyleDoc--encloseSep :: StyleDoc -> StyleDoc -> StyleDoc -> [StyleDoc] -> StyleDoc-encloseSep (StyleDoc x) (StyleDoc y) (StyleDoc z) =-  StyleDoc . P.encloseSep x y z . map unStyleDoc--indent :: Int -> StyleDoc -> StyleDoc-indent a = StyleDoc . P.indent a . unStyleDoc--hang :: Int -> StyleDoc -> StyleDoc-hang a = StyleDoc . P.hang a . unStyleDoc--softbreak :: StyleDoc-softbreak = StyleDoc P.softbreak--softline :: StyleDoc-softline = StyleDoc P.softline--group :: StyleDoc -> StyleDoc-group = StyleDoc . P.group . unStyleDoc+{-# LANGUAGE NoImplicitPrelude          #-}
+{-# LANGUAGE DefaultSignatures          #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE OverloadedStrings          #-}
+{-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE UndecidableInstances       #-}
+
+-- | This module re-exports some of the interface for
+-- "Text.PrettyPrint.Annotated.Leijen" along with additional definitions
+-- useful for stack.
+--
+-- It defines a 'Monoid' instance for 'Doc'.
+module Text.PrettyPrint.Leijen.Extended
+  (
+    -- * Pretty-print typeclass
+    Pretty (..)
+
+    -- * Ansi terminal Doc
+    --
+    -- See "System.Console.ANSI" for 'SGR' values to use beyond the colors
+    -- provided.
+  , StyleDoc (..)
+  , StyleAnn(..)
+  -- hDisplayAnsi,
+  , displayAnsi
+  , displayPlain
+  , renderDefault
+
+  -- * Selective re-exports from "Text.PrettyPrint.Annotated.Leijen"
+  --
+  -- Documentation of omissions up-to-date with @annotated-wl-pprint-0.7.0@
+
+  -- ** Documents, parametrized by their annotations
+  --
+  -- Omitted compared to original: @putDoc, hPutDoc@
+  -- Doc,
+
+  -- ** Basic combinators
+  --
+  -- Omitted compared to original: @empty, char, text, (<>)@
+  --
+  -- Instead of @text@ and @char@, use 'fromString'.
+  --
+  -- Instead of @empty@, use 'mempty'.
+  , nest
+  , line
+  , linebreak
+  , group
+  , softline
+  , softbreak
+
+  -- ** Alignment
+  --
+  -- The combinators in this section can not be described by Wadler's
+  -- original combinators. They align their output relative to the
+  -- current output position - in contrast to @nest@ which always
+  -- aligns to the current nesting level. This deprives these
+  -- combinators from being \`optimal\'. In practice however they
+  -- prove to be very useful. The combinators in this section should
+  -- be used with care, since they are more expensive than the other
+  -- combinators. For example, @align@ shouldn't be used to pretty
+  -- print all top-level declarations of a language, but using @hang@
+  -- for let expressions is fine.
+  --
+  -- Omitted compared to original: @list, tupled, semiBraces@
+  , align
+  , hang
+  , indent
+  , encloseSep
+
+  -- ** Operators
+  --
+  -- Omitted compared to original: @(<$>), (</>), (<$$>), (<//>)@
+  , (<+>)
+
+    -- ** List combinators
+  , hsep
+  , vsep
+  , fillSep
+  , sep
+  , hcat
+  , vcat
+  , fillCat
+  , cat
+  , punctuate
+
+    -- ** Fillers
+  , fill
+  , fillBreak
+
+    -- ** Bracketing combinators
+  , enclose
+  , squotes
+  , dquotes
+  , parens
+  , angles
+  , braces
+  , brackets
+
+    -- ** Character documents
+    -- Entirely omitted:
+    --
+    -- @
+    -- lparen, rparen, langle, rangle, lbrace, rbrace, lbracket, rbracket,
+    -- squote, dquote, semi, colon, comma, space, dot, backslash, equals,
+    -- pipe
+    -- @
+
+    -- ** Primitive type documents
+    -- Omitted compared to the original:
+    --
+    -- @
+    -- int, integer, float, double, rational, bool,
+    -- @
+  , string
+
+    -- ** Semantic annotations
+  , annotate
+  , noAnnotate
+  , styleAnn
+
+  -- ** Rendering
+  -- Original entirely omitted:
+  -- @
+  -- SimpleDoc(..), renderPretty, renderCompact, displayDecorated, displayDecoratedA, display, displayS, displayIO,
+  -- SpanList(..), displaySpans
+  -- @
+
+  -- ** Undocumented
+  -- Entirely omitted:
+  -- @
+  -- column, nesting, width
+  -- @
+  ) where
+
+import           Control.Monad.Reader ( local, runReader )
+import           Data.Array.IArray ( (!), (//) )
+import qualified Data.Text as T
+import           Distribution.ModuleName ( ModuleName )
+import qualified Distribution.Text ( display )
+import           Path ( Dir, File, Path, SomeBase, prjSomeBase, toFilePath )
+import           RIO
+import qualified RIO.Map as M
+import           RIO.PrettyPrint.DefaultStyles ( defaultStyles )
+import           RIO.PrettyPrint.Types ( Style (Dir, File), Styles )
+import           RIO.PrettyPrint.StylesUpdate
+                   ( HasStylesUpdate, StylesUpdate (..), stylesUpdateL )
+import           System.Console.ANSI ( ConsoleLayer (..), SGR (..), setSGRCode )
+import qualified Text.PrettyPrint.Annotated.Leijen as P
+import           Text.PrettyPrint.Annotated.Leijen ( Doc, SimpleDoc (..) )
+
+-- TODO: consider smashing together the code for wl-annotated-pprint and
+-- wl-pprint-text. The code here already handles doing the
+-- ansi-wl-pprint stuff (better!) atop wl-annotated-pprint. So the
+-- result would be a package unifying 3 different wl inspired packages.
+--
+-- Perhaps it can still have native string support, by adding a type
+-- parameter to Doc?
+
+instance Semigroup StyleDoc where
+  StyleDoc x <> StyleDoc y = StyleDoc (x P.<> y)
+
+instance Monoid StyleDoc where
+  mappend = (<>)
+  mempty = StyleDoc P.empty
+
+--------------------------------------------------------------------------------
+-- Pretty-Print class
+
+class Pretty a where
+  pretty :: a -> StyleDoc
+  default pretty :: Show a => a -> StyleDoc
+  pretty = StyleDoc . fromString . show
+
+instance Pretty StyleDoc where
+  pretty = id
+
+instance Pretty (Path b File) where
+  pretty = styleAnn File . StyleDoc . fromString . toFilePath
+
+instance Pretty (Path b Dir) where
+  pretty = styleAnn Dir . StyleDoc . fromString . toFilePath
+
+instance Pretty (SomeBase File) where
+  pretty = prjSomeBase pretty
+
+instance Pretty (SomeBase Dir) where
+  pretty = prjSomeBase pretty
+
+instance Pretty ModuleName where
+  pretty = StyleDoc . fromString . Distribution.Text.display
+
+--------------------------------------------------------------------------------
+-- Style Doc
+
+-- |A style annotation.
+newtype StyleAnn = StyleAnn (Maybe Style)
+  deriving (Eq, Show, Semigroup)
+
+instance Monoid StyleAnn where
+  mempty = StyleAnn Nothing
+  mappend = (<>)
+
+-- |A document annotated by a style
+newtype StyleDoc = StyleDoc { unStyleDoc :: Doc StyleAnn }
+  deriving (IsString, Show)
+
+-- |An ANSI code(s) annotation.
+newtype AnsiAnn = AnsiAnn [SGR]
+  deriving (Eq, Show, Semigroup, Monoid)
+
+-- |Convert a 'SimpleDoc' annotated with 'StyleAnn' to one annotated with
+-- 'AnsiAnn', by reference to a 'Styles'.
+toAnsiDoc :: Styles -> SimpleDoc StyleAnn -> SimpleDoc AnsiAnn
+toAnsiDoc styles = go
+ where
+  go SEmpty        = SEmpty
+  go (SChar c d)   = SChar c (go d)
+  go (SText l s d) = SText l s (go d)
+  go (SLine i d)   = SLine i (go d)
+  go (SAnnotStart (StyleAnn (Just s)) d) =
+    SAnnotStart (AnsiAnn (snd $ styles ! s)) (go d)
+  go (SAnnotStart (StyleAnn Nothing) d) = SAnnotStart (AnsiAnn []) (go d)
+  go (SAnnotStop d) = SAnnotStop (go d)
+
+displayPlain ::
+     ( Pretty a, HasLogFunc env, HasStylesUpdate env, MonadReader env m
+     , HasCallStack
+     )
+  => Int -> a -> m Utf8Builder
+displayPlain w =
+  displayAnsiSimple . renderDefault w . fmap (const mempty) . unStyleDoc . pretty
+
+-- TODO: tweak these settings more?
+-- TODO: options for settings if this is released as a lib
+
+renderDefault :: Int -> Doc a -> SimpleDoc a
+renderDefault = P.renderPretty 1
+
+displayAnsi ::
+     ( Pretty a, HasLogFunc env, HasStylesUpdate env, MonadReader env m
+     , HasCallStack
+     )
+  => Int -> a -> m Utf8Builder
+displayAnsi w =
+  displayAnsiSimple . renderDefault w . unStyleDoc . pretty
+
+{- Not used --------------------------------------------------------------------
+
+hDisplayAnsi
+    :: (Display a, HasAnsiAnn (Ann a), MonadIO m)
+    => Handle -> Int -> a -> m ()
+hDisplayAnsi h w x = liftIO $ do
+    useAnsi <- hSupportsANSI h
+    T.hPutStr h $ if useAnsi then displayAnsi w x else displayPlain w x
+
+-}
+
+displayAnsiSimple ::
+     (HasLogFunc env, HasStylesUpdate env, MonadReader env m, HasCallStack)
+  => SimpleDoc StyleAnn
+  -> m Utf8Builder
+displayAnsiSimple doc = do
+  update <- view stylesUpdateL
+  let styles = defaultStyles // stylesUpdate update
+      doc' = toAnsiDoc styles doc
+  return $ flip runReader mempty $ displayDecoratedWrap go doc'
+ where
+  go (AnsiAnn sgrs) inner = do
+    old <- ask
+    let sgrs' = mapMaybe (\sgr -> if sgr == Reset
+                                    then Nothing
+                                    else Just (getSGRTag sgr, sgr)) sgrs
+        new = if Reset `elem` sgrs
+                then M.fromList sgrs'
+                else foldl' (\mp (tag, sgr) -> M.insert tag sgr mp) old sgrs'
+    (extra, contents) <- local (const new) inner
+    return (extra, transitionCodes old new <> contents <> transitionCodes new old)
+  transitionCodes old new =
+    case (null removals, null additions) of
+      (True, True) -> mempty
+      (True, False) -> fromString (setSGRCode additions)
+      (False, _) -> fromString (setSGRCode (Reset : M.elems new))
+   where
+    (removals, additions) = partitionEithers $ M.elems $
+      M.mergeWithKey
+        (\_ o n -> if o == n then Nothing else Just (Right n))
+        (fmap Left)
+        (fmap Right)
+        old
+        new
+
+displayDecoratedWrap ::
+     forall a m. Monad m
+  => (forall b. a -> m (b, Utf8Builder) -> m (b, Utf8Builder))
+  -> SimpleDoc a
+  -> m Utf8Builder
+displayDecoratedWrap f doc = do
+  (mafter, result) <- go doc
+  case mafter of
+    Just _ -> error "Invariant violated by input to displayDecoratedWrap: no \
+                    \matching SAnnotStart for SAnnotStop."
+    Nothing -> return result
+ where
+  spaces n = display (T.replicate n " ")
+
+  go :: SimpleDoc a -> m (Maybe (SimpleDoc a), Utf8Builder)
+  go SEmpty = return (Nothing, mempty)
+  go (SChar c x) = fmap (fmap (display c <>)) (go x)
+  -- NOTE: Could actually use the length to guess at an initial
+  -- allocation.  Better yet would be to just use Text in pprint..
+  go (SText _l s x) = fmap (fmap (fromString s <>)) (go x)
+  go (SLine n x) = fmap (fmap ((display '\n' <>) . (spaces n <>))) (go x)
+  go (SAnnotStart ann x) = do
+    (mafter, contents) <- f ann (go x)
+    case mafter of
+      Just after -> fmap (fmap (contents <>)) (go after)
+      Nothing -> error "Invariant violated by input to displayDecoratedWrap: \
+                       \no matching SAnnotStop for SAnnotStart."
+  go (SAnnotStop x) = return (Just x, mempty)
+
+{- Not used --------------------------------------------------------------------
+
+-- Foreground color combinators
+
+black, red, green, yellow, blue, magenta, cyan, white,
+    dullblack, dullred, dullgreen, dullyellow, dullblue, dullmagenta, dullcyan, dullwhite,
+    onblack, onred, ongreen, onyellow, onblue, onmagenta, oncyan, onwhite,
+    ondullblack, ondullred, ondullgreen, ondullyellow, ondullblue, ondullmagenta, ondullcyan, ondullwhite
+    :: Doc AnsiAnn -> Doc AnsiAnn
+(black, dullblack, onblack, ondullblack) = colorFunctions Black
+(red, dullred, onred, ondullred) = colorFunctions Red
+(green, dullgreen, ongreen, ondullgreen) = colorFunctions Green
+(yellow, dullyellow, onyellow, ondullyellow) = colorFunctions Yellow
+(blue, dullblue, onblue, ondullblue) = colorFunctions Blue
+(magenta, dullmagenta, onmagenta, ondullmagenta) = colorFunctions Magenta
+(cyan, dullcyan, oncyan, ondullcyan) = colorFunctions Cyan
+(white, dullwhite, onwhite, ondullwhite) = colorFunctions White
+
+type EndoAnsiDoc = Doc AnsiAnn -> Doc AnsiAnn
+
+colorFunctions :: Color -> (EndoAnsiDoc, EndoAnsiDoc, EndoAnsiDoc, EndoAnsiDoc)
+colorFunctions color =
+    ( ansiAnn [SetColor Foreground Vivid color]
+    , ansiAnn [SetColor Foreground Dull color]
+    , ansiAnn [SetColor Background Vivid color]
+    , ansiAnn [SetColor Background Dull color]
+    )
+
+-}
+
+styleAnn :: Style -> StyleDoc -> StyleDoc
+styleAnn s = StyleDoc . P.annotate (StyleAnn (Just s)) . unStyleDoc
+
+{- Not used --------------------------------------------------------------------
+
+-- Intensity combinators
+
+bold, faint, normal :: Doc AnsiAnn -> Doc AnsiAnn
+bold = ansiAnn [SetConsoleIntensity BoldIntensity]
+faint = ansiAnn [SetConsoleIntensity FaintIntensity]
+normal = ansiAnn [SetConsoleIntensity NormalIntensity]
+
+-}
+
+-- | Tags for each field of state in SGR (Select Graphics Rendition).
+--
+-- It's a bit of a hack that 'TagReset' is included.
+data SGRTag
+  = TagReset
+  | TagConsoleIntensity
+  | TagItalicized
+  | TagUnderlining
+  | TagBlinkSpeed
+  | TagVisible
+  | TagSwapForegroundBackground
+  | TagColorForeground
+  | TagColorBackground
+  | TagRGBColor
+  | TagPaletteColor
+  deriving (Eq, Ord)
+
+getSGRTag :: SGR -> SGRTag
+getSGRTag Reset{}                       = TagReset
+getSGRTag SetConsoleIntensity{}         = TagConsoleIntensity
+getSGRTag SetItalicized{}               = TagItalicized
+getSGRTag SetUnderlining{}              = TagUnderlining
+getSGRTag SetBlinkSpeed{}               = TagBlinkSpeed
+getSGRTag SetVisible{}                  = TagVisible
+getSGRTag SetSwapForegroundBackground{} = TagSwapForegroundBackground
+getSGRTag (SetColor Foreground _ _)     = TagColorForeground
+getSGRTag (SetColor Background _ _)     = TagColorBackground
+getSGRTag SetRGBColor{}                 = TagRGBColor
+getSGRTag SetPaletteColor{}             = TagPaletteColor
+
+(<+>) :: StyleDoc -> StyleDoc -> StyleDoc
+StyleDoc x <+> StyleDoc y = StyleDoc (x P.<+> y)
+
+align :: StyleDoc -> StyleDoc
+align = StyleDoc . P.align . unStyleDoc
+
+noAnnotate :: StyleDoc -> StyleDoc
+noAnnotate = StyleDoc . P.noAnnotate . unStyleDoc
+
+braces :: StyleDoc -> StyleDoc
+braces = StyleDoc . P.braces . unStyleDoc
+
+angles :: StyleDoc -> StyleDoc
+angles = StyleDoc . P.angles . unStyleDoc
+
+parens :: StyleDoc -> StyleDoc
+parens = StyleDoc . P.parens . unStyleDoc
+
+dquotes :: StyleDoc -> StyleDoc
+dquotes = StyleDoc . P.dquotes . unStyleDoc
+
+squotes :: StyleDoc -> StyleDoc
+squotes = StyleDoc . P.squotes . unStyleDoc
+
+brackets :: StyleDoc -> StyleDoc
+brackets = StyleDoc . P.brackets . unStyleDoc
+
+-- | The document @string s@ concatenates all characters in @s@ using @line@ for
+-- newline characters and @char@ for all other characters. It is used whenever
+-- the text contains newline characters.
+--
+-- @since 0.1.4.0
+string :: String -> StyleDoc
+string "" = mempty
+string ('\n':s) = line <> string s
+string s        = let (xs, ys) = span (/='\n') s
+                  in  fromString xs <> string ys
+
+annotate :: StyleAnn -> StyleDoc -> StyleDoc
+annotate a = StyleDoc . P.annotate a . unStyleDoc
+
+nest :: Int -> StyleDoc -> StyleDoc
+nest a = StyleDoc . P.nest a . unStyleDoc
+
+line :: StyleDoc
+line = StyleDoc P.line
+
+linebreak :: StyleDoc
+linebreak = StyleDoc P.linebreak
+
+fill :: Int -> StyleDoc -> StyleDoc
+fill a = StyleDoc . P.fill a . unStyleDoc
+
+fillBreak :: Int -> StyleDoc -> StyleDoc
+fillBreak a = StyleDoc . P.fillBreak a . unStyleDoc
+
+enclose :: StyleDoc -> StyleDoc -> StyleDoc -> StyleDoc
+enclose l r x = l <> x <> r
+
+cat :: [StyleDoc] -> StyleDoc
+cat = StyleDoc . P.cat . map unStyleDoc
+
+punctuate :: StyleDoc -> [StyleDoc] -> [StyleDoc]
+punctuate (StyleDoc x) = map StyleDoc . P.punctuate x . map unStyleDoc
+
+fillCat :: [StyleDoc] -> StyleDoc
+fillCat = StyleDoc . P.fillCat . map unStyleDoc
+
+hcat :: [StyleDoc] -> StyleDoc
+hcat = StyleDoc . P.hcat . map unStyleDoc
+
+vcat :: [StyleDoc] -> StyleDoc
+vcat = StyleDoc . P.vcat . map unStyleDoc
+
+sep :: [StyleDoc] -> StyleDoc
+sep = StyleDoc . P.sep . map unStyleDoc
+
+vsep :: [StyleDoc] -> StyleDoc
+vsep = StyleDoc . P.vsep . map unStyleDoc
+
+hsep :: [StyleDoc] -> StyleDoc
+hsep = StyleDoc . P.hsep . map unStyleDoc
+
+fillSep :: [StyleDoc] -> StyleDoc
+fillSep = StyleDoc . P.fillSep . map unStyleDoc
+
+encloseSep :: StyleDoc -> StyleDoc -> StyleDoc -> [StyleDoc] -> StyleDoc
+encloseSep (StyleDoc x) (StyleDoc y) (StyleDoc z) =
+  StyleDoc . P.encloseSep x y z . map unStyleDoc
+
+indent :: Int -> StyleDoc -> StyleDoc
+indent a = StyleDoc . P.indent a . unStyleDoc
+
+hang :: Int -> StyleDoc -> StyleDoc
+hang a = StyleDoc . P.hang a . unStyleDoc
+
+softbreak :: StyleDoc
+softbreak = StyleDoc P.softbreak
+
+softline :: StyleDoc
+softline = StyleDoc P.softline
+
+group :: StyleDoc -> StyleDoc
+group = StyleDoc . P.group . unStyleDoc