1{-# LANGUAGE BangPatterns, OverloadedStrings #-}
29import Control.Concurrent
30import Control.Exception (SomeException, AsyncException(UserInterrupt), catch, fromException, throw)
31import Control.Monad (when)
32import qualified Data.ByteString.Builder as B
33import qualified Data.NonEmptyList as NE
34import qualified System.Exit as Exit
35import qualified System.Info as Info
36import System.IO (hFlush, hPutStr, hPutStrLn, stderr, stdout)
38import qualified Elm.ModuleName as ModuleName
39import qualified Elm.Package as Pkg
40import qualified Elm.Version as V
41import qualified Json.Encode as Encode
42import Reporting.Doc ((<+>), (<>))
43import qualified Reporting.Doc as D
44import qualified Reporting.Exit as Exit
45import qualified Reporting.Exit.Help as Help
70 Terminal <$> newMVar ()
77attempt :: (x -> Help.Report) -> IO (Either x a) -> IO a
78attempt toReport work =
79 do result <- work `catch` reportExceptionsNicely
85 do Exit.toStderr (toReport x)
89attemptWithStyle :: Style -> (x -> Help.Report) -> IO (Either x a) -> IO a
90attemptWithStyle style toReport work =
91 do result <- work `catch` reportExceptionsNicely
102 do B.hPutBuilder stderr (Encode.encodeUgly (Exit.toJson (toReport x)))
107 Exit.toStderr (toReport x)
117 D.green $ if isWindows then "+" else "●"
122 D.red $ if isWindows then "X" else "✗"
134newtype Key msg = Key (msg -> IO ())
137report :: Key msg -> msg -> IO ()
138report (Key send) msg =
144 Key (\_ -> return ())
151ask :: D.Doc -> IO Bool
167 do putStr "Must type 'y' for yes or 'n' for no: "
177trackDetails :: Style -> (DKey -> IO a) -> IO a
178trackDetails style callback =
181 callback (Key (\_ -> return ()))
184 callback (Key (\_ -> return ()))
191 detailsLoop chan (DState 0 0 0 0 0 0 0)
194 answer <- callback (Key (writeChan chan . Just))
195 writeChan chan Nothing
199detailsLoop :: Chan (Maybe DMsg) -> DState -> IO ()
200detailsLoop chan state@(DState total _ _ _ _ built _) =
201 do msg <- readChan chan
204 detailsLoop chan =<< detailsStep dmsg state
207 putStrLn $ clear (toBuildProgress total total) $
209 then "Dependencies ready!"
210 else "Dependency problem!"
229 | DReceived Pkg.Name V.Version
230 | DFailed Pkg.Name V.Version
235detailsStep :: DMsg -> DState -> IO DState
236detailsStep msg (DState total cached rqst rcvd failed built broken) =
238 DStart numDependencies ->
239 return (DState numDependencies 0 0 0 0 0 0)
242 putTransition (DState total (cached + 1) rqst rcvd failed built broken)
245 do when (rqst == 0) (putStrLn "Starting downloads...\n")
246 return (DState total cached (rqst + 1) rcvd failed built broken)
249 do putDownload goodMark pkg vsn
250 putTransition (DState total cached rqst (rcvd + 1) failed built broken)
253 do putDownload badMark pkg vsn
254 putTransition (DState total cached rqst rcvd (failed + 1) built broken)
257 putBuilt (DState total cached rqst rcvd failed (built + 1) broken)
260 putBuilt (DState total cached rqst rcvd failed built (broken + 1))
263putDownload :: D.Doc -> Pkg.Name -> V.Version -> IO ()
264putDownload mark pkg vsn =
265 Help.toStdout $ D.indent 2 $
267 <+> D.fromPackage pkg
268 <+> D.fromVersion vsn
272putTransition :: DState -> IO DState
273putTransition state@(DState total cached _ rcvd failed built broken) =
274 if cached + rcvd + failed < total then
278 do let char = if rcvd + failed == 0 then '\r' else '\n'
279 putStrFlush (char : toBuildProgress (built + broken + failed) total)
283putBuilt :: DState -> IO DState
284putBuilt state@(DState total cached _ rcvd failed built broken) =
285 do when (total == cached + rcvd + failed) $
286 putStrFlush $ '\r' : toBuildProgress (built + broken + failed) total
290toBuildProgress :: Int -> Int -> [Char]
291toBuildProgress built total =
292 "Verifying dependencies (" ++ show built ++ "/" ++ show total ++ ")"
295clear :: [Char] -> [Char] -> [Char]
297 '\r' : replicate (length before) ' ' ++ '\r' : after
306type BResult a = Either Exit.BuildProblem a
309trackBuild :: Style -> (BKey -> IO (BResult a)) -> IO (BResult a)
310trackBuild style callback =
313 callback (Key (\_ -> return ()))
316 callback (Key (\_ -> return ()))
323 putStrFlush "Compiling ..."
327 result <- callback (Key (writeChan chan . Left))
328 writeChan chan (Right result)
336buildLoop :: Chan (Either BMsg (BResult a)) -> Int -> IO ()
338 do msg <- readChan chan
341 do let !done1 = done + 1
342 putStrFlush $ "\rCompiling (" ++ show done1 ++ ")"
347 !message = toFinalMessage done result
348 !width = 12 + length (show done)
351 if length message < width
352 then '\r' : replicate width ' ' ++ '\r' : message
356toFinalMessage :: Int -> BResult a -> [Char]
357toFinalMessage done result =
362 1 -> "Success! Compiled 1 module."
363 n -> "Success! Compiled " ++ show n ++ " modules."
367 Exit.BuildBadModules _ _ [] ->
368 "Detected problems in 1 module."
370 Exit.BuildBadModules _ _ (_:ps) ->
371 "Detected problems in " ++ show (2 + length ps) ++ " modules."
373 Exit.BuildProjectProblem _ ->
374 "Detected a problem."
381reportGenerate :: Style -> NE.List ModuleName.Raw -> FilePath -> IO ()
382reportGenerate style names output =
392 let cnames = fmap ModuleName.toChars names
393 putStrLn ('\n' : toGenDiagram cnames output)
396toGenDiagram :: NE.List [Char] -> FilePath -> [Char]
397toGenDiagram (NE.List name names) output =
399 width = 3 + foldr (max . length) (length name) names
403 toGenLine width name ('>' : ' ' : output ++ "\n")
407 toGenLine width name (vtop : hbar : hbar : '>' : ' ' : output)
408 : reverse (zipWith (toGenLine width) (reverse names) ([vbottom] : repeat [vmiddle]))
411toGenLine :: Int -> [Char] -> [Char] -> [Char]
412toGenLine width name end =
413 " " ++ name ++ ' ' : replicate (width - length name) hbar ++ end
417hbar = if isWindows then '-' else '─'
420vtop = if isWindows then '+' else '┬'
423vmiddle = if isWindows then '+' else '┤'
426vbottom = if isWindows then '+' else '┘'
432putStrFlush :: String -> IO ()
434 hPutStr stdout str >> hFlush stdout
438-- REPORT EXCEPTIONS NICELY
441reportExceptionsNicely :: SomeException -> IO a
442reportExceptionsNicely e =
443 case fromException e of
444 Just UserInterrupt -> throw e
445 _ -> putException e >> throw e
448putException :: SomeException -> IO ()
451 Help.toStderr $ D.stack $
452 [ D.dullyellow "-- ERROR -----------------------------------------------------------------------"
454 "I ran into something that bypassed the normal error reporting process!\
455 \ I extracted whatever information I could from the internal error:"
456 , D.vcat $ map (\line -> D.red ">" <> " " <> D.fromChars line) (lines (show e))
458 "These errors are usually pretty confusing, so start by asking around on one of\
459 \ forums listed at https://elm-lang.org/community to see if anyone can get you\
461 , D.dullyellow "-- REQUEST ---------------------------------------------------------------------"
463 "If you are feeling up to it, please try to get your code down to the smallest\
464 \ version that still triggers this message. Ideally in a single Main.elm and\
467 "From there open a NEW issue at https://github.com/elm/compiler/issues with\
468 \ your reduced example pasted in directly. (Not a link to a repo or gist!) Do not\
469 \ worry about if someone else saw something similar. More examples is better!"
471 "This kind of error is usually tied up in larger architectural choices that are\
472 \ hard to change, so even when we have a couple good examples, it can take some\
473 \ time to resolve in a solid way."
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