@@ -5,10 +5,11 @@ module Reporting
8− , exit
8+ , attemptWithStyle
14 , DMsg(..)
15 , DMsg(..)
@@ -24,6 +25,7 @@ module Reporting
26import Control.Concurrent
27import Control.Concurrent
28+import Control.Exception (SomeException, AsyncException(UserInterrupt), catch, fromException, throw)
27import Control.Monad (when)
29import Control.Monad (when)
28import qualified Data.ByteString.Builder as B
30import qualified Data.ByteString.Builder as B
29import qualified Data.NonEmptyList as NE
31import qualified Data.NonEmptyList as NE
@@ -64,25 +66,31 @@ terminal =
67−attempt :: Style -> IO (Either Help.Report a) -> IO a
69+attempt :: (x -> Help.Report) -> IO (Either x a) -> IO a
68−attempt style work =
70+attempt toReport work =
69− do result <- work
71+ do result <- work `catch` reportExceptionsNicely
70 case result of
72 case result of
71 Right a -> return a
73 Right a -> return a
72− Left ex -> exit style ex
74+ Left x ->
75+ do Exit.toStderr (toReport x)
75−exit :: Style -> Help.Report -> IO a
79+attemptWithStyle :: Style -> (x -> Help.Report) -> IO (Either x a) -> IO a
76−exit style rep =
80+attemptWithStyle style toReport work =
81+ do result <- work `catch` reportExceptionsNicely
77− case style of
85+ case style of
79− do B.hPutBuilder stderr (Encode.encodeUgly (Exit.toJson rep))
87+ do B.hPutBuilder stderr (Encode.encodeUgly (Exit.toJson (toReport x)))
80− Exit.exitFailure
88+ Exit.exitFailure
82− Terminal mvar ->
90+ Terminal mvar ->
83− do readMVar mvar
91+ do readMVar mvar
84− Exit.toStderr rep
92+ Exit.toStderr (toReport x)
85− Exit.exitFailure
93+ Exit.exitFailure
@@ -122,6 +130,29 @@ report (Key send) msg =
136+ask :: D.Doc -> IO Bool
138+ do Help.toStdout doc
152+ do putStr "Must type 'y' for yes or 'n' for no: "
125-- DETAILS
156-- DETAILS
@@ -377,3 +408,40 @@ vbottom = if isWindows then '+' else '┘'
377putStrFlush :: String -> IO ()
408putStrFlush :: String -> IO ()
378putStrFlush str =
409putStrFlush str =
379 hPutStr stdout str >> hFlush stdout
410 hPutStr stdout str >> hFlush stdout
414+-- REPORT EXCEPTIONS NICELY
417+reportExceptionsNicely :: SomeException -> IO a
418+reportExceptionsNicely e =
419+ case fromException e of
420+ Just UserInterrupt -> throw e
421+ _ -> putException e >> throw e
424+putException :: SomeException -> IO ()
426+ Help.toStderr $ D.stack $
428+ "Oh no! I ran into something that bypassed the normal error reporting process!\
429+ \ I extracted whatever information I could from the internal error:"
430+ , D.vcat $ map (\line -> D.red ">" <> " " <> D.fromChars line) (lines (show e))
432+ "These errors are usually pretty confusing, so start by asking around on Slack\
433+ \ or Discourse to see if anyone can get you unstuck quickly."
434+ , "------------------------------------------------------------"
436+ "From there, if you are feeling up to it, please try to get your code down to the\
437+ \ smallest version that still triggers this message. Ideally in a single Main.elm\
438+ \ and elm.json file."
440+ "From there open a NEW issue at https://github.com/elm/compiler/issues with\
441+ \ your reduced example pasted in directly. (Not a link to a repo or gist!) Do not\
442+ \ worry about if someone else saw something similar. More examples is better!"
444+ "This kind of error is usually tied up in larger architectural choices that are\
445+ \ hard to change, so even when we have a couple good examples, it can take some\
446+ \ time to resolve in a solid way."