/src/Language/Haskell/Brittany/Internal/Layouters/IE.hs

https://github.com/lspitzner/brittany · Haskell · 184 lines · 154 code · 10 blank · 20 comment · 4 complexity · f6e6359d5ebf0d3e58ee18acd7e7dfd6 MD5 · raw file

  1. module Language.Haskell.Brittany.Internal.Layouters.IE
  2. ( layoutIE
  3. , layoutLLIEs
  4. , layoutAnnAndSepLLIEs
  5. )
  6. where
  7. #include "prelude.inc"
  8. import Language.Haskell.Brittany.Internal.Types
  9. import Language.Haskell.Brittany.Internal.LayouterBasics
  10. import Language.Haskell.Brittany.Internal.Config.Types
  11. import GHC ( unLoc
  12. , runGhc
  13. , GenLocated(L)
  14. , moduleNameString
  15. , AnnKeywordId(..)
  16. , Located
  17. )
  18. import HsSyn
  19. import Name
  20. import HsImpExp
  21. import FieldLabel
  22. import qualified FastString
  23. import BasicTypes
  24. import Language.Haskell.Brittany.Internal.Utils
  25. #if MIN_VERSION_ghc(8,2,0)
  26. prepareName :: LIEWrappedName name -> Located name
  27. prepareName = ieLWrappedName
  28. #else
  29. prepareName :: Located name -> Located name
  30. prepareName = id
  31. #endif
  32. layoutIE :: ToBriDoc IE
  33. layoutIE lie@(L _ ie) = docWrapNode lie $ case ie of
  34. #if MIN_VERSION_ghc(8,6,0)
  35. IEVar _ x -> layoutWrapped lie x
  36. #else
  37. IEVar x -> layoutWrapped lie x
  38. #endif
  39. #if MIN_VERSION_ghc(8,6,0)
  40. IEThingAbs _ x -> layoutWrapped lie x
  41. #else
  42. IEThingAbs x -> layoutWrapped lie x
  43. #endif
  44. #if MIN_VERSION_ghc(8,6,0)
  45. IEThingAll _ x -> docSeq [layoutWrapped lie x, docLit $ Text.pack "(..)"]
  46. #else
  47. IEThingAll x -> docSeq [layoutWrapped lie x, docLit $ Text.pack "(..)"]
  48. #endif
  49. #if MIN_VERSION_ghc(8,6,0)
  50. IEThingWith _ x (IEWildcard _) _ _ ->
  51. #else
  52. IEThingWith x (IEWildcard _) _ _ ->
  53. #endif
  54. docSeq [layoutWrapped lie x, docLit $ Text.pack "(..)"]
  55. #if MIN_VERSION_ghc(8,6,0)
  56. IEThingWith _ x _ ns _ -> do
  57. #else
  58. IEThingWith x _ ns _ -> do
  59. #endif
  60. hasComments <- orM
  61. ( hasCommentsBetween lie AnnOpenP AnnCloseP
  62. : hasAnyCommentsBelow x
  63. : map hasAnyCommentsBelow ns
  64. )
  65. runFilteredAlternative $ do
  66. addAlternativeCond (not hasComments)
  67. $ docSeq
  68. $ [layoutWrapped lie x, docLit $ Text.pack "("]
  69. ++ intersperse docCommaSep (map nameDoc ns)
  70. ++ [docParenR]
  71. addAlternative
  72. $ docWrapNodeRest lie
  73. $ docAddBaseY BrIndentRegular
  74. $ docPar
  75. (layoutWrapped lie x)
  76. (layoutItems (splitFirstLast ns))
  77. where
  78. nameDoc = (docLit =<<) . lrdrNameToTextAnn . prepareName
  79. layoutItem n = docSeq [docCommaSep, docWrapNode n $ nameDoc n]
  80. layoutItems FirstLastEmpty = docSetBaseY $ docLines
  81. [docSeq [docParenLSep, docNodeAnnKW lie (Just AnnOpenP) docEmpty], docParenR]
  82. layoutItems (FirstLastSingleton n) = docSetBaseY $ docLines
  83. [docSeq [docParenLSep, docNodeAnnKW lie (Just AnnOpenP) $ nameDoc n], docParenR]
  84. layoutItems (FirstLast n1 nMs nN) =
  85. docSetBaseY
  86. $ docLines
  87. $ [docSeq [docParenLSep, docWrapNode n1 $ nameDoc n1]]
  88. ++ map layoutItem nMs
  89. ++ [docSeq [docCommaSep, docNodeAnnKW lie (Just AnnOpenP) $ nameDoc nN], docParenR]
  90. #if MIN_VERSION_ghc(8,6,0)
  91. IEModuleContents _ n -> docSeq
  92. #else
  93. IEModuleContents n -> docSeq
  94. #endif
  95. [ docLit $ Text.pack "module"
  96. , docSeparator
  97. , docLit . Text.pack . moduleNameString $ unLoc n
  98. ]
  99. _ -> docEmpty
  100. where
  101. #if MIN_VERSION_ghc(8,2,0) /* ghc-8.2, 8.4, .. */
  102. layoutWrapped _ = \case
  103. L _ (IEName n) -> docLit =<< lrdrNameToTextAnn n
  104. L _ (IEPattern n) -> do
  105. name <- lrdrNameToTextAnn n
  106. docLit $ Text.pack "pattern " <> name
  107. L _ (IEType n) -> do
  108. name <- lrdrNameToTextAnn n
  109. docLit $ Text.pack "type " <> name
  110. #else /* ghc-8.0 */
  111. layoutWrapped outer n = do
  112. name <- lrdrNameToTextAnn n
  113. hasType <- hasAnnKeyword n AnnType
  114. hasPattern <- hasAnnKeyword outer AnnPattern
  115. docLit $ if
  116. | hasType -> Text.pack "type (" <> name <> Text.pack ")"
  117. | hasPattern -> Text.pack "pattern " <> name
  118. | otherwise -> name
  119. #endif
  120. -- Helper function to deal with Located lists of LIEs.
  121. -- In particular this will also associate documentation
  122. -- from the located list that actually belongs to the last IE.
  123. -- It also adds docCommaSep to all but the first element
  124. -- This configuration allows both vertical and horizontal
  125. -- handling of the resulting list. Adding parens is
  126. -- left to the caller since that is context sensitive
  127. layoutAnnAndSepLLIEs
  128. :: Located [LIE GhcPs] -> ToBriDocM [ToBriDocM BriDocNumbered]
  129. layoutAnnAndSepLLIEs llies@(L _ lies) = do
  130. let makeIENode ie = docSeq [docCommaSep, ie]
  131. let ieDocs = layoutIE <$> lies
  132. ieCommaDocs <-
  133. docWrapNodeRest llies $ sequence $ case splitFirstLast ieDocs of
  134. FirstLastEmpty -> []
  135. FirstLastSingleton ie -> [ie]
  136. FirstLast ie1 ieMs ieN ->
  137. [ie1] ++ map makeIENode ieMs ++ [makeIENode ieN]
  138. pure $ fmap pure ieCommaDocs -- returned shared nodes
  139. -- Builds a complete layout for the given located
  140. -- list of LIEs. The layout provides two alternatives:
  141. -- (item, item, ..., item)
  142. -- ( item
  143. -- , item
  144. -- ...
  145. -- , item
  146. -- )
  147. -- If the llies contains comments the list will
  148. -- always expand over multiple lines, even when empty:
  149. -- () -- no comments
  150. -- ( -- a comment
  151. -- )
  152. layoutLLIEs :: Bool -> Located [LIE GhcPs] -> ToBriDocM BriDocNumbered
  153. layoutLLIEs enableSingleline llies = do
  154. ieDs <- layoutAnnAndSepLLIEs llies
  155. hasComments <- hasAnyCommentsBelow llies
  156. runFilteredAlternative $
  157. case ieDs of
  158. [] -> do
  159. addAlternativeCond (not hasComments) $
  160. docLit $ Text.pack "()"
  161. addAlternativeCond hasComments $
  162. docPar (docSeq [docParenLSep, docWrapNodeRest llies docEmpty])
  163. docParenR
  164. (ieDsH:ieDsT) -> do
  165. addAlternativeCond (not hasComments && enableSingleline)
  166. $ docSeq
  167. $ [docLit (Text.pack "(")]
  168. ++ (docForceSingleline <$> ieDs)
  169. ++ [docParenR]
  170. addAlternative
  171. $ docPar (docSetBaseY $ docSeq [docParenLSep, ieDsH])
  172. $ docLines
  173. $ ieDsT
  174. ++ [docParenR]