1+ {-# LANGUAGE RecordWildCards #-}
2+
13module Language.Haskell.Stylish.Step.Data where
24
35import Data.List (find , intercalate )
4- import Data.Maybe (maybeToList )
6+ import Data.Maybe (fromMaybe , maybeToList )
57import qualified Language.Haskell.Exts as H
68import Language.Haskell.Exts.Comments
79import Language.Haskell.Stylish.Block
@@ -10,20 +12,36 @@ import Language.Haskell.Stylish.Step
1012import Language.Haskell.Stylish.Util
1113import Prelude hiding (init )
1214
15+ data Indent
16+ = SameLine
17+ | Indent ! Int
18+ deriving (Show )
19+
20+ data Config = Config
21+ { cEquals :: ! Indent
22+ -- ^ Indent between type constructor and @=@ sign (measured from column 0)
23+ , cFirstField :: ! Indent
24+ -- ^ Indent between data constructor and @{@ line (measured from column with data constructor name)
25+ , cFieldComment :: ! Int
26+ -- ^ Indent between column with @{@ and start of field line comment (this line has @cFieldComment = 2@)
27+ , cDeriving :: ! Int
28+ -- ^ Indent before @deriving@ lines (measured from column 0)
29+ } deriving (Show )
30+
1331datas :: H. Module l -> [H. Decl l ]
1432datas (H. Module _ _ _ _ decls) = decls
1533datas _ = []
1634
1735type ChangeLine = Change String
1836
19- step :: Int -> Step
20- step indentSize = makeStep " Data" (step' indentSize )
37+ step :: Config -> Step
38+ step cfg = makeStep " Data" (step' cfg )
2139
22- step' :: Int -> Lines -> Module -> Lines
23- step' indentSize ls (module', allComments) = applyChanges changes ls
40+ step' :: Config -> Lines -> Module -> Lines
41+ step' cfg ls (module', allComments) = applyChanges changes ls
2442 where
2543 datas' = datas $ fmap linesFromSrcSpan module'
26- changes = datas' >>= maybeToList . changeDecl allComments indentSize
44+ changes = datas' >>= maybeToList . changeDecl allComments cfg
2745
2846findCommentOnLine :: LineBlock -> [Comment ] -> Maybe Comment
2947findCommentOnLine lb = find commentOnLine
@@ -43,9 +61,9 @@ commentsWithin lb = filter within
4361 within (Comment _ (H. SrcSpan _ start _ end _) _) =
4462 start >= blockStart lb && end <= blockEnd lb
4563
46- changeDecl :: [Comment ] -> Int -> H. Decl LineBlock -> Maybe ChangeLine
64+ changeDecl :: [Comment ] -> Config -> H. Decl LineBlock -> Maybe ChangeLine
4765changeDecl _ _ (H. DataDecl _ (H. DataType _) Nothing _ [] _) = Nothing
48- changeDecl allComments indentSize (H. DataDecl block (H. DataType _) Nothing dhead decls derivings)
66+ changeDecl allComments cfg @ Config { .. } (H. DataDecl block (H. DataType _) Nothing dhead decls derivings)
4967 | hasRecordFields = Just $ change block (const $ concat newLines)
5068 | otherwise = Nothing
5169 where
@@ -54,27 +72,55 @@ changeDecl allComments indentSize (H.DataDecl block (H.DataType _) Nothing dhead
5472 (H. QualConDecl _ _ _ (H. RecDecl {})) -> True
5573 _ -> False )
5674 decls
57- newLines = fmap constructors zipped ++ [fmap (indented . H. prettyPrint) derivings]
75+
76+ typeConstructor = " data " <> H. prettyPrint dhead
77+
78+ -- In any case set @pipeIndent@ such that @|@ is aligned with @=@.
79+ (firstLine, firstLineInit, pipeIndent) =
80+ case cEquals of
81+ SameLine -> (Nothing , typeConstructor <> " = " , length typeConstructor + 1 )
82+ Indent n -> (Just [[typeConstructor]], indent n " = " , n)
83+
84+ newLines = fromMaybe [] firstLine ++ fmap constructors zipped <> [fmap (indent cDeriving . H. prettyPrint) derivings]
5885 zipped = zip decls ([1 .. ] :: [Int ])
59- constructors (decl, 1 ) = processConstructor allComments typeConstructor indentSize decl
60- constructors (decl, _) = processConstructor allComments (indented " | " ) indentSize decl
61- typeConstructor = " data " <> H. prettyPrint dhead <> " = "
62- indented = indent indentSize
86+
87+ constructors (decl, 1 ) = processConstructor allComments firstLineInit cfg decl
88+ constructors (decl, _) = processConstructor allComments (indent pipeIndent " | " ) cfg decl
6389changeDecl _ _ _ = Nothing
6490
65- processConstructor :: [Comment ] -> String -> Int -> H. QualConDecl LineBlock -> [String ]
66- processConstructor allComments init indentSize (H. QualConDecl _ _ _ (H. RecDecl _ dname fields )) = do
67- init <> H. prettyPrint dname : n1 ++ ns ++ [indented " }" ]
91+ processConstructor :: [Comment ] -> String -> Config -> H. QualConDecl LineBlock -> [String ]
92+ processConstructor allComments init Config { .. } (H. QualConDecl _ _ _ (H. RecDecl _ dname (f : fs) )) = do
93+ fromMaybe [] firstLine <> n1 <> ns <> [indent fieldIndent " }" ]
6894 where
69- n1 = processName " { " ( extractField $ head fields)
70- ns = tail fields >>= (processName " , " . extractField)
95+ n1 = processName firstLinePrefix (extractField f)
96+ ns = fs >>= processName (indent fieldIndent " , " ) . extractField
97+
98+ -- Set @fieldIndent@ such that @,@ is aligned with @{@.
99+ (firstLine, firstLinePrefix, fieldIndent) =
100+ case cFirstField of
101+ SameLine ->
102+ ( Nothing
103+ , init <> H. prettyPrint dname <> " { "
104+ , length init + length (H. prettyPrint dname) + 1
105+ )
106+ Indent n ->
107+ ( Just [init <> H. prettyPrint dname]
108+ , indent (length init + n) " { "
109+ , length init + n
110+ )
111+
71112 processName prefix (fnames, _type, lineComment, commentBelowLine) =
72- [indented prefix <> intercalate " , " (fmap H. prettyPrint fnames) <> " :: " <> H. prettyPrint _type <> addLineComment lineComment] ++ addCommentBelow commentBelowLine
113+ [prefix <> intercalate " , " (fmap H. prettyPrint fnames) <> " :: " <> H. prettyPrint _type <> addLineComment lineComment
114+ ] ++ addCommentBelow commentBelowLine
115+
73116 addLineComment (Just (Comment _ _ c)) = " --" <> c
74117 addLineComment Nothing = " "
118+
119+ -- Field comment indent is measured from the column with @{@, hence adding of @fieldIndent@ here.
75120 addCommentBelow Nothing = []
76- addCommentBelow (Just (Comment _ _ c)) = [indented " --" <> c]
121+ addCommentBelow (Just (Comment _ _ c)) = [indent (fieldIndent + cFieldComment) " --" <> c]
122+
77123 extractField (H. FieldDecl lb names _type) =
78124 (names, _type, findCommentOnLine lb allComments, findCommentBelowLine lb allComments)
79- indented = indent indentSize
125+
80126processConstructor _ init _ decl = [init <> trimLeft (H. prettyPrint decl)]
0 commit comments