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