packages feed

hpasteit-0.3.1: ProgOpts.hs

module ProgOpts
    ( ProgOpts(..)
    , parseOpts
    ) where

import Control.Monad
import Data.Char
import Data.List
import Data.Monoid

import Network.URI
import Options.Applicative
import Safe

data ProgOpts = PasteOpts { optTitle     :: Maybe String
                          , optAuthor    :: Maybe String
                          , optLanguage  :: Maybe String
                          , optChannel   :: String
                          , optDebug     :: Bool
                          , optFile      :: FilePath
                          }
              | ViewOpts  { optPasteID   :: Integer }

optParser :: Parser ProgOpts
optParser = foldr (<|>) empty
    [ subparser $ mconcat

        [ command "paste" $ info (helper <*> optPasteParser)
                          $ infoMod <> progDesc "paste something"

        , command "view"  $ info (helper <*> optViewParser)
                          $ infoMod <> progDesc "view a paste"
        ]

    , optPasteParser
    ]

optViewParser :: Parser ProgOpts
optViewParser = ViewOpts
        <$> argument parsePasteID (mconcat [ metavar "PASTEID"
                                           , help pasteIDHelp
                                           ])
  where
    pasteIDHelp = "The URL or the ID number of the paste you want to view"

    parsePasteID :: String -> Maybe Integer
    parsePasteID input = readMay input <|> parsePasteUri input

    parsePasteUri :: String -> Maybe Integer
    parsePasteUri input = do
        URI { uriAuthority = uri_authority
            , uriPath      = '/':uri_path  } <- parseURI input'

        URIAuth { uriRegName = "hpaste.org" } <- uri_authority

        paste_id <- readMay uri_path
        guard (paste_id > 0)
        return paste_id
      where
        input' = if "http://" `isPrefixOf` input
                    then input
                    else "http://" ++ input

optPasteParser :: Parser ProgOpts
optPasteParser = PasteOpts
        <$> nullOption (mconcat [ reader  (Right . Just)
                                , value   Nothing
                                , showDefaultWith $ \_ ->
                                    "inferred by file name else (no title)"
                                , short   't'
                                , long    "title"
                                , metavar "TITLE"
                                , help    "The title of the paste"
                                ])

        <*> nullOption (mconcat [ reader  (Right . Just)
                                , value   Nothing
                                , showDefaultWith $ \_ ->
                                    "defined by $HPASTE_AUTHOR else Anonymous"
                                , short   'a'
                                , long    "author"
                                , metavar "AUTHOR"
                                , help    "The author of the paste"
                                ])

        <*> nullOption (mconcat [ reader  (fmap Just . readLanguage . map toLower)
                                , long    "language"
                                , short   'l'
                                , metavar "LANGUAGE"
                                , value   Nothing
                                , showDefaultWith $ \_ ->
                                    "inferred by file name else Haskell"
                                , help    "The language of the paste"
                                ])

        <*> nullOption (mconcat [ reader  (readChannel . map toLower)
                                , long    "channel"
                                , short   'c'
                                , metavar "CHANNEL"
                                , value   ""
                                , showDefault
                                , help    "The IRC channel to notify"
                                ])

        <*> switch (mconcat [ value False
                            , long "debug"
                            , short 'd'
                            , showDefault
                            , help "Just print debug info"
                            ])

        <*> argument Just (mconcat [ metavar "FILE"
                                   , value   "-"
                                   , showDefault
                                   , help  $ "The path of the file to paste "
                                          ++ "(use - for STDIN)"
                                   ])

  where
    -- The string arguments of these functions are (assumed to be) lower-case.

    readLanguage :: String -> Either ParseError String
    readLanguage lang
      | lang `elem` langs = Right lang
      | otherwise         = Left (ErrorMsg err_msg)
      where
        -- Not an exhaustive list.
        langs = ["haskell","agda","ocaml","lisp","erlang","literatehaskell"
                ,"c","cpp"
                ]

        err_msg = "Invalid language. See hpaste.org for a full list of "
               ++ "supported languages."

    readChannel :: String -> Either ParseError String
    readChannel chan = case trimBangs chan `elemIndex` map trimBangs chans of
        -- Let the user input a channel without the leading #s but
        -- fix the input so that it is a valid channel.
        Just idx -> Right (chans !! idx)

        Nothing  -> Left (ErrorMsg err_msg)
      where
        trimBangs = dropWhile (=='#')

        -- Not an exhaustive list.
        chans = ["#haskell"]

        err_msg = "Invalid IRC channel. See hpaste.org for a full list of "
               ++ "valid IRC channels."

infoMod :: InfoMod ProgOpts
infoMod = mconcat [ fullDesc
                  , header "hpasteit - command-line client for hpaste.org"
                  ]

parseOpts :: IO ProgOpts
parseOpts = customExecParser (prefs showHelpOnError)
          $ info (helper <*> optParser)
          $ mconcat [ infoMod
                    , footer $ "Append --help after a command to see detailed "
                            ++ "usage information\n"
                            ++ "By default, the command is 'paste'\n"
                            ++ "Define $HPASTE_AUTHOR to set a default author."
                    ]