diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@
 
 Both formats:
 ```bash
-hasktags --ignore-close-implementation .
+hasktags --both .
 ```
 
 *NB:* Generating both tags generates a file called `TAGS` for Emacs, and one called `ctags` for Vim.
diff --git a/hasktags.cabal b/hasktags.cabal
--- a/hasktags.cabal
+++ b/hasktags.cabal
@@ -1,5 +1,5 @@
 Name: hasktags
-Version: 0.70.1
+Version: 0.71.0
 Copyright: The University Court of the University of Glasgow
 License: BSD3
 License-File: LICENSE
@@ -42,7 +42,6 @@
   testcases/testcase11.hs
   testcases/simple.hs
   testcases/monad-base-control.hs
-  testcases/16.hs
   testcases/16-regression.hs
   testcases/9.hs
   testcases/9-too.hs
@@ -76,7 +75,10 @@
       base,
       directory,
       filepath,
-      hasktags
+      hasktags,
+      optparse-applicative,
+      containers
+    other-modules: Paths_hasktags
     ghc-options: -Wall
     default-language: Haskell2010
 
diff --git a/src/Hasktags.hs b/src/Hasktags.hs
--- a/src/Hasktags.hs
+++ b/src/Hasktags.hs
@@ -1,40 +1,42 @@
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE RecordWildCards #-}
+
 -- should this be named Data.Hasktags or such?
 module Hasktags (
   FileData,
   generate,
-  findWithCache,
   findThings,
   findThingsInBS,
 
   Mode(..),
+  TagsFile(..),
+  Tags(..),
   --  TODO think about these: Must they be exported ?
-  getMode,
   getOutFile,
 
   dirToFiles
 ) where
 import           Control.Monad              (when)
-import qualified Data.ByteString.Lazy.Char8 as BS (ByteString, readFile, unpack)
-import qualified Data.ByteString.Lazy.UTF8  as BS8 (fromString)
+import           Control.Arrow              ((***))
+import qualified Data.ByteString.Char8 as BS (ByteString, readFile, unpack)
+import qualified Data.ByteString.UTF8  as BS8 (fromString)
 import           Data.Char                  (isSpace)
+import           Data.String                (IsString(..))
 import           Data.List                  (isPrefixOf, isSuffixOf, groupBy,
-                                             tails)
+                                             tails, nub)
 import           Data.Maybe                 (maybeToList)
 import           DebugShow                  (trace_)
 import           System.Directory           (doesDirectoryExist, doesFileExist,
                                              getDirectoryContents,
                                              getModificationTime,
+                                             canonicalizePath,
 #if MIN_VERSION_directory(1,3,0)
                                               pathIsSymbolicLink)
 #else
                                               isSymbolicLink)
 #endif
 import           System.FilePath            ((</>))
