module Darcs.UI.Usage
( usageInfo
, formatOptions
, getCommandHelp
, getCommandMiniHelp
, usage
, subusage
) where
import Prelude ()
import Darcs.Prelude
import Data.Functor.Compose
import System.Console.GetOpt( OptDescr(..), ArgDescr(..) )
import Darcs.UI.Options.All ( stdCmdActions )
import Darcs.UI.Commands
( CommandControl(..)
, DarcsCommand(..)
, wrappedCommandName
, wrappedCommandDescription
, getSubcommands
, commandAlloptions
)
import Darcs.UI.Options ( DarcsOptDescr, odesc )
import Darcs.Util.Printer
( Doc, text, vsep, ($$), vcat, hsep
, renderString
)
formatOptions :: [DarcsOptDescr a] -> [String]
formatOptions optDescrs = table
where (ss,ls,ds) = (unzip3 . concatMap fmtOpt) optDescrs
table = zipWith3 paste
shortPadded
(zipWith (++) (map (unlines' . init) ls)
(sameLen $ map last ls))
ds
shortPadded = sameLen ss
prePad = replicate (3 + length (head shortPadded)) ' '
unlines' = concatMap (\x -> x ++ ",\n" ++ prePad)
paste x y z = " " ++ x ++ " " ++ y ++ " " ++ z
sameLen xs = flushLeft ((maximum . map length) xs) xs
flushLeft n xs = [ take n (x ++ repeat ' ') | x <- xs ]
usageInfo :: String
-> [DarcsOptDescr a]
-> String
usageInfo header optDescrs = unlines (header:formatOptions optDescrs)
fmtOpt :: DarcsOptDescr a -> [(String,[String],String)]
fmtOpt (Compose (Option sos los ad descr)) =
case lines descr of
[] -> [(sosFmt,losFmt,"")]
(d:ds) -> (sosFmt,losFmt,d) : [ ("",[],d') | d' <- ds ]
where endBy _ [] = ""
endBy ch [x] = x ++ [ch]
endBy ch (x:xs) = x ++ ch:' ':endBy ch xs
sosFmt = endBy ',' (map fmtShort sos)
losFmt = map (fmtLong ad) los
fmtShort :: Char -> String
fmtShort so = "-" ++ [so]
fmtLong :: ArgDescr a -> String -> String
fmtLong (NoArg _ ) lo = "--" ++ lo
fmtLong (ReqArg _ ad) lo = "--" ++ lo ++ "=" ++ ad
fmtLong (OptArg _ ad) lo = "--" ++ lo ++ "[=" ++ ad ++ "]"
usage :: [CommandControl] -> Doc
usage cs = vsep
[ "Usage: darcs COMMAND ..."
, "Commands:" $$ usageHelper cs
, vcat
[ "Use 'darcs COMMAND --help' for help on a single command."
, "Use 'darcs --version' to see the darcs version number."
, "Use 'darcs --exact-version' to see a detailed darcs version."
, "Use 'darcs help patterns' for help on patch matching."
, "Use 'darcs help environment' for help on environment variables."
, "Use 'darcs help manpage' to display help in the manpage format."
, "Use 'darcs help markdown' to display help in the markdown format."
]
, "Check bug reports at http://bugs.darcs.net/"
]
subusage :: DarcsCommand pf -> String
subusage super = renderString $ vsep
[ header
, subcommandsHelp
, vcat $ map text $ formatOptions $ odesc stdCmdActions
, text $ commandHelp super
]
where
usageHelp = hsep $ map text
[ "Usage:"
, commandProgramName super
, commandName super
, "SUBCOMMAND ..."
]
header = usageHelp $$ text (commandDescription super)
subcommandsHelp = case getSubcommands super of
[] -> mempty
subcommands -> usageHelper subcommands
usageHelper :: [CommandControl] -> Doc
usageHelper xs = vsep (groups xs)
where
groups [] = []
groups (HiddenCommand _:cs) = groups cs
groups (GroupName n:cs) =
mempty : case groups cs of
[] -> [text n]
(g:gs) -> (text n $$ g) : gs
groups (CommandData c:cs) =
case groups cs of
[] -> [cmdHelp c]
(g:gs) -> (cmdHelp c $$ g) : gs
cmdHelp c = text $ " " ++
padSpaces maxwidth (wrappedCommandName c) ++
wrappedCommandDescription c
padSpaces n s = s ++ replicate (n length s) ' '
maxwidth = maximum $ 15 : (map cwidth xs)
cwidth (CommandData c) = length (wrappedCommandName c) + 2
cwidth _ = 0
getCommandMiniHelp :: Maybe (DarcsCommand pf1) -> DarcsCommand pf2 -> String
getCommandMiniHelp msuper cmd = renderString $ vsep
[ getCommandHelpCore msuper cmd
, hsep $ map text
[ "See"
, commandProgramName cmd
, "help"
, maybe "" ((++ " ") . commandName) msuper ++ commandName cmd
, "for details."
]
]
getCommandHelp :: Maybe (DarcsCommand pf1) -> DarcsCommand pf2 -> Doc
getCommandHelp msuper cmd = vsep
[ getCommandHelpCore msuper cmd
, subcommandsHelp
, withHeading "Options:" basicOptionsHelp
, withHeading "Advanced options:" advancedOptionsHelp
, text $ commandHelp cmd
]
where
withHeading _ [] = mempty
withHeading h ls = vcat (text h : map text ls)
(basic, advanced) = commandAlloptions cmd
(basicOptionsHelp, advancedOptionsHelp) =
splitAt (length basic) $ formatOptions (basic ++ advanced)
subcommandsHelp =
case msuper of
Nothing ->
case getSubcommands cmd of
[] -> mempty
subcommands -> usageHelper subcommands
Just _ -> mempty
getCommandHelpCore :: Maybe (DarcsCommand pf1) -> DarcsCommand pf2 -> Doc
getCommandHelpCore msuper cmd = vcat
[ hsep $
[ "Usage:"
, text $ commandProgramName cmd
, maybe mempty (text . commandName) msuper
, text $ commandName cmd
, "[OPTION]..."
]
++ args_help
, text $ commandDescription cmd
]
where
args_help = case cmd of
(DarcsCommand {}) -> map text $ commandExtraArgHelp cmd
_ -> []