Skip to content

Commit dd4fd68

Browse files
committed
Reload .cabal files when they are modified
1 parent 349ff6e commit dd4fd68

File tree

5 files changed

+61
-5
lines changed

5 files changed

+61
-5
lines changed

ghcide/session-loader/Development/IDE/Session.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir que = do
586586
unless (null new_deps || not checkProject) $ do
587587
cfps' <- liftIO $ filterM (IO.doesFileExist . fromNormalizedFilePath) (concatMap targetLocations all_targets)
588588
void $ shakeEnqueue extras $ mkDelayedAction "InitialLoad" Debug $ void $ do
589-
mmt <- uses GetModificationTime cfps'
589+
mmt <- uses GetPhysicalModificationTime cfps'
590590
let cs_exist = catMaybes (zipWith (<$) cfps' mmt)
591591
modIfaces <- uses GetModIface cs_exist
592592
-- update exports map

ghcide/src/Development/IDE/Core/FileStore.hs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ import System.FilePath
7878
import System.IO.Error
7979
import System.IO.Unsafe
8080

81-
8281
data Log
8382
= LogCouldNotIdentifyReverseDeps !NormalizedFilePath
8483
| LogTypeCheckingReverseDeps !NormalizedFilePath !(Maybe [NormalizedFilePath])
@@ -147,6 +146,35 @@ getModificationTimeImpl missingFileDiags file = do
147146
then return (Nothing, ([], Nothing))
148147
else return (Nothing, ([diag], Nothing))
149148

149+
150+
getPhysicalModificationTimeRule :: Recorder (WithPriority Log) -> Rules ()
151+
getPhysicalModificationTimeRule recorder = defineEarlyCutoff (cmapWithPrio LogShake recorder) $ Rule $ \GetPhysicalModificationTime file ->
152+
getPhysicalModificationTimeImpl file
153+
154+
getPhysicalModificationTimeImpl
155+
:: NormalizedFilePath
156+
-> Action (Maybe BS.ByteString, ([FileDiagnostic], Maybe FileVersion))
157+
getPhysicalModificationTimeImpl file = do
158+
let file' = fromNormalizedFilePath file
159+
let wrap time = (Just $ LBS.toStrict $ B.encode $ toRational time, ([], Just $ ModificationTime time))
160+
-- if isWF
161+
-- then
162+
-- -- the file is watched so we can rely on FileWatched notifications,
163+
-- -- but also need a dependency on IsFileOfInterest to reinstall
164+
-- -- alwaysRerun when the file becomes VFS
165+
-- void (use_ IsFileOfInterest file)
166+
-- else
167+
alwaysRerun
168+
169+
liftIO $ fmap wrap (getModTime file')
170+
`catch` \(e :: IOException) -> do
171+
let err | isDoesNotExistError e = "File does not exist: " ++ file'
172+
| otherwise = "IO error while reading " ++ file' ++ ", " ++ displayException e
173+
diag = ideErrorText file (T.pack err)
174+
if isDoesNotExistError e
175+
then return (Nothing, ([], Nothing))
176+
else return (Nothing, ([diag], Nothing))
177+
150178
-- | Interface files cannot be watched, since they live outside the workspace.
151179
-- But interface files are private, in that only HLS writes them.
152180
-- So we implement watching ourselves, and bypass the need for alwaysRerun.
@@ -170,7 +198,11 @@ resetFileStore ideState changes = mask $ \_ -> do
170198
case c of
171199
LSP.FileChangeType_Changed
172200
-- already checked elsewhere | not $ HM.member nfp fois
173-
-> atomically $ deleteValue (shakeExtras ideState) GetModificationTime nfp
201+
->
202+
atomically $ do
203+
ks <- deleteValue (shakeExtras ideState) GetModificationTime nfp
204+
vs <- deleteValue (shakeExtras ideState) GetPhysicalModificationTime nfp
205+
pure $ ks ++ vs
174206
_ -> pure []
175207

176208

@@ -233,6 +265,7 @@ getVersionedTextDoc doc = do
233265
fileStoreRules :: Recorder (WithPriority Log) -> (NormalizedFilePath -> Action Bool) -> Rules ()
234266
fileStoreRules recorder isWatched = do
235267
getModificationTimeRule recorder
268+
getPhysicalModificationTimeRule recorder
236269
getFileContentsRule recorder
237270
addWatchedFileRule recorder isWatched
238271

ghcide/src/Development/IDE/Core/RuleTypes.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
{-# LANGUAGE PatternSynonyms #-}
77
{-# LANGUAGE TemplateHaskell #-}
88
{-# LANGUAGE TypeFamilies #-}
9+
{-# LANGUAGE DeriveAnyClass #-}
910

1011
-- | A Shake implementation of the compiler service, built
1112
-- using the "Shaker" abstraction layer for in-memory use.
@@ -316,6 +317,13 @@ instance Hashable GetModificationTime where
316317

317318
instance NFData GetModificationTime
318319

320+
data GetPhysicalModificationTime = GetPhysicalModificationTime
321+
deriving (Generic, Show, Eq)
322+
deriving anyclass (Hashable, NFData)
323+
324+
-- | Get the modification time of a file.
325+
type instance RuleResult GetPhysicalModificationTime = FileVersion
326+
319327
pattern GetModificationTime :: GetModificationTime
320328
pattern GetModificationTime = GetModificationTime_ {missingFileDiagnostics=True}
321329

ghcide/src/Development/IDE/Core/Rules.hs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ data Log
181181
| LogLoadingHieFileFail !FilePath !SomeException
182182
| LogLoadingHieFileSuccess !FilePath
183183
| LogTypecheckedFOI !NormalizedFilePath
184+
| LogDependencies !NormalizedFilePath [FilePath]
184185
deriving Show
185186

186187
instance Pretty Log where
@@ -205,6 +206,11 @@ instance Pretty Log where
205206
<+> "the HLS version being used, the plugins enabled, and if possible the codebase and file which"
206207
<+> "triggered this warning."
207208
]
209+
LogDependencies nfp deps ->
210+
vcat $
211+
[ "Add dependency" <+> pretty (fromNormalizedFilePath nfp)
212+
, nest 2 $ pretty deps
213+
]
208214

209215
templateHaskellInstructions :: T.Text
210216
templateHaskellInstructions = "https://haskell-language-server.readthedocs.io/en/latest/troubleshooting.html#static-binaries"
@@ -715,7 +721,8 @@ loadGhcSession recorder ghcSessionDepsConfig = do
715721
let nfp = toNormalizedFilePath' fp
716722
itExists <- getFileExists nfp
717723
when itExists $ void $ do
718-
use_ GetModificationTime nfp
724+
use_ GetPhysicalModificationTime nfp
725+
logWith recorder Logger.Info $ LogDependencies file deps
719726
mapM_ addDependency deps
720727

721728
let cutoffHash = LBS.toStrict $ B.encode (hash (snd val))

plugins/hls-cabal-plugin/src/Ide/Plugin/Cabal.hs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
{-# LANGUAGE LambdaCase #-}
44
{-# LANGUAGE OverloadedStrings #-}
55
{-# LANGUAGE TypeFamilies #-}
6+
{-# LANGUAGE PatternSynonyms #-}
67

78
module Ide.Plugin.Cabal (descriptor, haskellInteractionDescriptor, Log (..)) where
89

@@ -154,7 +155,7 @@ descriptor recorder plId =
154155
\ide vfs _ (DidSaveTextDocumentParams TextDocumentIdentifier{_uri} _) -> liftIO $ do
155156
whenUriFile _uri $ \file -> do
156157
log' Debug $ LogDocSaved _uri
157-
restartCabalShakeSession (shakeExtras ide) vfs file "(saved)" $
158+
restartCabalShakeSessionPhysical (shakeExtras ide) vfs file "(saved)" $
158159
addFileOfInterest recorder ide file OnDisk
159160
, mkPluginNotificationHandler LSP.SMethod_TextDocumentDidClose $
160161
\ide vfs _ (DidCloseTextDocumentParams TextDocumentIdentifier{_uri}) -> liftIO $ do
@@ -188,6 +189,13 @@ restartCabalShakeSession shakeExtras vfs file actionMsg actionBetweenSession = d
188189
keys <- actionBetweenSession
189190
return (toKey GetModificationTime file:keys)
190191

192+
193+
restartCabalShakeSessionPhysical :: ShakeExtras -> VFS.VFS -> NormalizedFilePath -> String -> IO [Key] -> IO ()
194+
restartCabalShakeSessionPhysical shakeExtras vfs file actionMsg actionBetweenSession = do
195+
restartShakeSession shakeExtras (VFSModified vfs) (fromNormalizedFilePath file ++ " " ++ actionMsg) [] $ do
196+
keys <- actionBetweenSession
197+
return (toKey GetModificationTime file:toKey GetPhysicalModificationTime file:keys)
198+
191199
-- ----------------------------------------------------------------
192200
-- Plugin Rules
193201
-- ----------------------------------------------------------------

0 commit comments

Comments
 (0)