+
+ -- todo: we shouldn't do this, we should check all notifications were delivered first
+ putMVar didPass True
+
+ result <- takeMVar didPass
+ terminateProcess serverProc
+
+ -- restore directory
+ setCurrentDirectory prevDir
+
+ return result
+
+-- todo: Maybe make a reader monad and a fail function for it?
+listenServer
+ :: [B.ByteString]
+ -> Handle
+ -> (MVar LSP.LspIdRsp, MVar LSP.LspId)
+ -> MVar Bool
+ -> IO ()
+listenServer [] _ _ passVar = putMVar passVar True
+listenServer expectedMsgs h semas@(reqSema, rspSema) passVar = do
+ msg <- getNextMessage h
+ putStrLn $ "Remaining messages " ++ show (length expectedMsgs)
+ if inRightOrder msg expectedMsgs
+ then do
+
+ whenResponse msg $ \res -> do
+ putStrLn $ "Got response for id " ++ show (res ^. LSP.id)
+ putMVar reqSema (res ^. LSP.id) -- unblock the handler waiting to send a request
+
+ whenRequest msg $ \req -> do
+ putStrLn $ "Got request for id " ++ show (req ^. LSP.id) ++ " " ++ show (req ^. LSP.method)
+ putMVar rspSema (req ^. LSP.id) -- unblock the handler waiting for a response
+
+ whenNotification msg $ \n -> putStrLn $ "Got notification " ++ (show (n ^. LSP.method))
+
+ when (not (msg `elem` expectedMsgs)) $ do
+ putStrLn "Got an unexpected message"
+ putMVar passVar False
+
+ listenServer (delete msg expectedMsgs) h semas passVar
+ else do
+ putStrLn $ "Got: " ++ show msg ++ "\n Expected: " ++ show
+ (head (filter (not . isNotification) expectedMsgs))
+ putMVar passVar False
+
+isNotification :: B.ByteString -> Bool
+isNotification msg =
+ isJust (decode msg :: Maybe (LSP.NotificationMessage Value Value))
+
+whenResponse :: B.ByteString -> (LSP.ResponseMessage Value -> IO ()) -> IO ()
+whenResponse msg f = case decode msg :: Maybe (LSP.ResponseMessage Value) of
+ Just msg' -> when (isJust (msg' ^. LSP.result)) (f msg')
+ _ -> return ()
+
+whenRequest
+ :: B.ByteString -> (LSP.RequestMessage Value Value Value -> IO ()) -> IO ()
+whenRequest msg =
+ forM_ (decode msg :: (Maybe (LSP.RequestMessage Value Value Value)))
+
+whenNotification :: B.ByteString -> (LSP.NotificationMessage Value Value -> IO ()) -> IO ()
+whenNotification msg = forM_ (decode msg :: (Maybe (LSP.NotificationMessage Value Value)))
+
+-- TODO: QuickCheck tests?
+-- | Checks wether or not the message appears in the right order
+-- @ N1 N2 N3 REQ1 N4 N5 REQ2 RES1 @
+-- given N2, notification order doesn't matter.
+-- @ N1 N3 REQ1 N4 N5 REQ2 RES1 @
+-- given REQ1
+-- @ N1 N3 N4 N5 REQ2 RES1 @
+-- given RES1
+-- @ N1 N3 N4 N5 XXXX RES1 @ False!
+-- Order of requests and responses matter
+inRightOrder :: B.ByteString -> [B.ByteString] -> Bool
+inRightOrder _ [] = error "why is this empty"
+inRightOrder received msgs = received `elem` valid