on master help sign in
Merge pull request #2857 from LeifW/watch_files_for_changes

Add :watch files for changes command to REPL.

commit9e8930d494325ff68d0aea0aacb01271b81187b0 authorEdwin Brady <edwin.brady@gmail.com> dateWed 20 Jan 2016, 16:06 (11 years ago) parent9fa5aa151e6a29
6 files changed+55−34
idris.cabal+2 src/IRTS/System.hs+3−7 src/Idris/AbsSyntaxTree.hs+1 src/Idris/ProofSearch.hs+1−2 src/Idris/REPL.hs+46−24 src/Idris/REPLParser.hs+2−1
idris.cabal+2
@@ -977,6 +977,8 @@ Library
977977 , vector-binary-instances < 0.3
978978 , zip-archive > 0.2.3.5 && < 0.2.4
979979 , safe
980+ , fsnotify < 2.2
981+ , async < 2.1
980982 -- zlib >= 0.6.1 is broken with GHC < 7.10.3
981983 if impl(ghc < 7.10.3)
982984 build-depends: zlib < 0.6.1
src/IRTS/System.hs+3−7
@@ -21,10 +21,7 @@ getCC :: IO String
2121getCC = fromMaybe "gcc" <$> environment "IDRIS_CC"
2222
2323getEnvFlags :: IO [String]
24−getEnvFlags = do flags <- environment "IDRIS_CFLAGS"
25− case flags of
26− Nothing -> return $ []
27− Just s -> return $ splitOn " " s
24+getEnvFlags = maybe [] (splitOn " ") <$> environment "IDRIS_CFLAGS"
2825
2926mvnCommand :: String
3027#ifdef mingw32_HOST_OS
@@ -37,9 +34,8 @@ getMvn :: IO String
3734getMvn = fromMaybe mvnCommand <$> environment "IDRIS_MVN"
3835
3936environment :: String -> IO (Maybe String)
40−environment x = catchIO (do e <- getEnv x
41− return (Just e))
42− (\_ -> return Nothing)
37+environment x = catchIO (Just <$> getEnv x)
38+ (\_ -> return Nothing)
4339
4440getTargetDir :: IO String
4541getTargetDir = environment "TARGET" >>= maybe getDataDir return
src/Idris/AbsSyntaxTree.hs+1
@@ -393,6 +393,7 @@ data Command = Quit
393393 | DocStr (Either Name Const) HowMuchDocs
394394 | TotCheck Name
395395 | Reload
396+ | Watch
396397 | Load FilePath (Maybe Int) -- up to maximum line number
397398 | ChangeDirectory FilePath
398399 | ModImport String
src/Idris/ProofSearch.hs+1−2
@@ -478,8 +478,7 @@ resTC' tcs defaultOn topholes depth topg fn elab ist
478478 return (num + 1)
479479 _ -> return 0
480480
481− solven 0 = return ()
482− solven n = do solve; solven (n - 1)
481+ solven n = replicateM_ n solve
483482
484483 resolve n depth
485484 | depth == 0 = fail $ "Can't resolve type class"
src/Idris/REPL.hs+46−24
@@ -94,6 +94,10 @@ import Data.Word (Word)
9494import Data.Either (partitionEithers)
9595import Control.DeepSeq
9696
97+import Control.Concurrent.Async (race)
98+import System.FSNotify (withManager, watchDir)
99+import System.FSNotify.Devel (allEvents, doAllEvents)
100+
97101import Numeric ( readHex )
98102
99103import Debug.Trace
@@ -126,10 +130,8 @@ repl orig mods efile
126130 do ms <- H.catch (lift $ processInput input orig mods efile)
127131 (ctrlC (return (Just mods)))
128132 case ms of
129− Just mods -> let efile' = case mods of
130− [] -> efile
131− (e:_) -> e in
132− repl orig mods efile'
133+ Just mods -> let efile' = fromMaybe efile (listToMaybe mods)
134+ in repl orig mods efile'
133135 Nothing -> return ()
134136-- ctrlC)
135137-- ctrlC
@@ -154,15 +156,13 @@ repl orig mods efile
154156
155157-- | Run the REPL server
156158startServer :: PortID -> IState -> [FilePath] -> Idris ()
157−startServer port orig fn_in = do tid <- runIO $ forkOS (serverLoop port)
159+startServer port orig fn_in = do tid <- runIO $ forkIO (serverLoop port)
158160 return ()
159161 where serverLoop port = withSocketsDo $
160162 do sock <- listenOnLocalhost port
161163 loop fn orig { idris_colourRepl = False } sock
162164
163− fn = case fn_in of
164− (f:_) -> f
165− _ -> ""
165+ fn = fromMaybe "" (listToMaybe fn_in)
166166
167167 loop fn ist sock
168168 = do (h,_,_) <- accept sock
@@ -276,9 +276,7 @@ idemode h orig mods
276276 i <- getIState
277277 putIState $ i { idris_outputmode = (IdeMode id h) }
278278 idrisCatch -- to report correct id back!
279− (do let fn = case mods of
280− (f:_) -> f
281− _ -> ""
279+ (do let fn = fromMaybe "" (listToMaybe mods)
282280 case IdeMode.sexpToCommand sexp of
283281 Just cmd -> runIdeModeCommand h id orig fn mods cmd
284282 Nothing -> iPrintError "did not understand" )
@@ -677,30 +675,54 @@ lit f = case splitExtension f of
677675 (_, ".lidr") -> True
678676 _ -> False
679677
678+reload :: IState -> [FilePath] -> Idris (Maybe [FilePath])
679+reload orig inputs = do
680+ i <- getIState
681+ -- The $!! here prevents a space leak on reloading.
682+ -- This isn't a solution - but it's a temporary stopgap.
683+ -- See issue #2386
684+ putIState $!! orig { idris_options = idris_options i
685+ , idris_colourTheme = idris_colourTheme i
686+ , imported = imported i
687+ }
688+ clearErr
689+ fmap Just $ loadInputs inputs Nothing
690+
691+watch :: IState -> [FilePath] -> Idris (Maybe [FilePath])
692+watch orig inputs = do
693+ let inputSet = S.fromList inputs
694+ let dirs = nub $ map takeDirectory inputs
695+ resp <- runIO $ do
696+ signal <- newEmptyMVar
697+ withManager $ \mgr -> do
698+ forM_ dirs $ \dir ->
699+ watchDir mgr dir (allEvents $ flip S.member inputSet) (doAllEvents $ putMVar signal)
700+ race getLine (takeMVar signal)
701+ case resp of
702+ Left _ -> return (Just inputs) -- canceled, so nop
703+ Right _ -> reload orig inputs >> watch orig inputs
704+
680705processInput :: String ->
681706 IState -> [FilePath] -> FilePath -> Idris (Maybe [FilePath])
682707processInput cmd orig inputs efile
683708 = do i <- getIState
684709 let opts = idris_options i
685710 let quiet = opt_quiet opts
686− let fn = case inputs of
687− (f:_) -> f
688− _ -> ""
711+ let fn = fromMaybe "" (listToMaybe inputs)
689712 c <- colourise
690713 case parseCmd i "(input)" cmd of
691714 Failure err -> do iputStrLn $ show (fixColour c err)
692715 return (Just inputs)
693716 Success (Right Reload) ->
694− -- The $!! here prevents a space leak on reloading.
695− -- This isn't a solution - but it's a temporary stopgap.
696− -- See issue #2386
697− do putIState $!! orig { idris_options = idris_options i
698− , idris_colourTheme = idris_colourTheme i
699− , imported = imported i
700− }
701− clearErr
702− mods <- loadInputs inputs Nothing
703− return (Just mods)
717+ reload orig inputs
718+ Success (Right Watch) ->
719+ if null inputs then
720+ do iputStrLn "No loaded files to watch."
721+ return (Just inputs)
722+ else
723+ do iputStrLn efile
724+ iputStrLn $ "Watching for .idr changes in " ++ show inputs ++ ", press enter to cancel."
725+ watch orig inputs
704726 Success (Right (Load f toline)) ->
705727 -- The $!! here prevents a space leak on reloading.
706728 -- This isn't a solution - but it's a temporary stopgap.
src/Idris/REPLParser.hs+2−1
@@ -67,6 +67,7 @@ parserCommandsForHelp =
6767 , namespaceArgCmd ["browse"] Browse "List the contents of some namespace"
6868 , nameArgCmd ["total"] TotCheck "Check the totality of a name"
6969 , noArgCmd ["r", "reload"] Reload "Reload current file"
70+ , noArgCmd ["w", "watch"] Watch "Watch the current file for changes"
7071 , (["l", "load"], FileArg, "Load a new file"
7172 , strArg (\f -> Load f Nothing))
7273 , (["cd"], FileArg, "Change working directory"
@@ -98,7 +99,7 @@ parserCommandsForHelp =
9899 , (["consolewidth"], ConsoleWidthArg, "Set the width of the console", cmd_consolewidth)
99100 , (["printerdepth"], OptionalArg NumberArg, "Set the maximum pretty-printer depth (no arg for infinite)", cmd_printdepth)
100101 , noArgCmd ["q", "quit"] Quit "Exit the Idris system"
101− , noArgCmd ["w", "warranty"] Warranty "Displays warranty information"
102+ , noArgCmd ["warranty"] Warranty "Displays warranty information"
102103 , (["let"], ManyArgs DeclArg
103104 , "Evaluate a declaration, such as a function definition, instance implementation, or fixity declaration"
104105 , cmd_let)