Merge branch 'master' into release
This commit is contained in:
commit
ac4fadf0d0
@ -71,8 +71,8 @@ getSrcSpanTypeForFnSplit :: GhcMonad m => G.ModSummary -> Int -> Int -> m (Maybe
|
|||||||
getSrcSpanTypeForFnSplit modSum lineNo colNo = do
|
getSrcSpanTypeForFnSplit modSum lineNo colNo = do
|
||||||
p@ParsedModule{pm_parsed_source = _pms} <- G.parseModule modSum
|
p@ParsedModule{pm_parsed_source = _pms} <- G.parseModule modSum
|
||||||
tcm@TypecheckedModule{tm_typechecked_source = tcs} <- G.typecheckModule p
|
tcm@TypecheckedModule{tm_typechecked_source = tcs} <- G.typecheckModule p
|
||||||
let varPat = find isPatternVar $ listifySpans tcs (lineNo, colNo) :: Maybe (LPat Id)
|
let varPat = find isPatternVar $ listifySpans tcs (lineNo, colNo) :: Maybe (LPat Id)
|
||||||
match:_ = listifySpans tcs (lineNo, colNo) :: [Gap.GLMatchI]
|
match = last $ listifySpans tcs (lineNo, colNo) :: Gap.GLMatchI
|
||||||
case varPat of
|
case varPat of
|
||||||
Nothing -> return Nothing
|
Nothing -> return Nothing
|
||||||
Just varPat' -> do
|
Just varPat' -> do
|
||||||
@ -188,8 +188,11 @@ getCaseSplitText text (SplitToTextInfo { sVarName = sVN, sBindingSpan = sBS
|
|||||||
, sVarSpan = sVS, sTycons = sT }) =
|
, sVarSpan = sVS, sTycons = sT }) =
|
||||||
let bindingText = getBindingText text sBS
|
let bindingText = getBindingText text sBS
|
||||||
difference = srcSpanDifference sBS sVS
|
difference = srcSpanDifference sBS sVS
|
||||||
replaced = concatMap (replaceVarWithTyCon bindingText difference sVN) sT
|
replaced = map (replaceVarWithTyCon bindingText difference sVN) sT
|
||||||
in T.unpack $ T.intercalate (T.pack "\n") replaced
|
-- The newly generated bindings need to be indented to align with the
|
||||||
|
-- original binding.
|
||||||
|
replaced' = head replaced : map (indentBindingTo sBS) (tail replaced)
|
||||||
|
in T.unpack $ T.intercalate (T.pack "\n") (concat replaced')
|
||||||
|
|
||||||
getBindingText :: [T.Text] -> SrcSpan -> [T.Text]
|
getBindingText :: [T.Text] -> SrcSpan -> [T.Text]
|
||||||
getBindingText text srcSpan =
|
getBindingText text srcSpan =
|
||||||
@ -220,3 +223,9 @@ replaceVarWithTyCon text (vsl,vsc,_,vec) varname tycon =
|
|||||||
then T.take vsc line `T.append` tycon'' `T.append` T.drop vec line
|
then T.take vsc line `T.append` tycon'' `T.append` T.drop vec line
|
||||||
else T.replicate spacesToAdd (T.pack " ") `T.append` line)
|
else T.replicate spacesToAdd (T.pack " ") `T.append` line)
|
||||||
[0 ..] text
|
[0 ..] text
|
||||||
|
|
||||||
|
indentBindingTo :: SrcSpan -> [T.Text] -> [T.Text]
|
||||||
|
indentBindingTo bndLoc binds =
|
||||||
|
let Just (_,sl,_,_) = Gap.getSrcSpan bndLoc
|
||||||
|
indent = (T.replicate (sl - 1) (T.pack " ") `T.append`)
|
||||||
|
in indent (head binds) : tail binds
|
||||||
|
@ -32,7 +32,7 @@ cleanupCradle crdl = removeDirectoryRecursive $ cradleTempDir crdl
|
|||||||
|
|
||||||
cabalCradle :: FilePath -> IO Cradle
|
cabalCradle :: FilePath -> IO Cradle
|
||||||
cabalCradle wdir = do
|
cabalCradle wdir = do
|
||||||
Just cabalFile <- findCabalFiles wdir
|
Just cabalFile <- findCabalFile wdir
|
||||||
let cabalDir = takeDirectory cabalFile
|
let cabalDir = takeDirectory cabalFile
|
||||||
pkgDbStack <- getPackageDbStack cabalDir
|
pkgDbStack <- getPackageDbStack cabalDir
|
||||||
tmpDir <- newTempDir cabalDir
|
tmpDir <- newTempDir cabalDir
|
||||||
|
@ -30,8 +30,9 @@ data GhcModError = GMENoMsg
|
|||||||
-- ^ Launching an operating system process failed. The first
|
-- ^ Launching an operating system process failed. The first
|
||||||
-- field is the command.
|
-- field is the command.
|
||||||
| GMENoCabalFile
|
| GMENoCabalFile
|
||||||
|
-- ^ No cabal file found.
|
||||||
| GMETooManyCabalFiles [FilePath]
|
| GMETooManyCabalFiles [FilePath]
|
||||||
-- ^ No or too many cabal files found.
|
-- ^ Too many cabal files found.
|
||||||
deriving (Eq,Show,Typeable)
|
deriving (Eq,Show,Typeable)
|
||||||
|
|
||||||
instance Exception GhcModError
|
instance Exception GhcModError
|
||||||
|
@ -99,7 +99,7 @@ import Control.Monad.Error (Error(..))
|
|||||||
#endif
|
#endif
|
||||||
import Control.Monad.Journal.Class
|
import Control.Monad.Journal.Class
|
||||||
|
|
||||||
import Data.Maybe (fromJust, isJust)
|
import Data.Maybe (isJust)
|
||||||
import Data.IORef (IORef, readIORef, writeIORef, newIORef)
|
import Data.IORef (IORef, readIORef, writeIORef, newIORef)
|
||||||
import System.Directory (getCurrentDirectory)
|
import System.Directory (getCurrentDirectory)
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ instance MonadIO m => MonadIO (GhcModT m) where
|
|||||||
|
|
||||||
where
|
where
|
||||||
fromEx :: Exception e => SomeException -> e
|
fromEx :: Exception e => SomeException -> e
|
||||||
fromEx = fromJust . fromException
|
fromEx se = let Just e = fromException se in e
|
||||||
isIOError se =
|
isIOError se =
|
||||||
case fromException se of
|
case fromException se of
|
||||||
Just (_ :: IOError) -> True
|
Just (_ :: IOError) -> True
|
||||||
@ -221,7 +221,8 @@ initializeFlagsWithCradle opt c
|
|||||||
cabal = isJust mCabalFile
|
cabal = isJust mCabalFile
|
||||||
ghcopts = ghcUserOptions opt
|
ghcopts = ghcUserOptions opt
|
||||||
withCabal = do
|
withCabal = do
|
||||||
pkgDesc <- parseCabalFile c $ fromJust mCabalFile
|
let Just cabalFile = mCabalFile
|
||||||
|
pkgDesc <- parseCabalFile c cabalFile
|
||||||
compOpts <- getCompilerOptions ghcopts c pkgDesc
|
compOpts <- getCompilerOptions ghcopts c pkgDesc
|
||||||
initSession CabalPkg opt compOpts
|
initSession CabalPkg opt compOpts
|
||||||
withSandbox = initSession SingleFile opt compOpts
|
withSandbox = initSession SingleFile opt compOpts
|
||||||
|
@ -28,24 +28,32 @@ type FileName = String
|
|||||||
-- is assumed to be the project directory. If only one cabal file exists in this
|
-- is assumed to be the project directory. If only one cabal file exists in this
|
||||||
-- directory it is returned otherwise @findCabalFiles@ throws 'GMENoCabalFile'
|
-- directory it is returned otherwise @findCabalFiles@ throws 'GMENoCabalFile'
|
||||||
-- or 'GMETooManyCabalFiles'
|
-- or 'GMETooManyCabalFiles'
|
||||||
findCabalFiles :: FilePath -> IO (Maybe FilePath)
|
findCabalFile :: FilePath -> IO (Maybe FilePath)
|
||||||
findCabalFiles directory = do
|
findCabalFile directory = do
|
||||||
-- Look for cabal files in all parent directories of @dir@
|
-- Look for cabal files in @dir@ and all it's parent directories
|
||||||
dcs <- getCabalFiles `zipMapM` parents directory
|
dcs <- getCabalFiles `zipMapM` parents directory
|
||||||
-- Extract first non-empty list, which represents a directory with cabal
|
-- Extract first non-empty list, which represents a directory with cabal
|
||||||
-- files.
|
-- files.
|
||||||
case find (not . null) $ uncurry makeAbsolute `map` dcs of
|
case find (not . null) $ uncurry appendDir `map` dcs of
|
||||||
Just [] -> throw $ GMENoCabalFile
|
Just [] -> throw $ GMENoCabalFile
|
||||||
Just cfs@(_:_:_) -> throw $ GMETooManyCabalFiles cfs
|
Just cfs@(_:_:_) -> throw $ GMETooManyCabalFiles cfs
|
||||||
a -> return $ head <$> a
|
a -> return $ head <$> a
|
||||||
|
where
|
||||||
|
appendDir :: DirPath -> [FileName] -> [FilePath]
|
||||||
|
appendDir dir fs = (dir </>) `map` fs
|
||||||
|
|
||||||
-- | @getCabalFiles dir@. Find all files ending in @.cabal@ in @dir@.
|
-- | @getCabalFiles dir@. Find all files ending in @.cabal@ in @dir@.
|
||||||
getCabalFiles :: DirPath -> IO [FileName]
|
getCabalFiles :: DirPath -> IO [FileName]
|
||||||
getCabalFiles dir =
|
getCabalFiles dir =
|
||||||
filter ((==) ".cabal" . takeExtension) <$> getDirectoryContents dir
|
filterM isCabalFile =<< getDirectoryContents dir
|
||||||
|
where
|
||||||
|
isCabalFile f = do
|
||||||
|
exists <- doesFileExist $ dir </> f
|
||||||
|
return (exists && takeExtension' f == ".cabal")
|
||||||
|
|
||||||
makeAbsolute :: DirPath -> [FileName] -> [FilePath]
|
takeExtension' p = if takeFileName p == takeExtension p
|
||||||
makeAbsolute dir fs = (dir </>) `map` fs
|
then ""
|
||||||
|
else takeExtension p
|
||||||
|
|
||||||
zipMapM :: Monad m => (a -> m c) -> [a] -> m [(a,c)]
|
zipMapM :: Monad m => (a -> m c) -> [a] -> m [(a,c)]
|
||||||
zipMapM f as = mapM (\a -> liftM (a,) $ f a) as
|
zipMapM f as = mapM (\a -> liftM (a,) $ f a) as
|
||||||
|
@ -127,7 +127,7 @@
|
|||||||
(defun ghc-expand-th ()
|
(defun ghc-expand-th ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(let* ((file (buffer-file-name))
|
(let* ((file (buffer-file-name))
|
||||||
(cmds (list "expand" file "-b" "\n"))
|
(cmds (list "expand" file))
|
||||||
(source (ghc-run-ghc-mod cmds)))
|
(source (ghc-run-ghc-mod cmds)))
|
||||||
(when source
|
(when source
|
||||||
(ghc-display
|
(ghc-display
|
||||||
|
@ -34,6 +34,7 @@ Extra-Source-Files: ChangeLog
|
|||||||
test/data/broken-cabal/cabal.sandbox.config.in
|
test/data/broken-cabal/cabal.sandbox.config.in
|
||||||
test/data/broken-sandbox/*.cabal
|
test/data/broken-sandbox/*.cabal
|
||||||
test/data/broken-sandbox/cabal.sandbox.config
|
test/data/broken-sandbox/cabal.sandbox.config
|
||||||
|
test/data/case-split/*.hs
|
||||||
test/data/cabal-flags/*.cabal
|
test/data/cabal-flags/*.cabal
|
||||||
test/data/check-test-subdir/*.cabal
|
test/data/check-test-subdir/*.cabal
|
||||||
test/data/check-test-subdir/src/Check/Test/*.hs
|
test/data/check-test-subdir/src/Check/Test/*.hs
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
module CabalApiSpec where
|
module CabalApiSpec where
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Data.Maybe
|
|
||||||
import Language.Haskell.GhcMod.CabalApi
|
import Language.Haskell.GhcMod.CabalApi
|
||||||
import Language.Haskell.GhcMod.Cradle
|
import Language.Haskell.GhcMod.Cradle
|
||||||
import Language.Haskell.GhcMod.Types
|
import Language.Haskell.GhcMod.Types
|
||||||
@ -35,7 +34,8 @@ spec = do
|
|||||||
cwd <- getCurrentDirectory
|
cwd <- getCurrentDirectory
|
||||||
withDirectory "test/data/subdir1/subdir2" $ \dir -> do
|
withDirectory "test/data/subdir1/subdir2" $ \dir -> do
|
||||||
crdl <- findCradle
|
crdl <- findCradle
|
||||||
pkgDesc <- runD $ parseCabalFile crdl $ fromJust $ cradleCabalFile crdl
|
let Just cabalFile = cradleCabalFile crdl
|
||||||
|
pkgDesc <- runD $ parseCabalFile crdl cabalFile
|
||||||
res <- runD $ getCompilerOptions [] crdl pkgDesc
|
res <- runD $ getCompilerOptions [] crdl pkgDesc
|
||||||
let res' = res {
|
let res' = res {
|
||||||
ghcOptions = ghcOptions res
|
ghcOptions = ghcOptions res
|
||||||
|
@ -18,3 +18,24 @@ spec = do
|
|||||||
res `shouldBe` "24 1 24 30"++
|
res `shouldBe` "24 1 24 30"++
|
||||||
" \"mlAppend Nil y = _mlAppend_body\NUL"++
|
" \"mlAppend Nil y = _mlAppend_body\NUL"++
|
||||||
"mlAppend (Cons x1 x2) y = _mlAppend_body\"\n"
|
"mlAppend (Cons x1 x2) y = _mlAppend_body\"\n"
|
||||||
|
|
||||||
|
it "works with case expressions" $ do
|
||||||
|
withDirectory_ "test/data/case-split" $ do
|
||||||
|
res <- runD $ splits "Vect.hs" 28 20
|
||||||
|
res `shouldBe` "28 19 28 39"++
|
||||||
|
" \"Nil -> _mlAppend_body\NUL"++
|
||||||
|
" (Cons x'1 x'2) -> _mlAppend_body\"\n"
|
||||||
|
|
||||||
|
it "works with where clauses" $ do
|
||||||
|
withDirectory_ "test/data/case-split" $ do
|
||||||
|
res <- runD $ splits "Vect.hs" 34 17
|
||||||
|
res `shouldBe` "34 5 34 43"++
|
||||||
|
" \"mlReverse' Nil accum = _mlReverse_body\NUL"++
|
||||||
|
" mlReverse' (Cons xs'1 xs'2) accum = _mlReverse_body\"\n"
|
||||||
|
|
||||||
|
it "works with let bindings" $ do
|
||||||
|
withDirectory_ "test/data/case-split" $ do
|
||||||
|
res <- runD $ splits "Vect.hs" 38 33
|
||||||
|
res `shouldBe` "38 21 38 59"++
|
||||||
|
" \"mlReverse' Nil accum = _mlReverse_body\NUL"++
|
||||||
|
" mlReverse' (Cons xs'1 xs'2) accum = _mlReverse_body\"\n"
|
||||||
|
@ -8,6 +8,7 @@ import Language.Haskell.GhcMod.GhcPkg
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
import System.Directory
|
import System.Directory
|
||||||
|
import System.Environment
|
||||||
import System.FilePath ((</>))
|
import System.FilePath ((</>))
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
|
|
||||||
@ -28,3 +29,14 @@ spec = do
|
|||||||
|
|
||||||
it "returns Nothing if the sandbox config file is broken" $ do
|
it "returns Nothing if the sandbox config file is broken" $ do
|
||||||
getSandboxDb "test/data/broken-sandbox" `shouldReturn` Nothing
|
getSandboxDb "test/data/broken-sandbox" `shouldReturn` Nothing
|
||||||
|
|
||||||
|
describe "getCabalFiles" $ do
|
||||||
|
it "doesn't think $HOME/.cabal is a cabal file" $ do
|
||||||
|
(getCabalFiles =<< getEnv "HOME") `shouldReturn` []
|
||||||
|
|
||||||
|
describe "findCabalFile" $ do
|
||||||
|
it "works" $ do
|
||||||
|
findCabalFile "test/data" `shouldReturn` Just "test/data/cabalapi.cabal"
|
||||||
|
|
||||||
|
it "finds cabal files in parent directories" $ do
|
||||||
|
findCabalFile "test/data/subdir1/subdir2" `shouldReturn` Just "test/data/cabalapi.cabal"
|
||||||
|
@ -22,3 +22,18 @@ data MyList a = Nil | Cons a (MyList a)
|
|||||||
|
|
||||||
mlAppend :: MyList a -> MyList a -> MyList a
|
mlAppend :: MyList a -> MyList a -> MyList a
|
||||||
mlAppend x y = _mlAppend_body
|
mlAppend x y = _mlAppend_body
|
||||||
|
|
||||||
|
mlAppend2 :: MyList a -> MyList a -> MyList a
|
||||||
|
mlAppend2 x y = case x of
|
||||||
|
x' -> _mlAppend_body
|
||||||
|
|
||||||
|
mlReverse :: MyList a -> MyList a
|
||||||
|
mlReverse xs = mlReverse' xs Nil
|
||||||
|
where
|
||||||
|
mlReverse' :: MyList a -> MyList a -> MyList a
|
||||||
|
mlReverse' xs' accum = _mlReverse_body
|
||||||
|
|
||||||
|
mlReverse2 :: MyList a -> MyList a
|
||||||
|
mlReverse2 xs = let mlReverse' :: MyList a -> MyList a -> MyList a
|
||||||
|
mlReverse' xs' accum = _mlReverse_body
|
||||||
|
in mlReverse' xs Nil
|
||||||
|
Loading…
Reference in New Issue
Block a user