packages feed

git-fmt-0.3.0.3: app/Git/Fmt/Options.hs

{-|
Module      : Git.Fmt.Options
Description : Optparse utilities.

Copyright   : (c) Henry J. Wylde, 2015
License     : BSD3
Maintainer  : public@hjwylde.com

Optparse utilities.
-}

module Git.Fmt.Options (
    -- * Options
    Options(..), Chatty(..), Mode(..), Files(..),

    -- * Optparse
    gitFmtPrefs, gitFmtInfo, gitFmt,
) where

import Data.Char    (isDigit)
import Data.Version (showVersion)

import Options.Applicative
import Options.Applicative.Types (readerAsk)

import Git.Fmt.Version as This

-- | Options.
data Options = Options {
        optChatty    :: Chatty,
        optNull      :: Bool,
        optMode      :: Mode,
        optOperateOn :: Files,
        optThreads   :: Maybe Int,
        argPaths     :: [FilePath]
    }
    deriving (Eq, Show)

-- | Chattyness level.
data Chatty = Default | Quiet | Verbose
    deriving (Eq, Show)

-- | Run mode.
data Mode = Normal | DryRun
    deriving (Eq, Show)

-- | Operation files.
data Files = Tracked | Reference String
    deriving (Eq, Show)

-- | The default preferences.
--   Limits the help output to 100 columns.
gitFmtPrefs :: ParserPrefs
gitFmtPrefs = prefs $ columns 100

-- | An optparse parser of a git-fmt command.
gitFmtInfo :: ParserInfo Options
gitFmtInfo = info (infoOptions <*> gitFmt) fullDesc
    where
        infoOptions = helper <*> version <*> numericVersion
        helper = abortOption ShowHelpText $ mconcat [
            short 'h', hidden,
            help "Show this help text"
            ]
        version = infoOption ("Version " ++ showVersion This.version) $ mconcat [
            long "version", short 'V', hidden,
            help "Show this binary's version"
            ]
        numericVersion = infoOption (showVersion This.version) $ mconcat [
            long "numeric-version", hidden,
            help "Show this binary's version (without the prefix)"
            ]

-- | An options parser.
gitFmt :: Parser Options
gitFmt = Options
    <$> (
            flag' Quiet (mconcat [
            long "quiet", short 'q', hidden,
            help "Be quiet"
            ])
        <|> flag Default Verbose (mconcat [
            long "verbose", short 'v', hidden,
            help "Be verbose"
            ])
        )
    <*> switch (mconcat [
        long "null", short '0',
        help "Input files are delimited by a null terminator instead of white space"
        ])
    <*> modeOption (mconcat [
        long "mode", short 'm', metavar "MODE",
        value Normal, showDefaultWith $ const "normal",
        help "Specify the mode as either `normal' or `dry-run'"
        ])
    <*> (
            flag' Tracked (mconcat [
            long "operate-on-tracked",
            help "Operate on all tracked files (i.e., `git ls-files')"
            ])
        <|> Reference <$> strOption (mconcat [
            long "operate-on", metavar "REF",
            value "head", showDefault,
            help "Operate on all files in the reference (i.e., `git diff REF --name-only')"
            ])
        )
    <*> natOption (mconcat [
        long "threads", metavar "INT",
        value Nothing, showDefaultWith $ const "number of processors",
        help "Specify the number of threads to use"
        ])
    <*> many (strArgument $ mconcat [
        metavar "-- PATHS..."
        ])
    where
        natOption   = option $ readerAsk >>= \opt -> if all isDigit opt
            then return $ Just (read opt :: Int)
            else readerError $ "not a natural number `" ++ opt ++ "'"
        modeOption  = option $ readerAsk >>= \opt -> case opt of
            "normal"    -> return Normal
            "dry-run"   -> return DryRun
            _           -> readerError $ "unrecognised mode `" ++ opt ++ "'"