ghcid 0.6.5 → 0.6.6
raw patch · 8 files changed
+70/−26 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Language.Haskell.Ghcid: instance GHC.Classes.Eq Language.Haskell.Ghcid.Ghci
Files
- CHANGES.txt +5/−0
- README.md +4/−0
- ghcid.cabal +2/−2
- src/Ghcid.hs +12/−9
- src/Language/Haskell/Ghcid.hs +7/−1
- src/Language/Haskell/Ghcid/Terminal.hs +7/−2
- src/Session.hs +32/−11
- src/Test/Ghcid.hs +1/−1
CHANGES.txt view
@@ -1,5 +1,10 @@ Changelog for ghcid +0.6.6+ #89, exit sooner when the child process exits unexpectedly+ Add Eq instance for Ghci+ #88, add a --project flag+ Rename --notitle flag to --no-title 0.6.5 #82, properly deal with warning messages including spans #78, support boot files better
README.md view
@@ -31,6 +31,10 @@ Please [report any bugs](https://github.com/ndmitchell/ghcid/issues) you find. +### Ghcid Integration++There are a few tools that integrate Ghcid into editors, see the [plugins](plugins/) folder for currently supported integrations.+ ### FAQ * _This isn't as good as full IDE._ I've gone for simplicity over features. It's a point in the design space, but not necessarily the best point in the design space for you. For "real" IDEs see [the Haskell wiki](http://www.haskell.org/haskellwiki/IDEs).
ghcid.cabal view
@@ -1,7 +1,7 @@-cabal-version: >= 1.10+cabal-version: >= 1.18 build-type: Simple name: ghcid-version: 0.6.5+version: 0.6.6 license: BSD3 license-file: LICENSE category: Development
src/Ghcid.hs view
@@ -36,11 +36,12 @@ ,arguments :: [String] ,test :: [String] ,warnings :: Bool- ,nostatus :: Bool+ ,no_status :: Bool ,height :: Maybe Int ,width :: Maybe Int ,topmost :: Bool- ,notitle :: Bool+ ,no_title :: Bool+ ,project :: String ,reload :: [FilePath] ,restart :: [FilePath] ,directory :: FilePath@@ -54,11 +55,12 @@ ,arguments = [] &= args &= typ "MODULE" ,test = [] &= name "T" &= typ "EXPR" &= help "Command to run after successful loading" ,warnings = False &= name "W" &= help "Allow tests to run even with warnings"- ,nostatus = False &= name "S" &= explicit &= name "no-status" &= help "Suppress status messages"+ ,no_status = False &= name "S" &= help "Suppress status messages" ,height = Nothing &= help "Number of lines to use (defaults to console height)" ,width = Nothing &= name "w" &= help "Number of columns to use (defaults to console width)" ,topmost = False &= name "t" &= help "Set window topmost (Windows only)"- ,notitle = False &= help "Don't update the shell title/icon"+ ,no_title = False &= help "Don't update the shell title/icon"+ ,project = "" &= typ "NAME" &= help "Name of the project, defaults to current directory" ,restart = [] &= typ "PATH" &= help "Restart the command when the given file or directory contents change (defaults to .ghci and any .cabal file)" ,reload = [] &= typ "PATH" &= help "Reload when the given file or directory contents change (defaults to none)" ,directory = "." &= typDir &= name "C" &= help "Set the current directory"@@ -192,14 +194,15 @@ if null test || countErrors /= 0 || (countWarnings /= 0 && not warnings) then Nothing else Just $ intercalate "\n" test - unless notitle $ setWindowIcon $+ unless no_title $ setWindowIcon $ if countErrors > 0 then IconError else if countWarnings > 0 then IconWarning else IconOK - let updateTitle extra = unless notitle $ setTitle $+ let updateTitle extra = unless no_title $ setTitle $ let f n msg = if n == 0 then "" else show n ++ " " ++ msg ++ ['s' | n > 1] in (if countErrors == 0 && countWarnings == 0 then allGoodMessage else f countErrors "error" ++- (if countErrors > 0 && countWarnings > 0 then ", " else "") ++ f countWarnings "warning") ++- " " ++ extra ++ [' ' | extra /= ""] ++ "- " ++ takeFileName curdir+ (if countErrors > 0 && countWarnings > 0 then ", " else "") ++ f countWarnings "warning") +++ " " ++ extra ++ [' ' | extra /= ""] ++ "- " +++ (if null project then takeFileName curdir else project) updateTitle $ if isJust test then "(running test)" else "" outputFill (Just (loadedCount, messages)) ["Running test..." | isJust test]@@ -220,7 +223,7 @@ updateTitle "(test done)" reason <- nextWait $ restart ++ reload ++ loaded- unless nostatus $ outputFill Nothing $ "Reloading..." : map (" " ++) reason+ unless no_status $ outputFill Nothing $ "Reloading..." : map (" " ++) reason restartTimes2 <- mapM getModTime restart if restartTimes == restartTimes2 then do nextWait <- waitFiles waiter
src/Language/Haskell/Ghcid.hs view
@@ -20,6 +20,7 @@ import Data.Maybe import Data.IORef import Control.Applicative+import Data.Unique import System.Console.CmdArgs.Verbosity @@ -37,8 +38,12 @@ data Ghci = Ghci {ghciProcess :: ProcessHandle ,ghciInterrupt :: IO ()- ,ghciExec :: String -> (Stream -> String -> IO ()) -> IO ()}+ ,ghciExec :: String -> (Stream -> String -> IO ()) -> IO ()+ ,ghciUnique :: Unique+ } +instance Eq Ghci where+ a == b = ghciUnique a == ghciUnique b -- | Start GHCi, returning a function to perform further operation, as well as the result of the initial loading. -- If you do not call 'stopGhci' then the underlying process may be leaked.@@ -132,6 +137,7 @@ stop <- syncFresh void $ consume2 "Interrupt" $ \_ s -> return $ if stop s then Just () else Nothing + ghciUnique <- newUnique let ghci = Ghci{..} -- Now wait for 'GHCi, version' to appear before sending anything real, required for #57
src/Language/Haskell/Ghcid/Terminal.hs view
@@ -24,11 +24,16 @@ iCON_BIG = 1 iCON_SMALL = 0 +#ifdef x86_64_HOST_ARCH+#define CALLCONV ccall+#else+#define CALLCONV stdcall+#endif -foreign import stdcall unsafe "windows.h GetConsoleWindow"+foreign import CALLCONV unsafe "windows.h GetConsoleWindow" getConsoleWindow :: IO HWND -foreign import stdcall unsafe "windows.h SetWindowPos"+foreign import CALLCONV unsafe "windows.h SetWindowPos" setWindowPos :: HWND -> HWND -> Int -> Int -> Int -> Int -> Word32 -> IO Bool #endif
src/Session.hs view
@@ -27,14 +27,11 @@ ,command :: IORef (Maybe String) -- ^ The last command passed to sessionStart ,warnings :: IORef [Load] -- ^ The warnings from the last load ,running :: Var Bool -- ^ Am I actively running an async command+ ,withThread :: ThreadId -- ^ Thread that called withSession } --- | Ensure an action runs off the main thread, so can't get hit with Ctrl-C exceptions.--- Disabled because it plays havoc with tests and cleaning up quickly enough.-ctrlC :: IO a -> IO a-ctrlC = id -- join . onceFork-+debugShutdown x = when False $ print ("DEBUG SHUTDOWN", x) -- | The function 'withSession' expects to be run on the main thread, -- but the inner function will not. This ensures Ctrl-C is handled@@ -45,18 +42,28 @@ command <- newIORef Nothing warnings <- newIORef [] running <- newVar False- ctrlC (f Session{..}) `finally` do+ debugShutdown "Starting session"+ withThread <- myThreadId+ f Session{..} `finally` do+ debugShutdown "Start finally" modifyVar_ running $ const $ return False whenJustM (readIORef ghci) $ \v -> do writeIORef ghci Nothing- ctrlC $ kill v+ debugShutdown "Calling kill"+ kill v+ debugShutdown "Finish finally" -- | Kill. Wait just long enough to ensure you've done the job, but not to see the results. kill :: Ghci -> IO () kill ghci = ignore $ do- timeout 5 $ quit ghci+ timeout 5 $ do+ debugShutdown "Before quit"+ ignore $ quit ghci+ debugShutdown "After quit"+ debugShutdown "Before terminateProcess" terminateProcess $ process ghci+ debugShutdown "After terminateProcess" -- | Spawn a new Ghci process at a given command line. Returns the load messages, plus@@ -65,12 +72,26 @@ sessionStart Session{..} cmd = do modifyVar_ running $ const $ return False writeIORef command $ Just cmd- val <- readIORef ghci- whenJust val $ void . forkIO . kill- writeIORef ghci Nothing++ -- cleanup any old instances+ whenJustM (readIORef ghci) $ \v -> do+ writeIORef ghci Nothing+ void $ forkIO $ kill v++ -- start the new outStrLn $ "Loading " ++ cmd ++ " ..." (v, messages) <- startGhci cmd Nothing $ const outStrLn writeIORef ghci $ Just v++ -- install a handler+ forkIO $ do+ waitForProcess $ process v+ whenJustM (readIORef ghci) $ \ghci ->+ when (ghci == v) $ do+ sleep 0.3 -- give anyone reading from the stream a chance to throw first+ throwTo withThread $ ErrorCall $ "Command \"" ++ cmd ++ "\" exited unexpectedly"++ -- handle what the process returned messages <- return $ mapMaybe tidyMessage messages writeIORef warnings [m | m@Message{..} <- messages, loadSeverity == Warning] return (messages, nubOrd $ map loadFile messages)
src/Test/Ghcid.hs view
@@ -71,7 +71,7 @@ done <- newBarrier res <- bracket (flip forkFinally (const $ signalBarrier done ()) $- withArgs (["--notitle","--no-status"]++args) $+ withArgs (["--no-title","--no-status"]++args) $ mainWithTerminal (return (100, 50)) output) killThread $ \_ -> script require waitBarrier done