% Copyright (C) 2002-2004 David Roundy % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation; either version 2, or (at your option) % any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program; if not, write to the Free Software Foundation, % Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. \begin{code} module DarcsArguments ( DarcsFlag( .. ), isa, fix_flag, fix_filepath, unfix_filepaths, DarcsOption( .. ), option_from_darcsoption, help, verbose, list_options, list_files, quiet, any_verbosity, notest, test, working_repo_dir, leave_test_dir, possibly_remote_repo_dir, get_repodir, list_registered_files, list_unregistered_files, author, get_author, patchname_option, distname_option, logfile, rmlogfile, from_opt, target, cc, get_cc, output, recursive, edit_file, askdeps, ignoretimes, lookforadds, ask_long_comment, sign, verify, edit_description, reponame, tagname, no_resolve_conflicts, reply, use_external_merge, want_external_merge, no_deps, nocompress, compress, uncompress, uncompress_nocompress, options_latex, noskip_boring, allow_caseonly, applyas, human_readable, changes_reverse, changes_format, match_one_context, match_one_nontag, send_to_context, pipe_interactive, all_interactive, gui_pipe_interactive, gui_interactive, all_gui_pipe_interactive, all_gui_interactive, summary, unified, tokens, checkpoint, partial, partial_check, diffflags, unidiff, xmloutput, force_replace, dry_run, match_one, match_several, match_range, happy_forwarding, set_default, (///), ) where import System.Console.GetOpt import Directory hiding ( getCurrentDirectory ) import List import System import Maybe ( catMaybes ) import Monad ( liftM, mplus ) import IO ( hFlush, stdout ) import Char ( isDigit ) import Autoconf ( path_separator ) import DarcsUtils ( catchall, ortryrunning, withCurrentDirectory ) import DarcsURL ( is_relative ) import RepoPrefs ( boring_file_filter, get_preflist ) import FileName ( fn2fp, fp2fn, norm_path ) import PatchMatchData ( patch_match ) import DarcsFlags ( DarcsFlag(..) ) \end{code} \begin{code} get_content :: DarcsFlag -> Maybe String get_content (SignAs s) = Just s get_content (SignSSL s) = Just s get_content (Toks s) = Just s get_content (Target s) = Just s get_content (Output s) = Just s get_content (Author s) = Just s get_content (PatchName s) = Just s get_content (DistName s) = Just s get_content (Verify s) = Just s get_content (VerifySSL s) = Just s get_content (ApplyAs s) = Just s get_content (RepoName s) = Just s get_content (TagName s) = Just s get_content (DiffFlags s) = Just s get_content (ExternalMerge s) = Just s get_content (RepoDir s) = Just s get_content _ = Nothing isa :: DarcsFlag -> (String -> DarcsFlag) -> Bool a `isa` b = case get_content a of Nothing -> False Just s -> a == b s data DarcsOption = DarcsArgOption [Char] [String] (String->DarcsFlag) String String | DarcsNoArgOption [Char] [String] DarcsFlag String | DarcsMultipleChoiceOption [DarcsOption] option_from_darcsoption :: DarcsOption -> [OptDescr DarcsFlag] option_from_darcsoption (DarcsNoArgOption a b c h) = [Option a b (NoArg c) h] option_from_darcsoption (DarcsArgOption a b c n h) = [Option a b (ReqArg c n) h] option_from_darcsoption (DarcsMultipleChoiceOption os) = concat $ map option_from_darcsoption os \end{code} \begin{code} fix_flag :: FilePath -> DarcsFlag -> DarcsFlag fix_flag fix (Output s) = Output $ fix_maybe_absolute fix s fix_flag fix (Verify s) = Verify $ fix_maybe_absolute fix s fix_flag fix (LogFile s) = LogFile $ fix_maybe_absolute fix s fix_flag fix (VerifySSL s) = VerifySSL $ fix_maybe_absolute fix s fix_flag _ (Context "") = Context "" fix_flag fix (Context s) = Context $ fix_maybe_absolute fix s fix_flag _ f = f fix_maybe_absolute :: FilePath -> FilePath -> FilePath fix_maybe_absolute fix pat = fma $ map cleanup pat where fma p@('/':_) = p fma p = fix /// p cleanup '\\' | path_separator == '\\' = '/' cleanup c = c fix_filepath :: [DarcsFlag] -> FilePath -> FilePath fix_filepath [] f = f fix_filepath (FixFilePath fix:_) f = fix_maybe_absolute fix f fix_filepath (_:fs) f = fix_filepath fs f unfix_filepaths :: [DarcsFlag] -> [FilePath] -> [FilePath] unfix_filepaths [] f = f unfix_filepaths (FixFilePath fix:_) f = drop_paths fix f unfix_filepaths (_:fs) f = unfix_filepaths fs f (///) :: FilePath -> FilePath -> FilePath ""///a = do_norm a a///b = do_norm $ a ++ "/" ++ b do_norm :: FilePath -> FilePath do_norm f = fn2fp $ norm_path $ fp2fn f drop_paths :: String -> [String] -> [String] drop_paths fix ps = catMaybes $ map drop_path ps where drop_path ('.':'/':p) = drop_path $ dropWhile (=='/') p drop_path p = if take (length fix) p == fix then Just $ dropWhile (=='/') $ drop (length fix) p else if is_relative p then Nothing else Just p \end{code} \begin{code} list_options :: DarcsOption list_options = DarcsNoArgOption [] ["list-options"] ListOptions "simply list the command's arguments" verbose :: DarcsOption quiet :: DarcsOption any_verbosity :: DarcsOption reponame :: DarcsOption tagname :: DarcsOption no_deps :: DarcsOption checkpoint :: DarcsOption partial :: DarcsOption partial_check :: DarcsOption tokens :: DarcsOption working_repo_dir :: DarcsOption possibly_remote_repo_dir :: DarcsOption gui_interactive, pipe_interactive, gui_pipe_interactive, all_gui_interactive, all_gui_pipe_interactive, all_interactive, all_patches, interactive, pipe, human_readable, diffflags, allow_caseonly, noskip_boring, ask_long_comment, match_one_nontag, changes_reverse, changes_format, match_one_context, happy_forwarding, send_to_context, use_external_merge, target, cc, no_resolve_conflicts, reply, xmloutput, distname_option, patchname_option, edit_description, output, unidiff, unified, summary, compress, uncompress, uncompress_nocompress, nocompress, author, askdeps, lookforadds, ignoretimes, test, notest, help, force_replace, match_one, match_range, match_several, dry_run, #ifdef HAVEWX gui, #endif logfile, rmlogfile, leave_test_dir, from_opt, set_default :: DarcsOption recursive :: String -> DarcsOption sign, applyas, verify :: DarcsOption \end{code} \section{Common options to darcs commands} \subsection{Help} Every {\tt COMMAND} accepts \verb!--help! as an argument, which tells it to provide a bit of help. Among other things, this help always provides an accurate listing of the options available with that command, and is guaranteed never to be out of sync with the version of darcs you actually have installed (unlike this manual, which could be for an entirely different version of darcs). \begin{verbatim} % darcs COMMAND --help \end{verbatim} \begin{code} help = DarcsNoArgOption ['h'] ["help"] Help "shows brief description of command and its arguments" \end{code} \subsection{Verbose} Most commands also accept the \verb!--verbose! option, which tells darcs to provide additional output. The amount of verbosity varies from command to command. \begin{code} verbose = DarcsMultipleChoiceOption [DarcsNoArgOption ['v'] ["verbose"] Verbose "give verbose output", DarcsNoArgOption [] ["standard-verbosity"] NormalVerbosity "don't give verbose output"] quiet = DarcsMultipleChoiceOption [DarcsNoArgOption ['q'] ["quiet"] Quiet "suppress informational output", DarcsNoArgOption [] ["standard-verbosity"] NormalVerbosity "normal informational output"] any_verbosity = DarcsMultipleChoiceOption [DarcsNoArgOption ['v'] ["verbose"] Verbose "give verbose output", DarcsNoArgOption ['q'] ["quiet"] Quiet "suppress informational output", DarcsNoArgOption [] ["standard-verbosity"] NormalVerbosity "neither verbose nor quiet output"] \end{code} \subsection{Repository directory} Another common option is the \verb!--repodir! option, which allows you to specify the directory of the repository in which to perform the command. This option is used with commands, such as whatsnew, that ordinarily would be performed within a repository directory, and allows you to use those commands without actually being in the repo directory when calling the command. This is useful when running darcs as a pipe, as might be the case when running apply from a mailer. \begin{code} working_repo_dir = DarcsArgOption [] ["repodir"] WorkDir "DIRECTORY" "specify the repository directory in which to run" possibly_remote_repo_dir = DarcsArgOption [] ["repo"] RepoDir "URL" "specify the repository URL" get_repodir :: [DarcsFlag] -> String get_repodir [] = "." get_repodir (WorkDir r:_) = r get_repodir (RepoDir r:_) = r get_repodir (_:fs) = get_repodir fs \end{code} \input{Match.lhs} \input{PatchMatch.lhs} \begin{code} patchname_option = DarcsArgOption ['m'] ["patch-name"] PatchName "PATCHNAME" "name of patch" send_to_context = DarcsArgOption [] ["context"] Context "FILENAME" "send to context stored in FILENAME" match_one_context = DarcsMultipleChoiceOption [DarcsArgOption [] ["to-match"] mp "PATTERN" "select changes up to a patch matching PATTERN", DarcsArgOption [] ["to-patch"] OnePatch "REGEXP" "select changes up to a patch matching REGEXP", DarcsArgOption [] ["tag"] OneTag "REGEXP" "select tag matching REGEXP", DarcsArgOption [] ["context"] Context "FILENAME" "version specified by the context in FILENAME" ] where mp s = OnePattern (patch_match s) match_one = DarcsMultipleChoiceOption [DarcsArgOption [] ["match"] mp "PATTERN" "select patch matching PATTERN", DarcsArgOption ['p'] ["patch"] OnePatch "REGEXP" "select patch matching REGEXP", DarcsArgOption ['t'] ["tag"] OneTag "REGEXP" "select tag matching REGEXP"] where mp s = OnePattern (patch_match s) match_one_nontag = DarcsMultipleChoiceOption [DarcsArgOption [] ["match"] mp "PATTERN" "select patch matching PATTERN", DarcsArgOption ['p'] ["patch"] OnePatch "REGEXP" "select patch matching REGEXP"] where mp s = OnePattern (patch_match s) match_several = DarcsMultipleChoiceOption [DarcsArgOption [] ["matches"] mp "PATTERN" "select patches matching PATTERN", DarcsArgOption ['p'] ["patches"] SeveralPatch "REGEXP" "select patches matching REGEXP", DarcsArgOption ['t'] ["tags"] OneTag "REGEXP" "select tags matching REGEXP"] where mp s = SeveralPattern (patch_match s) match_range = DarcsMultipleChoiceOption [DarcsArgOption [] ["to-match"] uptop "PATTERN" "select changes up to a patch matching PATTERN", DarcsArgOption [] ["to-patch"] UpToPatch "REGEXP" "select changes up to a patch matching REGEXP", DarcsArgOption [] ["to-tag"] UpToTag "REGEXP" "select changes up to a tag matching REGEXP", DarcsArgOption [] ["from-match"] fromp "PATTERN" "select changes starting with a patch matching PATTERN", DarcsArgOption [] ["from-patch"] AfterPatch "REGEXP" "select changes starting with a patch matching REGEXP", DarcsArgOption [] ["from-tag"] AfterTag "REGEXP" "select changes starting with a tag matching REGEXP", DarcsArgOption [] ["match"] onep "PATTERN" "select a single patch matching PATTERN", DarcsArgOption ['p'] ["patch"] OnePatch "REGEXP" "select a single patch matching REGEXP", DarcsArgOption [] ["last"] lastn "NUMBER" "select the last NUMBER patches"] where uptop s = UpToPattern (patch_match s) fromp s = AfterPattern (patch_match s) onep s = OnePattern (patch_match s) lastn s = if and (map isDigit s) then LastN (read s) else error "--last requires an integer argument" \end{code} \begin{code} notest = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["no-test"] NoTest "don't run the test script", DarcsNoArgOption [] ["test"] Test "run the test script"] test = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["test"] Test "run the test script", DarcsNoArgOption [] ["no-test"] NoTest "don't run the test script"] leave_test_dir = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["leave-test-directory"] LeaveTestDir "don't remove the test directory", DarcsNoArgOption [] ["remove-test-directory"] NoLeaveTestDir "remove the test directory"] \end{code} \subsection{Ignore file modification times} Darcs optimizes its operations by keeping track of the modification times of your files. This dramatically speeds up commands such as \verb!whatsnew! and \verb!record! which would otherwise require reading every file in the repo and comparing it with a reference version. However, there are times when this can cause problems, such as when running a series of darcs commands from a script, in which case often a file will be modified twice in the same second, which can lead to the second modification going unnoticed. The solution to such predicaments is the \verb!--ignore-times! option, which instructs darcs not to trust the file modification times, but instead to check each file's contents explicitely. \begin{code} ignoretimes = DarcsNoArgOption [] ["ignore-times"] IgnoreTimes "don't trust the file modification times" lookforadds = DarcsMultipleChoiceOption [DarcsNoArgOption ['l'] ["look-for-adds"] LookForAdds "Add any new files or directories in the working dir", DarcsNoArgOption [] ["dont-look-for-adds"] NoLookForAdds "Don't add any files or directories automatically"] \end{code} \begin{code} askdeps = DarcsNoArgOption [] ["ask-deps"] AskDeps "ask about dependencies" ask_long_comment = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["edit-long-comment"] EditLongComment "Edit the long comment by default", DarcsNoArgOption [] ["skip-long-comment"] NoEditLongComment "Don't give a long comment", DarcsNoArgOption [] ["prompt-long-comment"] PromptLongComment "Prompt for whether to edit the long comment"] \end{code} \subsection{Author} Several commands need to be able to identify you. Conventionally, you provide an email address for this purpose. The easiest way to do this is to define an environment variable \verb!EMAIL! or \verb!DARCS_EMAIL! (with the latter overriding the former). You can also override this using the \verb!--author! flag to any command. Alternatively, you could set your email address on a per-repository basis using the ``defaults'' mechanism for ``ALL'' commands, as described in Appendix~\ref{repository_format}. Or, you could specify the author on a per-repository basis using the \verb!_darcs/prefs/author! file as described in section~\ref{author_prefs}. \begin{code} logfile = DarcsArgOption [] ["logfile"] LogFile "FILE" "give long description using logfile" rmlogfile = DarcsNoArgOption [] ["delete-logfile"] RmLogFile "delete the logfile when done" author = DarcsArgOption ['A'] ["author"] Author "EMAIL" "specify author id" from_opt = DarcsArgOption [] ["from"] Author "EMAIL" "specify email address" get_author :: [DarcsFlag] -> IO String get_author (Author a:_) = return a get_author (Pipe:_) = do putStr "Who is the author? " hFlush stdout getLine get_author (_:flags) = get_author flags get_author [] = do pref_author <- author_pref easy_author <- try_author [getEnv "DARCS_EMAIL", getEnv "EMAIL"] case pref_author `mplus` easy_author of Just a -> return a Nothing -> do aminrepo <- doesDirectoryExist "_darcs/prefs" if aminrepo then do putStr "Darcs needs to know what name (conventionally an email\n" putStr "address) to use as the author. If you provide one now\n" putStr "I will store it in the file '_darcs/prefs/author', and\n" putStr "use it by default in the future. To change your preferred\n" putStr "author address, simply delete this file.\n\n" putStr "What is your email address? " hFlush stdout add <- getLine writeFile "_darcs/prefs/author" add return add else do putStr "What is your email address? " hFlush stdout getLine where try_author (g:gs) = (liftM Just g) `catchall` try_author gs try_author [] = return Nothing author_pref = do au <- get_preflist "author" case au of [] -> return Nothing (a:_) -> return $ Just a \end{code} \subsection{Patch compression} By default, darcs commands that write patches to disk will compress the patch files. If you don't want this, you can choose the \verb!--dont-compress! option, which causes darcs not to compress the patch file. \begin{code} nocompress = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["compress"] Compress "create compressed patches", DarcsNoArgOption [] ["dont-compress"] NoCompress "don't create compressed patches"] uncompress = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["compress"] Compress "create compressed patches", DarcsNoArgOption [] ["uncompress"] NoCompress "uncompress patches"] compress = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["dont-compress"] NoCompress "don't create compressed patches", DarcsNoArgOption [] ["compress"] Compress "create compressed patches"] uncompress_nocompress = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["compress"] Compress "create compressed patches", DarcsNoArgOption [] ["dont-compress"] NoCompress "don't create compressed patches", DarcsNoArgOption [] ["uncompress"] NoCompress "uncompress patches"] \end{code} \subsection{Optional graphical interface} Certain commands may have an optional graphical user interface. If such commands are supported, you can activate the graphical user interface by calling darcs with the \verb!--gui! flag. \begin{code} #ifdef HAVEWX gui = DarcsNoArgOption ['g'] ["gui"] Gui "use graphical interface" #endif summary = DarcsMultipleChoiceOption [DarcsNoArgOption ['s'] ["summary"] Summary "summarize changes", DarcsNoArgOption [] ["no-summary"] NoSummary "don't summarize changes"] unified = DarcsNoArgOption ['u'] ["unified"] Unified "output patch in format similar to diff -u" unidiff = DarcsNoArgOption ['u'] ["unified"] Unified "pass -u option to diff" \end{code} \begin{code} target = DarcsArgOption [] ["to"] Target "EMAIL" "specify destination email" cc = DarcsArgOption [] ["cc"] Cc "EMAIL" "specify email address to cc" get_cc :: [DarcsFlag] -> String get_cc fs = lt $ catMaybes $ map whatcc fs where whatcc (Cc t) = Just t whatcc _ = Nothing lt [t] = t lt [t,""] = t lt (t:ts) = t++" , "++lt ts lt [] = "" \end{code} \begin{code} output = DarcsArgOption ['o'] ["output"] Output "FILE" "specify output filename" \end{code} \begin{code} edit_description = DarcsNoArgOption [] ["edit-description"] EditDescription "edit the patch bundle description" \end{code} \begin{code} distname_option = DarcsArgOption ['d'] ["dist-name"] DistName "DISTNAME" "name of version" \end{code} \begin{code} recursive h = DarcsMultipleChoiceOption [DarcsNoArgOption ['r'] ["recursive"] Recursive h, DarcsNoArgOption [] ["not-recursive"] NoRecursive ("don't "++h)] \end{code} \begin{code} xmloutput = DarcsNoArgOption [] ["xml-output"] XMLOutput "generate XML formatted output" \end{code} \begin{code} sign = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["sign"] Sign "sign the patch with your gpg key", DarcsArgOption [] ["sign-as"] SignAs "KEYID" "sign the patch with a given keyid", DarcsArgOption [] ["sign-ssl"] SignSSL "IDFILE" "sign the patch using openssl with a given private key", DarcsNoArgOption [] ["dont-sign"] NoSign "do not sign the patch"] applyas = DarcsMultipleChoiceOption [DarcsArgOption [] ["apply-as"] ApplyAs "USERNAME" "apply patch as another user using sudo", DarcsNoArgOption [] ["apply-as-myself"] NonApply "don't use sudo to apply as another user [DEFAULT]"] happy_forwarding = DarcsNoArgOption [] ["happy-forwarding"] HappyForwarding "forward unsigned messages without extra header" set_default = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["set-default"] SetDefault "set default repository [DEFAULT]", DarcsNoArgOption [] ["no-set-default"] NoSetDefault "don't set default repository"] \end{code} \begin{code} verify = DarcsMultipleChoiceOption [DarcsArgOption [] ["verify"] Verify "PUBRING" "verify that the patch was signed by a key in PUBRING", DarcsArgOption [] ["verify-ssl"] VerifySSL "KEYS" "verify using openSSL with authorized keys from file 'KEYS'", DarcsNoArgOption [] ["no-verify"] NonVerify "don't verify patch signature"] \end{code} \subsection{Partial repositories and checkpoints} Any tag can have a checkpoint. It is created with the \verb!--checkpoint! option, directly with the \verb!tag! command, or later with the \verb!optimize! command and a tag name. The checkpoint is a compilation of all patches prior to the tag. A partial repository only contains patches from after the checkpoint. You get a partial repository with the \verb!--partial! option to \verb!get! if the tag you get has a checkpoint. A partial repository works just like a normal repository, but any command that needs to look at the contents of a missing patch will complain and abort. \begin{code} reponame = DarcsArgOption [] ["repo-name"] RepoName "REPONAME" "name of output repository" tagname = DarcsArgOption ['t'] ["tag-name"] TagName "TAGNAME" "name of version to pull" no_deps = DarcsNoArgOption [] ["no-deps"] DontGrabDeps "don't automatically fulfill dependencies" checkpoint = DarcsNoArgOption [] ["checkpoint"] CheckPoint "create a checkpoint file" partial = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["partial"] Partial "get partial repository using checkpoint", DarcsNoArgOption [] ["complete"] Complete "get a complete copy of the repository"] partial_check = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["complete"] Complete "check the entire repository", DarcsNoArgOption [] ["partial"] Partial "check patches since latest checkpoint"] tokens = DarcsArgOption [] ["token-chars"] Toks "\"[CHARS]\"" "define token to contain these characters" \end{code} \begin{code} force_replace = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["force"] ForceReplace "proceed with replace even if 'new' token already exists", DarcsNoArgOption [] ["no-force"] NonForce "don't force the replace if it looks scary"] \end{code} \begin{code} reply = DarcsArgOption [] ["reply"] Reply "FROM" "send email response" no_resolve_conflicts = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["no-resolve-conflicts"] NoResolve "don't try to resolve conflicts", DarcsNoArgOption [] ["resolve-conflicts"] Resolve "try to resolve conflicts"] use_external_merge = DarcsArgOption [] ["external-merge"] ExternalMerge "COMMAND" "Use external tool to merge conflicts" want_external_merge :: [DarcsFlag] -> Maybe String want_external_merge [] = Nothing want_external_merge (ExternalMerge c:_) = Just c want_external_merge (_:fs) = want_external_merge fs dry_run = DarcsNoArgOption [] ["dry-run"] DryRun "don't actually make any changes" \end{code} \input{Resolution.lhs} \begin{code} noskip_boring = DarcsNoArgOption [] ["boring"] Boring "don't skip boring files" allow_caseonly = DarcsNoArgOption [] ["case-ok"] AllowCaseOnly "don't refuse to add files differing only in case" diffflags = DarcsArgOption [] ["diff-opts"] DiffFlags "OPTIONS" "options to pass to diff" \end{code} \begin{code} changes_format = DarcsMultipleChoiceOption [DarcsNoArgOption [] ["context"] (Context "") "give output suitable for get --context", xmloutput, human_readable ] changes_reverse = DarcsNoArgOption [] ["reverse"] Reverse "show changes in reverse order" human_readable = DarcsNoArgOption [] ["human-readable"] HumanReadable "give human-readable output" pipe = DarcsNoArgOption [] ["pipe"] Pipe "Expect to receive input from a pipe" interactive = DarcsNoArgOption [] ["interactive"] Interactive "Prompt user interactively" all_patches = DarcsNoArgOption ['a'] ["all"] All "answer yes to all patches" all_interactive = DarcsMultipleChoiceOption [all_patches, interactive] all_gui_pipe_interactive #ifdef HAVEWX = DarcsMultipleChoiceOption [all_patches,gui,pipe,interactive] #else = DarcsMultipleChoiceOption [all_patches,pipe,interactive] #endif all_gui_interactive #ifdef HAVEWX = DarcsMultipleChoiceOption [all_patches,gui,interactive] #else = all_interactive #endif gui_pipe_interactive = #ifdef HAVEWX DarcsMultipleChoiceOption [gui, pipe, interactive] #else pipe_interactive #endif pipe_interactive = DarcsMultipleChoiceOption [pipe, interactive] gui_interactive = #ifdef HAVEWX DarcsMultipleChoiceOption [gui, interactive] #else DarcsMultipleChoiceOption [] #endif \end{code} \begin{code} edit_file :: String -> IO ExitCode edit_file f = do ed <- get_editor system (ed++" "++f) `ortryrunning` system ("emacs "++f) `ortryrunning` system ("emacs -nw "++f) `ortryrunning` system ("nano "++f) get_editor :: IO String get_editor = getEnv "DARCS_EDITOR" `catchall` getEnv "DARCSEDITOR" `catchall` getEnv "VISUAL" `catchall` getEnv "EDITOR" `catchall` return "vi" \end{code} \begin{code} list_files :: IO [String] list_files = do skip_boring <- boring_file_filter fnames <- (filter (/= "_darcs") . skip_boring) `liftM` getDirectoryContents "." subdirlist <- do_this_list skip_boring fnames return $ skip_boring subdirlist do_this_list :: ([String] -> [String]) -> [String] -> IO [String] do_this_list _ [] = return [] do_this_list skip_boring (f:fs) = do isdir <- doesDirectoryExist f if isdir then do subdirlist <- (withCurrentDirectory f $ do fnames <- skip_boring `liftM` getDirectoryContents "." do_this_list skip_boring fnames) rest <- do_this_list skip_boring fs return $ f : rest ++ map ((++) (f++"/")) subdirlist --return $ rest ++ map ((++) (f++"/")) subdirlist else do rest <- do_this_list skip_boring fs return $ f : rest list_unregistered_files :: IO [String] list_unregistered_files = do files <- list_files registered_files <- list_registered_files return $ files \\ registered_files list_registered_files :: IO [String] list_registered_files = withCurrentDirectory "_darcs/current" list_files \end{code} \begin{code} options_latex :: [DarcsOption] -> String options_latex opts = "\\begin{tabular}{lll}\n"++ unlines (map option_latex opts)++ "\\end{tabular}\n" latex_help :: String -> String latex_help h = "\\begin{minipage}{7cm}\n\\raggedright\n" ++ h ++ "\\end{minipage}\n" option_latex :: DarcsOption -> String option_latex (DarcsNoArgOption a b _ h) = show_short_options a ++ show_long_options b ++ latex_help h ++ "\\\\" option_latex (DarcsArgOption a b _ arg h) = show_short_options a ++ show_long_options (map (++(" "++arg)) b) ++ latex_help h ++ "\\\\" option_latex (DarcsMultipleChoiceOption os) = unlines (map option_latex os) show_short_options :: [Char] -> String show_short_options [] = "&" show_short_options [c] = "\\verb!-"++[c]++"! &" show_short_options (c:cs) = "\\verb!-"++[c]++"!,"++show_short_options cs show_long_options :: [String] -> String show_long_options [] = " &" show_long_options [s] = "\\verb!--" ++ s ++ "! &" show_long_options (s:ss) = "\\verb!--" ++ s ++ "!,"++ show_long_options ss \end{code}