Move shell completion things into a separate file
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 16 Dec 2013 18:15:58 +0000 (20:15 +0200)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Tue, 24 Dec 2013 04:40:59 +0000 (05:40 +0100)
Move (most) things related to shell completion into a separate file from
wman.cpp.  This allows independent refactoring of the different parts.
Also clean up write_man() and the mechanism that invokes it now that it
is only used with the new context mechanism.

Change-Id: Ife0e3e5c64a78b73917123d9b7bdbe121f844ebc

src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/commandline/pargs.cpp
src/gromacs/commandline/shellcompletions.cpp [new file with mode: 0644]
src/gromacs/commandline/shellcompletions.h [new file with mode: 0644]
src/gromacs/commandline/wman.cpp
src/gromacs/commandline/wman.h

index d709f562ffe3e1622914507d20ce97d03a843e98..0e2487c085023aaefc6c505288d78d80c38e5de2 100644 (file)
@@ -929,30 +929,11 @@ class CMainCommandLineModule : public CommandLineModuleInterface
         }
         virtual void writeHelp(const CommandLineHelpContext &context) const
         {
-            const HelpOutputFormat format = context.writerContext().outputFormat();
-            const char            *type;
-            switch (format)
-            {
-                case eHelpOutputFormat_Console:
-                    type = "help";
-                    break;
-                case eHelpOutputFormat_Man:
-                    type = "nroff";
-                    break;
-                case eHelpOutputFormat_Html:
-                    type = "html";
-                    break;
-                default:
-                    GMX_THROW(NotImplementedError(
-                                      "Command-line help is not implemented for this output format"));
-            }
-            char *argv[4];
-            int   argc = 3;
+            char *argv[2];
+            int   argc = 1;
             // TODO: The constness should not be cast away.
             argv[0] = const_cast<char *>(name_);
-            argv[1] = const_cast<char *>("-man");
-            argv[2] = const_cast<char *>(type);
-            argv[3] = NULL;
+            argv[1] = NULL;
             GlobalCommandLineHelpContext global(context);
             mainFunction_(argc, argv);
         }
index 757dfc51cced632d3f0ca9dc03e7ff5a6168705a..2654d680f9a7dd7e42b0333938a44335ff5b99d7 100644 (file)
@@ -61,6 +61,8 @@
 #include "gromacs/legacyheaders/string2.h"
 #include "gromacs/legacyheaders/thread_mpi/threads.h"
 
+#include "gromacs/commandline/cmdlinehelpcontext.h"
+#include "gromacs/commandline/shellcompletions.h"
 #include "gromacs/commandline/wman.h"
 #include "gromacs/fileio/timecontrol.h"
 #include "gromacs/utility/exceptions.h"
@@ -576,7 +578,7 @@ gmx_bool parse_common_args(int *argc, char *argv[], unsigned long Flags,
                            output_env_t *oenv)
 {
     const char *manstr[] = {
-        NULL, "no", "help", "html", "nroff", "completion", NULL
+        NULL, "no", "completion", NULL
     };
     /* This array should match the order of the enum in oenv.h */
     const char *xvg_format[] = { NULL, "xmgrace", "xmgr", "none", NULL };
@@ -641,7 +643,7 @@ gmx_bool parse_common_args(int *argc, char *argv[], unsigned long Flags,
           "HIDDENWrite file with debug information, 1: short, 2: also x and f" },
     };
 #define NPCA_PA asize(pca_pa)
-    gmx_bool bExit, bXvgr;
+    gmx_bool bXvgr;
     int      i, j, k, npall, max_pa;
 
     // Handle the flags argument, which is a bit field
@@ -801,15 +803,34 @@ gmx_bool parse_common_args(int *argc, char *argv[], unsigned long Flags,
         all_pa[i].desc = mk_desc(&(all_pa[i]), output_env_get_time_unit(*oenv));
     }
 
-    // To satisfy clang.
-    GMX_ASSERT(manstr[0] != NULL,
-               "Enum option default assignment should have changed this");
-    bExit = (strcmp(manstr[0], "no") != 0);
-
 #if (defined __sgi && USE_SGI_FPE)
     doexceptions();
 #endif
 
