1module Distribution.Pretty (
2    Pretty (..),
3    prettyShow,
4    defaultStyle,
5    flatStyle,
6    -- * Utilities
7    showFilePath,
8    showToken,
9    showFreeText,
10    showFreeTextV3,
11    -- * Deprecated
12    Separator,
13    ) where
14
15import Distribution.CabalSpecVersion
16import Distribution.Compat.Prelude
17import Prelude ()
18
19import qualified Text.PrettyPrint as PP
20
21class Pretty a where
22    pretty :: a -> PP.Doc
23
24    prettyVersioned :: CabalSpecVersion -> a -> PP.Doc
25    prettyVersioned _ = pretty
26
27-- | @since 3.4.0.0
28instance Pretty PP.Doc where
29    pretty = id
30
31instance Pretty Bool where
32    pretty = PP.text . show
33
34instance Pretty Int where
35    pretty = PP.text . show
36
37instance Pretty a => Pretty (Identity a) where
38    pretty = pretty . runIdentity
39
40prettyShow :: Pretty a => a -> String
41prettyShow = PP.renderStyle defaultStyle . pretty
42
43-- | The default rendering style used in Cabal for console
44-- output. It has a fixed page width and adds line breaks
45-- automatically.
46defaultStyle :: PP.Style
47defaultStyle = PP.Style { PP.mode           = PP.PageMode
48                          , PP.lineLength     = 79
49                          , PP.ribbonsPerLine = 1.0
50                          }
51
52-- | A style for rendering all on one line.
53flatStyle :: PP.Style
54flatStyle = PP.Style { PP.mode = PP.LeftMode
55                       , PP.lineLength = err "lineLength"
56                       , PP.ribbonsPerLine = err "ribbonsPerLine"
57                       }
58  where
59    err x = error ("flatStyle: tried to access " ++ x ++ " in LeftMode. " ++
60                   "This should never happen and indicates a bug in Cabal.")
61
62-------------------------------------------------------------------------------
63-- Utilities
64-------------------------------------------------------------------------------
65
66-- TODO: remove when ReadP parser is gone.
67type Separator = [PP.Doc] -> PP.Doc
68
69showFilePath :: FilePath -> PP.Doc
70showFilePath = showToken
71
72showToken :: String -> PP.Doc
73showToken str
74    -- if token looks like a comment (starts with --), print it in quotes
75    | "--" `isPrefixOf` str                 = PP.text (show str)
76    -- also if token ends with a colon (e.g. executable name), print it in quotes
77    | ":" `isSuffixOf` str                  = PP.text (show str)
78    | not (any dodgy str) && not (null str) = PP.text str
79    | otherwise                             = PP.text (show str)
80  where
81    dodgy c = isSpace c || c == ','
82
83
84-- | Pretty-print free-format text, ensuring that it is vertically aligned,
85-- and with blank lines replaced by dots for correct re-parsing.
86showFreeText :: String -> PP.Doc
87showFreeText "" = mempty
88showFreeText s  = PP.vcat [ PP.text (if null l then "." else l) | l <- lines_ s ]
89
90-- | Pretty-print free-format text.
91-- Since @cabal-version: 3.0@ we don't replace blank lines with dots.
92--
93-- @since 3.0.0.0
94showFreeTextV3 :: String -> PP.Doc
95showFreeTextV3 "" = mempty
96showFreeTextV3 s  = PP.vcat [ PP.text l | l <- lines_ s ]
97
98-- | 'lines_' breaks a string up into a list of strings at newline
99-- characters.  The resulting strings do not contain newlines.
100lines_                   :: String -> [String]
101lines_ [] = [""]
102lines_ s  =
103    let (l, s') = break (== '\n') s
104    in  l : case s' of
105        []      -> []
106        (_:s'') -> lines_ s''
107