3Description : Utilities to display Idris' internals and other informtation to the user.
6Maintainer : The Idris Community.
9{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
11module Idris.Output where
14import Idris.Colours (hEndColourise, hStartColourise)
15import Idris.Core.Evaluate (isDConName, isFnName, isTConName, normaliseAll)
17import Idris.Delaborate
18import Idris.Docstrings
22import Util.ScreenSize (getScreenWidth)
23import Util.System (isATTY)
25import Prelude hiding ((<$>))
27import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT)
28import Data.Char (isAlpha)
29import Data.List (intersperse, nub)
30import Data.Maybe (fromMaybe)
31import System.Console.Haskeline.MonadException (MonadException(controlIO),
33import System.FilePath (replaceExtension)
34import System.IO (Handle, hPutStr, hPutStrLn, stdout)
36instance MonadException m => MonadException (ExceptT Err m) where
37 controlIO f = ExceptT $ controlIO $ \(RunIO run) -> let
38 run' = RunIO (fmap ExceptT . run . runExceptT)
39 in fmap runExceptT $ f run'
41pshow :: IState -> Err -> String
42pshow ist err = displayDecorated (consoleDecorate ist) .
44 fmap (fancifyAnnots ist True) $ pprintErr ist err
46iWarn :: FC -> Doc OutputAnnotation -> Idris ()
49 case idris_outputmode i of
51 do err' <- iRender . fmap (fancifyAnnots i True) $
53 FC fn _ _ | fn /= "" -> text (show fc) <> colon <//> err
57 do err' <- iRender . fmap (fancifyAnnots i True) $ err
58 let (str, spans) = displaySpans err'
60 convSExp "warning" (fc_fname fc, fc_start fc, fc_end fc, str, spans) n
62iRender :: Doc a -> Idris (SimpleDoc a)
63iRender d = do w <- getWidth
65 let ideMode = case idris_outputmode ist of
70 InfinitelyWide -> return $ renderPretty 1.0 1000000000 d
71 ColsWide n -> return $
73 then renderPretty 1.0 1000000000 d
74 else renderPretty 0.8 n d
75 AutomaticWidth | ideMode || not tty -> return $ renderPretty 1.0 80 d
76 | otherwise -> do width <- runIO getScreenWidth
77 return $ renderPretty 0.8 width d
79hWriteDoc :: Handle -> IState -> SimpleDoc OutputAnnotation -> Idris ()
80hWriteDoc h ist rendered =
81 do runIO $ displayDecoratedA
83 (maybe (return ()) (hStartColourise h))
84 (maybe (return ()) (hEndColourise h))
85 (fmap (annotationColour ist) rendered)
86 runIO $ hPutStr h "\n" -- newline translation on the output
87 -- stream should take care of this for
90-- | Write a pretty-printed term to the console with semantic coloring
91consoleDisplayAnnotated :: Handle -> Doc OutputAnnotation -> Idris ()
92consoleDisplayAnnotated h output =
94 rendered <- iRender output
95 hWriteDoc h ist rendered
97iPrintTermWithType :: Doc OutputAnnotation -> Doc OutputAnnotation -> Idris ()
98iPrintTermWithType tm ty = iRenderResult (tm <+> colon <+> align ty)
100-- | Pretty-print a collection of overloadings to REPL or IDEMode - corresponds to :t name
101iPrintFunTypes :: [(Name, Bool)] -> Name -> [(Name, Doc OutputAnnotation)] -> Idris ()
102iPrintFunTypes bnd n [] = iPrintError $ "No such variable " ++ show n
103iPrintFunTypes bnd n overloads = do ist <- getIState
104 let ppo = ppOptionIst ist
105 let infixes = idris_infixes ist
106 let output = vsep (map (uncurry (ppOverload ppo infixes)) overloads)
108 where fullName ppo n | length overloads > 1 = prettyName True True bnd n
109 | otherwise = prettyName True (ppopt_impl ppo) bnd n
110 ppOverload ppo infixes n tm =
111 fullName ppo n <+> colon <+> align tm
113iRenderOutput :: Doc OutputAnnotation -> Idris ()
116 case idris_outputmode i of
117 RawOutput h -> do out <- iRender doc
121 do (str, spans) <- fmap displaySpans . iRender . fmap (fancifyAnnots i True) $ doc
122 let out = [toSExp str, toSExp spans]
123 runIO . hPutStrLn h $ convSExp "write-decorated" out n
125iRenderResult :: Doc OutputAnnotation -> Idris ()
126iRenderResult d = do ist <- getIState
127 case idris_outputmode ist of
128 RawOutput h -> consoleDisplayAnnotated h d
129 IdeMode n h -> ideModeReturnAnnotated n h d
131ideModeReturnWithStatus :: String -> Integer -> Handle -> Doc OutputAnnotation -> Idris ()
132ideModeReturnWithStatus status n h out = do
134 (str, spans) <- fmap displaySpans .
136 fmap (fancifyAnnots ist True) $
138 let good = [SymbolAtom status, toSExp str, toSExp spans]
139 runIO . hPutStrLn h $ convSExp "return" good n
142-- | Write pretty-printed output to IDEMode with semantic annotations
143ideModeReturnAnnotated :: Integer -> Handle -> Doc OutputAnnotation -> Idris ()
144ideModeReturnAnnotated = ideModeReturnWithStatus "ok"
146-- | Show an error with semantic highlighting
147iRenderError :: Doc OutputAnnotation -> Idris ()
148iRenderError e = do ist <- getIState
149 case idris_outputmode ist of
150 RawOutput h -> consoleDisplayAnnotated h e
151 IdeMode n h -> ideModeReturnWithStatus "error" n h e
153iPrintWithStatus :: String -> String -> Idris ()
154iPrintWithStatus status s = do
156 case idris_outputmode i of
157 RawOutput h -> case s of
159 s -> runIO $ hPutStrLn h s
161 let good = SexpList [SymbolAtom status, toSExp s] in
162 runIO $ hPutStrLn h $ convSExp "return" good n
165iPrintResult :: String -> Idris ()
166iPrintResult = iPrintWithStatus "ok"
168iPrintError :: String -> Idris ()
169iPrintError = iPrintWithStatus "error"
171iputStrLn :: String -> Idris ()
172iputStrLn s = do i <- getIState
173 case idris_outputmode i of
174 RawOutput h -> runIO $ hPutStrLn h s
175 IdeMode n h -> runIO . hPutStrLn h $ convSExp "write-string" s n
177iputStr :: String -> Idris ()
178iputStr s = do i <- getIState
179 case idris_outputmode i of
180 RawOutput h -> runIO $ hPutStr h s
181 IdeMode n h -> runIO . hPutStr h $ convSExp "write-string" s n
183idemodePutSExp :: SExpable a => String -> a -> Idris ()
184idemodePutSExp cmd info = do i <- getIState
185 case idris_outputmode i of
187 runIO . hPutStrLn h $
191-- TODO: send structured output similar to the metavariable list
192iputGoal :: SimpleDoc OutputAnnotation -> Idris ()
193iputGoal g = do i <- getIState
194 case idris_outputmode i of
195 RawOutput h -> hWriteDoc h i g
197 let (str, spans) = displaySpans . fmap (fancifyAnnots i True) $ g
198 goal = [toSExp str, toSExp spans]
199 in runIO . hPutStrLn h $ convSExp "write-goal" goal n
201-- | Warn about totality problems without failing to compile
202warnTotality :: Idris ()
203warnTotality = do ist <- getIState
204 mapM_ (warn ist) (nub (idris_totcheckfail ist))
205 where warn ist (fc, e) = iWarn fc (pprintErr ist (Msg e))
208printUndefinedNames :: [Name] -> Doc OutputAnnotation
209printUndefinedNames ns = text "Undefined " <> names <> text "."
210 where names = encloseSep empty empty (char ',') $ map ppName ns
211 ppName = prettyName True True []
214prettyDocumentedIst :: IState
215 -> (Name, PTerm, Maybe (Docstring DocTerm))
216 -> Doc OutputAnnotation
217prettyDocumentedIst ist (name, ty, docs) =
218 prettyName True True [] name <+> colon <+> align (prettyIst ist ty) <$>
219 fromMaybe empty (fmap (\d -> renderDocstring (renderDocTerm ppTm norm) d <> line) docs)
220 where ppTm = pprintDelab ist
221 norm = normaliseAll (tt_ctxt ist) []
223sendParserHighlighting :: Idris ()
224sendParserHighlighting =
226 let hs = map unwrap . nub . map wrap $ idris_parserHighlights ist
229 putIState ist {idris_parserHighlights = []}
230 where wrap (fc, a) = (FC' fc, a)
231 unwrap (fc', a) = (unwrapFC fc', a)
233sendHighlighting :: [(FC, OutputAnnotation)] -> Idris ()
234sendHighlighting highlights =
236 case idris_outputmode ist of
237 RawOutput _ -> updateIState $
238 \ist -> ist { idris_highlightedRegions =
239 highlights ++ idris_highlightedRegions ist }
241 let fancier = [ toSExp (fc, fancifyAnnots ist False annot)
242 | (fc, annot) <- highlights, fullFC fc
246 _ -> runIO . hPutStrLn h $
249 (SymbolAtom "highlight-source", fancier)) n
251 where fullFC (FC _ _ _) = True
254-- | Write the highlighting information to a file, for use in external tools
255-- or in editors that don't support the IDE protocol
256writeHighlights :: FilePath -> Idris ()
259 let hs = reverse $ idris_highlightedRegions ist
260 let hfile = replaceExtension f "idh"
261 let annots = toSExp [ (fc, fancifyAnnots ist False annot)
262 | (fc@(FC _ _ _), annot) <- hs
264 runIO $ writeFile hfile $ sExpToString annots
266clearHighlights :: Idris ()
267clearHighlights = updateIState $ \ist -> ist { idris_highlightedRegions = [] }
269renderExternal :: OutputFmt -> Int -> Doc OutputAnnotation -> Idris String
270renderExternal fmt width doc
271 | width < 1 = throwError . Msg $ "There must be at least one column for the pretty-printer."
275 displayDecorated (decorate fmt) .
276 renderPretty 1.0 width .
277 fmap (fancifyAnnots ist True) $
280 decorate _ (AnnFC _) = id
282 decorate HTMLOutput (AnnName _ (Just TypeOutput) d _) =
284 decorate HTMLOutput (AnnName _ (Just FunOutput) d _) =
285 tag "idris-function" d
286 decorate HTMLOutput (AnnName _ (Just DataOutput) d _) =
288 decorate HTMLOutput (AnnName _ (Just MetavarOutput) d _) =
289 tag "idris-metavar" d
290 decorate HTMLOutput (AnnName _ (Just PostulateOutput) d _) =
291 tag "idris-postulate" d
292 decorate HTMLOutput (AnnName _ _ _ _) = id
293 decorate HTMLOutput (AnnBoundName _ True) = tag "idris-bound idris-implicit" Nothing
294 decorate HTMLOutput (AnnBoundName _ False) = tag "idris-bound" Nothing
295 decorate HTMLOutput (AnnConst c) =
296 tag (if constIsType c then "idris-type" else "idris-data")
298 decorate HTMLOutput (AnnData _ _) = tag "idris-data" Nothing
299 decorate HTMLOutput (AnnType _ _) = tag "idris-type" Nothing
300 decorate HTMLOutput AnnKeyword = tag "idris-keyword" Nothing
301 decorate HTMLOutput (AnnTextFmt fmt) =
303 BoldText -> mkTag "strong"
304 ItalicText -> mkTag "em"
305 UnderlineText -> tag "idris-underlined" Nothing
306 where mkTag t x = "<"++t++">"++x++"</"++t++">"
307 decorate HTMLOutput (AnnTerm _ _) = id
308 decorate HTMLOutput (AnnSearchResult _) = id
309 decorate HTMLOutput (AnnErr _) = id
310 decorate HTMLOutput (AnnNamespace _ _) = id
311 decorate HTMLOutput (AnnLink url) =
312 \txt -> "<a href=\"" ++ url ++ "\">" ++ txt ++ "</a>"
313 decorate HTMLOutput AnnQuasiquote = id
314 decorate HTMLOutput AnnAntiquote = id
316 decorate LaTeXOutput (AnnName _ (Just TypeOutput) _ _) =
318 decorate LaTeXOutput (AnnName _ (Just FunOutput) _ _) =
319 latex "IdrisFunction"
320 decorate LaTeXOutput (AnnName _ (Just DataOutput) _ _) =
322 decorate LaTeXOutput (AnnName _ (Just MetavarOutput) _ _) =
324 decorate LaTeXOutput (AnnName _ (Just PostulateOutput) _ _) =
325 latex "IdrisPostulate"
326 decorate LaTeXOutput (AnnName _ _ _ _) = id
327 decorate LaTeXOutput (AnnBoundName _ True) = latex "IdrisImplicit"
328 decorate LaTeXOutput (AnnBoundName _ False) = latex "IdrisBound"
329 decorate LaTeXOutput (AnnConst c) =
330 latex $ if constIsType c then "IdrisType" else "IdrisData"
331 decorate LaTeXOutput (AnnData _ _) = latex "IdrisData"
332 decorate LaTeXOutput (AnnType _ _) = latex "IdrisType"
333 decorate LaTeXOutput AnnKeyword = latex "IdrisKeyword"
334 decorate LaTeXOutput (AnnTextFmt fmt) =
336 BoldText -> latex "textbf"
337 ItalicText -> latex "emph"
338 UnderlineText -> latex "underline"
339 decorate LaTeXOutput (AnnTerm _ _) = id
340 decorate LaTeXOutput (AnnSearchResult _) = id
341 decorate LaTeXOutput (AnnErr _) = id
342 decorate LaTeXOutput (AnnNamespace _ _) = id
343 decorate LaTeXOutput (AnnLink url) = (++ "(\\url{" ++ url ++ "})")
344 decorate LaTeXOutput AnnQuasiquote = id
345 decorate LaTeXOutput AnnAntiquote = id
347 tag cls docs str = "<span class=\""++cls++"\""++title++">" ++ str ++ "</span>"
348 where title = maybe "" (\d->" title=\"" ++ d ++ "\"") docs
350 latex cmd str = "\\"++cmd++"{"++str++"}"
352 wrap HTMLOutput str =
353 "<!doctype html><html><head><style>" ++ css ++ "</style></head>" ++
354 "<body><!-- START CODE --><pre>" ++ str ++ "</pre><!-- END CODE --></body></html>"
355 where css = concat . intersperse "\n" $
356 [".idris-data { color: red; } ",
357 ".idris-type { color: blue; }",
358 ".idris-function {color: green; }",
359 ".idris-keyword { font-weight: bold; }",
360 ".idris-bound { color: purple; }",
361 ".idris-implicit { font-style: italic; }",
362 ".idris-underlined { text-decoration: underline; }"]
363 wrap LaTeXOutput str =
364 concat . intersperse "\n" $
365 ["\\documentclass{article}",
366 "\\usepackage{fancyvrb}",
367 "\\usepackage[usenames]{xcolor}"] ++
368 map (\(cmd, color) ->
369 "\\newcommand{\\"++ cmd ++
370 "}[1]{\\textcolor{"++ color ++"}{#1}}")
371 [("IdrisData", "red"), ("IdrisType", "blue"),
372 ("IdrisBound", "magenta"), ("IdrisFunction", "green")] ++
373 ["\\newcommand{\\IdrisKeyword}[1]{{\\underline{#1}}}",
374 "\\newcommand{\\IdrisImplicit}[1]{{\\itshape \\IdrisBound{#1}}}",
378 "\\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