2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 #include "gromacs/commandline/shellcompletions.h"
42 #include "gromacs/commandline/pargs.h"
43 #include "gromacs/fileio/filenm.h"
44 #include "gromacs/fileio/gmxfio.h"
46 #include "gromacs/legacyheaders/copyrite.h"
47 #include "gromacs/legacyheaders/smalloc.h"
49 // Shell types for completion.
51 eshellCSH, eshellBASH, eshellZSH
54 // TODO: Don't duplicate this from filenm.c/futil.c.
56 static const char *z_ext[NZEXT] = { ".gz", ".Z" };
58 static void pr_fopts(FILE *fp, int nf, const t_filenm tfn[], int shell)
63 for (int i = 0; i < nf; i++)
65 fprintf(fp, " \"n/%s/f:*.", tfn[i].opt);
66 const int ftp = tfn[i].ftp;
67 const int genericCount = ftp2generic_count(ftp);
71 const int *const genericTypes = ftp2generic_list(ftp);
72 for (int j = 0; j < genericCount; j++)
78 fprintf(fp, "%s", ftp2ext(genericTypes[j]));
84 fprintf(fp, "%s", ftp2ext(ftp));
87 for (int j = 0; j < NZEXT; j++)
89 fprintf(fp, ",%s", z_ext[j]);
95 for (int i = 0; i < nf; i++)
97 fprintf(fp, "%s) COMPREPLY=( $(compgen -X '!*.", tfn[i].opt);
98 const int ftp = tfn[i].ftp;
99 const int genericCount = ftp2generic_count(ftp);
100 if (genericCount > 0)
103 const int *const genericTypes = ftp2generic_list(ftp);
104 for (int j = 0; j < genericCount; j++)
110 fprintf(fp, "%s", ftp2ext(genericTypes[j]));
116 fprintf(fp, "%s", ftp2ext(ftp));
119 for (int j = 0; j < NZEXT; j++)
125 fprintf(fp, "%s", z_ext[j]);
127 fprintf(fp, ")' -f $c ; compgen -S '/' -X '.*' -d $c ));;\n");
131 for (int i = 0; i < nf; i++)
133 fprintf(fp, "- 'c[-1,%s]' -g '*.", tfn[i].opt);
134 const int ftp = tfn[i].ftp;
135 const int genericCount = ftp2generic_count(ftp);
136 if (genericCount > 0)
139 const int *const genericTypes = ftp2generic_list(ftp);
140 for (int j = 0; j < genericCount; j++)
146 fprintf(fp, "%s", ftp2ext(genericTypes[j]));
152 fprintf(fp, "%s", ftp2ext(ftp));
155 for (int j = 0; j < NZEXT; j++)
157 fprintf(fp, "|%s", z_ext[j]);
159 fprintf(fp, ") *(/)' ");
165 static void pr_opts(FILE *fp,
166 int nfile, t_filenm *fnm,
167 int npargs, t_pargs pa[], int shell)
172 fprintf(fp, " \"c/-/(");
173 for (int i = 0; i < nfile; i++)
175 fprintf(fp, " %s", fnm[i].opt+1);
177 for (int i = 0; i < npargs; i++)
179 if (pa[i].type == etBOOL && *(pa[i].u.b))
181 fprintf(fp, " no%s", pa[i].option+1);
185 fprintf(fp, " %s", pa[i].option+1);
191 fprintf(fp, "if (( $COMP_CWORD <= 1 )) || [[ $c == -* ]]; then COMPREPLY=( $(compgen -W '");
192 for (int i = 0; i < nfile; i++)
194 fprintf(fp, " -%s", fnm[i].opt+1);
196 for (int i = 0; i < npargs; i++)
198 if (pa[i].type == etBOOL && *(pa[i].u.b))
200 fprintf(fp, " -no%s", pa[i].option+1);
204 fprintf(fp, " -%s", pa[i].option+1);
207 fprintf(fp, "' -- $c)); return 0; fi\n");
210 fprintf(fp, " -x 's[-]' -s \"");
211 for (int i = 0; i < nfile; i++)
213 fprintf(fp, " %s", fnm[i].opt+1);
215 for (int i = 0; i < npargs; i++)
217 if (pa[i].type == etBOOL && *(pa[i].u.b))
219 fprintf(fp, " no%s", pa[i].option+1);
223 fprintf(fp, " %s", pa[i].option+1);
231 static void pr_enums(FILE *fp, int npargs, t_pargs pa[], int shell)
238 for (i = 0; i < npargs; i++)
240 if (pa[i].type == etENUM)
242 fprintf(fp, " \"n/%s/(", pa[i].option);
243 for (j = 1; pa[i].u.c[j]; j++)
245 fprintf(fp, " %s", pa[i].u.c[j]);
252 for (i = 0; i < npargs; i++)
254 if (pa[i].type == etENUM)
256 fprintf(fp, "%s) COMPREPLY=( $(compgen -W '", pa[i].option);
257 for (j = 1; pa[i].u.c[j]; j++)
259 fprintf(fp, " %s", pa[i].u.c[j]);
261 fprintf(fp, " ' -- $c ));;\n");
266 for (i = 0; i < npargs; i++)
268 if (pa[i].type == etENUM)
270 fprintf(fp, "- 'c[-1,%s]' -s \"", pa[i].option);
271 for (j = 1; pa[i].u.c[j]; j++)
273 fprintf(fp, " %s", pa[i].u.c[j]);
282 static void write_bashcompl(FILE *out,
283 int nfile, t_filenm *fnm,
284 int npargs, t_pargs *pa)
286 /* Advanced bash completions are handled by shell functions.
287 * p and c hold the previous and current word on the command line.
288 * We need to use extended globbing, so write it in each completion file */
289 fprintf(out, "shopt -s extglob\n");
290 fprintf(out, "_%s_compl() {\nlocal p c\n", ShortProgram());
291 fprintf(out, "COMPREPLY=() c=${COMP_WORDS[COMP_CWORD]} p=${COMP_WORDS[COMP_CWORD-1]}\n");
292 pr_opts(out, nfile, fnm, npargs, pa, eshellBASH);
293 fprintf(out, "case \"$p\" in\n");
295 pr_enums(out, npargs, pa, eshellBASH);
296 pr_fopts(out, nfile, fnm, eshellBASH);
297 fprintf(out, "esac }\ncomplete -F _%s_compl %s\n", ShortProgram(), ShortProgram());
300 static void write_cshcompl(FILE *out,
301 int nfile, t_filenm *fnm,
302 int npargs, t_pargs *pa)
304 fprintf(out, "complete %s", ShortProgram());
305 pr_enums(out, npargs, pa, eshellCSH);
306 pr_fopts(out, nfile, fnm, eshellCSH);
307 pr_opts(out, nfile, fnm, npargs, pa, eshellCSH);
311 static void write_zshcompl(FILE *out,
312 int nfile, t_filenm *fnm,
313 int npargs, t_pargs *pa)
315 fprintf(out, "compctl ");
317 /* start with options, since they are always present */
318 pr_opts(out, nfile, fnm, npargs, pa, eshellZSH);
319 pr_enums(out, npargs, pa, eshellZSH);
320 pr_fopts(out, nfile, fnm, eshellZSH);
321 fprintf(out, "-- %s\n", ShortProgram());
324 void write_completions(const char *type, const char *program,
325 int nfile, t_filenm *fnm,
326 int npargs, t_pargs *pa)
329 sprintf(buf, "%s.%s", program, type);
330 FILE *out = gmx_fio_fopen(buf, "w");
335 // Remove hidden arguments.
338 for (int i = 0; i < npargs; i++)
340 if (!is_hidden(&pa[i]))
347 if (strcmp(type, "completion-zsh") == 0)
349 write_zshcompl(out, nfile, fnm, npar, par);
351 if (strcmp(type, "completion-bash") == 0)
353 write_bashcompl(out, nfile, fnm, npar, par);
355 if (strcmp(type, "completion-csh") == 0)
357 write_cshcompl(out, nfile, fnm, npar, par);