module UI.Command.Doc (
helpCmd, manCmd,
help, man
)where
import Data.Default
import Data.Char (toUpper)
import System.Locale (defaultTimeLocale)
import Data.Time.Format (formatTime)
import Data.Time.Clock (getCurrentTime)
import Text.Printf (printf)
import Control.Monad.Trans (liftIO)
import UI.Command.App (App, appArgs)
import UI.Command.Application
import UI.Command.Command
import UI.Command.Render
internalCmds :: [Command ()]
internalCmds = [helpCmd, manCmd]
helpCmd = def {
cmdName = "help",
cmdShortDesc = "Display help for a specific cmdcommand"
}
help app = do
args <- appArgs
liftIO $ mapM_ putStr $ longHelp app args
longHelp :: (Default opts, Default config) => Application opts config -> [String] -> [String]
longHelp app [] =
[appShortDesc app ++ "\n"] ++
["Usage: " ++ (appName app) ++ " [--version] [--help] command [args]\n\n"] ++
[indent 2 (appLongDesc app), "\n"] ++
map (categoryHelp app) (appCategories app) ++
[internalHelp app] ++
["\nPlease report bugs to <" ++ appBugEmail app ++ ">\n"]
longHelp app (command:_) = contextHelp app command m
where m = filter (\x -> cmdName x == command) (appCmds app)
categoryHelp :: (Default opts, Default config) => Application opts config -> String -> String
categoryHelp app c = c ++ ":\n" ++ unlines (map itemHelp items) ++ "\n"
where
items = filter (\x -> cmdCategory x == c) (appCmds app)
internalHelp :: (Default opts, Default config) => Application opts config -> String
internalHelp app = unlines $ "Miscellaneous:" : map itemHelp internalCmds
itemHelp i = printf " %-14s%s" (cmdName i) (cmdShortDesc i)
contextHelp :: (Default opts, Default config) => Application opts config -> [Char] -> [Command config] -> [String]
contextHelp app command [] = longHelp app [] ++ contextError
where contextError = ["\n*** \"" ++ command ++ "\": Unknown command.\n"]
contextHelp app command (item:_) = synopsis ++ usage ++ description ++ examples
where usage = ["Usage: " ++ appName app ++ " " ++ command ++ hasOpts command ++ "\n"]
hasOpts "help" = " command"
hasOpts _ = " [options]"
synopsis = [(appName app) ++ " " ++ command ++ ": " ++ cmdSynopsis item ++ "\n"]
description = case (cmdShortDesc item) of
"" -> []
_ -> ["\n" ++ indent 2 (cmdShortDesc item)]
examples = case (cmdExamples item) of
[] -> []
_ -> ["\nExamples:"] ++
flip map (cmdExamples item) (\(desc,opts) ->
"\n " ++ desc ++ ":\n " ++ (appName app) ++ " " ++ command ++
" " ++ opts ++ "\n")
manCmd :: (Default config) => Command config
manCmd = def {
cmdName = "man",
cmdShortDesc = "Generate Unix man page for specific cmdcommand"
}
man app = do
args <- appArgs
currentTime <- liftIO $ getCurrentTime
let dateStamp = formatTime defaultTimeLocale "%B %Y" currentTime
liftIO $ putStrLn . concat $ longMan app dateStamp args
manSH :: String -> String
manSH s = "\n.SH " ++ s ++ "\n\n"
headerMan :: (Default opts, Default config) => Application opts config -> String -> [String]
headerMan app dateStamp = [unwords [".TH", u, "1", quote dateStamp, quote (appName app), project, "\n"]]
where
u = map toUpper (appName app)
project | appProject app == def = ""
| otherwise = quote $ appProject app
synopsisMan :: (Default opts, Default config) => Application opts config -> String -> [Command config] -> [String]
synopsisMan app _ [] =
[manSH "SYNOPSIS", ".B ", appName app, "\n.RI COMMAND\n[\n.I OPTIONS\n]\n.I filename ...\n\n"]
synopsisMan app command (item:_) =
[manSH "SYNOPSIS", ".B ", appName app, "\n.RI ", command, "\n", hasOpts command, "\n"]
where hasOpts "help" = ".I <cmdcommand>\n"
hasOpts "man" = ".I <cmdcommand>\n"
hasOpts _ = "[\n.I OPTIONS\n]\n"
authorsMan :: (Default opts, Default config) => Application opts config -> String -> [String]
authorsMan app command = manSH "AUTHORS" : a ++ g ++ e
where
n = appName app
a | appAuthors app == [] = []
| otherwise = [n ++ " was written by ", englishList $ appAuthors app, "\n\n"]
g = ["This manual page was autogenerated by\n.B " ++ n ++ " man" ++ space command ++ ".\n\n"]
e | appBugEmail app == "" = []
| otherwise = ["Please report bugs to <" ++ appBugEmail app ++ ">\n"]
space "" = ""
space c = ' ':c
descMan :: String -> [String]
descMan desc = [manSH "DESCRIPTION", desc, "\n"]
longMan :: (Default opts, Default config) => Application opts config -> String -> [String] -> [String]
longMan app dateStamp [] =
headerMan app dateStamp ++
[manSH "NAME"] ++
[appName app, " \\- ", appShortDesc app, "\n\n"] ++
synopsisMan app "COMMAND" [] ++
descMan (".B " ++ appName app ++ "\n" ++ appLongDesc app) ++
map (categoryMan app) (appCategories app) ++
authorsMan app "" ++
seeAlsoMan app
longMan app dateStamp (command:_) = contextMan app dateStamp command m
where
m = filter (\x -> cmdName x == command) (appCmds app)
seeAlsoMan :: (Default opts, Default config) => Application opts config -> [String]
seeAlsoMan app
| appSeeAlso app == def = []
| otherwise = [manSH "SEE ALSO" ++ ".PP\n"] ++
map (\x -> "\\fB"++x++"\\fR(1)\n") (appSeeAlso app)
categoryMan :: (Default opts, Default config) => Application opts config -> String -> String
categoryMan app c = manSH (map toUpper c) ++ concat (map itemMan items) ++ "\n"
where items = filter (\x -> cmdCategory x == c) (appCmds app)
itemMan i = printf ".IP %s\n%s\n" (cmdName i) (cmdShortDesc i)
contextMan :: (Default opts, Default config) => Application opts config -> String -> [Char] -> [Command config] -> [String]
contextMan app dateStamp _ [] = longMan app dateStamp []
contextMan app dateStamp command i@(item:_) =
headerMan app dateStamp ++
synopsisMan app command i ++
descMan (cmdSynopsis item) ++
description ++
examples ++
authorsMan app command
where
description | cmdShortDesc item == "" = []
| otherwise = ["\n" ++ cmdShortDesc item]
examples | cmdExamples item == [] = []
| otherwise = manSH "EXAMPLES" :
flip map (cmdExamples item) (\(desc, opts) ->
".PP\n" ++ desc ++ ":\n.PP\n.RS\n\\f(CW" ++
appName app ++ " " ++ command ++ " " ++
opts ++ "\\fP\n.RE\n")