@@ -42,7 +42,7 @@ import Idris.Elab.Value
4242import Version_idris (gitHash)
4343import Util.System
4444import Util.DynamicLinker
45−import Util.Net (listenOnLocalhost)
45+import Util.Net (listenOnLocalhost, listenOnLocalhostAnyPort)
4646import Util.Pretty hiding ((</>))
4747
4848import Idris.Core.Evaluate
@@ -91,6 +91,8 @@ import Data.Word (Word)
9191import Data.Either (partitionEithers)
9292import Control.DeepSeq
9393
94+import Numeric ( readHex )
95+
9496import Debug.Trace
9597
9698-- | Run the REPL
@@ -206,44 +208,68 @@ runClient str = withSocketsDo $ do
206208 else do l <- hGetLine h
207209 hGetResp (acc ++ l ++ "\n") h
208210
211+initIdeslaveSocket :: IO (Handle)
212+initIdeslaveSocket = do
213+ (sock, port) <- listenOnLocalhostAnyPort
214+ putStrLn $ show port
215+ (h, _, _) <- accept sock
216+ hSetEncoding h utf8
217+ return h
218+
209219-- | Run the IdeSlave
210−ideslaveStart :: IState -> [FilePath] -> Idris ()
211−ideslaveStart orig mods
212− = do i <- getIState
220+ideslaveStart :: Bool -> IState -> [FilePath] -> Idris ()
221+ideslaveStart s orig mods
222+ = do h <- runIO $ if s then initIdeslaveSocket else return stdout
223+ setIdeSlave True h
224+ i <- getIState
213225 case idris_outputmode i of
214− IdeSlave n ->
215− when (mods /= []) (do isetPrompt (mkPrompt mods))
216− ideslave orig mods
217−
218−
219−ideslave :: IState -> [FilePath] -> Idris ()
220−ideslave orig mods
226+ IdeSlave n h ->
227+ do runIO $ hPutStrLn h $ IdeSlave.convSExp "protocol-version" IdeSlave.ideSlaveEpoch n
228+ when (mods /= []) (do isetPrompt (mkPrompt mods))
229+ ideslave h orig mods
230+
231+getNChar :: Handle -> Int -> String -> IO (String)
232+getNChar _ 0 s = return (reverse s)
233+getNChar h n s = do c <- hGetChar h
234+ getNChar h (n - 1) (c : s)
235+
236+getLen :: Handle -> Idris (Int)
237+getLen h = do s <- runIO $ getNChar h 6 ""
238+ case readHex s of
239+ ((num, ""):_) -> return num
240+ _ -> ierror (Msg $ "Couldn't read length " ++ s)
241+
242+ideslave :: Handle -> IState -> [FilePath] -> Idris ()
243+ideslave h orig mods
221244 = do idrisCatch
222− (do l <- runIO $ getLine
245+ (do let inh = if h == stdout then stdin else h
246+ len <- getLen inh
247+ l <- runIO $ getNChar inh len ""
223248 (sexp, id) <- case IdeSlave.parseMessage l of
224249 Left err -> ierror err
225250 Right (sexp, id) -> return (sexp, id)
226251 i <- getIState
227− putIState $ i { idris_outputmode = (IdeSlave id) }
252+ putIState $ i { idris_outputmode = (IdeSlave id h) }
228253 idrisCatch -- to report correct id back!
229254 (do let fn = case mods of
230255 (f:_) -> f
231− _ -> ""
256+ _ -> ""
232257 case IdeSlave.sexpToCommand sexp of
233− Just cmd -> runIdeSlaveCommand id orig fn mods cmd
258+ Just cmd -> runIdeSlaveCommand h id orig fn mods cmd
234259 Nothing -> iPrintError "did not understand" )
235260 (\e -> do iPrintError $ show e))
236261 (\e -> do iPrintError $ show e)
237− ideslave orig mods
262+ ideslave h orig mods
238263
239264-- | Run IDESlave commands
240−runIdeSlaveCommand :: Integer -- ^^ The continuation ID for the client
265+runIdeSlaveCommand :: Handle -- ^^ The handle for communication
266+ -> Integer -- ^^ The continuation ID for the client
241267 -> IState -- ^^ The original IState
242268 -> FilePath -- ^^ The current open file
243269 -> [FilePath] -- ^^ The currently loaded modules
244270 -> IdeSlave.IdeSlaveCommand -- ^^ The command to process
245271 -> Idris ()
246−runIdeSlaveCommand id orig fn mods (IdeSlave.Interpret cmd) =
272+runIdeSlaveCommand h id orig fn mods (IdeSlave.Interpret cmd) =
247273 do c <- colourise
248274 i <- getIState
249275 case parseCmd i "(input)" cmd of
@@ -253,8 +279,8 @@ runIdeSlaveCommand id orig fn mods (IdeSlave.Interpret cmd) =
253279 (do process stdout fn (Prove n')
254280 isetPrompt (mkPrompt mods)
255281 case idris_outputmode i of
256− IdeSlave n -> -- signal completion of proof to ide
257− runIO . hPutStrLn stdout $
282+ IdeSlave n h -> -- signal completion of proof to ide
283+ runIO . hPutStrLn h $
258284 IdeSlave.convSExp "return"
259285 (IdeSlave.SymbolAtom "ok", "")
260286 n
@@ -262,25 +288,25 @@ runIdeSlaveCommand id orig fn mods (IdeSlave.Interpret cmd) =
262288 (\e -> do ist <- getIState
263289 isetPrompt (mkPrompt mods)
264290 case idris_outputmode i of
265− IdeSlave n ->
266− runIO . hPutStrLn stdout $
291+ IdeSlave n h ->
292+ runIO . hPutStrLn h $
267293 IdeSlave.convSExp "abandon-proof" "Abandoned" n
268294 _ -> return ()
269− ihRenderError stdout $ pprintErr ist e)
295+ ihRenderError h $ pprintErr ist e)
270296 Success cmd -> idrisCatch
271297 (ideslaveProcess fn cmd)
272− (\e -> getIState >>= ihRenderError stdout . flip pprintErr e)
273−runIdeSlaveCommand id orig fn mods (IdeSlave.REPLCompletions str) =
298+ (\e -> getIState >>= ihRenderError h . flip pprintErr e)
299+runIdeSlaveCommand h id orig fn mods (IdeSlave.REPLCompletions str) =
274300 do (unused, compls) <- replCompletion (reverse str, "")
275301 let good = IdeSlave.SexpList [IdeSlave.SymbolAtom "ok",
276302 IdeSlave.toSExp (map replacement compls,
277303 reverse unused)]
278− runIO $ putStrLn $ IdeSlave.convSExp "return" good id
279−runIdeSlaveCommand id orig fn mods (IdeSlave.LoadFile filename toline) =
304+ runIO . hPutStrLn h $ IdeSlave.convSExp "return" good id
305+runIdeSlaveCommand h id orig fn mods (IdeSlave.LoadFile filename toline) =
280306 do i <- getIState
281307 clearErr
282308 putIState (orig { idris_options = idris_options i,
283− idris_outputmode = (IdeSlave id) })
309+ idris_outputmode = (IdeSlave id h) })
284310 loadInputs stdout [filename] toline
285311 isetPrompt (mkPrompt [filename])
286312 -- Report either success or failure
@@ -291,10 +317,10 @@ runIdeSlaveCommand id orig fn mods (IdeSlave.LoadFile filename toline) =
291317 (\fc -> IdeSlave.SexpList [IdeSlave.SymbolAtom "ok",
292318 IdeSlave.toSExp fc])
293319 (idris_parsedSpan i)
294− in runIO . putStrLn $ IdeSlave.convSExp "return" msg id
320+ in runIO . hPutStrLn h $ IdeSlave.convSExp "return" msg id
295321 Just x -> iPrintError $ "didn't load " ++ filename
296− ideslave orig [filename]
297−runIdeSlaveCommand id orig fn mods (IdeSlave.TypeOf name) =
322+ ideslave h orig [filename]
323+runIdeSlaveCommand h id orig fn mods (IdeSlave.TypeOf name) =
298324 case splitName name of
299325 Left err -> iPrintError err
300326 Right n -> process stdout "(ideslave)"
@@ -304,32 +330,32 @@ runIdeSlaveCommand id orig fn mods (IdeSlave.TypeOf name) =
304330 [] -> Left ("Didn't understand name '" ++ s ++ "'")
305331 [n] -> Right $ sUN n
306332 (n:ns) -> Right $ sNS (sUN n) ns
307−runIdeSlaveCommand id orig fn mods (IdeSlave.DocsFor name) =
333+runIdeSlaveCommand h id orig fn mods (IdeSlave.DocsFor name) =
308334 case parseConst orig name of
309335 Success c -> process stdout "(ideslave)" (DocStr (Right c))
310336 Failure _ ->
311337 case splitName name of
312338 Left err -> iPrintError err
313339 Right n -> process stdout "(ideslave)" (DocStr (Left n))
314−runIdeSlaveCommand id orig fn mods (IdeSlave.CaseSplit line name) =
340+runIdeSlaveCommand h id orig fn mods (IdeSlave.CaseSplit line name) =
315341 process stdout fn (CaseSplitAt False line (sUN name))
316−runIdeSlaveCommand id orig fn mods (IdeSlave.AddClause line name) =
342+runIdeSlaveCommand h id orig fn mods (IdeSlave.AddClause line name) =
317343 process stdout fn (AddClauseFrom False line (sUN name))
318−runIdeSlaveCommand id orig fn mods (IdeSlave.AddProofClause line name) =
344+runIdeSlaveCommand h id orig fn mods (IdeSlave.AddProofClause line name) =
319345 process stdout fn (AddProofClauseFrom False line (sUN name))
320−runIdeSlaveCommand id orig fn mods (IdeSlave.AddMissing line name) =
346+runIdeSlaveCommand h id orig fn mods (IdeSlave.AddMissing line name) =
321347 process stdout fn (AddMissing False line (sUN name))
322−runIdeSlaveCommand id orig fn mods (IdeSlave.MakeWithBlock line name) =
348+runIdeSlaveCommand h id orig fn mods (IdeSlave.MakeWithBlock line name) =
323349 process stdout fn (MakeWith False line (sUN name))
324−runIdeSlaveCommand id orig fn mods (IdeSlave.ProofSearch r line name hints depth) =
350+runIdeSlaveCommand h id orig fn mods (IdeSlave.ProofSearch r line name hints depth) =
325351 doProofSearch stdout fn False r line (sUN name) (map sUN hints) depth
326−runIdeSlaveCommand id orig fn mods (IdeSlave.MakeLemma line name) =
352+runIdeSlaveCommand h id orig fn mods (IdeSlave.MakeLemma line name) =
327353 case splitName name of
328354 Left err -> iPrintError err
329355 Right n -> process stdout fn (MakeLemma False line n)
330−runIdeSlaveCommand id orig fn mods (IdeSlave.Apropos a) =
356+runIdeSlaveCommand h id orig fn mods (IdeSlave.Apropos a) =
331357 process stdout fn (Apropos a)
332−runIdeSlaveCommand id orig fn mods (IdeSlave.GetOpts) =
358+runIdeSlaveCommand h id orig fn mods (IdeSlave.GetOpts) =
333359 do ist <- getIState
334360 let opts = idris_options ist
335361 let impshow = opt_showimp opts
@@ -337,16 +363,16 @@ runIdeSlaveCommand id orig fn mods (IdeSlave.GetOpts) =
337363 let options = (IdeSlave.SymbolAtom "ok",
338364 [(IdeSlave.SymbolAtom "show-implicits", impshow),
339365 (IdeSlave.SymbolAtom "error-context", errCtxt)])
340− runIO . putStrLn $ IdeSlave.convSExp "return" options id
341−runIdeSlaveCommand id orig fn mods (IdeSlave.SetOpt IdeSlave.ShowImpl b) =
366+ runIO . hPutStrLn h $ IdeSlave.convSExp "return" options id
367+runIdeSlaveCommand h id orig fn mods (IdeSlave.SetOpt IdeSlave.ShowImpl b) =
342368 do setImpShow b
343369 let msg = (IdeSlave.SymbolAtom "ok", b)
344− runIO . putStrLn $ IdeSlave.convSExp "return" msg id
345−runIdeSlaveCommand id orig fn mods (IdeSlave.SetOpt IdeSlave.ErrContext b) =
370+ runIO . hPutStrLn h $ IdeSlave.convSExp "return" msg id
371+runIdeSlaveCommand h id orig fn mods (IdeSlave.SetOpt IdeSlave.ErrContext b) =
346372 do setErrContext b
347373 let msg = (IdeSlave.SymbolAtom "ok", b)
348− runIO . putStrLn $ IdeSlave.convSExp "return" msg id
349−runIdeSlaveCommand id orig fn mods (IdeSlave.Metavariables cols) =
374+ runIO . hPutStrLn h $ IdeSlave.convSExp "return" msg id
375+runIdeSlaveCommand h id orig fn mods (IdeSlave.Metavariables cols) =
350376 do ist <- getIState
351377 let mvs = reverse $ map fst (idris_metavars ist) \\ primDefs
352378 let ppo = ppOptionIst ist
@@ -362,7 +388,7 @@ runIdeSlaveCommand id orig fn mods (IdeSlave.Metavariables cols) =
362388 (zip bnds hs),
363389 render ist bnd c pc))
364390 splitMvs
365− runIO . putStrLn $
391+ runIO . hPutStrLn h $
366392 IdeSlave.convSExp "return" (IdeSlave.SymbolAtom "ok", mvOutput) id
367393 where mapPair f g xs = zip (map (f . fst) xs) (map (g . snd) xs)
368394 mapSnd f xs = zip (map fst xs) (map (f . snd) xs)
@@ -407,32 +433,32 @@ runIdeSlaveCommand id orig fn mods (IdeSlave.Metavariables cols) =
407433 let (out, spans) = render ist bnd t pt in
408434 (show n , out, spans)
409435
410−runIdeSlaveCommand id orig fn mods (IdeSlave.WhoCalls n) =
436+runIdeSlaveCommand h id orig fn mods (IdeSlave.WhoCalls n) =
411437 case splitName n of
412438 Left err -> iPrintError err
413439 Right n -> do calls <- whoCalls n
414440 ist <- getIState
415441 let msg = (IdeSlave.SymbolAtom "ok",
416442 map (\ (n,ns) -> (pn ist n, map (pn ist) ns)) calls)
417− runIO . putStrLn $ IdeSlave.convSExp "return" msg id
443+ runIO . hPutStrLn h $ IdeSlave.convSExp "return" msg id
418444 where pn ist = displaySpans .
419445 renderPretty 0.9 1000 .
420446 fmap (fancifyAnnots ist) .
421447 prettyName True True []
422−runIdeSlaveCommand id orig fn mods (IdeSlave.CallsWho n) =
448+runIdeSlaveCommand h id orig fn mods (IdeSlave.CallsWho n) =
423449 case splitName n of
424450 Left err -> iPrintError err
425451 Right n -> do calls <- callsWho n
426452 ist <- getIState
427453 let msg = (IdeSlave.SymbolAtom "ok",
428454 map (\ (n,ns) -> (pn ist n, map (pn ist) ns)) calls)
429− runIO . putStrLn $ IdeSlave.convSExp "return" msg id
455+ runIO . hPutStrLn h $ IdeSlave.convSExp "return" msg id
430456 where pn ist = displaySpans .
431457 renderPretty 0.9 1000 .
432458 fmap (fancifyAnnots ist) .
433459 prettyName True True []
434460
435−runIdeSlaveCommand id orig fn modes (IdeSlave.TermNormalise bnd tm) =
461+runIdeSlaveCommand h id orig fn modes (IdeSlave.TermNormalise bnd tm) =
436462 do ctxt <- getContext
437463 ist <- getIState
438464 let tm' = force (normaliseAll ctxt [] tm)
@@ -446,15 +472,15 @@ runIdeSlaveCommand id orig fn modes (IdeSlave.TermNormalise bnd tm) =
446472 displaySpans .
447473 renderPretty 0.9 80 .
448474 fmap (fancifyAnnots ist) $ ptm)
449− runIO . putStrLn $ IdeSlave.convSExp "return" msg id
450−runIdeSlaveCommand id orig fn modes (IdeSlave.TermShowImplicits bnd tm) =
451− ideSlaveForceTermImplicits id bnd True tm
452−runIdeSlaveCommand id orig fn modes (IdeSlave.TermNoImplicits bnd tm) =
453− ideSlaveForceTermImplicits id bnd False tm
475+ runIO . hPutStrLn h $ IdeSlave.convSExp "return" msg id
476+runIdeSlaveCommand h id orig fn modes (IdeSlave.TermShowImplicits bnd tm) =
477+ ideSlaveForceTermImplicits h id bnd True tm
478+runIdeSlaveCommand h id orig fn modes (IdeSlave.TermNoImplicits bnd tm) =
479+ ideSlaveForceTermImplicits h id bnd False tm
454480
455481-- | Show a term for IDESlave with the specified implicitness
456−ideSlaveForceTermImplicits :: Integer -> [(Name, Bool)] -> Bool -> Term -> Idris ()
457−ideSlaveForceTermImplicits id bnd impl tm =
482+ideSlaveForceTermImplicits :: Handle -> Integer -> [(Name, Bool)] -> Bool -> Term -> Idris ()
483+ideSlaveForceTermImplicits h id bnd impl tm =
458484 do ist <- getIState
459485 let expl = annotate (AnnTerm bnd tm)
460486 (pprintPTerm ((ppOptionIst ist) { ppopt_impl = impl })
@@ -464,7 +490,7 @@ ideSlaveForceTermImplicits id bnd impl tm =
464490 displaySpans .
465491 renderPretty 0.9 80 .
466492 fmap (fancifyAnnots ist) $ expl)
467− runIO . putStrLn $ IdeSlave.convSExp "return" msg id
493+ runIO . hPutStrLn h $ IdeSlave.convSExp "return" msg id
468494
469495splitName :: String -> Either String Name
470496splitName s = case reverse $ splitOn "." s of
@@ -950,8 +976,8 @@ process h fn Execute
950976 case idris_outputmode ist of
951977 RawOutput -> do runIO $ system tmpn
952978 return ()
953− IdeSlave n -> runIO . hPutStrLn h $
954− IdeSlave.convSExp "run-program" tmpn n)
979+ IdeSlave n h -> runIO . hPutStrLn h $
980+ IdeSlave.convSExp "run-program" tmpn n)
955981 (\e -> getIState >>= ihRenderError stdout . flip pprintErr e)
956982 where fc = fileFC "main"
957983process h fn (Compile codegen f)
@@ -1275,7 +1301,6 @@ idrisMain opts =
12751301 mapM_ addLangExt (opt getLanguageExt opts)
12761302 setREPL runrepl
12771303 setQuiet (quiet || isJust script || not (null immediate))
1278− setIdeSlave idesl
12791304 setVerbose verbose
12801305 setCmdLine opts
12811306 setOutputTy outty
@@ -1359,7 +1384,8 @@ idrisMain opts =
13591384-- clearOrigPats
13601385 startServer orig inputs
13611386 runInputT (replSettings (Just historyFile)) $ repl orig inputs
1362− when (idesl) $ ideslaveStart orig inputs
1387+ let idesock = IdeslaveSocket `elem` opts
1388+ when (idesl) $ ideslaveStart idesock orig inputs
13631389 ok <- noErrors
13641390 when (not ok) $ runIO (exitWith (ExitFailure 1))
13651391 where