registry-options-0.1.0.0: src/Data/Registry/Options/Help.hs
-- | Support for storing help messages associated to options
-- and for displaying a full help message
module Data.Registry.Options.Help where
import Data.Registry.Options.OptionDescription hiding (help)
import Protolude hiding (Any)
-- | This data type contains optional fields describing
-- either a full command or just a single option
-- A command refers to a list of command fields but can also contain subcommands
data Help = Help
{ -- | name of a command
helpCommandName :: Maybe Text,
-- | name of the parent command
helpParentCommandName :: Maybe Text,
-- | short description of a command
helpCommandShortDescription :: Maybe Text,
-- | long description of a command
helpCommandLongDescription :: Maybe Text,
-- | list of fields for a given command. Each option description contains some help text
helpCommandFields :: [OptionDescription],
-- | list of subcommands
helpCommands :: [Help],
-- | True if the command name is the default subcommand when not mentioned explicitly
helpDefaultSubcommand :: Bool
}
deriving (Eq, Show)
-- | Function updating the help
type HelpUpdate = Help -> Help
-- | Create a Help from a list of updates
makeHelp :: [HelpUpdate] -> Help
makeHelp = foldl (\r u -> u r) mempty
-- | Empty Help description
noHelp :: Help
noHelp = Help mempty mempty mempty mempty mempty mempty False
-- | Create a Help value with a short command description
shortDescription :: Text -> HelpUpdate
shortDescription t h = h {helpCommandShortDescription = Just t}
-- | Create a Help value with a long command description
longDescription :: Text -> HelpUpdate
longDescription t h = h {helpCommandLongDescription = Just t}
-- | Create a Help value with a command name, a long and a short description
commandHelp :: Text -> Text -> Text -> Help
commandHelp n s l = Help (Just n) Nothing (Just s) (Just l) mempty mempty False
-- | Create a Help value with no command name
noCommandName :: Help -> Help
noCommandName h = h {helpCommandName = Nothing}
-- | Set the current subcommand as the default one
defaultSubcommand :: Help -> Help
defaultSubcommand h = h {helpDefaultSubcommand = True}
instance Semigroup Help where
Help n1 p1 s1 l1 fs1 cs1 d1 <> Help n2 p2 s2 l2 fs2 cs2 d2 = do
let subcommands = (\c -> c {helpParentCommandName = n1 <|> n2}) <$> (cs1 <> cs2)
Help (n1 <|> n2) (p1 <|> p2) (s1 <|> s2) (l1 <|> l2) (fs1 <> fs2) subcommands (d1 || d2)
instance Monoid Help where
mempty = noHelp
mappend = (<>)
-- | Create a Help description for the alternative of 2 different help descriptions
-- This function is used for collecting the helps of 2 parsers when using the @<|>@ operator
--
-- - two commands end-up being the subcommands of the alternative
-- - a command alternated with some fields becomes a subcommand
alt :: Help -> Help -> Help
alt h1@(Help (Just _) _ _ _ _ _ _) h2@(Help (Just _) _ _ _ _ _ _) = noHelp {helpCommands = [h1, h2]}
alt (Help Nothing _ _ _ fs1 cs1 _) h2@(Help (Just _) _ _ _ _ _ _) = noHelp {helpCommandFields = fs1, helpCommands = cs1 <> [h2]}
alt h1@(Help (Just _) _ _ _ _ _ _) (Help Nothing _ _ _ fs2 cs2 _) = noHelp {helpCommandFields = fs2, helpCommands = h1 : cs2}
alt (Help Nothing _ _ _ fs1 cs1 _) (Help Nothing _ _ _ fs2 cs2 _) = noHelp {helpCommandFields = fs1 <> fs2, helpCommands = cs1 <> cs2}
-- | Create a Help value from the description of a simple option
fromCliOption :: OptionDescription -> Help
fromCliOption o = noHelp {helpCommandFields = [o]}