    {-# LANGUAGE DefaultSignatures #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE GADTs #-}
    {-# LANGUAGE InstanceSigs #-}
    {-# LANGUAGE LambdaCase #-}
    {-# LANGUAGE OverlappingInstances  #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE TypeSynonymInstances #-}

    {-# OPTIONS_GHC -fno-warn-deprecated-flags #-}

    module WithCli.Argument where

    import           Data.Orphans ()
    import           Prelude ()
    import           Prelude.Compat

    import           Data.List
    import           Data.Proxy
    import           Text.Read

    -- | 'Argument' is a typeclass for things that can be parsed as atomic values from
    --   single command line arguments, e.g. strings (and filenames) and numbers.
    --
    --   Occasionally you might want to declare your own instance for additional
    --   type safety and for providing a more informative command argument type.
    --   Here's an example:

    -- ### Start "docs/CustomOption.hs" "module CustomOption where\n\n" Haddock ###

    -- |
    -- >  {-# LANGUAGE DeriveDataTypeable #-}
    -- >
    -- >  import WithCli
    -- >
    -- >  data File = File FilePath
    -- >    deriving (Show, Typeable)
    -- >
    -- >  instance Argument File where
    -- >    argumentType Proxy = "custom-file-type"
    -- >    parseArgument f = Just (File f)
    -- >
    -- >  instance HasArguments File where
    -- >    argumentsParser = atomicArgumentsParser
    -- >
    -- >  main :: IO ()
    -- >  main = withCli run
    -- >
    -- >  run :: File -> IO ()
    -- >  run = print

    -- ### End ###

    -- | And this is how the above program behaves:

    -- ### Start "docs/CustomOption.shell-protocol" "" Haddock ###

    -- |
    -- >  $ program --help
    -- >  program [OPTIONS] custom-file-type
    -- >    -h  --help  show help and exit
    -- >  $ program some/file
    -- >  File "some/file"

    -- ### End ###

    class Argument a where
      argumentType :: Proxy a -> String
      parseArgument :: String -> Maybe a

    instance Argument String where
      argumentType :: Proxy String -> String
    argumentType Proxy String
    Proxy = String
    "STRING"
      parseArgument :: String -> Maybe String
    parseArgument = String -> Maybe String
    forall a. a -> Maybe a
    Just

    instance Argument Int where
      argumentType :: Proxy Int -> String
    argumentType Proxy Int
    _ = String
    "INTEGER"
      parseArgument :: String -> Maybe Int
    parseArgument = String -> Maybe Int
    forall a. Read a => String -> Maybe a
    readMaybe

    instance Argument Integer where
      argumentType :: Proxy Integer -> String
    argumentType Proxy Integer
    _ = String
    "INTEGER"
      parseArgument :: String -> Maybe Integer
    parseArgument = String -> Maybe Integer
    forall a. Read a => String -> Maybe a
    readMaybe

    instance Argument Float where
      argumentType :: Proxy Float -> String
    argumentType Proxy Float
    _ = String
    "NUMBER"
      parseArgument :: String -> Maybe Float
    parseArgument = String -> Maybe Float
    forall n. (RealFloat n, Read n) => String -> Maybe n
    readFloat

    instance Argument Double where
      argumentType :: Proxy Double -> String
    argumentType Proxy Double
    _ = String
    "NUMBER"
      parseArgument :: String -> Maybe Double
    parseArgument = String -> Maybe Double
    forall n. (RealFloat n, Read n) => String -> Maybe n
    readFloat

    readFloat :: (RealFloat n, Read n) => String -> Maybe n
    readFloat :: forall n. (RealFloat n, Read n) => String -> Maybe n
    readFloat String
    s = case String -> Maybe n
    forall a. Read a => String -> Maybe a
    readMaybe String
    s of
      Just n
    n -> n -> Maybe n
    forall a. a -> Maybe a
    Just n
    n
      Maybe n
    Nothing
        | String
    "." String -> String -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` String
    s -> String -> Maybe n
    forall a. Read a => String -> Maybe a
    readMaybe (String
    "0" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    s)
        | Bool
    otherwise -> Maybe n
    forall a. Maybe a
    Nothing