-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
165 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
{-# LANGUAGE BangPatterns #-} | ||
-- | Cabal-like file AST types: 'Field', 'Section' etc, | ||
-- | ||
-- This (intermediate) data type is used for pretty-printing. | ||
-- | ||
-- @since 3.0.0.0 | ||
-- | ||
module Distribution.Fields.Pretty ( | ||
-- * Fields | ||
PrettyField (..), | ||
showFields, | ||
showFields', | ||
-- * Transformation from 'P.Field' | ||
fromParsecFields, | ||
genericFromParsecFields, | ||
prettyFieldLines, | ||
prettySectionArgs, | ||
) where | ||
|
||
import Data.Functor.Identity (Identity (..)) | ||
import Distribution.Pretty (showToken) | ||
|
||
import Distribution.Parsec.Field (FieldName) | ||
import Distribution.Simple.Utils (fromUTF8BS) | ||
|
||
import qualified Distribution.Parsec.Parser as P | ||
|
||
import qualified Data.ByteString as BS | ||
import qualified Text.PrettyPrint as PP | ||
|
||
data PrettyField | ||
= PrettyField FieldName PP.Doc | ||
| PrettySection FieldName [PP.Doc] [PrettyField] | ||
deriving Show | ||
|
||
-- | Prettyprint a list of fields. | ||
showFields :: [PrettyField] -> String | ||
showFields = showFields' 4 | ||
|
||
-- | 'showFields' with user specified indentation. | ||
showFields' :: Int -> [PrettyField] -> String | ||
showFields' n = unlines . renderFields indent where | ||
-- few hardcoded, "unrolled" variants. | ||
indent | n == 4 = indent4 | ||
| n == 2 = indent2 | ||
| otherwise = (replicate (max n 1) ' ' ++) | ||
|
||
indent4 :: String -> String | ||
indent4 [] = [] | ||
indent4 xs = ' ' : ' ' : ' ' : ' ' : xs | ||
|
||
indent2 :: String -> String | ||
indent2 [] = [] | ||
indent2 xs = ' ' : ' ' : xs | ||
|
||
renderFields :: (String -> String) -> [PrettyField] -> [String] | ||
renderFields indent fields = flattenBlocks $ map (renderField indent len) fields | ||
where | ||
len = maxNameLength 0 fields | ||
|
||
maxNameLength !acc [] = acc | ||
maxNameLength !acc (PrettyField name _ : rest) = maxNameLength (max acc (BS.length name)) rest | ||
maxNameLength !acc (PrettySection {} : rest) = maxNameLength acc rest | ||
|
||
-- | Block of lines, | ||
-- Boolean parameter tells whether block should be surrounded by empty lines | ||
data Block = Block Bool [String] | ||
|
||
flattenBlocks :: [Block] -> [String] | ||
flattenBlocks = go0 where | ||
go0 [] = [] | ||
go0 (Block surr strs : blocks) = strs ++ go surr blocks | ||
|
||
go _surr' [] = [] | ||
go surr' (Block surr strs : blocks) = ins $ strs ++ go surr blocks where | ||
ins | surr' || surr = ("" :) | ||
| otherwise = id | ||
|
||
renderField :: (String -> String) -> Int -> PrettyField -> Block | ||
renderField indent fw (PrettyField name doc) = Block False $ case lines narrow of | ||
[] -> [ name' ++ ":" ] | ||
[singleLine] | length singleLine < 60 | ||
-> [ name' ++ ": " ++ replicate (fw - length name') ' ' ++ narrow ] | ||
_ -> (name' ++ ":") : map indent (lines (PP.render doc)) | ||
where | ||
name' = fromUTF8BS name | ||
narrow = PP.renderStyle narrowStyle doc | ||
|
||
narrowStyle :: PP.Style | ||
narrowStyle = PP.style { PP.lineLength = PP.lineLength PP.style - fw } | ||
|
||
renderField indent _ (PrettySection name args fields) = Block True $ | ||
PP.render (PP.hsep $ PP.text (fromUTF8BS name) : args) | ||
: | ||
map indent (renderFields indent fields) | ||
|
||
------------------------------------------------------------------------------- | ||
-- Transform from Parsec.Field | ||
------------------------------------------------------------------------------- | ||
|
||
genericFromParsecFields | ||
:: Applicative f | ||
=> (FieldName -> [P.FieldLine ann] -> f PP.Doc) -- ^ transform field contents | ||
-> (FieldName -> [P.SectionArg ann] -> f [PP.Doc]) -- ^ transform section arguments | ||
-> [P.Field ann] | ||
-> f [PrettyField] | ||
genericFromParsecFields f g = goMany where | ||
goMany = traverse go | ||
|
||
go (P.Field (P.Name _ann name) fls) = PrettyField name <$> f name fls | ||
go (P.Section (P.Name _ann name) secargs fs) = PrettySection name <$> g name secargs <*> goMany fs | ||
|
||
-- | Used in 'fromParsecFields'. | ||
prettyFieldLines :: FieldName -> [P.FieldLine ann] -> PP.Doc | ||
prettyFieldLines _ fls = PP.vcat | ||
[ PP.text $ fromUTF8BS bs | ||
| P.FieldLine _ bs <- fls | ||
] | ||
|
||
-- | Used in 'fromParsecFields'. | ||
prettySectionArgs :: FieldName -> [P.SectionArg ann] -> [PP.Doc] | ||
prettySectionArgs _ = map $ \sa -> case sa of | ||
P.SecArgName _ bs -> showToken $ fromUTF8BS bs | ||
P.SecArgStr _ bs -> showToken $ fromUTF8BS bs | ||
P.SecArgOther _ bs -> PP.text $ fromUTF8BS bs | ||
|
||
-- | Simple variant of 'genericFromParsecField' | ||
fromParsecFields :: [P.Field ann] -> [PrettyField] | ||
fromParsecFields = runIdentity . genericFromParsecFields | ||
(Identity .: prettyFieldLines) | ||
(Identity .: prettySectionArgs) | ||
where | ||
(.:) :: (a -> b) -> (c -> d -> a) -> (c -> d -> b) | ||
(f .: g) x y = f (g x y) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters