3Description : Entry Point for the Idris REPL and CLI.
5Maintainer : The Idris Community.
8{-# LANGUAGE PatternGuards #-}
20import Control.Category
21import Control.Concurrent
22import Control.Concurrent.Async (race)
24import qualified Control.Exception as X
26import Control.Monad.Trans (lift)
27import Control.Monad.Trans.Except (runExceptT)
28import Control.Monad.Trans.State.Strict (evalStateT, get, put)
29import qualified Data.Binary as Binary
30import qualified Data.ByteString.Base64 as Base64
31import qualified Data.ByteString.Lazy as Lazy
32import qualified Data.ByteString.UTF8 as UTF8
34import Data.Either (partitionEithers)
35import Data.List hiding (group)
36import Data.List.Split (splitOn)
38import qualified Data.Set as S
39import qualified Data.Text as T
42import Idris.Apropos (apropos, aproposModules)
44import Idris.Colours hiding (colourise)
45import Idris.Completion
46import Idris.Core.Constraints
47import Idris.Core.Evaluate
48import Idris.Core.Execute (execute)
50import Idris.Core.Unify
54import Idris.Delaborate
56import Idris.Docstrings (overview, renderDocTerm, renderDocstring)
57import Idris.Elab.Clause
59import Idris.Elab.Value
62import Idris.ErrReverse
65import qualified Idris.IdeMode as IdeMode
69import Idris.Interactive
70import Idris.ModeCommon
73import Idris.Parser hiding (indent)
75import Idris.REPL.Browse (namesInNS, namespacesInNS)
76import Idris.REPL.Commands
77import Idris.REPL.Parser
78import Idris.Termination
79import Idris.TypeSearch (searchByType)
83import Prelude hiding (id, (.), (<$>))
84import System.Console.Haskeline as H
85import System.Directory
86import System.Environment
88import System.FilePath (addExtension, dropExtension, splitExtension,
89 takeDirectory, takeExtension, (<.>), (</>))
90import System.FSNotify (watchDir, withManager)
91import System.FSNotify.Devel (allEvents, doAllEvents)
94import Text.Trifecta.Result (ErrInfo(..), Result(..))
95import Util.DynamicLinker
96import Util.Net (listenOnLocalhost, listenOnLocalhostAnyPort)
97import Util.Pretty hiding ((</>))
99import Version_idris (gitHash)
104repl :: IState -- ^ The initial state
105 -> [FilePath] -- ^ The loaded modules
106 -> FilePath -- ^ The file to edit (with :e)
110 do let quiet = opt_quiet (idris_options orig)
112 let colour = idris_colourRepl i
113 let theme = idris_colourTheme i
114 let mvs = idris_metavars i
115 let prompt = if quiet
117 else showMVs colour theme mvs ++
118 let str = mkPrompt mods ++ ">" in
119 (if colour && not isWindows
120 then colourisePrompt theme str
122 x <- H.catch (H.withInterrupt $ getInputLine prompt)
123 (ctrlC (return $ Just ""))
125 Nothing -> do lift $ when (not quiet) (iputStrLn "Bye bye")
127 Just input -> -- H.catch
128 do ms <- H.catch (H.withInterrupt $ lift $ processInput input orig mods efile)
129 (ctrlC (return (Just mods)))
131 Just mods -> let efile' = fromMaybe efile (listToMaybe mods)
132 in repl orig mods efile'
136 where ctrlC :: InputT Idris a -> SomeException -> InputT Idris a
137 ctrlC act e = do lift $ iputStrLn (show e)
138 act -- repl orig mods
140 showMVs c thm [] = ""
141 showMVs c thm ms = "Holes: " ++
142 show' 4 c thm (map fst ms) ++ "\n"
144 show' 0 c thm ms = let l = length ms in
147 ++ if l == 1 then ")" else "s)"
148 show' n c thm [m] = showM c thm m
149 show' n c thm (m : ms) = showM c thm m ++ ", " ++
150 show' (n - 1) c thm ms
152 showM c thm n = if c then colouriseFun thm (show n)
155-- | Run the REPL server
156startServer :: PortNumber -> IState -> [FilePath] -> Idris ()
157startServer port orig fn_in = do tid <- runIO $ forkIO (serverLoop port)
159 where serverLoop port = withSocketsDo $
160 do sock <- listenOnLocalhost port
161 loop fn orig { idris_colourRepl = False } sock
163 fn = fromMaybe "" (listToMaybe fn_in)
166 = do (h,_,_) <- accept sock
169 let isth = case idris_outputmode ist of
170 RawOutput _ -> ist {idris_outputmode = RawOutput h}
171 IdeMode n _ -> ist {idris_outputmode = IdeMode n h}
172 (ist', fn) <- processNetCmd orig isth h fn cmd
176processNetCmd :: IState -> IState -> Handle -> FilePath -> String ->
177 IO (IState, FilePath)
178processNetCmd orig i h fn cmd
179 = do res <- case parseCmd i "(net)" cmd of
180 Failure (ErrInfo err _) -> return (Left (Msg " invalid command"))
181 Success (Right c) -> runExceptT $ evalStateT (processNet fn c) i
182 Success (Left err) -> return (Left (Msg err))
185 Left err -> do hPutStrLn h (show err)
188 processNet fn Reload = processNet fn (Load fn Nothing)
189 processNet fn (Load f toline) =
190 -- The $!! here prevents a space leak on reloading.
191 -- This isn't a solution - but it's a temporary stopgap.
193 do putIState $!! orig { idris_options = idris_options i
194 , idris_colourTheme = idris_colourTheme i
195 , idris_colourRepl = False
201 mods <- loadInputs [f] toline
204 processNet fn c = do process fn c
207 setOutH :: Handle -> Idris ()
210 putIState $ case idris_outputmode ist of
211 RawOutput _ -> ist {idris_outputmode = RawOutput h}
212 IdeMode n _ -> ist {idris_outputmode = IdeMode n h}
214-- | Run a command on the server on localhost
215runClient :: Maybe PortNumber -> String -> IO ()
216runClient port str = withSocketsDo $ do
217 let port' = fromMaybe defaultPort port
218 res <- X.try (connectTo "localhost" $ PortNumber port')
223 resp <- hGetResp "" h
229 exitWith (ExitFailure 1)
231 where hGetResp acc h = do eof <- hIsEOF h
232 if eof then return acc
233 else do l <- hGetLine h
234 hGetResp (acc ++ l ++ "\n") h
236 connectionError :: X.SomeException -> IO ()
238 putStrLn "Unable to connect to a running Idris repl"
241initIdemodeSocket :: IO Handle
242initIdemodeSocket = do
243 (sock, port) <- listenOnLocalhostAnyPort
245 (h, _, _) <- accept sock
250idemodeStart :: Bool -> IState -> [FilePath] -> Idris ()
251idemodeStart s orig mods
252 = do h <- runIO $ if s then initIdemodeSocket else return stdout
255 case idris_outputmode i of
257 do runIO $ hPutStrLn h $ IdeMode.convSExp "protocol-version" IdeMode.ideModeEpoch n
259 a:_ -> runIdeModeCommand h n i "" [] (IdeMode.LoadFile a Nothing)
263idemode :: Handle -> IState -> [FilePath] -> Idris ()
266 (do let inh = if h == stdout then stdin else h
267 len' <- runIO $ IdeMode.getLen inh
269 Left err -> ierror err
271 l <- runIO $ IdeMode.getNChar inh len ""
272 (sexp, id) <- case IdeMode.parseMessage l of
273 Left err -> ierror err
274 Right (sexp, id) -> return (sexp, id)
276 putIState $ i { idris_outputmode = (IdeMode id h) }
277 idrisCatch -- to report correct id back!
278 (do let fn = fromMaybe "" (listToMaybe mods)
279 case IdeMode.sexpToCommand sexp of
280 Just cmd -> runIdeModeCommand h id orig fn mods cmd
281 Nothing -> iPrintError "did not understand" )
282 (\e -> do iPrintError $ show e))
283 (\e -> do iPrintError $ show e)
286-- | Run IDEMode commands
287runIdeModeCommand :: Handle -- ^^ The handle for communication
288 -> Integer -- ^^ The continuation ID for the client
289 -> IState -- ^^ The original IState
290 -> FilePath -- ^^ The current open file
291 -> [FilePath] -- ^^ The currently loaded modules
292 -> IdeMode.IdeModeCommand -- ^^ The command to process
294runIdeModeCommand h id orig fn mods (IdeMode.Interpret cmd) =
297 case parseCmd i "(input)" cmd of
298 Failure (ErrInfo err _) -> iPrintError $ show (fixColour False err)
299 Success (Right (Prove mode n')) ->
301 (do process fn (Prove mode n')
302 isetPrompt (mkPrompt mods)
303 case idris_outputmode i of
304 IdeMode n h -> -- signal completion of proof to ide
305 runIO . hPutStrLn h $
306 IdeMode.convSExp "return"
307 (IdeMode.SymbolAtom "ok", "")
310 (\e -> do ist <- getIState
311 isetPrompt (mkPrompt mods)
312 case idris_outputmode i of
314 runIO . hPutStrLn h $
315 IdeMode.convSExp "abandon-proof" "Abandoned" n
317 iRenderError $ pprintErr ist e)
318 Success (Right cmd) -> idrisCatch
319 (idemodeProcess fn cmd)
320 (\e -> getIState >>= iRenderError . flip pprintErr e)
321 Success (Left err) -> iPrintError err
322runIdeModeCommand h id orig fn mods (IdeMode.REPLCompletions str) =
323 do (unused, compls) <- replCompletion (reverse str, "")
324 let good = IdeMode.SexpList [IdeMode.SymbolAtom "ok",
325 IdeMode.toSExp (map replacement compls,
327 runIO . hPutStrLn h $ IdeMode.convSExp "return" good id
328runIdeModeCommand h id orig fn mods (IdeMode.LoadFile filename toline) =
329 -- The $!! here prevents a space leak on reloading.
330 -- This isn't a solution - but it's a temporary stopgap.
334 putIState $!! orig { idris_options = idris_options i,
335 idris_outputmode = (IdeMode id h) }
336 mods <- loadInputs [filename] toline
337 isetPrompt (mkPrompt mods)
338 -- Report either success or failure
341 Nothing -> let msg = maybe (IdeMode.SexpList [IdeMode.SymbolAtom "ok",
342 IdeMode.SexpList []])
343 (\fc -> IdeMode.SexpList [IdeMode.SymbolAtom "ok",
346 in runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
347 Just x -> iPrintError $ "didn't load " ++ filename
349runIdeModeCommand h id orig fn mods (IdeMode.TypeOf name) =
350 case splitName name of
351 Left err -> iPrintError err
352 Right n -> process "(idemode)"
353 (Check (PRef (FC "(idemode)" (0,0) (0,0)) [] n))
354runIdeModeCommand h id orig fn mods (IdeMode.DocsFor name w) =
355 case parseConst orig name of
356 Success c -> process "(idemode)" (DocStr (Right c) (howMuch w))
358 case splitName name of
359 Left err -> iPrintError err
360 Right n -> process "(idemode)" (DocStr (Left n) (howMuch w))
361 where howMuch IdeMode.Overview = OverviewDocs
362 howMuch IdeMode.Full = FullDocs
363runIdeModeCommand h id orig fn mods (IdeMode.CaseSplit line name) =
364 process fn (CaseSplitAt False line (sUN name))
365runIdeModeCommand h id orig fn mods (IdeMode.AddClause line name) =
366 process fn (AddClauseFrom False line (sUN name))
367runIdeModeCommand h id orig fn mods (IdeMode.AddProofClause line name) =
368 process fn (AddProofClauseFrom False line (sUN name))
369runIdeModeCommand h id orig fn mods (IdeMode.AddMissing line name) =
370 process fn (AddMissing False line (sUN name))
371runIdeModeCommand h id orig fn mods (IdeMode.MakeWithBlock line name) =
372 process fn (MakeWith False line (sUN name))
373runIdeModeCommand h id orig fn mods (IdeMode.MakeCaseBlock line name) =
374 process fn (MakeCase False line (sUN name))
375runIdeModeCommand h id orig fn mods (IdeMode.ProofSearch r line name hints depth) =
376 doProofSearch fn False r line (sUN name) (map sUN hints) depth
377runIdeModeCommand h id orig fn mods (IdeMode.MakeLemma line name) =
378 case splitName name of
379 Left err -> iPrintError err
380 Right n -> process fn (MakeLemma False line n)
381runIdeModeCommand h id orig fn mods (IdeMode.Apropos a) =
382 process fn (Apropos [] a)
383runIdeModeCommand h id orig fn mods (IdeMode.GetOpts) =
385 let opts = idris_options ist
386 let impshow = opt_showimp opts
387 let errCtxt = opt_errContext opts
388 let options = (IdeMode.SymbolAtom "ok",
389 [(IdeMode.SymbolAtom "show-implicits", impshow),
390 (IdeMode.SymbolAtom "error-context", errCtxt)])
391 runIO . hPutStrLn h $ IdeMode.convSExp "return" options id
392runIdeModeCommand h id orig fn mods (IdeMode.SetOpt IdeMode.ShowImpl b) =
394 let msg = (IdeMode.SymbolAtom "ok", b)
395 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
396runIdeModeCommand h id orig fn mods (IdeMode.SetOpt IdeMode.ErrContext b) =
398 let msg = (IdeMode.SymbolAtom "ok", b)
399 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
400runIdeModeCommand h id orig fn mods (IdeMode.Metavariables cols) =
402 let mvs = reverse $ [ (n, i)
403 | (n, (_, i, _, _, _)) <- idris_metavars ist
404 , not (n `elem` primDefs)
406 let ppo = ppOptionIst ist
407 -- splitMvs is a list of pairs of names and their split types
408 let splitMvs = [ (n, (premises, concl, tm))
409 | (n, i, ty) <- mvTys ist mvs
410 , let (premises, concl, tm) = splitPi ist i ty]
411 -- mvOutput is the pretty-printed version ready for conversion to SExpr
412 let mvOutput = map (\(n, (hs, c)) -> (n, hs, c)) $
415 let bnd = [ n | (n,_,_) <- hs ] in
416 let bnds = inits bnd in
417 (map (\(bnd, h) -> processPremise ist bnd h)
419 render ist bnd c pc))
421 runIO . hPutStrLn h $
422 IdeMode.convSExp "return" (IdeMode.SymbolAtom "ok", mvOutput) id
423 where mapPair f g xs = zip (map (f . fst) xs) (map (g . snd) xs)
424 firstOfThree (x, y, z) = x
425 mapThird f xs = map (\(x, y, z) -> (x, y, f z)) xs
427 -- | Split a function type into a pair of premises, conclusion.
428 -- Each maintains both the original and delaborated versions.
429 splitPi :: IState -> Int -> Type -> ([(Name, Type, PTerm)], Type, PTerm)
430 splitPi ist i (Bind n (Pi _ _ t _) rest) | i > 0 =
431 let (hs, c, pc) = splitPi ist (i - 1) rest in
432 ((n, t, delabTy' ist [] [] t False False True):hs,
433 c, delabTy' ist [] [] c False False True)
434 splitPi ist i tm = ([], tm, delabTy' ist [] [] tm False False True)
436 -- | Get the types of a list of metavariable names
437 mvTys :: IState -> [(Name, Int)] -> [(Name, Int, Type)]
438 mvTys ist mvs = [ (n, i, ty)
440 , ty <- maybeToList (fmap (vToP . snd) (lookupTyNameExact n (tt_ctxt ist)))
443 -- | Show a type and its corresponding PTerm in a format suitable
444 -- for the IDE - that is, pretty-printed and annotated.
445 render :: IState -> [Name] -> Type -> PTerm -> (String, SpanList OutputAnnotation)
446 render ist bnd t pt =
447 let prettyT = pprintPTerm (ppOptionIst ist)
448 (zip bnd (repeat False))
454 renderPretty 0.9 cols .
455 fmap (fancifyAnnots ist True) .
456 annotate (AnnTerm (zip bnd (take (length bnd) (repeat False))) t) $
459 -- | Juggle the bits of a premise to prepare for output.
460 processPremise :: IState
461 -> [Name] -- ^ the names to highlight as bound
462 -> (Name, Type, PTerm)
465 SpanList OutputAnnotation)
466 processPremise ist bnd (n, t, pt) =
467 let (out, spans) = render ist bnd t pt in
468 (show n , out, spans)
470runIdeModeCommand h id orig fn mods (IdeMode.WhoCalls n) =
472 Left err -> iPrintError err
473 Right n -> do calls <- whoCalls n
475 let msg = (IdeMode.SymbolAtom "ok",
476 map (\ (n,ns) -> (pn ist n, map (pn ist) ns)) calls)
477 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
478 where pn ist = displaySpans .
479 renderPretty 0.9 1000 .
480 fmap (fancifyAnnots ist True) .
481 prettyName True True []
483runIdeModeCommand h id orig fn mods (IdeMode.CallsWho n) =
485 Left err -> iPrintError err
486 Right n -> do calls <- callsWho n
488 let msg = (IdeMode.SymbolAtom "ok",
489 map (\ (n,ns) -> (pn ist n, map (pn ist) ns)) calls)
490 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
491 where pn ist = displaySpans .
492 renderPretty 0.9 1000 .
493 fmap (fancifyAnnots ist True) .
494 prettyName True True []
496runIdeModeCommand h id orig fn modes (IdeMode.BrowseNS ns) =
497 case splitOn "." ns of
498 [] -> iPrintError "No namespace provided"
499 ns -> do underNSs <- fmap (map $ concat . intersperse ".") $ namespacesInNS ns
500 names <- namesInNS ns
501 if null underNSs && null names
502 then iPrintError "Invalid or empty namespace"
503 else do ist <- getIState
504 underNs <- mapM pn names
505 let msg = (IdeMode.SymbolAtom "ok", (underNSs, underNs))
506 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
508 do ctxt <- getContext
512 renderPretty 0.9 1000 .
513 fmap (fancifyAnnots ist True) $
514 prettyName True False [] n <>
515 case lookupTyExact n ctxt of
517 space <> colon <> space <> align (group (pprintDelab ist t))
521runIdeModeCommand h id orig fn modes (IdeMode.TermNormalise bnd tm) =
522 do ctxt <- getContext
524 let tm' = normaliseAll ctxt [] tm
525 ptm = annotate (AnnTerm bnd tm')
526 (pprintPTerm (ppOptionIst ist)
531 msg = (IdeMode.SymbolAtom "ok",
533 renderPretty 0.9 80 .
534 fmap (fancifyAnnots ist True) $ ptm)
535 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
536runIdeModeCommand h id orig fn modes (IdeMode.TermShowImplicits bnd tm) =
537 ideModeForceTermImplicits h id bnd True tm
538runIdeModeCommand h id orig fn modes (IdeMode.TermNoImplicits bnd tm) =
539 ideModeForceTermImplicits h id bnd False tm
540runIdeModeCommand h id orig fn modes (IdeMode.TermElab bnd tm) =
542 let ptm = annotate (AnnTerm bnd tm)
543 (pprintTT (map fst bnd) tm)
544 msg = (IdeMode.SymbolAtom "ok",
546 renderPretty 0.9 70 .
547 fmap (fancifyAnnots ist True) $ ptm)
548 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
549runIdeModeCommand h id orig fn mods (IdeMode.PrintDef name) =
550 case splitName name of
551 Left err -> iPrintError err
552 Right n -> process "(idemode)" (PrintDef n)
553runIdeModeCommand h id orig fn modes (IdeMode.ErrString e) =
555 let out = displayS . renderPretty 1.0 60 $ pprintErr ist e
556 msg = (IdeMode.SymbolAtom "ok", IdeMode.StringAtom $ out "")
557 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
558runIdeModeCommand h id orig fn modes (IdeMode.ErrPPrint e) =
562 renderPretty 0.9 80 .
563 fmap (fancifyAnnots ist True) $ pprintErr ist e
564 msg = (IdeMode.SymbolAtom "ok", out, spans)
565 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
566runIdeModeCommand h id orig fn modes IdeMode.GetIdrisVersion =
567 let idrisVersion = (versionBranch getIdrisVersionNoGit,
568 if not (null gitHash)
571 msg = (IdeMode.SymbolAtom "ok", idrisVersion)
572 in runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
575-- | Show a term for IDEMode with the specified implicitness
576ideModeForceTermImplicits :: Handle -> Integer -> [(Name, Bool)] -> Bool -> Term -> Idris ()
577ideModeForceTermImplicits h id bnd impl tm =
579 let expl = annotate (AnnTerm bnd tm)
580 (pprintPTerm ((ppOptionIst ist) { ppopt_impl = impl })
581 bnd [] (idris_infixes ist)
583 msg = (IdeMode.SymbolAtom "ok",
585 renderPretty 0.9 80 .
586 fmap (fancifyAnnots ist True) $ expl)
587 runIO . hPutStrLn h $ IdeMode.convSExp "return" msg id
589splitName :: String -> Either String Name
590splitName s | "{{{{{" `isPrefixOf` s =
591 decode $ drop 5 $ reverse $ drop 5 $ reverse s
593 case Base64.decode (UTF8.fromString x) of
596 case Binary.decodeOrFail (Lazy.fromStrict ok) of
597 Left _ -> Left "Bad binary instance for Name"
598 Right (_, _, n) -> Right n
600splitName s = case reverse $ splitOn "." s of
601 [] -> Left ("Didn't understand name '" ++ s ++ "'")
602 [n] -> Right . sUN $ unparen n
603 (n:ns) -> Right $ sNS (sUN (unparen n)) ns
604 where unparen "" = ""
605 unparen ('(':x:xs) | last xs == ')' = init (x:xs)
608idemodeProcess :: FilePath -> Command -> Idris ()
609idemodeProcess fn Warranty = process fn Warranty
610idemodeProcess fn Help = process fn Help
611idemodeProcess fn (RunShellCommand cmd) =
612 iPrintError ":! is not currently supported in IDE mode."
613idemodeProcess fn (ChangeDirectory f) =
614 do process fn (ChangeDirectory f)
615 dir <- runIO $ getCurrentDirectory
616 iPrintResult $ "changed directory to " ++ dir
617idemodeProcess fn (ModImport f) = process fn (ModImport f)
618idemodeProcess fn (Eval t) = process fn (Eval t)
619idemodeProcess fn (NewDefn decls) = do process fn (NewDefn decls)
620 iPrintResult "defined"
621idemodeProcess fn (Undefine n) = process fn (Undefine n)
622idemodeProcess fn (ExecVal t) = process fn (ExecVal t)
623idemodeProcess fn (Check (PRef x hls n)) = process fn (Check (PRef x hls n))
624idemodeProcess fn (Check t) = process fn (Check t)
625idemodeProcess fn (Core t) = process fn (Core t)
626idemodeProcess fn (DocStr n w) = process fn (DocStr n w)
627idemodeProcess fn Universes = process fn Universes
628idemodeProcess fn (Defn n) = do process fn (Defn n)
630idemodeProcess fn (TotCheck n) = process fn (TotCheck n)
631idemodeProcess fn (DebugInfo n) = do process fn (DebugInfo n)
633idemodeProcess fn (Search ps t) = process fn (Search ps t)
634idemodeProcess fn (Spec t) = process fn (Spec t)
635-- RmProof and AddProof not supported!
636idemodeProcess fn (ShowProof n') = process fn (ShowProof n')
637idemodeProcess fn (WHNF t) = process fn (WHNF t)
638--idemodeProcess fn TTShell = process fn TTShell -- need some prove mode!
639idemodeProcess fn (TestInline t) = process fn (TestInline t)
641idemodeProcess fn (Execute t) = do process fn (Execute t)
643idemodeProcess fn (Compile codegen f) = do process fn (Compile codegen f)
645idemodeProcess fn (LogLvl i) = do process fn (LogLvl i)
647idemodeProcess fn (Pattelab t) = process fn (Pattelab t)
648idemodeProcess fn (Missing n) = process fn (Missing n)
649idemodeProcess fn (DynamicLink l) = do process fn (DynamicLink l)
651idemodeProcess fn ListDynamic = do process fn ListDynamic
653idemodeProcess fn Metavars = process fn Metavars
654idemodeProcess fn (SetOpt ErrContext) = do process fn (SetOpt ErrContext)
656idemodeProcess fn (UnsetOpt ErrContext) = do process fn (UnsetOpt ErrContext)
658idemodeProcess fn (SetOpt ShowImpl) = do process fn (SetOpt ShowImpl)
660idemodeProcess fn (UnsetOpt ShowImpl) = do process fn (UnsetOpt ShowImpl)
662idemodeProcess fn (SetOpt ShowOrigErr) = do process fn (SetOpt ShowOrigErr)
664idemodeProcess fn (UnsetOpt ShowOrigErr) = do process fn (UnsetOpt ShowOrigErr)
666idemodeProcess fn (SetOpt x) = process fn (SetOpt x)
667idemodeProcess fn (UnsetOpt x) = process fn (UnsetOpt x)
668idemodeProcess fn (CaseSplitAt False pos str) = process fn (CaseSplitAt False pos str)
669idemodeProcess fn (AddProofClauseFrom False pos str) = process fn (AddProofClauseFrom False pos str)
670idemodeProcess fn (AddClauseFrom False pos str) = process fn (AddClauseFrom False pos str)
671idemodeProcess fn (AddMissing False pos str) = process fn (AddMissing False pos str)
672idemodeProcess fn (MakeWith False pos str) = process fn (MakeWith False pos str)
673idemodeProcess fn (MakeCase False pos str) = process fn (MakeCase False pos str)
674idemodeProcess fn (DoProofSearch False r pos str xs) = process fn (DoProofSearch False r pos str xs)
675idemodeProcess fn (SetConsoleWidth w) = do process fn (SetConsoleWidth w)
677idemodeProcess fn (SetPrinterDepth d) = do process fn (SetPrinterDepth d)
679idemodeProcess fn (Apropos pkg a) = do process fn (Apropos pkg a)
681idemodeProcess fn (WhoCalls n) = process fn (WhoCalls n)
682idemodeProcess fn (CallsWho n) = process fn (CallsWho n)
683idemodeProcess fn (PrintDef n) = process fn (PrintDef n)
684idemodeProcess fn (PPrint fmt n tm) = process fn (PPrint fmt n tm)
685idemodeProcess fn _ = iPrintError "command not recognized or not supported"
688-- | The prompt consists of the currently loaded modules, or "Idris" if there are none
690mkPrompt [x] = "*" ++ dropExtension x
691mkPrompt (x:xs) = "*" ++ dropExtension x ++ " " ++ mkPrompt xs
693-- | Determine whether a file uses literate syntax
694lit f = case splitExtension f of
698reload :: IState -> [FilePath] -> Idris (Maybe [FilePath])
699reload orig inputs = do
701 -- The $!! here prevents a space leak on reloading.
702 -- This isn't a solution - but it's a temporary stopgap.
704 putIState $!! orig { idris_options = idris_options i
705 , idris_colourTheme = idris_colourTheme i
706 , imported = imported i
709 fmap Just $ loadInputs inputs Nothing
711watch :: IState -> [FilePath] -> Idris (Maybe [FilePath])
712watch orig inputs = do
714 let dirs = nub $ map takeDirectory inputs
715 inputSet <- fmap S.fromList $ mapM canonicalizePath inputs
716 signal <- newEmptyMVar
717 withManager $ \mgr -> do
719 watchDir mgr dir (allEvents $ flip S.member inputSet) (doAllEvents $ putMVar signal)
720 race getLine (takeMVar signal)
722 Left _ -> return (Just inputs) -- canceled, so nop
723 Right _ -> reload orig inputs >> watch orig inputs
725processInput :: String ->
726 IState -> [FilePath] -> FilePath -> Idris (Maybe [FilePath])
727processInput cmd orig inputs efile
729 let opts = idris_options i
730 let quiet = opt_quiet opts
731 let fn = fromMaybe "" (listToMaybe inputs)
733 case parseCmd i "(input)" cmd of
734 Failure (ErrInfo err _) -> do iputStrLn $ show (fixColour c err)
736 Success (Right Reload) ->
738 Success (Right Watch) ->
740 do iputStrLn "No loaded files to watch."
744 iputStrLn $ "Watching for .idr changes in " ++ show inputs ++ ", press enter to cancel."
746 Success (Right (Load f toline)) ->
747 -- The $!! here prevents a space leak on reloading.
748 -- This isn't a solution - but it's a temporary stopgap.
750 do putIState $!! orig { idris_options = idris_options i
751 , idris_colourTheme = idris_colourTheme i
754 mod <- loadInputs [f] toline
756 Success (Right (ModImport f)) ->
758 fmod <- loadModule f (IBC_REPL True)
759 return (Just (inputs ++ maybe [] (:[]) fmod))
760 Success (Right Edit) -> do -- takeMVar stvar
763 Success (Right Proofs) -> do proofs orig
765 Success (Right Quit) -> do when (not quiet) (iputStrLn "Bye bye")
767 Success (Right cmd ) -> do idrisCatch (process fn cmd)
768 (\e -> do msg <- showErr e ; iputStrLn msg)
770 Success (Left err) -> do runIO $ putStrLn err
773resolveProof :: Name -> Idris Name
777 n <- case lookupNames n' ctxt of
780 ns -> ierror (CantResolveAlts ns)
783removeProof :: Name -> Idris ()
786 let proofs = proof_list i
787 let ps = filter ((/= n) . fst) proofs
788 putIState $ i { proof_list = ps }
790edit :: FilePath -> IState -> Idris ()
791edit "" orig = iputStrLn "Nothing to edit"
794 env <- runIO getEnvironment
795 let editor = getEditor env
796 let line = case errSpan i of
797 Just l -> '+' : show (fst (fc_start l))
799 let cmdLine = intercalate " " [editor, line, fixName f]
800 runIO $ system cmdLine
802 -- The $!! here prevents a space leak on reloading.
803 -- This isn't a solution - but it's a temporary stopgap.
805 putIState $!! orig { idris_options = idris_options i
806 , idris_colourTheme = idris_colourTheme i
808 loadInputs [f] Nothing
812 where getEditor env | Just ed <- lookup "EDITOR" env = ed
813 | Just ed <- lookup "VISUAL" env = ed
815 fixName file | map toLower (takeExtension file) `elem` [".lidr", ".idr"] = quote file
816 | otherwise = quote $ addExtension file "idr"
818 quoteChar = if isWindows then '"' else '\''
819 quote s = [quoteChar] ++ s ++ [quoteChar]
823proofs :: IState -> Idris ()
826 let ps = proof_list i
828 [] -> iputStrLn "No proofs available"
829 _ -> iputStrLn $ "Proofs:\n\t" ++ (show $ map fst ps)
831insertScript :: String -> [String] -> [String]
832insertScript prf [] = "\n---------- Proofs ----------" : "" : [prf]
833insertScript prf (p@"---------- Proofs ----------" : "" : xs)
835insertScript prf (x : xs) = x : insertScript prf xs
837process :: FilePath -> Command -> Idris ()
838process fn Help = iPrintResult displayHelp
839process fn Warranty = iPrintResult warranty
840process fn (RunShellCommand cmd) = runIO $ system cmd >> return ()
841process fn (ChangeDirectory f)
842 = do runIO $ setCurrentDirectory f
844process fn (ModImport f) = do fmod <- loadModule f (IBC_REPL True)
846 Just pr -> isetPrompt pr
847 Nothing -> iPrintError $ "Can't find import " ++ f
849 = withErrorReflection $
850 do logParser 5 $ show t
851 getIState >>= flip warnDisamb t
852 (tm, ty) <- elabREPL (recinfo (fileFC "toplevel")) ERHS t
854 let tm' = perhapsForce $ normaliseBlocking ctxt []
859 let ty' = perhapsForce $ normaliseAll ctxt [] ty
860 -- Add value to context, call it "it"
861 updateContext (addCtxtDef (sUN "it") (Function ty' tm'))
863 logParser 3 $ "Raw: " ++ show (tm', ty')
864 logParser 10 $ "Debug: " ++ showEnvDbg [] tm'
865 let tmDoc = pprintDelab ist tm'
866 -- errReverse to make type more readable
867 tyDoc = pprintDelab ist (errReverse ist ty')
868 iPrintTermWithType tmDoc tyDoc
869 where perhapsForce tm | termSmallerThan 100 tm = force tm
872process fn (NewDefn decls) = do
873 logParser 3 ("Defining names using these decls: " ++ show (showDecls verbosePPOption decls))
874 mapM_ defineName namedGroups where
875 namedGroups = groupBy (\d1 d2 -> getName d1 == getName d2) decls
876 getName :: PDecl -> Maybe Name
877 getName (PTy docs argdocs syn fc opts name _ ty) = Just name
878 getName (PClauses fc opts name (clause:clauses)) = Just (getClauseName clause)
879 getName (PData doc argdocs syn fc opts dataDecl) = Just (d_name dataDecl)
880 getName (PInterface doc syn fc constraints name nfc parms parmdocs fds decls _ _) = Just name
882 -- getClauseName is partial and I am not sure it's used safely! -- trillioneyes
883 getClauseName (PClause fc name whole with rhs whereBlock) = name
884 getClauseName (PWith fc name whole with rhs pn whereBlock) = name
885 defineName :: [PDecl] -> Idris ()
886 defineName (tyDecl@(PTy docs argdocs syn fc opts name _ ty) : decls) = do
887 elabDecl EAll info tyDecl
888 elabClauses info fc opts name (concatMap getClauses decls)
889 setReplDefined (Just name)
890 defineName [PClauses fc opts _ [clause]] = do
891 let pterm = getRHS clause
892 (tm,ty) <- elabVal info ERHS pterm
894 let tm' = force (normaliseAll ctxt [] tm)
895 let ty' = force (normaliseAll ctxt [] ty)
896 updateContext (addCtxtDef (getClauseName clause) (Function ty' tm'))
897 setReplDefined (Just $ getClauseName clause)
898 defineName (PClauses{} : _) = tclift $ tfail (Msg "Only one function body is allowed without a type declaration.")
899 -- fixity and syntax declarations are ignored by elabDecls, so they'll have to be handled some other way
900 defineName (PFix fc fixity strs : defns) = do
901 fmodifyState idris_fixities (map (Fix fixity) strs ++)
902 unless (null defns) $ defineName defns
903 defineName (PSyntax _ syntax:_) = do
905 put (addReplSyntax i syntax)
906 defineName decls = do
907 elabDecls (toplevelWith fn) (map fixClauses decls)
908 setReplDefined (getName (head decls))
909 getClauses (PClauses fc opts name clauses) = clauses
911 getRHS :: PClause -> PTerm
912 getRHS (PClause fc name whole with rhs whereBlock) = rhs
913 getRHS (PWith fc name whole with rhs pn whereBlock) = rhs
914 getRHS (PClauseR fc with rhs whereBlock) = rhs
915 getRHS (PWithR fc with rhs pn whereBlock) = rhs
916 setReplDefined :: Maybe Name -> Idris ()
917 setReplDefined Nothing = return ()
918 setReplDefined (Just n) = do
920 fmodifyState repl_definitions (n:)
921 -- the "name" field of PClauses seems to always be MN 2 "__", so we need to
922 -- retrieve the actual name from deeper inside.
923 -- This should really be a full recursive walk through the structure of PDecl, but
924 -- I think it should work this way and I want to test sooner. Also lazy.
925 fixClauses :: PDecl' t -> PDecl' t
926 fixClauses (PClauses fc opts _ css@(clause:cs)) =
927 PClauses fc opts (getClauseName clause) css
928 fixClauses (PImplementation doc argDocs syn fc constraints pnames acc opts cls nfc parms pextra ty implName decls) =
929 PImplementation doc argDocs syn fc constraints pnames acc opts cls nfc parms pextra ty implName (map fixClauses decls)
930 fixClauses decl = decl
932 info = recinfo (fileFC "toplevel")
934process fn (Undefine names) = undefine names
936 undefine :: [Name] -> Idris ()
938 allDefined <- idris_repl_defs `fmap` get
939 undefine' allDefined []
940 -- Keep track of which names you've removed so you can
941 -- print them out to the user afterward
942 undefine names = undefine' names []
943 undefine' [] list = do iRenderResult $ printUndefinedNames list
945 undefine' (n:names) already = do
946 allDefined <- idris_repl_defs `fmap` get
947 if n `elem` allDefined
948 then do undefinedJustNow <- undefClosure n
949 undefine' names (undefinedJustNow ++ already)
950 else do tclift $ tfail $ Msg ("Can't undefine " ++ show n ++ " because it wasn't defined at the repl")
951 undefine' names already
952 undefOne n = do fputState (ctxt_lookup n . known_terms) Nothing
953 -- for now just assume it's an interface. Eventually we'll want some kind of
954 -- smart detection of exactly what kind of name we're undefining.
955 fputState (ctxt_lookup n . known_interfaces) Nothing
956 fmodifyState repl_definitions (delete n)
958 do replDefs <- idris_repl_defs `fmap` get
959 callGraph <- whoCalls n
960 let users = case lookup n callGraph of
962 Nothing -> fail ("Tried to undefine nonexistent name" ++ show n)
963 undefinedJustNow <- concat `fmap` mapM undefClosure users
965 return (nub (n : undefinedJustNow))
969process fn (ExecVal t)
970 = do ctxt <- getContext
972 (tm, ty) <- elabVal (recinfo (fileFC "toplevel")) ERHS t
973-- let tm' = normaliseAll ctxt [] tm
974 let ty' = normaliseAll ctxt [] ty
976 let (resOut, tyOut) = (prettyIst ist (delab ist res),
977 prettyIst ist (delab ist ty'))
978 iPrintTermWithType resOut tyOut
980process fn (Check (PRef _ _ n))
981 = do ctxt <- getContext
983 let ppo = ppOptionIst ist
984 case lookupNames n ctxt of
986 case lookup t (idris_metavars ist) of
987 Just (_, i, _, _, _) -> iRenderResult . fmap (fancifyAnnots ist True) $
988 showMetavarInfo ppo ist n i
989 Nothing -> iPrintFunTypes [] n (map (\n -> (n, pprintDelabTy ist n)) ts)
990 [] -> iPrintError $ "No such variable " ++ show n
992 showMetavarInfo ppo ist n i
993 = case lookupTy n (tt_ctxt ist) of
994 (ty:_) -> let ty' = normaliseC (tt_ctxt ist) [] ty in
995 putTy ppo ist i [] (delab ist (errReverse ist ty'))
996 putTy :: PPOption -> IState -> Int -> [(Name, Bool)] -> PTerm -> Doc OutputAnnotation
997 putTy ppo ist 0 bnd sc = putGoal ppo ist bnd sc
998 putTy ppo ist i bnd (PPi _ n _ t sc)
999 = let current = case n of
1001 UN nm | ('_':'_':_) <- str nm -> text ""
1005 <+> align (tPretty bnd ist t)
1008 current <> putTy ppo ist (i-1) ((n,False):bnd) sc
1009 putTy ppo ist _ bnd sc = putGoal ppo ist ((n,False):bnd) sc
1010 putGoal ppo ist bnd g
1011 = text "--------------------------------------" <$>
1012 annotate (AnnName n Nothing Nothing Nothing) (text $ show n) <+> colon <+>
1013 align (tPretty bnd ist g)
1015 tPretty bnd ist t = pprintPTerm (ppOptionIst ist) bnd [] (idris_infixes ist) t
1019 = do (tm, ty) <- elabREPL (recinfo (fileFC "toplevel")) ERHS t
1022 let ppo = ppOptionIst ist
1023 ty' = if opt_evaltypes (idris_options ist)
1024 then normaliseC ctxt [] ty
1028 iPrintTermWithType (prettyIst ist (PType emptyFC)) type1Doc
1029 _ -> iPrintTermWithType (pprintDelab ist tm)
1030 (pprintDelab ist ty')
1036 case lookupDef n (tt_ctxt ist) of
1037 [CaseOp _ _ _ _ _ _] -> pprintDef True n >>= iRenderResult . vsep
1041 do (tm, ty) <- elabREPL (recinfo (fileFC "toplevel")) ERHS t
1042 iPrintTermWithType (pprintTT [] tm) (pprintTT [] ty)
1044process fn (DocStr (Left n) w)
1045 | UN ty <- n, ty == T.pack "Type" = getIState >>= iRenderResult . pprintTypeDoc
1048 let docs = lookupCtxtName n (idris_docstrings ist) ++
1049 map (\(n,d)-> (n, (d, [])))
1050 (lookupCtxtName (modDocN n) (idris_moduledocs ist))
1052 [] -> iPrintError $ "No documentation for " ++ show n
1053 ns -> do toShow <- mapM (showDoc ist) ns
1054 iRenderResult (vsep toShow)
1055 where showDoc ist (n, d) = do doc <- getDocs n w
1056 return $ pprintDocs ist doc
1058 modDocN (NS (UN n) ns) = NS modDocName (n:ns)
1059 modDocN (UN n) = NS modDocName [n]
1060 modDocN _ = sMN 1 "NotFoundForSure"
1062process fn (DocStr (Right c) _) -- constants only have overviews
1063 = do ist <- getIState
1064 iRenderResult $ pprintConstDocs ist c (constDocs c)
1068 let cs = idris_constraints i
1069 let cslist = S.toAscList cs
1070-- iputStrLn $ showSep "\n" (map show cs)
1071 iputStrLn $ showSep "\n" (map show cslist)
1072 let n = length cslist
1073 iputStrLn $ "(" ++ show n ++ " constraints)"
1075 Error e -> iPrintError $ pshow i e
1076 OK _ -> iPrintResult "Universes OK"
1079 let head = text "Compiled patterns:" <$>
1080 text (show (lookupDef n (tt_ctxt i)))
1082 case lookupCtxt n (idris_patdefs i) of
1084 [(d, _)] -> text "Original definiton:" <$>
1085 vsep (map (printCase i) d)
1087 case lookupTotal n (tt_ctxt i) of
1088 [t] -> showTotal t i
1090 iRenderResult $ vsep [head, defs, tot]
1091 where printCase i (_, lhs, rhs)
1092 = let i' = i { idris_options = (idris_options i) { opt_showimp = True } }
1093 in text (showTm i' (delab i lhs)) <+> text "=" <+>
1094 text (showTm i' (delab i rhs))
1095process fn (TotCheck n)
1097 case lookupNameTotal n (tt_ctxt i) of
1098 [] -> iPrintError $ "Unknown operator " ++ show n
1099 ts -> do ist <- getIState
1101 let ppo = ppOptionIst ist
1102 let showN n = annotate (AnnName n Nothing Nothing Nothing) . text $
1103 showName (Just ist) [] ppo False n
1104 iRenderResult . vsep .
1105 map (\(n, t) -> hang 4 $ showN n <+> text "is" <+> showTotal t i) $
1108process fn (DebugUnify l r)
1109 = do (ltm, _) <- elabVal (recinfo (fileFC "toplevel")) ERHS l
1110 (rtm, _) <- elabVal (recinfo (fileFC "toplevel")) ERHS r
1112 case unify ctxt [] (ltm, Nothing) (rtm, Nothing) [] [] [] [] of
1113 OK ans -> iputStrLn (show ans)
1114 Error e -> iputStrLn (show e)
1116process fn (DebugInfo n)
1118 let oi = lookupCtxtName n (idris_optimisation i)
1119 when (not (null oi)) $ iputStrLn (show oi)
1120 let si = lookupCtxt n (idris_statics i)
1121 when (not (null si)) $ iputStrLn (show si)
1122 let di = lookupCtxt n (idris_datatypes i)
1123 when (not (null di)) $ iputStrLn (show di)
1124 let imps = lookupCtxt n (idris_implicits i)
1125 when (not (null imps)) $ iputStrLn (show imps)
1126 let d = lookupDefAcc n False (tt_ctxt i)
1127 when (not (null d)) $ iputStrLn $ "Definition: " ++ (show (head d))
1128 let cg = lookupCtxtName n (idris_callgraph i)
1130 let cg' = lookupCtxtName n (idris_callgraph i)
1131 sc <- checkSizeChange n
1132 iputStrLn $ "Size change: " ++ show sc
1133 let fn = lookupCtxtName n (idris_fninfo i)
1134 when (not (null cg')) $ do iputStrLn "Call graph:\n"
1135 iputStrLn (show cg')
1136 when (not (null fn)) $ iputStrLn (show fn)
1137process fn (Search pkgs t) = searchByType pkgs t
1138process fn (CaseSplitAt updatefile l n)
1139 = caseSplitAt fn updatefile l n
1140process fn (AddClauseFrom updatefile l n)
1141 = addClauseFrom fn updatefile l n
1142process fn (AddProofClauseFrom updatefile l n)
1143 = addProofClauseFrom fn updatefile l n
1144process fn (AddMissing updatefile l n)
1145 = addMissing fn updatefile l n
1146process fn (MakeWith updatefile l n)
1147 = makeWith fn updatefile l n
1148process fn (MakeCase updatefile l n)
1149 = makeCase fn updatefile l n
1150process fn (MakeLemma updatefile l n)
1151 = makeLemma fn updatefile l n
1152process fn (DoProofSearch updatefile rec l n hints)
1153 = doProofSearch fn updatefile rec l n hints Nothing
1155 = do (tm, ty) <- elabVal (recinfo (fileFC "toplevel")) ERHS t
1158 let tm' = simplify ctxt [] {- (idris_statics ist) -} tm
1159 iPrintResult (show (delab ist tm'))
1161process fn (RmProof n')
1163 n <- resolveProof n'
1164 let proofs = proof_list i
1165 case lookup n proofs of
1166 Nothing -> iputStrLn "No proof to remove"
1167 Just _ -> do removeProof n
1169 iputStrLn $ "Removed proof " ++ show n
1171 insertMetavar :: Name -> Idris ()
1174 let ms = idris_metavars i
1175 putIState $ i { idris_metavars = (n, (Nothing, 0, [], False, False)) : ms }
1177process fn' (AddProof prf)
1179 let fn'' = takeWhile (/= ' ') fn'
1180 ex <- runIO $ doesFileExist fn''
1181 let fnExt = fn'' <.> "idr"
1182 exExt <- runIO $ doesFileExist fnExt
1187 else ifail $ "Neither \""++fn''++"\" nor \""++fnExt++"\" exist"
1189 runIO $ copyFile fn fb -- make a backup in case something goes wrong!
1190 prog <- runIO $ readSource fb
1192 let proofs = proof_list i
1194 Nothing -> case proofs of
1195 [] -> ifail "No proof to add"
1196 ((x, _) : _) -> return x
1197 Just nm -> return nm
1198 n <- resolveProof n'
1199 case lookup n proofs of
1200 Nothing -> iputStrLn "No proof to add"
1202 do let script = if mode
1203 then showRunElab (lit fn) n prf
1204 else showProof (lit fn) n prf
1205 let prog' = insertScript script ls
1206 runIO $ writeSource fn (unlines prog')
1208 iputStrLn $ "Added proof " ++ show n
1209 where ls = (lines prog)
1211process fn (ShowProof n')
1213 n <- resolveProof n'
1214 let proofs = proof_list i
1215 case lookup n proofs of
1216 Nothing -> iPrintError "No proof to show"
1217 Just (m, p) -> iPrintResult $ if m
1218 then showRunElab False n p
1219 else showProof False n p
1221process fn (Prove mode n')
1222 = do ctxt <- getContext
1224 let ns = lookupNames n' ctxt
1225 let metavars = mapMaybe (\n -> do c <- lookup n (idris_metavars ist); return (n, c)) ns
1226 n <- case metavars of
1227 [] -> ierror (Msg $ "Cannot find metavariable " ++ show n')
1228 [(n, (_,_,_,False,_))] -> return n
1229 [(_, (_,_,_,_,False))] -> ierror (Msg "Can't prove this hole as it depends on other holes")
1230 [(_, (_,_,_,True,_))] -> ierror (Msg "Declarations not solvable using prover")
1231 ns -> ierror (CantResolveAlts (map fst ns))
1232 prover (toplevelWith fn) mode (lit fn) n
1235 totcheck (fileFC "(input)", n)
1236 mapM_ (\ (f,n) -> setTotality n Unchecked) (idris_totcheck i)
1237 mapM_ checkDeclTotality (idris_totcheck i)
1240 = do (tm, ty) <- elabVal (recinfo (fileFC "toplevel")) ERHS t
1243 let tm' = whnf ctxt [] tm
1244 let tmArgs' = whnfArgs ctxt [] tm
1245 iPrintResult $ "WHNF: " ++ (show (delab ist tm'))
1246 iPrintResult $ "WHNF args: " ++ (show (delab ist tmArgs'))
1247process fn (TestInline t)
1248 = do (tm, ty) <- elabVal (recinfo (fileFC "toplevel")) ERHS t
1251 let tm' = inlineTerm ist tm
1253 iPrintResult (showTm ist (delab ist tm'))
1254process fn (Execute tm)
1256 (do ist <- getIState
1257 (m_in, _) <- elabVal (recinfo (fileFC "toplevel")) ERHS (elabExec fc tm)
1259 (tmpn, tmph) <- runIO $ tempfile ""
1262 -- gcc adds .exe when it builds windows programs
1263 progName <- return $ if isWindows then tmpn ++ ".exe" else tmpn
1264 ir <- compile t tmpn (Just m)
1265 runIO $ generate t (fst (head (idris_imported ist))) ir
1266 case idris_outputmode ist of
1267 RawOutput h -> do runIO $ rawSystem progName []
1269 IdeMode n h -> runIO . hPutStrLn h $
1270 IdeMode.convSExp "run-program" tmpn n)
1271 (\e -> getIState >>= iRenderError . flip pprintErr e)
1272 where fc = fileFC "main"
1273process fn (Compile codegen f)
1274 | map toLower (takeExtension f) `elem` [".idr", ".lidr", ".idc"] =
1275 iPrintError $ "Invalid filename for compiler output \"" ++ f ++"\""
1276 | otherwise = do opts <- getCmdLine
1277 let iface = Interface `elem` opts
1278 let mainname = sNS (sUN "main") ["Main"]
1280 m <- if iface then return Nothing else
1281 do (m', _) <- elabVal (recinfo (fileFC "compiler")) ERHS
1282 (PApp fc (PRef fc [] (sUN "run__IO"))
1283 [pexp $ PRef fc [] mainname])
1285 ir <- compile codegen f m
1287 runIO $ generate codegen (fst (head (idris_imported i))) ir
1288 where fc = fileFC "main"
1289process fn (LogLvl i) = setLogLevel i
1290process fn (LogCategory cs) = setLogCats cs
1291-- Elaborate as if LHS of a pattern (debug command)
1292process fn (Pattelab t)
1293 = do (tm, ty) <- elabVal (recinfo (fileFC "toplevel")) ELHS t
1294 iPrintResult $ show tm ++ "\n\n : " ++ show ty
1296process fn (Missing n)
1298 ppOpts <- fmap ppOptionIst getIState
1299 case lookupCtxt n (idris_patdefs i) of
1300 [] -> iPrintError $ "Unknown name " ++ show n
1302 iRenderResult (vsep (map (pprintPTerm ppOpts
1307 _ -> iPrintError "Ambiguous name"
1308process fn (DynamicLink l)
1310 let importdirs = opt_importdirs (idris_options i)
1312 handle <- lift . lift $ tryLoadLib importdirs lib
1314 Nothing -> iPrintError $ "Could not load dynamic lib \"" ++ l ++ "\""
1315 Just x -> do let libs = idris_dynamic_libs i
1317 then do logParser 1 ("Tried to load duplicate library " ++ lib_name x)
1319 else putIState $ i { idris_dynamic_libs = x:libs }
1320 where trim = reverse . dropWhile isSpace . reverse . dropWhile isSpace
1321process fn ListDynamic
1323 iputStrLn "Dynamic libraries:"
1324 showLibs $ idris_dynamic_libs i
1325 where showLibs [] = return ()
1326 showLibs ((Lib name _):ls) = do iputStrLn $ "\t" ++ name; showLibs ls
1328 = do ist <- getIState
1329 let mvs = map fst (idris_metavars ist) \\ primDefs
1331 [] -> iPrintError "No global holes to solve"
1332 _ -> iPrintResult $ "Global holes:\n\t" ++ show mvs
1333process fn NOP = return ()
1335process fn (SetOpt ErrContext) = setErrContext True
1336process fn (UnsetOpt ErrContext) = setErrContext False
1337process fn (SetOpt ShowImpl) = setImpShow True
1338process fn (UnsetOpt ShowImpl) = setImpShow False
1339process fn (SetOpt ShowOrigErr) = setShowOrigErr True
1340process fn (UnsetOpt ShowOrigErr) = setShowOrigErr False
1341process fn (SetOpt AutoSolve) = setAutoSolve True
1342process fn (UnsetOpt AutoSolve) = setAutoSolve False
1343process fn (SetOpt NoBanner) = setNoBanner True
1344process fn (UnsetOpt NoBanner) = setNoBanner False
1345process fn (SetOpt WarnReach) = fmodifyState opts_idrisCmdline $ nub . (WarnReach:)
1346process fn (UnsetOpt WarnReach) = fmodifyState opts_idrisCmdline $ delete WarnReach
1347process fn (SetOpt EvalTypes) = setEvalTypes True
1348process fn (UnsetOpt EvalTypes) = setEvalTypes False
1350process fn (SetOpt DesugarNats) = setDesugarNats True
1351process fn (UnsetOpt DesugarNats) = setDesugarNats False
1353process fn (SetOpt _) = iPrintError "Not a valid option"
1354process fn (UnsetOpt _) = iPrintError "Not a valid option"
1355process fn (SetColour ty c) = setColour ty c
1357 = do ist <- getIState
1358 putIState $ ist { idris_colourRepl = True }
1360 = do ist <- getIState
1361 putIState $ ist { idris_colourRepl = False }
1362process fn ListErrorHandlers =
1364 iPrintResult $ case idris_errorhandlers ist of
1365 [] -> "No registered error handlers"
1366 handlers -> "Registered error handlers: " ++ (concat . intersperse ", " . map show) handlers
1367process fn (SetConsoleWidth w) = setWidth w
1368process fn (SetPrinterDepth d) = setDepth d
1369process fn (Apropos pkgs a) =
1370 do orig <- getIState
1371 when (not (null pkgs)) $
1372 iputStrLn $ "Searching packages: " ++ showSep ", " pkgs
1373 mapM_ loadPkgIndex pkgs
1375 let mods = aproposModules ist (T.pack a)
1376 let names = apropos ist (T.pack a)
1377 let aproposInfo = [ (n,
1379 fmap (overview . fst) (lookupCtxtExact n (idris_docstrings ist)))
1380 | n <- sort names, isUN n ]
1381 if (not (null mods)) || (not (null aproposInfo))
1382 then iRenderResult $ vsep (map (\(m, d) -> text "Module" <+> text m <$>
1383 ppD ist d <> line) mods) <$>
1384 vsep (map (prettyDocumentedIst ist) aproposInfo)
1385 else iRenderError $ text "No results found"
1386 where isUN (UN _) = True
1387 isUN (NS n _) = isUN n
1389 ppD ist = renderDocstring (renderDocTerm (pprintDelab ist) (normaliseAll (tt_ctxt ist) []))
1392process fn (WhoCalls n) =
1393 do calls <- whoCalls n
1395 iRenderResult . vsep $
1397 text "Callers of" <+> prettyName True True [] n <$>
1398 indent 1 (vsep (map ((text "*" <+>) . align . prettyName True True []) ns)))
1401process fn (CallsWho n) =
1402 do calls <- callsWho n
1404 iRenderResult . vsep $
1406 prettyName True True [] n <+> text "calls:" <$>
1407 indent 1 (vsep (map ((text "*" <+>) . align . prettyName True True []) ns)))
1410process fn (Browse ns) =
1411 do underNSs <- namespacesInNS ns
1412 names <- namesInNS ns
1413 if null underNSs && null names
1414 then iPrintError "Invalid or empty namespace"
1415 else do ist <- getIState
1417 text "Namespaces:" <$>
1418 indent 2 (vsep (map (text . showSep ".") underNSs)) <$>
1420 indent 2 (vsep (map (\n -> prettyName True False [] n <+> colon <+>
1421 (group . align $ pprintDelabTy ist n))
1425process fn (MakeDoc s) =
1426 do istate <- getIState
1428 parse n | Success x <- runparser (fmap fst name) istate fn n = Right x
1430 (bad, nss) = partitionEithers $ map parse names
1431 cd <- runIO getCurrentDirectory
1432 let outputDir = cd </> "doc"
1433 result <- if null bad then runIO $ generateDocs istate nss outputDir
1434 else return . Left $ "Illegal name: " ++ head bad
1435 case result of Right _ -> iputStrLn "IdrisDoc generated"
1436 Left err -> iPrintError err
1437process fn (PrintDef n) =
1438 do result <- pprintDef False n
1440 [] -> iPrintError "Not found"
1441 outs -> iRenderResult . vsep $ outs
1443-- Show relevant transformation rules for the name 'n'
1444process fn (TransformInfo n)
1446 let ts = lookupCtxt n (idris_transforms i)
1447 let res = map (showTrans i) ts
1448 iRenderResult . vsep $ concat res
1449 where showTrans :: IState -> [(Term, Term)] -> [Doc OutputAnnotation]
1451 showTrans i ((lhs, rhs) : ts)
1452 = let ppTm tm = annotate (AnnTerm [] tm) .
1453 pprintPTerm (ppOptionIst i) [] [] [] .
1455 ts' = showTrans i ts in
1456 ppTm lhs <+> text " ==> " <+> ppTm rhs : ts'
1458-- iRenderOutput (pretty lhs)
1460-- iPrintTermWithType (pprintDelab i rhs)
1461-- iputStrLn "---------------"
1464process fn (PPrint fmt width (PRef _ _ n))
1465 = do outs <- pprintDef False n
1466 iPrintResult =<< renderExternal fmt width (vsep outs)
1469process fn (PPrint fmt width t)
1470 = do (tm, ty) <- elabVal (recinfo (fileFC "toplevel")) ERHS t
1473 let ppo = ppOptionIst ist
1474 ty' = normaliseC ctxt [] ty
1475 iPrintResult =<< renderExternal fmt width (pprintDelab ist tm)
1477showTotal :: Totality -> IState -> Doc OutputAnnotation
1478showTotal t@(Partial (Other ns)) i
1479 = text "possibly not total due to:" <$>
1480 vsep (map (showTotalN i) ns)
1481showTotal t@(Partial (Mutual ns)) i
1482 = text "possibly not total due to recursive path:" <$>
1483 align (group (vsep (punctuate comma
1484 (map (\n -> annotate (AnnName n Nothing Nothing Nothing) $
1487showTotal t i = text (show t)
1489showTotalN :: IState -> Name -> Doc OutputAnnotation
1490showTotalN ist n = case lookupTotal n (tt_ctxt ist) of
1491 [t] -> showN n <> text ", which is" <+> showTotal t ist
1494 ppo = ppOptionIst ist
1495 showN n = annotate (AnnName n Nothing Nothing Nothing) . text $
1496 showName (Just ist) [] ppo False n
1498displayHelp = let vstr = showVersion getIdrisVersionNoGit in
1499 "\nIdris version " ++ vstr ++ "\n" ++
1500 "--------------" ++ map (\x -> '-') vstr ++ "\n\n" ++
1501 concatMap cmdInfo helphead ++
1502 concatMap cmdInfo help
1503 where cmdInfo (cmds, args, text) = " " ++ col 16 12 (showSep " " cmds) (show args) text
1505 l ++ take (c1 - length l) (repeat ' ') ++
1506 m ++ take (c2 - length m) (repeat ' ') ++ r ++ "\n"
1508pprintDef :: Bool -> Name -> Idris [Doc OutputAnnotation]
1512 let ambiguous = length (lookupNames n ctxt) > 1
1513 patdefs = idris_patdefs ist
1514 tyinfo = idris_datatypes ist
1516 then return $ map (ppCoreDef ist) (lookupCtxtName n patdefs)
1517 else return $ map (ppDef ambiguous ist) (lookupCtxtName n patdefs) ++
1518 map (ppTy ambiguous ist) (lookupCtxtName n tyinfo) ++
1519 map (ppCon ambiguous ist) (filter (flip isDConName ctxt) (lookupNames n ctxt))
1520 where ppCoreDef :: IState -> (Name, ([([(Name, Term)], Term, Term)], [PTerm])) -> Doc OutputAnnotation
1521 ppCoreDef ist (n, (clauses, missing)) =
1522 case lookupTy n (tt_ctxt ist) of
1523 [] -> error "Attempted pprintDef of TT of thing that doesn't exist"
1524 (ty:_) -> prettyName True True [] n <+> colon <+>
1525 align (annotate (AnnTerm [] ty) (pprintTT [] ty)) <$>
1526 vsep (map (\(vars, lhs, rhs) -> pprintTTClause vars lhs rhs) clauses)
1527 ppDef :: Bool -> IState -> (Name, ([([(Name, Term)], Term, Term)], [PTerm])) -> Doc OutputAnnotation
1528 ppDef amb ist (n, (clauses, missing)) =
1529 prettyName True amb [] n <+> colon <+>
1530 align (pprintDelabTy ist n) <$>
1531 ppClauses ist clauses <> ppMissing missing
1532 ppClauses ist [] = text "No clauses."
1533 ppClauses ist cs = vsep (map pp cs)
1534 where pp (varTys, lhs, rhs) =
1535 let vars = map fst varTys
1536 ppTm t = annotate (AnnTerm (zip vars (repeat False)) t) .
1537 pprintPTerm (ppOptionIst ist)
1538 (zip vars (repeat False))
1539 [] (idris_infixes ist) .
1540 delabWithEnv ist varTys $
1542 in group $ ppTm lhs <+> text "=" <$> (group . align . hang 2 $ ppTm rhs)
1545 ppTy :: Bool -> IState -> (Name, TypeInfo) -> Doc OutputAnnotation
1546 ppTy amb ist (n, TI constructors isCodata _ _ _ _)
1547 = kwd key <+> prettyName True amb [] n <+> colon <+>
1548 align (pprintDelabTy ist n) <+> kwd "where" <$>
1549 indent 2 (vsep (map (ppCon False ist) constructors))
1551 key | isCodata = "codata"
1552 | otherwise = "data"
1553 kwd = annotate AnnKeyword . text
1554 ppCon amb ist n = prettyName True amb [] n <+> colon <+> align (pprintDelabTy ist n)
1558 [ (["Command"], SpecialHeaderArg, "Purpose"),
1563replSettings :: Maybe FilePath -> Settings Idris
1564replSettings hFile = setComplete replCompletion $ defaultSettings {
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list