Skip to content

Commit 58eca00

Browse files
committed
Send unhandled exceptions to the user
1 parent ae6f707 commit 58eca00

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
@@ -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

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

0 commit comments

Comments
 (0)