-import           System.IO                  (Handle,
-                                             IOMode (AppendMode, WriteMode),
-                                             hClose, hGetContents, openFile,
-                                             stdin, stdout)
+import           System.IO                  (Handle, IOMode, hClose, openFile, stdout)
 import           Tags                       (FileData (..), FileName,
                                              FoundThing (..),
                                              FoundThingType (FTClass, FTCons, FTConsAccessor, FTConsGADT, FTData, FTDataGADT, FTFuncImpl, FTFuncTypeDef, FTInstance, FTModule, FTNewtype, FTPattern, FTPatternTypeDef, FTType),
@@ -92,37 +94,42 @@
 -- Reference: http://ctags.sourceforge.net/FORMAT
 
 
--- | getMode takes a list of modes and extracts the mode with the
---   highest precedence.  These are as follows: Both, CTags, ETags
---   The default case is Both.
-getMode :: [Mode] -> Mode
-getMode [] = BothTags
-getMode xs = maximum xs
-
 -- | getOutFile scans the modes searching for output redirection
 --   if not found, open the file with name passed as parameter.
 --   Handle special file -, which is stdout
-getOutFile :: String -> IOMode -> [Mode] -> IO Handle
-getOutFile _           _        (OutRedir "-" : _) = return stdout
-getOutFile _           openMode (OutRedir f : _)   = openFile f openMode
-getOutFile name        openMode (_:xs)             = getOutFile name openMode xs
-getOutFile defaultName openMode []                 = openFile
-                                                     defaultName
-                                                     openMode
+getOutFile :: String -> IOMode -> IO Handle
+getOutFile filepath openMode
+  | "-" == filepath = return stdout
+  | otherwise       = openFile filepath openMode
 
-data Mode = ExtendedCtag
-          | ETags
-          | CTags
-          | BothTags
-          | Append
-          | OutRedir String
-          | CacheFiles
-          | FollowDirectorySymLinks
-          | Help
-          | HsSuffixes [String]
-          | AbsolutePath
-          deriving (Ord, Eq, Show)
+data TagsFile = TagsFile
+  { _ctagsFile :: FilePath
+  , _etagsFile :: FilePath
+  }
 
+instance Show TagsFile where
+  show TagsFile{..} = "ctags: " ++ _ctagsFile ++ ", etags: " ++ _etagsFile
+
+instance IsString TagsFile where
+  fromString s = TagsFile s s
+
+data Tags =
+    Ctags
+  | Etags
+  | Both
+  deriving Show
+
+data Mode = Mode
+  { _tags             :: Tags
+  , _extendedCtag     :: Bool
+  , _appendTags       :: IOMode
+  , _outputFile       :: TagsFile
+  , _cacheData        :: Bool
+  , _followSymlinks   :: Bool
+  , _suffixes         :: [String]
+  , _absoluteTagPaths :: Bool
+  } deriving Show
+
 data Token = Token String Pos
             | NewLine Int -- space 8*" " = "\t"
   deriving (Eq)
@@ -143,34 +150,28 @@
 trimNewlines :: [Token] -> [Token]
 trimNewlines = filter (not . isNewLine Nothing)
 
-generate :: [Mode] -> [FileName] -> IO ()
-generate modes filenames = do
+generate :: Mode -> [FilePath] -> IO ()
+generate Mode{..} files = do
+  files_or_dirs <- if _absoluteTagPaths
+                          then mapM canonicalizePath files
+                          else return files
 
-  let mode = getMode (filter ( `elem` [BothTags, CTags, ETags] ) modes)
-      openFileMode = if Append `elem` modes
-                     then AppendMode
-                     else WriteMode
-  filedata <- mapM (findWithCache (CacheFiles `elem` modes)) filenames
+  filenames <- (nub . concat) <$> mapM (dirToFiles _followSymlinks _suffixes) files_or_dirs
 
-  when (mode == CTags)
-       (do ctagsfile <- getOutFile "tags" openFileMode modes
-           writectagsfile ctagsfile (ExtendedCtag `elem` modes) filedata
-           hClose ctagsfile)
+  filedata <- mapM (findWithCache _cacheData) filenames
 
-  when (mode == ETags)
-       (do etagsfile <- getOutFile "TAGS" openFileMode modes
-           writeetagsfile etagsfile filedata
-           hClose etagsfile)
+  writeTags _tags filedata
 
-  -- avoid problem when both is used in combination
-  -- with redirection on stdout
-  when (mode == BothTags)
-       (do etagsfile <- getOutFile "TAGS" openFileMode modes
-           writeetagsfile etagsfile filedata
-           ctagsfile <- getOutFile "ctags" openFileMode modes
-           writectagsfile ctagsfile (ExtendedCtag `elem` modes) filedata
-           hClose etagsfile
-           hClose ctagsfile)
+  where
+    writeTags Ctags filedata = writeFile' _ctagsFile (writectagsfile _extendedCtag filedata)
+    writeTags Etags filedata = writeFile' _etagsFile (writeetagsfile filedata)
+    writeTags Both filedata  = writeTags Ctags filedata >> writeTags Etags filedata
+    writeFile' :: FilePath -> (Handle -> IO ()) -> IO ()
+    writeFile' name f = do
+      file <- getOutFile name _appendTags
+      f file
+      hClose file
+    TagsFile{..} = _outputFile
 
 -- Find the definitions in a file, or load from cache if the file
 -- hasn't changed since last time.
@@ -204,7 +205,7 @@
 -- Find the definitions in a file
 findThings :: FileName -> IO FileData
 findThings filename =
-  fmap (findThingsInBS filename) $ BS.readFile filename
+  findThingsInBS filename <$> BS.readFile filename
 
 findThingsInBS :: String -> BS.ByteString -> FileData
 findThingsInBS filename bs = do
@@ -217,7 +218,7 @@
                   cppLine _         = False
                 in filter (not . emptyLine) . filter (not . cppLine)
 
-        let debugStep m = (\s -> trace_ (m ++ " result") s s)
+        let debugStep m s = trace_ (m ++ " result") s s
 
         let (isLiterate, slines) =
               debugStep "fromLiterate"
@@ -256,7 +257,7 @@
         let topLevelIndent = debugStep "top level indent" $ getTopLevelIndent isLiterate tokenLines
         let sections = map tail -- strip leading NL (no longer needed)
                        $ filter (not . null)
-                       $ splitByNL (Just (topLevelIndent) )
+                       $ splitByNL (Just topLevelIndent )
                        $ concat (trace_ "tokenLines" tokenLines tokenLines)
         -- only take one of
         -- a 'x' = 7
@@ -278,8 +279,8 @@
             skipCons FTData (FTCons _ _)       = False
             skipCons FTDataGADT (FTConsGADT _) = False
             skipCons _ _                       = True
-        let things = iCI $ filterAdjacentFuncImpl $ concatMap (flip findstuff Nothing) $
-                map (\s -> trace_ "section in findThingsInBS" s s) sections
+        let things = iCI $ filterAdjacentFuncImpl $ concatMap (flip findstuff Nothing .
+                (\s -> trace_ "section in findThingsInBS" s s)) sections
         let
           -- If there's a module with the same name of another definition, we
           -- are not interested in the module, but only in the definition.
@@ -336,8 +337,7 @@
 
 findstuff :: [Token] -> Scope -> [FoundThing]
 findstuff (Token "module" _ : Token name pos : _) _ =
-        trace_ "module" pos $
-        [FoundThing FTModule name pos] -- nothing will follow this section
+        trace_ "module" pos [FoundThing FTModule name pos] -- nothing will follow this section
 findstuff tokens@(Token "data" _ : Token name pos : xs) _
         | any ( (== "where"). tokenString ) xs -- GADT
             -- TODO will be found as FTCons (not FTConsGADT), the same for
@@ -358,15 +358,15 @@
         -- FoundThing FTNewtype name pos : findstuff xs
 findstuff tokens@(Token "type" _ : Token name pos : xs) _ =
         trace_  "findstuff type" tokens $
-        case (break ((== "where").tokenString) xs) of
+        case break ((== "where").tokenString) xs of
         (ys, []) ->
-          trace_ "findstuff type b1 " ys $ [FoundThing FTType name pos]
+          trace_ "findstuff type b1 " ys [FoundThing FTType name pos]
         (ys, r) ->
           trace_ "findstuff type b2 " (ys, r) $
           FoundThing FTType name pos : fromWhereOn r Nothing
 findstuff tokens@(Token "class" _ : xs) _ =
         trace_  "findstuff class" tokens $
-        case (break ((== "where").tokenString) xs) of
+        case break ((== "where").tokenString) xs of
         (ys, []) ->
           trace_ "findstuff class b1 " ys $
           maybeToList $ className ys
@@ -386,7 +386,7 @@
               _                     -> Nothing
 findstuff tokens@(Token "instance" _ : xs) _ =
         trace_  "findstuff instance" tokens $
-        case (break ((== "where").tokenString) xs) of
+        case break ((== "where").tokenString) xs of
         (ys, []) ->
           trace_ "findstuff instance b1 " ys $
           maybeToList $ instanceName ys
@@ -398,8 +398,7 @@
             (map (\a -> if a == '.' then '-' else a) $ concatTokens lst) p
           instanceName _ = Nothing
 findstuff tokens@(Token "pattern" _ : Token name pos : Token "::" _ : sig) _ =
-        trace_ "findstuff pattern type annotation" tokens $
-        [FoundThing (FTPatternTypeDef (concatTokens sig)) name pos]
+        trace_ "findstuff pattern type annotation" tokens [FoundThing (FTPatternTypeDef (concatTokens sig)) name pos]
 findstuff tokens@(Token "pattern" _ : Token name pos : xs) scope =
         trace_ "findstuff pattern" tokens $
         FoundThing FTPattern name pos : findstuff xs scope
@@ -415,7 +414,10 @@
 findFuncTypeDefs found xs@(Token "(" _ :_) scope =
           case break myBreakF xs of
             (inner@(Token _ p : _), rp : xs') ->
-              let merged = Token ( concatMap (\(Token x _) -> x) $ inner ++ [rp] ) p
+              let merged = Token ( concatMap (\z -> case z of
+                                                 (Token x _) -> x
+                                                 (NewLine _) -> "")
+                                   $ inner ++ [rp] ) p
               in findFuncTypeDefs found (merged : xs') scope
             _ -> []
     where myBreakF (Token ")" _) = True
@@ -493,7 +495,7 @@
 getTopLevelIndent :: Bool -> [[Token]] -> Int
 getTopLevelIndent _ [] = 0 -- (no import found, assuming indent 0: this can be
                            -- done better but should suffice for most needs
-getTopLevelIndent isLiterate ((nl:next:_):xs) = if "import" == (tokenString next)
+getTopLevelIndent isLiterate ((nl:next:_):xs) = if "import" == tokenString next
                           then let (NewLine i) = nl in i
                           else getTopLevelIndent isLiterate xs
 getTopLevelIndent isLiterate (_:xs) = getTopLevelIndent isLiterate xs
@@ -515,17 +517,17 @@
     else (False, lns)
 
   where unlit, returnCode :: [(String, Int)] -> [(String, Int)]
-        unlit ((('>':' ':xs),n):ns) = ((' ':xs),n):unlit(ns) -- unlit keeps space, so do we
+        unlit (('>':' ':xs,n):ns) = (' ':xs,n):unlit ns -- unlit keeps space, so do we
         unlit ((line,_):ns) = if "\\begin{code}" `isPrefixOf` line then returnCode ns else unlit ns
         unlit [] = []
 
         -- in \begin{code} block
-        returnCode (t@(line,_):ns) = if "\\end{code}" `isPrefixOf` line then unlit ns else t:(returnCode ns)
+        returnCode (t@(line,_):ns) = if "\\end{code}" `isPrefixOf` line then unlit ns else t:returnCode ns
         returnCode [] = [] -- unexpected - hasktags does tagging, not compiling, thus don't treat missing \end{code} to be an error
 
 -- suffixes: [".hs",".lhs"], use "" to match all files
 dirToFiles :: Bool -> [String] -> FilePath -> IO [ FilePath ]
-dirToFiles _ _ "STDIN" = fmap lines $ hGetContents stdin
+dirToFiles _ _ "STDIN" = lines <$> getContents
 dirToFiles followSyms suffixes p = do
   isD <- doesDirectoryExist p
 #if MIN_VERSION_directory(1,3,0)
@@ -533,15 +535,14 @@
 #else
   isSymLink <- isSymbolicLink p
 #endif
-  case isD of
-    False -> return $ if matchingSuffix then [p] else []
-    True ->
-      if isSymLink && not followSyms
+  if isD
+    then if isSymLink && not followSyms
         then return []
         else do
           -- filter . .. and hidden files .*
           contents <- filter ((/=) '.' . head) `fmap` getDirectoryContents p
-          concat `fmap` (mapM (dirToFiles followSyms suffixes . (</>) p) contents)
+          concat `fmap` mapM (dirToFiles followSyms suffixes . (</>) p) contents
+    else return [p | matchingSuffix ]
   where matchingSuffix = any (`isSuffixOf` p) suffixes
 
 concatTokens :: [Token] -> String
@@ -558,6 +559,5 @@
 
 extractOperator :: [Token] -> (String, [Token])
 extractOperator ts@(Token "(" _ : _) =
-    (\(a, b) -> (foldr ((++) . tokenString) ")" a, tail' b)) $
-        break ((== ")") . tokenString) ts
+    foldr ((++) . tokenString) ")" *** tail $ break ((== ")") . tokenString) ts
 extractOperator _ = ("", [])
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -1,88 +1,180 @@
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE RecordWildCards #-}
 
 module Main (main) where
-import           Hasktags
+import Hasktags
 
-import           System.Environment
+import Control.Monad (unless)
+import Data.Monoid
+import Data.Set (Set, notMember, fromList, union)
+import Data.Version (showVersion)
+import Options.Applicative
+import Options.Applicative.Help.Pretty (text, line)
+import Paths_hasktags (version)
+import System.Directory (doesFileExist)
+import System.Environment (getArgs)
+import System.Exit (die)
+import System.IO (IOMode (AppendMode, WriteMode))
 
-import           Data.List
+import qualified Data.Set as Set
 
-import           Control.Monad
-import           System.Console.GetOpt
-import           System.Directory
-import           System.Exit
+data Options = Options
+  { _mode :: Mode
+  , _optionFiles :: [FilePath]
+  , _files :: [FilePath]
+  } deriving Show
 
-hsSuffixesDefault :: Mode
-hsSuffixesDefault =  HsSuffixes [ ".hs", ".lhs", ".hsc" ]
+options :: Parser Options
+options = Options
+    <$> mode
+    <*> many optionFiles
+    <*> files
+  where
+    mode :: Parser Mode
+    mode = Mode
+      <$> (ctags <|> etags <|> bothTags)
+      <*> extendedCtag
+      <*> appendTags
+      <*> outputRedirection
+      <*> cacheData
+      <*> followSymlinks
+      <*> suffixes
+      <*> absoluteTagPaths
+    ctags :: Parser Tags
+    ctags = flag Both Ctags $
+         long "ctags"
+      <> short 'c'
+      <> help "generate CTAGS file (ctags)"
 
-options :: [OptDescr Mode]
-options = [ Option "c" ["ctags"]
-            (NoArg CTags) "generate CTAGS file (ctags)"
-          , Option "e" ["etags"]
-            (NoArg ETags) "generate ETAGS file (etags)"
-          , Option "b" ["both"]
-            (NoArg BothTags) "generate both CTAGS and ETAGS"
-          , Option "a" ["append"]
-              (NoArg Append)
-            $ "append to existing CTAGS and/or ETAGS file(s). Afterward this "
-              ++ "file will no longer be sorted!"
-          , Option "o" ["output"]
-            (ReqArg OutRedir "")
-            "output to given file, instead of 'tags', '-' file is stdout"
-          , Option "f" ["file"]
-            (ReqArg OutRedir "")
-            "same as -o, but used as compatibility with ctags"
-          , Option "x" ["extendedctag"]
-            (NoArg ExtendedCtag) "Generate additional information in ctag file."
-          , Option "" ["cache"] (NoArg CacheFiles) "Cache file data."
-          , Option "L" ["follow-symlinks"] (NoArg FollowDirectorySymLinks) "follow symlinks when recursing directories"
-          , Option "S" ["suffixes"] (OptArg suffStr ".hs,.lhs") "list of hs suffixes including \".\""
-          , Option "R" ["tags-absolute"] (NoArg AbsolutePath) "make tags paths absolute. Useful when setting tags files in other directories"
-          , Option "h" ["help"] (NoArg Help) "This help"
-          ]
-  where suffStr Nothing  = hsSuffixesDefault
-        suffStr (Just s) = HsSuffixes $ strToSuffixes s
-        strToSuffixes = lines . map commaToEOL
-        commaToEOL ',' = '\n'
-        commaToEOL x   = x
+    etags :: Parser Tags
+    etags = flag Both Etags  $
+         long "etags"
+      <> short 'e'
+      <> help "generate ETAGS file (etags)"
 
+    bothTags :: Parser Tags
+    bothTags = flag' Both $
+         long "both"
+      <> short 'b'
+      <> help "generate both CTAGS and ETAGS (default)"
 
-main :: IO ()
-main = do
-        progName <- getProgName
-        args <- getArgs
-        let usageString =
-                   "Usage: " ++ progName
-                ++ " [OPTION...] [files or directories...]\n"
-                ++ "directories will be replaced by DIR/**/*.hs DIR/**/*.lhs\n"
-                ++ "Thus hasktags . tags all important files in the current\n"
-                ++ "directory.\n"
-                ++ "\n"
-                ++ "If directories are symlinks they will not be followed\n"
-                ++ "unless you pass -L.\n"
-                ++ "\n"
-                ++ "A special file \"STDIN\" will make hasktags read the line separated file\n"
-                ++ "list to be tagged from STDIN.\n"
-        let (modes, files_or_dirs_unexpanded, errs) = getOpt Permute options args
-#if debug
-        print $ "modes: " ++ (show modes)
-#endif
+    extendedCtag :: Parser Bool
+    extendedCtag = switch $
+         long "extendedctag"
+      <> short 'x'
+      <> showDefault
+      <> help "Generate additional information in ctag file."
 
-        files_or_dirs <- if AbsolutePath `elem` modes
-                             then sequence $ map canonicalizePath files_or_dirs_unexpanded
-                             else return files_or_dirs_unexpanded
-        let hsSuffixes = head $ [ s | (HsSuffixes s) <- modes ++ [hsSuffixesDefault] ]
+    appendTags :: Parser IOMode
+    appendTags = flag WriteMode AppendMode $
+         long "append"
+      <> short 'a'
+      <> showDefault
+      <> help "append to existing CTAGS and/or ETAGS file(s). Afterward this file will no longer be sorted!"
 
-        let followSymLinks = FollowDirectorySymLinks `elem` modes
+    outputRedirection :: Parser TagsFile
+    outputRedirection = strOption $
+         long "output"
+      <> long "file"
+      <> short 'o'
+      <> short 'f'
+      <> metavar "FILE|-"
+      <> value (TagsFile "tags" "TAGS")
+      <> showDefault
+      <> help "output to given file, instead of using the default names. '-' writes to stdout"
 
-        filenames
-          <- liftM (nub . concat) $ mapM (dirToFiles followSymLinks hsSuffixes) files_or_dirs
+    cacheData :: Parser Bool
+    cacheData = switch $
+         long "cache"
+      <> showDefault
+      <> help "cache file data"
 
-        when (errs /= [] || elem Help modes || files_or_dirs == [])
-             (do putStr $ unlines errs
-                 putStr $ usageInfo usageString options
-                 exitWith (ExitFailure 1))
+    followSymlinks :: Parser Bool
+    followSymlinks = switch $
+         long "follow-symlinks"
+      <> short 'L'
+      <> showDefault
+      <> help "follow symlinks when recursing directories"
 
-        when (filenames == []) $ putStrLn "warning: no files found!"
+    suffixes :: Parser [String]
+    suffixes = option auto $
+         long "suffixes"
+      <> short 'S'
+      <> value [".hs", ".lhs", ".hsc"]
+      <> showDefault
+      <> help "list of hs suffixes including \".\""
 
-        generate modes filenames
+    absoluteTagPaths :: Parser Bool
+    absoluteTagPaths = switch $
+         long "tags-absolute"
+      <> short 'R'
+      <> showDefault
+      <> help "make tags paths absolute. Useful when setting tags files in other directories"
+
+    files :: Parser [FilePath]
+    files = some $ argument str (metavar "<files or directories...>")
+
+    optionFiles :: Parser FilePath
+    optionFiles = strOption $
+         long "options"
+      <> metavar "FILE"
+      <> help "read additional options from file. The file should contain one option per line"
+
+type Argument = String
+
+parseArgs :: [Argument] -> Set FilePath -> IO Options
+parseArgs args parsedOptionFiles = do
+  parsedOptions@Options{..} <- handleParseResult $ execParserPure defaultPrefs opts args
+
+  let filesToParse = nonParsedFiles _optionFiles
+
+  if null filesToParse
+    then return parsedOptions
+    else do
+      mapM_ dieIfFilesDoesntExist filesToParse
+      newFlags <- parseArgsFromFiles filesToParse
+      parseArgs (args ++ newFlags) (fromList filesToParse `union` parsedOptionFiles)
+
+  where
+    dieIfFilesDoesntExist :: FilePath -> IO ()
+    dieIfFilesDoesntExist file = do
+          exists <- doesFileExist file
+          unless exists (die $ file ++ " from --options doesn't exist")
+
+    nonParsedFiles :: [FilePath] -> [FilePath]
+    nonParsedFiles = filter (`notMember` parsedOptionFiles)
+
+    parseArgsFromFiles :: [FilePath] -> IO [Argument]
+    parseArgsFromFiles fps = concat <$> mapM parseArgsFromFile fps
+      where
+        parseArgsFromFile :: FilePath -> IO [Argument]
+        parseArgsFromFile fp = lines <$> readFile fp
+
+    opts = info (options <**> versionFlag <**> helper) $
+         fullDesc
+      <> progDescDoc (Just $
+             replaceDirsInfo <> line <> line
+          <> symlinksInfo <> line <> line
+          <> stdinInfo)
+      where
+        versionFlag = infoOption (showVersion version) $
+             long "version"
+          <> help "show version"
+
+        replaceDirsInfo = text $ "directories will be replaced by DIR/**/*.hs DIR/**/*.lhs"
+          ++ "Thus hasktags . tags all important files in the current directory."
+        symlinksInfo = text $ "If directories are symlinks they will not be followed"
+          ++ "unless you pass -L."
+        stdinInfo = text $ "A special file \"STDIN\" will make hasktags read the line separated file"
+          ++ "list to be tagged from STDIN."
+
+main :: IO ()
+main = do
+  args <- getArgs
+  Options{..} <- parseArgs args Set.empty
+
+  generate _mode _files
+
+-- Local Variables:
+-- dante-target: "exe:hasktags"
+-- End:
diff --git a/src/Tags.hs b/src/Tags.hs
--- a/src/Tags.hs
+++ b/src/Tags.hs
@@ -7,8 +7,7 @@
 import           Control.Monad       (when)
 import           Data.Char           (isSpace)
 import           Data.Data           (Data, Typeable)
-import           Data.List           (sortBy)
-import           Data.List           (intercalate)
+import           Data.List           (sortBy, intercalate)
 import           Lens.Micro.Platform
 import           System.IO           (Handle, hPutStr, hPutStrLn)
 
@@ -148,8 +147,8 @@
                           else normalDump thing
 
 -- stuff for dealing with ctags output format
-writectagsfile :: Handle -> Bool -> [FileData] -> IO ()
-writectagsfile ctagsfile extended filedata = do
+writectagsfile :: Bool -> [FileData] -> Handle -> IO ()
+writectagsfile extended filedata ctagsfile = do
     let things = concatMap getfoundthings filedata
     when extended
          (do hPutStrLn
@@ -172,8 +171,8 @@
 
 -- stuff for dealing with etags output format
 
-writeetagsfile :: Handle -> [FileData] -> IO ()
-writeetagsfile etagsfile = mapM_ (hPutStr etagsfile . etagsDumpFileData)
+writeetagsfile :: [FileData] -> Handle -> IO ()
+writeetagsfile fileData etagsfile = mapM_ (hPutStr etagsfile . etagsDumpFileData) fileData
 
 etagsDumpFileData :: FileData -> String
 etagsDumpFileData (FileData filename things) =
diff --git a/testcases/16.hs b/testcases/16.hs
deleted file mode 100644
--- a/testcases/16.hs
+++ /dev/null
@@ -1,14 +0,0 @@
--- to be found T
--- to be found T
--- to be found t1
--- to be found t2
--- to be found t3
--- to be found t4
--- to be found t5
-data T = T {
-  t1 :: Int
-, t2 :: Int
-, t3 :: Int
-, t4 :: Int
-, t5 :: Int
-}
diff --git a/tests/Test.hs b/tests/Test.hs
--- a/tests/Test.hs
+++ b/tests/Test.hs
@@ -8,7 +8,7 @@
 import           System.Directory
 import           System.Exit
 
-import qualified Data.ByteString.Lazy.Char8 as BS
+import qualified Data.ByteString.Char8 as BS
 
 import           Test.HUnit
 
