{-# LANGUAGE CPP #-}
module GetOpt.Declarative.Util (mkUsageInfo, mapOptDescr) where

import           Prelude ()
import           Test.Hspec.Core.Compat

import           System.Console.GetOpt

import           Test.Hspec.Core.Util

modifyHelp :: (String -> String) -> OptDescr a -> OptDescr a
modifyHelp :: (String -> String) -> OptDescr a -> OptDescr a
modifyHelp String -> String
modify (Option String
s [String]
n ArgDescr a
a String
help) = String -> [String] -> ArgDescr a -> String -> OptDescr a
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
s [String]
n ArgDescr a
a (String -> String
modify String
help)

mkUsageInfo :: String -> [OptDescr a] -> String
mkUsageInfo :: String -> [OptDescr a] -> String
mkUsageInfo String
title = String -> [OptDescr a] -> String
forall a. String -> [OptDescr a] -> String
usageInfo String
title ([OptDescr a] -> String)
-> ([OptDescr a] -> [OptDescr a]) -> [OptDescr a] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [OptDescr a] -> [OptDescr a]
forall a. [OptDescr a] -> [OptDescr a]
addLineBreaksForHelp ([OptDescr a] -> [OptDescr a])
-> ([OptDescr a] -> [OptDescr a]) -> [OptDescr a] -> [OptDescr a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [OptDescr a] -> [OptDescr a]
forall a. [OptDescr a] -> [OptDescr a]
condenseNoOptions

addLineBreaksForHelp :: [OptDescr a] -> [OptDescr a]
addLineBreaksForHelp :: [OptDescr a] -> [OptDescr a]
addLineBreaksForHelp [OptDescr a]
options = (OptDescr a -> OptDescr a) -> [OptDescr a] -> [OptDescr a]
forall a b. (a -> b) -> [a] -> [b]
map ((String -> String) -> OptDescr a -> OptDescr a
forall a. (String -> String) -> OptDescr a -> OptDescr a
modifyHelp String -> String
addLineBreaks) [OptDescr a]
options
  where
    withoutHelpWidth :: [OptDescr a] -> Int
withoutHelpWidth = String -> Int
maxLength (String -> Int) -> ([OptDescr a] -> String) -> [OptDescr a] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [OptDescr a] -> String
forall a. String -> [OptDescr a] -> String
usageInfo String
"" ([OptDescr a] -> String)
-> ([OptDescr a] -> [OptDescr a]) -> [OptDescr a] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (OptDescr a -> OptDescr a) -> [OptDescr a] -> [OptDescr a]
forall a b. (a -> b) -> [a] -> [b]
map OptDescr a -> OptDescr a
forall a. OptDescr a -> OptDescr a
removeHelp
    helpWidth :: Int
helpWidth = Int
80 Int -> Int -> Int
forall a. Num a => a -> a -> a
- [OptDescr a] -> Int
forall a. [OptDescr a] -> Int
withoutHelpWidth [OptDescr a]
options

    addLineBreaks :: String -> String
addLineBreaks = [String] -> String
unlines ([String] -> String) -> (String -> [String]) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String -> [String]
lineBreaksAt Int
helpWidth

    maxLength :: String -> Int
maxLength = [Int] -> Int
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ([Int] -> Int) -> (String -> [Int]) -> String -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Int) -> [String] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([String] -> [Int]) -> (String -> [String]) -> String -> [Int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines
    removeHelp :: OptDescr a -> OptDescr a
removeHelp = (String -> String) -> OptDescr a -> OptDescr a
forall a. (String -> String) -> OptDescr a -> OptDescr a
modifyHelp (String -> String -> String
forall a b. a -> b -> a
const String
"")

condenseNoOptions :: [OptDescr a] -> [OptDescr a]
condenseNoOptions :: [OptDescr a] -> [OptDescr a]
condenseNoOptions [OptDescr a]
options = case [OptDescr a]
options of
  Option String
"" [String
optionA] ArgDescr a
arg String
help : Option String
"" [String
optionB] ArgDescr a
_ String
_ : [OptDescr a]
ys | String
optionB String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== (String
"no-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
optionA) ->
    String -> [String] -> ArgDescr a -> String -> OptDescr a
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"[no-]" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
optionA] ArgDescr a
arg String
help OptDescr a -> [OptDescr a] -> [OptDescr a]
forall a. a -> [a] -> [a]
: [OptDescr a] -> [OptDescr a]
forall a. [OptDescr a] -> [OptDescr a]
condenseNoOptions [OptDescr a]
ys
  OptDescr a
x : [OptDescr a]
xs -> OptDescr a
x OptDescr a -> [OptDescr a] -> [OptDescr a]
forall a. a -> [a] -> [a]
: [OptDescr a] -> [OptDescr a]
forall a. [OptDescr a] -> [OptDescr a]
condenseNoOptions [OptDescr a]
xs
  [] -> []

mapOptDescr :: (a -> b) -> OptDescr a -> OptDescr b
#if MIN_VERSION_base(4,7,0)
mapOptDescr :: (a -> b) -> OptDescr a -> OptDescr b
mapOptDescr = (a -> b) -> OptDescr a -> OptDescr b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
#else
mapOptDescr f opt = case opt of
  Option short long arg help -> Option short long (mapArgDescr f arg) help

mapArgDescr :: (a -> b) -> ArgDescr a -> ArgDescr b
mapArgDescr f arg = case arg of
  NoArg a -> NoArg (f a)
  ReqArg parse name -> ReqArg (fmap f parse) name
  OptArg parse name -> OptArg (fmap f parse) name
#endif