1 %  Copyright (C) 2002,2003,2005 David Roundy
    2 %
    3 %  This program is free software; you can redistribute it and/or modify
    4 %  it under the terms of the GNU General Public License as published by
    5 %  the Free Software Foundation; either version 2, or (at your option)
    6 %  any later version.
    7 %
    8 %  This program is distributed in the hope that it will be useful,
    9 %  but WITHOUT ANY WARRANTY; without even the implied warranty of
   10 %  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11 %  GNU General Public License for more details.
   12 %
   13 %  You should have received a copy of the GNU General Public License
   14 %  along with this program; see the file COPYING.  If not, write to
   15 %  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   16 %  Boston, MA 02110-1301, USA.
   17 
   18 \begin{code}
   19 module Darcs.Commands ( CommandControl( Command_data, Hidden_command, Group_name ),
   20                        DarcsCommand( DarcsCommand, command_name,
   21                                      command_help, command_description,
   22                                      command_basic_options, command_advanced_options,
   23                                      command_command,
   24                                      command_prereq,
   25                                      command_extra_arg_help,
   26                                      command_extra_args,
   27                                      command_argdefaults,
   28                                      command_get_arg_possibilities,
   29                                      SuperCommand,
   30                                      command_sub_commands ),
   31                        command_alias, command_stub,
   32                        command_options, command_alloptions,
   33                        disambiguate_commands, CommandArgs(..),
   34                        get_command_help, get_command_mini_help,
   35                        get_subcommands,
   36                        usage, subusage, chomp_newline,
   37                        extract_commands,
   38                        super_name,
   39                        nodefaults,
   40                        loggers,
   41                      ) where
   42 
   43 import System.Console.GetOpt( OptDescr, usageInfo )
   44 
   45 import Data.List ( sort, isPrefixOf )
   46 import Darcs.Arguments ( DarcsFlag, DarcsOption, disable, help,
   47                          any_verbosity, posthook_cmd, posthook_prompt,
   48                          prehook_cmd, prehook_prompt, option_from_darcsoption )
   49 import Darcs.RepoPath ( AbsolutePath, rootDirectory )
   50 import Darcs.Utils ( putStrLnError )
   51 import Printer ( Doc, putDocLn )
   52 \end{code}
   53 
   54 The general format of a darcs command is
   55 \begin{verbatim}
   56 % darcs COMMAND OPTIONS ARGUMENTS ...
   57 \end{verbatim}
   58 Here \verb|COMMAND| is a command such as \verb|add| or \verb|record|, which of
   59 course may have one or more arguments.  Options have the form
   60 \verb!--option! or \verb!-o!, while arguments vary from command to
   61 command.  There are many options which are common to a number of different
   62 commands, which will be summarized here.
   63 
   64 If you wish, you may use any unambiguous beginning of a command name as a
   65 shortcut: for \verb!darcs record!, you could type \verb!darcs recor! or
   66 \verb!darcs rec!, but not \verb!darcs re! since that could be confused with
   67 \verb!darcs replace!, \verb!darcs revert! and \verb!darcs remove!.
   68 
   69 In some cases, \verb|COMMAND| actually consists of two words, a
   70 super-command and a subcommand.  For example, the ``display the
   71 manifest'' command has the form \verb|darcs query manifest|.
   72 
   73 \paragraph{Command overview}
   74 
   75 Not all commands modify the ``patches'' of your repository (that
   76 is, the named patches which other users can pull); some commands only
   77 affect the copy of the source tree you're working on (your ``working
   78 directory''), and some affect both. This table summarizes what you should
   79 expect from each one and will hopefully serve as guide when you're having
   80 doubts about which command to use.
   81 
   82 \begin{center}
   83 \footnotetext[1]{But it affects the repository and working directory targeted
   84   by the push}
   85 \footnotetext[2]{As for the other end, see apply}
   86 \begin{tabular}{|c|c|c|}
   87 \hline
   88 affects & patches & working directory\\
   89 \hline
   90 record & yes & no\\
   91 \hline
   92 unrecord & yes & no\\
   93 \hline
   94 rollback & yes & yes\\
   95 \hline
   96 revert & no & yes\\
   97 \hline
   98 unrevert & no & yes\\
   99 \hline
  100 pull & yes & yes\\
  101 \hline
  102 obliterate & yes & yes\\
  103 \hline
  104 apply & yes & yes\\
  105 \hline
  106 push\footnote{But it affects the repository and working directory targeted by
  107 the push} & no & no\\
  108 \hline
  109 send\footnote{As for the other end, see apply} & no & no\\
  110 \hline
  111 put\footnote{Creates a new repository} & no & no\\
  112 \hline
  113 \end{tabular}
  114 \end{center}
  115 
  116 \begin{code}
  117 extract_commands, extract_hidden_commands :: [CommandControl] -> [DarcsCommand]
  118 extract_commands cs = concatMap (\x -> case x of { Command_data cmd_d -> [cmd_d]; _ -> []}) cs
  119 extract_hidden_commands cs = concatMap (\x -> case x of { Hidden_command cmd_d -> [cmd_d]; _ -> []}) cs
  120 \end{code}
  121 
  122 \input{Darcs/Arguments.lhs}
  123 
  124 \begin{code}
  125 data CommandControl = Command_data DarcsCommand
  126                     | Hidden_command DarcsCommand
  127                     | Group_name String
  128 
  129 data DarcsCommand =
  130     DarcsCommand {command_name, command_help, command_description :: String,
  131                   command_extra_args :: Int,
  132                   command_extra_arg_help :: [String],
  133                   command_command :: [DarcsFlag] -> [String] -> IO (),
  134                   command_prereq :: [DarcsFlag] -> IO (Either String ()),
  135                   command_get_arg_possibilities :: IO [String],
  136                   command_argdefaults :: [DarcsFlag] -> AbsolutePath -> [String] -> IO [String],
  137                   command_basic_options :: [DarcsOption],
  138                   command_advanced_options :: [DarcsOption]}
  139   | SuperCommand {command_name, command_help, command_description :: String,
  140                   command_prereq :: [DarcsFlag] -> IO (Either String ()),
  141                   command_sub_commands :: [CommandControl]}
  142 
  143 command_alloptions :: DarcsCommand -> ([DarcsOption], [DarcsOption])
  144 command_alloptions DarcsCommand { command_basic_options = opts1
  145                                 , command_advanced_options = opts2 }
  146     = (opts1 ++ [disable, help],
  147        any_verbosity ++ opts2 ++
  148                 [posthook_cmd, posthook_prompt
  149                 ,prehook_cmd, prehook_prompt])
  150 
  151 --  Supercommands cannot be disabled.
  152 command_alloptions SuperCommand { } = ([help],[])
  153 
  154 --  Obtain options suitable as input to
  155 --  System.Console.Getopt, including the --disable option (which is
  156 --  not listed explicitly in the DarcsCommand definitions).
  157 command_options :: AbsolutePath -> DarcsCommand -> ([OptDescr DarcsFlag], [OptDescr DarcsFlag])
  158 command_options cwd c = (convert basic, convert advanced)
  159  where (basic, advanced) = command_alloptions c
  160        convert = concatMap (option_from_darcsoption cwd)
  161 
  162 nodefaults :: [DarcsFlag] -> AbsolutePath -> [String] -> IO [String]
  163 nodefaults _ _ xs = return xs
  164 
  165 get_subcommands :: DarcsCommand -> [CommandControl]
  166 get_subcommands c@(SuperCommand {}) = command_sub_commands c
  167 get_subcommands _ = []
  168 
  169 command_alias :: String -> DarcsCommand -> DarcsCommand
  170 command_alias n c =
  171   c { command_name = n
  172     , command_description = "Alias for `darcs " ++ command_name c ++ "'."
  173     , command_help = "The `darcs " ++ n ++ "' command is an alias for " ++
  174                      "`darcs " ++ command_name c ++ "'.\n" ++
  175                      command_help c
  176     }
  177 
  178 command_stub :: String -> String -> String -> DarcsCommand -> DarcsCommand
  179 command_stub n h d c =
  180   c { command_name = n
  181     , command_help = h
  182     , command_description = d
  183     , command_command = \_ _ -> putStr h
  184     }
  185 
  186 usage :: [CommandControl] -> String
  187 usage cs = "Usage: darcs COMMAND ...\n\nCommands:\n" ++
  188            usage_helper cs ++ "\n" ++
  189            "Use 'darcs COMMAND --help' for help on a single command.\n" ++
  190            "Use 'darcs --version' to see the darcs version number.\n" ++
  191            "Use 'darcs --exact-version' to get the exact version of this darcs instance.\n" ++
  192            "Use 'darcs help patterns' for help on patch matching.\n" ++
  193            "Use 'darcs help environment' for help on environment variables.\n" ++
  194            "\n" ++
  195            "Check bug reports at http://bugs.darcs.net/\n"
  196 
  197 subusage :: DarcsCommand -> String
  198 subusage super =
  199     (usageInfo
  200      ("Usage: darcs "++command_name super++" SUBCOMMAND ... " ++
  201       "\n\n"++ command_description super++
  202       "\n\nSubcommands:\n" ++ usage_helper (get_subcommands super) ++ "\nOptions:")
  203      (option_from_darcsoption rootDirectory help))
  204     ++ "\n" ++ command_help super
  205 
  206 usage_helper :: [CommandControl] -> String
  207 usage_helper [] = ""
  208 usage_helper (Hidden_command _:cs) = usage_helper cs
  209 usage_helper ((Command_data c):cs) = "  "++pad_spaces (command_name c) 15 ++
  210                       chomp_newline (command_description c)++"\n"++usage_helper cs
  211 usage_helper ((Group_name n):cs) = "\n" ++ n ++ "\n" ++ usage_helper cs
  212 
  213 chomp_newline :: String -> String
  214 chomp_newline "" = ""
  215 chomp_newline s = if last s == '\n' then init s else s
  216 
  217 pad_spaces :: String -> Int -> String
  218 pad_spaces s n = s ++ replicate (n - length s) ' '
  219 
  220 super_name :: Maybe DarcsCommand -> String
  221 super_name Nothing  = ""
  222 super_name (Just x) = command_name x ++ " "
  223 
  224 get_command_mini_help :: Maybe DarcsCommand -> DarcsCommand -> String
  225 get_command_mini_help msuper cmd =
  226   get_command_help_core msuper cmd ++
  227   "\n\nSee darcs help "
  228   ++ (maybe "" (\c -> command_name c ++ " ") msuper)
  229   ++ command_name cmd ++ " for details."
  230 
  231 get_command_help :: Maybe DarcsCommand -> DarcsCommand -> String
  232 get_command_help msuper cmd =
  233     unlines (reverse basicR)
  234     ++ (if null advanced then ""
  235         else "\nAdvanced options:\n" ++ unlines (reverse advancedR))
  236     ++ "\n" ++ command_help cmd
  237     where -- we could just call usageInfo twice, but then the advanced
  238           -- options might not line up with the basic ones (no short flags)
  239           (advancedR, basicR) =
  240              splitAt (length advanced) $ reverse $ lines combinedUsage
  241           combinedUsage = usageInfo
  242             (get_command_help_core msuper cmd ++ subcommands ++ "\n\nOptions:")
  243             (basic ++ advanced)
  244           (basic, advanced) = command_options rootDirectory cmd
  245           subcommands =
  246             case msuper of
  247             Nothing -> case get_subcommands cmd of
  248                        [] -> []
  249                        s  -> "\n\nSubcommands:\n" ++ (usage_helper s)
  250             -- we don't want to list subcommands if we're already specifying them
  251             Just _  -> ""
  252 
  253 get_command_help_core :: Maybe DarcsCommand -> DarcsCommand -> String
  254 get_command_help_core msuper cmd =
  255     "Usage: darcs "++super_name msuper++command_name cmd++
  256     " [OPTION]... " ++ unwords args_help ++
  257     "\n"++ command_description cmd
  258     where args_help = case cmd of
  259             (DarcsCommand _ _ _ _ _ _ _ _ _ _ _) ->
  260               command_extra_arg_help cmd
  261             _ -> []
  262 
  263 data CommandArgs = CommandOnly      DarcsCommand
  264                  | SuperCommandOnly DarcsCommand
  265                  | SuperCommandSub  DarcsCommand DarcsCommand
  266 
  267 -- Parses a darcs command line with potentially abbreviated commands
  268 disambiguate_commands :: [CommandControl] -> String -> [String]
  269                       -> Either String (CommandArgs, [String])
  270 disambiguate_commands allcs cmd args =
  271  do c <- extract cmd allcs
  272     case (get_subcommands c, args) of
  273       ([], _)         -> return (CommandOnly c, args)
  274       (_ ,[])         -> return (SuperCommandOnly c, args)
  275       (subcs, (a:as)) -> case extract a subcs of
  276                          Left _   -> return (SuperCommandOnly c, args)
  277                          Right sc -> return (SuperCommandSub c sc, as)
  278 
  279 extract :: String -> [CommandControl] -> Either String DarcsCommand
  280 extract cmd cs =
  281  case [ c | c <- extract_commands cs, cmd `isPrefixOf` command_name c ] ++
  282       [ h | h <- extract_hidden_commands cs,    cmd == command_name h ] of
  283    []  -> Left $ "No such command '" ++ cmd ++ "'\n"
  284    [c] -> Right c
  285    cs' -> Left $ "Ambiguous command...\n\n" ++
  286                     "The command '"++cmd++"' could mean one of:\n" ++
  287                     unwords (sort $ map command_name cs')
  288 
  289 -- | Output functions equivalent to (putStrLn, hPutStrLn stderr, putDocLn)
  290 loggers :: [DarcsFlag] -> ( String -> IO ()
  291                           , String -> IO ()
  292                           , Doc -> IO ())
  293 loggers _ = (putStrLn, putStrLnError, putDocLn)
  294 \end{code}