@@ -51,6 +51,7 @@ import qualified Data.Map as Map
5151import qualified Data.ByteString.Char8 as BS
5252import Data.Dynamic
5353import Data.Maybe
54+import Data.Map.Strict (Map)
5455import Data.Either.Extra
5556import Data.List.Extra
5657import qualified Data.Text as T
@@ -80,11 +81,14 @@ import Language.Haskell.LSP.Types
8081-- information we stash inside the shakeExtra field
8182data ShakeExtras = ShakeExtras
8283 {eventer :: LSP.FromServerMessage -> IO ()
83− ,debouncer :: Debouncer Uri
84+ ,debouncer :: Debouncer NormalizedUri
8485 ,logger :: Logger
8586 ,globals :: Var (HMap.HashMap TypeRep Dynamic)
8687 ,state :: Var Values
8788 ,diagnostics :: Var DiagnosticStore
89+ ,publishedDiagnostics :: Var (Map NormalizedUri [Diagnostic])
90+ -- ^ This represents the set of diagnostics that we have published.
91+ -- Due to debouncing not every change might get published.
8892 }
8993
9094getShakeExtras :: Action ShakeExtras
@@ -224,6 +228,7 @@ shakeOpen eventer logger opts rules = do
224228 globals <- newVar HMap.empty
225229 state <- newVar HMap.empty
226230 diagnostics <- newVar mempty
231+ publishedDiagnostics <- newVar mempty
227232 debouncer <- newDebouncer
228233 pure ShakeExtras{..}
229234 (shakeDb, shakeClose) <- shakeOpenDatabase opts{shakeExtra = addShakeExtra shakeExtras $ shakeExtra opts} rules
@@ -382,22 +387,25 @@ updateFileDiagnostics ::
382387 -> ShakeExtras
383388 -> [Diagnostic] -- ^ current results
384389 -> Action ()
385−updateFileDiagnostics fp k ShakeExtras{diagnostics, state, debouncer, eventer} current = liftIO $ do
390+updateFileDiagnostics fp k ShakeExtras{diagnostics, publishedDiagnostics, state, debouncer, eventer} current = liftIO $ do
386391 modTime <- join <$> getValues state GetModificationTime fp
387392 mask_ $ do
388393 -- Mask async exceptions to ensure that updated diagnostics are always
389394 -- published. Otherwise, we might never publish certain diagnostics if
390395 -- an exception strikes between modifyVar but before
391396 -- publishDiagnosticsNotification.
392− (newDiags, oldDiags) <- modifyVar diagnostics $ \old -> do
393− let oldDiags = getFileDiagnostics fp old
397+ newDiags <- modifyVar diagnostics $ \old -> do
394398 let newDiagsStore = setStageDiagnostics fp (vfsVersion =<< modTime) (T.pack $ show k) current old
395399 let newDiags = getFileDiagnostics fp newDiagsStore
396− pure (newDiagsStore, (newDiags, oldDiags))
397− let uri = fromNormalizedUri $ filePathToUri' fp
398− when (newDiags /= oldDiags) $ do
399− let delay = if null newDiags then 0.1 else 0
400− registerEvent debouncer delay uri $ eventer $ publishDiagnosticsNotification uri newDiags
400+ pure (newDiagsStore, newDiags)
401+ let uri = filePathToUri' fp
402+ let delay = if null newDiags then 0.1 else 0
403+ registerEvent debouncer delay uri $ do
404+ mask_ $ modifyVar_ publishedDiagnostics $ \published -> do
405+ let lastPublish = Map.findWithDefault [] uri published
406+ when (lastPublish /= newDiags) $
407+ eventer $ publishDiagnosticsNotification (fromNormalizedUri uri) newDiags
408+ pure (Map.insert uri newDiags published)
401409
402410publishDiagnosticsNotification :: Uri -> [Diagnostic] -> LSP.FromServerMessage
403411publishDiagnosticsNotification uri diags =