%  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; see the file COPYING.  If not, write to
%  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
%  Boston, MA 02110-1301, USA.

\begin{code}
module DarcsArguments ( DarcsFlag( .. ), isa,
                        fix_filepaths, fix_filepaths_wrt,
                        fix_flag, fix_filepath, unfix_filepaths,
                        DarcsOption( .. ), option_from_darcsoption,
                        help, verbose, list_options, list_files,
                        help_on_match,
                        quiet, any_verbosity, disable, restrict_paths,
                        notest, test, working_repo_dir,
                        leave_test_dir,
                        possibly_remote_repo_dir, get_repodir,
                        list_registered_files, list_unregistered_files,
                        author, get_author, get_sendmail_cmd,
                        patchname_option, distname_option,
                        logfile, rmlogfile, from_opt, subject, get_subject,
                        target, cc, get_cc, output, recursive,
                        edit_file, askdeps, ignoretimes, lookforadds,
                        ask_long_comment, sendmail_cmd, view_file,
                        sign, verify, edit_description,
                        reponame, tagname, creatorhash,
                        apply_conflict_options, reply,
                        use_external_merge, want_external_merge,
                        no_deps, nocompress, compress, uncompress,
                        uncompress_nocompress, intersection_or_union,
                        options_latex, modernize_patches, reorder_patches,
                        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,
                        diff_cmd_flag, diffflags, unidiff, xmloutput,
                        force_replace, dry_run,
                        print_dry_run_message_and_exit,
                        match_one, match_several, match_range,
                        match_several_or_range, happy_forwarding,
                        match_several_or_last,
                        set_default,
                        fancy_move_add, pristine_tree,
                        set_scripts_executable,
                        sibling, flagsToSiblings, relink, relink_pristine,
                        files, directories, pending,
                        posthook_cmd, posthook_prompt,
                        get_posthook_cmd, nullFlag,
                        disable_ssh_cm, umask_option,
                      ) where
import System.Console.GetOpt
import System.Directory ( doesDirectoryExist )
import List
import System
import Exec ( exec_interactive )
import Maybe ( catMaybes )
import Monad ( liftM, mplus, when )
import Char ( isDigit )

