PageRenderTime 72ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Language/Haskell/Stylish/Step/LanguagePragmas.hs

https://gitlab.com/alx741/stylish-haskell
Haskell | 168 lines | 102 code | 39 blank | 27 comment | 3 complexity | 2986110443ab9c823a1d1b001c1de812 MD5 | raw file
  1. --------------------------------------------------------------------------------
  2. module Language.Haskell.Stylish.Step.LanguagePragmas
  3. ( Style (..)
  4. , step
  5. -- * Utilities
  6. , addLanguagePragma
  7. ) where
  8. --------------------------------------------------------------------------------
  9. import qualified Data.Set as S
  10. import qualified Language.Haskell.Exts as H
  11. --------------------------------------------------------------------------------
  12. import Language.Haskell.Stylish.Block
  13. import Language.Haskell.Stylish.Editor
  14. import Language.Haskell.Stylish.Step
  15. import Language.Haskell.Stylish.Util
  16. --------------------------------------------------------------------------------
  17. data Style
  18. = Vertical
  19. | Compact
  20. | CompactLine
  21. deriving (Eq, Show)
  22. --------------------------------------------------------------------------------
  23. pragmas :: H.Module l -> [(l, [String])]
  24. pragmas (H.Module _ _ ps _ _) =
  25. [(l, map nameToString names) | H.LanguagePragma l names <- ps]
  26. pragmas _ = []
  27. --------------------------------------------------------------------------------
  28. -- | The start of the first block
  29. firstLocation :: [(Block a, [String])] -> Int
  30. firstLocation = minimum . map (blockStart . fst)
  31. --------------------------------------------------------------------------------
  32. verticalPragmas :: Int -> Bool -> [String] -> Lines
  33. verticalPragmas longest align pragmas' =
  34. [ "{-# LANGUAGE " ++ pad pragma ++ " #-}"
  35. | pragma <- pragmas'
  36. ]
  37. where
  38. pad
  39. | align = padRight longest
  40. | otherwise = id
  41. --------------------------------------------------------------------------------
  42. compactPragmas :: Int -> [String] -> Lines
  43. compactPragmas columns pragmas' = wrap columns "{-# LANGUAGE" 13 $
  44. map (++ ",") (init pragmas') ++ [last pragmas', "#-}"]
  45. --------------------------------------------------------------------------------
  46. compactLinePragmas :: Int -> Bool -> [String] -> Lines
  47. compactLinePragmas _ _ [] = []
  48. compactLinePragmas columns align pragmas' = map (wrapLanguage . pad) prags
  49. where
  50. wrapLanguage ps = "{-# LANGUAGE" ++ ps ++ " #-}"
  51. maxWidth = columns - 16
  52. longest = maximum $ map length prags
  53. pad
  54. | align = padRight longest
  55. | otherwise = id
  56. prags = map truncateComma $ wrap maxWidth "" 1 $
  57. map (++ ",") (init pragmas') ++ [last pragmas']
  58. --------------------------------------------------------------------------------
  59. truncateComma :: String -> String
  60. truncateComma "" = ""
  61. truncateComma xs
  62. | last xs == ',' = init xs
  63. | otherwise = xs
  64. --------------------------------------------------------------------------------
  65. prettyPragmas :: Int -> Int -> Bool -> Style -> [String] -> Lines
  66. prettyPragmas _ longest align Vertical = verticalPragmas longest align
  67. prettyPragmas cols _ _ Compact = compactPragmas cols
  68. prettyPragmas cols _ align CompactLine = compactLinePragmas cols align
  69. --------------------------------------------------------------------------------
  70. -- | Filter redundant (and duplicate) pragmas out of the groups. As a side
  71. -- effect, we also sort the pragmas in their group...
  72. filterRedundant :: (String -> Bool)
  73. -> [(l, [String])]
  74. -> [(l, [String])]
  75. filterRedundant isRedundant' = snd . foldr filterRedundant' (S.empty, [])
  76. where
  77. filterRedundant' (l, xs) (known, zs)
  78. | S.null xs' = (known', zs)
  79. | otherwise = (known', (l, S.toAscList xs') : zs)
  80. where
  81. fxs = filter (not . isRedundant') xs
  82. xs' = S.fromList fxs `S.difference` known
  83. known' = xs' `S.union` known
  84. --------------------------------------------------------------------------------
  85. step :: Int -> Style -> Bool -> Bool -> Step
  86. step = (((makeStep "LanguagePragmas" .) .) .) . step'
  87. --------------------------------------------------------------------------------
  88. step' :: Int -> Style -> Bool -> Bool -> Lines -> Module -> Lines
  89. step' columns style align removeRedundant ls (module', _)
  90. | null pragmas' = ls
  91. | otherwise = applyChanges changes ls
  92. where
  93. isRedundant'
  94. | removeRedundant = isRedundant module'
  95. | otherwise = const False
  96. pragmas' = pragmas $ fmap linesFromSrcSpan module'
  97. longest = maximum $ map length $ snd =<< pragmas'
  98. groups = [(b, concat pgs) | (b, pgs) <- groupAdjacent pragmas']
  99. changes =
  100. [ change b (const $ prettyPragmas columns longest align style pg)
  101. | (b, pg) <- filterRedundant isRedundant' groups
  102. ]
  103. --------------------------------------------------------------------------------
  104. -- | Add a LANGUAGE pragma to a module if it is not present already.
  105. addLanguagePragma :: String -> H.Module H.SrcSpanInfo -> [Change String]
  106. addLanguagePragma prag modu
  107. | prag `elem` present = []
  108. | otherwise = [insert line ["{-# LANGUAGE " ++ prag ++ " #-}"]]
  109. where
  110. pragmas' = pragmas (fmap linesFromSrcSpan modu)
  111. present = concatMap snd pragmas'
  112. line = if null pragmas' then 1 else firstLocation pragmas'
  113. --------------------------------------------------------------------------------
  114. -- | Check if a language pragma is redundant. We can't do this for all pragmas,
  115. -- but we do a best effort.
  116. isRedundant :: H.Module H.SrcSpanInfo -> String -> Bool
  117. isRedundant m "ViewPatterns" = isRedundantViewPatterns m
  118. isRedundant m "BangPatterns" = isRedundantBangPatterns m
  119. isRedundant _ _ = False
  120. --------------------------------------------------------------------------------
  121. -- | Check if the ViewPatterns language pragma is redundant.
  122. isRedundantViewPatterns :: H.Module H.SrcSpanInfo -> Bool
  123. isRedundantViewPatterns m = null
  124. [() | H.PViewPat _ _ _ <- everything m :: [H.Pat H.SrcSpanInfo]]
  125. --------------------------------------------------------------------------------
  126. -- | Check if the BangPatterns language pragma is redundant.
  127. isRedundantBangPatterns :: H.Module H.SrcSpanInfo -> Bool
  128. isRedundantBangPatterns m = null
  129. [() | H.PBangPat _ _ <- everything m :: [H.Pat H.SrcSpanInfo]]