2 module Java.ClassPath.Common where
5 import Data.String.Utils (split)
7 import Java.ClassPath.Types
10 mapF :: (t -> a) -> [Tree t] -> [Tree a]
11 mapF fn forest = map (mapT fn) forest
14 mapFM :: (Monad m, Functor m) => (t -> m a) -> [Tree t] -> m [Tree a]
15 mapFM fn forest = mapM (mapTM fn) forest
18 mapTM :: (Monad m, Functor m) => (t -> m a) -> Tree t -> m (Tree a)
19 mapTM fn (Directory dir forest) = Directory dir `fmap` mapFM fn forest
20 mapTM fn (File a) = File `fmap` fn a
23 mapT :: (t -> a) -> Tree t -> Tree a
24 mapT fn (Directory dir forest) = Directory dir (mapF fn forest)
25 mapT fn (File a) = File (fn a)
27 -- | Build tree from list of filenames.
28 -- For example, ["org/haskell", "org/java"] --> [org/{haskell, java}]
29 buildTree :: [FilePath] -> [Tree FilePath]
31 let build :: [[String]] -> [Tree FilePath]
32 build [[name]] = [File name]
33 build ss = map node $ groupBy eq (sort ss)
35 node [] = error "Impossible: groupBy give an empty group!"
37 node l | all (null . tail) l = File (head $ head l)
38 | otherwise = Directory (head $ head l) (build $ map tail l)
40 ls = map (split "/") strs
43 eq (x:_) (y:_) = x == y
47 -- | Merge ClassPath forest.
48 -- For example, [org/haskell, org/java] --> [org/{haskell, java}].
49 merge :: [Tree CPEntry] -> [Tree CPEntry]
51 merge [t1,t2] = merge1 [t1] t2
52 merge (t:ts) = foldl merge1 [t] ts
54 -- | Add one ClassPath tree to forest.
55 merge1 :: [Tree CPEntry] -> Tree CPEntry -> [Tree CPEntry]
57 merge1 (x@(File e): es) y@(File e') | e == e' = x: es
58 | otherwise = x: merge1 es y
59 merge1 (d@(Directory _ _):es) f@(File _) = d: merge1 es f
60 merge1 (f@(File _):es) d@(Directory _ _) = f: merge1 es d
61 merge1 (x@(Directory dir f):es) y@(Directory dir' f')
62 | dir == dir' = Directory dir (merge $ f ++ f'): es
63 | otherwise = x: merge1 es y