This repository was archived by the owner on Oct 7, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 206
/
Copy pathGhcModuleCache.hs
145 lines (119 loc) · 5.08 KB
/
GhcModuleCache.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
module Haskell.Ide.Engine.GhcModuleCache where
import qualified Data.ByteString.Char8 as B
import Data.Dynamic (Dynamic)
import Data.List
import qualified Data.Map as Map
import qualified Data.Trie as T
import Data.Typeable (TypeRep)
import qualified HIE.Bios as Bios
import GHC (TypecheckedModule, ParsedModule, HscEnv)
import Haskell.Ide.Engine.ArtifactMap
import Haskell.Ide.Engine.Cradle
import Language.Haskell.LSP.Types
type UriCaches = Map.Map FilePath UriCacheResult
data UriCacheResult = UriCacheSuccess UriCache
| UriCacheFailed
deriving (Show)
uriCacheState :: UriCacheResult -> String
uriCacheState UriCacheFailed = "UriCacheFailed"
uriCacheState UriCacheSuccess{} = "UriCacheSuccess"
data UriCache = UriCache
{ cachedInfo :: !CachedInfo
, cachedPsMod :: !ParsedModule
, cachedTcMod :: !(Maybe TypecheckedModule)
-- | Data pertaining to the typechecked module,
-- not the parsed module
, cachedData :: !(Map.Map TypeRep Dynamic)
}
instance Show UriCache where
show (UriCache _ _ (Just _) dat) =
"UriCache { cachedTcMod, cachedData { " ++ show dat ++ " } }"
show (UriCache _ _ _ dat) =
"UriCache { cachedPsMod, cachedData { " ++ show dat ++ " } }"
data CachedInfo = CachedInfo
{ locMap :: !LocMap
, typeMap :: !TypeMap
, moduleMap :: !ModuleMap
, defMap :: !DefMap
, revMap :: !(FilePath -> FilePath)
, newPosToOld :: !(Position -> Maybe Position)
, oldPosToNew :: !(Position -> Maybe Position)
}
class CacheableModule a where
fromUriCache :: UriCache -> Maybe a
instance CacheableModule TypecheckedModule where
fromUriCache (UriCache _ _ mtm _) = mtm
instance CacheableModule ParsedModule where
fromUriCache (UriCache _ pm _ _) = Just pm
-- ---------------------------------------------------------------------
-- | Given a list of things with their start and end position in the
-- file, return the set of them that cross include the given position,
-- after it is updated based on edits since the last compile.
getThingsAtPos :: CachedInfo -> Position -> [(Position,Position,a)] -> [(Range,a)]
getThingsAtPos cm pos ts =
case newPosToOld cm pos of
Nothing -> []
Just pos' -> getArtifactsAtPos pos' (genIntervalMap ts)
-- ---------------------------------------------------------------------
-- The following to move into ghc-mod-core
class Monad m => HasGhcModuleCache m where
getModuleCache :: m GhcModuleCache
modifyModuleCache :: (GhcModuleCache -> GhcModuleCache) -> m ()
emptyModuleCache :: GhcModuleCache
emptyModuleCache = GhcModuleCache T.empty Map.empty Nothing
data LookupCradleResult = ReuseCradle | LoadCradle CachedCradle | NewCradle FilePath
-- | Lookup for the given File if the module cache has a fitting Cradle.
-- Checks if the File belongs to the current Cradle and if it is,
-- the current Cradle can be reused for the given Module/File.
--
-- If the Module is part of another Cradle that has already been loaded,
-- return the Cradle.
-- Otherwise, a new Cradle for the given FilePath needs to be created.
--
-- After loading, the cradle needs to be set as the current Cradle
-- via 'setCurrentCradle' before the Cradle can be cached via 'cacheCradle'.
lookupCradle :: FilePath -> GhcModuleCache -> LookupCradleResult
lookupCradle fp gmc =
lookupInCache fp gmc (const $ const ReuseCradle) LoadCradle $ NewCradle fp
-- | Find the cradle wide 'ComponentOptions' that apply to a 'FilePath'
lookupComponentOptions
:: HasGhcModuleCache m => FilePath -> m (Maybe Bios.ComponentOptions)
lookupComponentOptions fp = do
gmc <- getModuleCache
return $ lookupInCache fp gmc (const Just) (Just . compOpts) Nothing
lookupInCache
:: FilePath
-> GhcModuleCache
-> (Bios.Cradle CabalHelper -> Bios.ComponentOptions -> a)
-- ^ Called when file is in the current cradle
-> (CachedCradle -> a)
-- ^ Called when file is a member of a cached cradle
-> a
-- ^ Default value to return if a cradle is not found
-> a
lookupInCache fp gmc cur cached def = case currentCradle gmc of
Just (dirs, c, co) | any (`isPrefixOf` fp) dirs -> cur c co
_ -> case T.match (cradleCache gmc) (B.pack fp) of
Just (_k, c, _suf) -> cached c
Nothing -> def
-- | A 'Cradle', it's 'HscEnv' and 'ComponentOptions'
data CachedCradle = CachedCradle
{ ccradle :: Bios.Cradle CabalHelper
, hscEnv :: HscEnv
, compOpts :: Bios.ComponentOptions
}
instance Show CachedCradle where
show (CachedCradle x _ _) = show x
data GhcModuleCache = GhcModuleCache
{ cradleCache :: !(T.Trie CachedCradle)
-- ^ map from FilePath to cradle and it's config.
-- May not include currentCradle
, uriCaches :: !UriCaches
, currentCradle :: Maybe ([FilePath], Bios.Cradle CabalHelper, Bios.ComponentOptions)
-- ^ The current cradle, it's config,
-- and which FilePath's it is responsible for.
} deriving (Show)
-- ---------------------------------------------------------------------