@@ -40,6 +40,8 @@ import Development.IDE.Types.Logger
40
40
41
41
import System.IO.Unsafe (unsafeInterleaveIO )
42
42
43
+ issueTrackerUrl = " https://github.com/haskell/haskell-language-server/issues"
44
+
43
45
runLanguageServer
44
46
:: forall config . (Show config )
45
47
=> LSP. Options
@@ -138,48 +140,49 @@ runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChan
138
140
registerIdeConfiguration (shakeExtras ide) initConfig
139
141
140
142
let handleServerException (Left e) = do
141
- logError (ideLogger ide) $
143
+ logError logger $
142
144
T. pack $ " Fatal error in server thread: " <> show e
143
145
exitClientMsg
144
146
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
+ ]
145
157
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
146
175
_ <- flip forkFinally handleServerException $ runWithDb logger dbLoc $ \ hiedb hieChan -> do
147
176
putMVar dbMVar (hiedb,hieChan)
148
177
forever $ do
149
178
msg <- readChan clientMsgChan
150
179
-- We dispatch notifications synchronously and requests asynchronously
151
180
-- This is to ensure that all file edits and config changes are applied before a request is handled
152
181
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
160
184
pure $ Right (env,ide)
161
185
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
183
186
184
187
185
188
cancelHandler :: (SomeLspId -> IO () ) -> LSP. Handlers (ServerM c )
0 commit comments