1
- {-# LANGUAGE LambdaCase #-}
2
1
{-# LANGUAGE OverloadedStrings #-}
3
2
{-# LANGUAGE ViewPatterns #-}
4
3
{-# OPTIONS_GHC -Wwarn #-}
@@ -15,14 +14,17 @@ import qualified Data.Text as T
15
14
import Development.IDE.GHC.Compat
16
15
import GHC (ExecOptions , ExecResult (.. ),
17
16
execStmt )
17
+ import GHC.Driver.Monad (reflectGhc , reifyGhc )
18
18
import Ide.Plugin.Eval.Types (Language (Plain ), Loc ,
19
19
Located (.. ),
20
20
Section (sectionLanguage ),
21
21
Test (.. ), Txt , locate , locate0 )
22
22
import qualified Language.LSP.Protocol.Lens as L
23
23
import Language.LSP.Protocol.Types (Position (Position ),
24
24
Range (Range ))
25
+ import System.IO (stderr , stdout )
25
26
import System.IO.Extra (newTempFile , readFile' )
27
+ import System.IO.Silently (hCapture )
26
28
27
29
-- | Return the ranges of the expression and result parts of the given test
28
30
testRanges :: Test -> (Range , Range )
@@ -79,20 +81,31 @@ asStmts (Example e _ _) = NE.toList e
79
81
asStmts (Property t _ _) =
80
82
[" prop11 = " ++ t, " (propEvaluation prop11 :: IO String)" ]
81
83
82
-
83
-
84
84
-- | A wrapper of 'InteractiveEval.execStmt', capturing the execution result
85
85
myExecStmt :: String -> ExecOptions -> Ghc (Either String (Maybe String ))
86
86
myExecStmt stmt opts = do
87
87
(temp, purge) <- liftIO newTempFile
88
88
evalPrint <- head <$> runDecls (" evalPrint x = P.writeFile " <> show temp <> " (P.show x)" )
89
89
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"
94
103
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
96
109
97
110
{- | GHC declarations required to execute test properties
98
111
0 commit comments