fix-imports 1.0.0 → 1.0.1
raw patch · 4 files changed
+42/−35 lines, 4 files
Files
- fix-imports.cabal +13/−8
- src/Config.hs +16/−6
- src/FixImports.hs +9/−13
- src/Types.hs +4/−8
fix-imports.cabal view
@@ -1,25 +1,30 @@ name: fix-imports-version: 1.0.0+version: 1.0.1 cabal-version: >= 1.6 build-type: Simple synopsis: Program to manage the imports of a haskell module description:- A small standalone program to manage the import block of a haskell program.- It will try to add import lines for qualified names with no corresponding- import, remove unused import lines, and sort the import block according to- some heuristic you can define. This only works for qualified imports!- Unqualified imports are left untouched.+ fix-imports is a small standalone program to manage the import block of a+ haskell program. It will try to add import lines for qualified names+ with no corresponding import, remove unused import lines, and sort the+ import block according to some heuristic you can define. This only works+ for qualified imports! Unqualified imports are left untouched. . It's most convenient if bound to an editor key. . Recent major changes: .+ * version 1.0.1+ .+ * Fix a bunch of bugs: properly recognize unqualified imports as imports,+ never import the current module, don't pick up modules with the same suffix+ but a different name.+ . * version 1.0.0 . * Change name from FixImports to fix-imports, which is more unixy. .- * Change ghc-pkg parsing from String to Text.- It's noticeably faster.+ * Change ghc-pkg parsing from String to Text. It's noticeably faster. . * Add a more flexible system for prioritizing imports. When there are several possibilities for a module name, they are all given
src/Config.hs view
@@ -46,25 +46,35 @@ defaultPriorities :: Priorities defaultPriorities = Priorities- ([], ["haskell98"])+ -- Make some common packages low priority so their exports don't get+ -- chosen over what you probably wanted:+ -- haskell98 has obsolete toplevel module names.+ -- ghc exports tons of toplevel modules that you probably don't want.+ -- Cabal is probably mostly used in Setup.hs and exports Distribution.Text.+ ([], ["haskell98", "ghc", "Cabal"]) (map Types.ModuleName [], map Types.ModuleName ["GHC"]) -- * pick candidates -- | Prefer local modules that share prefix with the module path, then prefer -- local modules to ones from packages, then prefer modules from the packages--- in packagePriority.+-- in packagePriority. If all else is equal alphabetize so at least the+-- order is predictable. pickModule :: Priorities -> FilePath -> [(Maybe Index.Package, Types.ModuleName)] -> Maybe (Maybe Index.Package, Types.ModuleName) pickModule prios modulePath candidates =- Util.head $ Util.sortOn (uncurry (prioritize prios modulePath)) candidates+ Util.head $ Util.sortOn (uncurry (prioritize prios modulePath)) $+ -- Don't pick myself!+ filter ((/= Types.pathToModule modulePath) . snd) candidates prioritize :: Priorities -> FilePath -> Maybe String -> Types.ModuleName- -> ((Int, Int), (Int, Int))+ -> ((Int, Int), (Int, Int), String) prioritize prios modulePath mbPackage mod =- (packagePrio (prioPackage prios) mbPackage,- (modulePrio (prioModule prios) mod, dots mod))+ ( packagePrio (prioPackage prios) mbPackage+ , (modulePrio (prioModule prios) mod, dots mod)+ , Types.moduleName mod+ ) where packagePrio _ Nothing = (localPrio modulePath mod, 0) packagePrio (high, low) (Just pack) = (1, searchPrio high low pack)
src/FixImports.hs view
@@ -178,8 +178,7 @@ -- TODO actually, only load it if I don't find local imports -- I guess Data.Binary's laziness will serve me there index <- if Set.null newImports then return Index.empty else Index.loadIndex- mbNew <- mapM (mkImportLine config modulePath index)- (Set.toList newImports)+ mbNew <- mapM (mkImportLine config modulePath index) (Set.toList newImports) mbExisting <- mapM (findImport (Config.configIncludes config)) imports let existing = map (Types.importDeclModule . fst) imports let (notFound, importLines) = Either.partitionEithers $@@ -266,7 +265,7 @@ then concat <$> mapM (findFiles (depth-1) file) (filter isModuleDir subdirs) else return []- return $ filter (file `List.isSuffixOf`) fns ++ subfns+ return $ filter ((==file) . FilePath.takeFileName) fns ++ subfns where isModuleDir = all Char.isUpper . take 1 . FilePath.takeFileName @@ -306,22 +305,18 @@ importInfo :: Types.Module -> [Haskell.Comment] -> (Set.Set Types.Qualification, Set.Set Types.ModuleName, [(Types.ImportDecl, [Types.Comment])], (Int, Int))- -- ^ (newModules, unusedModules, moduleToImport, rangeOfImportBlock).-importInfo mod cmts = (missing, redundantModules, declCmts, range)+ -- ^ (missingImports, removedModules, moduleToImport, rangeOfImportBlock).+importInfo mod cmts = (missing, removed, declCmts, range) where- redundant = Set.difference imported used+ removed = Set.difference (Set.fromList modules)+ (Set.fromList (map (Types.importDeclModule . fst) declCmts)) missing = Set.difference used imported- imported = Set.fromList (Maybe.catMaybes quals)+ imported = Set.fromList quals -- Get from the qualified import name back to the actual module name so -- I can return that. modules = map Types.importDeclModule imports quals = map Types.importDeclQualification imports- qualToModule =- Map.fromList [(qual, mod) | (Just qual, mod) <- zip quals modules]- redundantModules = Set.fromList $ Maybe.catMaybes- [Map.lookup qual qualToModule | qual <- Set.toList redundant]- used = Set.fromList (moduleQNames mod) imports = moduleImportDecls mod declCmts =@@ -330,7 +325,8 @@ , keepImport decl ] -- Keep unqualified imports, but only keep qualified ones if they are used.- keepImport = maybe True (`Set.member` used) . Types.importDeclQualification+ keepImport decl = Set.member (Types.importDeclQualification decl) used+ || not (Haskell.importQualified decl) range = importRange mod filterImportCmts :: (Int, Int) -> [Haskell.Comment] -> [Haskell.Comment]
src/Types.hs view
@@ -35,14 +35,10 @@ moduleToPath (ModuleName name) = map (\c -> if c == '.' then '/' else c) name ++ ".hs" ---- | Get the qualified name from a qualified import, if it is a qualified--- import.-importDeclQualification :: ImportDecl -> Maybe Qualification-importDeclQualification decl- | Haskell.importQualified decl = Just $ moduleToQualification $- maybe (Haskell.importModule decl) id (Haskell.importAs decl)- | otherwise = Nothing+-- | Get the qualified name from an import.+importDeclQualification :: ImportDecl -> Qualification+importDeclQualification decl = moduleToQualification $+ maybe (Haskell.importModule decl) id (Haskell.importAs decl) -- | Extract the ModuleName from an ImportDecl. importDeclModule :: ImportDecl -> ModuleName