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 +1/−1
- hasktags.cabal +5/−3
- src/Hasktags.hs +84/−84
- src/Main.hs +164/−72
- src/Tags.hs +5/−6
- testcases/16.hs +0/−14
- tests/Test.hs +1/−1
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