Commit c76feb6f authored by Sumit Sahrawat's avatar Sumit Sahrawat

Seamless outputs from buttons

It just works.
parent e253c848
...@@ -149,7 +149,7 @@ runKernel kernelOpts profileSrc = do ...@@ -149,7 +149,7 @@ runKernel kernelOpts profileSrc = do
oldState <- liftIO $ takeMVar state oldState <- liftIO $ takeMVar state
let replier = writeChan (iopubChannel interface) let replier = writeChan (iopubChannel interface)
widgetMessageHandler = widgetHandler replier replyHeader widgetMessageHandler = widgetHandler replier replyHeader
tempState <- liftIO $ handleComm replier oldState request replyHeader tempState <- handleComm replier oldState request replyHeader
newState <- flushWidgetMessages tempState [] widgetMessageHandler newState <- flushWidgetMessages tempState [] widgetMessageHandler
liftIO $ putMVar state newState liftIO $ putMVar state newState
liftIO $ writeChan (shellReplyChannel interface) SendNothing liftIO $ writeChan (shellReplyChannel interface) SendNothing
...@@ -293,21 +293,32 @@ replyTo _ HistoryRequest{} replyHeader state = do ...@@ -293,21 +293,32 @@ replyTo _ HistoryRequest{} replyHeader state = do
} }
return (state, reply) return (state, reply)
handleComm :: (Message -> IO ()) -> KernelState -> Message -> MessageHeader -> IO KernelState handleComm :: (Message -> IO ()) -> KernelState -> Message -> MessageHeader -> Interpreter KernelState
handleComm replier kernelState req replyHeader = do handleComm send kernelState req replyHeader = do
displayed <- liftIO $ newMVar []
updateNeeded <- liftIO $ newMVar False
pagerOutput <- liftIO $ newMVar []
let widgets = openComms kernelState let widgets = openComms kernelState
uuid = commUuid req uuid = commUuid req
dat = commData req dat = commData req
communicate value = do communicate value = do
head <- dupHeader replyHeader CommDataMessage head <- dupHeader replyHeader CommDataMessage
replier $ CommData head uuid value send $ CommData head uuid value
toUsePager = usePager kernelState
run = capturedIO publish kernelState
publish = publishResult send replyHeader displayed updateNeeded pagerOutput toUsePager
case Map.lookup uuid widgets of case Map.lookup uuid widgets of
Nothing -> return kernelState Nothing -> return kernelState
Just (Widget widget) -> Just (Widget widget) ->
case msgType $ header req of case msgType $ header req of
CommDataMessage -> do CommDataMessage -> do
comm widget dat communicate disp <- run $ comm widget dat communicate
pgrOut <- liftIO $ readMVar pagerOutput
liftIO $ publish $ FinalResult disp (if toUsePager then pgrOut else []) []
return kernelState return kernelState
CommCloseMessage -> do CommCloseMessage -> do
close widget dat disp <- run $ close widget dat
pgrOut <- liftIO $ readMVar pagerOutput
liftIO $ publish $ FinalResult disp (if toUsePager then pgrOut else []) []
return kernelState { openComms = Map.delete uuid widgets } return kernelState { openComms = Map.delete uuid widgets }
...@@ -14,6 +14,7 @@ module IHaskell.Eval.Evaluate ( ...@@ -14,6 +14,7 @@ module IHaskell.Eval.Evaluate (
typeCleaner, typeCleaner,
globalImports, globalImports,
formatType, formatType,
capturedIO,
) where ) where
import IHaskellPrelude import IHaskellPrelude
...@@ -278,7 +279,7 @@ cleanString x = if allBrackets ...@@ -278,7 +279,7 @@ cleanString x = if allBrackets
-- | Evaluate some IPython input code. -- | Evaluate some IPython input code.
evaluate :: KernelState -- ^ The kernel state. evaluate :: KernelState -- ^ The kernel state.
-> String -- ^ Haskell code or other interpreter commands. -> String -- ^ Haskell code or other interpreter commands.
-> (EvaluationResult -> IO ()) -- ^ Function used to publish data outputs. -> Publisher -- ^ Function used to publish data outputs.
-> (KernelState -> [WidgetMsg] -> IO KernelState) -- ^ Function to handle widget messages -> (KernelState -> [WidgetMsg] -> IO KernelState) -- ^ Function to handle widget messages
-> Interpreter KernelState -> Interpreter KernelState
evaluate kernelState code output widgetHandler = do evaluate kernelState code output widgetHandler = do
...@@ -761,44 +762,7 @@ evalCommand _ (Directive GetDoc query) state = safely state $ do ...@@ -761,44 +762,7 @@ evalCommand _ (Directive GetDoc query) state = safely state $ do
results <- liftIO $ Hoogle.document query results <- liftIO $ Hoogle.document query
return $ hoogleResults state results return $ hoogleResults state results
evalCommand output (Statement stmt) state = wrapExecution state $ do evalCommand output (Statement stmt) state = wrapExecution state $ evalStatementOrIO output state (Left stmt)
write state $ "Statement:\n" ++ stmt
let outputter str = output $ IntermediateResult $ Display [plain str]
(printed, result) <- capturedStatement outputter stmt
case result of
RunOk names -> do
dflags <- getSessionDynFlags
let allNames = map (showPpr dflags) names
isItName name =
name == "it" ||
name == "it" ++ show (getExecutionCounter state)
nonItNames = filter (not . isItName) allNames
output = [plain printed | not . null $ strip printed]
write state $ "Names: " ++ show allNames
-- Display the types of all bound names if the option is on. This is similar to GHCi :set +t.
if not $ useShowTypes state
then return $ Display output
else do
-- Get all the type strings.
types <- forM nonItNames $ \name -> do
theType <- showSDocUnqual dflags . ppr <$> exprType name
return $ name ++ " :: " ++ theType
let joined = unlines types
htmled = unlines $ map formatGetType types
return $
case extractPlain output of
"" -> Display [html htmled]
-- Return plain and html versions. Previously there was only a plain version.
text -> Display [plain $ joined ++ "\n" ++ text, html $ htmled ++ mono text]
RunException exception -> throw exception
RunBreak{} -> error "Should not break."
evalCommand output (Expression expr) state = do evalCommand output (Expression expr) state = do
write state $ "Expression:\n" ++ expr write state $ "Expression:\n" ++ expr
...@@ -1087,10 +1051,10 @@ keepingItVariable act = do ...@@ -1087,10 +1051,10 @@ keepingItVariable act = do
goStmt $ printf "let it = %s" itVariable goStmt $ printf "let it = %s" itVariable
act act
capturedStatement :: (String -> IO ()) -- ^ Function used to publish intermediate output. capturedEval :: (String -> IO ()) -- ^ Function used to publish intermediate output.
-> String -- ^ Statement to evaluate. -> Either String (IO a) -- ^ Statement to evaluate.
-> Interpreter (String, RunResult) -- ^ Return the output and result. -> Interpreter (String, RunResult) -- ^ Return the output and result.
capturedStatement output stmt = do capturedEval output stmt = do
-- Generate random variable names to use so that we cannot accidentally override the variables by -- Generate random variable names to use so that we cannot accidentally override the variables by
-- using the right names in the terminal. -- using the right names in the terminal.
gen <- liftIO getStdGen gen <- liftIO getStdGen
...@@ -1134,6 +1098,13 @@ capturedStatement output stmt = do ...@@ -1134,6 +1098,13 @@ capturedStatement output stmt = do
goStmt :: String -> Ghc RunResult goStmt :: String -> Ghc RunResult
goStmt s = runStmt s RunToCompletion goStmt s = runStmt s RunToCompletion
runWithResult (Left str) = goStmt str
runWithResult (Right io) = do
status <- gcatch (liftIO io >> return NoException) (return . AnyException)
return $ case status of
NoException -> RunOk []
AnyException e -> RunException e
-- Initialize evaluation context. -- Initialize evaluation context.
void $ forM initStmts goStmt void $ forM initStmts goStmt
...@@ -1149,7 +1120,6 @@ capturedStatement output stmt = do ...@@ -1149,7 +1120,6 @@ capturedStatement output stmt = do
fd <- head <$> unsafeCoerce hValues fd <- head <$> unsafeCoerce hValues
fdToHandle fd fdToHandle fd
-- Keep track of whether execution has completed. -- Keep track of whether execution has completed.
completed <- liftIO $ newMVar False completed <- liftIO $ newMVar False
finishedReading <- liftIO newEmptyMVar finishedReading <- liftIO newEmptyMVar
...@@ -1192,7 +1162,7 @@ capturedStatement output stmt = do ...@@ -1192,7 +1162,7 @@ capturedStatement output stmt = do
liftIO $ forkIO loop liftIO $ forkIO loop
result <- gfinally (goStmt stmt) $ do result <- gfinally (runWithResult stmt) $ do
-- Execution is done. -- Execution is done.
liftIO $ modifyMVar_ completed (const $ return True) liftIO $ modifyMVar_ completed (const $ return True)
...@@ -1206,6 +1176,58 @@ capturedStatement output stmt = do ...@@ -1206,6 +1176,58 @@ capturedStatement output stmt = do
printedOutput <- liftIO $ readMVar outputAccum printedOutput <- liftIO $ readMVar outputAccum
return (printedOutput, result) return (printedOutput, result)
data AnyException = NoException | AnyException SomeException
capturedIO :: Publisher -> KernelState -> IO a -> Interpreter Display
capturedIO publish state action = evalStatementOrIO publish state (Right action)
evalStatementOrIO :: Publisher -> KernelState -> Either String (IO a) -> Interpreter Display
evalStatementOrIO publish state cmd = do
let output str = publish . IntermediateResult $ Display [plain str]
(printed, result) <- case cmd of
Left stmt -> do
write state $ "Statement:\n" ++ stmt
capturedEval output (Left stmt)
Right io -> do
write state $ "evalStatementOrIO in Action"
capturedEval output (Right io)
case result of
RunOk names -> do
dflags <- getSessionDynFlags
let allNames = map (showPpr dflags) names
isItName name =
name == "it" ||
name == "it" ++ show (getExecutionCounter state)
nonItNames = filter (not . isItName) allNames
output = [plain printed | not . null $ strip printed]
write state $ "Names: " ++ show allNames
-- Display the types of all bound names if the option is on. This is similar to GHCi :set +t.
if not $ useShowTypes state
then return $ Display output
else do
-- Get all the type strings.
types <- forM nonItNames $ \name -> do
theType <- showSDocUnqual dflags . ppr <$> exprType name
return $ name ++ " :: " ++ theType
let joined = unlines types
htmled = unlines $ map formatGetType types
return $
case extractPlain output of
"" -> Display [html htmled]
-- Return plain and html versions. Previously there was only a plain version.
text -> Display [plain $ joined ++ "\n" ++ text, html $ htmled ++ mono text]
RunException exception -> throw exception
RunBreak{} -> error "Should not break."
-- Read from a file handle until we hit a delimiter or until we've read as many characters as -- Read from a file handle until we hit a delimiter or until we've read as many characters as
-- requested -- requested
readChars :: Handle -> String -> Int -> IO String readChars :: Handle -> String -> Int -> IO String
......
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