import Patch ( Patch, patch_summary, patch2patchinfo )
import PatchInfo ( human_friendly )
import PatchShow ( showUnnamed )
import DarcsUtils ( askUser, catchall, ortryrunning )
import RepoPrefs ( boring_file_filter, get_preflist, get_global )
import DarcsURL ( is_relative )
import FilePathUtils ( fix_maybe_absolute, drop_paths, (///) )
import PatchMatchData ( patch_match )
import DarcsFlags ( DarcsFlag(..) )
import Repository ( slurp_pending, identifyRepository )
import DarcsRepo ( slurp_all_but_darcs )
import SlurpDirectory ( list_slurpy )
import Printer ( putDocLn, text, prefix, vsep, ($$) )
import Workaround ( getCurrentDirectory )
#include "impossible.h"
\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 (SendmailCmd 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 (TagName s) = Just s
get_content (DiffFlags s) = Just s
get_content (ExternalMerge s) = Just s
get_content (RepoDir s) = Just s
get_content (WorkDir s) = Just s
get_content (PosthookCmd 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}
extract_fix_path :: [DarcsFlag] -> Maybe FilePath
extract_fix_path [] = Nothing
extract_fix_path ((FixFilePath fix):_)  = Just fix
extract_fix_path (_:fs) = extract_fix_path fs

fix_filepaths_wrt :: FilePath -> [DarcsFlag] -> [FilePath] -> IO [FilePath]
fix_filepaths_wrt repodir opts args = do
  here    <- getCurrentDirectory
  let absRepo | null repodir        = ""
              | repodir == "."      = here
              | is_relative repodir = here /// repodir
              | otherwise           = repodir
  return $ fix_filepaths absRepo opts args

fix_filepaths :: FilePath -> [DarcsFlag] -> [FilePath] -> [FilePath]
fix_filepaths repo opts args =
  case extract_fix_path opts of
  Nothing  -> args
  Just fix -> map (fix_maybe_absolute repo fix) args

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_filepath :: FilePath -> [DarcsFlag] -> FilePath -> FilePath
fix_filepath repo fs f =
  case extract_fix_path fs of
  Nothing  -> f
  Just fix -> fix_maybe_absolute repo fix f

unfix_filepaths :: [DarcsFlag] -> [FilePath] -> [FilePath]
unfix_filepaths flags f =
  case extract_fix_path flags of
  Nothing  -> f
  Just fix -> drop_paths fix f
\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
disable :: DarcsOption
restrict_paths :: 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, creatorhash,
  changes_format, match_one_context, happy_forwarding, send_to_context,
  diff_cmd_flag,
  use_external_merge, target, cc, apply_conflict_options, reply, xmloutput,
  distname_option, patchname_option, edit_description, output, unidiff,
  intersection_or_union,
  unified, summary, compress, uncompress, uncompress_nocompress, subject,
  nocompress, match_several_or_range, match_several_or_last,
  author, askdeps, lookforadds, ignoretimes, test, notest, help, force_replace,
  help_on_match,
  match_one, match_range, match_several, dry_run, fancy_move_add, sendmail_cmd,
#ifdef HAVEWX
  gui,
#endif
  logfile, rmlogfile, leave_test_dir, from_opt, set_default, pristine_tree

      :: DarcsOption

recursive :: String -> DarcsOption

sign, applyas, verify :: DarcsOption
\end{code}

\section{Common options to darcs commands}

\begin{options}
--help
\end{options}
Every \verb|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"

help_on_match = DarcsNoArgOption [] ["match"] HelpOnMatch
       "shows a summary of how to use patch matching rules"
\end{code}

\begin{options}
--disable
\end{options}
Every {\tt COMMAND} accepts the \verb!--disable! option, which can be used in
\verb!_darcs/prefs/defaults! to disable some commands in the repository. This
can be helpful if you want to protect the repository from accidental use of
advanced commands like unpull, unrecord or amend-record.
\begin{code}
disable = DarcsNoArgOption [] ["disable"] Disable
        "disable this command"
\end{code}

\begin{options}
--verbose
\end{options}
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}

\begin{options}
--repodir
\end{options}
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 repository directory when calling the
command.  This is useful when running darcs in a pipe, as might be the case
when running \verb'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 LastN (-1)
match_several_or_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 [] ["last"] lastn "NUMBER"
               "select the last NUMBER patches",
               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 uptop s = UpToPattern (patch_match s)
          fromp s = AfterPattern (patch_match s)
          lastn s = if and (map isDigit s)
                    then LastN (read s)
                    else LastN (-1)
          mp s = SeveralPattern (patch_match s)
match_several_or_last = DarcsMultipleChoiceOption
              [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 [] ["last"] lastn "NUMBER"
               "select the last NUMBER patches",
               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 fromp s = AfterPattern (patch_match s)
          lastn s = if and (map isDigit s)
                    then LastN (read s)
                    else LastN (-1)
          mp s = SeveralPattern (patch_match s)
\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}

\begin{options}
--ignore-times
\end{options}
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 repository 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 explicitly.
\begin{code}
ignoretimes = DarcsNoArgOption [] ["ignore-times"] IgnoreTimes
              "don't trust the file modification times"
lookforadds =
    DarcsMultipleChoiceOption
    [DarcsNoArgOption ['l'] ["look-for-adds"] LookForAdds
     "In addition to modifications, look for files that are not boring, and thus are potentially pending addition",
     DarcsNoArgOption [] ["dont-look-for-adds"] NoLookForAdds
     "Don't look for any files or directories that could be added, and don't add them automatically"]

fancy_move_add =
    DarcsMultipleChoiceOption
    [DarcsNoArgOption [] ["date-trick"] FancyMoveAdd
     "add files with date appended to avoid conflict. [EXPERIMENTAL] ",
     DarcsNoArgOption [] ["no-date-trick"] NoFancyMoveAdd
     "don't use experimental date appending trick. [DEFAULT]"]

pristine_tree =
    DarcsMultipleChoiceOption
    [DarcsNoArgOption [] ["plain-pristine-tree"] PristinePlain
     "Use a plain pristine tree [DEFAULT]",
     DarcsNoArgOption [] ["no-pristine-tree"] PristineNone
     "Use no pristine tree"]

\end{code}

\begin{code}
askdeps =
    DarcsMultipleChoiceOption
    [DarcsNoArgOption [] ["ask-deps"] AskDeps
     "ask for extra dependencies",
     DarcsNoArgOption [] ["no-ask-deps"] NoAskDeps
     "don't ask for extra 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}

\begin{options}
--author
\end{options}
Several commands need to be able to identify you.  Conventionally, you
provide an email address for this purpose, which can include comments,
e.g.\ \verb!David Roundy <droundy@abridgegame.org>!.  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}.

Also, a global author file can be created in your home directory with the name
\verb!.darcs/author!.  This file overrides the
contents of the environment variables, but a repository-specific author
file overrides the global author file.

\begin{code}
logfile = DarcsArgOption [] ["logfile"] LogFile "FILE"
          "give patch name and comment in file"

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 askUser "Who is the author? "
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 "
          putStr "address) to use as the\npatch author, e.g. 'Fred Bloggs "
          putStr "<fred@bloggs.invalid>'.  If you provide one\nnow "
          putStr "it will be stored in the file '_darcs/prefs/author' and "
          putStr "used as a default\nin the future.  To change your preferred "
          putStr "author address, simply delete or edit\nthis file.\n\n"
          add <- askUser "What is your email address? "
          writeFile "_darcs/prefs/author" add
          return add
        else do askUser "What is your email address (e.g. John Doe <a@b.com>)? "
    where try_author (g:gs) = (liftM Just g) `catchall` try_author gs
          try_author [] = return Nothing
          author_pref = do au <- get_preflist "author"
                           augl <- get_global "author"
                           case au++augl of [] -> return Nothing
                                            (a:_) -> return $ Just a
\end{code}

\begin{options}
--dont-compress, --compress
\end{options}
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"] UnCompress
       "uncompress patches"]
\end{code}

\begin{options}
--gui
\end{options}
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.

NOTE: The GUI is not currently functional, but is expected to re-appear 
in a future release. 

\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 a darcs-specific format similar to diff -u"
unidiff = DarcsNoArgOption ['u'] ["unified"] Unified
          "pass -u option to diff"
diff_cmd_flag = DarcsArgOption [] ["diff-command"]
       DiffCmd "COMMAND" "specify diff command (ignores --diff-opts)"
\end{code}

\begin{code}
target = DarcsArgOption [] ["to"] Target "EMAIL" "specify destination email"
cc = DarcsArgOption [] ["cc"] Cc "EMAIL" "mail results to additional EMAIL(s). Requires --reply"
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}
subject = DarcsArgOption [] ["subject"] Subject "SUBJECT" "specify mail subject"
get_subject :: [DarcsFlag] -> Maybe String
get_subject (Subject s:_) = Just s
get_subject (_:fs) = get_subject fs
get_subject [] = Nothing
\end{code}

