packages feed

lentil-1.3.2.0: src/Lentil/Args.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Lentil.Query
-- Copyright   :  © 2015 Francesco Ariis
-- License     :  GPLv3 (see the LICENSE file)
--
-- Command line parsing
-----------------------------------------------------------------------------

module Lentil.Args where

import Lentil.Types
import Lentil.Query
import Lentil.Helpers

import Options.Applicative
import qualified Data.Char  as C
import qualified Data.Maybe as M


-----------
-- TYPES --
-----------

data LOptions = LOptions { loInExcl    :: ([FilePath], [FilePath]),
                           loFormat    :: Format,
                           loFilters   :: [LFilter],
                           loSort      :: [LSort],
                           loAlias     :: [Alias],
                           loFlagwords :: [FlagWord],
                           loOutFile   :: Maybe FilePath }

type LFilter = [Issue] -> [Issue]
type ChType  = [LFilter] -> [Issue] -> [Issue] -- AND or OR chain
type LSort   = [Issue] -> [Issue]


lOpts :: Parser LOptions
lOpts = LOptions <$> inexcls <*> format <*> filters <*>
                     issort <*> aliases <*> flagwords <*> outfile
    where inexcls = (,) <$> includes <*> many exclude
          filters = many $ foldl1 (<|>) [tag, notag, path,
                                         nopath, desc, nodesc]
          aliases   = fmap M.catMaybes (many alias)
          flagwords = many flagword


-------------
-- PARSERS --
-------------

-- argument "." gets replaced to "" (all files)
includes :: Parser [FilePath]
includes = some (argument str (metavar "PATH..."))

exclude :: Parser FilePath
exclude = strOption ( short 'x'      <>
                      metavar "PATH" <>
                      help "file/directory to exclude" )

format :: Parser Format
format = option (str >>= parseFormat)
                    ( short 'f'      <>
                      metavar "TYPE" <>
                      value Pretty   <>
                      help "output format (pretty, tagpop, csv, comp, xml)" )
    where
          parseFormat :: String -> ReadM Format
          parseFormat s = let asl = map forTup (enumFrom minBound)
                          in maybe (rerr s "unrecognised format")
                                   return (lookup s asl)

          forTup f      = (map C.toLower $ show f, f)


alias :: Parser (Maybe Alias)
alias = option (str >>= parseAlias)
                   ( short 'a'       <>
                     metavar "ALIAS" <>
                     help ("extension alias (e.g.: -a d" ++ aliasSign ++
                          "cpp)") )
    where
          parseAlias :: String -> ReadM (Maybe Alias)
          parseAlias s = return (aliasp s)


flagword :: Parser FlagWord
flagword =  fmap normaliseFlagword $
                strOption ( short 'w'          <>
                            metavar "FLAGWORD" <>
                            help "additional flagword (e.g.: -w Hack)" )


outfile :: Parser (Maybe FilePath)
outfile = optional $ strOption
                    ( long "output"  <>
                      metavar "FILE" <>
                      help "output file (if not present, prints to stdout)" )



issort :: Parser [LSort]
issort = pure []


-------------------
-- FILTER PARAMS --
-------------------

path :: Parser LFilter
path = option (filterFilepath <$> str)
                       ( short 'p'        <>
                         metavar "EXPR"   <>
                         help "filters for filepath matching EXPR" )

nopath :: Parser LFilter
nopath = option (negFilter . filterFilepath <$> str)
                         ( short 'P'        <>
                           metavar "EXPR"   <>
                           help "filters for filepath NOT matching EXPR" )

desc :: Parser LFilter
desc = option (filterDescription <$> str)
                       ( short 'd'        <>
                         metavar "EXPR"   <>
                         help "filters for description matching EXPR" )

nodesc :: Parser LFilter
nodesc = option (negFilter . filterDescription <$> str)
                       ( short 'D'        <>
                         metavar "EXPR"   <>
                         help "filters for description NOT matching EXPR" )

tag :: Parser LFilter
tag = option (filterTags <$> str)
                       ( short 't'       <>
                         metavar "EXPR"  <>
                         help "filter for tag matching EXPR" )

notag :: Parser LFilter
notag = option (negFilter . filterTags <$> str)
                       ( short 'T'       <>
                         metavar "EXPR"  <>
                         help "filter for tag NOT matching EXPR" )


-----------------
-- ANCILLARIES --
-----------------

rerr :: String -> String -> ReadM a
rerr var msg = readerError $ msg ++ " \"" ++ var ++ "\""