module GramLab.Commands ( Command , CommandName , Help , CommandSpec (..) , module System.Console.GetOpt , defaultMain ) where import Text.PrettyPrint(renderStyle,render,nest,vcat,hsep,style,Mode(..),mode,text,(<>),($$),($+$),(<+>)) import System.Console.GetOpt import System.Environment import System.IO (stderr) import System.IO.UTF8 (hPutStr) import qualified Data.List as List type Command a = ([a] -> [String] -> IO ()) type CLArgName = String type CommandName = String type Help = String data CommandSpec a = CommandSpec (Command a) Help [OptDescr a] [CLArgName] defaultMain commands header = do args <- getArgs let theUsage = usage commands header case args of [] -> theUsage [] command:opts -> case List.lookup command commands of Nothing -> theUsage ["Invalid command: " ++ command] Just spec -> runCommand theUsage spec opts runCommand theUsage (CommandSpec command help optDesc argnames) args = case getOpt Permute optDesc args of (o,n,[] ) -> command o n (_,_,errs) -> theUsage errs usage commands header errs = hPutStr stderr . render $ vcat (List.map text errs) $$ usageMsg commands header usageMsg commands header = text header $+$ (vcat (List.map commandUsage commands)) commandUsage (name , CommandSpec command help optionDesc args) = text name <> text ":" $$ (nest 10 (text help)) $$ (text name <+> text "[OPTION...]" <+> hsep (map text args)) <+> (nest 10 (text $ usageInfo "" optionDesc))