@@ -40,6 +40,8 @@ import Development.IDE.Types.Logger
4040
4141import System.IO.Unsafe (unsafeInterleaveIO )
4242
43+ issueTrackerUrl = " https://github.com/haskell/haskell-language-server/issues"
44+
4345runLanguageServer
4446 :: forall config . (Show config )
4547 => LSP. Options
@@ -137,48 +139,49 @@ runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChan
137139 registerIdeConfiguration (shakeExtras ide) initConfig
138140
139141 let handleServerException (Left e) = do
140- logError (ideLogger ide) $
142+ logError logger $
141143 T. pack $ " Fatal error in server thread: " <> show e
142144 exitClientMsg
143145 handleServerException _ = pure ()
146+
147+ uncaughtError (e :: SomeException ) = do
148+ logError logger $ T. pack $
149+ " Unexpected exception on notification, please report!\n " ++
150+ " Exception: " ++ show e
151+ LSP. runLspT env $ LSP. sendNotification SWindowShowMessage $
152+ ShowMessageParams MtError $ T. unlines
153+ [ " Unhandled error, please [report](" <> issueTrackerUrl <> " ): "
154+ , T. pack(show e)
155+ ]
144156 logger = ideLogger ide
157+
158+ checkCancelled _id act k =
159+ flip finally (clearReqId _id) $
160+ catch (do
161+ -- We could optimize this by first checking if the id
162+ -- is in the cancelled set. However, this is unlikely to be a
163+ -- bottleneck and the additional check might hide
164+ -- issues with async exceptions that need to be fixed.
165+ cancelOrRes <- race (waitForCancel _id) act
166+ case cancelOrRes of
167+ Left () -> do
168+ logDebug (ideLogger ide) $ T. pack $ " Cancelled request " <> show _id
169+ k $ ResponseError RequestCancelled " " Nothing
170+ Right res -> pure res
171+ ) $ \ (e :: SomeException ) -> do
172+ uncaughtError e
173+ k $ ResponseError InternalError (T. pack $ show e) Nothing
145174 _ <- flip forkFinally handleServerException $ runWithDb logger dbLoc $ \ hiedb hieChan -> do
146175 putMVar dbMVar (hiedb,hieChan)
147176 forever $ do
148177 msg <- readChan clientMsgChan
149178 -- We dispatch notifications synchronously and requests asynchronously
150179 -- This is to ensure that all file edits and config changes are applied before a request is handled
151180 case msg of
152- ReactorNotification act -> do
153- catch act $ \ (e :: SomeException ) ->
154- logError (ideLogger ide) $ T. pack $
155- " Unexpected exception on notification, please report!\n " ++
156- " Exception: " ++ show e
157- ReactorRequest _id act k -> void $ async $
158- checkCancelled ide clearReqId waitForCancel _id act k
181+ ReactorNotification act -> handle uncaughtError act
182+ ReactorRequest _id act k -> void $ async $ checkCancelled _id act k
159183 pure $ Right (env,ide)
160184
161- checkCancelled
162- :: IdeState -> (SomeLspId -> IO () ) -> (SomeLspId -> IO () ) -> SomeLspId
163- -> IO () -> (ResponseError -> IO () ) -> IO ()
164- checkCancelled ide clearReqId waitForCancel _id act k =
165- flip finally (clearReqId _id) $
166- catch (do
167- -- We could optimize this by first checking if the id
168- -- is in the cancelled set. However, this is unlikely to be a
169- -- bottleneck and the additional check might hide
170- -- issues with async exceptions that need to be fixed.
171- cancelOrRes <- race (waitForCancel _id) act
172- case cancelOrRes of
173- Left () -> do
174- logDebug (ideLogger ide) $ T. pack $ " Cancelled request " <> show _id
175- k $ ResponseError RequestCancelled " " Nothing
176- Right res -> pure res
177- ) $ \ (e :: SomeException ) -> do
178- logError (ideLogger ide) $ T. pack $
179- " Unexpected exception on request, please report!\n " ++
180- " Exception: " ++ show e
181- k $ ResponseError InternalError (T. pack $ show e) Nothing
182185
183186
184187cancelHandler :: (SomeLspId -> IO () ) -> LSP. Handlers (ServerM c )
0 commit comments