Commit c4c864ae authored by Andrew Gibiansky's avatar Andrew Gibiansky

Error messages have context and don't line-wrap

parent 1ccc9ffb
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes, OverloadedStrings, ExtendedDefaultRules #-}
-- Keep all the language pragmas here so it can be compiled separately.
module Main where module Main where
import Prelude import Prelude
import GHC import GHC
...@@ -10,7 +11,7 @@ import Data.List ...@@ -10,7 +11,7 @@ import Data.List
import System.Directory import System.Directory
import Shelly (Sh, shelly, cmd, (</>), toTextIgnore, cd, withTmpDir, mkdir_p, import Shelly (Sh, shelly, cmd, (</>), toTextIgnore, cd, withTmpDir, mkdir_p,
touchfile) touchfile)
import qualified Shelly as Shelly import qualified Shelly
import Filesystem.Path.CurrentOS (encodeString) import Filesystem.Path.CurrentOS (encodeString)
import Data.String.Here import Data.String.Here
import Data.String.Utils (strip, replace) import Data.String.Utils (strip, replace)
......
...@@ -53,6 +53,10 @@ import Exception hiding (evaluate) ...@@ -53,6 +53,10 @@ import Exception hiding (evaluate)
import Outputable import Outputable
import Packages import Packages
import Module import Module
import qualified Pretty
import FastString
import Bag
import ErrUtils (errMsgShortDoc, errMsgExtraInfo)
import qualified System.IO.Strict as StrictIO import qualified System.IO.Strict as StrictIO
...@@ -109,7 +113,9 @@ interpret allowedStdin action = runGhc (Just libdir) $ do ...@@ -109,7 +113,9 @@ interpret allowedStdin action = runGhc (Just libdir) $ do
-- Set the dynamic session flags -- Set the dynamic session flags
originalFlags <- getSessionDynFlags originalFlags <- getSessionDynFlags
let dflags = xopt_set originalFlags Opt_ExtendedDefaultRules let dflags = xopt_set originalFlags Opt_ExtendedDefaultRules
void $ setSessionDynFlags $ dflags { hscTarget = HscInterpreted, ghcLink = LinkInMemory } void $ setSessionDynFlags $ dflags { hscTarget = HscInterpreted,
ghcLink = LinkInMemory,
pprCols = 300 }
initializeImports initializeImports
...@@ -237,7 +243,7 @@ evaluate kernelState code output = do ...@@ -237,7 +243,7 @@ evaluate kernelState code output = do
storeItCommand execCount = Statement $ printf "let it%d = it" execCount storeItCommand execCount = Statement $ printf "let it%d = it" execCount
safely :: KernelState -> Interpreter EvalOut -> Interpreter EvalOut safely :: KernelState -> Interpreter EvalOut -> Interpreter EvalOut
safely state = ghandle handler safely state = ghandle handler . ghandle sourceErrorHandler
where where
handler :: SomeException -> Interpreter EvalOut handler :: SomeException -> Interpreter EvalOut
handler exception = handler exception =
...@@ -248,6 +254,37 @@ safely state = ghandle handler ...@@ -248,6 +254,37 @@ safely state = ghandle handler
evalPager = "" evalPager = ""
} }
sourceErrorHandler :: SourceError -> Interpreter EvalOut
sourceErrorHandler srcerr = do
let msgs = bagToList $ srcErrorMessages srcerr
errStrs <- forM msgs $ \msg -> do
shortStr <- doc $ errMsgShortDoc msg
contextStr <- doc $ errMsgExtraInfo msg
return $ unlines [shortStr, contextStr]
let fullErr = unlines errStrs
return EvalOut {
evalStatus = Failure,
evalResult = displayError fullErr,
evalState = state,
evalPager = ""
}
doc :: GhcMonad m => SDoc -> m String
doc sdoc = do
flags <- getSessionDynFlags
let cols = pprCols flags
d = runSDoc sdoc (initSDocContext flags defaultUserStyle)
return $ Pretty.fullRender Pretty.PageMode cols 1.5 string_txt "" d
where
string_txt :: Pretty.TextDetails -> String -> String
string_txt (Pretty.Chr c) s = c:s
string_txt (Pretty.Str s1) s2 = s1 ++ s2
string_txt (Pretty.PStr s1) s2 = unpackFS s1 ++ s2
string_txt (Pretty.LStr s1 _) s2 = unpackLitString s1 ++ s2
wrapExecution :: KernelState wrapExecution :: KernelState
-> Interpreter [DisplayData] -> Interpreter [DisplayData]
-> Interpreter EvalOut -> Interpreter EvalOut
...@@ -968,39 +1005,12 @@ formatErrorWithClass :: String -> ErrMsg -> String ...@@ -968,39 +1005,12 @@ formatErrorWithClass :: String -> ErrMsg -> String
formatErrorWithClass cls = formatErrorWithClass cls =
printf "<span class='%s'>%s</span>" cls . printf "<span class='%s'>%s</span>" cls .
replace "\n" "<br/>" . replace "\n" "<br/>" .
fixLineWrapping .
fixStdinError . fixStdinError .
replace useDashV "" . replace useDashV "" .
rstrip . rstrip .
typeCleaner typeCleaner
where where
useDashV = "\nUse -v to see a list of the files searched for." useDashV = "\nUse -v to see a list of the files searched for."
fixLineWrapping err
| isThreePartTypeError err =
let (before, exp:after) = break ("Expected type" `isInfixOf`) $ lines err
(expected, act:actual) = break ("Actual type" `isInfixOf`) after in
unlines $ map unstripped [before, exp:expected, act:actual]
| isTwoPartTypeError err =
let (one, two) = break ("with actual type" `isInfixOf`) $ lines err in
unlines $ map unstripped [one, two]
| isShowError err =
let (one, arising:possibleFix:two) = break ("arising" `isInfixOf`) $ lines err in
unlines $ map unstripped [one, [arising], [possibleFix], two]
| otherwise = err
where
unstripped (line:lines) = unwords $ line:map lstrip lines
isThreePartTypeError err = all (`isInfixOf` err) [
"Couldn't match type",
"with",
"Expected type:",
"Actual type:"
]
isTwoPartTypeError err = all (`isInfixOf` err) [
"Couldn't match expected type",
"with actual type"
]
isShowError err = isShowError err =
startswith "No instance for (Show" err && startswith "No instance for (Show" err &&
isInfixOf " arising from a use of `print'" err isInfixOf " arising from a use of `print'" err
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment