{-# OPTIONS_GHC -fno-warn-orphans -fno-warn-dodgy-imports #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleContexts #-}
module Render
( blockBodyToDoc
) where
import Data.List.Compat hiding (group)
import Data.Maybe
import Data.Monoid.Compat
import Data.Ord
import Distribution.Pretty
import Distribution.Types.Dependency
import Distribution.Types.IncludeRenaming
import Distribution.Types.LegacyExeDependency
import Distribution.Types.Mixin
import Distribution.Types.ModuleReexport
import Distribution.Types.ModuleRenaming
import Distribution.Types.PackageName
import Distribution.Types.PkgconfigDependency
import Distribution.Types.PkgconfigName
import Distribution.Version
import Documentation.Haddock.Types
import Prelude.Compat hiding ((<$>))
import qualified Prelude.Compat as P
import Text.PrettyPrint.ANSI.Leijen hiding ((<>))
import Render.Lib
import Render.Options
import Types.Block
import Types.Field
deriving instance Ord ModuleReexport
fieldValueToDoc k (Field _ f) =
case f of
Dependencies ds ->
buildDepsToDoc k $ map (\(Dependency pn v) -> (P $ unPackageName pn, v)) ds
ToolDepends ts -> buildDepsToDoc k $ map exeDependencyAsDependency ts
OldToolDepends ds ->
buildDepsToDoc k $ map (\(LegacyExeDependency pn v) -> (P pn, v)) ds
PcDepends ds ->
buildDepsToDoc k $
map (\(PkgconfigDependency pn v) -> (P $ unPkgconfigName pn, v)) ds
Mixins ms -> mixinsToDoc k $ map (\(Mixin pn r) -> (P $ unPackageName pn, r)) ms
RexpModules rms ->
buildDepsToDoc k $
map (\rexp -> (P $ show $ rexpModuleDoc rexp, anyVersion)) rms
n -> val' n <&> \v -> colon <> indent (k + 1) (align v)
where
val' (Str x) = pure $ string x
val' (File x) = pure $ filepath x
val' (Version v) = pure $ string $ prettyShow v
val' (CabalVersion (Left v)) = pure $ string $ prettyShow v
val' (CabalVersion (Right vr))
| vr == anyVersion = showVersionRange (orLaterVersion (mkVersion [1, 10]))
| otherwise = showVersionRange vr
val' (License l) = pure $ string $ prettyShow l
val' (SPDXLicense l) = pure $ string $ prettyShow l
val' (TestedWith ts) = renderTestedWith ts
val' (LongList fs) = pure $ vcat $ map filepath fs
val' (Commas fs) = pure $ fillSep $ punctuate comma $ map filepath fs
val' (Spaces ls) = pure $ fillSep $ map filepath ls
val' (Modules ms) = pure $ vcat $ map moduleDoc $ sort ms
val' (Module m) = pure $ moduleDoc m
val' (Extensions es) = val' (LongList $ map prettyShow $ sort es)
val' (FlibType ty) = pure $ string $ prettyShow ty
val' (FlibOptions fs) = val' $ Spaces $ map prettyShow fs
val' x = error $ show x
fieldValueToDoc k (Description s) = descriptionToDoc k s
descriptionToDoc k paras = do
n <- asks indentSize
return $
(<>) colon $
nest n $
case paras of
DocParagraph {} -> indent (k + 1) ds
_ -> linebreak <> ds
where
ds = renderDescription paras
mixinsToDoc k bs
| k == 0 = pure $ deps ": "
| otherwise = pure $ colon <> indent (k - 1) (deps " ")
where
deps lsep =
enclose (string lsep) empty $
hcat $
intersperse (hardline <> string ", ") $ map showField $ sortOn fst bs
longest = maximum $ map (length . unP . fst) bs
hasRequires = any (\(_, c) -> not (isDefaultRenaming $ includeRequiresRn c)) bs
showField (P fName, i@IncludeRenaming {..})
| isDefaultIncludeRenaming i = string fName
| otherwise =
width (string fName) $ \fn ->
let delt n =
indent
(n + 1)
(if isDefaultRenaming includeRequiresRn
then providesDoc includeProvidesRn
else group $
align'
9
(providesDoc includeProvidesRn <$>
string "requires" <+>
providesDoc includeRequiresRn))
pad doc =
if hasRequires
then string (replicate (8 - longest) ' ') <> doc
else doc
in flatAlt (pad $ delt (longest - fn)) (delt 0)
parenthesize =
group .
encloseSep
(flatAlt (string " (") lparen)
(flatAlt (line <> rparen) rparen)
(string ", ")
providesDoc (ModuleRenaming ms) = parenthesize $ map renaming ms
providesDoc (HidingRenaming hs) = string "hiding" <+> parenthesize (map moduleDoc hs)
providesDoc DefaultRenaming = empty
renaming (m1, m2) = moduleDoc m1 <+> string "as" <+> moduleDoc m2
align' n doc = column (\ko -> nesting (\i -> nest (ko - i - n) doc))
buildDepsToDoc :: Int -> [(P, VersionRange)] -> Render Doc
buildDepsToDoc k bs
| k == 0 = deps ": "
| otherwise = fmap (\r -> colon <> indent (k - 1) r) (deps " ")
where
deps lsep = do
fs <- mapM showField $ sortOn fst bs
return $ encloseSep (string lsep) empty (string ", ") fs
longest = maximum $ map (length . unP . fst) bs
showField (P fName, fieldVal)
| fieldVal == anyVersion = pure $ string fName
| otherwise =
widthR (string fName) $ \fn -> do
shown <- showVersionRange fieldVal
let delt n = indent (n + 1) shown
in pure $ flatAlt (delt (longest - fn)) (delt 0)
fieldsToDoc :: [Field] -> Render Doc
fieldsToDoc fs =
vcat P.<$>
mapM
(\field ->
widthR (dullblue $ string (fieldName field)) $ \fn ->
fieldValueToDoc (longestField - fn) field)
fs
where
longestField = maximum $ map (length . fieldName) fs
renderBlock :: Block -> Render Doc
renderBlock (Block t fs blocks) = do
blkhead <- renderBlockHead t
body <- indentM . align =<< blockBodyToDoc fs blocks
return $
(if isElse t
then id
else (<>) line)
blkhead <$$>
body
blockBodyToDoc :: [Maybe Field] -> [Block] -> Render Doc
blockBodyToDoc fs blocks = do
fields <-
fieldsToDoc
(if null fs'
then buildable'
else fs')
subblocks <- mapM renderBlock blocks
return $ fields <> vcat (empty : subblocks)
where
fs' = catMaybes fs
buildable' = [fromJust $ stringField "buildable" "True"]