module Idris.Output where import Idris.Core.TT import Idris.Core.Evaluate (isDConName, isTConName, isFnName) import Idris.AbsSyntax import Idris.Delaborate import Idris.Docstrings import Idris.IdeSlave import Util.Pretty import Util.ScreenSize (getScreenWidth) import Debug.Trace import System.IO (stdout, Handle, hPutStrLn) import Data.List (nub) import Data.Maybe (fromMaybe) pshow :: IState -> Err -> String pshow ist err = displayDecorated (consoleDecorate ist) . renderPretty 1.0 80 . fmap (fancifyAnnots ist) $ pprintErr ist err ihWarn :: Handle -> FC -> Doc OutputAnnotation -> Idris () ihWarn h fc err = do i <- getIState case idris_outputmode i of RawOutput -> do err' <- iRender . fmap (fancifyAnnots i) $ if fc_fname fc /= "" then text (show fc) <> colon err else err runIO . hPutStrLn h $ displayDecorated (consoleDecorate i) err' IdeSlave n -> do err' <- iRender . fmap (fancifyAnnots i) $ err let (str, spans) = displaySpans err' runIO . hPutStrLn h $ convSExp "warning" (fc_fname fc, fc_start fc, fc_end fc, str, spans) n iRender :: Doc a -> Idris (SimpleDoc a) iRender d = do w <- getWidth ist <- getIState let ideSlave = case idris_outputmode ist of IdeSlave _ -> True _ -> False case w of InfinitelyWide -> return $ renderPretty 1.0 1000000000 d ColsWide n -> return $ if n < 1 then renderPretty 1.0 1000000000 d else renderPretty 0.8 n d AutomaticWidth | ideSlave -> return $ renderPretty 1.0 1000000000 d | otherwise -> do width <- runIO getScreenWidth return $ renderPretty 0.8 width d -- | Write a pretty-printed term to the console with semantic coloring consoleDisplayAnnotated :: Handle -> Doc OutputAnnotation -> Idris () consoleDisplayAnnotated h output = do ist <- getIState rendered <- iRender $ output runIO . hPutStrLn h . displayDecorated (consoleDecorate ist) $ rendered ihPrintTermWithType :: Handle -> Doc OutputAnnotation -> Doc OutputAnnotation -> Idris () ihPrintTermWithType h tm ty = ihRenderResult h (tm <+> colon <+> align ty) -- | Pretty-print a collection of overloadings to REPL or IDESlave - corresponds to :t name ihPrintFunTypes :: Handle -> [(Name, Bool)] -> Name -> [(Name, PTerm)] -> Idris () ihPrintFunTypes h bnd n [] = ihPrintError h $ "No such variable " ++ show n ihPrintFunTypes h bnd n overloads = do ist <- getIState let ppo = ppOptionIst ist let infixes = idris_infixes ist let output = vsep (map (uncurry (ppOverload ppo infixes)) overloads) ihRenderResult h output where fullName n = prettyName True bnd n ppOverload ppo infixes n tm = fullName n <+> colon <+> align (pprintPTerm ppo bnd [] infixes tm) ihRenderResult :: Handle -> Doc OutputAnnotation -> Idris () ihRenderResult h d = do ist <- getIState case idris_outputmode ist of RawOutput -> consoleDisplayAnnotated h d IdeSlave n -> ideSlaveReturnAnnotated n h d makeAnnName :: IState -> Name -> Maybe OutputAnnotation makeAnnName ist n | isDConName n ctxt = annName DataOutput | isFnName n ctxt = annName FunOutput | isTConName n ctxt = annName TypeOutput | isMetavarName n ist = annName MetavarOutput | otherwise = Nothing where ctxt = tt_ctxt ist docs = docOverview ist n ty = Just (getTy ist n) annName :: NameOutput -> Maybe OutputAnnotation annName nameType = Just (AnnName n (Just nameType) docs ty) docOverview :: IState -> Name -> Maybe String -- pretty-print first paragraph of docs docOverview ist n = do docs <- lookupCtxtExact n (idris_docstrings ist) let o = overview (fst docs) -- TODO make width configurable out = displayS . renderPretty 1.0 50 $ renderDocstring o return (out "") getTy :: IState -> Name -> String -- fails if name not already extant! getTy ist n = let theTy = pprintPTerm (ppOptionIst ist) [] [] (idris_infixes ist) $ delabTy ist n in (displayS . renderPretty 1.0 50 $ theTy) "" fancifyAnnots :: IState -> OutputAnnotation -> OutputAnnotation fancifyAnnots ist annot@(AnnName n _ _ _) = case makeAnnName ist n of Just fancyAnnot -> fancyAnnot Nothing -> annot fancifyAnnots _ annot = annot ideSlaveReturnWithStatus :: String -> Integer -> Handle -> Doc OutputAnnotation -> Idris () ideSlaveReturnWithStatus status n h out = do ist <- getIState (str, spans) <- fmap displaySpans . iRender . fmap (fancifyAnnots ist) $ out let good = [SymbolAtom status, toSExp str, toSExp spans] runIO . hPutStrLn h $ convSExp "return" good n -- | Write pretty-printed output to IDESlave with semantic annotations ideSlaveReturnAnnotated :: Integer -> Handle -> Doc OutputAnnotation -> Idris () ideSlaveReturnAnnotated = ideSlaveReturnWithStatus "ok" -- | Show an error with semantic highlighting ihRenderError :: Handle -> Doc OutputAnnotation -> Idris () ihRenderError h e = do ist <- getIState case idris_outputmode ist of RawOutput -> consoleDisplayAnnotated h e IdeSlave n -> ideSlaveReturnWithStatus "error" n h e ihPrintWithStatus :: String -> Handle -> String -> Idris () ihPrintWithStatus status h s = do i <- getIState case idris_outputmode i of RawOutput -> case s of "" -> return () s -> runIO $ hPutStrLn h s IdeSlave n -> let good = SexpList [SymbolAtom status, toSExp s] in runIO $ hPutStrLn h $ convSExp "return" good n ihPrintResult :: Handle -> String -> Idris () ihPrintResult = ihPrintWithStatus "ok" ihPrintError :: Handle -> String -> Idris () ihPrintError = ihPrintWithStatus "error" ihputStrLn :: Handle -> String -> Idris () ihputStrLn h s = do i <- getIState case idris_outputmode i of RawOutput -> runIO $ hPutStrLn h s IdeSlave n -> runIO . hPutStrLn h $ convSExp "write-string" s n iputStrLn = ihputStrLn stdout iPrintError = ihPrintError stdout iPrintResult = ihPrintResult stdout iWarn = ihWarn stdout ideslavePutSExp :: SExpable a => String -> a -> Idris () ideslavePutSExp cmd info = do i <- getIState case idris_outputmode i of IdeSlave n -> runIO . putStrLn $ convSExp cmd info n _ -> return () -- this needs some typing magic and more structured output towards emacs iputGoal :: SimpleDoc OutputAnnotation -> Idris () iputGoal g = do i <- getIState case idris_outputmode i of RawOutput -> runIO $ putStrLn (displayDecorated (consoleDecorate i) g) IdeSlave n -> runIO . putStrLn $ convSExp "write-goal" (displayS (fmap (fancifyAnnots i) g) "") n -- | Warn about totality problems without failing to compile warnTotality :: Idris () warnTotality = do ist <- getIState mapM_ (warn ist) (nub (idris_totcheckfail ist)) where warn ist (fc, e) = iWarn fc (pprintErr ist (Msg e))