1module Idris.Chaser(buildTree, getImports, getModuleFiles, ModuleTree(..)) where
12import System.Directory
14import Control.Monad.Trans
15import Control.Monad.State
19import Util.System (readSource, writeSource)
21data ModuleTree = MTree { mod_path :: IFileType,
22 mod_needsRecheck :: Bool,
24 mod_deps :: [ModuleTree] }
27latest :: UTCTime -> [ModuleTree] -> UTCTime
29latest tm (m : ms) = latest (max tm (mod_time m)) (ms ++ mod_deps m)
31-- Given a module tree, return the list of files to be loaded. If any
32-- module has a descendent which needs reloading, return its source, otherwise
35getModuleFiles :: [ModuleTree] -> [IFileType]
36getModuleFiles ts = nub $ execState (modList ts) [] where
37 modList :: [ModuleTree] -> State [IFileType] ()
38 modList [] = return ()
39 modList (m : ms) = do modTree [] m; modList ms
41 modTree path (MTree p rechk tm deps)
42 = do let file = chkReload rechk p
43 -- Needs rechecking if 'rechk' is true, or if any of the
44 -- modification times in 'deps' are later than tm
45 let depMod = latest tm deps
46 let needsRechk = rechk || depMod > tm
49 if needsRechk then put $ nub (getSrc file : updateToSrc path st)
50 else put $ nub (file : st)
51-- when (not (ibc p) || rechk) $
52 mapM_ (modTree (getSrc p : path)) deps
58 chkReload True (IBC fn src) = chkReload True src
61 getSrc (IBC fn src) = getSrc src
64 updateToSrc path [] = []
65 updateToSrc path (x : xs) = if getSrc x `elem` path
66 then getSrc x : updateToSrc path xs
67 else x : updateToSrc path xs
69-- Strip quotes and the backslash escapes that Haskeline adds
70extractFileName :: String -> String
71extractFileName ('"':xs) = takeWhile (/= '"') xs
72extractFileName ('\'':xs) = takeWhile (/= '\'') xs
73extractFileName x = build x []
75 build [] acc = reverse $ dropWhile (== ' ') acc
76 build ('\\':' ':xs) acc = build xs (' ':acc)
77 build (x:xs) acc = build xs (x:acc)
79getIModTime (IBC i _) = getModificationTime i
80getIModTime (IDR i) = getModificationTime i
81getIModTime (LIDR i) = getModificationTime i
83getImports :: [(FilePath, [ImportInfo])] -> [FilePath] ->
84 Idris [(FilePath, [ImportInfo])]
85getImports acc [] = return acc
86getImports acc (f : fs) = do
88 let file = extractFileName f
89 ibcsd <- valIBCSubDir i
92 fp <- findImport ["."] ibcsd file
94 case lookup parsef acc of
95 Just _ -> getImports acc fs
97 exist <- runIO $ doesFileExist parsef
99 src_in <- runIO $ readSource parsef
100 src <- if lit fp then tclift $ unlit parsef src_in
102 (_, _, modules, _) <- parseImports parsef src
104 getImports ((parsef, modules) : acc)
105 (fs ++ map import_path modules)
106 else getImports ((parsef, []) : acc) fs)
107 (\_ -> getImports acc fs) -- not in current soure tree, ignore
114 fname (IBC _ src) = fname src
116buildTree :: [FilePath] -> -- already guaranteed built
117 [(FilePath, [ImportInfo])] -> -- import lists (don't reparse)
118 FilePath -> Idris [ModuleTree]
119buildTree built importlists fp = evalStateT (btree [] fp) []
121 addFile :: FilePath -> [ModuleTree] ->
122 StateT [(FilePath, [ModuleTree])] Idris [ModuleTree]
123 addFile f m = do fs <- get
127 btree :: [FilePath] -> FilePath ->
128 StateT [(FilePath, [ModuleTree])] Idris [ModuleTree]
130 do i <- lift getIState
131 let file = extractFileName f
132 lift $ logLvl 1 $ "CHASING " ++ show file ++ " (" ++ show fp ++ ")"
133 ibcsd <- lift $ valIBCSubDir i
134 ids <- lift $ allImportDirs
135 fp <- lift $ findImport ids ibcsd file
136 lift $ logLvl 1 $ "Found " ++ show fp
137 mt <- lift $ runIO $ getIModTime fp
138 if (file `elem` built)
139 then return [MTree fp False mt []]
140 else if file `elem` stk then
141 do lift $ tclift $ tfail
142 (Msg $ "Cycle detected in imports: "
143 ++ showSep " -> " (reverse (file : stk)))
144 else do donetree <- get
145 case lookup file donetree of
147 _ -> do ms <- mkChildren file fp
150 where mkChildren file (LIDR fn) = do ms <- children True fn (file : stk)
151 mt <- lift $ runIO $ getModificationTime fn
152 return [MTree (LIDR fn) True mt ms]
153 mkChildren file (IDR fn) = do ms <- children False fn (file : stk)
154 mt <- lift $ runIO $ getModificationTime fn
155 return [MTree (IDR fn) True mt ms]
156 mkChildren file (IBC fn src)
157 = do srcexist <- lift $ runIO $ doesFileExist (getSrcFile src)
158 ms <- if srcexist then
159 do [MTree _ _ _ ms'] <- mkChildren file src
162 mt <- lift $ idrisCatch (runIO $ getModificationTime fn)
163 (\c -> runIO $ getIModTime src)
164 -- FIXME: It's also not up to date if anything it imports has
165 -- been modified since its own ibc has.
167 -- Issue #1592 on the issue tracker.
169 -- https://github.com/idris-lang/Idris-dev/issues/1592
170 ibcOutdated <- lift $ fn `younger` (getSrcFile src)
171 -- FIXME (EB): The below 'hasValidIBCVersion' that's
172 -- commented out appears to be breaking reloading in vim
173 -- mode. Until we know why, I've commented it out.
174 ibcValid <- return True -- hasValidIBCVersion fn
175 return [MTree (IBC fn src) (ibcOutdated || not ibcValid) mt ms]
177 getSrcFile (IBC _ src) = getSrcFile src
178 getSrcFile (LIDR src) = src
179 getSrcFile (IDR src) = src
181 younger ibc src = do exist <- runIO $ doesFileExist src
183 ibct <- runIO $ getModificationTime ibc
184 srct <- runIO $ getModificationTime src
188 children :: Bool -> FilePath -> [FilePath] ->
189 StateT [(FilePath, [ModuleTree])] Idris [ModuleTree]
190 children lit f stk = -- idrisCatch
191 do exist <- lift $ runIO $ doesFileExist f
193 lift $ logLvl 1 $ "Reading source " ++ show f
194 let modules = maybe [] id (lookup f importlists)
195 ms <- mapM (btree stk . import_path) modules
197 else return [] -- IBC with no source available
198-- (\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