    -- | Provide help for plugins
    module Lambdabot.Plugin.Core.Help (helpPlugin) where

    import Lambdabot.Command
    import Lambdabot.Message (Message)
    import Lambdabot.Module
    import Lambdabot.Monad
    import Lambdabot.Plugin
    import Lambdabot.Util

    import Control.Monad.Reader

    helpPlugin :: Module ()
    helpPlugin :: Module ()
    helpPlugin = Module ()
    forall st. Module st
    newModule
        { moduleCmds = return
            [ (command "help")
                { help = say "help <command>. Ask for help for <command>. Try 'list' for all commands"
                , process = \String
    args -> (forall a. Message a => a -> Cmd (ModuleT () LB) ())
    -> Cmd (ModuleT () LB) ()
    forall (m :: * -> *) t.
    Monad m =>
    (forall a. Message a => a -> Cmd m t) -> Cmd m t
    withMsg ((forall a. Message a => a -> Cmd (ModuleT () LB) ())
     -> Cmd (ModuleT () LB) ())
    -> (forall a. Message a => a -> Cmd (ModuleT () LB) ())
    -> Cmd (ModuleT () LB) ()
    forall a b. (a -> b) -> a -> b
    $ \a
    msg -> do
                    tgt <- Cmd (ModuleT () LB) Nick
    forall (m :: * -> *). Monad m => Cmd m Nick
    getTarget
                    lb (doHelp msg tgt args) >>= mapM_ say
                }
            ]
        }

    moduleHelp :: (Monad m, Message a) =>
                  Command m -> a -> Nick -> String -> m [String]
    moduleHelp :: forall (m :: * -> *) a.
    (Monad m, Message a) =>
    Command m -> a -> Nick -> String -> m [String]
    moduleHelp Command m
    theCmd a
    msg Nick
    tgt String
    cmd =
        Cmd m () -> a -> Nick -> String -> m [String]
    forall (m :: * -> *) a t.
    (Monad m, Message a) =>
    Cmd m t -> a -> Nick -> String -> m [String]
    execCmd (Command m -> Cmd m ()
    forall (m :: * -> *). Command m -> Cmd m ()
    help Command m
    theCmd) a
    msg Nick
    tgt String
    cmd

    --
    -- If a target is a command, find the associated help, otherwise if it's
    -- a module, return a list of commands that module implements.
    --
    doHelp :: Message t => t -> Nick -> [Char] -> LB [[Char]]
    doHelp :: forall t. Message t => t -> Nick -> String -> LB [String]
    doHelp t
    msg Nick
    tgt [] = t -> Nick -> String -> LB [String]
    forall t. Message t => t -> Nick -> String -> LB [String]
    doHelp t
    msg Nick
    tgt String
    "help"
    doHelp t
    msg Nick
    tgt String
    rest =
        String
    -> LB [String]
    -> (forall st. Command (ModuleT st LB) -> ModuleT st LB [String])
    -> LB [String]
    forall a.
    String
    -> LB a
    -> (forall st. Command (ModuleT st LB) -> ModuleT st LB a)
    -> LB a
    withCommand String
    arg                  -- see if it is a command
            (String
    -> LB [String]
    -> (forall st. ModuleT st LB [String])
    -> LB [String]
    forall a. String -> LB a -> (forall st. ModuleT st LB a) -> LB a
    inModuleNamed String
    arg           -- else maybe it's a module name
                (t -> Nick -> String -> LB [String]
    forall t. Message t => t -> Nick -> String -> LB [String]
    doHelp t
    msg Nick
    tgt String
    "help")             -- else give up
                (do -- its a module
                    cmds <- Module st -> ModuleT st LB [Command (ModuleT st LB)]
    forall st. Module st -> ModuleT st LB [Command (ModuleT st LB)]
    moduleCmds (Module st -> ModuleT st LB [Command (ModuleT st LB)])
    -> ModuleT st LB (Module st)
    -> ModuleT st LB [Command (ModuleT st LB)]
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (ModuleInfo st -> Module st) -> ModuleT st LB (Module st)
    forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
    asks ModuleInfo st -> Module st
    forall st. ModuleInfo st -> Module st
    theModule
                    let ss = [Command (ModuleT st LB)]
    cmds [Command (ModuleT st LB)]
    -> (Command (ModuleT st LB) -> [String]) -> [String]
    forall a b. [a] -> (a -> [b]) -> [b]
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Command (ModuleT st LB) -> [String]
    forall (m :: * -> *). Command m -> [String]
    cmdNames
                    let s | [String] -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null [String]
    ss   = String
    arg String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " is a module."
                          | Bool
    otherwise = String
    arg String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " provides: " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ [String] -> String
    forall a. Show a => [a] -> String
    showClean [String]
    ss
                    return [s]))

            -- so it's a valid command, try to find its help
            (\Command (ModuleT st LB)
    theCmd -> Command (ModuleT st LB)
    -> t -> Nick -> String -> ModuleT st LB [String]
    forall (m :: * -> *) a.
    (Monad m, Message a) =>
    Command m -> a -> Nick -> String -> m [String]
    moduleHelp Command (ModuleT st LB)
    theCmd t
    msg Nick
    tgt String
    arg)

        where (String
    arg:[String]
    _) = String -> [String]
    words String
    rest