From 096a56e660af01852e1505be04577fbdbfc1c44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Sat, 3 May 2014 16:16:50 +0200 Subject: [PATCH 1/8] Hide `catch` from Prelude --- Language/Haskell/GhcMod/CabalApi.hs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Language/Haskell/GhcMod/CabalApi.hs b/Language/Haskell/GhcMod/CabalApi.hs index 50b6759..322f3fd 100644 --- a/Language/Haskell/GhcMod/CabalApi.hs +++ b/Language/Haskell/GhcMod/CabalApi.hs @@ -12,6 +12,8 @@ module Language.Haskell.GhcMod.CabalApi ( , cabalConfigDependencies ) where +import Prelude hiding (catch) + import Language.Haskell.GhcMod.Types import Language.Haskell.GhcMod.GhcPkg import Language.Haskell.GhcMod.Utils From c50b4f5a384caafae3f60413a405fb396a8b3a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Sat, 3 May 2014 16:08:28 +0200 Subject: [PATCH 2/8] ghc-mod deserves it's own monad Having to call `findCradle` and `initializeFlagsWithCradle` everywhere we interact with ghc-mod's API doesn't seem very Haskell-like to me I think we should provide a Monad that has a run function that already does all those tedious tasks for us. The `GhcMod` monad is basically a wrapper around `RWST r w s IO` with an instance for `GhcMonad` Having a `Reader` allows us to pass `Options` to runGhcMod and not have to worry about passing it everywhere, `Cradle` is also stored in the reader environment on initialization. Writer and State are just there for future use. I've included a `toGhcMod` function that turns a `Ghc a` into a `GhcMod a` this will make it easy to transition everyting to using the `GhcMod` monad instead of `Ghc` without breaking the build or test suite for extended periods of time. Conflicts: ghc-mod.cabal --- Language/Haskell/GhcMod/Monad.hs | 110 +++++++++++++++++++++++++++++++ ghc-mod.cabal | 9 +++ 2 files changed, 119 insertions(+) create mode 100644 Language/Haskell/GhcMod/Monad.hs diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs new file mode 100644 index 0000000..82c3806 --- /dev/null +++ b/Language/Haskell/GhcMod/Monad.hs @@ -0,0 +1,110 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses, RankNTypes, TypeFamilies #-} +module Language.Haskell.GhcMod.Monad ( + GhcMod + , GhcModEnv(..) + , GhcModWriter + , GhcModState(..) + , runGhcMod' + , runGhcMod + , toGhcMod + , module Control.Monad.Reader.Class + , module Control.Monad.Writer.Class + , module Control.Monad.State.Class + ) where + +import Language.Haskell.GhcMod.Types +import Language.Haskell.GhcMod.Cradle +import Language.Haskell.GhcMod.GHCApi + +import GHC +import GHC.Paths (libdir) +import GhcMonad +import Exception +import MonadUtils +import DynFlags + +import Data.IORef (IORef, readIORef, writeIORef, newIORef) + +import Control.Monad (liftM) +import Control.Monad.Base (MonadBase,liftBase) +import Control.Monad.Trans.RWS.Lazy (RWST,runRWST) +import Control.Monad.Trans.Control (MonadBaseControl(..), StM, liftBaseWith + , control, liftBaseOp, liftBaseOp_) +import Control.Monad.Reader.Class +import Control.Monad.Writer.Class +import Control.Monad.State.Class + +data GhcModEnv = GhcModEnv { + gmGhcSession :: !(IORef HscEnv) + , gmOptions :: Options + , gmCradle :: Cradle + } + +data GhcModState = GhcModState + +defaultState :: GhcModState +defaultState = GhcModState + +type GhcModWriter = () + +newtype GhcMod a = GhcMod { + unGhcMod :: RWST GhcModEnv GhcModWriter GhcModState IO a } + deriving (Functor, + Applicative, + Monad, + MonadIO, + MonadReader GhcModEnv, + MonadWriter GhcModWriter, + MonadState GhcModState) + +runGhcMod' :: GhcModEnv + -> GhcModState + -> GhcMod a + -> IO (a,(GhcModState, GhcModWriter)) +runGhcMod' r s a = do + (a', s',w) <- runRWST (unGhcMod $ initGhcMonad (Just libdir) >> a) r s + return (a',(s',w)) + +runGhcMod :: Options -> GhcMod a -> IO a +runGhcMod opt a = do + session <- newIORef (error "empty session") + cradle <- findCradle + let env = GhcModEnv { gmGhcSession = session + , gmOptions = opt + , gmCradle = cradle } + fst <$> runGhcMod' env defaultState (a' cradle) + where + a' cradle = (toGhcMod $ initializeFlagsWithCradle opt cradle) >> a + +toGhcMod :: Ghc a -> GhcMod a +toGhcMod a = do + s <- gmGhcSession <$> ask + liftIO $ unGhc a $ Session s + +instance MonadBase IO GhcMod where + liftBase = GhcMod . liftBase + +instance MonadBaseControl IO GhcMod where + newtype StM GhcMod a = StGhcMod { + unStGhcMod :: StM (RWST GhcModEnv () GhcModState IO) a } + + liftBaseWith f = GhcMod . liftBaseWith $ \runInBase -> + f $ liftM StGhcMod . runInBase . unGhcMod + + restoreM = GhcMod . restoreM . unStGhcMod + {-# INLINE liftBaseWith #-} + {-# INLINE restoreM #-} + +instance GhcMonad GhcMod where + getSession = liftIO . readIORef . gmGhcSession =<< ask + setSession a = liftIO . flip writeIORef a . gmGhcSession =<< ask + +instance HasDynFlags GhcMod where + getDynFlags = getSessionDynFlags + +instance ExceptionMonad GhcMod where + gcatch act handler = control $ \run -> + run act `gcatch` (run . handler) + + gmask = liftBaseOp gmask . liftRestore + where liftRestore f r = f $ liftBaseOp_ r diff --git a/ghc-mod.cabal b/ghc-mod.cabal index 7141c4b..509a088 100644 --- a/ghc-mod.cabal +++ b/ghc-mod.cabal @@ -74,12 +74,14 @@ Library Language.Haskell.GhcMod.PkgDoc Language.Haskell.GhcMod.Utils Language.Haskell.GhcMod.Types + Language.Haskell.GhcMod.Monad Build-Depends: base >= 4.0 && < 5 , containers , deepseq , directory , filepath , ghc + , ghc-paths , ghc-syb-utils , hlint >= 1.8.61 , io-choice @@ -88,6 +90,9 @@ Library , syb , time , transformers + , transformers-base + , mtl + , monad-control , split if impl(ghc < 7.7) Build-Depends: convertible @@ -151,6 +156,7 @@ Test-Suite spec , directory , filepath , ghc + , ghc-paths , ghc-syb-utils , hlint >= 1.7.1 , io-choice @@ -159,6 +165,9 @@ Test-Suite spec , syb , time , transformers + , transformers-base + , mtl + , monad-control , hspec >= 1.8.2 , split if impl(ghc < 7.7) From 3b5b9f8fcf9a70dc7fee0965ead4cd7022777731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Sat, 3 May 2014 14:47:33 +0200 Subject: [PATCH 3/8] Expose `Language.Haskell.GhcMod.Monad` --- ghc-mod.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ghc-mod.cabal b/ghc-mod.cabal index 509a088..464353f 100644 --- a/ghc-mod.cabal +++ b/ghc-mod.cabal @@ -52,6 +52,7 @@ Library GHC-Options: -Wall Exposed-Modules: Language.Haskell.GhcMod Language.Haskell.GhcMod.Ghc + Language.Haskell.GhcMod.Monad Language.Haskell.GhcMod.Internal Other-Modules: Language.Haskell.GhcMod.Boot Language.Haskell.GhcMod.Browse @@ -74,7 +75,6 @@ Library Language.Haskell.GhcMod.PkgDoc Language.Haskell.GhcMod.Utils Language.Haskell.GhcMod.Types - Language.Haskell.GhcMod.Monad Build-Depends: base >= 4.0 && < 5 , containers , deepseq From e74faa4a9da45deb863758555e6fe963397403b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Sun, 4 May 2014 04:46:27 +0200 Subject: [PATCH 4/8] Add `add-source-timestamps` to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0c36049..61ecc03 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ dist/ elisp/*.elc *~ /.cabal-sandbox/ +add-source-timestamps package.cache cabal.sandbox.config # Mac OS generates From ea427d60ba3912297dc8fe653a2c08d0c04fcd05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Sun, 4 May 2014 04:46:58 +0200 Subject: [PATCH 5/8] note: MonadIO class --- Language/Haskell/GhcMod/Monad.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index 82c3806..ee7e5b6 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -27,6 +27,7 @@ import Data.IORef (IORef, readIORef, writeIORef, newIORef) import Control.Monad (liftM) import Control.Monad.Base (MonadBase,liftBase) +--import Control.Monad.IO.Class (MonadIO) import Control.Monad.Trans.RWS.Lazy (RWST,runRWST) import Control.Monad.Trans.Control (MonadBaseControl(..), StM, liftBaseWith , control, liftBaseOp, liftBaseOp_) From 635830b527e83f603ec7e1acb3e1cd0631e0cd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Mon, 5 May 2014 00:28:03 +0200 Subject: [PATCH 6/8] Fix #242, ghcPkgList(Ex) on NixOS --- Language/Haskell/GhcMod/GhcPkg.hs | 92 +++++++++++++++++++-------- Language/Haskell/GhcMod/Monad.hs-boot | 16 +++++ test/GhcPkgSpec.hs | 10 ++- 3 files changed, 88 insertions(+), 30 deletions(-) create mode 100644 Language/Haskell/GhcMod/Monad.hs-boot diff --git a/Language/Haskell/GhcMod/GhcPkg.hs b/Language/Haskell/GhcMod/GhcPkg.hs index d63e806..44fde2c 100644 --- a/Language/Haskell/GhcMod/GhcPkg.hs +++ b/Language/Haskell/GhcMod/GhcPkg.hs @@ -12,19 +12,25 @@ module Language.Haskell.GhcMod.GhcPkg ( , getPackageDbStack ) where -import Config (cProjectVersionInt) -- ghc version -import Control.Applicative ((<$>)) +import Config (cProjectVersionInt,cProjectVersion,cTargetPlatformString) +import DynFlags (DynFlags(..), systemPackageConfig,getDynFlags) +import Exception (handleIO) +import CoreMonad (liftIO) +import Control.Applicative ((<$>),(<*>),(<*),(*>)) import Control.Exception (SomeException(..)) +import Control.Monad (void) import qualified Control.Exception as E import Data.Char (isSpace,isAlphaNum) import Data.List (isPrefixOf, intercalate) import Data.List.Split (splitOn) -import Data.Maybe (listToMaybe, maybeToList) +import Data.Maybe (catMaybes) import Distribution.Package (InstalledPackageId(..)) import Language.Haskell.GhcMod.Types import Language.Haskell.GhcMod.Utils +import {-# SOURCE #-} Language.Haskell.GhcMod.Monad import System.FilePath (()) -import Text.ParserCombinators.ReadP (ReadP, char, between, sepBy1, many1, string, choice, eof) +import System.Directory (getAppUserDataDirectory,doesDirectoryExist) +import Text.ParserCombinators.ReadP (ReadP, char, satisfy, between, sepBy1, many1, many, manyTill, skipMany, skipMany1, skipSpaces, string, choice, eof,(+++)) import qualified Text.ParserCombinators.ReadP as P ghcVersion :: Int @@ -59,31 +65,42 @@ getPackageDbStack cdir = (getSandboxDb cdir >>= \db -> return [GlobalDb, PackageDb db]) `E.catch` \(_ :: SomeException) -> return [GlobalDb, UserDb] + + +-- Copied from ghc module `Packages' unfortunately it's not exported :/ +resolvePackageDb :: DynFlags -> GhcPkgDb -> IO (Maybe FilePath) +resolvePackageDb df GlobalDb = return $ Just (systemPackageConfig df) +resolvePackageDb _ UserDb = handleIO (\_ -> return Nothing) $ do + appdir <- getAppUserDataDirectory "ghc" + let dir = appdir (target_os ++ '-':target_arch ++ '-':cProjectVersion) + pkgconf = dir "package.conf.d" + exist <- doesDirectoryExist pkgconf + return $ if exist then Just pkgconf else Nothing + where + [target_arch,_,target_os] = splitOn "-" cTargetPlatformString +resolvePackageDb _ (PackageDb name) = return $ Just name + + -- | List packages in one or more ghc package store -ghcPkgList :: [GhcPkgDb] -> IO [PackageBaseName] +ghcPkgList :: [GhcPkgDb] -> GhcMod [PackageBaseName] ghcPkgList dbs = map fst3 <$> ghcPkgListEx dbs where fst3 (x,_,_) = x -ghcPkgListEx :: [GhcPkgDb] -> IO [Package] +ghcPkgListEx :: [GhcPkgDb] -> GhcMod [Package] ghcPkgListEx dbs = do - parseGhcPkgOutput .lines <$> readProcess' "ghc-pkg" opts - where + df <- getDynFlags + out <- liftIO $ readProcess' "ghc-pkg" opts + rdbs <- catMaybes <$> mapM (liftIO . resolvePackageDb df) dbs + return $ concatMap snd $ filter ((`elem` rdbs) . fst) $ parseGhcPkgOutput out + where opts = ["list", "-v"] ++ ghcPkgDbStackOpts dbs -parseGhcPkgOutput :: [String] -> [Package] -parseGhcPkgOutput [] = [] -parseGhcPkgOutput (l:ls) = - parseGhcPkgOutput ls ++ case l of - [] -> [] - h:_ | isSpace h -> maybeToList $ packageLine l - | otherwise -> [] - -packageLine :: String -> Maybe Package -packageLine l = - case listToMaybe $ P.readP_to_S packageLineP l of - Just ((Normal,p),_) -> Just p - Just ((Hidden,p),_) -> Just p - _ -> Nothing +parseGhcPkgOutput :: String -> [(FilePath, [Package])] +parseGhcPkgOutput p = + case P.readP_to_S ghcPkgOutputP p of + (a, rest):_ | all isSpace rest -> a + res@(a,reset):_ -> error $ "parseGhcPkgOutput: " ++ show a ++ "\nwith rest:```" ++ reset ++ "```\n\nwhole result: " ++ show res + _ -> error $ "parseGhcPkgOutput: failed to parse output!\n\n" ++ p fromInstalledPackageId' :: InstalledPackageId -> Maybe Package fromInstalledPackageId' pid = let @@ -99,21 +116,42 @@ fromInstalledPackageId pid = Nothing -> error $ "fromInstalledPackageId: `"++show pid++"' is not a valid package-id" +ghcPkgOutputP :: ReadP [(FilePath, [Package])] +ghcPkgOutputP = do + dbs <- ghcPkgOutputP' + return $ do + (path, ps) <- dbs + return (path,map snd $ filter ((`elem`[Normal,Hidden]) . fst) ps) + +ghcPkgOutputP' :: ReadP [(FilePath, [(PackageState, Package)])] +ghcPkgOutputP' = do + skipUseCacheLinesP *> (many1 $ (,) <$> pathLineP <*> many1 packageLineP) + where + skipUseCacheLinesP = skipMany $ do + void $ string "using cache:" + void $ manyTill (satisfy $ const True) (char '\n') + +pathLineP :: ReadP FilePath +pathLineP = do + p <- (:) <$> char '/' <*> manyTill (satisfy $ const True) (char ':') + char '\n' + return p + data PackageState = Normal | Hidden | Broken deriving (Eq,Show) packageLineP :: ReadP (PackageState, Package) packageLineP = do - P.skipSpaces + skipSpaces p <- choice [ (Hidden,) <$> between (char '(') (char ')') packageP , (Broken,) <$> between (char '{') (char '}') packageP , (Normal,) <$> packageP ] - eof + char '\n' return p packageP :: ReadP (PackageBaseName, PackageVersion, PackageId) packageP = do pkgSpec@(name,ver) <- packageSpecP - P.skipSpaces + skipSpaces i <- between (char '(') (char ')') $ packageIdSpecP pkgSpec return (name,ver,i) @@ -125,11 +163,11 @@ packageSpecP = do packageIdSpecP :: (PackageBaseName,PackageVersion) -> ReadP PackageId packageIdSpecP (name,ver) = do string name >> char '-' >> string ver >> char '-' >> return () - many1 (P.satisfy isAlphaNum) + many1 (satisfy isAlphaNum) packageCompCharP :: ReadP Char packageCompCharP = - P.satisfy $ \c -> isAlphaNum c || c `elem` "_-." + satisfy $ \c -> isAlphaNum c || c `elem` "_-." -- | Get options needed to add a list of package dbs to ghc-pkg's db stack ghcPkgDbStackOpts :: [GhcPkgDb] -- ^ Package db stack diff --git a/Language/Haskell/GhcMod/Monad.hs-boot b/Language/Haskell/GhcMod/Monad.hs-boot new file mode 100644 index 0000000..5f80fc3 --- /dev/null +++ b/Language/Haskell/GhcMod/Monad.hs-boot @@ -0,0 +1,16 @@ +{-# LANGUAGE RoleAnnotations #-} +module Language.Haskell.GhcMod.Monad where + +import DynFlags (HasDynFlags) +import Control.Monad.IO.Class (MonadIO) +import Control.Applicative (Applicative) + +data GhcMod a +type role GhcMod nominal + +instance Functor GhcMod +instance Applicative GhcMod +instance Monad GhcMod + +instance HasDynFlags GhcMod +instance MonadIO GhcMod diff --git a/test/GhcPkgSpec.hs b/test/GhcPkgSpec.hs index 6e80a03..07f6dea 100644 --- a/test/GhcPkgSpec.hs +++ b/test/GhcPkgSpec.hs @@ -2,6 +2,9 @@ module GhcPkgSpec where import Language.Haskell.GhcMod.Types import Language.Haskell.GhcMod.GhcPkg +import Language.Haskell.GhcMod.Monad + +import CoreMonad (liftIO) import Control.Applicative import System.Directory @@ -22,7 +25,8 @@ spec = do getSandboxDb "test/data/broken-sandbox" `shouldThrow` anyException describe "getPackageDbPackages" $ do - it "find a config file and extracts packages" $ do - sdb <- getSandboxDb "test/data/check-packageid" + it "find a config file and extracts packages" $ + runGhcMod defaultOptions $ do + sdb <- liftIO $ getSandboxDb "test/data/check-packageid" pkgs <- ghcPkgListEx [PackageDb sdb] - pkgs `shouldBe` [("template-haskell","2.8.0.0","32d4f24abdbb6bf41272b183b2e23e9c")] + liftIO $ pkgs `shouldBe` [("template-haskell","2.8.0.0","32d4f24abdbb6bf41272b183b2e23e9c")] From 81504de8bdd74d13d055dee254c543e6079084a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Mon, 5 May 2014 09:26:56 +0200 Subject: [PATCH 7/8] spec: Be more forgiving for ghc opts in `getCompilerOptions` --- test/CabalApiSpec.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/CabalApiSpec.hs b/test/CabalApiSpec.hs index 00e78ab..46b6b8e 100644 --- a/test/CabalApiSpec.hs +++ b/test/CabalApiSpec.hs @@ -37,8 +37,8 @@ spec = do , includeDirs = map (toRelativeDir dir) (includeDirs res) } if ghcVersion < 706 - then ghcOptions res' `shouldBe` ["-global-package-conf", "-no-user-package-conf","-package-conf",cwd "test/data/.cabal-sandbox/i386-osx-ghc-7.6.3-packages.conf.d","-XHaskell98"] - else ghcOptions res' `shouldBe` ["-global-package-db", "-no-user-package-db","-package-db",cwd "test/data/.cabal-sandbox/i386-osx-ghc-7.6.3-packages.conf.d","-XHaskell98","-optP-include","-optP" ++ cwd "test/data/dist/build/autogen/cabal_macros.h"] + then ghcOptions res' `shouldContain` ["-global-package-conf", "-no-user-package-conf","-package-conf",cwd "test/data/.cabal-sandbox/i386-osx-ghc-7.6.3-packages.conf.d","-XHaskell98"] + else ghcOptions res' `shouldContain` ["-global-package-db", "-no-user-package-db","-package-db",cwd "test/data/.cabal-sandbox/i386-osx-ghc-7.6.3-packages.conf.d","-XHaskell98"] includeDirs res' `shouldBe` ["test/data","test/data/dist/build","test/data/dist/build/autogen","test/data/subdir1/subdir2","test/data/test"] (pkgName `map` depPackages res') `shouldContain` ["Cabal"] From 5044cf7f56f67e7c65055dec02afbcd48dbe1527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Mon, 5 May 2014 09:43:14 +0200 Subject: [PATCH 8/8] Fix warnings --- Language/Haskell/GhcMod/CabalApi.hs | 2 ++ Language/Haskell/GhcMod/GhcPkg.hs | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Language/Haskell/GhcMod/CabalApi.hs b/Language/Haskell/GhcMod/CabalApi.hs index 322f3fd..8264a35 100644 --- a/Language/Haskell/GhcMod/CabalApi.hs +++ b/Language/Haskell/GhcMod/CabalApi.hs @@ -12,7 +12,9 @@ module Language.Haskell.GhcMod.CabalApi ( , cabalConfigDependencies ) where +#if MIN_VERSION_base(4,7,0) import Prelude hiding (catch) +#endif import Language.Haskell.GhcMod.Types import Language.Haskell.GhcMod.GhcPkg diff --git a/Language/Haskell/GhcMod/GhcPkg.hs b/Language/Haskell/GhcMod/GhcPkg.hs index 44fde2c..9a6e732 100644 --- a/Language/Haskell/GhcMod/GhcPkg.hs +++ b/Language/Haskell/GhcMod/GhcPkg.hs @@ -16,7 +16,7 @@ import Config (cProjectVersionInt,cProjectVersion,cTargetPlatformString) import DynFlags (DynFlags(..), systemPackageConfig,getDynFlags) import Exception (handleIO) import CoreMonad (liftIO) -import Control.Applicative ((<$>),(<*>),(<*),(*>)) +import Control.Applicative ((<$>),(<*>),(*>)) import Control.Exception (SomeException(..)) import Control.Monad (void) import qualified Control.Exception as E @@ -30,7 +30,7 @@ import Language.Haskell.GhcMod.Utils import {-# SOURCE #-} Language.Haskell.GhcMod.Monad import System.FilePath (()) import System.Directory (getAppUserDataDirectory,doesDirectoryExist) -import Text.ParserCombinators.ReadP (ReadP, char, satisfy, between, sepBy1, many1, many, manyTill, skipMany, skipMany1, skipSpaces, string, choice, eof,(+++)) +import Text.ParserCombinators.ReadP (ReadP, char, satisfy, between, sepBy1, many1, manyTill, skipMany, skipSpaces, string, choice) import qualified Text.ParserCombinators.ReadP as P ghcVersion :: Int @@ -133,9 +133,9 @@ ghcPkgOutputP' = do pathLineP :: ReadP FilePath pathLineP = do - p <- (:) <$> char '/' <*> manyTill (satisfy $ const True) (char ':') - char '\n' - return p + p <- (:) <$> char '/' <*> manyTill (satisfy $ const True) (char ':') + void $ char '\n' + return p data PackageState = Normal | Hidden | Broken deriving (Eq,Show) @@ -145,7 +145,7 @@ packageLineP = do p <- choice [ (Hidden,) <$> between (char '(') (char ')') packageP , (Broken,) <$> between (char '{') (char '}') packageP , (Normal,) <$> packageP ] - char '\n' + void $ char '\n' return p packageP :: ReadP (PackageBaseName, PackageVersion, PackageId)