3Description : Utilities to display Idris' internals and other informtation to the user.
6Maintainer : The Idris Community.
9{-# LANGUAGE FlexibleInstances #-}
10{-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
12module Idris.Output (clearHighlights, idemodePutSExp, iPrintError, iPrintFunTypes,
13 iPrintResult, iPrintTermWithType, iputGoal, iputStr, iputStrLn,
14 iRender, iRenderError, iRenderOutput, iRenderResult, iWarn,
15 prettyDocumentedIst, printUndefinedNames, pshow, renderExternal,
16 sendHighlighting, sendParserHighlighting, warnTotality,
17 writeHighlights) where
20import Idris.Colours (hEndColourise, hStartColourise)
21import Idris.Core.Evaluate (normaliseAll)
23import Idris.Delaborate
24import Idris.Docstrings
29import Util.ScreenSize (getScreenWidth)
30import Util.System (isATTY)
32import Prelude hiding ((<$>))
34import Control.Monad.Trans.Except (ExceptT(ExceptT), runExceptT)
35import Data.List (intersperse, nub)
36import Data.Maybe (fromMaybe)
37import System.Console.Haskeline.MonadException (MonadException(controlIO),
39import System.FilePath (replaceExtension)
40import System.IO (Handle, hPutStr, hPutStrLn)
42instance MonadException m => MonadException (ExceptT Err m) where
43 controlIO f = ExceptT $ controlIO $ \(RunIO run) -> let
44 run' = RunIO (fmap ExceptT . run . runExceptT)
45 in fmap runExceptT $ f run'
47pshow :: IState -> Err -> String
48pshow ist err = displayDecorated (consoleDecorate ist) .
50 fmap (fancifyAnnots ist True) $ pprintErr ist err
52iWarn :: FC -> Doc OutputAnnotation -> Idris ()
55 case idris_outputmode i of
57 do err' <- iRender . fmap (fancifyAnnots i True) $
59 FC fn _ _ | fn /= "" -> text (show fc) <> colon <//> err
63 do err' <- iRender . fmap (fancifyAnnots i True) $ err
64 let (str, spans) = displaySpans err'
66 convSExp "warning" (fc_fname fc, fc_start fc, fc_end fc, str, spans) n
68iRender :: Doc a -> Idris (SimpleDoc a)
69iRender d = do w <- getWidth
71 let ideMode = case idris_outputmode ist of
76 InfinitelyWide -> return $ renderPretty 1.0 1000000000 d
77 ColsWide n -> return $
79 then renderPretty 1.0 1000000000 d
80 else renderPretty 0.8 n d
81 AutomaticWidth | ideMode || not tty -> return $ renderPretty 1.0 80 d
82 | otherwise -> do width <- runIO getScreenWidth
83 return $ renderPretty 0.8 width d
85hWriteDoc :: Handle -> IState -> SimpleDoc OutputAnnotation -> Idris ()
86hWriteDoc h ist rendered =
87 do runIO $ displayDecoratedA
89 (maybe (return ()) (hStartColourise h))
90 (maybe (return ()) (hEndColourise h))
91 (fmap (annotationColour ist) rendered)
92 runIO $ hPutStr h "\n" -- newline translation on the output
93 -- stream should take care of this for
96-- | Write a pretty-printed term to the console with semantic coloring
97consoleDisplayAnnotated :: Handle -> Doc OutputAnnotation -> Idris ()
98consoleDisplayAnnotated h output =
100 rendered <- iRender output
101 hWriteDoc h ist rendered
103iPrintTermWithType :: Doc OutputAnnotation -> Doc OutputAnnotation -> Idris ()
104iPrintTermWithType tm ty = iRenderResult (tm <+> colon <+> align ty)
106-- | Pretty-print a collection of overloadings to REPL or IDEMode - corresponds to :t name
107iPrintFunTypes :: [(Name, Bool)] -> Name -> [(Name, Doc OutputAnnotation)] -> Idris ()
108iPrintFunTypes bnd n [] = iPrintError $ "No such variable " ++ show n
109iPrintFunTypes bnd n overloads = do ist <- getIState
110 let ppo = ppOptionIst ist
111 let infixes = idris_infixes ist
112 let output = vsep (map (uncurry (ppOverload ppo infixes)) overloads)
114 where fullName ppo n | length overloads > 1 = prettyName True True bnd n
115 | otherwise = prettyName True (ppopt_impl ppo) bnd n
116 ppOverload ppo infixes n tm =
117 fullName ppo n <+> colon <+> align tm
119iRenderOutput :: Doc OutputAnnotation -> Idris ()
122 case idris_outputmode i of
123 RawOutput h -> do out <- iRender doc
127 do (str, spans) <- fmap displaySpans . iRender . fmap (fancifyAnnots i True) $ doc
128 let out = [toSExp str, toSExp spans]
129 runIO . hPutStrLn h $ convSExp "write-decorated" out n
131iRenderResult :: Doc OutputAnnotation -> Idris ()
132iRenderResult d = do ist <- getIState
133 case idris_outputmode ist of
134 RawOutput h -> consoleDisplayAnnotated h d
135 IdeMode n h -> ideModeReturnAnnotated n h d
137ideModeReturnWithStatus :: String -> Integer -> Handle -> Doc OutputAnnotation -> Idris ()
138ideModeReturnWithStatus status n h out = do
140 (str, spans) <- fmap displaySpans .
142 fmap (fancifyAnnots ist True) $
144 let good = [SymbolAtom status, toSExp str, toSExp spans]
145 runIO . hPutStrLn h $ convSExp "return" good n
148-- | Write pretty-printed output to IDEMode with semantic annotations
149ideModeReturnAnnotated :: Integer -> Handle -> Doc OutputAnnotation -> Idris ()
150ideModeReturnAnnotated = ideModeReturnWithStatus "ok"
152-- | Show an error with semantic highlighting
153iRenderError :: Doc OutputAnnotation -> Idris ()
154iRenderError e = do ist <- getIState
155 case idris_outputmode ist of
156 RawOutput h -> consoleDisplayAnnotated h e
157 IdeMode n h -> ideModeReturnWithStatus "error" n h e
159iPrintWithStatus :: String -> String -> Idris ()
160iPrintWithStatus status s = do
162 case idris_outputmode i of
163 RawOutput h -> case s of
165 s -> runIO $ hPutStrLn h s
167 let good = SexpList [SymbolAtom status, toSExp s] in
168 runIO $ hPutStrLn h $ convSExp "return" good n
171iPrintResult :: String -> Idris ()
172iPrintResult = iPrintWithStatus "ok"
174iPrintError :: String -> Idris ()
175iPrintError = iPrintWithStatus "error"
177iputStrLn :: String -> Idris ()
178iputStrLn s = do i <- getIState
179 case idris_outputmode i of
180 RawOutput h -> runIO $ hPutStrLn h s
181 IdeMode n h -> runIO . hPutStrLn h $ convSExp "write-string" s n
183iputStr :: String -> Idris ()
184iputStr s = do i <- getIState
185 case idris_outputmode i of
186 RawOutput h -> runIO $ hPutStr h s
187 IdeMode n h -> runIO . hPutStr h $ convSExp "write-string" s n
189idemodePutSExp :: SExpable a => String -> a -> Idris ()
190idemodePutSExp cmd info = do i <- getIState
191 case idris_outputmode i of
193 runIO . hPutStrLn h $
197-- TODO: send structured output similar to the metavariable list
198iputGoal :: SimpleDoc OutputAnnotation -> Idris ()
199iputGoal g = do i <- getIState
200 case idris_outputmode i of
201 RawOutput h -> hWriteDoc h i g
203 let (str, spans) = displaySpans . fmap (fancifyAnnots i True) $ g
204 goal = [toSExp str, toSExp spans]
205 in runIO . hPutStrLn h $ convSExp "write-goal" goal n
207-- | Warn about totality problems without failing to compile
208warnTotality :: Idris ()
209warnTotality = do ist <- getIState
210 mapM_ (warn ist) (nub (idris_totcheckfail ist))
211 where warn ist (fc, e) = iWarn fc (pprintErr ist (Msg e))
214printUndefinedNames :: [Name] -> Doc OutputAnnotation
215printUndefinedNames ns = text "Undefined " <> names <> text "."
216 where names = encloseSep empty empty (char ',') $ map ppName ns
217 ppName = prettyName True True []
220prettyDocumentedIst :: IState
221 -> (Name, PTerm, Maybe (Docstring DocTerm))
222 -> Doc OutputAnnotation
223prettyDocumentedIst ist (name, ty, docs) =
224 prettyName True True [] name <+> colon <+> align (prettyIst ist ty) <$>
225 fromMaybe empty (fmap (\d -> renderDocstring (renderDocTerm ppTm norm) d <> line) docs)
226 where ppTm = pprintDelab ist
227 norm = normaliseAll (tt_ctxt ist) []
229sendParserHighlighting :: Idris ()
230sendParserHighlighting =
232 let hs = map unwrap . nub . map wrap $ idris_parserHighlights ist
235 putIState ist {idris_parserHighlights = []}
236 where wrap (fc, a) = (FC' fc, a)
237 unwrap (fc', a) = (unwrapFC fc', a)
239sendHighlighting :: [(FC, OutputAnnotation)] -> Idris ()
240sendHighlighting highlights =
242 case idris_outputmode ist of
243 RawOutput _ -> updateIState $
244 \ist -> ist { idris_highlightedRegions =
245 highlights ++ idris_highlightedRegions ist }
247 let fancier = [ toSExp (fc, fancifyAnnots ist False annot)
248 | (fc, annot) <- highlights, fullFC fc
252 _ -> runIO . hPutStrLn h $
255 (SymbolAtom "highlight-source", fancier)) n
257 where fullFC (FC _ _ _) = True
260-- | Write the highlighting information to a file, for use in external tools
261-- or in editors that don't support the IDE protocol
262writeHighlights :: FilePath -> Idris ()
265 let hs = reverse $ idris_highlightedRegions ist
266 let hfile = replaceExtension f "idh"
267 let annots = toSExp [ (fc, fancifyAnnots ist False annot)
268 | (fc@(FC _ _ _), annot) <- hs
270 runIO $ writeFile hfile $ sExpToString annots
272clearHighlights :: Idris ()
273clearHighlights = updateIState $ \ist -> ist { idris_highlightedRegions = [] }
275renderExternal :: OutputFmt -> Int -> Doc OutputAnnotation -> Idris String
276renderExternal fmt width doc
277 | width < 1 = throwError . Msg $ "There must be at least one column for the pretty-printer."
281 displayDecorated (decorate fmt) .
282 renderPretty 1.0 width .
283 fmap (fancifyAnnots ist True) $
286 decorate _ (AnnFC _) = id
288 decorate HTMLOutput (AnnName _ (Just TypeOutput) d _) =
290 decorate HTMLOutput (AnnName _ (Just FunOutput) d _) =
291 tag "idris-function" d
292 decorate HTMLOutput (AnnName _ (Just DataOutput) d _) =
294 decorate HTMLOutput (AnnName _ (Just MetavarOutput) d _) =
295 tag "idris-metavar" d
296 decorate HTMLOutput (AnnName _ (Just PostulateOutput) d _) =
297 tag "idris-postulate" d
298 decorate HTMLOutput (AnnName _ _ _ _) = id
299 decorate HTMLOutput (AnnBoundName _ True) = tag "idris-bound idris-implicit" Nothing
300 decorate HTMLOutput (AnnBoundName _ False) = tag "idris-bound" Nothing
301 decorate HTMLOutput (AnnConst c) =
302 tag (if constIsType c then "idris-type" else "idris-data")
304 decorate HTMLOutput (AnnData _ _) = tag "idris-data" Nothing
305 decorate HTMLOutput (AnnType _ _) = tag "idris-type" Nothing
306 decorate HTMLOutput AnnKeyword = tag "idris-keyword" Nothing
307 decorate HTMLOutput (AnnTextFmt fmt) =
309 BoldText -> mkTag "strong"
310 ItalicText -> mkTag "em"
311 UnderlineText -> tag "idris-underlined" Nothing
312 where mkTag t x = "<"++t++">"++x++"</"++t++">"
313 decorate HTMLOutput (AnnTerm _ _) = id
314 decorate HTMLOutput (AnnSearchResult _) = id
315 decorate HTMLOutput (AnnErr _) = id
316 decorate HTMLOutput (AnnNamespace _ _) = id
317 decorate HTMLOutput (AnnLink url) =
318 \txt -> "<a href=\"" ++ url ++ "\">" ++ txt ++ "</a>"
319 decorate HTMLOutput AnnQuasiquote = id
320 decorate HTMLOutput AnnAntiquote = id
321 decorate HTMLOutput (AnnSyntax c) = \txt -> c
323 decorate LaTeXOutput (AnnName _ (Just TypeOutput) _ _) =
325 decorate LaTeXOutput (AnnName _ (Just FunOutput) _ _) =
326 latex "IdrisFunction"
327 decorate LaTeXOutput (AnnName _ (Just DataOutput) _ _) =
329 decorate LaTeXOutput (AnnName _ (Just MetavarOutput) _ _) =
331 decorate LaTeXOutput (AnnName _ (Just PostulateOutput) _ _) =
332 latex "IdrisPostulate"
333 decorate LaTeXOutput (AnnName _ _ _ _) = id
334 decorate LaTeXOutput (AnnBoundName _ True) = latex "IdrisImplicit"
335 decorate LaTeXOutput (AnnBoundName _ False) = latex "IdrisBound"
336 decorate LaTeXOutput (AnnConst c) =
337 latex $ if constIsType c then "IdrisType" else "IdrisData"
338 decorate LaTeXOutput (AnnData _ _) = latex "IdrisData"
339 decorate LaTeXOutput (AnnType _ _) = latex "IdrisType"
340 decorate LaTeXOutput AnnKeyword = latex "IdrisKeyword"
341 decorate LaTeXOutput (AnnTextFmt fmt) =
343 BoldText -> latex "textbf"
344 ItalicText -> latex "emph"
345 UnderlineText -> latex "underline"
346 decorate LaTeXOutput (AnnTerm _ _) = id
347 decorate LaTeXOutput (AnnSearchResult _) = id
348 decorate LaTeXOutput (AnnErr _) = id
349 decorate LaTeXOutput (AnnNamespace _ _) = id
350 decorate LaTeXOutput (AnnLink url) = (++ "(\\url{" ++ url ++ "})")
351 decorate LaTeXOutput AnnQuasiquote = id
352 decorate LaTeXOutput AnnAntiquote = id
353 decorate LaTeXOutput (AnnSyntax c) = \txt ->
355 "\\" -> "\\textbackslash"
361 tag cls docs str = "<span class=\""++cls++"\""++title++">" ++ str ++ "</span>"
362 where title = maybe "" (\d->" title=\"" ++ d ++ "\"") docs
364 latex cmd str = "\\"++cmd++"{"++str++"}"
366 wrap HTMLOutput str =
367 "<!doctype html><html><head><style>" ++ css ++ "</style></head>" ++
368 "<body><!-- START CODE --><pre>" ++ str ++ "</pre><!-- END CODE --></body></html>"
369 where css = concat . intersperse "\n" $
370 [".idris-data { color: red; } ",
371 ".idris-type { color: blue; }",
372 ".idris-function {color: green; }",
373 ".idris-metavar {color: turquoise; }",
374 ".idris-keyword { font-weight: bold; }",
375 ".idris-bound { color: purple; }",
376 ".idris-implicit { font-style: italic; }",
377 ".idris-underlined { text-decoration: underline; }"]
378 wrap LaTeXOutput str =
379 concat . intersperse "\n" $
380 ["\\documentclass{article}",
381 "\\usepackage{fancyvrb}",
382 "\\usepackage[usenames]{xcolor}"] ++
383 map (\(cmd, color) ->
384 "\\newcommand{\\"++ cmd ++
385 "}[1]{\\textcolor{"++ color ++"}{#1}}")
386 [("IdrisData", "red"), ("IdrisType", "blue"),
387 ("IdrisBound", "magenta"), ("IdrisFunction", "green"),
388 ("IdrisMetavar", "cyan")] ++
389 ["\\newcommand{\\IdrisKeyword}[1]{{\\underline{#1}}}",
390 "\\newcommand{\\IdrisImplicit}[1]{{\\itshape \\IdrisBound{#1}}}",
394 "\\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