ghcid 0.7 → 0.7.1
raw patch · 8 files changed
+40/−23 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGES.txt +6/−0
- README.md +9/−6
- ghcid.cabal +2/−2
- src/Ghcid.hs +9/−7
- src/Language/Haskell/Ghcid.hs +2/−1
- src/Session.hs +1/−1
- src/Test/API.hs +2/−2
- src/Wait.hs +9/−4
CHANGES.txt view
@@ -1,5 +1,11 @@ Changelog for ghcid (* = breaking change) +0.7.1, released 2018-09-07+ #190, load benchmarks as well as tests when using stack+ #171, support GHCJSi+ #163, allow --run, like --test but defaults to main+ #161, if a file disappears, reload as soon as it returns+ #162, always disable :set +t (which writes out types) 0.7, released 2018-04-18 #153, show errors/warnings to freshly edited files first #153, set -j
README.md view
@@ -1,4 +1,4 @@-# ghcid [](https://hackage.haskell.org/package/ghcid) [](https://www.stackage.org/package/ghcid) [](https://travis-ci.org/ndmitchell/ghcid) [](https://ci.appveyor.com/project/ndmitchell/ghcid)+# ghcid [](https://hackage.haskell.org/package/ghcid) [](https://www.stackage.org/package/ghcid) [](https://travis-ci.org/ndmitchell/ghcid) [](https://ci.appveyor.com/project/ndmitchell/ghcid) Either "GHCi as a daemon" or "GHC + a bit of an IDE". To a first approximation, it opens `ghci` and runs `:reload` whenever your source code changes, formatting the output to fit a fixed height console. Unlike other Haskell development tools, `ghcid` is intended to be _incredibly simple_. In particular, it doesn't integrate with any editors, doesn't depend on GHC the library and doesn't start web servers. @@ -6,7 +6,7 @@ ### Using it -Run `cabal update && cabal install ghcid` to install it as normal. Then run `ghcid "--command=ghci Main.hs"`. The `command` is how you start your project in `ghci`. If you omit `--command` then it will default to `stack ghci` if you have the `stack.yaml` file and `.stack-work` directory, default to `ghci` if you have a `.ghci` file in the current directory, and otherwise default to `cabal repl`.+Run `stack install ghcid` or `cabal update && cabal install ghcid` to install it as normal. Then run `ghcid "--command=ghci Main.hs"`. The `command` is how you start your project in `ghci`. If you omit `--command` then it will default to `stack ghci` if you have the `stack.yaml` file and `.stack-work` directory, default to `ghci` if you have a `.ghci` file in the current directory, and otherwise default to `cabal repl`. Personally, I always create a `.ghci` file at the root of all my projects, which usually [reads something like](https://github.com/ndmitchell/ghcid/blob/master/.ghci): @@ -31,7 +31,7 @@ Please [report any bugs](https://github.com/ndmitchell/ghcid/issues) you find. -### Ghcid Integration+### Editor integration There are a few plugins that integrate Ghcid into editors, notably: @@ -39,9 +39,11 @@ * [nvim](plugins/nvim/) * [Emacs](plugins/emacs/) -And a blog article on using it:+### Usage tips -* [Auto-reload threepenny-gui apps during development](https://binarin.ru/post/auto-reload-threepenny-gui/)+* If you have a `.ghcid` file in the current folder, or a parent folder, the contents of that file will be used as command line arguments. For example, if you always want to pass `--command=custom-ghci` then putting that in a `.ghcid` file will free you from writing it each time.+* There is an article on [auto-reloading threepenny-gui apps during development](https://binarin.ru/post/auto-reload-threepenny-gui/).+* There are a list of [general tips for using Ghcid](http://www.parsonsmatt.org/2018/05/19/ghcid_for_the_win.html). ### FAQ @@ -50,6 +52,7 @@ * _I want to run my tests when files change._ You can pass any `ghci` expression with the `--test` flag, e.g. `--test=:main`, which will be run whenever the code is warning free (or pass `--warnings` for when the code is merely error free). * _I want to run arbitrary commands when arbitrary files change._ This project reloads `ghci` when files loaded by `ghci` change. If you want a more general mechanism something like [Steel Overseer](https://github.com/schell/steeloverseer) or [Watchman](https://facebook.github.io/watchman/) will probably work better. * _I want syntax highlighting in the error messages._ One option is to use Neovim or Emacs and run the terminal in a buffer whose file type is set to Haskell. Another option is to pipe `ghcid` through [source-highlight](https://www.gnu.org/software/src-highlite/) (`ghcid | source-highlight -s haskell -f esc`).-* _I'm not seeing pattern matching warnings._ Ghcid automatically appends `-fno-code` to the command line, which makes the reload cycle about twice as fast. Unfortunately GHC 8.0 suffers from [bug 10600](https://ghc.haskell.org/trac/ghc/ticket/10600) which means `-fno-code` also disables pattern matching warnings. Until that GHC bug is fixed either accept no pattern match warnings or use `-c` to specify a command line to start `ghci` that doesn't include `-fno-code`.+* _I'm not seeing pattern matching warnings._ Ghcid automatically appends `-fno-code` to the command line, which makes the reload cycle about twice as fast. Unfortunately GHC 8.0 and 8.2 suffer from [bug 10600](https://ghc.haskell.org/trac/ghc/ticket/10600) which means `-fno-code` also disables pattern matching warnings. On these versions, either accept no pattern match warnings or use `-c` to specify a command line to start `ghci` that doesn't include `-fno-code`. From GHC 8.4 this problem no longer exists. * _I get "During interactive linking, GHCi couldn't find the following symbol"._ This problem is a manifestation of [GHC bug 8025](https://ghc.haskell.org/trac/ghc/ticket/8025), which is fixed in GHC 8.4 and above. Ghcid automatically appends `-fno-code` to the command line, but for older GHC's you can supress that with `--test "return ()"` (to add a fake test) or `-c "ghci ..."` to manually specify the command to run. * _I only see source-spans or error messages on errors/warnings after the first load._ Due to limitations in `ghci`, these flags are only set _after_ the first load. If you want them to apply from the start, pass them on the command line to `ghci` with something like `-c "ghci -ferror-spans -fdiagnostics-color=always".+* _I want to match on the file/line/column to get jump-to-error functionality in my editor._ You will variously see `file:line:col:message`, `file:line:col1-col2:msg` and `file:(line1,col1)-(line2,col2):message`, as these are the formats GHC uses. To match all of them you can use a regular expression such as `^(\\S*?):(?|(\\d+):(\\d+)(?:-\\d+)?|\\((\\d+),(\\d+)\\)-\\(\\d+,\\d+\\)):([^\n]*)`.
ghcid.cabal view
@@ -1,7 +1,7 @@ cabal-version: >= 1.18 build-type: Simple name: ghcid-version: 0.7+version: 0.7.1 license: BSD3 license-file: LICENSE category: Development@@ -13,7 +13,7 @@ Either \"GHCi as a daemon\" or \"GHC + a bit of an IDE\". A very simple Haskell development tool which shows you the errors in your project and updates them whenever you save. Run @ghcid --topmost --command=ghci@, where @--topmost@ makes the window on top of all others (Windows only) and @--command@ is the command to start GHCi on your project (defaults to @ghci@ if you have a @.ghci@ file, or else to @cabal repl@). homepage: https://github.com/ndmitchell/ghcid#readme bug-reports: https://github.com/ndmitchell/ghcid/issues-tested-with: GHC==8.4.1, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4+tested-with: GHC==8.4.3, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4 extra-doc-files: CHANGES.txt README.md
src/Ghcid.hs view
@@ -40,6 +40,7 @@ {command :: String ,arguments :: [String] ,test :: [String]+ ,run :: [String] ,warnings :: Bool ,no_status :: Bool ,height :: Maybe Int@@ -71,6 +72,7 @@ {command = "" &= name "c" &= typ "COMMAND" &= help "Command to run (defaults to ghci or cabal repl)" ,arguments = [] &= args &= typ "MODULE" ,test = [] &= name "T" &= typ "EXPR" &= help "Command to run after successful loading"+ ,run = [] &= name "r" &= typ "EXPR" &= opt "main" &= help "Command to run after successful loading (defaults to main)" ,warnings = False &= name "W" &= help "Allow tests to run even with warnings" ,no_status = False &= name "S" &= help "Suppress status messages" ,height = Nothing &= help "Number of lines to use (defaults to console height)"@@ -129,21 +131,21 @@ stack <- firstJustM findStack [".",".."] -- stack file might be parent, see #62 let cabal = map (curdir </>) $ filter ((==) ".cabal" . takeExtension) files- let opts = ["-fno-code" | null test] ++ ghciFlagsRequired ++ ghciFlagsUseful+ let opts = ["-fno-code" | null test && null run] ++ ghciFlagsRequired ++ ghciFlagsUseful return $ case () of _ | Just stack <- stack -> let flags = if null arguments then- "stack ghci --test" :+ "stack ghci --test --bench" : ["--no-load" | ".ghci" `elem` files] ++ map ("--ghci-options=" ++) opts else- "stack exec --test -- ghci" : opts+ "stack exec --test --bench -- ghci" : opts in f flags $ stack:cabal | ".ghci" `elem` files -> f ("ghci":opts) [curdir </> ".ghci"] | cabal /= [] -> f (if null arguments then "cabal repl":map ("--ghc-options=" ++) opts else "cabal exec -- ghci":opts) cabal | otherwise -> f ("ghci":opts) [] where- f c r = o{command = unwords $ c ++ map escape arguments, arguments = [], restart = restart ++ r}+ f c r = o{command = unwords $ c ++ map escape arguments, arguments = [], restart = restart ++ r, run = [], test = run ++ test} -- in practice we're not expecting many arguments to have anything funky in them escape x | ' ' `elem` x = "\"" ++ x ++ "\""@@ -240,8 +242,9 @@ -- Note that we capture restarting items at this point, not before invoking the command -- The reason is some restart items may be generated by the command itself restartTimes <- mapM getModTime restart- curdir <- getCurrentDirectory + project <- if project /= "" then return project else takeFileName <$> getCurrentDirectory+ -- fire, given a waiter, the messages/loaded let fire nextWait (messages, loaded) = do currTime <- getShortTime@@ -263,8 +266,7 @@ let f n msg = if n == 0 then "" else show n ++ " " ++ msg ++ ['s' | n > 1] in (if countErrors == 0 && countWarnings == 0 then allGoodMessage ++ ", at " ++ currTime else f countErrors "error" ++ (if countErrors > 0 && countWarnings > 0 then ", " else "") ++ f countWarnings "warning") ++- " " ++ extra ++ [' ' | extra /= ""] ++ "- " ++- (if null project then takeFileName curdir else project)+ " " ++ extra ++ [' ' | extra /= ""] ++ "- " ++ project updateTitle $ if isJust test then "(running test)" else ""
src/Language/Haskell/Ghcid.hs view
@@ -170,11 +170,12 @@ s <- return $ maybe s (removePrefix . snd) $ stripInfix ghcid_prefix s whenLoud $ outStrLn $ "%STDOUT2: " ++ s modifyIORef (if strm == Stdout then stdout else stderr) (s:)- when ("GHCi, version " `isPrefixOf` s) $ do+ when (any (`isPrefixOf` s) ["GHCi, version ","GHCJSi, version "]) $ do -- the thing before me may have done its own Haskell compiling writeIORef stdout [] writeIORef stderr [] writeInp "import qualified System.IO as INTERNAL_GHCID"+ writeInp ":unset +t +s" -- see https://github.com/ndmitchell/ghcid/issues/162 writeInp $ ":set prompt " ++ ghcid_prefix -- failure isn't harmful, so do them one-by-one
src/Session.hs view
@@ -99,7 +99,7 @@ -- do whatever preparation was requested exec v $ unlines setup - -- capture stdout+ -- deal with current directory (dir, _) <- showPaths v writeIORef curdir dir messages <- return $ qualify dir messages
src/Test/API.hs view
@@ -13,7 +13,7 @@ apiTests :: TestTree apiTests = testGroup "API test" [testCase "No files" $ withTempDir $ \dir -> do- (ghci,load) <- startGhci "ghci" (Just dir) $ const putStrLn+ (ghci,load) <- startGhci "ghci -ignore-dot-ghci" (Just dir) $ const putStrLn load @?= [] showModules ghci >>= (@?= []) exec ghci "import Data.List"@@ -22,7 +22,7 @@ ,testCase "Load file" $ withTempDir $ \dir -> do writeFile (dir </> "File.hs") "module A where\na = 123"- (ghci, load) <- startGhci "ghci File.hs" (Just dir) $ const putStrLn+ (ghci, load) <- startGhci "ghci -ignore-dot-ghci File.hs" (Just dir) $ const putStrLn load @?= [Loading "A" "File.hs"] exec ghci "a + 1" >>= (@?= ["124"]) reload ghci >>= (@?= [])
src/Wait.hs view
@@ -14,7 +14,6 @@ import System.Directory.Extra import Data.Time.Clock import Data.String-import Data.Maybe import System.Console.CmdArgs import System.Time.Extra import System.FSNotify@@ -83,11 +82,17 @@ case [x | (x,t1,t2) <- zip3 files old new, t1 /= t2] of [] -> recheck files new xs -> do- when (or $ zipWith (\o n -> isJust o && isNothing n) old new) $ do+ let disappeared = [x | (x, Just _, Nothing) <- zip3 files old new]+ when (disappeared /= []) $ do -- if someone is deleting a needed file, give them some space to put the file back -- typically caused by VIM- whenLoud $ outStrLn "%WAITING: Extra wait due to file removal"- sleep 1+ -- but try not to+ whenLoud $ outStrLn $ "%WAITING: Waiting max of 1s due to file removal, " ++ unwords disappeared+ -- at most 20 iterations, but stop as soon as the file returns+ void $ flip firstJustM (replicate 20 ()) $ \_ -> do+ sleep 0.05+ new <- mapM getModTime files+ return $ if null [x | (x, Just _, Nothing) <- zip3 files old new] then Just () else Nothing return xs