3Description : Module chaser to determine cycles and import modules.
6Maintainer : The Idris Community.
22import Control.Monad.State
23import Control.Monad.Trans
27import System.Directory
29import Util.System (readSource, writeSource)
31data ModuleTree = MTree { mod_path :: IFileType,
32 mod_needsRecheck :: Bool,
34 mod_deps :: [ModuleTree] }
37latest :: UTCTime -> [ModuleTree] -> UTCTime
39latest tm (m : ms) = latest (max tm (mod_time m)) (ms ++ mod_deps m)
41-- | Given a module tree, return the list of files to be loaded. If
42-- any module has a descendent which needs reloading, return its
43-- source, otherwise return the IBC
44getModuleFiles :: [ModuleTree] -> [IFileType]
45getModuleFiles ts = nub $ execState (modList ts) [] where
46 modList :: [ModuleTree] -> State [IFileType] ()
47 modList [] = return ()
48 modList (m : ms) = do modTree [] m; modList ms
50 modTree path (MTree p rechk tm deps)
51 = do let file = chkReload rechk p
52 -- Needs rechecking if 'rechk' is true, or if any of the
53 -- modification times in 'deps' are later than tm
54 let depMod = latest tm deps
55 let needsRechk = rechk || depMod > tm
58 if needsRechk then put $ nub (getSrc file : updateToSrc path st)
59 else put $ nub (file : st)
60-- when (not (ibc p) || rechk) $
61 mapM_ (modTree (getSrc p : path)) deps
67 chkReload True (IBC fn src) = chkReload True src
70 getSrc (IBC fn src) = getSrc src
73 updateToSrc path [] = []
74 updateToSrc path (x : xs) = if getSrc x `elem` path
75 then getSrc x : updateToSrc path xs
76 else x : updateToSrc path xs
78-- | Strip quotes and the backslash escapes that Haskeline adds
79extractFileName :: String -> String
80extractFileName ('"':xs) = takeWhile (/= '"') xs
81extractFileName ('\'':xs) = takeWhile (/= '\'') xs
82extractFileName x = build x []
84 build [] acc = reverse $ dropWhile (== ' ') acc
85 build ('\\':' ':xs) acc = build xs (' ':acc)
86 build (x:xs) acc = build xs (x:acc)
88getIModTime (IBC i _) = getModificationTime i
89getIModTime (IDR i) = getModificationTime i
90getIModTime (LIDR i) = getModificationTime i
92getImports :: [(FilePath, [ImportInfo])]
94 -> Idris [(FilePath, [ImportInfo])]
95getImports acc [] = return acc
96getImports acc (f : fs) = do
98 let file = extractFileName f
99 ibcsd <- valIBCSubDir i
101 srcds <- allSourceDirs
102 fp <- findImport srcds ibcsd file
103 let parsef = fname fp
104 case lookup parsef acc of
105 Just _ -> getImports acc fs
107 exist <- runIO $ doesFileExist parsef
109 src_in <- runIO $ readSource parsef
110 src <- if lit fp then tclift $ unlit parsef src_in
112 (_, _, modules, _) <- parseImports parsef src
114 getImports ((parsef, modules) : acc)
115 (fs ++ map import_path modules)
116 else getImports ((parsef, []) : acc) fs)
117 (\_ -> getImports acc fs) -- not in current soure tree, ignore
124 fname (IBC _ src) = fname src
126buildTree :: [FilePath] -- ^ already guaranteed built
127 -> [(FilePath, [ImportInfo])] -- ^ import lists (don't reparse)
129 -> Idris [ModuleTree]
130buildTree built importlists fp = evalStateT (btree [] fp) []
132 addFile :: FilePath -> [ModuleTree] ->
133 StateT [(FilePath, [ModuleTree])] Idris [ModuleTree]
134 addFile f m = do fs <- get
138 btree :: [FilePath] -> FilePath ->
139 StateT [(FilePath, [ModuleTree])] Idris [ModuleTree]
141 do i <- lift getIState
142 let file = extractFileName f
143 lift $ logLvl 1 $ "CHASING " ++ show file ++ " (" ++ show fp ++ ")"
144 ibcsd <- lift $ valIBCSubDir i
145 ids <- lift allImportDirs
146 fp <- lift $ findImport ids ibcsd file
147 lift $ logLvl 1 $ "Found " ++ show fp
148 mt <- lift $ runIO $ getIModTime fp
149 if (file `elem` built)
150 then return [MTree fp False mt []]
151 else if file `elem` stk then
152 do lift $ tclift $ tfail
153 (Msg $ "Cycle detected in imports: "
154 ++ showSep " -> " (reverse (file : stk)))
155 else do donetree <- get
156 case lookup file donetree of
158 _ -> do ms <- mkChildren file fp
161 where mkChildren file (LIDR fn) = do ms <- children True fn (file : stk)
162 mt <- lift $ runIO $ getModificationTime fn
163 return [MTree (LIDR fn) True mt ms]
164 mkChildren file (IDR fn) = do ms <- children False fn (file : stk)
165 mt <- lift $ runIO $ getModificationTime fn
166 return [MTree (IDR fn) True mt ms]
167 mkChildren file (IBC fn src)
168 = do srcexist <- lift $ runIO $ doesFileExist (getSrcFile src)
169 ms <- if srcexist then
170 do [MTree _ _ _ ms'] <- mkChildren file src
173 mt <- lift $ idrisCatch (runIO $ getModificationTime fn)
174 (\c -> runIO $ getIModTime src)
175 -- FIXME: It's also not up to date if anything it imports has
176 -- been modified since its own ibc has.
178 -- Issue #1592 on the issue tracker.
180 -- https://github.com/idris-lang/Idris-dev/issues/1592
181 ibcOutdated <- lift $ fn `younger` (getSrcFile src)
182 -- FIXME (EB): The below 'hasValidIBCVersion' that's
183 -- commented out appears to be breaking reloading in vim
184 -- mode. Until we know why, I've commented it out.
185 ibcValid <- return True -- hasValidIBCVersion fn
186 return [MTree (IBC fn src) (ibcOutdated || not ibcValid) mt ms]
188 getSrcFile (IBC _ src) = getSrcFile src
189 getSrcFile (LIDR src) = src
190 getSrcFile (IDR src) = src
192 younger ibc src = do exist <- runIO $ doesFileExist src
194 ibct <- runIO $ getModificationTime ibc
195 srct <- runIO $ getModificationTime src
199 children :: Bool -> FilePath -> [FilePath] ->
200 StateT [(FilePath, [ModuleTree])] Idris [ModuleTree]
201 children lit f stk = -- idrisCatch
202 do exist <- lift $ runIO $ doesFileExist f
204 lift $ logLvl 1 $ "Reading source " ++ show f
205 let modules = maybe [] id (lookup f importlists)
206 ms <- mapM (btree stk . import_path) modules
208 else return [] -- IBC with no source available
209-- (\c -> return []) -- error, can't chase modules here
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list