packages feed

hasktags 0.70.1 → 0.71.0

raw patch · 7 files changed

+260/−181 lines, 7 filesdep +containersdep +optparse-applicativedep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: containers, optparse-applicative

Dependency ranges changed: base

API changes (from Hackage documentation)

- Hasktags: AbsolutePath :: Mode
- Hasktags: Append :: Mode
- Hasktags: BothTags :: Mode
- Hasktags: CTags :: Mode
- Hasktags: CacheFiles :: Mode
- Hasktags: ETags :: Mode
- Hasktags: ExtendedCtag :: Mode
- Hasktags: FollowDirectorySymLinks :: Mode
- Hasktags: Help :: Mode
- Hasktags: HsSuffixes :: [String] -> Mode
- Hasktags: OutRedir :: String -> Mode
- Hasktags: findWithCache :: Bool -> FileName -> IO FileData
- Hasktags: getMode :: [Mode] -> Mode
- Hasktags: instance GHC.Classes.Eq Hasktags.Mode
- Hasktags: instance GHC.Classes.Ord Hasktags.Mode
+ Hasktags: Both :: Tags
+ Hasktags: Ctags :: Tags
+ Hasktags: Etags :: Tags
+ Hasktags: Mode :: Tags -> Bool -> IOMode -> TagsFile -> Bool -> Bool -> [String] -> Bool -> Mode
+ Hasktags: TagsFile :: FilePath -> FilePath -> TagsFile
+ Hasktags: [_absoluteTagPaths] :: Mode -> Bool
+ Hasktags: [_appendTags] :: Mode -> IOMode
+ Hasktags: [_cacheData] :: Mode -> Bool
+ Hasktags: [_ctagsFile] :: TagsFile -> FilePath
+ Hasktags: [_etagsFile] :: TagsFile -> FilePath
+ Hasktags: [_extendedCtag] :: Mode -> Bool
+ Hasktags: [_followSymlinks] :: Mode -> Bool
+ Hasktags: [_outputFile] :: Mode -> TagsFile
+ Hasktags: [_suffixes] :: Mode -> [String]
+ Hasktags: [_tags] :: Mode -> Tags
+ Hasktags: data Tags
+ Hasktags: data TagsFile
+ Hasktags: instance Data.String.IsString Hasktags.TagsFile
+ Hasktags: instance GHC.Show.Show Hasktags.Tags
+ Hasktags: instance GHC.Show.Show Hasktags.TagsFile
- Hasktags: generate :: [Mode] -> [FileName] -> IO ()
+ Hasktags: generate :: Mode -> [FilePath] -> IO ()
- Hasktags: getOutFile :: String -> IOMode -> [Mode] -> IO Handle
+ Hasktags: getOutFile :: String -> IOMode -> IO Handle

Files

README.md view
@@ -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.
hasktags.cabal view
@@ -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 
src/Hasktags.hs view
@@ -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 _ = ("", [])
src/Main.hs view
@@ -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:
src/Tags.hs view
@@ -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) =
− testcases/16.hs
@@ -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-}
tests/Test.hs view
@@ -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