diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2011, Yoshikuni Jujo
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+  * Neither the name of the Yoshikuni Jujo nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVEN SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+
+main = defaultMain
diff --git a/hssourceinfo.cabal b/hssourceinfo.cabal
new file mode 100644
--- /dev/null
+++ b/hssourceinfo.cabal
@@ -0,0 +1,53 @@
+build-type:	Simple
+cabal-version:	>= 1.6
+
+name:		hssourceinfo
+version:	0.0.2
+stability:	experimental
+author:		Yoshikuni Jujo <PAF01143@nifty.ne.jp>
+maintainer:	Yoshikuni Jujo <PAF01143@nifty.ne.jp>
+
+license:	BSD3
+license-file:	LICENSE
+
+category:	Development
+synopsis:	get haskell source code info
+description:
+  now only module dependencies and code line numbers
+  .
+  > % hsmodtree xturtle/src
+  > Graphics.X11.Turtle
+  >   + Graphics.X11.TurtleMove
+  >   |   + Graphics.X11.TurtleState
+  >   |   + Graphics.X11.TurtleField
+  >   + Graphics.X11.TurtleInput
+  >   |   + Grahpics.X11.TurtleState
+  >   + Graphics.X11.TurtleShape
+
+  > % hscodeline xturtle/src
+  > Graphics/X11/Turtle.hs          158
+  > Graphics/X11/TurtleMove.hs      82
+  > Graphics/X11/TurtleState.hs     54
+  > Graphics/X11/TurtleField.hs     428
+  > Graphics/X11/TurtleInput.hs     76
+  > Graphics/X11/TurtleShape.hs     10
+  > total                           808
+
+
+source-repository	head
+  type:		git
+  location:	git://github.com/YoshikuniJujo/hssourceinfo.git
+
+executable		hsmodtree
+  Hs-Source-Dirs:	src
+  Main-Is:		hsmodtree.hs
+  Build-Depends:	base >= 4 && < 5, containers, directory, regexpr
+  Ghc-Options:		-Wall
+  Other-Modules:	HsModTree
+
+executable		hscodelines
+  Hs-Source-Dirs:	src
+  Main-Is:		hscodelines.hs
+  Build-Depends:	base >= 4 && < 5, containers, directory, regexpr, filepath
+  Ghc-Options:		-Wall
+  Other-Modules:	HsModTree
diff --git a/src/HsModTree.hs b/src/HsModTree.hs
new file mode 100644
--- /dev/null
+++ b/src/HsModTree.hs
@@ -0,0 +1,107 @@
+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
diff --git a/src/hscodelines.hs b/src/hscodelines.hs
new file mode 100644
--- /dev/null
+++ b/src/hscodelines.hs
@@ -0,0 +1,52 @@
+module Main where
+
+import System.Environment
+import Control.Arrow(first)
+import Text.RegexPR
+import Data.Tree
+import Data.List
+import Data.Char
+import HsModTree
+import System.FilePath
+
+main :: IO ()
+main = do
+	[ dir ] <- getArgs
+	files <- fmap filterSource $ getDirectoryContentsRec dir
+	dependList <- mapM ( depend dir files ) files
+	let	depList = map (first $ gsubRegexPR "/" ".") dependList
+		trees = map nubTree $ mergeTree $ map makeTree depList
+	mapM_ (printModTreeLines dir) $ map (nub . flatten) trees
+
+printModTreeLines :: FilePath -> [String] -> IO ()
+printModTreeLines dir mns = do
+	s <- fmap sum $ mapM (printModLines dir) mns
+	putStrLn $ "total" ++ replicate 27 ' ' ++ show s
+	putStrLn ""
+
+printModLines :: FilePath -> String -> IO Int
+printModLines dir mn = do
+	let fp = modNameToFilePath mn
+	lns <- fileLines dir fp
+	putStrLn $ showModLines fp lns
+	return lns
+
+showModLines :: FilePath -> Int -> String
+showModLines fp lns = fp ++ replicate (32 - length fp) ' ' ++ show lns
+
+fileLines :: FilePath -> FilePath -> IO Int
+fileLines dir = fmap codeLines . readFile . (dir </>)
+
+modNameToFilePath :: String -> FilePath
+modNameToFilePath = (++ ".hs") . gsubRegexPR "\\." "/"
+
+codeLines :: String -> Int
+codeLines code = length $ filter (not . all isSpace) $ lines $ deleteComms code
+
+deleteComms :: String -> String
+deleteComms = subRegexPR "module\\s+(.|\n)*?\\s+where" "" .
+		gsubRegexPR "--.*\n" "" .
+		gsubRegexPR "{-(?:[^-]|-(?!}))*-}" ""
+
+testDeleteComms :: FilePath -> IO ()
+testDeleteComms fp = readFile fp >>= putStr . deleteComms
diff --git a/src/hsmodtree.hs b/src/hsmodtree.hs
new file mode 100644
--- /dev/null
+++ b/src/hsmodtree.hs
@@ -0,0 +1,15 @@
+module Main where
+
+import System.Environment
+import Control.Arrow(first)
+import Text.RegexPR
+import HsModTree
+
+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
