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}