+import Language.Haskell.LSP.Test.Session
+import System.Console.ANSI
+
+satisfy :: (MonadIO m, MonadSessionConfig m) => (FromServerMessage -> Bool) -> ConduitParser FromServerMessage m FromServerMessage
+satisfy pred = do
+ timeout <- timeout <$> lift sessionConfig
+ tId <- liftIO myThreadId
+ timeoutThread <- liftIO $ forkIO $ do
+ threadDelay (timeout * 1000000)
+ throwTo tId TimeoutException
+ x <- await
+ liftIO $ killThread timeoutThread
+
+ if pred x
+ then do
+ liftIO $ do
+ setSGR [SetColor Foreground Vivid Magenta]
+ putStrLn $ "<-- " ++ B.unpack (encodeMsg x)
+ setSGR [Reset]
+ return x
+ else empty
+
+-- | Matches if the message is a notification.
+anyNotification :: (MonadIO m, MonadSessionConfig m) => ConduitParser FromServerMessage m FromServerMessage
+anyNotification = named "Any notification" $ satisfy isServerNotification
+
+notification :: forall m a. (MonadIO m, MonadSessionConfig m, FromJSON a) => ConduitParser FromServerMessage m (NotificationMessage ServerMethod a)
+notification = named "Notification" $ do
+ let parser = decode . encodeMsg :: FromServerMessage -> Maybe (NotificationMessage ServerMethod a)
+ x <- satisfy (isJust . parser)
+ return $ castMsg x