1- {-# LANGUAGE LambdaCase #-}
21{-# LANGUAGE OverloadedStrings #-}
32{-# LANGUAGE ViewPatterns #-}
43{-# OPTIONS_GHC -Wwarn #-}
@@ -15,14 +14,17 @@ import qualified Data.Text as T
1514import Development.IDE.GHC.Compat
1615import GHC (ExecOptions , ExecResult (.. ),
1716 execStmt )
17+ import GHC.Driver.Monad (reflectGhc , reifyGhc )
1818import Ide.Plugin.Eval.Types (Language (Plain ), Loc ,
1919 Located (.. ),
2020 Section (sectionLanguage ),
2121 Test (.. ), Txt , locate , locate0 )
2222import qualified Language.LSP.Protocol.Lens as L
2323import Language.LSP.Protocol.Types (Position (Position ),
2424 Range (Range ))
25+ import System.IO (stderr , stdout )
2526import System.IO.Extra (newTempFile , readFile' )
27+ import System.IO.Silently (hCapture )
2628
2729-- | Return the ranges of the expression and result parts of the given test
2830testRanges :: Test -> (Range , Range )
@@ -79,20 +81,31 @@ asStmts (Example e _ _) = NE.toList e
7981asStmts (Property t _ _) =
8082 [" prop11 = " ++ t, " (propEvaluation prop11 :: IO String)" ]
8183
82-
83-
8484-- | A wrapper of 'InteractiveEval.execStmt', capturing the execution result
8585myExecStmt :: String -> ExecOptions -> Ghc (Either String (Maybe String ))
8686myExecStmt stmt opts = do
8787 (temp, purge) <- liftIO newTempFile
8888 evalPrint <- head <$> runDecls (" evalPrint x = P.writeFile " <> show temp <> " (P.show x)" )
8989 modifySession $ \ hsc -> hsc {hsc_IC = setInteractivePrintName (hsc_IC hsc) evalPrint}
90- result <- execStmt stmt opts >>= \ case
91- ExecComplete (Left err) _ -> pure $ Left $ show err
92- ExecComplete (Right _) _ -> liftIO $ Right . (\ x -> if null x then Nothing else Just x) <$> readFile' temp
93- ExecBreak {} -> pure $ Right $ Just " breakpoints are not supported"
90+ -- NB: We capture output to @stdout@ and @stderr@ induced as a possible side
91+ -- effect by the statement being evaluated. This is fragile because the
92+ -- output may be scrambled in a concurrent setting when HLS is writing to
93+ -- one of these file handles from a different thread.
94+ (output, execResult) <- reifyGhc $ \ session ->
95+ hCapture [stdout, stderr] (reflectGhc (execStmt stmt opts) session)
96+ evalResult <- case execResult of
97+ ExecComplete (Left err) _ ->
98+ pure $ Left $ show err
99+ ExecComplete (Right _) _ ->
100+ liftIO $ Right . fromList . (output <> ) <$> readFile' temp
101+ ExecBreak {} ->
102+ pure $ Right $ Just " breakpoints are not supported"
94103 liftIO purge
95- pure result
104+ pure evalResult
105+ where
106+ fromList :: String -> Maybe String
107+ fromList x | null x = Nothing
108+ | otherwise = Just x
96109
97110{- | GHC declarations required to execute test properties
98111
0 commit comments