\begin{code}
output = DarcsArgOption ['o'] ["output"] Output "FILE"
         "specify output filename"
\end{code}

\begin{code}
edit_description =
    DarcsMultipleChoiceOption
    [DarcsNoArgOption [] ["edit-description"] EditDescription
                          "edit the patch bundle description",
     DarcsNoArgOption [] ["dont-edit-description"] NoEditDescription
                      "don't 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}
creatorhash = DarcsArgOption [] ["creator-hash"] CreatorHash "HASH"
              "specify hash of creator patch (see docs)"
\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}

\begin{code}
reponame = DarcsArgOption [] ["repo-name"] WorkDir "DIRECTORY"
           "path of output directory"
tagname = DarcsArgOption ['t'] ["tag"] TagName "TAGNAME"
          "name of version to checkpoint"
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 ['f'] ["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" "reply to email-based patch using FROM address"
apply_conflict_options
    = DarcsMultipleChoiceOption
      [DarcsNoArgOption [] ["mark-conflicts"]
       MarkConflicts "mark conflicts",
       DarcsNoArgOption [] ["allow-conflicts"]
       AllowConflicts "allow conflicts, but don't mark them",
       DarcsArgOption [] ["external-merge"]
       ExternalMerge "COMMAND" "use external tool to merge conflicts",
       DarcsNoArgOption [] ["no-resolve-conflicts"] NoAllowConflicts
       "equivalent to --dont-allow-conflicts, for backwards compatibility",
       DarcsNoArgOption [] ["dont-allow-conflicts"]
       NoAllowConflicts "fail on patches that create conflicts [DEFAULT]"]
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
\end{code}

\begin{options}
--dry-run
\end{options}
The \verb!--dry-run! option will cause darcs not to actually take the specified
action, but only print what would have happened.  Not all commands accept
\verb!--dry-run!, but those that do should accept the \verb!--summary!  option.

\begin{options}
--summary, --no-summary
\end{options}
The \verb!--summary! option shows a summary of the patches that would have been
pulled/pushed/whatever. The format is similar to the output format of
\verb!cvs update! and looks like this:

\begin{verbatim}
A  ./added_but_not_recorded.c
A! ./added_but_not_recorded_conflicts.c
a  ./would_be_added_if_look_for_adds_option_was_used.h

M  ./modified.t -1 +1
M! ./modified_conflicts.t -1 +1

R  ./removed_but_not_recorded.c
R! ./removed_but_not_recorded_conflicts.c

\end{verbatim}

You can probably guess what the flags mean from the clever file names.
\begin{description}
\item{\texttt{A}} is for files that have been added but not recorded yet.
\item{\texttt{a}} is for files found using the \verb!--look-for-adds! option available for
\verb!whatsnew! and \verb!record!. They have not been added yet, but would be
added automatically if \verb!--look-for-adds! were used with the next
\verb!record! command.

\item{\texttt{M}} is for files that have been modified in the working directory but not
recorded yet. The number of added and subtracted lines is also shown.

\item{\texttt{R}}  is for files that have been removed, but the removal is not
recorded yet.
\end{description}
An exclamation mark appears next to any option that has a conflict.

\begin{code}
dry_run = DarcsNoArgOption [] ["dry-run"] DryRun
          "don't actually take the action"

print_dry_run_message_and_exit :: String -> [DarcsFlag] -> [Patch] -> IO ()
print_dry_run_message_and_exit action opts patches =
  let showpatch p = if Verbose `elem` opts
                    then (human_friendly $ fromJust $ patch2patchinfo p)
                      $$ showUnnamed p
                    else if Summary `elem` opts
                    then (human_friendly $ fromJust $ patch2patchinfo p)
                      $$ text "" $$ prefix "    " (patch_summary p)
                    else human_friendly $ fromJust $ patch2patchinfo p
  in do when (DryRun `elem` opts) $ do
          putDocLn $ text ("Would " ++ action ++ " the following changes:")
              $$ (vsep $ map showpatch patches)
          putStrLn ""
          putStrLn "Making no changes:  this is a dry run."
          exitWith ExitSuccess
        when (All `elem` opts && Summary `elem` opts) $
          putDocLn $ text ("Will " ++ action ++ " the following changes:")
              $$ (vsep $ map showpatch patches)
\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 ['i'] ["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

intersection_or_union =
    DarcsMultipleChoiceOption
    [DarcsNoArgOption [] ["intersection"] Intersection
     "take intersection of all repositories",
     DarcsNoArgOption [] ["union"] Union
     "take union of all repositories [DEFAULT]"]
\end{code}

\begin{code}
edit_file :: String -> IO ExitCode
edit_file f = do
  ed <- get_editor
  exec_interactive ed [f]
             `ortryrunning` exec_interactive "emacs" [f]
             `ortryrunning` exec_interactive "emacs" ["-nw",f]
             `ortryrunning` exec_interactive "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}
view_file :: String -> IO ExitCode
view_file f = do
  viewer <- get_viewer
  exec_interactive viewer [f]
             `ortryrunning` exec_interactive "more" [f]
get_viewer :: IO String
get_viewer = getEnv "DARCS_PAGER" `catchall`
             getEnv "PAGER" `catchall` return "less"
\end{code}

\begin{code}
list_files :: IO [String]
list_files = do s <- slurp_all_but_darcs "."
                skip_boring <- boring_file_filter
                return (skip_boring $ list_slurpy s)

list_unregistered_files :: IO [String]
list_unregistered_files =
    do repository <- identifyRepository "."
       s <- slurp_all_but_darcs "."
       skip_boring <- boring_file_filter
       regs <- slurp_pending repository
       return $ (skip_boring $ list_slurpy s) \\ (list_slurpy regs)

list_registered_files :: IO [String]
list_registered_files =
    list_slurpy `liftM` (identifyRepository "." >>= slurp_pending)
\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

set_scripts_executable :: DarcsOption
set_scripts_executable = DarcsMultipleChoiceOption
                              [DarcsNoArgOption [] ["set-scripts-executable"] SetScriptsExecutable
                               "make scripts executable",
                               DarcsNoArgOption [] ["dont-set-scripts-executable"] DontSetScriptsExecutable
                               "don't make scripts executable"]

\end{code}

\begin{code}
relink, relink_pristine, sibling :: DarcsOption
relink = DarcsNoArgOption [] ["relink"] Relink
         "relink random internal data to a sibling"

relink_pristine = DarcsNoArgOption [] ["relink-pristine"] RelinkPristine
                  "relink pristine tree (not recommended)"

sibling = DarcsArgOption [] ["sibling"] Sibling "URL"
          "specify a sibling directory"

flagsToSiblings :: [DarcsFlag] -> [String]
flagsToSiblings ((Sibling s) : l) = s : (flagsToSiblings l)
flagsToSiblings (_ : l) = flagsToSiblings l
flagsToSiblings [] = []
\end{code}

\begin{code}
modernize_patches :: DarcsOption
modernize_patches = DarcsNoArgOption [] ["modernize-patches"] ModernizePatches
                    "rewrite all patches in current darcs format"

reorder_patches :: DarcsOption
reorder_patches = DarcsNoArgOption [] ["reorder-patches"] Reorder
                  "reorder the patches in the repository"
\end{code}

\begin{code}
sendmail_cmd = DarcsArgOption [] ["sendmail-command"] SendmailCmd "COMMAND" "specify sendmail command"

get_sendmail_cmd :: [DarcsFlag] -> String
get_sendmail_cmd (SendmailCmd a:_) = a
get_sendmail_cmd (_:flags) = get_sendmail_cmd flags
get_sendmail_cmd [] = ""
\end{code}

\begin{code}
files :: DarcsOption
files = DarcsMultipleChoiceOption
        [DarcsNoArgOption [] ["files"] Files
         "include files in output [DEFAULT]",
         DarcsNoArgOption [] ["no-files"] NoFiles
         "do not include files in output"]

directories :: DarcsOption
directories = DarcsMultipleChoiceOption
              [DarcsNoArgOption [] ["directories"] Directories
               "include directories in output",
               DarcsNoArgOption [] ["no-directories"] NoDirectories
               "do not include directories in output [DEFAULT]"]

pending :: DarcsOption
pending = DarcsMultipleChoiceOption
              [DarcsNoArgOption [] ["pending"] Pending
               "reflect pending patches in output [DEFAULT]",
               DarcsNoArgOption [] ["no-pending"] NoPending
               "only included recorded patches in output"]

nullFlag :: DarcsOption        -- "null" is already taken
nullFlag = DarcsNoArgOption ['0'] ["null"] NullFlag
       "separate file names by NUL characters"
\end{code}
\begin{options}
--posthook=COMMAND, --no-posthook
\end{options}
To provide a command that should be run whenever a darcs command completes
successfully, use \verb!--posthook! to specify the command.  This is useful
for people who want to have a command run whenever a patch is applied.  Using
\verb!--no-posthook! will disable running the command.  
\begin{options}
--prompt-posthook, --run-posthook
\end{options}
These options control prompting before running the posthook.  Use
\verb!--prompt-posthook! to force prompting before running the
posthook command.  For security reasons, this is the default.  When
defining a posthook for apply, you will need to use
\verb!--run-posthook! or else you will get an error, because the
subprocess which runs the apply command cannot prompt the user.
\begin{code}
posthook_cmd :: DarcsOption
posthook_cmd = DarcsMultipleChoiceOption
               [DarcsArgOption [] ["posthook"] PosthookCmd 
                "COMMAND" "specify command to run after this darcs command.",
                DarcsNoArgOption [] ["no-posthook"] NoPosthook
                "Do not run posthook command."]

posthook_prompt :: DarcsOption
posthook_prompt = DarcsMultipleChoiceOption
                  [DarcsNoArgOption [] ["prompt-posthook"] AskPosthook
                   "Prompt before running posthook. [DEFAULT]",
                   DarcsNoArgOption [] ["run-posthook"] RunPosthook
                   "Run posthook command without prompting."]

get_posthook_cmd :: [DarcsFlag] -> Maybe String
get_posthook_cmd (PosthookCmd a:_) = Just a
get_posthook_cmd (_:flags) = get_posthook_cmd flags
get_posthook_cmd [] = Nothing
\end{code}

\begin{options}
--disable-ssh-cm
\end{options}

For commands which invoke ssh, darcs will normally multiplex ssh
sessions over a single connection as long as your version of ssh has
the ControlMaster feature from OpenSSH versions 3.9 and above.  This
option will avoid darcs trying to use this feature even if your ssh
supports it.
\begin{code}
disable_ssh_cm :: DarcsOption
disable_ssh_cm = DarcsNoArgOption [] ["disable-ssh-cm"] DisableSSHControlMaster
                  "Disable use of SSH ControlMaster feature"
\end{code}
\begin{options}
--umask
\end{options}
By default, Darcs will use your current umask.  The option
\verb|--umask| will cause Darcs to switch to a different umask before
writing to the repository.

\begin{code}
umask_option :: DarcsOption
umask_option =
    DarcsArgOption [] ["umask"] UMask "UMASK"
        "specify umask to use when writing."
\end{code}

\begin{options}
--dont-restrict-paths, --restrict-paths
\end{options}
By default darcs is only allowed to manage and modify files and directories
contained inside the current repository and not being part of any darcs
repository's meta data (including the current one). This is mainly for
security, to protect you from spoofed patches modifying arbitrary files
with sensitive data---say, in your home directory---or tempering with any
repository's meta data to switch off this safety guard.

But sometimes you may want to manage a group of ``sub'' repositories'
preference files with a global repository, or use darcs in some other
advanced way. The best way is probably to put
\verb!ALL dont-restrict-paths! in \verb!_darcs/prefs/defaults!. This turns
off all sanity checking for file paths in patches.

Path checking can be temporarily turned on with \verb!--restrict-paths! on
the command line, when pulling or applying unknown patches.

\begin{code}
restrict_paths =
    DarcsMultipleChoiceOption
    [DarcsNoArgOption [] ["restrict-paths"] RestrictPaths
     "don't allow darcs to touch external files or repo metadata",
     DarcsNoArgOption [] ["dont-restrict-paths"] DontRestrictPaths
     "allow darcs to modify any file or directory (unsafe)"]
\end{code}

