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
178idemodePutSExp :: SExpable a => String -> a -> Idris ()
179idemodePutSExp cmd info = do i <- getIState
180 case idris_outputmode i of
182 runIO . hPutStrLn h $
186-- TODO: send structured output similar to the metavariable list
187iputGoal :: SimpleDoc OutputAnnotation -> Idris ()
188iputGoal g = do i <- getIState
189 case idris_outputmode i of
190 RawOutput h -> hWriteDoc h i g
192 let (str, spans) = displaySpans . fmap (fancifyAnnots i True) $ g
193 goal = [toSExp str, toSExp spans]
194 in runIO . hPutStrLn h $ convSExp "write-goal" goal n
196-- | Warn about totality problems without failing to compile
197warnTotality :: Idris ()
198warnTotality = do ist <- getIState
199 mapM_ (warn ist) (nub (idris_totcheckfail ist))
200 where warn ist (fc, e) = iWarn fc (pprintErr ist (Msg e))
203printUndefinedNames :: [Name] -> Doc OutputAnnotation
204printUndefinedNames ns = text "Undefined " <> names <> text "."
205 where names = encloseSep empty empty (char ',') $ map ppName ns
206 ppName = prettyName True True []
209prettyDocumentedIst :: IState
210 -> (Name, PTerm, Maybe (Docstring DocTerm))
211 -> Doc OutputAnnotation
212prettyDocumentedIst ist (name, ty, docs) =
213 prettyName True True [] name <+> colon <+> align (prettyIst ist ty) <$>
214 fromMaybe empty (fmap (\d -> renderDocstring (renderDocTerm ppTm norm) d <> line) docs)
215 where ppTm = pprintDelab ist
216 norm = normaliseAll (tt_ctxt ist) []
218sendParserHighlighting :: Idris ()
219sendParserHighlighting =
221 let hs = map unwrap . nub . map wrap $ idris_parserHighlights ist
224 putIState ist {idris_parserHighlights = []}
225 where wrap (fc, a) = (FC' fc, a)
226 unwrap (fc', a) = (unwrapFC fc', a)
228sendHighlighting :: [(FC, OutputAnnotation)] -> Idris ()
229sendHighlighting highlights =
231 case idris_outputmode ist of
232 RawOutput _ -> updateIState $
233 \ist -> ist { idris_highlightedRegions =
234 highlights ++ idris_highlightedRegions ist }
236 let fancier = [ toSExp (fc, fancifyAnnots ist False annot)
237 | (fc, annot) <- highlights, fullFC fc
241 _ -> runIO . hPutStrLn h $
244 (SymbolAtom "highlight-source", fancier)) n
246 where fullFC (FC _ _ _) = True
249-- | Write the highlighting information to a file, for use in external tools
250-- or in editors that don't support the IDE protocol
251writeHighlights :: FilePath -> Idris ()
254 let hs = reverse $ idris_highlightedRegions ist
255 let hfile = replaceExtension f "idh"
256 let annots = toSExp [ (fc, fancifyAnnots ist False annot)
257 | (fc@(FC _ _ _), annot) <- hs
259 runIO $ writeFile hfile $ sExpToString annots
261clearHighlights :: Idris ()
262clearHighlights = updateIState $ \ist -> ist { idris_highlightedRegions = [] }
264renderExternal :: OutputFmt -> Int -> Doc OutputAnnotation -> Idris String
265renderExternal fmt width doc
266 | width < 1 = throwError . Msg $ "There must be at least one column for the pretty-printer."
270 displayDecorated (decorate fmt) .
271 renderPretty 1.0 width .
272 fmap (fancifyAnnots ist True) $
275 decorate _ (AnnFC _) = id
277 decorate HTMLOutput (AnnName _ (Just TypeOutput) d _) =
279 decorate HTMLOutput (AnnName _ (Just FunOutput) d _) =
280 tag "idris-function" d
281 decorate HTMLOutput (AnnName _ (Just DataOutput) d _) =
283 decorate HTMLOutput (AnnName _ (Just MetavarOutput) d _) =
284 tag "idris-metavar" d
285 decorate HTMLOutput (AnnName _ (Just PostulateOutput) d _) =
286 tag "idris-postulate" d
287 decorate HTMLOutput (AnnName _ _ _ _) = id
288 decorate HTMLOutput (AnnBoundName _ True) = tag "idris-bound idris-implicit" Nothing
289 decorate HTMLOutput (AnnBoundName _ False) = tag "idris-bound" Nothing
290 decorate HTMLOutput (AnnConst c) =
291 tag (if constIsType c then "idris-type" else "idris-data")
293 decorate HTMLOutput (AnnData _ _) = tag "idris-data" Nothing
294 decorate HTMLOutput (AnnType _ _) = tag "idris-type" Nothing
295 decorate HTMLOutput AnnKeyword = tag "idris-keyword" Nothing
296 decorate HTMLOutput (AnnTextFmt fmt) =
298 BoldText -> mkTag "strong"
299 ItalicText -> mkTag "em"
300 UnderlineText -> tag "idris-underlined" Nothing
301 where mkTag t x = "<"++t++">"++x++"</"++t++">"
302 decorate HTMLOutput (AnnTerm _ _) = id
303 decorate HTMLOutput (AnnSearchResult _) = id
304 decorate HTMLOutput (AnnErr _) = id
305 decorate HTMLOutput (AnnNamespace _ _) = id
306 decorate HTMLOutput (AnnLink url) =
307 \txt -> "<a href=\"" ++ url ++ "\">" ++ txt ++ "</a>"
308 decorate HTMLOutput AnnQuasiquote = id
309 decorate HTMLOutput AnnAntiquote = id
311 decorate LaTeXOutput (AnnName _ (Just TypeOutput) _ _) =
313 decorate LaTeXOutput (AnnName _ (Just FunOutput) _ _) =
314 latex "IdrisFunction"
315 decorate LaTeXOutput (AnnName _ (Just DataOutput) _ _) =
317 decorate LaTeXOutput (AnnName _ (Just MetavarOutput) _ _) =
319 decorate LaTeXOutput (AnnName _ (Just PostulateOutput) _ _) =
320 latex "IdrisPostulate"
321 decorate LaTeXOutput (AnnName _ _ _ _) = id
322 decorate LaTeXOutput (AnnBoundName _ True) = latex "IdrisImplicit"
323 decorate LaTeXOutput (AnnBoundName _ False) = latex "IdrisBound"
324 decorate LaTeXOutput (AnnConst c) =
325 latex $ if constIsType c then "IdrisType" else "IdrisData"
326 decorate LaTeXOutput (AnnData _ _) = latex "IdrisData"
327 decorate LaTeXOutput (AnnType _ _) = latex "IdrisType"
328 decorate LaTeXOutput AnnKeyword = latex "IdrisKeyword"
329 decorate LaTeXOutput (AnnTextFmt fmt) =
331 BoldText -> latex "textbf"
332 ItalicText -> latex "emph"
333 UnderlineText -> latex "underline"
334 decorate LaTeXOutput (AnnTerm _ _) = id
335 decorate LaTeXOutput (AnnSearchResult _) = id
336 decorate LaTeXOutput (AnnErr _) = id
337 decorate LaTeXOutput (AnnNamespace _ _) = id
338 decorate LaTeXOutput (AnnLink url) = (++ "(\\url{" ++ url ++ "})")
339 decorate LaTeXOutput AnnQuasiquote = id
340 decorate LaTeXOutput AnnAntiquote = id
342 tag cls docs str = "<span class=\""++cls++"\""++title++">" ++ str ++ "</span>"
343 where title = maybe "" (\d->" title=\"" ++ d ++ "\"") docs
345 latex cmd str = "\\"++cmd++"{"++str++"}"
347 wrap HTMLOutput str =
348 "<!doctype html><html><head><style>" ++ css ++ "</style></head>" ++
349 "<body><!-- START CODE --><pre>" ++ str ++ "</pre><!-- END CODE --></body></html>"
350 where css = concat . intersperse "\n" $
351 [".idris-data { color: red; } ",
352 ".idris-type { color: blue; }",
353 ".idris-function {color: green; }",
354 ".idris-keyword { font-weight: bold; }",
355 ".idris-bound { color: purple; }",
356 ".idris-implicit { font-style: italic; }",
357 ".idris-underlined { text-decoration: underline; }"]
358 wrap LaTeXOutput str =
359 concat . intersperse "\n" $
360 ["\\documentclass{article}",
361 "\\usepackage{fancyvrb}",
362 "\\usepackage[usenames]{xcolor}"] ++
363 map (\(cmd, color) ->
364 "\\newcommand{\\"++ cmd ++
365 "}[1]{\\textcolor{"++ color ++"}{#1}}")
366 [("IdrisData", "red"), ("IdrisType", "blue"),
367 ("IdrisBound", "magenta"), ("IdrisFunction", "green")] ++
368 ["\\newcommand{\\IdrisKeyword}[1]{{\\underline{#1}}}",
369 "\\newcommand{\\IdrisImplicit}[1]{{\\itshape \\IdrisBound{#1}}}",
373 "\\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