From c0652c0321ea3ad51ef6a6ee19435baf9a765c4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 18:08:28 +0200 Subject: [PATCH 01/28] Move GhcModError to Types.hs --- Language/Haskell/GhcMod/Monad.hs | 10 ---------- Language/Haskell/GhcMod/Types.hs | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index 36aabdd..44e9dd0 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -122,16 +122,6 @@ data CompilerMode = Simple | Intelligent deriving (Eq,Show,Read) defaultState :: GhcModState defaultState = GhcModState Simple -data GhcModError = GMENoMsg - | GMEString String - | GMECabal - | GMEGhc - deriving (Eq,Show,Read) - -instance Error GhcModError where - noMsg = GMENoMsg - strMsg = GMEString - ---------------------------------------------------------------- -- | A constraint alias (-XConstraintKinds) to make functions dealing with diff --git a/Language/Haskell/GhcMod/Types.hs b/Language/Haskell/GhcMod/Types.hs index b42b018..5bab199 100644 --- a/Language/Haskell/GhcMod/Types.hs +++ b/Language/Haskell/GhcMod/Types.hs @@ -2,9 +2,24 @@ module Language.Haskell.GhcMod.Types where import Data.List (intercalate) import qualified Data.Map as M +import Control.Monad.Error (Error(..)) import PackageConfig (PackageConfig) +-- | +data GhcModError = GMENoMsg + -- ^ Unknown error + | GMEString String + -- ^ Some Error with a message. These are produced mostly by + -- 'fail' calls on GhcModT. + | GMECabal String + | GMEGhc + deriving (Eq,Show,Read) + +instance Error GhcModError where + noMsg = GMENoMsg + strMsg = GMEString + -- | Output style. data OutputStyle = LispStyle -- ^ S expression style. | PlainStyle -- ^ Plain textstyle. From e345c92edb4a2b2f60a9b0adaa68fff76f0d0c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 18:09:31 +0200 Subject: [PATCH 02/28] Make GhcModT's MonadState instance pass through ..to the underlying monad --- Language/Haskell/GhcMod/Monad.hs | 29 +++++++++++++++++++---------- Language/Haskell/GhcMod/Target.hs | 2 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index 44e9dd0..6df8380 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -30,8 +30,6 @@ module Language.Haskell.GhcMod.Monad ( , withOptions -- ** Exporting convenient modules , module Control.Monad.Reader.Class - , module Control.Monad.Writer.Class - , module Control.Monad.State.Class , module Control.Monad.Journal.Class ) where @@ -85,10 +83,10 @@ import Control.Monad.Trans.Control (MonadBaseControl(..), StM, liftBaseWith, import Control.Monad.Trans.Class import Control.Monad.Reader.Class -import Control.Monad.Writer.Class -import Control.Monad.State.Class +import Control.Monad.Writer.Class (MonadWriter) +import Control.Monad.State.Class (MonadState(..)) -import Control.Monad.Error (Error(..), MonadError, ErrorT, runErrorT) +import Control.Monad.Error (MonadError, ErrorT, runErrorT) import Control.Monad.Reader (ReaderT, runReaderT) import Control.Monad.State.Strict (StateT, runStateT) import Control.Monad.Trans.Journal (JournalT, runJournalT) @@ -155,13 +153,18 @@ newtype GhcModT m a = GhcModT { #endif , MonadReader GhcModEnv , MonadWriter w - , MonadState GhcModState , MonadError GhcModError ) instance MonadTrans GhcModT where lift = GhcModT . lift . lift . lift . lift +instance MonadState s m => MonadState s (GhcModT m) where + get = GhcModT $ lift $ lift $ lift $ get + put = GhcModT . lift . lift . lift . put + state = GhcModT . lift . lift . lift . state + + #if MONADIO_INSTANCES instance MonadIO m => MonadIO (StateT s m) where liftIO = lift . liftIO @@ -283,17 +286,23 @@ toGhcModT a = do ---------------------------------------------------------------- +gmsGet :: IOish m => GhcModT m GhcModState +gmsGet = GhcModT get + +gmsPut :: IOish m => GhcModState -> GhcModT m () +gmsPut = GhcModT . put + options :: IOish m => GhcModT m Options options = gmOptions <$> ask cradle :: IOish m => GhcModT m Cradle cradle = gmCradle <$> ask -getCompilerMode :: (Functor m, MonadState GhcModState m) => m CompilerMode -getCompilerMode = gmCompilerMode <$> get +getCompilerMode :: IOish m => GhcModT m CompilerMode +getCompilerMode = gmCompilerMode <$> gmsGet -setCompilerMode :: MonadState GhcModState m => CompilerMode -> m () -setCompilerMode mode = (\s -> put s { gmCompilerMode = mode } ) =<< get +setCompilerMode :: IOish m => CompilerMode -> GhcModT m () +setCompilerMode mode = (\s -> gmsPut s { gmCompilerMode = mode } ) =<< gmsGet ---------------------------------------------------------------- diff --git a/Language/Haskell/GhcMod/Target.hs b/Language/Haskell/GhcMod/Target.hs index 572388b..1744a72 100644 --- a/Language/Haskell/GhcMod/Target.hs +++ b/Language/Haskell/GhcMod/Target.hs @@ -15,7 +15,7 @@ setTargetFiles :: IOish m => [FilePath] -> GhcModT m () setTargetFiles files = do targets <- forM files $ \file -> G.guessTarget file Nothing G.setTargets targets - mode <- gmCompilerMode <$> get + mode <- getCompilerMode if mode == Intelligent then loadTargets Intelligent else do From 87c587993aaf1d73d25e7f57a07df37c3d011b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 18:11:32 +0200 Subject: [PATCH 03/28] Make `parseCabalFile` use MonadError --- Language/Haskell/GhcMod/CabalApi.hs | 21 +++++++++++++-------- Language/Haskell/GhcMod/Debug.hs | 4 ++-- Language/Haskell/GhcMod/Monad.hs | 4 ++-- test/CabalApiSpec.hs | 15 +++++++++------ test/MonadSpec.hs | 4 ++-- test/TestUtils.hs | 17 +++++++++++++++++ 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/Language/Haskell/GhcMod/CabalApi.hs b/Language/Haskell/GhcMod/CabalApi.hs index e312488..4978d65 100644 --- a/Language/Haskell/GhcMod/CabalApi.hs +++ b/Language/Haskell/GhcMod/CabalApi.hs @@ -11,14 +11,16 @@ module Language.Haskell.GhcMod.CabalApi ( ) where import Language.Haskell.GhcMod.CabalConfig -import Language.Haskell.GhcMod.Gap (benchmarkBuildInfo, benchmarkTargets, toModuleString) +import Language.Haskell.GhcMod.Gap (benchmarkBuildInfo, benchmarkTargets, + toModuleString) import Language.Haskell.GhcMod.GhcPkg import Language.Haskell.GhcMod.Types import Control.Applicative ((<$>)) import qualified Control.Exception as E import Control.Monad (filterM) -import CoreMonad (liftIO) +import Control.Monad.IO.Class (MonadIO, liftIO) +import Control.Monad.Error.Class (MonadError(..)) import Data.Maybe (maybeToList) import Data.Set (fromList, toList) import Distribution.Package (Dependency(Dependency) @@ -71,17 +73,20 @@ includeDirectories cdir wdir dirs = uniqueAndSort (extdirs ++ [cdir,wdir]) -- | Parsing a cabal file and returns 'PackageDescription'. -- 'IOException' is thrown if parsing fails. -parseCabalFile :: FilePath -> IO PackageDescription +parseCabalFile :: (MonadIO m, MonadError GhcModError m) + => FilePath + -> m PackageDescription parseCabalFile file = do - cid <- getGHCId - epgd <- readPackageDescription silent file + cid <- liftIO $ getGHCId + epgd <- liftIO $ readPackageDescription silent file case toPkgDesc cid epgd of - Left deps -> E.throwIO $ userError $ show deps ++ " are not installed" + Left deps -> throwError $ GMECabal $ show deps ++ " are not installed" Right (pd,_) -> if nullPkg pd - then E.throwIO $ userError $ file ++ " is broken" + then throwError $ GMECabal $ file ++ " is broken" else return pd where - toPkgDesc cid = finalizePackageDescription [] (const True) buildPlatform cid [] + toPkgDesc cid = + finalizePackageDescription [] (const True) buildPlatform cid [] nullPkg pd = name == "" where PackageName name = C.pkgName (P.package pd) diff --git a/Language/Haskell/GhcMod/Debug.hs b/Language/Haskell/GhcMod/Debug.hs index d9cd186..82685f3 100644 --- a/Language/Haskell/GhcMod/Debug.hs +++ b/Language/Haskell/GhcMod/Debug.hs @@ -31,9 +31,9 @@ debugInfo = cradle >>= \c -> convert' =<< do where simpleCompilerOption = options >>= \op -> return $ CompilerOptions (ghcOpts op) [] [] - fromCabalFile c = options >>= \opts -> liftIO $ do + fromCabalFile c = options >>= \opts -> do pkgDesc <- parseCabalFile $ fromJust $ cradleCabalFile c - getCompilerOptions (ghcOpts opts) c pkgDesc + liftIO $ getCompilerOptions (ghcOpts opts) c pkgDesc ---------------------------------------------------------------- diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index 6df8380..3b99b1a 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -187,7 +187,7 @@ instance MonadIO m => MonadIO (MaybeT m) where -- | Initialize the 'DynFlags' relating to the compilation of a single -- file or GHC session according to the 'Cradle' and 'Options' -- provided. -initializeFlagsWithCradle :: GhcMonad m +initializeFlagsWithCradle :: (GhcMonad m, MonadError GhcModError m) => Options -> Cradle -> m () @@ -199,7 +199,7 @@ initializeFlagsWithCradle opt c cabal = isJust mCradleFile ghcopts = ghcOpts opt withCabal = do - pkgDesc <- liftIO $ parseCabalFile $ fromJust mCradleFile + pkgDesc <- parseCabalFile $ fromJust mCradleFile compOpts <- liftIO $ getCompilerOptions ghcopts c pkgDesc initSession CabalPkg opt compOpts withSandbox = initSession SingleFile opt compOpts diff --git a/test/CabalApiSpec.hs b/test/CabalApiSpec.hs index d7b1d13..a43488d 100644 --- a/test/CabalApiSpec.hs +++ b/test/CabalApiSpec.hs @@ -13,6 +13,7 @@ import System.Directory import System.FilePath import Dir +import TestUtils import Config (cProjectVersionInt) -- ghc version @@ -23,14 +24,16 @@ spec :: Spec spec = do describe "parseCabalFile" $ do it "throws an exception if the cabal file is broken" $ do - parseCabalFile "test/data/broken-cabal/broken.cabal" `shouldThrow` (\(_::IOException) -> True) + shouldReturnError $ + runD' $ parseCabalFile "test/data/broken-cabal/broken.cabal" + describe "getCompilerOptions" $ do it "gets necessary CompilerOptions" $ do cwd <- getCurrentDirectory withDirectory "test/data/subdir1/subdir2" $ \dir -> do cradle <- findCradle - pkgDesc <- parseCabalFile $ fromJust $ cradleCabalFile cradle + pkgDesc <- runD $ parseCabalFile $ fromJust $ cradleCabalFile cradle res <- getCompilerOptions [] cradle pkgDesc let res' = res { ghcOptions = ghcOptions res @@ -45,18 +48,18 @@ spec = do describe "cabalDependPackages" $ do it "extracts dependent packages" $ do - pkgs <- cabalDependPackages . cabalAllBuildInfo <$> parseCabalFile "test/data/cabalapi.cabal" + pkgs <- cabalDependPackages . cabalAllBuildInfo <$> runD (parseCabalFile "test/data/cabalapi.cabal") pkgs `shouldBe` ["Cabal","base","template-haskell"] describe "cabalSourceDirs" $ do it "extracts all hs-source-dirs" $ do - dirs <- cabalSourceDirs . cabalAllBuildInfo <$> parseCabalFile "test/data/check-test-subdir/check-test-subdir.cabal" + dirs <- cabalSourceDirs . cabalAllBuildInfo <$> runD (parseCabalFile "test/data/check-test-subdir/check-test-subdir.cabal") dirs `shouldBe` ["src", "test"] it "extracts all hs-source-dirs including \".\"" $ do - dirs <- cabalSourceDirs . cabalAllBuildInfo <$> parseCabalFile "test/data/cabalapi.cabal" + dirs <- cabalSourceDirs . cabalAllBuildInfo <$> runD (parseCabalFile "test/data/cabalapi.cabal") dirs `shouldBe` [".", "test"] describe "cabalAllBuildInfo" $ do it "extracts build info" $ do - info <- cabalAllBuildInfo <$> parseCabalFile "test/data/cabalapi.cabal" + info <- cabalAllBuildInfo <$> runD (parseCabalFile "test/data/cabalapi.cabal") show info `shouldBe` "[BuildInfo {buildable = True, buildTools = [], cppOptions = [], ccOptions = [], ldOptions = [], pkgconfigDepends = [], frameworks = [], cSources = [], hsSourceDirs = [\".\"], otherModules = [ModuleName [\"Browse\"],ModuleName [\"CabalApi\"],ModuleName [\"Cabal\"],ModuleName [\"CabalDev\"],ModuleName [\"Check\"],ModuleName [\"ErrMsg\"],ModuleName [\"Flag\"],ModuleName [\"GHCApi\"],ModuleName [\"GHCChoice\"],ModuleName [\"Gap\"],ModuleName [\"Info\"],ModuleName [\"Lang\"],ModuleName [\"Lint\"],ModuleName [\"List\"],ModuleName [\"Paths_ghc_mod\"],ModuleName [\"Types\"]], defaultLanguage = Nothing, otherLanguages = [], defaultExtensions = [], otherExtensions = [], oldExtensions = [], extraLibs = [], extraLibDirs = [], includeDirs = [], includes = [], installIncludes = [], options = [(GHC,[\"-Wall\"])], ghcProfOptions = [], ghcSharedOptions = [], customFieldsBI = [], targetBuildDepends = [Dependency (PackageName \"Cabal\") (UnionVersionRanges (ThisVersion (Version {versionBranch = [1,10], versionTags = []})) (LaterVersion (Version {versionBranch = [1,10], versionTags = []}))),Dependency (PackageName \"base\") (IntersectVersionRanges (UnionVersionRanges (ThisVersion (Version {versionBranch = [4,0], versionTags = []})) (LaterVersion (Version {versionBranch = [4,0], versionTags = []}))) (EarlierVersion (Version {versionBranch = [5], versionTags = []}))),Dependency (PackageName \"template-haskell\") AnyVersion]},BuildInfo {buildable = True, buildTools = [], cppOptions = [], ccOptions = [], ldOptions = [], pkgconfigDepends = [], frameworks = [], cSources = [], hsSourceDirs = [\"test\",\".\"], otherModules = [ModuleName [\"Expectation\"],ModuleName [\"BrowseSpec\"],ModuleName [\"CabalApiSpec\"],ModuleName [\"FlagSpec\"],ModuleName [\"LangSpec\"],ModuleName [\"LintSpec\"],ModuleName [\"ListSpec\"]], defaultLanguage = Nothing, otherLanguages = [], defaultExtensions = [], otherExtensions = [], oldExtensions = [], extraLibs = [], extraLibDirs = [], includeDirs = [], includes = [], installIncludes = [], options = [], ghcProfOptions = [], ghcSharedOptions = [], customFieldsBI = [], targetBuildDepends = [Dependency (PackageName \"Cabal\") (UnionVersionRanges (ThisVersion (Version {versionBranch = [1,10], versionTags = []})) (LaterVersion (Version {versionBranch = [1,10], versionTags = []}))),Dependency (PackageName \"base\") (IntersectVersionRanges (UnionVersionRanges (ThisVersion (Version {versionBranch = [4,0], versionTags = []})) (LaterVersion (Version {versionBranch = [4,0], versionTags = []}))) (EarlierVersion (Version {versionBranch = [5], versionTags = []})))]}]" diff --git a/test/MonadSpec.hs b/test/MonadSpec.hs index 74404f1..938f763 100644 --- a/test/MonadSpec.hs +++ b/test/MonadSpec.hs @@ -3,6 +3,7 @@ module MonadSpec where import Test.Hspec import Dir +import TestUtils import Control.Applicative import Control.Monad.Error.Class import Language.Haskell.GhcMod.Types @@ -23,5 +24,4 @@ spec = do describe "runGhcModT" $ it "complains if the cabal file fails to parse while a sandbox is present" $ withDirectory_ "test/data/broken-cabal" $ do - (a,_) <- runGhcModT defaultOptions (gmCradle <$> ask) - a `shouldSatisfy` (\(Left _) -> True) + shouldReturnError $ runD' (gmCradle <$> ask) diff --git a/test/TestUtils.hs b/test/TestUtils.hs index 02ce0e3..4732ffe 100644 --- a/test/TestUtils.hs +++ b/test/TestUtils.hs @@ -1,10 +1,12 @@ module TestUtils ( run , runD + , runD' , runI , runID , runIsolatedGhcMod , isolateCradle + , shouldReturnError , module Language.Haskell.GhcMod.Monad , module Language.Haskell.GhcMod.Types ) where @@ -12,6 +14,8 @@ module TestUtils ( import Language.Haskell.GhcMod.Monad import Language.Haskell.GhcMod.Types +import Test.Hspec + isolateCradle :: IOish m => GhcModT m a -> GhcModT m a isolateCradle action = local modifyEnv $ action @@ -42,3 +46,16 @@ run opt a = extract $ runGhcModT opt a -- | Run GhcMod with default options runD :: GhcModT IO a -> IO a runD = extract . runGhcModT defaultOptions + +runD' :: GhcModT IO a -> IO (Either GhcModError a, GhcModLog) +runD' = runGhcModT defaultOptions + +shouldReturnError :: Show a + => IO (Either GhcModError a, GhcModLog) + -> Expectation +shouldReturnError action = do + (a,_) <- action + a `shouldSatisfy` isLeft + where + isLeft (Left _) = True + isLeft _ = False From 9922cf08e18199baca59f545a35c3d627c17b526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 18:12:12 +0200 Subject: [PATCH 04/28] Generate cabal.sandbox.config in test/data/broken-cabal --- test/Main.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/Main.hs b/test/Main.hs index 0948f3a..93bdb76 100644 --- a/test/Main.hs +++ b/test/Main.hs @@ -11,7 +11,9 @@ import TestUtils main = do let sandboxes = [ "test/data", "test/data/check-packageid" - , "test/data/duplicate-pkgver/" ] + , "test/data/duplicate-pkgver/" + , "test/data/broken-cabal/" + ] genSandboxCfg dir = withDirectory dir $ \cwd -> do system ("sed 's|@CWD@|" ++ cwd ++ "|g' cabal.sandbox.config.in > cabal.sandbox.config") pkgDirs = From fa65d7269ecac86fcb76d4944b5c9b9edbff958a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 18:22:28 +0200 Subject: [PATCH 05/28] Add a test for gmsGet/Put --- Language/Haskell/GhcMod/Monad.hs | 2 ++ test/MonadSpec.hs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index 3b99b1a..92e6ac2 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -23,6 +23,8 @@ module Language.Haskell.GhcMod.Monad ( -- ** Conversion , toGhcModT -- ** Accessing 'GhcModEnv' and 'GhcModState' + , gmsGet + , gmsPut , options , cradle , getCompilerMode diff --git a/test/MonadSpec.hs b/test/MonadSpec.hs index 938f763..49f8198 100644 --- a/test/MonadSpec.hs +++ b/test/MonadSpec.hs @@ -25,3 +25,8 @@ spec = do describe "runGhcModT" $ it "complains if the cabal file fails to parse while a sandbox is present" $ withDirectory_ "test/data/broken-cabal" $ do shouldReturnError $ runD' (gmCradle <$> ask) + + describe "gmsGet/Put" $ + it "work" $ do + (runD $ gmsPut (GhcModState Intelligent) >> gmsGet) + `shouldReturn` (GhcModState Intelligent) From edeb57a6a4575e7741afb2be00d5e0dd0b825008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 18:23:23 +0200 Subject: [PATCH 06/28] note --- Language/Haskell/GhcMod/Monad.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index 92e6ac2..66b35f7 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -153,7 +153,8 @@ newtype GhcModT m a = GhcModT { #if DIFFERENT_MONADIO , Control.Monad.IO.Class.MonadIO #endif - , MonadReader GhcModEnv + , MonadReader GhcModEnv -- TODO: make MonadReader instance + -- pass-through like MonadState , MonadWriter w , MonadError GhcModError ) From 0fa870efa67cb42abd5c7b58849e609866e0ad9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 18:54:48 +0200 Subject: [PATCH 07/28] Fix ghc<=7.6 --- 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 66b35f7..25214eb 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -94,6 +94,7 @@ import Control.Monad.State.Strict (StateT, runStateT) import Control.Monad.Trans.Journal (JournalT, runJournalT) #ifdef MONADIO_INSTANCES import Control.Monad.Trans.Maybe (MaybeT) +import Control.Monad.Error (Error(..)) #endif import Control.Monad.Journal.Class From 3dfd04c7fe744f00e953174e238866cc09563e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 19:06:04 +0200 Subject: [PATCH 08/28] Use the right MonadIO class --- Language/Haskell/GhcMod/CabalApi.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Language/Haskell/GhcMod/CabalApi.hs b/Language/Haskell/GhcMod/CabalApi.hs index 4978d65..b97a168 100644 --- a/Language/Haskell/GhcMod/CabalApi.hs +++ b/Language/Haskell/GhcMod/CabalApi.hs @@ -16,10 +16,10 @@ import Language.Haskell.GhcMod.Gap (benchmarkBuildInfo, benchmarkTargets, import Language.Haskell.GhcMod.GhcPkg import Language.Haskell.GhcMod.Types +import MonadUtils (MonadIO, liftIO) import Control.Applicative ((<$>)) import qualified Control.Exception as E import Control.Monad (filterM) -import Control.Monad.IO.Class (MonadIO, liftIO) import Control.Monad.Error.Class (MonadError(..)) import Data.Maybe (maybeToList) import Data.Set (fromList, toList) From c4ae9bc58900068b25fd87a991af31762777fc7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 21:00:06 +0200 Subject: [PATCH 09/28] Expose GhcModError --- Language/Haskell/GhcMod.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/Language/Haskell/GhcMod.hs b/Language/Haskell/GhcMod.hs index 5362ea8..69c00bd 100644 --- a/Language/Haskell/GhcMod.hs +++ b/Language/Haskell/GhcMod.hs @@ -18,6 +18,7 @@ module Language.Haskell.GhcMod ( -- * Monad Types , GhcModT , IOish + , GhcModError(..) -- * Monad utilities , runGhcModT , withOptions From e0bbd91eba8ae5185091ed1fa043016e6123f02f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 21:07:12 +0200 Subject: [PATCH 10/28] Remove GMECabal, GMEGhc constructors from GhcModError for now --- Language/Haskell/GhcMod/CabalApi.hs | 11 +++++------ Language/Haskell/GhcMod/Types.hs | 2 -- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Language/Haskell/GhcMod/CabalApi.hs b/Language/Haskell/GhcMod/CabalApi.hs index b97a168..8483691 100644 --- a/Language/Haskell/GhcMod/CabalApi.hs +++ b/Language/Haskell/GhcMod/CabalApi.hs @@ -20,7 +20,7 @@ import MonadUtils (MonadIO, liftIO) import Control.Applicative ((<$>)) import qualified Control.Exception as E import Control.Monad (filterM) -import Control.Monad.Error.Class (MonadError(..)) +import Control.Monad.Error.Class (Error, MonadError(..)) import Data.Maybe (maybeToList) import Data.Set (fromList, toList) import Distribution.Package (Dependency(Dependency) @@ -71,18 +71,17 @@ includeDirectories cdir wdir dirs = uniqueAndSort (extdirs ++ [cdir,wdir]) ---------------------------------------------------------------- --- | Parsing a cabal file and returns 'PackageDescription'. --- 'IOException' is thrown if parsing fails. -parseCabalFile :: (MonadIO m, MonadError GhcModError m) +-- | Parse a cabal file and return a 'PackageDescription'. +parseCabalFile :: (MonadIO m, Error e, MonadError e m) => FilePath -> m PackageDescription parseCabalFile file = do cid <- liftIO $ getGHCId epgd <- liftIO $ readPackageDescription silent file case toPkgDesc cid epgd of - Left deps -> throwError $ GMECabal $ show deps ++ " are not installed" + Left deps -> fail $ show deps ++ " are not installed" Right (pd,_) -> if nullPkg pd - then throwError $ GMECabal $ file ++ " is broken" + then fail $ file ++ " is broken" else return pd where toPkgDesc cid = diff --git a/Language/Haskell/GhcMod/Types.hs b/Language/Haskell/GhcMod/Types.hs index 5bab199..b92b32c 100644 --- a/Language/Haskell/GhcMod/Types.hs +++ b/Language/Haskell/GhcMod/Types.hs @@ -12,8 +12,6 @@ data GhcModError = GMENoMsg | GMEString String -- ^ Some Error with a message. These are produced mostly by -- 'fail' calls on GhcModT. - | GMECabal String - | GMEGhc deriving (Eq,Show,Read) instance Error GhcModError where From 4def562179fbda231a22c3f39a8c9c38c0a6b8c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 21:20:36 +0200 Subject: [PATCH 11/28] Add version number to symbol table cache filename --- Language/Haskell/GhcMod/Find.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Language/Haskell/GhcMod/Find.hs b/Language/Haskell/GhcMod/Find.hs index b923917..37d10c6 100644 --- a/Language/Haskell/GhcMod/Find.hs +++ b/Language/Haskell/GhcMod/Find.hs @@ -59,8 +59,13 @@ newtype SymbolDb = SymbolDb (Map Symbol [ModuleString]) ---------------------------------------------------------------- +-- | When introducing incompatible changes to the 'symbolCache' file format +-- increment this version number. +symbolCacheVersion = 0 + +-- | Filename of the symbol table cache file. symbolCache :: String -symbolCache = "ghc-mod.cache" +symbolCache = "ghc-mod-"++ show symbolCacheVersion ++".cache" packageCache :: String packageCache = "package.cache" @@ -130,7 +135,6 @@ getSymbolCachePath = do -- if the file does not exist or is invalid. -- The file name is printed. --- TODO: Before releaseing add a version number to the name of the cache file dumpSymbol :: IOish m => GhcModT m String dumpSymbol = do dir <- getSymbolCachePath From 2a1fd287715537e8fdb1032438c0fbfa2e584076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Tue, 12 Aug 2014 21:21:08 +0200 Subject: [PATCH 12/28] docs for `ghcModExecutable` --- Language/Haskell/GhcMod/Find.hs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Language/Haskell/GhcMod/Find.hs b/Language/Haskell/GhcMod/Find.hs index 37d10c6..c6a3a6b 100644 --- a/Language/Haskell/GhcMod/Find.hs +++ b/Language/Haskell/GhcMod/Find.hs @@ -94,6 +94,8 @@ lookupSym sym (SymbolDb db) = fromMaybe [] $ M.lookup sym db loadSymbolDb :: IO SymbolDb loadSymbolDb = SymbolDb <$> readSymbolDb +-- | Returns the path to the currently running ghc-mod executable. With ghc<7.6 +-- this is a guess but >=7.6 uses 'getExecutablePath'. ghcModExecutable :: IO FilePath #ifndef SPEC ghcModExecutable = do From 625d4661e7190b7223d2d465976c3e353a01ec48 Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Wed, 13 Aug 2014 15:21:13 +0900 Subject: [PATCH 13/28] fix #295. --- ghc-mod.cabal | 1 + src/GHCModi.hs | 14 ++++++++------ src/Utils.hs | 27 +++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 src/Utils.hs diff --git a/ghc-mod.cabal b/ghc-mod.cabal index 73922a3..1069577 100644 --- a/ghc-mod.cabal +++ b/ghc-mod.cabal @@ -133,6 +133,7 @@ Executable ghc-modi Default-Language: Haskell2010 Main-Is: GHCModi.hs Other-Modules: Paths_ghc_mod + Utils GHC-Options: -Wall -threaded Default-Extensions: ConstraintKinds, FlexibleContexts HS-Source-Dirs: src diff --git a/src/GHCModi.hs b/src/GHCModi.hs index 6276338..c6e2541 100644 --- a/src/GHCModi.hs +++ b/src/GHCModi.hs @@ -39,6 +39,8 @@ import System.Directory (setCurrentDirectory) import System.Environment (getArgs) import System.IO (hFlush,stdout) +import Utils + ---------------------------------------------------------------- type Logger = IO String @@ -231,7 +233,7 @@ showInfo :: IOish m -> FilePath -> GhcModT m (String, Bool, Set FilePath) showInfo set fileArg = do - let [file, expr] = words fileArg + let [file, expr] = splitN 2 fileArg set' <- newFileSet set file ret <- info file expr return (ret, True, set') @@ -241,7 +243,7 @@ showType :: IOish m -> FilePath -> GhcModT m (String, Bool, Set FilePath) showType set fileArg = do - let [file, line, column] = words fileArg + let [file, line, column] = splitN 3 fileArg set' <- newFileSet set file ret <- types file (read line) (read column) return (ret, True, set') @@ -251,7 +253,7 @@ doSplit :: IOish m -> FilePath -> GhcModT m (String, Bool, Set FilePath) doSplit set fileArg = do - let [file, line, column] = words fileArg + let [file, line, column] = splitN 3 fileArg set' <- newFileSet set file ret <- splits file (read line) (read column) return (ret, True, set') @@ -261,7 +263,7 @@ doSig :: IOish m -> FilePath -> GhcModT m (String, Bool, Set FilePath) doSig set fileArg = do - let [file, line, column] = words fileArg + let [file, line, column] = splitN 3 fileArg set' <- newFileSet set file ret <- sig file (read line) (read column) return (ret, True, set') @@ -271,7 +273,7 @@ doRefine :: IOish m -> FilePath -> GhcModT m (String, Bool, Set FilePath) doRefine set fileArg = do - let [file, line, column, expr] = words fileArg + let [file, line, column, expr] = splitN 4 fileArg set' <- newFileSet set file ret <- refine file (read line) (read column) expr return (ret, True, set') @@ -281,7 +283,7 @@ doAuto :: IOish m -> FilePath -> GhcModT m (String, Bool, Set FilePath) doAuto set fileArg = do - let [file, line, column] = words fileArg + let [file, line, column] = splitN 3 fileArg set' <- newFileSet set file ret <- auto file (read line) (read column) return (ret, True, set') diff --git a/src/Utils.hs b/src/Utils.hs new file mode 100644 index 0000000..c91151d --- /dev/null +++ b/src/Utils.hs @@ -0,0 +1,27 @@ +module Utils where + +-- | +-- +-- >>> split "foo bar baz" +-- ["foo","bar baz"] +-- >>> split "foo bar baz" +-- ["foo","bar baz"] +split :: String -> [String] +split xs = [ys, dropWhile isSpace zs] + where + isSpace = (== ' ') + (ys,zs) = break isSpace xs + +-- | +-- +-- >>> splitN 0 "foo bar baz" +-- ["foo","bar baz"] +-- >>> splitN 2 "foo bar baz" +-- ["foo","bar baz"] +-- >>> splitN 3 "foo bar baz" +-- ["foo","bar","baz"] +splitN :: Int -> String -> [String] +splitN n xs + | n <= 2 = split xs + | otherwise = let [ys,zs] = split xs + in ys : splitN (n - 1) zs From 4fcef0cb2b7c51963b990773a5bbec8a3f73adef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Wed, 13 Aug 2014 18:04:37 +0200 Subject: [PATCH 14/28] Reset DynFlags properly in `withCmdFlags` teardown --- Language/Haskell/GhcMod/DynFlags.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Language/Haskell/GhcMod/DynFlags.hs b/Language/Haskell/GhcMod/DynFlags.hs index 74c3ee5..5cf9153 100644 --- a/Language/Haskell/GhcMod/DynFlags.hs +++ b/Language/Haskell/GhcMod/DynFlags.hs @@ -88,8 +88,8 @@ withCmdFlags :: GhcMonad m => [GHCOption] -> m a -> m a withCmdFlags flags body = G.gbracket setup teardown (\_ -> body) where setup = do - dflags <- G.getSessionDynFlags >>= addCmdOpts flags - void $ G.setSessionDynFlags dflags + dflags <- G.getSessionDynFlags + void $ G.setSessionDynFlags =<< addCmdOpts flags dflags return dflags teardown = void . G.setSessionDynFlags From f2ccea7f295a4cedb201aa70665eebc3fa1ddeb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Wed, 13 Aug 2014 18:26:30 +0200 Subject: [PATCH 15/28] Fix error presentation --- src/GHCMod.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/GHCMod.hs b/src/GHCMod.hs index 83b9165..0e75f2c 100644 --- a/src/GHCMod.hs +++ b/src/GHCMod.hs @@ -138,7 +138,8 @@ main = flip E.catches handlers $ do cmd -> E.throw (NoSuchCommand cmd) case res of Right s -> putStr s - Left e -> error $ show e + Left (GMENoMsg) -> hPutStrLn stderr "Unknown error" + Left (GMEString msg) -> hPutStrLn stderr msg where handlers = [Handler (handleThenExit handler1), Handler (handleThenExit handler2)] handleThenExit handler e = handler e >> exitFailure From c1c7dcec2027e6a9faea87cd457fa9274733b457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Wed, 13 Aug 2014 18:40:01 +0200 Subject: [PATCH 16/28] Rename `ghcOpts` -> `ghcUserOptions` --- Language/Haskell/GhcMod/Debug.hs | 4 ++-- Language/Haskell/GhcMod/Logger.hs | 2 +- Language/Haskell/GhcMod/Monad.hs | 2 +- Language/Haskell/GhcMod/Types.hs | 5 +++-- src/GHCMod.hs | 2 +- src/GHCModi.hs | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Language/Haskell/GhcMod/Debug.hs b/Language/Haskell/GhcMod/Debug.hs index 82685f3..c12c93c 100644 --- a/Language/Haskell/GhcMod/Debug.hs +++ b/Language/Haskell/GhcMod/Debug.hs @@ -30,10 +30,10 @@ debugInfo = cradle >>= \c -> convert' =<< do ] where simpleCompilerOption = options >>= \op -> - return $ CompilerOptions (ghcOpts op) [] [] + return $ CompilerOptions (ghcUserOptions op) [] [] fromCabalFile c = options >>= \opts -> do pkgDesc <- parseCabalFile $ fromJust $ cradleCabalFile c - liftIO $ getCompilerOptions (ghcOpts opts) c pkgDesc + liftIO $ getCompilerOptions (ghcUserOptions opts) c pkgDesc ---------------------------------------------------------------- diff --git a/Language/Haskell/GhcMod/Logger.hs b/Language/Haskell/GhcMod/Logger.hs index 17aa82a..4962628 100644 --- a/Language/Haskell/GhcMod/Logger.hs +++ b/Language/Haskell/GhcMod/Logger.hs @@ -64,7 +64,7 @@ withLogger :: IOish m -> GhcModT m (Either String String) withLogger setDF body = ghandle sourceError $ do logref <- liftIO newLogRef - wflags <- filter ("-fno-warn" `isPrefixOf`) . ghcOpts <$> options + wflags <- filter ("-fno-warn" `isPrefixOf`) . ghcUserOptions <$> options withDynFlags (setLogger logref . setDF) $ withCmdFlags wflags $ do body diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index 25214eb..713d799 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -201,7 +201,7 @@ initializeFlagsWithCradle opt c where mCradleFile = cradleCabalFile c cabal = isJust mCradleFile - ghcopts = ghcOpts opt + ghcopts = ghcUserOptions opt withCabal = do pkgDesc <- parseCabalFile $ fromJust mCradleFile compOpts <- liftIO $ getCompilerOptions ghcopts c pkgDesc diff --git a/Language/Haskell/GhcMod/Types.hs b/Language/Haskell/GhcMod/Types.hs index b92b32c..b224059 100644 --- a/Language/Haskell/GhcMod/Types.hs +++ b/Language/Haskell/GhcMod/Types.hs @@ -28,7 +28,8 @@ newtype LineSeparator = LineSeparator String data Options = Options { outputStyle :: OutputStyle , hlintOpts :: [String] - , ghcOpts :: [GHCOption] + -- | GHC command line options set on the @ghc-mod@ command line + , ghcUserOptions:: [GHCOption] -- | If 'True', 'browse' also returns operators. , operators :: Bool -- | If 'True', 'browse' also returns types. @@ -44,7 +45,7 @@ defaultOptions :: Options defaultOptions = Options { outputStyle = PlainStyle , hlintOpts = [] - , ghcOpts = [] + , ghcUserOptions= [] , operators = False , detailed = False , qualified = False diff --git a/src/GHCMod.hs b/src/GHCMod.hs index 0e75f2c..84b8bbf 100644 --- a/src/GHCMod.hs +++ b/src/GHCMod.hs @@ -63,7 +63,7 @@ argspec = [ Option "l" ["tolisp"] (ReqArg (\h opts -> opts { hlintOpts = h : hlintOpts opts }) "hlintOpt") "hlint options" , Option "g" ["ghcOpt"] - (ReqArg (\g opts -> opts { ghcOpts = g : ghcOpts opts }) "ghcOpt") + (ReqArg (\g opts -> opts { ghcUserOptions = g : ghcUserOptions opts }) "ghcOpt") "GHC options" , Option "o" ["operators"] (NoArg (\opts -> opts { operators = True })) diff --git a/src/GHCModi.hs b/src/GHCModi.hs index c6e2541..f651a3a 100644 --- a/src/GHCModi.hs +++ b/src/GHCModi.hs @@ -58,7 +58,7 @@ argspec = [ Option "b" ["boundary"] (NoArg (\opts -> opts { outputStyle = LispStyle })) "print as a list of Lisp" , Option "g" [] - (ReqArg (\s opts -> opts { ghcOpts = s : ghcOpts opts }) "flag") "specify a ghc flag" + (ReqArg (\s opts -> opts { ghcUserOptions = s : ghcUserOptions opts }) "flag") "specify a ghc flag" ] usage :: String From 4b05c20205ad7d24e6795ab72c53107c86e3942e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Wed, 13 Aug 2014 18:40:23 +0200 Subject: [PATCH 17/28] Add missing signature --- Language/Haskell/GhcMod/Find.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/Language/Haskell/GhcMod/Find.hs b/Language/Haskell/GhcMod/Find.hs index c6a3a6b..18b21cf 100644 --- a/Language/Haskell/GhcMod/Find.hs +++ b/Language/Haskell/GhcMod/Find.hs @@ -61,6 +61,7 @@ newtype SymbolDb = SymbolDb (Map Symbol [ModuleString]) -- | When introducing incompatible changes to the 'symbolCache' file format -- increment this version number. +symbolCacheVersion :: Integer symbolCacheVersion = 0 -- | Filename of the symbol table cache file. From ec1b115cc1d3d2341201a97b0b9f2dda5da9f660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gr=C3=B6ber?= Date: Wed, 13 Aug 2014 19:25:27 +0200 Subject: [PATCH 18/28] In `check`, apply ghcUserOptions after setting -Wall --- Language/Haskell/GhcMod/CaseSplit.hs | 1 - Language/Haskell/GhcMod/Check.hs | 9 ++++++--- Language/Haskell/GhcMod/Monad.hs | 29 ++++++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Language/Haskell/GhcMod/CaseSplit.hs b/Language/Haskell/GhcMod/CaseSplit.hs index 421d20d..f3da01a 100644 --- a/Language/Haskell/GhcMod/CaseSplit.hs +++ b/Language/Haskell/GhcMod/CaseSplit.hs @@ -4,7 +4,6 @@ module Language.Haskell.GhcMod.CaseSplit ( splits ) where -import CoreMonad (liftIO) import Data.List (find, intercalate) import Data.Maybe (isJust) import qualified Data.Text as T diff --git a/Language/Haskell/GhcMod/Check.hs b/Language/Haskell/GhcMod/Check.hs index c6756a7..7ec5eb3 100644 --- a/Language/Haskell/GhcMod/Check.hs +++ b/Language/Haskell/GhcMod/Check.hs @@ -8,8 +8,10 @@ module Language.Haskell.GhcMod.Check ( import Control.Applicative ((<$>)) import Language.Haskell.GhcMod.DynFlags import qualified Language.Haskell.GhcMod.Gap as Gap +import qualified GHC as G import Language.Haskell.GhcMod.Logger -import Language.Haskell.GhcMod.Monad (IOish, GhcModT, withErrorHandler) +import Language.Haskell.GhcMod.Monad (IOish, GhcModT, withErrorHandler + , overrideGhcUserOptions) import Language.Haskell.GhcMod.Target (setTargetFiles) ---------------------------------------------------------------- @@ -34,8 +36,9 @@ checkSyntax files = withErrorHandler sessionName $ check :: IOish m => [FilePath] -- ^ The target files. -> GhcModT m (Either String String) -check fileNames = - withLogger (setAllWaringFlags . setNoMaxRelevantBindings) $ +check fileNames = overrideGhcUserOptions $ \ghcOpts -> do + withLogger (setAllWaringFlags . setNoMaxRelevantBindings) $ do + _ <- G.setSessionDynFlags =<< addCmdOpts ghcOpts =<< G.getSessionDynFlags setTargetFiles fileNames ---------------------------------------------------------------- diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index 713d799..eb1d860 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -30,7 +30,10 @@ module Language.Haskell.GhcMod.Monad ( , getCompilerMode , setCompilerMode , withOptions - -- ** Exporting convenient modules + , withTempSession + , overrideGhcUserOptions + -- ** Re-exporting convenient stuff + , liftIO , module Control.Monad.Reader.Class , module Control.Monad.Journal.Class ) where @@ -57,7 +60,7 @@ import Exception import GHC import qualified GHC as G import GHC.Paths (libdir) -import GhcMonad +import GhcMonad hiding (withTempSession) #if __GLASGOW_HASKELL__ <= 702 import HscTypes #endif @@ -282,6 +285,28 @@ withErrorHandler label = ghandle ignore hPrint stderr e exitSuccess +-- | Make a copy of the 'gmGhcSession' IORef, run the action and restore the +-- original 'HscEnv'. +withTempSession :: IOish m => GhcModT m a -> GhcModT m a +withTempSession action = do + session <- gmGhcSession <$> ask + savedHscEnv <- liftIO $ readIORef session + a <- action + liftIO $ writeIORef session savedHscEnv + return a + +-- | This is a very ugly workaround don't use it. +overrideGhcUserOptions :: IOish m => ([GHCOption] -> GhcModT m b) -> GhcModT m b +overrideGhcUserOptions action = withTempSession $ do + env <- ask + opt <- options + let ghcOpts = ghcUserOptions opt + opt' = opt { ghcUserOptions = [] } + + initializeFlagsWithCradle opt' (gmCradle env) + + action ghcOpts + -- | This is only a transitional mechanism don't use it for new code. toGhcModT :: IOish m => Ghc a -> GhcModT m a toGhcModT a = do From 02ce2d4a1d1525610921edbb64b01a0fb37b8a2f Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 10:01:35 +0900 Subject: [PATCH 19/28] removing warnings. --- Language/Haskell/GhcMod/Debug.hs | 1 - Language/Haskell/GhcMod/FillSig.hs | 1 - Language/Haskell/GhcMod/Find.hs | 1 - Language/Haskell/GhcMod/Lint.hs | 1 - Language/Haskell/GhcMod/Logger.hs | 1 - Language/Haskell/GhcMod/PkgDoc.hs | 1 - 6 files changed, 6 deletions(-) diff --git a/Language/Haskell/GhcMod/Debug.hs b/Language/Haskell/GhcMod/Debug.hs index c12c93c..85cf9f6 100644 --- a/Language/Haskell/GhcMod/Debug.hs +++ b/Language/Haskell/GhcMod/Debug.hs @@ -1,7 +1,6 @@ module Language.Haskell.GhcMod.Debug (debugInfo, rootInfo) where import Control.Applicative ((<$>)) -import CoreMonad (liftIO) import Data.List (intercalate) import Data.Maybe (isJust, fromJust) import Language.Haskell.GhcMod.Convert diff --git a/Language/Haskell/GhcMod/FillSig.hs b/Language/Haskell/GhcMod/FillSig.hs index 4c7783c..2070788 100644 --- a/Language/Haskell/GhcMod/FillSig.hs +++ b/Language/Haskell/GhcMod/FillSig.hs @@ -20,7 +20,6 @@ import Language.Haskell.GhcMod.Convert import Language.Haskell.GhcMod.Monad import Language.Haskell.GhcMod.SrcUtils import Language.Haskell.GhcMod.Types -import CoreMonad (liftIO) import Outputable (PprStyle) import qualified Type as Ty import qualified HsBinds as Ty diff --git a/Language/Haskell/GhcMod/Find.hs b/Language/Haskell/GhcMod/Find.hs index 18b21cf..7fb0b50 100644 --- a/Language/Haskell/GhcMod/Find.hs +++ b/Language/Haskell/GhcMod/Find.hs @@ -19,7 +19,6 @@ import Control.Applicative ((<$>)) import Control.Exception (handle, SomeException(..)) import Control.Monad (when, void) import Control.Monad.Error.Class -import CoreMonad (liftIO) import Data.Function (on) import Data.List (groupBy, sort) import Data.List.Split (splitOn) diff --git a/Language/Haskell/GhcMod/Lint.hs b/Language/Haskell/GhcMod/Lint.hs index b126e25..c6e471a 100644 --- a/Language/Haskell/GhcMod/Lint.hs +++ b/Language/Haskell/GhcMod/Lint.hs @@ -2,7 +2,6 @@ module Language.Haskell.GhcMod.Lint where import Exception (ghandle) import Control.Exception (SomeException(..)) -import CoreMonad (liftIO) import Language.Haskell.GhcMod.Logger (checkErrorPrefix) import Language.Haskell.GhcMod.Convert import Language.Haskell.GhcMod.Monad diff --git a/Language/Haskell/GhcMod/Logger.hs b/Language/Haskell/GhcMod/Logger.hs index 4962628..0263561 100644 --- a/Language/Haskell/GhcMod/Logger.hs +++ b/Language/Haskell/GhcMod/Logger.hs @@ -7,7 +7,6 @@ module Language.Haskell.GhcMod.Logger ( import Bag (Bag, bagToList) import Control.Applicative ((<$>)) -import CoreMonad (liftIO) import Data.IORef (IORef, newIORef, readIORef, writeIORef, modifyIORef) import Data.List (isPrefixOf) import Data.Maybe (fromMaybe) diff --git a/Language/Haskell/GhcMod/PkgDoc.hs b/Language/Haskell/GhcMod/PkgDoc.hs index b29e172..3697c95 100644 --- a/Language/Haskell/GhcMod/PkgDoc.hs +++ b/Language/Haskell/GhcMod/PkgDoc.hs @@ -1,6 +1,5 @@ module Language.Haskell.GhcMod.PkgDoc (pkgDoc) where -import CoreMonad (liftIO) import Language.Haskell.GhcMod.Types import Language.Haskell.GhcMod.GhcPkg import Language.Haskell.GhcMod.Monad From 81efe04c01df75e5427d70dd49e4fc5f15f785b5 Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 10:08:48 +0900 Subject: [PATCH 20/28] removing |||> (#292) --- Language/Haskell/GhcMod/GHCChoice.hs | 7 ------- Language/Haskell/GhcMod/Internal.hs | 4 +--- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Language/Haskell/GhcMod/GHCChoice.hs b/Language/Haskell/GhcMod/GHCChoice.hs index 3ac604e..8ceb214 100644 --- a/Language/Haskell/GhcMod/GHCChoice.hs +++ b/Language/Haskell/GhcMod/GHCChoice.hs @@ -21,10 +21,3 @@ goNext = liftIO . GE.throwIO $ userError "goNext" -- | Run any one 'Ghc' monad. runAnyOne :: GhcMonad m => [m a] -> m a runAnyOne = foldr (||>) goNext - ----------------------------------------------------------------- - --- | Try the left 'GhcMonad' action. If 'IOException' occurs, try --- the right 'GhcMonad' action. -(|||>) :: GhcMonad m => m a -> m a -> m a -x |||> y = x `GE.gcatch` (\(_ :: IOException) -> y) diff --git a/Language/Haskell/GhcMod/Internal.hs b/Language/Haskell/GhcMod/Internal.hs index 237aff4..d55bfc9 100644 --- a/Language/Haskell/GhcMod/Internal.hs +++ b/Language/Haskell/GhcMod/Internal.hs @@ -44,12 +44,10 @@ module Language.Haskell.GhcMod.Internal ( , getCompilerMode , setCompilerMode , withOptions - -- * 'Ghc' Choice + -- * 'GhcMonad' Choice , (||>) , goNext , runAnyOne - -- * 'GhcMonad' Choice - , (|||>) ) where import GHC.Paths (libdir) From 358ed2dfff7acec6f6fde4c61003b0b70dbeded6 Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 10:20:30 +0900 Subject: [PATCH 21/28] workaround for #318 --- elisp/ghc-rewrite.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/elisp/ghc-rewrite.el b/elisp/ghc-rewrite.el index 0b91963..7dbd84b 100644 --- a/elisp/ghc-rewrite.el +++ b/elisp/ghc-rewrite.el @@ -11,7 +11,9 @@ (require 'ghc-func) (require 'ghc-process) (require 'button) -(require 'dropdown-list) +(condition-case nil + (require 'dropdown-list) + (file-error nil)) (defvar ghc-auto-info nil) (defvar ghc-auto-buffer nil) From 0ee6d064111d309c878ee19a60bf40812e0d2898 Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 10:48:57 +0900 Subject: [PATCH 22/28] removing trailing white spaces. --- elisp/ghc-check.el | 2 +- elisp/ghc-func.el | 4 ++-- elisp/ghc-rewrite.el | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/elisp/ghc-check.el b/elisp/ghc-check.el index 72b770e..670e228 100644 --- a/elisp/ghc-check.el +++ b/elisp/ghc-check.el @@ -247,7 +247,7 @@ nil does not display errors/warnings. (line (string-to-number (match-string 2 text))) (coln (string-to-number (match-string 3 text))) (buf (find-file file))) - (with-current-buffer buf + (with-current-buffer buf (let* ((this-line (line-number-at-pos)) (diff (- line this-line))) (beginning-of-line) diff --git a/elisp/ghc-func.el b/elisp/ghc-func.el index e17fb33..a55273b 100644 --- a/elisp/ghc-func.el +++ b/elisp/ghc-func.el @@ -159,7 +159,7 @@ ;; (turn-off-haskell-font-lock) ;; (haskell-font-lock-defaults-create) ;; (turn-on-haskell-font-lock))) -;; (display-buffer buf +;; (display-buffer buf ;; '((display-buffer-reuse-window ;; display-buffer-pop-up-window)))))) @@ -174,7 +174,7 @@ (turn-off-haskell-font-lock) (haskell-font-lock-defaults-create) (turn-on-haskell-font-lock))) - (display-buffer buf + (display-buffer buf '((display-buffer-reuse-window display-buffer-pop-up-window)))))) diff --git a/elisp/ghc-rewrite.el b/elisp/ghc-rewrite.el index 7dbd84b..9e021e4 100644 --- a/elisp/ghc-rewrite.el +++ b/elisp/ghc-rewrite.el @@ -133,8 +133,8 @@ ;; (ghc-display nil ;; (lambda () ;; (insert "Possible completions:\n") -;; (mapc -;; (lambda (x) +;; (mapc +;; (lambda (x) ;; (let* ((ins1 (insert "- ")) ;; (pos-begin (point)) ;; (ins (insert x)) From 4090b301f77df12d94cee14ec5701970a50baf62 Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 10:49:48 +0900 Subject: [PATCH 23/28] removing trailing white spaces. --- Language/Haskell/GhcMod/FillSig.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Language/Haskell/GhcMod/FillSig.hs b/Language/Haskell/GhcMod/FillSig.hs index 2070788..213c047 100644 --- a/Language/Haskell/GhcMod/FillSig.hs +++ b/Language/Haskell/GhcMod/FillSig.hs @@ -142,7 +142,7 @@ getSignatureFromHE file lineNo colNo = do return $ case presult of HE.ParseOk (HE.Module _ _ _ _ mdecls) -> do decl <- find (typeSigInRangeHE lineNo colNo) mdecls - case decl of + case decl of HE.TypeSig (HE.SrcSpanInfo s _) names ty -> return $ HESignature s names ty HE.TypeFamDecl (HE.SrcSpanInfo s _) (HE.DHead _ name tys) _ -> return $ HEFamSignature s Open name (map cleanTyVarBind tys) @@ -281,7 +281,7 @@ refine file lineNo colNo expr = ghandle handler body iArgs = take diffArgs eArgs text = initialHead1 expr iArgs (infinitePrefixSupply name) in (fourInts loc, doParen paren text) - + handler (SomeException _) = emptyResult =<< options -- Look for the variable in the specified position @@ -351,7 +351,7 @@ auto file lineNo colNo = ghandle handler body env = filter filterFn almostEnv djinns <- djinn True (Just minfo) env rty (Max 10) 100000 return (fourInts loc, map (doParen paren) $ nub (djinnsEmpty ++ djinns)) - + handler (SomeException _) = emptyResult =<< options -- Functions we do not want in completions From 2875275fc002eaedf4576d774c54d71a36f611ef Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 11:11:02 +0900 Subject: [PATCH 24/28] hlint suggestions. --- Language/Haskell/GhcMod/CabalApi.hs | 2 +- Language/Haskell/GhcMod/Check.hs | 2 +- Language/Haskell/GhcMod/FillSig.hs | 22 +++++++++++----------- Language/Haskell/GhcMod/Find.hs | 4 ++-- Language/Haskell/GhcMod/Monad.hs | 9 ++++----- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Language/Haskell/GhcMod/CabalApi.hs b/Language/Haskell/GhcMod/CabalApi.hs index 8483691..60cdb8a 100644 --- a/Language/Haskell/GhcMod/CabalApi.hs +++ b/Language/Haskell/GhcMod/CabalApi.hs @@ -76,7 +76,7 @@ parseCabalFile :: (MonadIO m, Error e, MonadError e m) => FilePath -> m PackageDescription parseCabalFile file = do - cid <- liftIO $ getGHCId + cid <- liftIO getGHCId epgd <- liftIO $ readPackageDescription silent file case toPkgDesc cid epgd of Left deps -> fail $ show deps ++ " are not installed" diff --git a/Language/Haskell/GhcMod/Check.hs b/Language/Haskell/GhcMod/Check.hs index 7ec5eb3..6d30f55 100644 --- a/Language/Haskell/GhcMod/Check.hs +++ b/Language/Haskell/GhcMod/Check.hs @@ -36,7 +36,7 @@ checkSyntax files = withErrorHandler sessionName $ check :: IOish m => [FilePath] -- ^ The target files. -> GhcModT m (Either String String) -check fileNames = overrideGhcUserOptions $ \ghcOpts -> do +check fileNames = overrideGhcUserOptions $ \ghcOpts -> withLogger (setAllWaringFlags . setNoMaxRelevantBindings) $ do _ <- G.setSessionDynFlags =<< addCmdOpts ghcOpts =<< G.getSessionDynFlags setTargetFiles fileNames diff --git a/Language/Haskell/GhcMod/FillSig.hs b/Language/Haskell/GhcMod/FillSig.hs index 213c047..e6646df 100644 --- a/Language/Haskell/GhcMod/FillSig.hs +++ b/Language/Haskell/GhcMod/FillSig.hs @@ -118,13 +118,13 @@ getSignature modSum lineNo colNo = do G.DataFamily -> Data #endif #if __GLASGOW_HASKELL__ >= 706 - getTyFamVarName = \x -> case x of - L _ (G.UserTyVar n) -> n - L _ (G.KindedTyVar n _) -> n + getTyFamVarName x = case x of + L _ (G.UserTyVar n) -> n + L _ (G.KindedTyVar n _) -> n #else - getTyFamVarName = \x -> case x of -- In GHC 7.4, HsTyVarBndr's have an extra arg - L _ (G.UserTyVar n _) -> n - L _ (G.KindedTyVar n _ _) -> n + getTyFamVarName x = case x of -- In GHC 7.4, HsTyVarBndr's have an extra arg + L _ (G.UserTyVar n _) -> n + L _ (G.KindedTyVar n _ _) -> n #endif in return $ Just (TyFamDecl loc name flavour $ map getTyFamVarName vars) _ -> return Nothing @@ -169,7 +169,7 @@ initialBody' fname args = initialHead fname args ++ " = " initialFamBody :: FnArgsInfo ty name => DynFlags -> PprStyle -> name -> [name] -> String initialFamBody dflag style name args = initialHead (getFnName dflag style name) - (map (\arg -> FnExplicitName (getFnName dflag style arg)) args) + (map (FnExplicitName . getFnName dflag style) args) ++ " = ()" initialHead :: String -> [FnArg] -> String @@ -298,7 +298,7 @@ findVar dflag style tcm tcs lineNo colNo = then let Just (s,t) = tyInfo b = case others of -- If inside an App, we need parenthesis [] -> False - (L _ (G.HsApp (L _ a1) (L _ a2))):_ -> + L _ (G.HsApp (L _ a1) (L _ a2)):_ -> isSearchedVar i a1 || isSearchedVar i a2 _ -> False in return $ Just (s, name, t, b) @@ -339,9 +339,9 @@ auto file lineNo colNo = ghandle handler body topLevel <- getEverythingInTopLevel minfo let (f,pats) = getPatsForVariable tcs (lineNo,colNo) -- Remove self function to prevent recursion, and id to trim cases - filterFn = (\(n,_) -> let funName = G.getOccString n - recName = G.getOccString (G.getName f) - in not $ funName `elem` recName:notWantedFuns) + filterFn (n,_) = let funName = G.getOccString n + recName = G.getOccString (G.getName f) + in funName `notElem` recName:notWantedFuns -- Find without using other functions in top-level localBnds = M.unions $ map (\(L _ pat) -> getBindingsForPat pat) pats lbn = filter filterFn (M.toList localBnds) diff --git a/Language/Haskell/GhcMod/Find.hs b/Language/Haskell/GhcMod/Find.hs index 7fb0b50..b713ec0 100644 --- a/Language/Haskell/GhcMod/Find.hs +++ b/Language/Haskell/GhcMod/Find.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE CPP, BangPatterns #-} +{-# LANGUAGE CPP #-} module Language.Haskell.GhcMod.Find #ifndef SPEC @@ -150,7 +150,7 @@ dumpSymbol = do writeSymbolCache :: FilePath -> [(Symbol,[ModuleString])] -> IO () -writeSymbolCache cache sm = do +writeSymbolCache cache sm = void . withFile cache WriteMode $ \hdl -> mapM (hPrint hdl) sm diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index eb1d860..52f63d1 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -1,7 +1,6 @@ {-# LANGUAGE CPP, GeneralizedNewtypeDeriving, FlexibleInstances #-} {-# LANGUAGE FlexibleContexts, MultiParamTypeClasses, RankNTypes #-} {-# LANGUAGE TypeFamilies, UndecidableInstances, RecordWildCards #-} -{-# LANGUAGE StandaloneDeriving #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Language.Haskell.GhcMod.Monad ( @@ -167,7 +166,7 @@ instance MonadTrans GhcModT where lift = GhcModT . lift . lift . lift . lift instance MonadState s m => MonadState s (GhcModT m) where - get = GhcModT $ lift $ lift $ lift $ get + get = GhcModT $ lift $ lift $ lift get put = GhcModT . lift . lift . lift . put state = GhcModT . lift . lift . lift . state @@ -271,9 +270,9 @@ runGhcModT' :: IOish m -> m (Either GhcModError (a, GhcModState), GhcModLog) runGhcModT' r s a = do (res, w') <- - flip runReaderT r $ runJournalT $ runErrorT $ flip runStateT s - $ (unGhcModT $ initGhcMonad (Just libdir) >> a) - return $ (res, w') + flip runReaderT r $ runJournalT $ runErrorT $ + runStateT (unGhcModT $ initGhcMonad (Just libdir) >> a) s + return (res, w') ---------------------------------------------------------------- withErrorHandler :: IOish m => String -> GhcModT m a -> GhcModT m a From d5733874e00d8c934f6d7e4d09470ded3fd4ec02 Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 11:14:46 +0900 Subject: [PATCH 25/28] using <$> --- Language/Haskell/GhcMod/Monad.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Language/Haskell/GhcMod/Monad.hs b/Language/Haskell/GhcMod/Monad.hs index 52f63d1..05a24fa 100644 --- a/Language/Haskell/GhcMod/Monad.hs +++ b/Language/Haskell/GhcMod/Monad.hs @@ -252,7 +252,7 @@ runGhcModT :: IOish m -> m (Either GhcModError a, GhcModLog) runGhcModT opt action = do env <- liftBase $ newGhcModEnv opt =<< getCurrentDirectory - first (fmap fst) <$> (runGhcModT' env defaultState $ do + first (fst <$>) <$> (runGhcModT' env defaultState $ do dflags <- getSessionDynFlags defaultCleanupHandler dflags $ do initializeFlagsWithCradle opt (gmCradle env) From bc4bfe17521a4540be609a3897b9da9f15c976a8 Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 12:03:59 +0900 Subject: [PATCH 26/28] -v option for ghc-mod (#304) --- src/GHCMod.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/GHCMod.hs b/src/GHCMod.hs index 84b8bbf..dc007f2 100644 --- a/src/GHCMod.hs +++ b/src/GHCMod.hs @@ -65,6 +65,9 @@ argspec = [ Option "l" ["tolisp"] , Option "g" ["ghcOpt"] (ReqArg (\g opts -> opts { ghcUserOptions = g : ghcUserOptions opts }) "ghcOpt") "GHC options" + , Option "v" ["verbose"] + (NoArg (\opts -> opts { ghcUserOptions = "-v" : ghcUserOptions opts })) + "verbose" , Option "o" ["operators"] (NoArg (\opts -> opts { operators = True })) "print operators, too" From 4f785d7f8a82c29f493851cab9e2633d80425e3c Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 14:13:09 +0900 Subject: [PATCH 27/28] Set Opt_DeferTypeErrors to rescure type errors. (#310) Type errors are turned to warnings. We force to turn them to the errors again. --- Language/Haskell/GhcMod/Check.hs | 2 +- Language/Haskell/GhcMod/Logger.hs | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Language/Haskell/GhcMod/Check.hs b/Language/Haskell/GhcMod/Check.hs index 6d30f55..ea2e28a 100644 --- a/Language/Haskell/GhcMod/Check.hs +++ b/Language/Haskell/GhcMod/Check.hs @@ -37,7 +37,7 @@ check :: IOish m => [FilePath] -- ^ The target files. -> GhcModT m (Either String String) check fileNames = overrideGhcUserOptions $ \ghcOpts -> - withLogger (setAllWaringFlags . setNoMaxRelevantBindings) $ do + withLogger (setAllWaringFlags . setNoMaxRelevantBindings . Gap.setWarnTypedHoles . Gap.setDeferTypeErrors) $ do _ <- G.setSessionDynFlags =<< addCmdOpts ghcOpts =<< G.getSessionDynFlags setTargetFiles fileNames diff --git a/Language/Haskell/GhcMod/Logger.hs b/Language/Haskell/GhcMod/Logger.hs index 0263561..d3b712b 100644 --- a/Language/Haskell/GhcMod/Logger.hs +++ b/Language/Haskell/GhcMod/Logger.hs @@ -105,7 +105,13 @@ ppMsg spn sev dflag style msg = prefix ++ cts (line,col,_,_) <- Gap.getSrcSpan spn file <- normalise <$> Gap.getSrcFile spn let severityCaption = Gap.showSeverityCaption sev - return $ file ++ ":" ++ show line ++ ":" ++ show col ++ ":" ++ severityCaption + pref0 + | typeWarning `isPrefixOf` cts = file ++ ":" ++ show line ++ ":" ++ show col ++ ":" + | otherwise = file ++ ":" ++ show line ++ ":" ++ show col ++ ":" ++ severityCaption + return pref0 + -- DeferTypeErrors turns a type error to a warning. + -- So, let's turns it the error again. + typeWarning = "Couldn't match expected type" checkErrorPrefix :: String checkErrorPrefix = "Dummy:0:0:Error:" From 8606316d8428c71ee565a95d500398dc33392791 Mon Sep 17 00:00:00 2001 From: Kazu Yamamoto Date: Thu, 14 Aug 2014 16:42:05 +0900 Subject: [PATCH 28/28] one more type error to be rescued. --- Language/Haskell/GhcMod/Logger.hs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Language/Haskell/GhcMod/Logger.hs b/Language/Haskell/GhcMod/Logger.hs index d3b712b..9e78fb5 100644 --- a/Language/Haskell/GhcMod/Logger.hs +++ b/Language/Haskell/GhcMod/Logger.hs @@ -106,12 +106,14 @@ ppMsg spn sev dflag style msg = prefix ++ cts file <- normalise <$> Gap.getSrcFile spn let severityCaption = Gap.showSeverityCaption sev pref0 - | typeWarning `isPrefixOf` cts = file ++ ":" ++ show line ++ ":" ++ show col ++ ":" - | otherwise = file ++ ":" ++ show line ++ ":" ++ show col ++ ":" ++ severityCaption + | typeWarning1 `isPrefixOf` cts || + typeWarning2 `isPrefixOf` cts = file ++ ":" ++ show line ++ ":" ++ show col ++ ":" + | otherwise = file ++ ":" ++ show line ++ ":" ++ show col ++ ":" ++ severityCaption return pref0 -- DeferTypeErrors turns a type error to a warning. -- So, let's turns it the error again. - typeWarning = "Couldn't match expected type" + typeWarning1 = "Couldn't match expected type" + typeWarning2 = "Couldn't match type" checkErrorPrefix :: String checkErrorPrefix = "Dummy:0:0:Error:"