1{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
3module Idris.Output where
6import Idris.Core.Evaluate (isDConName, isTConName, isFnName, normaliseAll)
10import Idris.Docstrings
14import Util.ScreenSize (getScreenWidth)
16import Control.Monad.Trans.Except (ExceptT (ExceptT), runExceptT)
18import System.Console.Haskeline.MonadException
19 (MonadException (controlIO), RunIO (RunIO))
20import System.IO (stdout, Handle, hPutStrLn)
22import Data.Char (isAlpha)
23import Data.List (nub, intersperse)
24import Data.Maybe (fromMaybe)
26instance MonadException m => MonadException (ExceptT Err m) where
27 controlIO f = ExceptT $ controlIO $ \(RunIO run) -> let
28 run' = RunIO (fmap ExceptT . run . runExceptT)
29 in fmap runExceptT $ f run'
31pshow :: IState -> Err -> String
32pshow ist err = displayDecorated (consoleDecorate ist) .
34 fmap (fancifyAnnots ist) $ pprintErr ist err
36iWarn :: FC -> Doc OutputAnnotation -> Idris ()
39 case idris_outputmode i of
41 do err' <- iRender . fmap (fancifyAnnots i) $
43 then text (show fc) <> colon <//> err
45 runIO . hPutStrLn h $ displayDecorated (consoleDecorate i) err'
47 do err' <- iRender . fmap (fancifyAnnots i) $ err
48 let (str, spans) = displaySpans err'
50 convSExp "warning" (fc_fname fc, fc_start fc, fc_end fc, str, spans) n
52iRender :: Doc a -> Idris (SimpleDoc a)
53iRender d = do w <- getWidth
55 let ideSlave = case idris_outputmode ist of
59 InfinitelyWide -> return $ renderPretty 1.0 1000000000 d
60 ColsWide n -> return $
62 then renderPretty 1.0 1000000000 d
63 else renderPretty 0.8 n d
64 AutomaticWidth | ideSlave -> return $ renderPretty 1.0 1000000000 d
65 | otherwise -> do width <- runIO getScreenWidth
66 return $ renderPretty 0.8 width d
68-- | Write a pretty-printed term to the console with semantic coloring
69consoleDisplayAnnotated :: Handle -> Doc OutputAnnotation -> Idris ()
70consoleDisplayAnnotated h output = do ist <- getIState
71 rendered <- iRender $ output
73 displayDecorated (consoleDecorate ist) $
76iPrintTermWithType :: Doc OutputAnnotation -> Doc OutputAnnotation -> Idris ()
77iPrintTermWithType tm ty = iRenderResult (tm <+> colon <+> align ty)
79-- | Pretty-print a collection of overloadings to REPL or IDESlave - corresponds to :t name
80iPrintFunTypes :: [(Name, Bool)] -> Name -> [(Name, Doc OutputAnnotation)] -> Idris ()
81iPrintFunTypes bnd n [] = iPrintError $ "No such variable " ++ show n
82iPrintFunTypes bnd n overloads = do ist <- getIState
83 let ppo = ppOptionIst ist
84 let infixes = idris_infixes ist
85 let output = vsep (map (uncurry (ppOverload ppo infixes)) overloads)
87 where fullName n = prettyName True True bnd n
88 ppOverload ppo infixes n tm =
89 fullName n <+> colon <+> align tm
91iRenderOutput :: Doc OutputAnnotation -> Idris ()
94 case idris_outputmode i of
95 RawOutput h -> do out <- iRender doc
96 runIO $ putStrLn (displayDecorated (consoleDecorate i) out)
98 do (str, spans) <- fmap displaySpans . iRender . fmap (fancifyAnnots i) $ doc
99 let out = [toSExp str, toSExp spans]
100 runIO . hPutStrLn h $ convSExp "write-decorated" out n
102iRenderResult :: Doc OutputAnnotation -> Idris ()
103iRenderResult d = do ist <- getIState
104 case idris_outputmode ist of
105 RawOutput h -> consoleDisplayAnnotated h d
106 IdeSlave n h -> ideSlaveReturnAnnotated n h d
108ideSlaveReturnWithStatus :: String -> Integer -> Handle -> Doc OutputAnnotation -> Idris ()
109ideSlaveReturnWithStatus status n h out = do
111 (str, spans) <- fmap displaySpans .
113 fmap (fancifyAnnots ist) $
115 let good = [SymbolAtom status, toSExp str, toSExp spans]
116 runIO . hPutStrLn h $ convSExp "return" good n
119-- | Write pretty-printed output to IDESlave with semantic annotations
120ideSlaveReturnAnnotated :: Integer -> Handle -> Doc OutputAnnotation -> Idris ()
121ideSlaveReturnAnnotated = ideSlaveReturnWithStatus "ok"
123-- | Show an error with semantic highlighting
124iRenderError :: Doc OutputAnnotation -> Idris ()
125iRenderError e = do ist <- getIState
126 case idris_outputmode ist of
127 RawOutput h -> consoleDisplayAnnotated h e
128 IdeSlave n h -> ideSlaveReturnWithStatus "error" n h e
130iPrintWithStatus :: String -> String -> Idris ()
131iPrintWithStatus status s = do
133 case idris_outputmode i of
134 RawOutput h -> case s of
136 s -> runIO $ hPutStrLn h s
138 let good = SexpList [SymbolAtom status, toSExp s] in
139 runIO $ hPutStrLn h $ convSExp "return" good n
142iPrintResult :: String -> Idris ()
143iPrintResult = iPrintWithStatus "ok"
145iPrintError :: String -> Idris ()
146iPrintError = iPrintWithStatus "error"
148iputStrLn :: String -> Idris ()
149iputStrLn s = do i <- getIState
150 case idris_outputmode i of
151 RawOutput h -> runIO $ hPutStrLn h s
152 IdeSlave n h -> runIO . hPutStrLn h $ convSExp "write-string" s n
155ideslavePutSExp :: SExpable a => String -> a -> Idris ()
156ideslavePutSExp cmd info = do i <- getIState
157 case idris_outputmode i of
158 IdeSlave n h -> runIO . hPutStrLn h $ convSExp cmd info n
161-- TODO: send structured output similar to the metavariable list
162iputGoal :: SimpleDoc OutputAnnotation -> Idris ()
163iputGoal g = do i <- getIState
164 case idris_outputmode i of
165 RawOutput h -> runIO $ hPutStrLn h (displayDecorated (consoleDecorate i) g)
167 let (str, spans) = displaySpans . fmap (fancifyAnnots i) $ g
168 goal = [toSExp str, toSExp spans]
169 in runIO . hPutStrLn h $ convSExp "write-goal" goal n
171-- | Warn about totality problems without failing to compile
172warnTotality :: Idris ()
173warnTotality = do ist <- getIState
174 mapM_ (warn ist) (nub (idris_totcheckfail ist))
175 where warn ist (fc, e) = iWarn fc (pprintErr ist (Msg e))
178printUndefinedNames :: [Name] -> Doc OutputAnnotation
179printUndefinedNames ns = text "Undefined " <> names <> text "."
180 where names = encloseSep empty empty (char ',') $ map ppName ns
181 ppName = prettyName True True []
184prettyDocumentedIst :: IState
185 -> (Name, PTerm, Maybe (Docstring DocTerm))
186 -> Doc OutputAnnotation
187prettyDocumentedIst ist (name, ty, docs) =
188 prettyName True True [] name <+> colon <+> align (prettyIst ist ty) <$>
189 fromMaybe empty (fmap (\d -> renderDocstring (renderDocTerm ppTm norm) d <> line) docs)
190 where ppTm = pprintDelab ist
191 norm = normaliseAll (tt_ctxt ist) []
194renderExternal :: OutputFmt -> Int -> Doc OutputAnnotation -> Idris String
195renderExternal fmt width doc
196 | width < 1 = throwError . Msg $ "There must be at least one column for the pretty-printer."
200 displayDecorated (decorate fmt) .
201 renderPretty 1.0 width .
202 fmap (fancifyAnnots ist) $
205 decorate _ (AnnFC _) = id
207 decorate HTMLOutput (AnnName _ (Just TypeOutput) d _) =
209 decorate HTMLOutput (AnnName _ (Just FunOutput) d _) =
210 tag "idris-function" d
211 decorate HTMLOutput (AnnName _ (Just DataOutput) d _) =
213 decorate HTMLOutput (AnnName _ (Just MetavarOutput) d _) =
214 tag "idris-metavar" d
215 decorate HTMLOutput (AnnName _ (Just PostulateOutput) d _) =
216 tag "idris-postulate" d
217 decorate HTMLOutput (AnnName _ _ _ _) = id
218 decorate HTMLOutput (AnnBoundName _ True) = tag "idris-bound idris-implicit" Nothing
219 decorate HTMLOutput (AnnBoundName _ False) = tag "idris-bound" Nothing
220 decorate HTMLOutput (AnnConst c) =
221 tag (if constIsType c then "idris-type" else "idris-data")
223 decorate HTMLOutput (AnnData _ _) = tag "idris-data" Nothing
224 decorate HTMLOutput (AnnType _ _) = tag "idris-type" Nothing
225 decorate HTMLOutput AnnKeyword = tag "idris-keyword" Nothing
226 decorate HTMLOutput (AnnTextFmt fmt) =
228 BoldText -> mkTag "strong"
229 ItalicText -> mkTag "em"
230 UnderlineText -> tag "idris-underlined" Nothing
231 where mkTag t x = "<"++t++">"++x++"</"++t++">"
232 decorate HTMLOutput (AnnTerm _ _) = id
233 decorate HTMLOutput (AnnSearchResult _) = id
234 decorate HTMLOutput (AnnErr _) = id
236 decorate LaTeXOutput (AnnName _ (Just TypeOutput) _ _) =
238 decorate LaTeXOutput (AnnName _ (Just FunOutput) _ _) =
239 latex "IdrisFunction"
240 decorate LaTeXOutput (AnnName _ (Just DataOutput) _ _) =
242 decorate LaTeXOutput (AnnName _ (Just MetavarOutput) _ _) =
244 decorate LaTeXOutput (AnnName _ (Just PostulateOutput) _ _) =
245 latex "IdrisPostulate"
246 decorate LaTeXOutput (AnnName _ _ _ _) = id
247 decorate LaTeXOutput (AnnBoundName _ True) = latex "IdrisImplicit"
248 decorate LaTeXOutput (AnnBoundName _ False) = latex "IdrisBound"
249 decorate LaTeXOutput (AnnConst c) =
250 latex $ if constIsType c then "IdrisType" else "IdrisData"
251 decorate LaTeXOutput (AnnData _ _) = latex "IdrisData"
252 decorate LaTeXOutput (AnnType _ _) = latex "IdrisType"
253 decorate LaTeXOutput AnnKeyword = latex "IdrisKeyword"
254 decorate LaTeXOutput (AnnTextFmt fmt) =
256 BoldText -> latex "textbf"
257 ItalicText -> latex "emph"
258 UnderlineText -> latex "underline"
259 decorate LaTeXOutput (AnnTerm _ _) = id
260 decorate LaTeXOutput (AnnSearchResult _) = id
261 decorate LaTeXOutput (AnnErr _) = id
263 tag cls docs str = "<span class=\""++cls++"\""++title++">" ++ str ++ "</span>"
264 where title = maybe "" (\d->" title=\"" ++ d ++ "\"") docs
266 latex cmd str = "\\"++cmd++"{"++str++"}"
268 wrap HTMLOutput str =
269 "<!doctype html><html><head><style>" ++ css ++ "</style></head>" ++
270 "<body><!-- START CODE --><pre>" ++ str ++ "</pre><!-- END CODE --></body></html>"
271 where css = concat . intersperse "\n" $
272 [".idris-data { color: red; } ",
273 ".idris-type { color: blue; }",
274 ".idris-function {color: green; }",
275 ".idris-keyword { font-weight: bold; }",
276 ".idris-bound { color: purple; }",
277 ".idris-implicit { font-style: italic; }",
278 ".idris-underlined { text-decoration: underline; }"]
279 wrap LaTeXOutput str =
280 concat . intersperse "\n" $
281 ["\\documentclass{article}",
282 "\\usepackage{fancyvrb}",
283 "\\usepackage[usenames]{xcolor}"] ++
284 map (\(cmd, color) ->
285 "\\newcommand{\\"++ cmd ++
286 "}[1]{\\textcolor{"++ color ++"}{#1}}")
287 [("IdrisData", "red"), ("IdrisType", "blue"),
288 ("IdrisBound", "magenta"), ("IdrisFunction", "green")] ++
289 ["\\newcommand{\\IdrisKeyword}[1]{{\\underline{#1}}}",
290 "\\newcommand{\\IdrisImplicit}[1]{{\\itshape \\IdrisBound{#1}}}",
294 "\\begin{Verbatim}[commandchars=\\\\\\{\\}]",
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