diff --git a/COPYING b/COPYING
new file mode 100644
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,25 @@
+Copyright (c) 2013 Boris Sukholitko
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. 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.
+3. The names of the authors may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 EVENT SHALL THE AUTHORS 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/HScope.hs b/HScope.hs
new file mode 100644
--- /dev/null
+++ b/HScope.hs
@@ -0,0 +1,194 @@
+{-# LANGUAGE BangPatterns #-}
+module Main (main) where
+
+import System.Console.GetOpt
+import System.Environment (getArgs, getProgName)
+import Database.CDB.Write
+import Database.CDB.Read
+import Database.CDB.Packable
+import Language.Haskell.Exts.Annotated
+import Control.Monad.Trans (liftIO)
+import Control.Monad (void, when)
+import System.Process (readProcess)
+import Data.List (foldl', intercalate, isInfixOf)
+import Data.Maybe
+import Data.Serialize
+import qualified Data.ByteString.Char8 as B
+import qualified Data.Vector as V
+import Control.Applicative ((<$>), (<*>))
+import System.IO (hFlush, stdout)
+import Data.Generics.Uniplate.Data (transformBiM)
+import Data.Data
+
+data Flag = Build Bool | File FilePath | Line | Query String | CPPInclude String deriving (Show)
+
+data Config = Config { cBuild :: Bool, cFile :: FilePath, cLine :: Bool
+                        , cQuery :: Maybe String, cCPPIncludes :: [String] } deriving Show
+
+data IType = Definition | Call deriving (Enum, Show, Eq)
+data Info = Info IType String Int B.ByteString deriving Show
+type Lines = V.Vector (Int, B.ByteString)
+
+instance Serialize Info where
+    put (Info ity file line bs) = do
+        put $ fromEnum ity 
+        put file
+        put line
+        put bs
+
+    get = do
+        ity <- fmap toEnum get
+        Info ity <$> get <*> get <*> get
+
+instance Unpackable Info where
+    unpack = either error id . decode
+
+options :: [OptDescr Flag]
+options = [
+            Option ['b'] [ "build" ] (NoArg $ Build True) "Build hscope database"
+            , Option ['d'] [ "dont-update" ] (NoArg $ Build False)
+                "Do not update the cross-reference"
+            , Option ['l'] [ "line" ] (NoArg $ Line) "Line-oriented interface"
+            , Option ['f'] [ "file" ] (ReqArg File "REFFILE") $
+                "Use REFFILE as the cross-reference file name instead of the default"
+                    ++ " \"hscope.out\""
+            , Option ['1'] [ "definition" ] (ReqArg (Query . ('1':)) "SYMBOL") $ "Find the definition of the SYMBOL"
+            , Option ['3'] [ "callers" ] (ReqArg (Query . ('3':)) "SYMBOL") $ "Find SYMBOLs calling this SYMBOL"
+            , Option ['4'] [ "text" ] (ReqArg (Query . ('4':)) "TEXT") $ "Find TEXT in files"
+            , Option ['7'] [ "file" ] (ReqArg (Query . ('7':)) "FILE") $ "Find files matching FILE"
+            , Option ['I'] [ "cpp-include" ] (ReqArg CPPInclude "DIRECTORY") $ "Include path for CPP preprocessor"
+          ]
+
+parseFlags :: [Flag] -> Config
+parseFlags = foldl' go $ Config False "hscope.out" False Nothing [] where
+    go c (Build b) = c { cBuild = b }
+    go c (File f) = c { cFile = f }
+    go c Line = c { cLine = True }
+    go c (Query q) = c { cQuery = Just q }
+    go c (CPPInclude i) = c { cCPPIncludes = i:(cCPPIncludes c) }
+
+addInfo :: Lines -> IType -> Name SrcSpanInfo -> CDBMake
+addInfo vec ity n = cdbAdd f $ encode $ Info ity (fileName src) (fst lp) (snd lp)
+    where l = startLine src
+          lp = maybe (error $ "Bad line: " ++ show n ++ ", " ++ show vec) id $ vec V.!? (l - 1)
+          (src, f) = case n of
+            (Ident src' f') -> (src', f')
+            (Symbol src' f') -> (src', f')
+
+traverseAST :: (Data b, Monad m, Data a, Functor m) => (a -> m ()) -> b -> m ()
+traverseAST cb = void . transformBiM go where go v = cb v >> return v
+
+handleDefinitions :: Lines -> Decl SrcSpanInfo -> CDBMake
+handleDefinitions vec = go where
+    go (PatBind _ (PVar _ n) _ _ _) = addDef n
+    go (FunBind _ ((Match _ n _ _ _):_)) = addDef n
+    go _ = return ()
+    addDef = addInfo vec Definition
+
+handleCalls :: Lines -> QName SrcSpanInfo -> CDBMake
+handleCalls vec (UnQual _ n) = addInfo vec Call n
+handleCalls _ _ = return ()
+
+handleConstructors :: Lines -> ConDecl SrcSpanInfo -> CDBMake
+handleConstructors vec (ConDecl _ n _) = addInfo vec Definition n
+handleConstructors vec (RecDecl _ n recs) = do
+    addInfo vec Definition n
+    mapM_ go recs
+    where go (FieldDecl _ ns _) = mapM_ (addInfo vec Definition) ns
+handleConstructors _ c = error $ "handleConstructors " ++ show c
+
+handleDeclarations :: Lines -> DeclHead SrcSpanInfo -> CDBMake
+handleDeclarations vec (DHead _ n _) = addInfo vec Definition n
+handleDeclarations _ c = error $ "handleDeclarations " ++ show c
+
+mapLines :: Show a => FilePath -> [a] -> [String] -> [a]
+mapLines f to = reverse . snd . foldl' go ((to, True), []) where
+    go ((xs@(x:_), _), res) ('#':str) = ((xs, isInfixOf f str), x:res)
+    go (((x:xs), True), res) _ = ((xs, True), x:res)
+    go ((xs@(x:_), False), res) _ = ((xs, False), x:res)
+    go t l = error $ "mapLines: " ++ show t ++ " at " ++ l
+
+preprocess :: [String] -> FilePath -> IO (String, Lines)
+preprocess idirs f = do
+    origs <- B.lines <$> (liftIO $ B.readFile f)
+    flns <- fmap lines $ readProcess "cpp" (incs ++ [ "-traditional-cpp", f ]) ""
+    return (fconts flns, V.fromList $ mapLines f (zip [1 ..] origs) flns)
+    where fconts = intercalate "\n" . map cmnt
+          cmnt ('#':_) = ""
+          cmnt x = x
+          incs = concatMap (\i -> [ "-I", i ]) idirs
+
+parseCurrentFile :: FilePath -> String -> Either String (Module SrcSpanInfo)
+parseCurrentFile f fstr = go [] where
+    go exts = case parseFileContentsWithMode (pmode exts) fstr of
+        ParseOk m -> Right m
+        ParseFailed src str -> let (ext, rest) = break (== ' ') str
+                in if rest == " is not enabled"
+                   then go ((classifyExtension ext):exts)
+                   else Left $ str ++ " for " ++ f ++ " at " ++ show src
+    pmode exts = defaultParseMode { fixities = Just baseFixities
+                            , extensions = exts
+                            , parseFilename = f }
+
+buildOne :: Config -> FilePath -> CDBMake
+buildOne cfg f = do
+    cdbAdd "0_hs_files" f
+    (fstr, lns) <- liftIO $ preprocess (cCPPIncludes cfg) f
+    either (liftIO . putStrLn) (go lns) $ parseCurrentFile f fstr
+    where go lns modul = do
+                    traverseAST (handleDefinitions lns) modul
+                    traverseAST (handleCalls lns) modul
+                    traverseAST (handleConstructors lns) modul
+                    traverseAST (handleDeclarations lns) modul
+                    -- liftIO $ putStrLn $ show modul
+
+handleQuery :: CDB -> String -> IO ()
+handleQuery cdb ('1':str) = findInfo Definition cdb str
+handleQuery cdb ('3':str) = findInfo Call cdb str
+handleQuery cdb ('4':str) = do
+    let files = cdbGetAll cdb "0_hs_files"
+    lns <- fmap lines $ readProcess "grep" ("-n":"-H":str:files) ""
+    outputLines $ map go lns
+    where go l = let (f, rest1) = break (':' ==) l
+                     (n, rest2) = break (':' ==) $ drop 1 rest1
+                  in f ++ " <unknown> " ++ n ++ " " ++ drop 1 rest2 
+handleQuery cdb ('7':str) = do
+    let files = cdbGetAll cdb "0_hs_files"
+    outputLines $ map go $ filter (isInfixOf str) files
+    where go f = f ++ " <unknown> 1 <unknown>"
+handleQuery _ _ = return ()
+
+runLines :: CDB -> IO ()
+runLines cdb = do
+    putStr ">> "
+    hFlush stdout
+    !l <- getLine
+    handleQuery cdb l
+    case l of
+        ('q':_) -> return ()
+        _ -> runLines cdb
+
+outputLines :: [String] -> IO ()
+outputLines infos = do
+    putStrLn $ "cscope: " ++ (show $ length infos) ++ " lines"
+    mapM_ putStrLn infos
+
+findInfo :: IType -> CDB -> String -> IO ()
+findInfo ity cdb str = outputLines $ catMaybes $ map go $ cdbGetAll cdb str
+    where go (Info t file lno line) | t == ity = Just $ file ++ " " ++ str
+                                        ++ " " ++ show lno ++ " " ++ B.unpack line
+                                    | otherwise = Nothing
+
+main :: IO ()
+main = do
+    (flags, rest, _) <- fmap (getOpt Permute options) getArgs
+    let cfg = parseFlags flags
+    when (cBuild cfg) $ cdbMake (cFile cfg) $ mapM_ (buildOne cfg) rest
+    if null flags then usage else go cfg
+    where usage = do
+            pn <- getProgName
+            putStrLn $ usageInfo ("Usage: " ++ pn ++ " [OPTION...] files...") options
+          go cfg = do
+            cdb <- cdbInit $ cFile cfg
+            maybe (return ()) (handleQuery cdb) $ cQuery cfg
+            when (cLine cfg) $ runLines cdb
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/hscope.cabal b/hscope.cabal
new file mode 100644
--- /dev/null
+++ b/hscope.cabal
@@ -0,0 +1,50 @@
+Name:           hscope
+Version:        0.1
+License:        BSD3
+License-File:   COPYING
+Category:       source-tools
+Synopsis:       cscope like browser for Haskell code
+Description:
+    hscope is a partial cscope line oriented mode reimplementation for Haskell code.
+
+    Currently it supports finding the definition and callers of the function, types.
+    Also works searching for files and in files.
+    
+    See hscope --help for available options.
+
+    Being cscope-compatible gives Vim integration for free. Use :set cscopeprg
+    to configure hscope as cscope replacement for haskell files.
+
+Cabal-Version:  >= 1.10
+Build-Type:     Simple
+Author:         Boris Sukholitko <boriss@gmail.com>
+Copyright:      Boris Sukholitko <boriss@gmail.com>
+Maintainer:     Boris Sukholitko <boriss@gmail.com>
+homepage:       https://github.com/bosu/hscope
+Stability:      Experimental
+Extra-Source-Files:
+    t/files/Arrow.hs
+    t/files/a/c.h
+    t/files/a/a.h
+    t/files/b/b.h
+    t/files/CPP2.hs
+    t/files/garrs.hs
+    t/files/Simple.hs
+    t/files/CPP.hs
+    t/files/a.c
+
+Executable hscope
+    Main-Is: HScope.hs
+    GHC-Options: -Wall
+    Build-Depends: base (< 5), hs-cdb, haskell-src-exts, mtl, uniplate, cereal
+                             , vector, bytestring, process
+    Default-Language: Haskell2010
+
+test-suite Build
+    type:            exitcode-stdio-1.0
+    build-depends:   base, test-simple, process, directory, Unixutils, mtl
+    ghc-options:     -Wall
+    hs-source-dirs:  t
+    main-is:         Build.hs
+    Default-Language: Haskell2010
+
diff --git a/t/Build.hs b/t/Build.hs
new file mode 100644
--- /dev/null
+++ b/t/Build.hs
@@ -0,0 +1,129 @@
+{-# OPTIONS -fno-warn-unused-do-bind -XBangPatterns #-}
+module Main (main) where
+
+import Test.Simple
+import System.Unix.Directory (withTemporaryDirectory)
+import System.Directory (canonicalizePath, doesFileExist)
+import System.Process (system, readProcess, runInteractiveProcess, waitForProcess)
+import System.Exit (ExitCode(ExitSuccess))
+import Control.Monad.Trans (liftIO)
+import System.IO (hGetContents, hPutStrLn, hFlush, hSetBinaryMode)
+
+hscopeInteract :: FilePath -> FilePath -> [String] -> IO (ExitCode, String)
+hscopeInteract hpath td cmds = do
+    (inp, out, _, ph1) <- runInteractiveProcess hpath [ "-dl", "-f", td ++ "/hscope.out" ]
+                                Nothing Nothing
+    hSetBinaryMode inp False
+    mapM_ (go inp) $ cmds ++ [ "q" ]
+
+    !l1 <- hGetContents out
+    ec2 <- waitForProcess ph1
+    return (ec2, l1)
+    where go inp cmd = hPutStrLn inp cmd >> hFlush inp
+
+main :: IO ()
+main = withTemporaryDirectory "/tmp/hscope_test_XXXXXX" $ \td -> testSimpleMain $ do
+    plan 42
+    hpath <- liftIO $ canonicalizePath "./dist/build/hscope/hscope"
+    tfile <- liftIO $ canonicalizePath "./t/files/Simple.hs"
+    ec1 <- liftIO $ system $ "cd " ++ td ++ " && " ++ hpath ++ " -b " ++ tfile
+    res1 <- liftIO $ readProcess "cdb" [ "-l", td ++ "/hscope.out" ] ""
+    is ec1 ExitSuccess
+    like res1 "main"
+
+    res2 <- liftIO $ readProcess "cdb" [ "-q", td ++ "/hscope.out", "main" ] ""
+    like res2 "main = "
+
+    res3 <- liftIO $ readProcess "cdb" [ "-q", td ++ "/hscope.out", "findInfo" ] ""
+    like res3 "-> findInfo "
+
+    res4 <- liftIO $ readProcess "cdb" [ "-q", td ++ "/hscope.out", "options" ] ""
+    like res4 "Permute options"
+
+    res5 <- liftIO $ readProcess "cdb" [ "-q", td ++ "/hscope.out", "runLines" ] ""
+    like res5 ">>= runLines"
+
+    (ec2, l1) <- liftIO $ hscopeInteract hpath td [ "1main", "1findInfo" ]
+    is ec2 ExitSuccess
+    like l1 ">> "
+    like l1 tfile
+    like l1 "main ="
+    like l1 "findInfo ity cdb str ="
+
+    (ec3, l2) <- liftIO $ hscopeInteract hpath td [ "3findInfo", "1Build", "1Config" ]
+    is ec3 ExitSuccess
+    like l2 "-> findInfo "
+    like l2 "2 lines"
+    like l2 "Build Bool"
+    like l2 "    Config {"
+
+    (ec4, l3) <- liftIO $ hscopeInteract hpath td [ "1Flag", "1Unused", "1cBuild" ]
+    is ec4 ExitSuccess
+    like l3 "data Flag"
+    like l3 "type Unused"
+    like l3 "cBuild :: Bool"
+
+    (ec5, l4) <- liftIO $ hscopeInteract hpath td [ "3cBuild", "3Flag", "3==" ]
+    is ec5 ExitSuccess
+    like l4 "cBuild cfg"
+    like l4 "parseFlags ::"
+    like l4 "groupBy (==)"
+
+    res6 <- liftIO $ readProcess hpath [ "-b", "-f", td ++ "/foo.out", "t/files/a.c" ] ""
+    like res6 "Parse error: 0"
+    like res6 "a.c"
+
+    dfoo <- liftIO $ doesFileExist $ td ++ "/foo.out"
+    is dfoo True
+
+    res7 <- liftIO $ readProcess hpath [ "-b", "-f", td ++ "/foo.out"
+                                            , "t/files/Arrow.hs", "t/files/CPP.hs" ] ""
+    is res7 ""
+
+    res8 <- liftIO $ readProcess hpath [ "-d", "-f", td ++ "/foo.out"
+                                            , "-1", "doSth" ] ""
+    like res8 "doSth ="
+
+    res9 <- liftIO $ readProcess hpath [ "-d", "-f", td ++ "/foo.out"
+                                            , "-1", "foo" ] ""
+    like res9 "foo 6 bar = id"
+    unlike res9 "warning"
+
+    res9_1 <- liftIO $ readProcess hpath [ "-d", "-f", td ++ "/foo.out"
+                                            , "-7", "Ar" ] ""
+    is res9_1 "cscope: 1 lines\nt/files/Arrow.hs <unknown> 1 <unknown>\n"
+
+    res10 <- liftIO $ readProcess hpath [ "-d", "-f", td ++ "/hscope.out"
+                                            , "-3", "groupBy" ] ""
+    like res10 "groupBy (==)"
+
+    res10_1 <- liftIO $ readProcess hpath [ "-d", "-f", td ++ "/hscope.out"
+                                            , "-3", "Build" ] ""
+    like res10_1 "NoArg $ Build False"
+    like res10_1 "Build b) ="
+
+    res11 <- liftIO $ readProcess hpath [ "-d", "-f", td ++ "/hscope.out"
+                                            , "-4", "= do" ] ""
+    like res11 "files/Simple.hs <unknown> 115 main = do"
+
+    res12 <- liftIO $ readProcess hpath [ "-b", "-f", td ++ "/foo.out"
+                                    , "-I", "t/files/a", "-I", "t/files/b"
+                                    , "t/files/CPP2.hs" ] ""
+    is res12 ""
+
+    res13 <- liftIO $ readProcess hpath [ "-d", "-f", td ++ "/foo.out"
+                                            , "-1", "bar" ] ""
+    like res13 "bar 7 bar = id"
+
+    res14 <- liftIO $ readProcess hpath [ "-b", "-f", td ++ "/foo.out"
+                                    , "t/files/garrs.hs" ] ""
+    is res14 ""
+
+    res15 <- liftIO $ readProcess hpath [ "--help" ] ""
+    like res15 $ "Usage: hscope [OPTION...] files..."
+    like res15 "-b"
+
+    res16 <- liftIO $ readProcess hpath [] ""
+    is res16 res15
+
+    return ()
diff --git a/t/files/Arrow.hs b/t/files/Arrow.hs
new file mode 100644
--- /dev/null
+++ b/t/files/Arrow.hs
@@ -0,0 +1,6 @@
+module Main
+where
+
+import Control.Arrow
+
+doSth = (+ 1) . head &&& tail
diff --git a/t/files/CPP.hs b/t/files/CPP.hs
new file mode 100644
--- /dev/null
+++ b/t/files/CPP.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE CPP #-}
+
+#define bar foo
+
+bar :: Int -> Int
+bar = id
+
+baz' = 12
diff --git a/t/files/CPP2.hs b/t/files/CPP2.hs
new file mode 100644
--- /dev/null
+++ b/t/files/CPP2.hs
@@ -0,0 +1,7 @@
+{-# LANGUAGE CPP #-}
+
+#include "a.h"
+#include "b.h"
+
+bar :: Int -> Int
+bar = id
diff --git a/t/files/Simple.hs b/t/files/Simple.hs
new file mode 100644
--- /dev/null
+++ b/t/files/Simple.hs
@@ -0,0 +1,119 @@
+{-# LANGUAGE BangPatterns #-}
+module Main (main) where
+
+import System.Console.GetOpt
+import System.Environment (getArgs)
+import Database.CDB.Write
+import Database.CDB.Read
+import Database.CDB.Packable
+import Language.Haskell.Exts (parseFile)
+import Language.Haskell.Exts.Parser (ParseResult(ParseOk))
+import Control.Monad.Trans (liftIO)
+import Control.Monad (when)
+import Data.List (foldl')
+import Data.Maybe
+import Data.IORef
+import Data.Generics.Zipper.Bubble (bubble, Callback(..))
+import Language.Haskell.Exts.Syntax (Decl(PatBind, FunBind), Name(Ident)
+                        , Pat(PVar), SrcLoc(..), Match(Match), Exp(..), QName(UnQual))
+import Data.Serialize
+import qualified Data.ByteString.Char8 as B
+import qualified Data.Vector as V
+import Control.Applicative ((<$>), (<*>))
+import System.IO (hFlush, stdout)
+
+type Unused = Int
+
+testSymbol :: Eq a => [a] -> [a]
+testSymbol = groupBy (==)
+
+data Flag = Build Bool | File FilePath | Line deriving (Show)
+
+data Config =
+    Config { cBuild :: Bool, cFile :: FilePath, cLine :: Bool } deriving Show
+
+data IType = Definition | Call deriving (Enum, Show, Eq)
+data Info = Info IType String Int B.ByteString deriving Show
+
+instance Serialize Info where
+    put (Info ity file line bs) = do
+        put $ fromEnum ity 
+        put file
+        put line
+        put bs
+
+    get = do
+        ity <- fmap toEnum get
+        Info ity <$> get <*> get <*> get
+
+instance Unpackable Info where
+    unpack = either error id . decode
+
+options :: [OptDescr Flag]
+options = [
+            Option ['b'] [ "build" ] (NoArg $ Build True) "Build hscope database"
+            , Option ['d'] [ "dont-update" ] (NoArg $ Build False) "Do not update the cross-reference"
+            , Option ['l'] [ "line" ] (NoArg $ Line) "Line-oriented interface"
+            , Option ['f'] [ "file" ] (ReqArg File "REFFILE") $
+                "Use REFFILE as the cross-reference file name instead of the default \"hscope.out\""
+          ]
+
+parseFlags :: [Flag] -> Config
+parseFlags = foldl' go $ Config False "hscope.out" False where
+    go c (Build b) = c { cBuild = b }
+    go c (File f) = c { cFile = f }
+    go c Line = c { cLine = True }
+
+addInfo :: V.Vector B.ByteString -> SrcLoc -> IType -> String -> CDBMake
+addInfo vec (SrcLoc file line _) ity f = cdbAdd f $ encode $ Info ity file line (vec V.! (line - 1))
+
+handleDefinitions :: V.Vector B.ByteString -> Decl -> CDBMake
+handleDefinitions vec = go where
+    go (PatBind src (PVar (Ident f)) _ _ _) = addDef f src
+    go (FunBind ((Match src (Ident f) _ _ _ _):_)) = addDef f src
+    go _ = return ()
+    addDef f src = addInfo vec src Definition f
+
+handleSrcLoc :: IORef SrcLoc -> SrcLoc -> CDBMake
+handleSrcLoc ior = liftIO . writeIORef ior
+
+handleCalls :: IORef SrcLoc -> V.Vector B.ByteString -> Exp -> CDBMake
+handleCalls ior vec (Var (UnQual (Ident f))) = do
+    src <- liftIO $ readIORef ior
+    addInfo vec src Call f
+handleCalls _ _ _ = return ()
+
+buildOne :: FilePath -> CDBMake
+buildOne f = do
+    ParseOk modul <- liftIO $ parseFile f
+    lns <- V.fromList <$> B.lines <$> (liftIO $ B.readFile f)
+    sior <- liftIO $ newIORef $ SrcLoc f 1 1
+    bubble [Callback $ handleSrcLoc sior, Callback $ handleDefinitions lns, Callback $ handleCalls sior lns] [] modul
+
+runLines :: CDB -> IO ()
+runLines cdb = do
+    putStr ">> "
+    hFlush stdout
+    !l <- getLine
+    case l of
+        ('q':_) -> return ()
+        ('1':str) -> findInfo Definition cdb str
+        ('3':str) -> findInfo Call cdb str
+        _ -> runLines cdb
+
+findInfo :: IType -> CDB -> String -> IO ()
+findInfo ity cdb str = do
+    let infos = catMaybes $ map go $ cdbGetAll cdb str
+    putStrLn $ "cscope: " ++ (show $ length infos) ++ " lines"
+    mapM_ putStrLn infos
+    runLines cdb
+    where go (Info t file lno line) | t == ity = Just $ file ++ " " ++ str
+                                        ++ " " ++ show lno ++ " " ++ B.unpack line
+                                    | otherwise = Nothing
+
+main :: IO ()
+main = do
+    (flags, rest, _) <- fmap (getOpt Permute options) getArgs
+    let cfg = parseFlags flags
+    when (cBuild cfg) $ cdbMake "hscope.out" $ mapM_ buildOne rest
+    when (cLine cfg) $ (cdbInit $ cFile cfg) >>= runLines
diff --git a/t/files/a.c b/t/files/a.c
new file mode 100644
--- /dev/null
+++ b/t/files/a.c
@@ -0,0 +1,7 @@
+static int foo() {
+	return 0;
+}
+
+int main() {
+	return foo();
+}
diff --git a/t/files/a/a.h b/t/files/a/a.h
new file mode 100644
--- /dev/null
+++ b/t/files/a/a.h
@@ -0,0 +1,1 @@
+#include "c.h"
diff --git a/t/files/a/c.h b/t/files/a/c.h
new file mode 100644
--- /dev/null
+++ b/t/files/a/c.h
@@ -0,0 +1,3 @@
+type Hello = Int
+
+type Bye = Bool
diff --git a/t/files/b/b.h b/t/files/b/b.h
new file mode 100644
--- /dev/null
+++ b/t/files/b/b.h
@@ -0,0 +1,1 @@
+data Foo = Foo
diff --git a/t/files/garrs.hs b/t/files/garrs.hs
new file mode 100644
--- /dev/null
+++ b/t/files/garrs.hs
@@ -0,0 +1,6 @@
+data G a where
+    A :: a -> G Int
+    B :: b -> G Bool
+
+g :: Int -> Int
+g proc = proc + 1
