Skip to content

Commit 83ae7af

Browse files
committed
Send unhandled exceptions to the user
1 parent 854d2c5 commit 83ae7af

File tree

1 file changed

+32
-29
lines changed

1 file changed

+32
-29
lines changed

ghcide/src/Development/IDE/LSP/LanguageServer.hs

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ import Development.IDE.Types.Logger
4040

4141
import System.IO.Unsafe (unsafeInterleaveIO)
4242

43+
issueTrackerUrl = "https://github.com/haskell/haskell-language-server/issues"
44+
4345
runLanguageServer
4446
:: forall config. (Show config)
4547
=> LSP.Options
@@ -138,48 +140,49 @@ runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChan
138140
registerIdeConfiguration (shakeExtras ide) initConfig
139141

140142
let handleServerException (Left e) = do
141-
logError (ideLogger ide) $
143+
logError logger $
142144
T.pack $ "Fatal error in server thread: " <> show e
143145
exitClientMsg
144146
handleServerException _ = pure ()
147+
148+
uncaughtError (e :: SomeException) = do
149+
logError logger $ T.pack $
150+
"Unexpected exception on notification, please report!\n" ++
151+
"Exception: " ++ show e
152+
LSP.runLspT env $ LSP.sendNotification SWindowShowMessage $
153+
ShowMessageParams MtError $ T.unlines
154+
[ "Unhandled error, please [report](" <> issueTrackerUrl <> "): "
155+
, T.pack(show e)
156+
]
145157
logger = ideLogger ide
158+
159+
checkCancelled _id act k =
160+
flip finally (clearReqId _id) $
161+
catch (do
162+
-- We could optimize this by first checking if the id
163+
-- is in the cancelled set. However, this is unlikely to be a
164+
-- bottleneck and the additional check might hide
165+
-- issues with async exceptions that need to be fixed.
166+
cancelOrRes <- race (waitForCancel _id) act
167+
case cancelOrRes of
168+
Left () -> do
169+
logDebug (ideLogger ide) $ T.pack $ "Cancelled request " <> show _id
170+
k $ ResponseError RequestCancelled "" Nothing
171+
Right res -> pure res
172+
) $ \(e :: SomeException) -> do
173+
uncaughtError e
174+
k $ ResponseError InternalError (T.pack $ show e) Nothing
146175
_ <- flip forkFinally handleServerException $ runWithDb logger dbLoc $ \hiedb hieChan -> do
147176
putMVar dbMVar (hiedb,hieChan)
148177
forever $ do
149178
msg <- readChan clientMsgChan
150179
-- We dispatch notifications synchronously and requests asynchronously
151180
-- This is to ensure that all file edits and config changes are applied before a request is handled
152181
case msg of
153-
ReactorNotification act -> do
154-
catch act $ \(e :: SomeException) ->
155-
logError (ideLogger ide) $ T.pack $
156-
"Unexpected exception on notification, please report!\n" ++
157-
"Exception: " ++ show e
158-
ReactorRequest _id act k -> void $ async $
159-
checkCancelled ide clearReqId waitForCancel _id act k
182+
ReactorNotification act -> handle uncaughtError act
183+
ReactorRequest _id act k -> void $ async $ checkCancelled _id act k
160184
pure $ Right (env,ide)
161185

162-
checkCancelled
163-
:: IdeState -> (SomeLspId -> IO ()) -> (SomeLspId -> IO ()) -> SomeLspId
164-
-> IO () -> (ResponseError -> IO ()) -> IO ()
165-
checkCancelled ide clearReqId waitForCancel _id act k =
166-
flip finally (clearReqId _id) $
167-
catch (do
168-
-- We could optimize this by first checking if the id
169-
-- is in the cancelled set. However, this is unlikely to be a
170-
-- bottleneck and the additional check might hide
171-
-- issues with async exceptions that need to be fixed.
172-
cancelOrRes <- race (waitForCancel _id) act
173-
case cancelOrRes of
174-
Left () -> do
175-
logDebug (ideLogger ide) $ T.pack $ "Cancelled request " <> show _id
176-
k $ ResponseError RequestCancelled "" Nothing
177-
Right res -> pure res
178-
) $ \(e :: SomeException) -> do
179-
logError (ideLogger ide) $ T.pack $
180-
"Unexpected exception on request, please report!\n" ++
181-
"Exception: " ++ show e
182-
k $ ResponseError InternalError (T.pack $ show e) Nothing
183186

184187

185188
cancelHandler :: (SomeLspId -> IO ()) -> LSP.Handlers (ServerM c)

0 commit comments

Comments
 (0)