module HsModTree where
import Text.RegexPR
import System.Directory
import Data.List
import Data.Tree
import System.Environment
import Control.Monad
import Control.Arrow(first)
{-
main :: IO ()
main = do
[ dir ] <- getArgs
files <- fmap filterSource $ getDirectoryContentsRec dir
dependList <- mapM ( depend dir files ) files
let depList = map (first $ gsubRegexPR "/" ".") dependList
mapM_ ( putStr . showTree [ ] . nubTree ) $
mergeTree $ map makeTree depList
-}
getDirectoryContentsRec, getDirectoryContentsRecGen :: String -> IO [String]
getDirectoryContentsRec root = do
pre <- getCurrentDirectory
setCurrentDirectory root
ret <- getDirectoryContentsRecGen "."
setCurrentDirectory pre
return $ map (tail . tail) ret
getDirectoryContentsRecGen root = do
ps <- getDir root
files <- filterM (doesFileExist . (root ++) . ("/" ++)) ps
dirs <- filterM (doesDirectoryExist . (root ++) . ("/" ++)) ps
subs <- fmap concat $ mapM (getDirectoryContentsRecGen . mkPath) dirs
return $ map mkPath files ++ subs
-- roots <- fmap concat $ mapM (getDir . mkPath) dirs
where
mkPath = (root ++) . ("/" ++)
getDir = fmap (filter $ flip notElem [".", ".."]) . getDirectoryContents
showTree :: [ Bool ] -> Tree String -> String
showTree n ( Node x ns ) =
makePre ( reverse n ) ++ x ++ "\n" ++
( concatMap ( showTree ( True : n ) ) ( init ns ) ++
maybe "" ( showTree ( False : n ) ) ( last ns ) )
where
init [ ] = [ ]
init [ x ] = [ ]
init ( x : xs ) = x : init xs
last [ ] = Nothing
last [ x ] = Just x
last ( _ : xs ) = last xs
makePre [ ] = ""
makePre [ _ ] = " + "
makePre ( True : rest ) = " | " ++ makePre rest
makePre ( False : rest ) = " " ++ makePre rest
nubTree :: Eq a => Tree a -> Tree a
nubTree ( Node x ns ) = Node x $ nub $ map nubTree ns
makeTree :: Eq a => ( a, [ a ] ) -> Tree a
makeTree ( x, xs ) = Node x $ map ( flip Node [ ] ) xs
mergeTree :: Eq a => [ Tree a ] -> [ Tree a ]
mergeTree ts = case map fst $ filter snd $ map ( `addTree_` ts ) ts of
[ ] -> ts
new -> mergeTree new
addTree_ :: Eq a => Tree a -> [ Tree a ] -> ( Tree a, Bool )
addTree_ t@( Node x _ ) ts = addTree t $ filter ( ( /= x ) . rootLabel ) ts
addTree :: Eq a => Tree a -> [ Tree a ] -> ( Tree a, Bool )
addTree ( Node x ns ) ts = case filter ( ( == x ) . rootLabel ) ts of
[ ] -> ( Node x $ map fst rets, any snd rets )
t : _ -> ( t, True )
where
rets = map ( `addTree` ts ) ns
depend :: FilePath -> [ String ] -> String -> IO ( String, [ String ] )
depend dir fps fp = do
cnt <- readAnyFile [ dir ++ "/" ++ fp ++ ".hs", dir ++ "/" ++ fp ++ ".y" ]
return ( fp, map ( !! 1 ) $ ggetbrsRegexPR ( mkReg fps ) cnt )
filterSource :: [ FilePath ] -> [ FilePath ]
filterSource =
map stripSuffix . filter ( isSuffixOf ".hs" ||| isSuffixOf ".y" ) .
filter ( not . isPrefixOf "." )
mkReg :: [ FilePath ] -> String
mkReg fps_ =
"^import\\s+(?:qualified\\s+)?(" ++ intercalate "|" fps ++ ")($|\\s|\\()"
where
fps = map (gsubRegexPR "/" ".") fps_
stripSuffix :: String -> String
stripSuffix = takeWhile ( /= '.' )
initN :: Int -> [ a ] -> [ a ]
initN n = ( !! n ) . iterate init
(|||) :: ( a -> Bool ) -> ( a -> Bool ) -> a -> Bool
( f1 ||| f2 ) x = f1 x || f2 x
readAnyFile :: [ FilePath ] -> IO String
readAnyFile ( f : fs ) = do
ex <- doesFileExist f
if ex then readFile f else readAnyFile fs