packages feed

omnifmt-0.2.1.0: app/Omnifmt/Options.hs

{-|
Module      : Omnifmt.Options
Description : Optparse utilities.

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

Optparse utilities.
-}

module Omnifmt.Options (
    -- * Options
    Options(..), Chatty(..), Mode(..),

    -- * Optparse
    omnifmtPrefs, omnifmtInfo, omnifmt,
) where

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

import Omnifmt.Config  as Config
import Omnifmt.Version as This

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


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

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

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

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

-- | An optparse parser of a omnifmt command.
omnifmtInfo :: ParserInfo Options
omnifmtInfo = info (infoOptions <*> omnifmt) (fullDesc <> progDesc')
    where
        infoOptions     = helper <*> version <*> numericVersion
        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)"
            ]

        progDesc' = progDesc $ "Formats the paths given by applying the rules found in the root `" ++ Config.defaultFileName ++ "'"

-- | An options parser.
omnifmt :: Parser Options
omnifmt = 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",
        completeWith ["normal", "dry-run", "diff"],
        help "Specify the mode as either `normal', `dry-run' or `diff'"
        ])
    <*> 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...",
        action "file"
        ])
    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
            "diff"      -> return Diff
            _           -> readerError $ "unrecognised mode `" ++ opt ++ "'"