+    bool bExit = false;
+    try
+    {
+        const gmx::CommandLineHelpContext *context =
+            gmx::GlobalCommandLineHelpContext::get();
+        bExit = (context != NULL || strcmp(manstr[0], "no") != 0);
+        if (!(FF(PCA_QUIET)))
+        {
+            if (context != NULL)
+            {
+                write_man(*context, ndesc, desc, nfile, fnm, npall, all_pa, nbugs, bugs);
+            }
+            else if (!strcmp(manstr[0], "completion"))
+            {
+                const char *program = output_env_get_short_program_name(*oenv);
+                /* one file each for csh, bash and zsh if we do completions */
+                write_completions("completion-zsh", program, nfile, fnm, npall, all_pa);
+                write_completions("completion-bash", program, nfile, fnm, npall, all_pa);
+                write_completions("completion-csh", program, nfile, fnm, npall, all_pa);
+            }
+        }
+    }
+    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
+
     /* Set the nice level */
 #ifdef __sgi
     if (npri != 0 && !bExit)
@@ -839,29 +860,6 @@ gmx_bool parse_common_args(int *argc, char *argv[], unsigned long Flags,
 #endif
 #endif
 
-    if (strcmp(manstr[0], "no") != 0 && !(FF(PCA_QUIET)))
-    {
-        try
-        {
-            if (!strcmp(manstr[0], "completion"))
-            {
-                /* one file each for csh, bash and zsh if we do completions */
-                write_man("completion-zsh", output_env_get_short_program_name(*oenv),
-                          ndesc, desc, nfile, fnm, npall, all_pa, nbugs, bugs);
-                write_man("completion-bash", output_env_get_short_program_name(*oenv),
-                          ndesc, desc, nfile, fnm, npall, all_pa, nbugs, bugs);
-                write_man("completion-csh", output_env_get_short_program_name(*oenv),
-                          ndesc, desc, nfile, fnm, npall, all_pa, nbugs, bugs);
-            }
-            else
-            {
-                write_man(manstr[0], output_env_get_short_program_name(*oenv),
-                          ndesc, desc, nfile, fnm, npall, all_pa, nbugs, bugs);
-            }
-        }
-        GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
-    }
-
     /* convert time options, must be done after printing! */
 
     for (i = 0; i < npall; i++)
diff --git a/src/gromacs/commandline/shellcompletions.cpp b/src/gromacs/commandline/shellcompletions.cpp
new file mode 100644 (file)
index 0000000..002ff60
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2004, The GROMACS development team.
+ * Copyright (c) 2013, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gromacs/commandline/shellcompletions.h"
+
+#include <cstdio>
+#include <cstring>
+
+#include "gromacs/commandline/pargs.h"
+#include "gromacs/fileio/filenm.h"
+#include "gromacs/fileio/gmxfio.h"
+
+#include "gromacs/legacyheaders/copyrite.h"
+#include "gromacs/legacyheaders/smalloc.h"
+
+// Shell types for completion.
+enum {
+    eshellCSH, eshellBASH, eshellZSH
+};
+
+// TODO: Don't duplicate this from filenm.c/futil.c.
+#define NZEXT 2
+static const char *z_ext[NZEXT] = { ".gz", ".Z" };
+
+static void pr_fopts(FILE *fp, int nf, const t_filenm tfn[], int shell)
+{
+    switch (shell)
+    {
+        case eshellCSH:
+            for (int i = 0; i < nf; i++)
+            {
+                fprintf(fp, " \"n/%s/f:*.", tfn[i].opt);
+                const int ftp          = tfn[i].ftp;
+                const int genericCount = ftp2generic_count(ftp);
+                if (genericCount > 0)
+                {
+                    fprintf(fp, "{");
+                    const int *const genericTypes = ftp2generic_list(ftp);
+                    for (int j = 0; j < genericCount; j++)
+                    {
+                        if (j > 0)
+                        {
+                            fprintf(fp, ",");
+                        }
+                        fprintf(fp, "%s", ftp2ext(genericTypes[j]));
+                    }
+                    fprintf(fp, "}");
+                }
+                else
+                {
+                    fprintf(fp, "%s", ftp2ext(ftp));
+                }
+                fprintf(fp, "{");
+                for (int j = 0; j < NZEXT; j++)
+                {
+                    fprintf(fp, ",%s", z_ext[j]);
+                }
+                fprintf(fp, "}/\"");
+            }
+            break;
+        case eshellBASH:
+            for (int i = 0; i < nf; i++)
+            {
+                fprintf(fp, "%s) COMPREPLY=( $(compgen -X '!*.", tfn[i].opt);
+                const int ftp          = tfn[i].ftp;
+                const int genericCount = ftp2generic_count(ftp);
+                if (genericCount > 0)
+                {
+                    fprintf(fp, "+(");
+                    const int *const genericTypes = ftp2generic_list(ftp);
+                    for (int j = 0; j < genericCount; j++)
+                    {
+                        if (j > 0)
+                        {
+                            fprintf(fp, "|");
+                        }
+                        fprintf(fp, "%s", ftp2ext(genericTypes[j]));
+                    }
+                    fprintf(fp, ")");
+                }
+                else
+                {
+                    fprintf(fp, "%s", ftp2ext(ftp));
+                }
+                fprintf(fp, "*(");
+                for (int j = 0; j < NZEXT; j++)
+                {
+                    if (j > 0)
+                    {
+                        fprintf(fp, "|");
+                    }
+                    fprintf(fp, "%s", z_ext[j]);
+                }
+                fprintf(fp, ")' -f $c ; compgen -S '/' -X '.*' -d $c ));;\n");
+            }
+            break;
+        case eshellZSH:
+            for (int i = 0; i < nf; i++)
+            {
+                fprintf(fp, "- 'c[-1,%s]' -g '*.", tfn[i].opt);
+                const int ftp          = tfn[i].ftp;
+                const int genericCount = ftp2generic_count(ftp);
+                if (genericCount > 0)
+                {
+                    fprintf(fp, "(");
+                    const int *const genericTypes = ftp2generic_list(ftp);
+                    for (int j = 0; j < genericCount; j++)
+                    {
+                        if (j > 0)
+                        {
+                            fprintf(fp, "|");
+                        }
+                        fprintf(fp, "%s", ftp2ext(genericTypes[j]));
+                    }
+                    fprintf(fp, ")");
+                }
+                else
+                {
+                    fprintf(fp, "%s", ftp2ext(ftp));
+                }
+                fprintf(fp, "(");
+                for (int j = 0; j < NZEXT; j++)
+                {
+                    fprintf(fp, "|%s", z_ext[j]);
+                }
+                fprintf(fp, ") *(/)' ");
+            }
+            break;
+    }
+}
+
+static void pr_opts(FILE *fp,
+                    int nfile,  t_filenm *fnm,
+                    int npargs, t_pargs pa[], int shell)
+{
+    switch (shell)
+    {
+        case eshellCSH:
+            fprintf(fp, " \"c/-/(");
+            for (int i = 0; i < nfile; i++)
+            {
+                fprintf(fp, " %s", fnm[i].opt+1);
+            }
+            for (int i = 0; i < npargs; i++)
+            {
+                if (pa[i].type == etBOOL && *(pa[i].u.b))
+                {
+                    fprintf(fp, " no%s", pa[i].option+1);
+                }
+                else
+                {
+                    fprintf(fp, " %s", pa[i].option+1);
+                }
+            }
+            fprintf(fp, ")/\"");
+            break;
+        case eshellBASH:
+            fprintf(fp, "if (( $COMP_CWORD <= 1 )) || [[ $c == -* ]]; then COMPREPLY=( $(compgen  -W '");
+            for (int i = 0; i < nfile; i++)
+            {
+                fprintf(fp, " -%s", fnm[i].opt+1);
+            }
+            for (int i = 0; i < npargs; i++)
+            {
+                if (pa[i].type == etBOOL && *(pa[i].u.b))
+                {
+                    fprintf(fp, " -no%s", pa[i].option+1);
+                }
+                else
+                {
+                    fprintf(fp, " -%s", pa[i].option+1);
+                }
+            }
+            fprintf(fp, "' -- $c)); return 0; fi\n");
+            break;
+        case eshellZSH:
+            fprintf(fp, " -x 's[-]' -s \"");
+            for (int i = 0; i < nfile; i++)
+            {
+                fprintf(fp, " %s", fnm[i].opt+1);
+            }
+            for (int i = 0; i < npargs; i++)
+            {
+                if (pa[i].type == etBOOL && *(pa[i].u.b))
+                {
+                    fprintf(fp, " no%s", pa[i].option+1);
+                }
+                else
+                {
+                    fprintf(fp, " %s", pa[i].option+1);
+                }
+            }
+            fprintf(fp, "\" ");
+            break;
+    }
+}
+
+static void pr_enums(FILE *fp, int npargs, t_pargs pa[], int shell)
+{
+    int i, j;
+
+    switch (shell)
+    {
+        case eshellCSH:
+            for (i = 0; i < npargs; i++)
+            {
+                if (pa[i].type == etENUM)
+                {
+                    fprintf(fp, " \"n/%s/(", pa[i].option);
+                    for (j = 1; pa[i].u.c[j]; j++)
+                    {
+                        fprintf(fp, " %s", pa[i].u.c[j]);
+                    }
+                    fprintf(fp, ")/\"");
+                }
+            }
+            break;
+        case eshellBASH:
+            for (i = 0; i < npargs; i++)
+            {
+                if (pa[i].type == etENUM)
+                {
+                    fprintf(fp, "%s) COMPREPLY=( $(compgen -W '", pa[i].option);
+                    for (j = 1; pa[i].u.c[j]; j++)
+                    {
+                        fprintf(fp, " %s", pa[i].u.c[j]);
+                    }
+                    fprintf(fp, " ' -- $c ));;\n");
+                }
+            }
+            break;
+        case eshellZSH:
+            for (i = 0; i < npargs; i++)
+            {
+                if (pa[i].type == etENUM)
+                {
+                    fprintf(fp, "- 'c[-1,%s]' -s \"", pa[i].option);
+                    for (j = 1; pa[i].u.c[j]; j++)
+                    {
+                        fprintf(fp, " %s", pa[i].u.c[j]);
+                    }
+                    fprintf(fp, "\" ");
+                }
+            }
+            break;
+    }
+}
+
+static void write_bashcompl(FILE *out,
+                            int nfile,  t_filenm *fnm,
+                            int npargs, t_pargs *pa)
+{
+    /* Advanced bash completions are handled by shell functions.
+     * p and c hold the previous and current word on the command line.
+     * We need to use extended globbing, so write it in each completion file */
+    fprintf(out, "shopt -s extglob\n");
+    fprintf(out, "_%s_compl() {\nlocal p c\n", ShortProgram());
+    fprintf(out, "COMPREPLY=() c=${COMP_WORDS[COMP_CWORD]} p=${COMP_WORDS[COMP_CWORD-1]}\n");
+    pr_opts(out, nfile, fnm, npargs, pa, eshellBASH);
+    fprintf(out, "case \"$p\" in\n");
+
+    pr_enums(out, npargs, pa, eshellBASH);
+    pr_fopts(out, nfile, fnm, eshellBASH);
+    fprintf(out, "esac }\ncomplete -F _%s_compl %s\n", ShortProgram(), ShortProgram());
+}
+
+static void write_cshcompl(FILE *out,
+                           int nfile,  t_filenm *fnm,
+                           int npargs, t_pargs *pa)
+{
+    fprintf(out, "complete %s", ShortProgram());
+    pr_enums(out, npargs, pa, eshellCSH);
+    pr_fopts(out, nfile, fnm, eshellCSH);
+    pr_opts(out, nfile, fnm, npargs, pa, eshellCSH);
+    fprintf(out, "\n");
+}
+
+static void write_zshcompl(FILE *out,
+                           int nfile,  t_filenm *fnm,
+                           int npargs, t_pargs *pa)
+{
+    fprintf(out, "compctl ");
+
+    /* start with options, since they are always present */
+    pr_opts(out, nfile, fnm, npargs, pa, eshellZSH);
+    pr_enums(out, npargs, pa, eshellZSH);
+    pr_fopts(out, nfile, fnm, eshellZSH);
+    fprintf(out, "-- %s\n", ShortProgram());
+}
+
+void write_completions(const char *type, const char *program,
+                       int nfile,  t_filenm *fnm,
+                       int npargs, t_pargs *pa)
+{
+    char     buf[256];
+    sprintf(buf, "%s.%s", program, type);
+    FILE    *out = gmx_fio_fopen(buf, "w");
+
+    int      npar;
+    t_pargs *par;
+
+    // Remove hidden arguments.
+    snew(par, npargs);
+    npar = 0;
+    for (int i = 0; i < npargs; i++)
+    {
+        if (!is_hidden(&pa[i]))
+        {
+            par[npar] = pa[i];
+            npar++;
+        }
+    }
+
+    if (strcmp(type, "completion-zsh") == 0)
+    {
+        write_zshcompl(out, nfile, fnm, npar, par);
+    }
+    if (strcmp(type, "completion-bash") == 0)
+    {
+        write_bashcompl(out, nfile, fnm, npar, par);
+    }
+    if (strcmp(type, "completion-csh") == 0)
+    {
+        write_cshcompl(out, nfile, fnm, npar, par);
+    }
+
+    sfree(par);
+
+    gmx_fio_fclose(out);
+}
diff --git a/src/gromacs/commandline/shellcompletions.h b/src/gromacs/commandline/shellcompletions.h
new file mode 100644 (file)
index 0000000..d8e86b2
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2004, The GROMACS development team.
+ * Copyright (c) 2013, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#ifndef GMX_COMMANDLINE_SHELLCOMPLETIONS_H
+#define GMX_COMMANDLINE_SHELLCOMPLETIONS_H
+
+#include "gromacs/commandline/pargs.h"
+#include "gromacs/fileio/filenm.h"
+
+void write_completions(const char *type, const char *program,
+                       int nfile,  t_filenm *fnm,
+                       int npargs, t_pargs *pa);
+
+#endif
index 6d2f2f20bfc9e5987c2f983f679702e8f745b357..1d306f4a86d9d825b94d93575e308e6d52e690aa 100644 (file)
 
 #include "gromacs/commandline/cmdlinehelpcontext.h"
 #include "gromacs/fileio/filenm.h"
-#include "gromacs/fileio/gmxfio.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/file.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/stringutil.h"
 
-#include "copyrite.h"
 #include "gmx_fatal.h"
 #include "string2.h"
 #include "smalloc.h"
 
-// Shell types, for completion stuff
-enum {
-    eshellCSH, eshellBASH, eshellZSH
-};
-
-// TODO: Don't duplicate this from filenm.c/futil.c.
-#define NZEXT 2
-static const char *z_ext[NZEXT] = { ".gz", ".Z" };
-
 /* The source code in this file should be thread-safe.
  * Please keep it that way. */
 
@@ -577,302 +567,18 @@ static void write_htmlman(FILE *out,
     }
 }
 
