packages feed

hsimport 0.9.0 → 0.10.0

raw patch · 18 files changed

+358/−37 lines, 18 filesdep ~attoparsecdep ~basedep ~cmdargsPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: attoparsec, base, cmdargs, directory, dyre, haskell-src-exts, ilist, microlens, mtl, split, text

API changes (from Hackage documentation)

Files

CHANGELOG view
@@ -1,3 +1,7 @@+0.10.0+------+* Ensure that no imports are placed inbetween cpp directives+ 0.9.0 ----- * Support haddock comments
hsimport.cabal view
@@ -1,13 +1,13 @@-cabal-version: >=1.9.2+cabal-version: 2.0 name: hsimport-version: 0.9.0+version: 0.10.0 license: BSD3 license-file: LICENSE maintainer: daniel.trstenjak@gmail.com author: Daniel Trstenjak tested-with: ghc ==7.6.2 ghc ==7.6.3 ghc ==7.8.3 ghc ==7.10.1              ghc ==7.10.2 ghc ==8.0.1 ghc ==8.2.1 ghc ==8.4.2 ghc ==8.6.3-synopsis: A command line program for extending the import list of a Haskell source file.+synopsis: Extend the import list of a Haskell source file description:     A command line program for extending the import list of a Haskell source file. category: Utils, Development@@ -37,11 +37,12 @@         HsImport.ModuleImport         HsImport.SymbolImport         HsImport.ImportChange-        HsImport.Parse         HsImport.PrettyPrint         HsImport.Utils         HsImport.Types+        HsImport.Parse         Paths_hsimport+    default-language: Haskell2010     ghc-options: -W     build-depends:         base >=3 && <5,@@ -56,20 +57,56 @@         directory >=1.2.0.1 && <1.4,         dyre ==0.8.* +library library-internal+    exposed-modules:+        HsImport+        HsImport.Main+        HsImport.Config+        HsImport.Args+        HsImport.ImportPos+        HsImport.HsImportSpec+        HsImport.ModuleImport+        HsImport.SymbolImport+        HsImport.ImportChange+        HsImport.PrettyPrint+        HsImport.Utils+        HsImport.Types+        HsImport.Parse+        Paths_hsimport+    autogen-modules:+        Paths_hsimport+    cpp-options: -DCABAL+    hs-source-dirs: lib+    default-language: Haskell2010+    ghc-options: -W+    build-depends:+        base -any,+        cmdargs -any,+        haskell-src-exts -any,+        ilist -any,+        microlens -any,+        mtl -any,+        text -any,+        split -any,+        attoparsec -any,+        directory -any,+        dyre -any+ executable hsimport     main-is: Main.hs     cpp-options: -DCABAL     hs-source-dirs: exe+    default-language: Haskell2010     ghc-options: -W-    ghc-prof-options: -fprof-auto -rtsopts     build-depends:         base >=3 && <5,         hsimport -any -test-suite hsimport-tests+test-suite tests     type: exitcode-stdio-1.0     main-is: Main.hs     hs-source-dirs: tests+    default-language: Haskell2010     ghc-options: -W     build-depends:         base >=3 && <5,@@ -77,4 +114,4 @@         tasty-golden >=2.2.0.1 && <2.4,         filepath >=1.3.0.1 && <1.5,         haskell-src-exts >=1.18.0 && <1.22,-        hsimport -any+        library-internal -any
lib/HsImport/HsImportSpec.hs view
@@ -29,7 +29,7 @@    | otherwise = do       result <- parseFile $ Args.inputSrcFile args       case result of-           Right (HS.ParseOk hsModule) -> return $ Right $+           Right (ParseResult (HS.ParseOk hsModule) _) -> return $ Right $               HsImportSpec { sourceFile    = Args.inputSrcFile args                            , parsedSrcFile = hsModule                            , moduleImport  = module_@@ -37,7 +37,7 @@                            , saveToFile    = saveToFile                            } -           Right (HS.ParseFailed srcLoc error) -> return $ Left (show srcLoc ++ error)+           Right (ParseResult (HS.ParseFailed srcLoc error) _) -> return $ Left (show srcLoc ++ error)             Left error -> return $ Left error 
lib/HsImport/Parse.hs view
@@ -2,11 +2,11 @@  module HsImport.Parse    ( parseFile+   , replaceCpp    ) where  import qualified Data.Text.IO as TIO import qualified Data.Text as T-import Data.Maybe (fromMaybe) import Data.List (isPrefixOf) import qualified Language.Haskell.Exts as HS import Control.Exception (catch, SomeException)@@ -19,53 +19,70 @@  parseFile :: FilePath -> IO (Either Error ParseResult) parseFile file = do-   srcFile <- unlines. replaceCPPByEmptyLine . lines . T.unpack <$> TIO.readFile file+   srcFile <- replaceCpp . T.unpack <$> TIO.readFile file    catch (do let result = parseFileContents srcFile              case result of-                  HS.ParseOk _ -> return $ Right result+                  HS.ParseOk _ -> return . Right $ ParseResult result Nothing                    HS.ParseFailed srcLoc _ -> do                      srcResult <- parseInvalidSource (lines srcFile) (HS.srcLine srcLoc)-                     return $ Right $ fromMaybe result srcResult)+                     return $ case srcResult of+                                   Just srcRes -> Right srcRes+                                   Nothing -> Right $ ParseResult result Nothing)           (\(e :: SomeException) -> do             let srcLines = lines srcFile             srcResult <- parseInvalidSource srcLines (length srcLines)             return $ maybe (Left $ show e) Right srcResult)+++-- | replace the complete cpp directive, from #ifdef till #endif, by empty lines+replaceCpp :: String -> String+replaceCpp contents = unlines . reverse $ go (lines contents) [] 0    where-      -- | replace CPP directives by an empty line-      replaceCPPByEmptyLine = map $ \line ->-         if "#" `isPrefixOf` line-            then ""-            else line+      go [] newLines _ = newLines+      go lines newLines ifdefLevel = go lines' newLines' ifdefLevel'+         where+            currLine    = head lines+            hasCpp      = "#" `isPrefixOf` currLine+            hasIf       = "#if" `isPrefixOf` currLine+            hasEndIf    = "#endif" `isPrefixOf` currLine+            ifdefLevel' = ifdefLevel + (if hasIf then 1 else 0) - (if hasEndIf then 1 else 0)+            lines'      = tail lines+            inCpp       = hasCpp || (max ifdefLevel ifdefLevel') > 0+            newLines'   = (if inCpp then "" else currLine) : newLines  +type HsParseResult = HS.ParseResult Module++ -- | tries to find the maximal part of the source file (from the beginning) that contains --   valid/complete Haskell code parseInvalidSource :: [String] -> Int -> IO (Maybe ParseResult) parseInvalidSource srcLines firstInvalidLine = do    parseInvalidSource' 1 firstInvalidLine Nothing 0    where-      parseInvalidSource' :: Int -> Int -> Maybe (Int, ParseResult) -> Int -> IO (Maybe ParseResult)+      parseInvalidSource' :: Int -> Int -> Maybe (Int, HsParseResult) -> Int -> IO (Maybe ParseResult)       parseInvalidSource' lastValidLine currLastLine maxParseOk iteration          | null srcLines || lastValidLine >= currLastLine          = return Nothing           | iteration >= 10-         = return (snd <$> maxParseOk)+         = return $ case maxParseOk of+                         Just (lastLine, result) -> Just $ ParseResult result (Just lastLine)+                         Nothing -> Nothing           | otherwise = do             catch (case parseFileContents source of                         result@(HS.ParseOk _)-                           | nextLine == currLastLine ->-                              return $ Just result-                           | otherwise                ->-                              parseInvalidSource' nextLine currLastLine (maxParseOk' result) iteration'+                           | nextLine == currLastLine -> return . Just $ ParseResult result (Just lastValidLine)+                           | otherwise -> parseInvalidSource' nextLine currLastLine (maxParseOk' result) iteration'                          HS.ParseFailed srcLoc _                            | HS.srcLine srcLoc == firstInvalidLine ->                               parseInvalidSource' lastValidLine nextLine maxParseOk iteration'-                           | otherwise                             ->++                           | otherwise ->                               parseInvalidSource' nextLine currLastLine maxParseOk iteration')                    (\(_ :: SomeException) -> parseInvalidSource' lastValidLine nextLine maxParseOk iteration')@@ -83,7 +100,7 @@                     _ -> Just (nextLine, nextResult)  -parseFileContents :: String -> ParseResult+parseFileContents :: String -> HsParseResult parseFileContents contents =    let result = HS.parseFileContentsWithComments parseMode contents        in case result of
lib/HsImport/Types.hs view
@@ -14,8 +14,17 @@ type Name        = HS.Name Annotation type Module      = HS.Module Annotation type ModuleName  = String-type ParseResult = HS.ParseResult Module type Error       = String++data ParseResult = ParseResult+   { -- | the parse result+     result :: HS.ParseResult Module++     -- | if the source file isn't completely parsable, because e.g.+     --   it contains incomplete Haskell code, then 'lastValidLine'+     --   contains the last line till the source is parsable+   , lastValidLine :: Maybe Int+   }  firstSrcLine :: Annotation -> SrcLine firstSrcLine = minimum . map HS.srcSpanStartLine . srcSpans
tests/Main.hs view
@@ -8,11 +8,13 @@ import Data.List (intercalate) import qualified Language.Haskell.Exts as HS import qualified HsImport as HI+import qualified HsImport.Parse as HIP+import HsImport.Types  main = defaultMain tests  tests :: TestTree-tests = testGroup "Tests" [moduleTests, symbolTests]+tests = testGroup "Tests" [moduleTests, symbolTests, replaceCppTests, parseTests]  moduleTests :: TestTree moduleTests = testGroup "Module Tests"@@ -43,16 +45,17 @@    , test "ModuleTest24" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.qualifiedName = "CM" }    , test "ModuleTest25" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.qualifiedName = "Control.Monad" }    , test "ModuleTest26" $ HI.defaultArgs { HI.moduleName = "Control.Monad" }-   , test_ "ModuleTest27" (HI.defaultConfig { HI.findImportPos = importPosBeforeFirst }) (HI.defaultArgs { HI.moduleName = "Control.Monad" })-   , test_ "ModuleTest28" (HI.defaultConfig { HI.findImportPos = importPosAfterFirst }) (HI.defaultArgs { HI.moduleName = "Control.Monad" })-   , test_ "ModuleTest29" (HI.defaultConfig { HI.findImportPos = importPosBeforeLast }) (HI.defaultArgs { HI.moduleName = "Control.Monad" })-   , test_ "ModuleTest30" (HI.defaultConfig { HI.findImportPos = importPosAfterLast }) (HI.defaultArgs { HI.moduleName = "Control.Monad" })+   , configTest "ModuleTest27" (HI.defaultConfig { HI.findImportPos = importPosBeforeFirst }) (HI.defaultArgs { HI.moduleName = "Control.Monad" })+   , configTest "ModuleTest28" (HI.defaultConfig { HI.findImportPos = importPosAfterFirst }) (HI.defaultArgs { HI.moduleName = "Control.Monad" })+   , configTest "ModuleTest29" (HI.defaultConfig { HI.findImportPos = importPosBeforeLast }) (HI.defaultArgs { HI.moduleName = "Control.Monad" })+   , configTest "ModuleTest30" (HI.defaultConfig { HI.findImportPos = importPosAfterLast }) (HI.defaultArgs { HI.moduleName = "Control.Monad" })    , test "ModuleTest31" $ HI.defaultArgs { HI.moduleName = "Control.Monad", HI.as = "CM" }    , test "ModuleTest32" $ HI.defaultArgs { HI.moduleName = "Control.Monad" }    , test "ModuleTest33" $ HI.defaultArgs { HI.moduleName = "Control.Monad" }    , test "ModuleTest34" $ HI.defaultArgs { HI.moduleName = "Control.Monad" }    , test "ModuleTest35" $ HI.defaultArgs { HI.moduleName = "Control.Monad" }    , test "ModuleTest36" $ HI.defaultArgs { HI.moduleName = "Control.Monad" }+   , test "ModuleTest37" $ HI.defaultArgs { HI.moduleName = "Control.Monad" }    ]  @@ -87,19 +90,34 @@    , test "SymbolTest26" $ HI.defaultArgs { HI.moduleName = "Foo", HI.symbolName = "bar" }    , test "SymbolTest27" $ HI.defaultArgs { HI.moduleName = "Ugah.Blub", HI.symbolName = "g" }    , test "SymbolTest28" $ HI.defaultArgs { HI.moduleName = "Ugah.Blub", HI.symbolName = "d" }-   , test_ "SymbolTest29" (HI.defaultConfig { HI.prettyPrint = prettyPrint }) (HI.defaultArgs { HI.moduleName = "X.Y", HI.symbolName = "x" })-   , test_ "SymbolTest30" (HI.defaultConfig { HI.prettyPrint = prettyPrint }) (HI.defaultArgs { HI.moduleName = "X.Y", HI.symbolName = "x" })+   , configTest "SymbolTest29" (HI.defaultConfig { HI.prettyPrint = prettyPrint }) (HI.defaultArgs { HI.moduleName = "X.Y", HI.symbolName = "x" })+   , configTest "SymbolTest30" (HI.defaultConfig { HI.prettyPrint = prettyPrint }) (HI.defaultArgs { HI.moduleName = "X.Y", HI.symbolName = "x" })    , test "SymbolTest31" $ HI.defaultArgs { HI.moduleName = "Ugah.Blub", HI.symbolName = "d" }    , test "SymbolTest32" $ HI.defaultArgs { HI.moduleName = "Control.Foo", HI.symbolName = "foo" }    ]  +replaceCppTests :: TestTree+replaceCppTests = testGroup "ReplaceCpp Tests"+   [ replaceCppTest "ReplaceCppTest1"+   , replaceCppTest "ReplaceCppTest2"+   , replaceCppTest "ReplaceCppTest3"+   ]+++parseTests :: TestTree+parseTests = testGroup "Parse Tests"+   [ parseTest "ParseTest1"+   , parseTest "ParseTest2"+   ]++ test :: String -> HI.HsImportArgs -> TestTree-test testName args = test_ testName HI.defaultConfig args+test testName args = configTest testName HI.defaultConfig args  -test_ :: String -> HI.Config -> HI.HsImportArgs -> TestTree-test_ testName config args =+configTest :: String -> HI.Config -> HI.HsImportArgs -> TestTree+configTest testName config args =    goldenVsFileDiff testName diff goldenFile outputFile command    where       command = do@@ -107,6 +125,39 @@          case maybeErr of               Just err -> hPutStrLn stderr ("hsimport: " ++ err)               _        -> return ()++      diff ref new = ["diff", "-u", ref, new]++      goldenFile = "tests" </> "goldenFiles" </> testName <.> "hs"+      outputFile = "tests" </> "outputFiles" </> testName <.> "hs"+      inputFile  = "tests" </> "inputFiles"  </> testName <.> "hs"+++replaceCppTest :: String -> TestTree+replaceCppTest testName =+   goldenVsFileDiff testName diff goldenFile outputFile command+   where+      command = do+         contents <- readFile inputFile+         writeFile outputFile $ HIP.replaceCpp contents++      diff ref new = ["diff", "-u", ref, new]++      goldenFile = "tests" </> "goldenFiles" </> testName <.> "hs"+      outputFile = "tests" </> "outputFiles" </> testName <.> "hs"+      inputFile  = "tests" </> "inputFiles"  </> testName <.> "hs"+++parseTest :: String -> TestTree+parseTest testName =+   goldenVsFileDiff testName diff goldenFile outputFile command+   where+      command = do+         Right (ParseResult (HS.ParseOk _) lastValidLine) <- HIP.parseFile inputFile+         contents <- readFile inputFile+         case lastValidLine of+              Just line -> writeFile outputFile $ unlines . take line . lines $ contents+              Nothing -> writeFile outputFile contents        diff ref new = ["diff", "-u", ref, new] 
+ tests/goldenFiles/ModuleTest37.hs view
@@ -0,0 +1,22 @@+{-# Language PatternGuards #-}+module Blub+   ( blub+   , foo+   , bar+   ) where+#include "Foo.h"+#ifdef FOO+import Control.Applicative+#endif++import Control.BiFunctor+import Control.Monad++f :: Int -> Int+-- ^ Some Haddock doc+--   One line more+f = (+ 3)++g :: Int -> Int+g =+   where
+ tests/goldenFiles/ParseTest1.hs view
@@ -0,0 +1,16 @@+{-# Language PatternGuards #-}+module Blub+   ( blub+   , foo+   , bar+   ) where+#include "Foo.h"+import Ugah.Foo+import Control.Applicative+#ifdef FOO+import Ugah.Blub+#endif+f :: Int -> Int+f = (+ 3)++g :: Int -> Int
+ tests/goldenFiles/ParseTest2.hs view
@@ -0,0 +1,12 @@+{-# Language PatternGuards #-}+module Blub+   ( f+   ) where+#include "Foo.h"+import Ugah.Foo+import Control.Applicative+#ifdef FOO+import Ugah.Blub+#endif+f :: Int -> Int+f i = i + 3
+ tests/goldenFiles/ReplaceCppTest1.hs view
@@ -0,0 +1,18 @@+{-# Language PatternGuards #-}+module Blub+   ( blub+   , foo+   , bar+   ) where++import Ugah.Foo+import Control.Applicative++++f :: Int -> Int+f = (+ 3)++g :: Int -> Int+g =+   where
+ tests/goldenFiles/ReplaceCppTest2.hs view
@@ -0,0 +1,21 @@+{-# Language PatternGuards #-}+module Blub+   ( blub+   , foo+   , bar+   ) where++import Ugah.Foo+import Control.Applicative+++++++f :: Int -> Int+f = (+ 3)++g :: Int -> Int+g =+   where
+ tests/goldenFiles/ReplaceCppTest3.hs view
@@ -0,0 +1,12 @@+{-# Language PatternGuards #-}+module Blub+   ( f+   ) where++import Ugah.Foo+import Control.Applicative++++f :: Int -> Int+f i = i + 3
+ tests/inputFiles/ModuleTest37.hs view
@@ -0,0 +1,21 @@+{-# Language PatternGuards #-}+module Blub+   ( blub+   , foo+   , bar+   ) where+#include "Foo.h"+#ifdef FOO+import Control.Applicative+#endif++import Control.BiFunctor++f :: Int -> Int+-- ^ Some Haddock doc+--   One line more+f = (+ 3)++g :: Int -> Int+g =+   where
+ tests/inputFiles/ParseTest1.hs view
@@ -0,0 +1,18 @@+{-# Language PatternGuards #-}+module Blub+   ( blub+   , foo+   , bar+   ) where+#include "Foo.h"+import Ugah.Foo+import Control.Applicative+#ifdef FOO+import Ugah.Blub+#endif+f :: Int -> Int+f = (+ 3)++g :: Int -> Int+g =+   where
+ tests/inputFiles/ParseTest2.hs view
@@ -0,0 +1,12 @@+{-# Language PatternGuards #-}+module Blub+   ( f+   ) where+#include "Foo.h"+import Ugah.Foo+import Control.Applicative+#ifdef FOO+import Ugah.Blub+#endif+f :: Int -> Int+f i = i + 3
+ tests/inputFiles/ReplaceCppTest1.hs view
@@ -0,0 +1,18 @@+{-# Language PatternGuards #-}+module Blub+   ( blub+   , foo+   , bar+   ) where+#include "Foo.h"+import Ugah.Foo+import Control.Applicative+#ifdef FOO+import Ugah.Blub+#endif+f :: Int -> Int+f = (+ 3)++g :: Int -> Int+g =+   where
+ tests/inputFiles/ReplaceCppTest2.hs view
@@ -0,0 +1,21 @@+{-# Language PatternGuards #-}+module Blub+   ( blub+   , foo+   , bar+   ) where+#include "Foo.h"+import Ugah.Foo+import Control.Applicative+#ifdef FOO+import Ugah.Blub+#ifdef GOO+import Ugah.Blub+#endif+#endif+f :: Int -> Int+f = (+ 3)++g :: Int -> Int+g =+   where
+ tests/inputFiles/ReplaceCppTest3.hs view
@@ -0,0 +1,12 @@+{-# Language PatternGuards #-}+module Blub+   ( f+   ) where+#include "Foo.h"+import Ugah.Foo+import Control.Applicative+#ifdef FOO+import Ugah.Blub+#endif+f :: Int -> Int+f i = i + 3