forked from commercialhaskell/stack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPrettyPrint.hs
More file actions
146 lines (121 loc) · 4.82 KB
/
PrettyPrint.hs
File metadata and controls
146 lines (121 loc) · 4.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
module Stack.PrettyPrint
(
-- * Pretty printing functions
displayPlain, displayWithColor
-- * Logging based on pretty-print typeclass
, prettyDebug, prettyInfo, prettyWarn, prettyError
, debugBracket
-- * Color utils
-- | These are preferred to colors directly, so that we can
-- encourage consistency of color meanings.
, errorRed, goodGreen, shellMagenta
, displayTargetPkgId, displayCurrentPkgId, displayCurrentPkgName, displayErrorPkgId
, displayMilliseconds
-- * Formatting utils
, bulletedList
-- * Re-exports from "Text.PrettyPrint.Leijen.Extended"
, Display(..), AnsiDoc, AnsiAnn(..), HasAnsiAnn(..), Doc
, 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
) where
import Control.Exception.Lifted
import Control.Monad.Logger
import Control.Monad.Reader
import Data.List (intersperse)
import Data.Monoid
import Data.String (fromString)
import qualified Data.Text as T
import Language.Haskell.TH
import Path
import Stack.Types.Internal
import Stack.Types.Package
import Stack.Types.PackageIdentifier
import Stack.Types.PackageName
import Stack.Types.Version
import qualified System.Clock as Clock
import Text.PrettyPrint.Leijen.Extended
displayWithColor
:: (HasLogOptions env, MonadReader env m, Display a, HasAnsiAnn (Ann a))
=> a -> m T.Text
displayWithColor x = do
useAnsi <- liftM logUseColor $ view logOptionsL
return $ if useAnsi then displayAnsi x else displayPlain x
-- TODO: switch to using implicit callstacks once 7.8 support is dropped
prettyDebug :: Q Exp
prettyDebug = do
loc <- location
[e| monadLoggerLog loc "" LevelDebug <=< displayWithColor |]
prettyInfo :: Q Exp
prettyInfo = do
loc <- location
[e| monadLoggerLog loc "" LevelInfo <=< displayWithColor |]
prettyWarn :: Q Exp
prettyWarn = do
loc <- location
[e| monadLoggerLog loc "" LevelWarn <=< displayWithColor . (line <>) . (warningYellow "Warning:" <+>) |]
prettyError :: Q Exp
prettyError = do
loc <- location
[e| monadLoggerLog loc "" LevelError <=< displayWithColor . (line <>) . (errorRed "Error:" <+>) |]
debugBracket :: Q Exp
debugBracket = do
loc <- location
[e| \msg f -> do
let output = monadLoggerLog loc "" LevelDebug <=< displayWithColor
output $ "Start: " <> msg
start <- liftIO $ Clock.getTime Clock.Monotonic
x <- f `catch` \ex -> do
end <- liftIO $ Clock.getTime Clock.Monotonic
let diff = Clock.diffTimeSpec start end
output $ "Finished with exception in" <+> displayMilliseconds diff <> ":" <+>
msg <> line <>
"Exception thrown: " <> fromString (show ex)
throw (ex :: SomeException)
end <- liftIO $ Clock.getTime Clock.Monotonic
let diff = Clock.diffTimeSpec start end
output $ "Finished in" <+> displayMilliseconds diff <> ":" <+> msg
return x
|]
errorRed :: AnsiDoc -> AnsiDoc
errorRed = dullred
warningYellow :: AnsiDoc -> AnsiDoc
warningYellow = yellow
goodGreen :: AnsiDoc -> AnsiDoc
goodGreen = green
shellMagenta :: AnsiDoc -> AnsiDoc
shellMagenta = magenta
displayTargetPkgId :: PackageIdentifier -> AnsiDoc
displayTargetPkgId = cyan . display
displayCurrentPkgId :: PackageIdentifier -> AnsiDoc
displayCurrentPkgId = yellow . display
displayCurrentPkgName :: PackageName -> AnsiDoc
displayCurrentPkgName = yellow . display
displayErrorPkgId :: PackageIdentifier -> AnsiDoc
displayErrorPkgId = errorRed . display
instance Display PackageName where
display = fromString . packageNameString
instance Display PackageIdentifier where
display = fromString . packageIdentifierString
instance Display Version where
display = fromString . versionString
instance Display (Path b File) where
display = bold . white . fromString . toFilePath
instance Display (Path b Dir) where
display = bold . blue . fromString . toFilePath
instance Display (PackageName, NamedComponent) where
display = cyan . fromString . T.unpack . renderPkgComponent
-- Display milliseconds.
displayMilliseconds :: Clock.TimeSpec -> AnsiDoc
displayMilliseconds t = goodGreen $
(fromString . show . (`div` 10^(6 :: Int)) . Clock.toNanoSecs) t <> "ms"
bulletedList :: [AnsiDoc] -> AnsiDoc
bulletedList = mconcat . intersperse line . map ("*" <+>)