-static void pr_fopts(FILE *fp, int nf, const t_filenm tfn[], int shell)
-{
-    switch (shell)
-    {
-        case eshellCSH:
-            for (int i = 0; i < nf; i++)
-            {
-                fprintf(fp, " \"n/%s/f:*.", tfn[i].opt);
-                const int ftp          = tfn[i].ftp;
-                const int genericCount = ftp2generic_count(ftp);
-                if (genericCount > 0)
-                {
-                    fprintf(fp, "{");
-                    const int *const genericTypes = ftp2generic_list(ftp);
-                    for (int j = 0; j < genericCount; j++)
-                    {
-                        if (j > 0)
-                        {
-                            fprintf(fp, ",");
-                        }
-                        fprintf(fp, "%s", ftp2ext(genericTypes[j]));
-                    }
-                    fprintf(fp, "}");
-                }
-                else
-                {
-                    fprintf(fp, "%s", ftp2ext(ftp));
-                }
-                fprintf(fp, "{");
-                for (int j = 0; j < NZEXT; j++)
-                {
-                    fprintf(fp, ",%s", z_ext[j]);
-                }
-                fprintf(fp, "}/\"");
-            }
-            break;
-        case eshellBASH:
-            for (int i = 0; i < nf; i++)
-            {
-                fprintf(fp, "%s) COMPREPLY=( $(compgen -X '!*.", tfn[i].opt);
-                const int ftp          = tfn[i].ftp;
-                const int genericCount = ftp2generic_count(ftp);
-                if (genericCount > 0)
-                {
-                    fprintf(fp, "+(");
-                    const int *const genericTypes = ftp2generic_list(ftp);
-                    for (int j = 0; j < genericCount; j++)
-                    {
-                        if (j > 0)
-                        {
-                            fprintf(fp, "|");
-                        }
-                        fprintf(fp, "%s", ftp2ext(genericTypes[j]));
-                    }
-                    fprintf(fp, ")");
-                }
-                else
-                {
-                    fprintf(fp, "%s", ftp2ext(ftp));
-                }
-                fprintf(fp, "*(");
-                for (int j = 0; j < NZEXT; j++)
-                {
-                    if (j > 0)
-                    {
-                        fprintf(fp, "|");
-                    }
-                    fprintf(fp, "%s", z_ext[j]);
-                }
-                fprintf(fp, ")' -f $c ; compgen -S '/' -X '.*' -d $c ));;\n");
-            }
-            break;
-        case eshellZSH:
-            for (int i = 0; i < nf; i++)
-            {
-                fprintf(fp, "- 'c[-1,%s]' -g '*.", tfn[i].opt);
-                const int ftp          = tfn[i].ftp;
-                const int genericCount = ftp2generic_count(ftp);
-                if (genericCount > 0)
-                {
-                    fprintf(fp, "(");
-                    const int *const genericTypes = ftp2generic_list(ftp);
-                    for (int j = 0; j < genericCount; j++)
-                    {
-                        if (j > 0)
-                        {
-                            fprintf(fp, "|");
-                        }
-                        fprintf(fp, "%s", ftp2ext(genericTypes[j]));
-                    }
-                    fprintf(fp, ")");
-                }
-                else
-                {
-                    fprintf(fp, "%s", ftp2ext(ftp));
-                }
-                fprintf(fp, "(");
-                for (int j = 0; j < NZEXT; j++)
-                {
-                    fprintf(fp, "|%s", z_ext[j]);
-                }
-                fprintf(fp, ") *(/)' ");
-            }
-            break;
-    }
-}
-
-static void pr_opts(FILE *fp,
-                    int nfile,  t_filenm *fnm,
-                    int npargs, t_pargs pa[], int shell)
-{
-    int i;
-
-    switch (shell)
-    {
-        case eshellCSH:
-            fprintf(fp, " \"c/-/(");
-            for (i = 0; i < nfile; i++)
-            {
-                fprintf(fp, " %s", fnm[i].opt+1);
-            }
-            for (i = 0; i < npargs; i++)
-            {
-                if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
-                {
-                    fprintf(fp, " no%s", pa[i].option+1);
-                }
-                else
-                {
-                    fprintf(fp, " %s", pa[i].option+1);
-                }
-            }
-            fprintf(fp, ")/\"");
-            break;
-        case eshellBASH:
-            fprintf(fp, "if (( $COMP_CWORD <= 1 )) || [[ $c == -* ]]; then COMPREPLY=( $(compgen  -W '");
-            for (i = 0; i < nfile; i++)
-            {
-                fprintf(fp, " -%s", fnm[i].opt+1);
-            }
-            for (i = 0; i < npargs; i++)
-            {
-                if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
-                {
-                    fprintf(fp, " -no%s", pa[i].option+1);
-                }
-                else
-                {
-                    fprintf(fp, " -%s", pa[i].option+1);
-                }
-            }
-            fprintf(fp, "' -- $c)); return 0; fi\n");
-            break;
-        case eshellZSH:
-            fprintf(fp, " -x 's[-]' -s \"");
-            for (i = 0; i < nfile; i++)
-            {
-                fprintf(fp, " %s", fnm[i].opt+1);
-            }
-            for (i = 0; i < npargs; i++)
-            {
-                if ( (pa[i].type == etBOOL) && *(pa[i].u.b) )
-                {
-                    fprintf(fp, " no%s", pa[i].option+1);
-                }
-                else
-                {
-                    fprintf(fp, " %s", pa[i].option+1);
-                }
-            }
-            fprintf(fp, "\" ");
-            break;
-    }
-}
-
-static void pr_enums(FILE *fp, int npargs, t_pargs pa[], int shell)
-{
-    int i, j;
-
-    switch (shell)
-    {
-        case eshellCSH:
-            for (i = 0; i < npargs; i++)
-            {
-                if (pa[i].type == etENUM)
-                {
-                    fprintf(fp, " \"n/%s/(", pa[i].option);
-                    for (j = 1; pa[i].u.c[j]; j++)
-                    {
-                        fprintf(fp, " %s", pa[i].u.c[j]);
-                    }
-                    fprintf(fp, ")/\"");
-                }
-            }
-            break;
-        case eshellBASH:
-            for (i = 0; i < npargs; i++)
-            {
-                if (pa[i].type == etENUM)
-                {
-                    fprintf(fp, "%s) COMPREPLY=( $(compgen -W '", pa[i].option);
-                    for (j = 1; pa[i].u.c[j]; j++)
-                    {
-                        fprintf(fp, " %s", pa[i].u.c[j]);
-                    }
-                    fprintf(fp, " ' -- $c ));;\n");
-                }
-            }
-            break;
-        case eshellZSH:
-            for (i = 0; i < npargs; i++)
-            {
-                if (pa[i].type == etENUM)
-                {
-                    fprintf(fp, "- 'c[-1,%s]' -s \"", pa[i].option);
-                    for (j = 1; pa[i].u.c[j]; j++)
-                    {
-                        fprintf(fp, " %s", pa[i].u.c[j]);
-                    }
-                    fprintf(fp, "\" ");
-                }
-            }
-            break;
-    }
-}
-
-static void write_cshcompl(FILE *out,
-                           int nfile,  t_filenm *fnm,
-                           int npargs, t_pargs *pa)
-{
-    fprintf(out, "complete %s", ShortProgram());
-    pr_enums(out, npargs, pa, eshellCSH);
-    pr_fopts(out, nfile, fnm, eshellCSH);
-    pr_opts(out, nfile, fnm, npargs, pa, eshellCSH);
-    fprintf(out, "\n");
-}
-
-static void write_zshcompl(FILE *out,
-                           int nfile,  t_filenm *fnm,
-                           int npargs, t_pargs *pa)
-{
-    fprintf(out, "compctl ");
-
-    /* start with options, since they are always present */
-    pr_opts(out, nfile, fnm, npargs, pa, eshellZSH);
-    pr_enums(out, npargs, pa, eshellZSH);
-    pr_fopts(out, nfile, fnm, eshellZSH);
-    fprintf(out, "-- %s\n", ShortProgram());
-}
-
-static void write_bashcompl(FILE *out,
-                            int nfile,  t_filenm *fnm,
-                            int npargs, t_pargs *pa)
-{
-    /* Advanced bash completions are handled by shell functions.
-     * p and c hold the previous and current word on the command line.
-     * We need to use extended globbing, so write it in each completion file */
-    fprintf(out, "shopt -s extglob\n");
-    fprintf(out, "_%s_compl() {\nlocal p c\n", ShortProgram());
-    fprintf(out, "COMPREPLY=() c=${COMP_WORDS[COMP_CWORD]} p=${COMP_WORDS[COMP_CWORD-1]}\n");
-    pr_opts(out, nfile, fnm, npargs, pa, eshellBASH);
-    fprintf(out, "case \"$p\" in\n");
-
-    pr_enums(out, npargs, pa, eshellBASH);
-    pr_fopts(out, nfile, fnm, eshellBASH);
-    fprintf(out, "esac }\ncomplete -F _%s_compl %s\n", ShortProgram(), ShortProgram());
-}
-
-void write_man(const char *mantp,
-               const char *program,
+void write_man(const gmx::CommandLineHelpContext &context,
                int nldesc, const char **desc,
                int nfile, t_filenm *fnm,
                int npargs, t_pargs *pa,
                int nbug, const char **bugs)
 {
-    bool        bHidden = false;
+    FILE       *out     = context.writerContext().outputFile().handle();
+    const bool  bHidden = context.showHidden();
+
     int         npar;
     t_pargs    *par;
 
-    const gmx::CommandLineHelpContext *context
-        = gmx::GlobalCommandLineHelpContext::get();
-    bool  bFileOpened = false;
-    FILE *out;
-    if (context != NULL)
-    {
-        out     = context->writerContext().outputFile().handle();
-        bHidden = context->showHidden();
-    }
-    else
-    {
-        char buf[256];
-        sprintf(buf, "%s.%s", program, mantp);
-        out         = gmx_fio_fopen(buf, "w");
-        bFileOpened = true;
-    }
-
     if (bHidden)
     {
         npar = npargs;
@@ -892,43 +598,22 @@ void write_man(const char *mantp,
         }
     }
 
-    if (strcmp(mantp, "nroff") == 0)
+    switch (context.writerContext().outputFormat())
     {
-        GMX_RELEASE_ASSERT(context != NULL,
-                           "Man page export only implemented with the new context");
-        write_nroffman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
-                       *context);
-    }
-    if (strcmp(mantp, "help") == 0)
-    {
-        GMX_RELEASE_ASSERT(context != NULL,
-                           "Help export only implemented with the new context");
-        write_ttyman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
-                     context->writerContext());
-    }
-    if (strcmp(mantp, "html") == 0)
-    {
-        GMX_RELEASE_ASSERT(context != NULL,
-                           "HTML export only implemented with the new context");
-        write_htmlman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
-                      context->writerContext());
-    }
-    if (strcmp(mantp, "completion-zsh") == 0)
-    {
-        write_zshcompl(out, nfile, fnm, npar, par);
-    }
-    if (strcmp(mantp, "completion-bash") == 0)
-    {
-        write_bashcompl(out, nfile, fnm, npar, par);
-    }
-    if (strcmp(mantp, "completion-csh") == 0)
-    {
-        write_cshcompl(out, nfile, fnm, npar, par);
-    }
-
-    if (bFileOpened)
-    {
-        gmx_fio_fclose(out);
+        case gmx::eHelpOutputFormat_Man:
+            write_nroffman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
+                           context);
+            break;
+        case gmx::eHelpOutputFormat_Console:
+            write_ttyman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
+                         context.writerContext());
+            break;
+        case gmx::eHelpOutputFormat_Html:
+            write_htmlman(out, nldesc, desc, nfile, fnm, npar, par, nbug, bugs,
+                          context.writerContext());
+            break;
+        default:
+            GMX_THROW(gmx::NotImplementedError("Help format not implemented"));
     }
 
     if (!bHidden)
index ec5631451c8b5e71f2193aea622cd6e5fc279090..1137ab4b0e49588a300ca51c86ffc20cbceaf256 100644 (file)
 #include "gromacs/commandline/pargs.h"
 #include "gromacs/fileio/filenm.h"
 
-void write_man(const char *mantp, const char *program,
+namespace gmx
+{
+class CommandLineHelpContext;
+} // namespace gmx
+
+void write_man(const gmx::CommandLineHelpContext &context,
                int nldesc, const char **desc,
                int nfile, t_filenm *fnm,
                int npargs, t_pargs *pa,