@@ -4,94 +4,48 @@
44
55-- | Manipulations on import lists.
66module Ormolu.Imports
7− ( normalizeImports,
7+ ( sortImports,
88 )
99where
1010
1111import Data.Bifunctor
1212import Data.Char (isAlphaNum)
1313import Data.Function (on)
14+import Data.Generics (gcompare)
1415import Data.List (foldl', nubBy, sortBy, sortOn)
1516import Data.Map.Strict (Map)
1617import qualified Data.Map.Strict as M
17−import FastString (FastString)
1818import GHC hiding (GhcPs, IE)
1919import GHC.Hs.Extension
2020import GHC.Hs.ImpExp (IE (..))
2121import Ormolu.Utils (notImplemented, showOutputable)
2222
23−-- | Sort and normalize imports.
24−normalizeImports :: [LImportDecl GhcPs] -> [LImportDecl GhcPs]
25−normalizeImports =
26− fmap snd
27− . M.toAscList
28− . M.fromListWith combineImports
29− . fmap (\x -> (importId x, g x))
23+-- | Sort imports by module name. This also sorts and normalizes explicit
24+-- import lists for each declaration.
25+sortImports :: [LImportDecl GhcPs] -> [LImportDecl GhcPs]
26+sortImports = sortBy compareIdecl . fmap (fmap sortImportLists)
3027 where
31− g (L l ImportDecl {..}) =
32− L
33− l
28+ sortImportLists :: ImportDecl GhcPs -> ImportDecl GhcPs
29+ sortImportLists = \case
30+ ImportDecl {..} ->
3431 ImportDecl
3532 { ideclHiding = second (fmap normalizeLies) <$> ideclHiding,
3633 ..
3734 }
38− g _ = notImplemented "XImportDecl"
35+ XImportDecl x -> noExtCon x
3936
40−-- | Combine two import declarations. It should be assumed that 'ImportId's
41−-- are equal.
42−combineImports ::
43− LImportDecl GhcPs ->
44− LImportDecl GhcPs ->
45− LImportDecl GhcPs
46−combineImports (L lx ImportDecl {..}) (L _ y) =
47− L
48− lx
49− ImportDecl
50− { ideclHiding = case (ideclHiding, GHC.ideclHiding y) of
51− (Just (hiding, L l' xs), Just (_, L _ ys)) ->
52− Just (hiding, (L l' (normalizeLies (xs ++ ys))))
53− _ -> Nothing,
54− ..
55− }
56−combineImports _ _ = notImplemented "XImportDecl"
57−
58−-- | Import id, a collection of all things that justify having a separate
59−-- import entry. This is used for merging of imports. If two imports have
60−-- the same 'ImportId' they can be merged.
61−data ImportId = ImportId
62− { importIsPrelude :: Bool,
63− importIdName :: ModuleName,
64− importPkgQual :: Maybe FastString,
65− importSource :: Bool,
66− importSafe :: Bool,
67− importQualified :: Bool,
68− importImplicit :: Bool,
69− importAs :: Maybe ModuleName,
70− importHiding :: Maybe Bool
71− }
72− deriving (Eq, Ord)
73−
74−-- | Obtain an 'ImportId' for a given import.
75−importId :: LImportDecl GhcPs -> ImportId
76−importId (L _ ImportDecl {..}) =
77− ImportId
78− { importIsPrelude = isPrelude,
79− importIdName = moduleName,
80− importPkgQual = sl_fs <$> ideclPkgQual,
81− importSource = ideclSource,
82− importSafe = ideclSafe,
83− importQualified = case ideclQualified of
84− QualifiedPre -> True
85− QualifiedPost -> True
86− NotQualified -> False,
87− importImplicit = ideclImplicit,
88− importAs = unLoc <$> ideclAs,
89− importHiding = fst <$> ideclHiding
90− }
37+-- | Compare two @'LImportDecl' 'GhcPs'@ things.
38+compareIdecl :: LImportDecl GhcPs -> LImportDecl GhcPs -> Ordering
39+compareIdecl (L _ m0) (L _ m1) =
40+ case (isPrelude n0, isPrelude n1) of
41+ (False, False) -> n0 `compare` n1
42+ (True, False) -> GT
43+ (False, True) -> LT
44+ (True, True) -> m0 `gcompare` m1
9145 where
92− isPrelude = moduleNameString moduleName == "Prelude"
93− moduleName = unLoc ideclName
94−importId _ = notImplemented "XImportDecl"
46+ n0 = unLoc (ideclName m0)
47+ n1 = unLoc (ideclName m1)
48+ isPrelude = (== "Prelude") . moduleNameString
9549
9650-- | Normalize a collection of import\/export items.
9751normalizeLies :: [LIE GhcPs] -> [LIE GhcPs]