fix-imports 1.0.1 → 1.0.2
raw patch · 4 files changed
+50/−30 lines, 4 filesdep ~haskell-src-exts
Dependency ranges changed: haskell-src-exts
Files
- fix-imports.cabal +6/−2
- src/Config.hs +4/−4
- src/FixImports.hs +28/−17
- src/Main.hs +12/−7
fix-imports.cabal view
@@ -1,5 +1,5 @@ name: fix-imports-version: 1.0.1+version: 1.0.2 cabal-version: >= 1.6 build-type: Simple synopsis: Program to manage the imports of a haskell module@@ -13,7 +13,11 @@ It's most convenient if bound to an editor key. . Recent major changes:+ * version 1.0.2 .+ * Fix bug where a qualified import with >1 dot wasn't found. And don't+ mess with Prelude.+ . * version 1.0.1 . * Fix a bunch of bugs: properly recognize unqualified imports as imports,@@ -53,5 +57,5 @@ main-is: Main.hs hs-source-dirs: src build-depends: base >= 3 && < 5, containers, directory, filepath, process,- haskell-src-exts >= 1.11, uniplate, split, cpphs, text+ haskell-src-exts >= 1.13.2, uniplate, split, cpphs, text ghc-options: -Wall -fno-warn-name-shadowing
src/Config.hs view
@@ -15,7 +15,7 @@ data Config = Config { -- | Additional directories to search for local modules. Taken from the- -- -i flag.+ -- -i flag and 'include' config line. configIncludes :: [FilePath] -- | Format the import block. , configShowImports :: [Types.ImportLine] -> String@@ -25,9 +25,9 @@ -> Maybe (Maybe Index.Package, Types.ModuleName) } -config :: ImportOrder -> Priorities -> Config-config order prios = Config- { configIncludes = []+config :: [FilePath] -> ImportOrder -> Priorities -> Config+config include order prios = Config+ { configIncludes = include , configShowImports = formatGroups order , configPickModule = pickModule prios }
src/FixImports.hs view
@@ -51,7 +51,9 @@ import qualified Data.Set as Set import qualified Language.Haskell.Exts.Annotated as Haskell+import qualified Language.Haskell.Exts.Extension as Extension import qualified Language.Preprocessor.Cpphs as Cpphs+ import qualified System.Console.GetOpt as GetOpt import qualified System.Directory as Directory import qualified System.Environment@@ -75,8 +77,9 @@ (modulePath, (verbose, includes)) <- parseArgs =<< System.Environment.getArgs text <- IO.getContents- fixed <- fixModule (config { Config.configIncludes = includes })- modulePath text+ config <- return $ config+ { Config.configIncludes = includes ++ Config.configIncludes config }+ fixed <- fixModule config modulePath text `Exception.catch` (\(exc :: Exception.SomeException) -> return $ Left $ "exception: " ++ show exc) case fixed of@@ -86,15 +89,14 @@ System.Exit.exitFailure Right (Result text added removed) -> do IO.putStr text- when (verbose- && (not (Set.null added) || not (Set.null removed))) $- IO.hPutStrLn IO.stderr $ "added: " ++ names added- ++ "; removed: " ++ names removed+ let names = Util.join ", " . map Types.moduleName . Set.toList+ (addedMsg, removedMsg) = (names added, names removed)+ when (verbose && (not (null addedMsg) || not (null removedMsg))) $+ IO.hPutStrLn IO.stderr $ Util.join "; " $ filter (not . null)+ [ if null addedMsg then "" else "added: " ++ addedMsg+ , if null removedMsg then "" else "removed: " ++ removedMsg+ ] System.Exit.exitSuccess- where- names xs- | Set.null xs = "[]"- | otherwise = (Util.join ", " . map Types.moduleName . Set.toList) xs data Flag = Verbose | Include String deriving (Eq, Show)@@ -141,6 +143,7 @@ parse = Haskell.parseFileContentsWithComments $ Haskell.defaultParseMode { Haskell.parseFilename = modulePath+ , Haskell.extensions = Extension.haskell2010 -- The meaning of Nothing is undocumented, but I think it means -- to not check for fixity ambiguity at all, which is what I want. , Haskell.fixities = Nothing@@ -265,9 +268,10 @@ then concat <$> mapM (findFiles (depth-1) file) (filter isModuleDir subdirs) else return []- return $ filter ((==file) . FilePath.takeFileName) fns ++ subfns+ return $ filter sameSuffix fns ++ subfns where isModuleDir = all Char.isUpper . take 1 . FilePath.takeFileName+ sameSuffix fn = fn == file || ('/' : file) `List.isSuffixOf` fn -- * figure out existing imports@@ -305,18 +309,20 @@ importInfo :: Types.Module -> [Haskell.Comment] -> (Set.Set Types.Qualification, Set.Set Types.ModuleName, [(Types.ImportDecl, [Types.Comment])], (Int, Int))- -- ^ (missingImports, removedModules, moduleToImport, rangeOfImportBlock).-importInfo mod cmts = (missing, removed, declCmts, range)+ -- ^ (missingImports, unusedImports, unchangedImports, rangeOfImportBlock).+importInfo mod cmts = (missing, unused, declCmts, range) where- removed = Set.difference (Set.fromList modules)+ unused = Set.difference (Set.fromList modules) (Set.fromList (map (Types.importDeclModule . fst) declCmts)) missing = Set.difference used imported- imported = Set.fromList quals+ -- If the Prelude isn't explicitly imported, it's implicitly imported, so+ -- if I see Prelude.x it doesn't mean to add an import.+ imported = Set.fromList $ prelude : qualifiedImports -- 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+ qualifiedImports = map Types.importDeclQualification imports used = Set.fromList (moduleQNames mod) imports = moduleImportDecls mod declCmts =@@ -325,8 +331,13 @@ , keepImport decl ] -- Keep unqualified imports, but only keep qualified ones if they are used.- keepImport decl = Set.member (Types.importDeclQualification decl) used+ -- Prelude is considered always used if it appears, because removing it+ -- changes import behavour.+ keepImport decl =+ Set.member (Types.importDeclQualification decl)+ (Set.insert prelude used) || not (Haskell.importQualified decl)+ prelude = Types.Qualification "Prelude" range = importRange mod filterImportCmts :: (Int, Int) -> [Haskell.Comment] -> [Haskell.Comment]
src/Main.hs view
@@ -20,21 +20,26 @@ main :: IO () main = do- let deflt = (Config.ImportOrder [], Config.defaultPriorities, [])- (order, prios, warns) <- fmap (maybe deflt parse) $+ let deflt = ([], Config.ImportOrder [], Config.defaultPriorities, [])+ (include, order, prios, warns) <- fmap (maybe deflt parse) $ Util.catchENOENT $ Text.IO.readFile ".fix-imports" unless (null warns) $ IO.hPutStrLn IO.stderr $ "warnings unrecognized fields in .fix-imports: " ++ List.intercalate ", " warns- FixImports.runMain (Config.config order prios)+ FixImports.runMain (Config.config include order prios) -parse :: Text.Text -> (Config.ImportOrder, Config.Priorities, [String])-parse text = (order, prios, extra)+parse :: Text.Text+ -> ([FilePath], Config.ImportOrder, Config.Priorities, [String])+parse text = (include, order, prios, extra) where extra = Map.keys config List.\\ valid- valid = ["import-order", "prio-package-high", "prio-package-low",- "prio-module-high", "prio-module-low"]+ valid =+ [ "include", "import-order"+ , "prio-package-high", "prio-package-low"+ , "prio-module-high", "prio-module-low"+ ]+ include = get "include" order = Config.ImportOrder (getModules "import-order") prios = Config.Priorities (get "prio-package-high", get "prio-package-low") (getModules "prio-module-high", getModules "prio-module-low")