@@ -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
@@ -137,48 +139,49 @@ runLanguageServer options inH outH getHieDbLoc defaultConfig onConfigurationChan
137
139
registerIdeConfiguration (shakeExtras ide) initConfig
138
140
139
141
let handleServerException (Left e) = do
140
- logError (ideLogger ide) $
142
+ logError logger $
141
143
T. pack $ " Fatal error in server thread: " <> show e
142
144
exitClientMsg
143
145
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
+ ]
144
156
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
145
174
_ <- flip forkFinally handleServerException $ runWithDb logger dbLoc $ \ hiedb hieChan -> do
146
175
putMVar dbMVar (hiedb,hieChan)
147
176
forever $ do
148
177
msg <- readChan clientMsgChan
149
178
-- We dispatch notifications synchronously and requests asynchronously
150
179
-- This is to ensure that all file edits and config changes are applied before a request is handled
151
180
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
159
183
pure $ Right (env,ide)
160
184
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
182
185
183
186
184
187
cancelHandler :: (SomeLspId -> IO () ) -> LSP. Handlers (ServerM c )
0 commit comments