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)
21import System.FilePath (replaceExtension)
23import Prelude hiding ((<$>))
25import Data.Char (isAlpha)
26import Data.List (nub, intersperse)
27import Data.Maybe (fromMaybe)
29instance MonadException m => MonadException (ExceptT Err m) where
30 controlIO f = ExceptT $ controlIO $ \(RunIO run) -> let
31 run' = RunIO (fmap ExceptT . run . runExceptT)
32 in fmap runExceptT $ f run'
34pshow :: IState -> Err -> String
35pshow ist err = displayDecorated (consoleDecorate ist) .
37 fmap (fancifyAnnots ist True) $ pprintErr ist err
39iWarn :: FC -> Doc OutputAnnotation -> Idris ()
42 case idris_outputmode i of
44 do err' <- iRender . fmap (fancifyAnnots i True) $
46 FC fn _ _ | fn /= "" -> text (show fc) <> colon <//> err
48 runIO . hPutStrLn h $ displayDecorated (consoleDecorate i) err'
50 do err' <- iRender . fmap (fancifyAnnots i True) $ err
51 let (str, spans) = displaySpans err'
53 convSExp "warning" (fc_fname fc, fc_start fc, fc_end fc, str, spans) n
55iRender :: Doc a -> Idris (SimpleDoc a)
56iRender d = do w <- getWidth
58 let ideMode = case idris_outputmode ist of
62 InfinitelyWide -> return $ renderPretty 1.0 1000000000 d
63 ColsWide n -> return $
65 then renderPretty 1.0 1000000000 d
66 else renderPretty 0.8 n d
67 AutomaticWidth | ideMode -> return $ renderPretty 1.0 80 d
68 | otherwise -> do width <- runIO getScreenWidth
69 return $ renderPretty 0.8 width d
71-- | Write a pretty-printed term to the console with semantic coloring
72consoleDisplayAnnotated :: Handle -> Doc OutputAnnotation -> Idris ()
73consoleDisplayAnnotated h output = do ist <- getIState
74 rendered <- iRender $ output
76 displayDecorated (consoleDecorate ist) $
79iPrintTermWithType :: Doc OutputAnnotation -> Doc OutputAnnotation -> Idris ()
80iPrintTermWithType tm ty = iRenderResult (tm <+> colon <+> align ty)
82-- | Pretty-print a collection of overloadings to REPL or IDEMode - corresponds to :t name
83iPrintFunTypes :: [(Name, Bool)] -> Name -> [(Name, Doc OutputAnnotation)] -> Idris ()
84iPrintFunTypes bnd n [] = iPrintError $ "No such variable " ++ show n
85iPrintFunTypes bnd n overloads = do ist <- getIState
86 let ppo = ppOptionIst ist
87 let infixes = idris_infixes ist
88 let output = vsep (map (uncurry (ppOverload ppo infixes)) overloads)
90 where fullName ppo n | length overloads > 1 = prettyName True True bnd n
91 | otherwise = prettyName True (ppopt_impl ppo) bnd n
92 ppOverload ppo infixes n tm =
93 fullName ppo n <+> colon <+> align tm
95iRenderOutput :: Doc OutputAnnotation -> Idris ()
98 case idris_outputmode i of
99 RawOutput h -> do out <- iRender doc
100 runIO $ putStrLn (displayDecorated (consoleDecorate i) out)
102 do (str, spans) <- fmap displaySpans . iRender . fmap (fancifyAnnots i True) $ doc
103 let out = [toSExp str, toSExp spans]
104 runIO . hPutStrLn h $ convSExp "write-decorated" out n
106iRenderResult :: Doc OutputAnnotation -> Idris ()
107iRenderResult d = do ist <- getIState
108 case idris_outputmode ist of
109 RawOutput h -> consoleDisplayAnnotated h d
110 IdeMode n h -> ideModeReturnAnnotated n h d
112ideModeReturnWithStatus :: String -> Integer -> Handle -> Doc OutputAnnotation -> Idris ()
113ideModeReturnWithStatus status n h out = do
115 (str, spans) <- fmap displaySpans .
117 fmap (fancifyAnnots ist True) $
119 let good = [SymbolAtom status, toSExp str, toSExp spans]
120 runIO . hPutStrLn h $ convSExp "return" good n
123-- | Write pretty-printed output to IDEMode with semantic annotations
124ideModeReturnAnnotated :: Integer -> Handle -> Doc OutputAnnotation -> Idris ()
125ideModeReturnAnnotated = ideModeReturnWithStatus "ok"
127-- | Show an error with semantic highlighting
128iRenderError :: Doc OutputAnnotation -> Idris ()
129iRenderError e = do ist <- getIState
130 case idris_outputmode ist of
131 RawOutput h -> consoleDisplayAnnotated h e
132 IdeMode n h -> ideModeReturnWithStatus "error" n h e
134iPrintWithStatus :: String -> String -> Idris ()
135iPrintWithStatus status s = do
137 case idris_outputmode i of
138 RawOutput h -> case s of
140 s -> runIO $ hPutStrLn h s
142 let good = SexpList [SymbolAtom status, toSExp s] in
143 runIO $ hPutStrLn h $ convSExp "return" good n
146iPrintResult :: String -> Idris ()
147iPrintResult = iPrintWithStatus "ok"
149iPrintError :: String -> Idris ()
150iPrintError = iPrintWithStatus "error"
152iputStrLn :: String -> Idris ()
153iputStrLn s = do i <- getIState
154 case idris_outputmode i of
155 RawOutput h -> runIO $ hPutStrLn h s
156 IdeMode n h -> runIO . hPutStrLn h $ convSExp "write-string" s n
159idemodePutSExp :: SExpable a => String -> a -> Idris ()
160idemodePutSExp cmd info = do i <- getIState
161 case idris_outputmode i of
163 runIO . hPutStrLn h $
167-- TODO: send structured output similar to the metavariable list
168iputGoal :: SimpleDoc OutputAnnotation -> Idris ()
169iputGoal g = do i <- getIState
170 case idris_outputmode i of
171 RawOutput h -> runIO $ hPutStrLn h (displayDecorated (consoleDecorate i) g)
173 let (str, spans) = displaySpans . fmap (fancifyAnnots i True) $ g
174 goal = [toSExp str, toSExp spans]
175 in runIO . hPutStrLn h $ convSExp "write-goal" goal n
177-- | Warn about totality problems without failing to compile
178warnTotality :: Idris ()
179warnTotality = do ist <- getIState
180 mapM_ (warn ist) (nub (idris_totcheckfail ist))
181 where warn ist (fc, e) = iWarn fc (pprintErr ist (Msg e))
184printUndefinedNames :: [Name] -> Doc OutputAnnotation
185printUndefinedNames ns = text "Undefined " <> names <> text "."
186 where names = encloseSep empty empty (char ',') $ map ppName ns
187 ppName = prettyName True True []
190prettyDocumentedIst :: IState
191 -> (Name, PTerm, Maybe (Docstring DocTerm))
192 -> Doc OutputAnnotation
193prettyDocumentedIst ist (name, ty, docs) =
194 prettyName True True [] name <+> colon <+> align (prettyIst ist ty) <$>
195 fromMaybe empty (fmap (\d -> renderDocstring (renderDocTerm ppTm norm) d <> line) docs)
196 where ppTm = pprintDelab ist
197 norm = normaliseAll (tt_ctxt ist) []
199sendParserHighlighting :: Idris ()
200sendParserHighlighting =
202 let hs = map unwrap . nub . map wrap $ idris_parserHighlights ist
204 putIState ist {idris_parserHighlights = []}
205 where wrap (fc, a) = (FC' fc, a)
206 unwrap (fc', a) = (unwrapFC fc', a)
208sendHighlighting :: [(FC, OutputAnnotation)] -> Idris ()
209sendHighlighting highlights =
211 case idris_outputmode ist of
212 RawOutput _ -> updateIState $
213 \ist -> ist { idris_highlightedRegions =
214 highlights ++ idris_highlightedRegions ist }
216 let fancier = [ toSExp (fc, fancifyAnnots ist False annot)
217 | (fc, annot) <- highlights, fullFC fc
221 _ -> runIO . hPutStrLn h $
224 (SymbolAtom "highlight-source", fancier)) n
226 where fullFC (FC _ _ _) = True
229-- | Write the highlighting information to a file, for use in external tools
230-- or in editors that don't support the IDE protocol
231writeHighlights :: FilePath -> Idris ()
234 let hs = reverse $ idris_highlightedRegions ist
235 let hfile = replaceExtension f "idh"
236 let annots = toSExp [ (fc, fancifyAnnots ist False annot)
237 | (fc@(FC _ _ _), annot) <- hs
239 runIO $ writeFile hfile $ sExpToString annots
241clearHighlights :: Idris ()
242clearHighlights = updateIState $ \ist -> ist { idris_highlightedRegions = [] }
244renderExternal :: OutputFmt -> Int -> Doc OutputAnnotation -> Idris String
245renderExternal fmt width doc
246 | width < 1 = throwError . Msg $ "There must be at least one column for the pretty-printer."
250 displayDecorated (decorate fmt) .
251 renderPretty 1.0 width .
252 fmap (fancifyAnnots ist True) $
255 decorate _ (AnnFC _) = id
257 decorate HTMLOutput (AnnName _ (Just TypeOutput) d _) =
259 decorate HTMLOutput (AnnName _ (Just FunOutput) d _) =
260 tag "idris-function" d
261 decorate HTMLOutput (AnnName _ (Just DataOutput) d _) =
263 decorate HTMLOutput (AnnName _ (Just MetavarOutput) d _) =
264 tag "idris-metavar" d
265 decorate HTMLOutput (AnnName _ (Just PostulateOutput) d _) =
266 tag "idris-postulate" d
267 decorate HTMLOutput (AnnName _ _ _ _) = id
268 decorate HTMLOutput (AnnBoundName _ True) = tag "idris-bound idris-implicit" Nothing
269 decorate HTMLOutput (AnnBoundName _ False) = tag "idris-bound" Nothing
270 decorate HTMLOutput (AnnConst c) =
271 tag (if constIsType c then "idris-type" else "idris-data")
273 decorate HTMLOutput (AnnData _ _) = tag "idris-data" Nothing
274 decorate HTMLOutput (AnnType _ _) = tag "idris-type" Nothing
275 decorate HTMLOutput AnnKeyword = tag "idris-keyword" Nothing
276 decorate HTMLOutput (AnnTextFmt fmt) =
278 BoldText -> mkTag "strong"
279 ItalicText -> mkTag "em"
280 UnderlineText -> tag "idris-underlined" Nothing
281 where mkTag t x = "<"++t++">"++x++"</"++t++">"
282 decorate HTMLOutput (AnnTerm _ _) = id
283 decorate HTMLOutput (AnnSearchResult _) = id
284 decorate HTMLOutput (AnnErr _) = id
285 decorate HTMLOutput (AnnNamespace _ _) = id
286 decorate HTMLOutput (AnnLink url) =
287 \txt -> "<a href=\"" ++ url ++ "\">" ++ txt ++ "</a>"
288 decorate HTMLOutput AnnQuasiquote = id
289 decorate HTMLOutput AnnAntiquote = id
291 decorate LaTeXOutput (AnnName _ (Just TypeOutput) _ _) =
293 decorate LaTeXOutput (AnnName _ (Just FunOutput) _ _) =
294 latex "IdrisFunction"
295 decorate LaTeXOutput (AnnName _ (Just DataOutput) _ _) =
297 decorate LaTeXOutput (AnnName _ (Just MetavarOutput) _ _) =
299 decorate LaTeXOutput (AnnName _ (Just PostulateOutput) _ _) =
300 latex "IdrisPostulate"
301 decorate LaTeXOutput (AnnName _ _ _ _) = id
302 decorate LaTeXOutput (AnnBoundName _ True) = latex "IdrisImplicit"
303 decorate LaTeXOutput (AnnBoundName _ False) = latex "IdrisBound"
304 decorate LaTeXOutput (AnnConst c) =
305 latex $ if constIsType c then "IdrisType" else "IdrisData"
306 decorate LaTeXOutput (AnnData _ _) = latex "IdrisData"
307 decorate LaTeXOutput (AnnType _ _) = latex "IdrisType"
308 decorate LaTeXOutput AnnKeyword = latex "IdrisKeyword"
309 decorate LaTeXOutput (AnnTextFmt fmt) =
311 BoldText -> latex "textbf"
312 ItalicText -> latex "emph"
313 UnderlineText -> latex "underline"
314 decorate LaTeXOutput (AnnTerm _ _) = id
315 decorate LaTeXOutput (AnnSearchResult _) = id
316 decorate LaTeXOutput (AnnErr _) = id
317 decorate LaTeXOutput (AnnNamespace _ _) = id
318 decorate LaTeXOutput (AnnLink url) = (++ "(\\url{" ++ url ++ "})")
319 decorate LaTeXOutput AnnQuasiquote = id
320 decorate LaTeXOutput AnnAntiquote = id
322 tag cls docs str = "<span class=\""++cls++"\""++title++">" ++ str ++ "</span>"
323 where title = maybe "" (\d->" title=\"" ++ d ++ "\"") docs
325 latex cmd str = "\\"++cmd++"{"++str++"}"
327 wrap HTMLOutput str =
328 "<!doctype html><html><head><style>" ++ css ++ "</style></head>" ++
329 "<body><!-- START CODE --><pre>" ++ str ++ "</pre><!-- END CODE --></body></html>"
330 where css = concat . intersperse "\n" $
331 [".idris-data { color: red; } ",
332 ".idris-type { color: blue; }",
333 ".idris-function {color: green; }",
334 ".idris-keyword { font-weight: bold; }",
335 ".idris-bound { color: purple; }",
336 ".idris-implicit { font-style: italic; }",
337 ".idris-underlined { text-decoration: underline; }"]
338 wrap LaTeXOutput str =
339 concat . intersperse "\n" $
340 ["\\documentclass{article}",
341 "\\usepackage{fancyvrb}",
342 "\\usepackage[usenames]{xcolor}"] ++
343 map (\(cmd, color) ->
344 "\\newcommand{\\"++ cmd ++
345 "}[1]{\\textcolor{"++ color ++"}{#1}}")
346 [("IdrisData", "red"), ("IdrisType", "blue"),
347 ("IdrisBound", "magenta"), ("IdrisFunction", "green")] ++
348 ["\\newcommand{\\IdrisKeyword}[1]{{\\underline{#1}}}",
349 "\\newcommand{\\IdrisImplicit}[1]{{\\itshape \\IdrisBound{#1}}}",
353 "\\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