diff options
author | Frank Terbeck <ft@bewatermyfriend.org> | 2011-06-02 10:50:35 +0200 |
---|---|---|
committer | Frank Terbeck <ft@bewatermyfriend.org> | 2011-06-02 10:50:35 +0200 |
commit | 2438a0e95aa448f0aeda468752444306b44fe7d0 (patch) | |
tree | 8477e9c6af360f6a89af13e8cb5f2a4f9c1cff2c | |
parent | b495ba1e5a3ab1396844490ad8cad17dec23d6c1 (diff) | |
parent | 21266db1d9ae433bf1dcb196a4e258c00541b599 (diff) | |
download | zsh-2438a0e95aa448f0aeda468752444306b44fe7d0.tar.gz zsh-2438a0e95aa448f0aeda468752444306b44fe7d0.zip |
Merge commit 'zsh-4.3.12' into debian
192 files changed, 11353 insertions, 5107 deletions
@@ -1,5 +1,878 @@ +2011-05-31 Peter Stephenson <pws@csr.com> + + * unposted: Config/version.mk: release 4.3.12. + +2011-05-29 Nikolai Weibull <now@bitwi.se> + + * unposted: Completion/Unix/Command/_git: Update git-branch completion + to deal with -r and -d correctly. + +2011-05-27 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 29403: Src/hist.c: histlexwords splitting of ";;" in case. + +2011-05-27 Mikael Magnusson <mikachu@gmail.com> + + * 28364: Doc/Zsh/zle.yo: Document that space left by wrapping + double-width characters is highlighted with the 'special' style. + + * 29384: Completion/Base/Completer/_expand, + Completion/Unix/Type/_have_glob_qual, + Completion/Unix/Type/_path_files, Completion/compinit: Add + _comp_caller_options and use it in completions that want to + check values of options that are overwritten by _comp_options. + + * 29334: Completion/Unix/Command/_sh: Complete options for zsh with + _arguments --. + + * 29392: Doc/Zsh/compsys.yo: Remove now-defunct use-perl style + documentation. + + * 29387: Completion/Unix/Command/.distfiles, + Completion/Unix/Command/_at: Add completion for at and friends. + + * 29385: Doc/Zsh/compsys.yo: Document when directories and + local-directories are used. + +2011-05-27 Barton E. Schaefer <schaefer@zsh.org> + + * 29382: Src/Modules/curses.c: apply 29374 to zccmd_input too. + +2011-05-27 Mikael Magnusson <mikachu@gmail.com> + + * 29331: NEWS: Note g:: parameter expansion flag. + + * 29365: Completion/Unix/Command/_make: redefine _make so that + helper functions are only defined once. + + * 29376: Completion/Unix/Command/_initctl: redefine _initctl so + that helper functions are only defined once. + + * unposted: Doc/Zsh/params.yo: Document that PROMPT_EOL_MARK can + be empty, forgot in 28480. + + * 29329: Src/math.c: Fix undefined behaviour in function argument + evaluation order. + +2011-05-26 Peter Stephenson <pws@csr.com> + + * unposted: Etc/CONTRIBUTORS: expand. + + * 29374: Src/Zle/zle_main.c: Exit ZLE immediately if exit + is pending when a keypress is expected. + +2011-05-25 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * Bernhard Tittelbach: 29371: Completion/Unix/Command/_initctl: + completion for initctl and related system job management + utilities. + +2011-05-24 Barton E. Schaefer <schaefer@zsh.org> + + * 29368: Src/exec.c: do not restore xtrerr to stderr before + running simple commands; restore xtrerr to stderr just before + running a function body, but after printing the trace of + the function call itself. + + * 29367: Test/E02xtrace.ztst: update tests to fix mistaken + assumptions introduced by 25145 and add check of redirection + inside a function body. + +2011-05-24 Mikael Magnusson <mikachu@gmail.com> + + * 29364: Completion/Unix/Command/_make: Partial fix for + completion in dirs with spaces and other unusual characters. + + * 29335: Completion/Linux/Command/_valgrind: Update the hack + for --tool= completion. + + * 29338: Completion/Base/Core/_main_complete: Correct pattern + checking for true value in insert-tab style. + +2011-05-23 Peter Stephenson <pws@csr.com> + + * unposted: Config/version.mk: 4.3.11-dev-4. + + * 29351: Src/subst.c: need to cast non-integer + stdarg arguments to integer to fit % prototype. + + * unposted: Completion/Unix/Command/_go: typo + + * 29341, corrected: Completion/Unix/Command/_go, + Completion/Unix/Command/.distfiles: basic completion for + commands associated with the Go programming language. + +2011-05-22 Mikael Magnusson <mikachu@gmail.com> + + * unposted: Doc/Zsh/compsys.yo, ChangeLog: Quote -e with tt(). + Fix some formatting in ChangeLog. + + * 29328: Completion/Redhat/Command/_rpm, + Completion/Unix/Command/_git, Completion/Unix/Command/_gnutls, + Completion/Unix/Command/_gpg, Completion/Unix/Command/_growisofs, + Completion/Unix/Command/_php: Another missing backslash in _git, + remove some not needed backslashes in array definitions. + +2011-05-19 Mikael Magnusson <mikachu@gmail.com> + + * 29224: Doc/Zsh/expn.yo, NEWS, Src/subst.c, + Test/D04parameter.ztst: Support negative LEN in ${VAR:OFFSET:LEN} + like bash. + + * 29261: Doc/Zsh/expn.yo, Src/subst.c, Test/D04parameter.ztst: + Add g:: parameter expansion flag. Add note that s:: can take an + empty string. + + * 29307, 29308 + replies: Completion/BSD/Command/_bsd_pkg, + Completion/Base/Utility/_sep_parts, Completion/Unix/Command/_git, + Completion/Unix/Command/_osc, Completion/Unix/Command/_perforce, + Completion/compinit, Completion/openSUSE/Command/_osc, + Completion/openSUSE/Command/_zypper, Doc/Zsh/builtins.yo, + Doc/Zsh/calsys.yo, Doc/Zsh/compctl.yo, Doc/Zsh/compsys.yo, + Doc/Zsh/compwid.yo, Doc/Zsh/contrib.yo, + Doc/Zsh/expn.yo, Doc/Zsh/zle.yo, Etc/CONTRIBUTORS, + Functions/Calendar/calendar_parse, Functions/Misc/sticky-note, + Functions/TCP/tcp_read, Functions/Zftp/zfcput, Src/Zle/compctl.c, + Src/Zle/zle_hist.c, Src/exec.c, Src/hist.c, Src/jobs.c, Src/lex.c, + Src/math.c, Src/params.c, Src/subst.c: Fix some doubled words in + docs and comments. + +2011-05-18 Wayne Davison <wayned@users.sourceforge.net> + + * Valentin Haenel: 29315: Completion/Unix/Command/_git: add a + missing backslash. + +2011-05-17 Barton E. Schaefer <schaefer@zsh.org> + + * unposted: Doc/Zsh/options.yo: tweak description of the -l (LOGIN) + option for clarity. + + * 29313: Src/subst.c: when SHWORDSPLIT is in effect, the state of + the (@) expansion flag depends on the value of $IFS so as to mimic + Bourne shell join/split behavior more closely (see users/15442). + + * 29312, users/16032: Doc/Zsh/mod_zutil.yo, Src/Modules/zutil.c: + add "zparseopts -M" which allows option descriptions to map + synonymous option names onto a single name. + +2011-05-17 Clint Adams <clint@zsh.org> + + * 29306: Completion/Debian/Command/_make-kpkg: typo fix + from Laurent Fousse. + +2011-05-17 Frank Terbeck <ft@bewatermyfriend.org> + + * Nikolai Weibull: 29166: Completion/Unix/Command/_git: Speed + improvements for file completion. + +2011-05-17 Nikolai Weibull <now@bitwi.se> + + * 29273: Completion/Unix/Command/_git: Parse compadd options in + __git_guard_number. + +2011-05-14 Barton E. Schaefer <schaefer@zsh.org> + + * 29278: Completion/Unix/Type/_path_files: fix use of the $skips + pattern from the squeeze-slashes style. + +2011-05-14 Mikael Magnusson <mikachu@gmail.com> + + * 29271: Doc/Zsh/compwid.yo: document _alternative -O name. + +2011-05-14 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 29282: Src/mem.c: hide prototypes for ZSH_HEAP_DEBUG with + #ifdef's. + +2011-05-14 Bart Schaefer <schaefer@zsh.org> + + * 29276: Src/zsh.h: typedef Heapid unconditionally, to prevent + compile errors in automatically-generated header files. + +2011-05-14 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 29268: Src/Zle/compcore.c: dupstring() the value that's + going to be used for prpre, whatever the heck that is. + + * 29267: configure.ac, Src/mem.c, Src/zsh.h, Src/Zle/comp.h, + Src/Zle/compcore.c, Src/Zle/compctl.c, Src/Zle/complist.c, + Src/Zle/compresult.c: add --enable-zsh-heap-debug and use + for debugging completion matcher groups. + +2011-05-13 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * Danek: 29254: Src/cond.c, Src/Builtins/rlimits.c, + Src/Modules/datetime.c, Src/Modules/zftp.c, Src/Zle/computil.c: + fix some compiler warnings. + +2011-05-13 Peter Stephenson <pws@csr.com> + + * Jérémie Roquet: 29258: Src/Zle/zle_utils.c: mark a couple + more functions for export. + + * unposted (late commit): Completion/Unix/Command/.distfiles, + Config/version.mk, Test/.distfiles: update for 4.3.11-dev-3. + +2011-05-12 Mikael Magnusson <mikachu@gmail.com> + + * 29245: Completion/X/Command/_xset: pass -O instead of -o + to _describe. + + * Nikolai Weibull: 29124: Completion/Unix/Command/_git: Fix + -l option. + + * 29205: Completion/Unix/Type/_pids: don't sort processes. + + * 29208: Src/Zle/zle_move.c: make vimatchbracket check the + character left of the cursor when at the end of the line. + +2011-05-11 Mikael Magnusson <mikachu@gmail.com> + + * 29206: Doc/Zsh/mod_complist.yo: fix formatting. + +2011-05-11 Peter Stephenson <pws@csr.com> + + * 29217: Src/zsh.mdd: zshterm.h and zshcurses.h are now + dependencies for the main shell. + +2011-05-10 Peter Stephenson <pws@csr.com> + + * unposted: Src/.distfiles, Src/system.h, Src/zsh.mdd, + Src/zsh_system.h: rename system.h to zsh_system.h to ensure + there are no clashes. + + * 29214: Src/Makemod.in.in, Src/mkmakemod.sh, Src/zsh.mdd: use + -I to find headers in order to allow #include'ing generated + headers from non-generated headers when the build tree is + separate from the source tree. + + * 29191 (Danek) and 29203 (with fixes): Doc/Zsh/params.yo, + Src/params.c: make TERMINFO variable special. + +2011-05-09 Peter Stephenson <pws@csr.com> + + * 29195: Src/.distfiles, Src/hashnameddir.c, Src/hashtable.c, + Src/system.h, Src/zsh.mdd: Separate out hash handling for named + directories in order to keep RCP header usage from curses to + avoid clash on Solaris 8. + + * 29193: Src/text.c: fix variable declaration that was after + code. + + * 29165: Src/builtin.c, Src/exec.c, Src/glob.c, Src/hashtable.c, + Src/init.c, Src/jobs.c, Src/loop.c, Src/params.c, Src/prompt.c, + Src/system.h, Src/utils.c, Src/Modules/files.c, + Src/Modules/termcap.c, Src/Modules/zpty.c, Src/Zle/comp.h, + Src/Zle/complist.c, Src/Zle/compmatch.c, Src/Zle/compresult.c, + Src/Zle/computil.c, Src/Zle/zle_refresh.c, Src/Zle/zle_tricky.c, + Src/Zle/zle_utils.c: Use term.h globally if needed, instead of + just using in Modules and fudging the headers elsewhere. Fix + various name clashes. + +2011-05-08 Barton E. Schaefer <schaefer@zsh.org> + + * users/15986 (belated commit): Src/Modules/curses.c: handle + EINTR in zccmd_input. + +2011-05-08 Wayne Davison <wayned@users.sourceforge.net> + + * Valentin Haenel: 29187: Completion/Unix/Command/_git: add a + missing backslash. + +2011-05-07 Barton E. Schaefer <schaefer@zsh.org> + + * 29175 (w/comment typo fixed): Src/mem.c: optimize freeheap. + +2011-05-07 Frank Terbeck <ft@bewatermyfriend.org> + + * 29170: Doc/Zsh/contrib.yo: vcs_info: Clarify check-for-changes + style behaviour with the mercurial backend. + + * unposted: Doc/Zsh/contrib.yo: Add missing word ("style") spotted + by Bart. + +2011-05-06 Peter Stephenson <pws@csr.com> + + * 29163: README, Etc/FAQ.yo: update latest version claimed + to 4.3.12. + +2011-05-04 Barton E. Schaefer <schaefer@zsh.org> + + * 29140: Completion/bashcompinit: introduce function-scope wrapper + around the call to the bash completion function; in this wrapper, + hide the "words" special variable so that it may be used as an + ordinary variable by the bash completions. + +2011-05-04 Peter Stephenson <pws@csr.com> + + * Rocky Bernstein: 29135 (plus tweaks): Completion/bashcompinit, + Test/.distfiles, Test/Y04compgen.ztst, Test/compgentest: fix and + test "compgen -W" in bash completion. + + * unposted: NEWS: a few notes for next release. + +2011-05-03 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * Haakon Riiser: 29137: Completion/Unix/Command/_ffmpeg: better + handling of flags. + +2011-05-03 Peter Stephenson <pws@csr.com> + + * 29134: Src/prototypes.h: change termcap prototypes for AIX + locally until we find the header. + +2011-05-02 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 29129: Src/exec.c: reading off end of file descriptor array + noticed by Vincent. + +2011-05-01 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * Haakon Riiser: unposted: Completion/Unix/Command/_ffmpeg: more + tweaks. + +2011-04-30 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * Haakon Riiser: 29100: Completion/Unix/Command/_ffmpeg: Clean + up and add dependencies. + + * 29114: Doc/Makefile.in, Doc/Zsh/.distfiles, + Doc/Zsh/ftp_sites.yo, Doc/Zsh/metafaq.yo, Etc/FAQ.yo: Use same + FTP sites list in META-FAQ as FAQ. + + * İsmail Dönmez: 29020: Completion/openSUSE/Command/_SuSEconfig, + Completion/openSUSE/Command/_hwinfo, + Completion/openSUSE/Command/_osc, + Completion/openSUSE/Command/_yast2, + Completion/openSUSE/Command/_zypper (plus .distfiles): new + completions. + +2011-04-29 Barton E. Schaefer <schaefer@zsh.org> + + * 29107: Src/Zle/zle_tricky.c: replace overlapping strcpy with + memmove. + +2011-04-27 Mikael Magnusson <mikachu@gmail.com> + + * 29051: Completion/Unix/Command/_make: add _make- prefix to + internal helper functions. + +2011-04-26 Wayne Davison <wayned@users.sourceforge.net> + + * 29053 (modified): Src/prototypes.h: Use "const" qualifier + in termcap prototypes. + +2011-04-25 Frank Terbeck <ft@bewatermyfriend.org> + + * Felipe Contreras: 29028: Completion/Unix/Command/_git: Add + useful completion for `gitk'. + + * Simon Ruderich: 29041: Completion/Unix/Command/_git: Add + completion for `tig' like the one for `gitk' from 29028. + + * unposted: Functions/Zle/edit-command-line: Revert change from + 28896, which did more evil than good. + +2011-04-24 Barton E. Schaefer <schaefer@zsh.org> + + * Jun T.: 29031: Src/Zle/complist.c: increment global minfo + state when inserting characters on the line during interactive + menu selection. + +2011-04-21 Barton E. Schaefer <schaefer@zsh.org> + + * 29025: Test/A01grammar.ztst: in select test, assert LINES=3 + along with COLUMNS=80 so that the selectlist is sure to be + printed where the control script can capture/examine it. + +2011-04-21 Frank Terbeck <ft@bewatermyfriend.org> + + * Valentin Haenel: 29019, Completion/Unix/Command/_git: Fix git + stash completion (apply and pop subcommands). + + * 29027: Completion/Unix/Command/_screen: support "/dev/ttyUSB0 + [baud]"-style arguments. + + * unposted: INSTALL: Clarify at which point directories from + --enable-additional-fpath are added to $fpath. + +2011-04-19 Peter Stephenson <pws@csr.com> + + * unposted: Completion/X/Command/.distfiles, Config/version.mk: + development version 4.3.11-dev-2. + + * unposted: Completion/Unix/Command/_perforce: don't complete p4 + reopen to same change. + +2011-04-18 Frank Terbeck <ft@bewatermyfriend.org> + + * 29008, 29012: Config/defs.mk.in, Src/init.c, Src/zsh.mdd, + configure.ac, INSTALL: Add `--enable-additional-fpath' option to + add arbitrary directories to the default `$fpath'. + +2011-04-18 Peter Stephenson <pws@csr.com> + + * Simon Ruderich: 29004: M Doc/Zsh/compsys.yo, + Doc/Zsh/metafaq.yo, Etc/FAQ.yo: update archive list. + +2011-04-15 Wayne Davison <wayned@users.sourceforge.net> + + * Unposted: Src/Zle/computil.c: Fix compiler warning caused by + duplicate initialization of state.doff. + +2011-04-15 Frank Terbeck <ft@bewatermyfriend.org> + + * Simon Ruderich: 28927: Completion/Unix/Command/_git: Fix "git + tag -v" completion. + +2011-04-15 Mikael Magnusson <mikachu@gmail.com> + + * 28998: Completion/Unix/Command/_make: set return status + correctly. + +2011-04-14 Peter Stephenson <pws@csr.com> + + * 28997: configure.ac, Src/system.h: make --enable-libc-musl + explicit. + +2011-04-13 Peter Stephenson <pws@csr.com> + + * gi1242+zsh: 28991: Completion/Unix/Command/_subversion: fix + caching policy for subversion. + +2011-04-12 Peter Stephenson <pws@csr.com> + + * Valentin Ochs: 28990: configure.ac, Src/system.h: more + changes needed for signals. + + * Valentin Ochs: 28989: configure.ac: define _POSIX_C_SOURCE + when testing for sigset_t (needed for musl). + +2011-04-11 Peter Stephenson <pws@csr.com> + + * users/15953: Src/builtin.c: handle EINTR when using read -k or + -q together with -u or -p. + + * cat.in.136: users/15945: Completion/Redhat/Command/_yum: + various corrections and updates. + +2011-04-05 Wayne Davison <wayned@users.sourceforge.net> + + * 28977: Src/utils.c: fix copying of uninitialized memory + when trying to spell-correct a really long string. + +2011-04-01 Peter Stephenson <pws@csr.com> + + * Stef van Vlierberghe: 28965 (as posted in 28967): + findproc() should not return processes not marked as SP_RUNNING + since findproc() is used find processes still known to the OS. + +2011-03-30 Frank Terbeck <ft@bewatermyfriend.org> + + * Mike Meyer: 28956, 28957: + Functions/VCS_Info/Backends/VCS_INFO_detect_fossil, + Functions/VCS_Info/Backends/VCS_INFO_get_data_fossil, + Doc/Zsh/contrib.yo: Add fossil support to vcs_info. + + * unposted: Functions/VCS_Info/Backends/.distfiles: Add + new backend files to `.distfiles'. + + * unposted: ChangeLog: Fix typo in date. + + * 28958: Functions/VCS_Info/VCS_INFO_hook: Support registering + hooks independent of the context. + + * 28960: Doc/Zsh/contrib.yo, Functions/VCS_Info/.distfiles, + Functions/VCS_Info/vcs_info, Functions/VCS_Info/vcs_info_hookadd, + Functions/VCS_Info/vcs_info_hookdel: Add functions to add/remove + static hooks. + + * 28961: Doc/Zsh/contrib.yo, Functions/VCS_Info/VCS_INFO_set: Add + `no-vcs' hook. + + * 28959: Doc/Zsh/contrib.yo, Functions/VCS_Info/VCS_INFO_set, + Functions/VCS_Info/vcs_info: Make the nvcsformats style be used if + vcs_info is disabled. + +2011-03-29 Mikael Magnusson <mikachu@gmail.com> + + * unposted: Completion/Unix/Command/_vim: Fix typo in + description for -N. + +2011-03-29 Peter Stephenson <pws@csr.com> + + * Mikael: 28948: Completion/compinit, Doc/Zsh/compsys.yo: + compdef -e overrides interpretation of argument as service. + +2011-03-27 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * Mikael: 28941: Src/Zle/zle_params.c: accessing cursor with + metafied line was problematic. + +2011-03-21 Peter Stephenson <pws@csr.com> + + * 28936: Src/subst.c: ${#$} and ${#?} also didn't work. + +2011-03-20 Frank Terbeck <ft@bewatermyfriend.org> + + * Johan Sundström: 28890: Completion/Unix/Command/.distfiles, + Completion/Unix/Command/_npm: New _npm completion. + +2011-03-19 Barton E. Schaefer <schaefer@zsh.org> + + * 28926: Src/Zle/zle_tricky.c: No newline after the last line in + listlist() when printing the list in a single column. + +2011-03-18 Frank Terbeck <ft@bewatermyfriend.org> + + * Nikolai Weibull: 28914: Completion/Unix/Command/_git: Typo + fix in `cvsexportcommit' description. + + * Nikolai Weibull: 28911: Completion/Unix/Command/_git: Only show + modified files for git-checkout without tree. + + * Nikolai Weibull: 28913: Completion/Unix/Command/_git: Fix typo + which broke `send-email' completion. + +2011-03-16 Frank Terbeck <ft@bewatermyfriend.org> + + * 28896: Functions/Zle/edit-command-line: unset `monitor' option + while the widget is running to avoid accidential data loss. + +2011-03-16 Peter Stephenson <pws@csr.com> + + * Mikael: users/15875: Completion/Unix/Command/_gpg: use return + status from _arguments. + +2011-03-11 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28889: Src/subst.c, Test/D04parameter.ztst: ${##} should + return the length of $#. + +2011-03-11 Barton E. Schaefer <schaefer@zsh.org> + + * Greg Klanderman: 28887: Completion/Zsh/Type/_command_names: + fix quoting in defs array. + +2011-03-11 Peter Stephenson <pws@csr.com> + + * unposted: Completion/Zsh/Context/_dynamic_directory_name: + Mikael spotted that completion doesn't work if + $zsh_directory_name_functions is set but zsh_directory_name + isn't defined. + + * users/15864: Completion/Zsh/Context/_dynamic_directory_name, + Doc/Zsh/contrib.yo, Doc/Zsh/expn.yo, Functions/Chpwd/.distfiles, + Functions/Chpwd/zsh_directory_name_cdr, + Functions/Misc/add-zsh-hook, Src/subst.c, Src/utils.c: + turn zsh_directory_name into a hook. + + * 28886: Src/Zle/zle_utils.c: Fix 28772 for the case where + regions have the "P" flag to include $PREDISPLAY in the + offsets. + +2011-03-08 Barton E. Schaefer <schaefer@zsh.org> + + * Greg Klanderman: 28846: Completion/Zsh/Type/_functions, + Completion/Zsh/Type/_command_names, + Completion/Zsh/Type/_parameters, Doc/Zsh/compsys.yo: adapt + prefix-needed zstyle to handle the completion function naming + convention of a leading underscore. + +2011-03-06 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28866: Src/exec.c, Test/A04redirect.ztst: With POSIX_BUILTINS, + "command" prefix tops a command having special behaviour. + +2011-03-05 Barton E. Schaefer <schaefer@zsh.org> + + * Adrian: 28857: Functions/Prompts/prompt_bigfade_setup: use %d + instead of $PWD + +2011-03-04 Frank Terbeck <ft@bewatermyfriend.org> + + * 28853: Doc/Zsh/contrib.yo, Doc/Zsh/expn.yo, Functions/Chpwd/cdr, + Src/builtin.c, Src/prompt.c: Fix typo: preceed -> precede + +2011-03-02 Barton E. Schaefer <schaefer@zsh.org> + + * 28805: Doc/Zsh/builtins.yo, Doc/Zsh/mod_sched.yo: move stray + text about the sched builtin away from the set builtin. + +2011-03-01 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * Baptiste: 28819: Completion/BSD/Command/_sockstat, + Completion/Unix/Command/_mount, + Completion/Unix/Type/_file_systems: FreeBSD completion tweaks. + +2011-02-28 Barton E. Schaefer <schaefer@zsh.org> + + * 28823: Src/builtin.c: make it an error to tie the same scalar to + two different arrays (prevents crash bug); improve a couple of + other error messages. + +2011-02-28 Peter Stephenson <pws@csr.com> + + * Frank, 28812, modified as in 28813: Src/string.c: wcs_ztrdup() + needs to allocate array of wchar_t. Looks like this isn't + currently used anywhere. + +2011-02-27 Wayne Davison <wayned@users.sourceforge.net> + + * Nikolai Weibull: 28649,28804: Completion/Unix/Command/_git: + Latest version copied from https://github.com/now/zsh. + +2011-02-24 Peter Stephenson <pws@csr.com> + + * 28799: Src/lex.c: fix bug introduced with lexflags + that lexical analyser didn't stop quickly enough when + retrieving completion words. + +2011-02-23 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28795: Src/exec.c: tweak to 28791 for forked shells. + Also (unposted) typos in comments noticed by Mikael. + +2011-02-22 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28791: Doc/Zsh/options.yo, Src/builtin.c, Src/exec.c, + Test/A04redirect.ztst: exit on errors in special builtins + with POSIXBUILTINS. + +2011-02-21 Peter Stephenson <pws@csr.com> + + * 28783: Doc/Zsh/options.yo, Src/lex.c, Test/A01grammar.ztst: + allow ( to be treated specially in more places when SH_GLOB + is set but KSH_GLOB isn't. + + * 28784: Doc/Zsh/options.yo, Test/A04redirect.ztst, Src/exec.c: + exit on exec redirection error with POSIXBUILTINS. + +2011-02-19 Frank Terbeck <ft@bewatermyfriend.org> + + * 28776: Functions/VCS_Info/VCS_INFO_bydir_detect, + Functions/VCS_Info/Backends/VCS_INFO_detect_hg, + Functions/VCS_Info/Backends/VCS_INFO_get_data_hg: Let + vcs_info detect very old mercurial repositories. + + +2011-02-18 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28773, Doc/Zsh/zle.yo, Src/zle_hist.c: add + zle-history-line-set widget. + + * 28772: Doc/Zsh/zle.yo, Src/Zle/compcore.c, + Src/Zle/compresult.c, Src/Zle/zle.h, Src/Zle/zle_refresh.c, + Src/Zle/zle_tricky.c, Src/Zle/zle_utils.c: update regions + in $region_highlight dynamically. + +2011-02-17 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28761: Completion/Unix/Command/_sccs: file completion missing + for some commands. + + * 28762: Src/exec.c: logic for closing coproc file descriptors + was wrong. + +2011-02-15 Frank Terbeck <ft@bewatermyfriend.org> + + * 28758: Functions/Misc/colors: work with non-default option sets. + +2011-02-13 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28750 with some extra comments: + Completion/Unix/Type/_path_files: separate out completeinword + handling where the current component is not the last but is + the first from the already handled case where there is a further + component in front. + +2011-02-11 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28671: Src/Zle/zle_utils.c: better cursor positioning + after undo. + + * users/15738: Functions/Zle/modify-current-argument: better + positioning of the cursor after the operation. + +2011-02-11 Frank Terbeck <ft@bewatermyfriend.org> + + * Lennart Weller: 28739: + Functions/VCS_Info/Backends/VCS_INFO_detect_svn: Fix svn + detection in vcs_info. + +2011-02-10 Barton E. Schaefer <schaefer@zsh.org> + + * users/15759 (slightly augmented): Functions/Zle/send-invisible, + Functions/Zle/.distfiles: widget to read a concealed string from + the keyboard and stash it in $INVISIBLE. + + * users/15770: Src/init.c: disable HASH_DIRS when not interactive. + + * 28710: Completion/Debian/Type/_deb_packages: replace complex + parameter expansion with command substitution to speed diffing + of large lists of packages. + + * unposted: Doc/Zsh/contrib.yo: add send-invisible. Re-order + some other entries to restore approximate alphabetization. + +2011-01-24 Clint Adams <clint@zsh.org> + + * Carl Worth: 28648: Completion/Unix/Command/_notmuch: notmuch + completion by Ingmar Vanhassel. + +2011-01-23 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * gi1242+zsh@gmail.com: 28647: Completion/X/Command/_vnc: more + options. + + * gi1242+zsh@gmail.com: 28646: Completion/X/Command/_matlab: new + completion. + +2011-01-19 Peter Stephenson <pws@csr.com> + + * 28638: Doc/Zsh/parameter.yo, Src/zsh.h, + Src/Modules/parameter.c, plus NEWS added: add $usergroups hash + mapping from user's own groups by name to GID. + +2011-01-18 Peter Stephenson <pws@csr.com> + + * Mikael: 28637: Src/subst.c: ${foo:0:} caused crash. + +2011-01-17 Peter Stephenson <pws@csr.com> + + * Atom Smasher: users/15715: Completion/Zsh/Function/_zargs: new + +2011-01-16 Wayne Davison <wayned@users.sourceforge.net> + + * unposted: Config/defs.mk.in, configure.ac: use the -L option + with yodl 3.x. + +2011-01-16 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28631: gi1242+zsh@gmail.com (as in 28633): + Completion/Unix/Command/.distfiles, Completion/Unix/Command/_lp, + Completion/Unix/Command/_tex, Completion/Unix/Command/_xournal, + Completion/Unix/Type/.distfiles, Completion/Unix/Type/_tex, + Completion/X/Command/.distfiles, Completion/X/Command/_xournal: + various updates. + + * 28634: Test/D04parameter.ztst: test for 28630. + + * Ricky Zhou: 28630: Src/params.c: fix crash with isident. + + * gi1242+zsh@gmail.com: 28629: Completion/Unix/Command/.distfiles, + Completion/Unix/Command/_lp, Completion/Unix/Command/_tex, + Completion/Unix/Command/_xournal, + Completion/Unix/Type/.distfiles, Completion/Unix/Type/_tex, + Completion/X/Command/.distfiles, Completion/X/Command/_xournal: + completion updates. + +2011-01-16 Clint Adams <clint@zsh.org> + + * unposted: Completion/Unix/Command/_fuser: fix typo in pattern + +2011-01-13 Peter Stephenson <pws@csr.com> + + * c.f. 28628: Doc/Zsh/func.yo: some extra notes on traps. + +2011-01-11 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * unposted: Src/params.c: fix return types in 28617. + + * 28611: Src/Zle/zle_move.c: remove unused special behaviour for + VI mark 26. + +2011-01-11 Peter Stephenson <pws@csr.com> + + * 28626: Doc/Zsh/func.yo: summarise differences between two + types of trap. + +2011-01-10 Peter Stephenson <pws@csr.com> + + * 28617: Src/glob.c, Src/params.c, Test/E01options.ztst: NO_EXEC + option was doing to much work with parameter subscripting, + parameter assignments, and globbing. + +2011-01-09 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28544: Src/Makefile.in, Makemod.in.in: another way of handling + bad dependencies for 'make prep' as in 28541. + + * gi1242+zsh@gmail.com: 28594 (with changes as in 28598): + Completion/Linux/Command/.distfiles, + Completion/Linux/Command/_modutils, + Completion/Linux/Command/_wpa_cli, + Completion/Unix/Command/.distfiles, Completion/Unix/Command/_lp, + Completion/Unix/Command/_pgrep, + Completion/Unix/Command/_subversion, + Completion/Unix/Command/_unison, + Completion/Unix/Command/_xournal, Completion/Unix/Type/_pdf, + Completion/X/Command/.distfiles, Completion/X/Command/_gv, + Completion/X/Command/_okular, Completion/X/Command/_pdftk, + Completion/X/Command/_vnc, Completion/X/Command/_xrandr: Various + new and improved completions. + +2011-01-07 Peter Stephenson <pws@csr.com> + + * 28590 (added a comment): Src/builtin.c, Test/B04read.ztst: + read builtin should return non-zero status on error. + + * Mikael: 28585: Completion/Unix/Command/_mkdir: don't set ret=0 + when _wanted fails to find any matches. + +2011-01-06 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * unposted: Src/utils.c: fix argument type for write_loop(). + + * 28588: Src/text.c, Test/C02cond.ztst: fix textual display + after =~ test. + + * Ben: 28574: Completion/Unix/Command/_ri: use bs formatter. + +2011-01-06 Barton E. Schaefer <schaefer@zsh.org> + + * 28579: Completion/Unix/Command/_du: propagate failure status + from _arguments so that _complete will try other completions. + + * 28578 (plus test): Src/utils.c, Src/zsh.h, Test/B03print.ztst: + fix handling of numeric escapes that expand to "%" in printf + format strings, so they are not treated as format introducers. + +2011-01-05 Peter Stephenson <p.w.stephenson@ntlworld.com> + + * 28568 c.f. 28549 (Ricky Zhou): Src/utils.c: buffer overflow + examining paths. + + * Alexey: 28557: Completion/Unix/Command/_ri: update for new + versions of Ruby. + +2010-12-25 Clint Adams <clint@zsh.org> + + * 28548: Completion/Unix/Command/_fuser: match psmisc in any case. + +2010-12-21 Barton E. Schaefer <schaefer@zsh.org> + + * users/15662: Src/params.c: fix array slice assignment with one + index positive and one negative. + + * unposted: Test/A06assign.ztst: tests for users/15662. + +2010-12-21 Peter Stephenson <pws@csr.com> + + * users/15663: Test/A06Assign.ztst: some (incomplete) array + assignment tests. + + * unposted: Config/version.mk: update version to 4.3.11-dev-1. + 2010-12-20 Peter Stephenson <pws@csr.com> + * unposted: Src/Makefile.inc: restore unintentionally removed + .PHONY entires. + + * unposted: Config/version.mk, Src/Makefile.inc: release 4.3.11. + Tweak to Src/Makefile.inc was to workaround some make problem + with timestamps. + * Paul Ackersviller: 28538: as modified in 28540 plus a couple of casts to char * I missed: Src/init.c,Src/input.c, Src/parse.c, Src/prototypes.h, Src/utils.c, Src/Zle/zle_main.c: @@ -995,7 +1868,7 @@ * users/15011: Completion/Unix/Type/_path_files, Doc/Zsh/compsys.yo: add path-completion style to allow - completion of preceeding directories in files to be be turned + completion of preceding directories in files to be be turned off. 2010-04-13 Peter Stephenson <pws@csr.com> @@ -14010,5 +14883,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5161 $ +* $Revision: 1.5346 $ ***************************************************** diff --git a/Completion/BSD/Command/.distfiles b/Completion/BSD/Command/.distfiles index 86530b8ea..d08edf814 100644 --- a/Completion/BSD/Command/.distfiles +++ b/Completion/BSD/Command/.distfiles @@ -15,4 +15,5 @@ _portmaster _portsnap _powerd _procstat +_sockstat ' diff --git a/Completion/BSD/Command/_bsd_pkg b/Completion/BSD/Command/_bsd_pkg index 8cc1a6230..9f4b0f11a 100644 --- a/Completion/BSD/Command/_bsd_pkg +++ b/Completion/BSD/Command/_bsd_pkg @@ -178,7 +178,7 @@ _bsd_pkg() { '-m[show mtree files]' '-p[show installation prefixes]' '-q[be quiet]' - '-R[show list list of installed requiring packages]' + '-R[show list of installed requiring packages]' '-r[show requirements scripts]' '-v[be verbose]' ) diff --git a/Completion/BSD/Command/_sockstat b/Completion/BSD/Command/_sockstat new file mode 100644 index 000000000..2acbe6bec --- /dev/null +++ b/Completion/BSD/Command/_sockstat @@ -0,0 +1,23 @@ +#compdef sockstat + +local tmp_proto protocols proto + +tmp_proto=(${${(M)${(f)"$(</etc/protocols)"}##[a-z0-9]*}}) +for proto ($tmp_proto) { + case $proto in + *\#*) + protocols=($protocols ${${(j: :)${=proto}}// *\# /:}) + ;; + *) + protocols=($protocols ${${(j: :)${=proto}}// */}) + esac +} + +_arguments -s \ + '-4[Show AF_INET (IPv4) sockets]' \ + '-6[Show AF_INET6 (IPv6) sockets]' \ + '-c[Show connected sockets]' \ + '-l[Show listening sockets]' \ + '-u[Show AF_LOCAL (UNIX) sockets]' \ + '-p[Only show Internet sockets if the port number is on the specified list]' \ + '-P[Only show sockets of the specified protocols]:protocols:(($protocols))' diff --git a/Completion/Base/Completer/_expand b/Completion/Base/Completer/_expand index 89cc969c5..44954a2a8 100644 --- a/Completion/Base/Completer/_expand +++ b/Completion/Base/Completer/_expand @@ -70,7 +70,7 @@ if [[ "$force" = *s* ]] || ### parameter expressions such as ${foo} be expanded like brace ### expansions, too (and with braceccl set...). - if [[ ! -o ignorebraces && "${#${exp}//[^\{]}" = "${#${exp}//[^\}]}" ]]; then + if [[ ! $_comp_caller_options[ignorebraces] == on && "${#${exp}//[^\{]}" = "${#${exp}//[^\}]}" ]]; then local otmp tmp=${(q)word} diff --git a/Completion/Base/Core/_main_complete b/Completion/Base/Core/_main_complete index c7d0d5f4d..c50ff9db4 100644 --- a/Completion/Base/Core/_main_complete +++ b/Completion/Base/Core/_main_complete @@ -51,7 +51,7 @@ if [[ ( "$tmp" = *pending(|[[:blank:]]*) && PENDING -gt 0 ) || fi if [[ "$compstate[insert]" = tab* ]]; then - { [[ "$tmp" = (|[[:blank:]]*)(yes|true|on|1)(|[[:blank:]]*) ]] && + { [[ "$tmp" = (|*[[:blank:]])(yes|true|on|1)(|[[:blank:]]*) ]] && { [[ "$curcontext" != :* || -z "$compstate[vared]" ]] || zstyle -t ":completion:vared${curcontext}:" insert-tab } } && return 0 diff --git a/Completion/Base/Utility/_sep_parts b/Completion/Base/Utility/_sep_parts index 6e6c1beed..de836a696 100644 --- a/Completion/Base/Utility/_sep_parts +++ b/Completion/Base/Utility/_sep_parts @@ -96,7 +96,7 @@ suffixes=("") autosuffix=() while [[ $# -gt 0 && "$str" == *${1}* ]]; do - # Remove anything up to the the suffix. + # Remove anything up to the suffix. str="${str#*${1}}" diff --git a/Completion/Debian/Command/_make-kpkg b/Completion/Debian/Command/_make-kpkg index 68ddadc1e..c079d9aa0 100644 --- a/Completion/Debian/Command/_make-kpkg +++ b/Completion/Debian/Command/_make-kpkg @@ -35,7 +35,7 @@ _arguments \ kernel-source\:"package of the kernel sources" \ kernel-headers\:"package of the header files included in the kernel" \ kernel-manual\:"package of the manual pages included in the kernel" \ - kernel-doc\:"package of teh documentation included in the kernel" \ + kernel-doc\:"package of the documentation included in the kernel" \ kernel-image\:"package of the kernel image" \ build\:"compiles the kernel" \ modules\:"build all add-on modules" \ diff --git a/Completion/Debian/Type/_deb_packages b/Completion/Debian/Type/_deb_packages index dea50cfdc..74b151844 100644 --- a/Completion/Debian/Type/_deb_packages +++ b/Completion/Debian/Type/_deb_packages @@ -71,8 +71,10 @@ _deb_packages_update_uninstalled () { _deb_packages_update_avail _deb_packages_update_installed if (( ! $+_deb_packages_cache_uninstalled )); then + # Package lists too large to efficiently diff with zsh expansion _deb_packages_cache_uninstalled=( - ${_deb_packages_cache_avail:#${(j:|:)~${_deb_packages_cache_installed:q}}} + $( print -l $_deb_packages_cache_avail | + fgrep -xvf =(print -l $_deb_packages_cache_installed) ) ) fi cachevar=_deb_packages_cache_uninstalled diff --git a/Completion/Linux/Command/.distfiles b/Completion/Linux/Command/.distfiles index 3c3103e22..251204e3b 100644 --- a/Completion/Linux/Command/.distfiles +++ b/Completion/Linux/Command/.distfiles @@ -27,5 +27,6 @@ _tune2fs _uml _valgrind _vserver +_wpa_cli _yast ' diff --git a/Completion/Linux/Command/_modutils b/Completion/Linux/Command/_modutils index 3ae76fec9..b3f8fcd46 100644 --- a/Completion/Linux/Command/_modutils +++ b/Completion/Linux/Command/_modutils @@ -1,8 +1,23 @@ #compdef lsmod modinfo modprobe rmmod insmod +_modules_caching_policy() +{ + # Rebuild every week, or if $modules_dir is newer than the cache + local -a oldp + + oldp=( "$1"(Nmw+1) ) + (( $#oldp )) || [[ $modules_dir -nt $1 ]] +} + local curcontext="$curcontext" expl state line modules ign args ret=1 local -r modules_dir=/lib/modules +local update_policy +zstyle -s ":completion:*:*:$service:*" cache-policy update_policy +if [[ -z "$update_policy" ]]; then + zstyle ":completion:*:*:$service:*" cache-policy _modules_caching_policy +fi + args=( '(-)'{-V,--version}'[print version]' '(-)'{-h,--help}'[print help text]' @@ -39,6 +54,7 @@ case "$service" in "(-v --verbose $ign)"{-v,--verbose}'[print all commands as executed]' \ '(-C --config)'{-C,--config}'[specify config file]:config file:_files' \ "(-r --remove -l --list -t --type -a --all $ign)"{-r,--remove}'[remove module (stacks)]' \ + "(-l --list -t --type -a --all $ign)"{'-i[ignore install/remove commands in config file]','--ignore-install[ignore install commands in config file]','--ignore-remove[ignore remove commands in config file]'} \ "(* -l --list -r --remove $ign)"{-l,--list}'[list matching modules]' \ "(-c $ign)1:modules:->loadable_modules" \ "(-c -l --list -t --type $ign)*:params:->params" && ret=0 @@ -87,7 +103,13 @@ case "$state" in else kver=$(uname -r) fi - modules=( $modules_dir/$kver/(*~(source|build))/**/*(.:t:r) ) + if [[ -z $modules ]] && ! _cache_invalid modules-$kver && \ + ! _retrieve_cache modules-$kver; + then + # 2011-01-02 gi1242: Do we need .o files? Or is .ko enough? + modules=( $modules_dir/$kver/(*~(source|build))/**/*.(o|ko)(.:t:r) ) + _store_cache modules-$kver modules + fi if [[ $state = loadable_modules ]]; then modules=( ${modules:#(${(j:|:)~${=loaded_modules//_/-}})} ) diff --git a/Completion/Linux/Command/_valgrind b/Completion/Linux/Command/_valgrind index 34d2f774a..0284ff880 100644 --- a/Completion/Linux/Command/_valgrind +++ b/Completion/Linux/Command/_valgrind @@ -118,7 +118,11 @@ if [[ -n "$state" ]]; then # Basically uses debug output to find out the directory where the tools are # present and lists all executables in that directory. # Hope the program provides a neater interface some day! - tools=(${${${(M)${(f)"$(_call_program tools valgrind --tool=something -d 2> /dev/null)"}:#*launcher launching *something}##*launcher launching }%%something}*(*:t)) + () { + setopt localoptions histsubstpattern + tools=( ${${${(M)${(f)"$(_call_program tools valgrind --tool=something -d 2>&1)"}:#*launcher launching *something*}##*launcher launching }%%something*}*~*.*(*:t:s/-*//) ) + typeset -U tools + } _wanted tools exl 'valgrind tool' compadd $tools && return fi diff --git a/Completion/Linux/Command/_wpa_cli b/Completion/Linux/Command/_wpa_cli new file mode 100644 index 000000000..e1342ca80 --- /dev/null +++ b/Completion/Linux/Command/_wpa_cli @@ -0,0 +1,13 @@ +#compdef wpa_cli + +_arguments \ + '-p:path to ctrl sockets:_files -g "*(=)"' \ + '-i:ifname:_net_interfaces' \ + '-h[help]' \ + '-v[shown version information]' \ + '-B[run a daemon in the background]' \ + '-a[run in daemon mode]:action file:_files' \ + '-P:pid file:_files' \ + '-g:global ctrl:_files -g "*(=)"' \ + '-G:ping interval:' \ + ':command:(status ping mib help interface level license quit set logon logoff pmksa reassociate preauthenticate identity password new_password pin otp passphrase bssid list_networks select_network enable_network disable_network add_network remove_network set_network get_network save_config disconnect reconnect scan scan_results bss get_capability reconfigure terminate interface_add interface_remove interface_list ap_scan stkstart ft_ds wps_pbc wps_pin wps_reg)' diff --git a/Completion/Redhat/Command/_rpm b/Completion/Redhat/Command/_rpm index 184d7b00d..83922b60c 100644 --- a/Completion/Redhat/Command/_rpm +++ b/Completion/Redhat/Command/_rpm @@ -55,7 +55,7 @@ _rpm () { '--httpport:http port number' {-\?,--help}'[print help information]' '--version[print version number]' - '--pipe:pipe command:->command' \ + '--pipe:pipe command:->command' ) # package selection options of which only one can be used diff --git a/Completion/Redhat/Command/_yum b/Completion/Redhat/Command/_yum index d0ea0911a..ae63364e6 100644 --- a/Completion/Redhat/Command/_yum +++ b/Completion/Redhat/Command/_yum @@ -6,21 +6,23 @@ _yum() local curcontext="$curcontext" state lstate line _arguments -s \ - {-h,--help}'[show the help message]' \ - {-t,--tolerant}'[be tolerant of errors]' \ - '-C[run entirely from cache]' \ - '-c[config file location]:Yum conf file:_files' \ - '-R[maximum command wait time (in minutes)]:max wait time' \ - '-d[debug level (0-10)]:debug level' \ - '-e[error level (0-10)]:error level' \ - '-y[answer yes for all questions]' \ + '(- *)'{-h,--help}'[show the help message]' \ + '(-t --tolerant)'{-t,--tolerant}'[be tolerant of errors]' \ + '(-C --cacheonly)'{-C,--cacheonly}'[run entirely from cache]' \ + '(-c --config)'{-c,--config=}'[config file location]:Yum conf file:_files' \ + '(-R --randomwait)'{-R,--randomwait=}'[maximum command wait time (in minutes)]:max wait time' \ + '(-d --debuglevel)'{-d,--debuglevel=}'[debug level (0-10)]:debug level' \ + '(-e --errorlevel)'{-e,--errorlevel=}'[error level (0-10)]:error level' \ + '(-y --assumeyes)'{-y,--assumeyes}'[answer yes for all questions]' \ '--installroot=[set install root]:install root:_files -/' \ '*--enablerepo=[enable or or more repositories]:repos to enable:_yum_disabled_repos_list' \ '*--disablerepo=[disable one or more repositories]:disable repos:_yum_enabled_repos_list' \ - '--exclude=[exclude package(s) by name or glob]:exclude packages' \ + {*-x,*--exclude=}'[exclude package(s) by name or glob]:exclude packages' \ '--version[show yum version]' \ - '--obseletes[enable obsoletes processing during updates]' \ + '--obsoletes[enable obsoletes processing during updates]' \ + '--nogpgcheck[disable gpg signature checking]' \ '--noplugins[disable yum plugins]' \ + '--disablepresto[disable Presto plugin and don''''t download any deltarpms]' \ '*::yum command:_yum_command' } @@ -148,12 +150,16 @@ yum_repos() { (( $+functions[_yum_disabled_repos_list] )) || _yum_disabled_repos_list() { + compset -P '*,' + compset -S ',*' yum_repos compadd "$@" -a -- disabled_yum_repos } (( $+functions[_yum_enabled_repos_list] )) || _yum_enabled_repos_list() { + compset -P '*,' + compset -S ',*' yum_repos compadd "$@" -a -- enabled_yum_repos } diff --git a/Completion/Unix/Command/.distfiles b/Completion/Unix/Command/.distfiles index 0a158ee4b..cc47a7a0b 100644 --- a/Completion/Unix/Command/.distfiles +++ b/Completion/Unix/Command/.distfiles @@ -8,6 +8,7 @@ _apachectl _apm _arp _arping +_at _attr _awk _baz @@ -77,6 +78,7 @@ _global _gnu_generic _gnupod _gnutls +_go _gpg _gphoto2 _gprof @@ -94,6 +96,7 @@ _ifconfig _iftop _imagemagick _init_d +_initctl _ip _irssi _ispell @@ -137,6 +140,8 @@ _ncftp _netcat _nice _nmap +_notmuch +_npm _nslookup _osc _pack @@ -146,6 +151,7 @@ _pbm _perforce _perl _perldoc +_pgrep _php _pine _ping @@ -206,6 +212,7 @@ _tardy _tcpdump _tcptraceroute _telnet +_tex _texinfo _tidy _tiff @@ -222,6 +229,7 @@ _unace _uname _unexpand _uniq +_unison _units _user_admin _uzbl diff --git a/Completion/Unix/Command/_at b/Completion/Unix/Command/_at new file mode 100644 index 000000000..4e2d28e27 --- /dev/null +++ b/Completion/Unix/Command/_at @@ -0,0 +1,39 @@ +#compdef atrm atq at batch + +local context state line expl +typeset -A opt_args + +#todo (when extremely bored) make -l and -d do the atq and atrm completions +case $service in +atrm) + _arguments \ + '-V[Print version number]' \ + '*:job number:->jobs' + ;; +atq) + _arguments \ + '-V[Print version number]' \ + '-q[Uses specified queue]:a-z+A-Z' + ;; +at|batch) + _arguments \ + - new-job \ + '-V[Print version number]' \ + '-q[Uses specified queue, uppercase acts as batch]:a-z+A-Z' \ + '-f[Read job from file rather than from stdin]:file:_files' \ + '-v[Show the time the job will be executed]' \ + '-m[Send mail even if there was no output]' \ + ':time:' \ + - atq \ + '-l[Alias for atq]' \ + - atrm \ + '-d[Alias for atrm]' \ + - show-job \ + '-c[Cat specified jobs to stdout]:*:job number:->jobs' +esac + +case $state in +jobs) + _wanted job expl 'job number' compadd ${(M)${(f)"$(_call_program job atq)"}##<->} + ;; +esac diff --git a/Completion/Unix/Command/_du b/Completion/Unix/Command/_du index 769c620de..9974d72e9 100644 --- a/Completion/Unix/Command/_du +++ b/Completion/Unix/Command/_du @@ -1,6 +1,8 @@ #compdef du if _pick_variant gnu=Free\ Soft unix --version /dummy/no-such-file; then + local ret=1 + _arguments -s \ '(-a --all -s --summarize)'{-a,--all}'[write counts for all files]' \ '--apparent-size[print apparent sizes rather than disc usage]' \ @@ -27,22 +29,24 @@ if _pick_variant gnu=Free\ Soft unix --version /dummy/no-such-file; then '--time=-[show time of last modification of any file in the directory]:property:->time' \ '(* -)--help[display help information]' \ '(* -)--version[display version information]' \ - '*:file:_files' + '*:file:_files' && ret=0 case $state in (time) local -a property property=(atime access use ctime status) - _wanted property expl property compadd -a property + _wanted property expl property compadd -a property && ret=0 ;; (timestyle) local -a style desc style=(full-iso long-iso iso +) desc=('full-iso' 'long-iso' 'iso' '+FORMAT like `date'\''') - _wanted -V style expl style compadd -d desc -a style + _wanted -V style expl style compadd -d desc -a style && ret=0 ;; esac + return ret + else # based on $OSTYPE = solaris2.8 local xdev='[skip directories on different filesystems]' diff --git a/Completion/Unix/Command/_ffmpeg b/Completion/Unix/Command/_ffmpeg index 1c57e3b9c..8f9b2c9cb 100644 --- a/Completion/Unix/Command/_ffmpeg +++ b/Completion/Unix/Command/_ffmpeg @@ -1,135 +1,166 @@ #compdef ffmpeg -local context state line +local context state line expl typeset -A opt_args -local BOLD=$'\e[1m' -local NORM=$'\e[m' - -_ffmpeg_compadd() { - compadd -X "${BOLD}$1${NORM}" -q -S "$3" -a $2 -} - -_ffmpeg_presets() { +(( $+functions[_ffmpeg_presets] )) || _ffmpeg_presets() { local presets presets=(~/.ffmpeg/*.ffpreset(:t:r) "$FFMPEG_DATADIR"/*.ffpreset(:t:r)) - _ffmpeg_compadd 'select preset' presets '' + _wanted ffmpeg-presets expl 'select preset' compadd -a presets } -_ffmpeg_acodecs() { +(( $+functions[_ffmpeg_acodecs] )) || _ffmpeg_acodecs() { local acodecs - acodecs=(${${(M)${(f)"$(ffmpeg -codecs 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]]A[S[:space:]][D[:space:]][T[:space:]][[:space:]][^[:space:]]##*}//(#b)????????([^[:space:]]##)*/$match[1]}) - _ffmpeg_compadd 'force audio codec (''copy'' to copy stream)' acodecs '' + acodecs=(copy ${${(M)${(f)"$(_call_program audio-codecs $words[1] -codecs 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]]A[S[:space:]][D[:space:]][T[:space:]][[:space:]][^[:space:]]##*}//(#b)????????([^[:space:]]##)*/$match[1]}) + _wanted ffmpeg-audio-codecs expl 'force audio codec (''copy'' to copy stream)' compadd -a acodecs } -_ffmpeg_vcodecs() { +(( $+functions[_ffmpeg_vcodecs] )) || _ffmpeg_vcodecs() { local vcodecs - vcodecs=(${${(M)${(f)"$(ffmpeg -codecs 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]]V[S[:space:]][D[:space:]][T[:space:]][[:space:]][^[:space:]]##*}//(#b)????????([^[:space:]]##)*/$match[1]}) - _ffmpeg_compadd 'force video codec (''copy'' to copy stream)' vcodecs '' + vcodecs=(copy ${${(M)${(f)"$(_call_program video-codecs $words[1] -codecs 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]]V[S[:space:]][D[:space:]][T[:space:]][[:space:]][^[:space:]]##*}//(#b)????????([^[:space:]]##)*/$match[1]}) + _wanted ffmpeg-video-codecs expl 'force video codec (''copy'' to copy stream)' compadd -a vcodecs } -_ffmpeg_formats() { +(( $+functions[_ffmpeg_formats] )) || _ffmpeg_formats() { local formats - formats=(${(ou)${=${(s:,:)${${(M)${(f)"$(ffmpeg -formats 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]][[:space:]][^[:space:]]##*}//(#b)????([^[:space:]]##)*/$match[1]}}}}) - _ffmpeg_compadd 'force format' formats '' + formats=(${(ou)${=${(s:,:)${${(M)${(f)"$(_call_program formats $words[1] -formats 2>/dev/null)"}:#[[:space:]][D[:space:]][E[:space:]][[:space:]][^[:space:]]##*}//(#b)????([^[:space:]]##)*/$match[1]}}}}) + _wanted ffmpeg-formats expl 'force format' compadd -a formats } -_ffmpeg_list_pix_fmts() { - print -l ${${(M)${(f)"$(ffmpeg -pix_fmts 2>/dev/null)"}:#[I.]*}//(#b)??????([^[:space:]]##)*/$match[1]} +(( $+functions[_ffmpeg_list_pix_fmts] )) || _ffmpeg_list_pix_fmts() { + echo - ${${${(M)${(f)"$(_call_program formats $words[1] -pix_fmts 2>/dev/null)"}:#[I.][O.][H.][P.][B.] [^=[:space:]]*}#* }%% *} } -_ffmpeg_pix_fmts() { +(( $+functions[_ffmpeg_pix_fmts] )) || _ffmpeg_pix_fmts() { local pix_fmts pix_fmts=($(_ffmpeg_list_pix_fmts)) - _ffmpeg_compadd 'set pixel format' pix_fmts '' + _wanted ffmpeg-pix-fmts expl 'set pixel format' compadd -a pix_fmts } -_ffmpeg_bsfs() { +(( $+functions[_ffmpeg_bsfs] )) || _ffmpeg_bsfs() { local bsfs - bsfs=(${${(f)"$(ffmpeg -bsfs 2>/dev/null)"}:#*:}) - _ffmpeg_compadd 'set bitstream filter' bsfs '' + bsfs=(${${(f)"$(_call_program bsfs $words[1] -bsfs 2>/dev/null)"}:#*:}) + _wanted ffmpeg-bsfs expl 'set bitstream filter' compadd -a bsfs +} + +typeset -A _ffmpeg_flags + +(( $+functions[_ffmpeg_flag_options] )) || _ffmpeg_flag_options() { + local expl + _wanted options expl 'select flags' compadd -S '' -- {-,+}${^flag_options} } -_ffmpeg_argspecs="$(ffmpeg -h 2>/dev/null | perl -e ' -my $lastopt; -my $lastopt_description; -my $lastopt_takesargs; -my @lastopt_values; -while (<>) { - if (/^(-\S+)\s+(\S.+)$/) { - print_opt(); - $lastopt = $1; - $lastopt_description = $2; - if ($lastopt_description =~ /<\w+>/) { - $lastopt_description =~ s/<.*?>\s+//; - $lastopt_description =~ s/\S{5} ?//; - $lastopt_description = $lastopt if not $lastopt_description; - escape_str($lastopt_description); - } elsif ($lastopt_description =~ /^(\S+)\s\s+/) { - my $example = $1; - $lastopt_description =~ s/^\S+\s\s+//; - escape_str($example); - escape_str($lastopt_description); - if ($example eq q(filename)) { - $lastopt_takesargs = 0; - $lastopt .= qq(:$lastopt_description:_files); - } elsif ($lastopt =~ /^-[asv]pre$/) { - $lastopt_takesargs = 0; - $lastopt .= qq(: :_ffmpeg_presets); - } elsif ($lastopt eq q(-acodec)) { - $lastopt_takesargs = 0; - $lastopt .= qq(: :_ffmpeg_acodecs); - } elsif ($lastopt eq q(-vcodec)) { - $lastopt_takesargs = 0; - $lastopt .= qq(: :_ffmpeg_vcodecs); - } elsif ($lastopt eq q(-f)) { - $lastopt_takesargs = 0; - $lastopt .= qq(: :_ffmpeg_formats); - } elsif ($lastopt eq q(-pix_fmt)) { - $lastopt_takesargs = 0; - $lastopt .= qq(: :_ffmpeg_pix_fmts); - } elsif ($example eq q(bitstream_filter)) { - $lastopt_takesargs = 0; - $lastopt .= qq(: :_ffmpeg_bsfs); - } else { - $lastopt_takesargs = 1; - $lastopt_description .= qq{ ($example)}; - } - } else { - $lastopt_takesargs = 0; - if ($lastopt eq q(-vfilters)) { - $lastopt .= qq(: :->vfilters); - } - } - @lastopt_values = (); - } elsif (/^ (\S+)/) { - $lastopt_takesargs = 1; - push @lastopt_values, $1; - } +(( $+functions[_ffmpeg_more_flag_options] )) || _ffmpeg_more_flag_options() { + compset -p $1 && _ffmpeg_flag_options } -print_opt(); -exit; -sub escape_str { - $_[0] =~ s/:/\\:/g; +(( $+functions[_ffmpeg_new_flag_options] )) || _ffmpeg_new_flag_options() { + compset -P '*' && _ffmpeg_flag_options } -sub print_opt { - return if not $lastopt; - - print qq($lastopt); - if (!$lastopt_takesargs) { - print qq(\n); - } else { - print qq(:$lastopt_description:); - if (@lastopt_values) { - printf qq{(%s)}, join(q( ), @lastopt_values); - } - print qq(\n); - } +(( $+functions[_ffmpeg_flags] )) || _ffmpeg_flags() { + local -a flag_options + eval "flag_options=(\${=_ffmpeg_flags[$1]})" + + local match mbegin mend + integer ret=1 + + if [[ $PREFIX = (#b)(*)[-+]([^-+]#) ]]; then + if [[ -n ${flag_options[(R)$match[2]]} ]]; then + _ffmpeg_new_flag_options && ret=0 + fi + if [[ -n ${flag_options[(R)$match[2]?*]} ]]; then + _ffmpeg_more_flag_options ${#match[1]} && ret=0 + fi + else + _ffmpeg_flag_options && ret=0 + fi + + return $ret +} + +(( $+functions[_ffmpeg_register_lastopt_values] )) || _ffmpeg_register_lastopt_values() { + if (( lastopt_takesargs )); then + lastopt+=":$lastopt_description:" + if (( $#lastopt_values )); then + if [[ $lastopt_type == flags ]]; then + flagtype=${${lastopt%%:*}#-} + lastopt+="->$flagtype" + _ffmpeg_flags[$flagtype]="${lastopt_values[*]}" + else + lastopt+="(${lastopt_values[*]})" + fi + fi + fi + _ffmpeg_argspecs+=$lastopt +} + +local -a _ffmpeg_argspecs +{ + local lastopt + local lastopt_description + local lastopt_takesargs + local lastopt_type + local -a lastopt_values + + _call_program options $words[1] -h 2>/dev/null | while IFS=$'\n' read -r; do + if [[ $REPLY == -* ]]; then + [[ -n $lastopt ]] && _ffmpeg_register_lastopt_values + lastopt=${REPLY%%[[:space:]]*} + lastopt_description=${REPLY##-[^[:space:]]##[[:space:]]##} + if [[ $lastopt_description == (#b)'<'(?##)'>'* ]]; then + lastopt_type=$match[1] + lastopt_description=${lastopt_description##<[^[:space:]]##>[[:space:]]##[^[:space:]]##[[:space:]]#} + if [[ -z $lastopt_description ]]; then + lastopt_description=$lastopt + fi + lastopt_description=${lastopt_description//:/\\:} + elif [[ $lastopt_description == [^[:space:]]##[[:space:]][[:space:]]* ]]; then + local example=${lastopt_description%% *} + example=${example//:/\\:} + lastopt_description=${lastopt_description##[^[:space:]]##[[:space:]]##} + lastopt_description=${lastopt_description//:/\\:} + if [[ $example == filename ]]; then + lastopt_takesargs=0 + lastopt+=":$lastopt_description:_files" + elif [[ $lastopt == -[asv]pre ]]; then + lastopt_takesargs=0 + lastopt+=": :_ffmpeg_presets" + elif [[ $lastopt == -acodec ]]; then + lastopt_takesargs=0 + lastopt+=": :_ffmpeg_acodecs" + elif [[ $lastopt == -vcodec ]]; then + lastopt_takesargs=0 + lastopt+=": :_ffmpeg_vcodecs" + elif [[ $lastopt == -f ]]; then + lastopt_takesargs=0 + lastopt+=": :_ffmpeg_formats" + elif [[ $lastopt == -pix_fmt ]]; then + lastopt_takesargs=0 + lastopt+=": :_ffmpeg_pix_fmts" + elif [[ $example == bitstream_filter ]]; then + lastopt_takesargs=0 + lastopt+=": :_ffmpeg_bsfs" + else + lastopt_takesargs=1 + lastopt_description+=" ($example)" + fi + else + lastopt_takesargs=0 + if [[ $lastopt == -vfilters ]]; then + lastopt+=": :->vfilters" + fi + fi + lastopt_values=() + elif [[ $REPLY == ' '* ]]; then + REPLY=${REPLY##[[:space:]]##} + REPLY=${REPLY%%[[:space:]]##*} + lastopt_takesargs=1 + lastopt_values+=$REPLY + fi + done + [[ -n $lastopt ]] && _ffmpeg_register_lastopt_values } -')" -_ffmpeg_argspecs=(${(f)_ffmpeg_argspecs}) _arguments -S \ "${_ffmpeg_argspecs[@]}" \ @@ -137,27 +168,30 @@ _arguments -S \ && return 0 [[ "$state" == "vfilters" ]] && - _values -s , -S = 'video filters' \ - 'aspect:set aspect ratio (rational number X\:Y or decimal number):' \ - 'crop:crop input video (x\:y\:width\:height):' \ - 'format: :->format' \ - 'noformat: :->noformat' \ - 'null' \ - 'pad:add pads to the input image (width\:height\:x\:y\:color_string):' \ - 'pixelaspect:set pixel aspect ratio (rational number X\:Y or decimal number):' \ - 'scale:scale input video (width\:height):' \ - 'slicify:output slice height ("random" or a number of pixels):' \ - 'unsharp:luma_x\:luma_y\:luma_amount\:chroma_x\:chroma_y\:chroma_amount:' \ - 'vflip' \ - 'buffer' \ - 'nullsrc' \ - 'nullsink' \ - && return 0 + _values -s , -S = 'video filters' \ + 'aspect:set aspect ratio (rational number X\:Y or decimal number):' \ + 'crop:crop input video (x\:y\:width\:height):' \ + 'format: :->format' \ + 'noformat: :->noformat' \ + 'null' \ + 'pad:add pads to the input image (width\:height\:x\:y\:color_string):' \ + 'pixelaspect:set pixel aspect ratio (rational number X\:Y or decimal number):' \ + 'scale:scale input video (width\:height):' \ + 'slicify:output slice height ("random" or a number of pixels):' \ + 'unsharp:luma_x\:luma_y\:luma_amount\:chroma_x\:chroma_y\:chroma_amount:' \ + 'vflip' \ + 'buffer' \ + 'nullsrc' \ + 'nullsink' \ + && return 0 [[ "$state" == "format" ]] && - _values -s : -S = 'convert input video to one of the specified pixel formats' $(_ffmpeg_list_pix_fmts) && return 0 + _values -s : -S = 'convert input video to one of the specified pixel formats' $(_ffmpeg_list_pix_fmts) && return 0 [[ "$state" == "noformat" ]] && - _values -s : -S = 'disable specified pixel formats by force' $(_ffmpeg_list_pix_fmts) && return 0 + _values -s : -S = 'disable specified pixel formats by force' $(_ffmpeg_list_pix_fmts) && return 0 + +[[ -n $state && -n $_ffmpeg_flags[$state] ]] && + _ffmpeg_flags $state && return 0 return 1 diff --git a/Completion/Unix/Command/_fuser b/Completion/Unix/Command/_fuser index 6c291473f..ba0f301ea 100644 --- a/Completion/Unix/Command/_fuser +++ b/Completion/Unix/Command/_fuser @@ -3,7 +3,7 @@ local -a args arg1 typeset -A opt_args -if _pick_variant -c $words[1] psmisc=psmisc unix -V; then +if _pick_variant -c $words[1] psmisc='(#i)psmisc' unix -V; then (( $+functions[_fuser_services] )) || _fuser_services() { diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git index 8e54f3d90..e062705ee 100644 --- a/Completion/Unix/Command/_git +++ b/Completion/Unix/Command/_git @@ -1,4 +1,4 @@ -#compdef git git-cvsserver git-receive-pack git-upload-archive git-upload-pack git-shell +#compdef git git-cvsserver git-receive-pack git-upload-archive git-upload-pack git-shell gitk tig # Some parts of this completion's behaviour are configurable: # @@ -20,1434 +20,85 @@ # TODO: There is still undocumented configurability in here. -# TODO: All if (( words[(I)-option] )) should be turned into -# if (( words[(I)-option] > 0 && words[(I)-option] < CURRENT )), as the user -# may go back and want to add an option before -option and in that case should -# be able to complete whatever may come before -option. +# HIGH-LEVEL COMMANDS (PORCELAIN) -# TODO: suggested zstyles: -# -# zstyle ':completion::*:git-{name-rev,add,rm}:*' ignore-line true - -_git() { -local nul_arg abbrev_arg find_copies_harder_arg diff_l_arg pretty_arg exec_arg -local author_conversion_file_arg long_author_conversion_file_arg verbose_arg -local help_arg template_arg shared_arg thin_arg author_conversion_file_arg_spec -local -a diff_args fetch_args merge_args force_ref_arg tags_fetch_arg -local -a upload_pack_arg common_fetch_args common_apply_args -local -a revision_arguments - -nul_arg='-z[use NUL termination on output]' -abbrev_arg='--abbrev=-[set minimum SHA1 display-length]: :_guard "[[\:digit\:]]#" length' -find_copies_harder_arg='--find-copies-harder[try harder to find copies]' -diff_l_arg='-l-[limit number of rename/copy targets to run]: :_guard "[[\:digit\:]]#" number' - -diff_args=( - '--diff-filter=-[select certain kinds of files for diff]: :_guard "[ACDMRTUXB*]#" kinds' - $find_copies_harder_arg - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--name-only[show only names of changed files]' - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--name-status[show only names and status of changed files]' - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)'{-u,-p}'[generate diff in patch format]' - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--stat=-[generate a diffstat instead of a patch]:: :__git_guard_diff-stat-width' \ - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--patch-with-stat[generate patch and prepend its diffstat]' \ - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--patch-with-raw[generate patch but also keep the default raw diff output]' \ - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--raw[generate the default raw diff output]' \ - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--numstat[generate a more machine-friendly diffstat]' \ - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--shortstat[generate a summary diffstat]' \ - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--summary[generate a condensed summary of extended header information]' \ - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--dirstat[generate a dirstat by amount of changes]' \ - '(--name-only --name-status -u -p --stat --patch-with-stat --patch-with-raw --raw --numstat --shortstat --summary)--dirstat-by-file[generate a dirstat by number of files]' \ - '-B-[break complete rewrite changes into pairs of given size]: :_guard "[[\:digit\:]]#" size' - '-C-[detect copies as well as renames with given scope]: :_guard "[[\:digit\:]]#" size' - $diff_l_arg - '-M-[detect renames with given scope]: :_guard "[[\:digit\:]]#" size' - '-O-[output patch in the order of glob-pattern lines in given file]:file:_files' - '-R[do a reverse diff]' - '-S-[look for differences that contain the given string]:string' - '--pickaxe-all[when -S finds a change, show all changes in that changeset]' - '--pickaxe-regex[treat argument of -S as regular expression]' - '--full-index[show full object name of pre- and post-image blob]' - '(--full-index)--binary[in addition to --full-index, output binary diffs for git-apply]' - '( --no-color --color-words)--color[show colored diff]' - '(--color --color-words)--no-color[turn off colored diff]' - '(--color --no-color )--color-words[show colored-word diff]' - '--no-renames[turn off rename detection]' - '--check[warn if changes introduce trailing whitespace or space/tab indents]' - '(-a --text)'{-a,--text}'[treat all files as text]' - '(-b --ignore-space-change -w --ignore-all-space)'{-b,--ignore-space-change}'[ignore changes in amount of white space]' - '(-b --ignore-space-change -w --ignore-all-space)'{-w,--ignore-all-space}'[ignore white space when comparing lines]' - '(-1 --base)'{-1,--base}'[diff against stage 1]' - '(-2 --ours)'{-2,--ours}'[diff against stage 2]' - '(-3 --theirs)'{-3,--theirs}'[diff against stage 3]' - $abbrev_arg - $nul_arg - '--exit-code[report exit code 1 if differences, 0 otherwise]' - '--unified=[generate diffs with n lines of context]:n' - '--inter-hunk-context=[combine hunks closer than n lines]:n' - '--patience[generate diffs with patience algorithm]' - '(--exit-code)--quiet[disable all output]' - '--relative=:path:_files -/' -) - -pretty_arg='--pretty=-[pretty print commit messages]::pretty print:((raw\:"the raw commits" - medium\:"most parts of the messages" - short\:"few headers and only subject of messages" - full\:"all parts of the commit messages" - fuller\:"like full and includes dates" - email\:"use email headers like From and Subject" - oneline\:"commit-ids and subject of messages"))' - -exec_arg='--exec=-[specify path to git-upload-pack on remote side]:remote path' - -fetch_args=( - '-c[fetch commit objects]' - '-t[fetch trees associated with commit objects]' - '-a[fetch all objects]' - '-v[show what is downloaded]' - '-w[write commit-id into the filename under "$GIT_DIR/refs/<filename>"]:filename' - '--recover[recover from a failed fetch]' -) - -# TODO: Add descriptions to strategies (stupid is undocumented). -merge_args=( - '(-n --no-stat)'{-n,--no-stat}'[do not show diffstat at the end of the merge]' - '--stat[show a diffstat at the end of the merge]' - '--no-commit[perform the merge but do not autocommit]' - '--squash[merge, but do not make a commit]' - '--log[fill in one-line descriptions of the commits being merged in the log message]' - '--no-log[do not list one-line descriptions of the commits being merged in the log message]' - '--no-ff[generate a merge commit even if the merge resolved as a fast-forward]' - '--ff[do not generate a merge commit if the merge resolved as a fast-forward]' - '*'{-s,--strategy=-}'[use given merge strategy]:merge strategy:__git_merge_strategies' -) - -force_ref_arg=('(-f --force)'{-f,--force}'[allow refs that are not ancestors to be updated]') - -tags_fetch_arg=( - '(--no-tags -t --tags)--no-tags[disable automatic tag following]' - '(--no-tags -t --tags)'{-t,--tags}'[fetch remote tags]' -) - -author_conversion_file_arg_spec='[specify author-conversion file]:author-conversion file:_files' - -author_conversion_file_arg='-A'$author_conversion_file_arg_spec - -long_author_conversion_file_arg='--authors-file=-'$author_conversion_file_arg_spec - -verbose_arg='-v[produce verbose output]' - -help_arg='-h[display usage information]' - -upload_pack_arg=('(-u --upload-pack)'{-u,--upload-pack=-}'[specify path to git-upload-pack on remote side]:remote path') - -common_fetch_args=( - '(-a --append)'{-a,--append}'[append ref names and object names of fetched refs to "$GIT_DIR/FETCH_HEAD"]' - $upload_pack_arg - $force_ref_arg - $tags_fetch_arg - '(-k --keep)'{-k,--keep}'[keep downloaded pack]' - '(-u --update-head-ok)'{-u,--update-head-ok}'[allow updates of current branch head]' - '(-q --quiet)'{-q,--quiet}'[do not print any results to stdout]' - '(-v --verbose)'{-v,--verbose}'[output extra information]' - '--depth=[deepen the history of a shallow repository by the given number of commits]:depth' -) - -common_apply_args=( - '--whitespace=-[detect a new or modified line that ends with trailing whitespaces]: :__git_apply_whitespace_strategies' - '-p-[remove N leading slashes from traditional diff paths]: :_guard "[[\:digit\:]]#" number' - '-C-[ensure at least N lines of context match before and after each change]: :_guard "[[\:digit\:]]#" number') - -template_arg='--template=-[directory to use as a template for the object database]:directory:_directories' - -shared_arg='--shared=-[share repository amongst several users]::permissions:__git_repository_permissions' - -thin_arg='--thin[minimize number of objects to be sent]' - -__git_zstyle_default () { - zstyle -t $1 $2 - if (( $status == 2 )); then - zstyle $* - fi -} - -# TODO: Either skip uninteresting commands or skip the description - the list -# is just too long. -# NOTE: I'm coming to the opinion that skipping the description is the right -# thing to do…, but not 100% sure yet. -(( $+functions[_git_commands] )) || -_git_commands () { - local -a base_commands - base_commands=( - 'add:add paths to the index' - 'apply:apply patch on a git index file and a work tree' - 'bisect:find the change that introduced a bug' - 'branch:create and show branches' - 'checkout:checkout and switch to a branch' - 'cherry-pick:cherry-pick the effect of an existing commit' - 'clone:clone a repository into a new directory' - 'commit:record changes to the repository' - 'diff:show changes between commits, commit and working tree, etc.' - 'fetch:download objects and a head from another repository' - 'gc:cleanup unnecessary files and optimize the local repository' - 'grep:print lines matching a pattern' - 'help:display help information about git subcommands' - 'init:create empty git object database' - 'log:show commit logs' - 'merge:grand unified merge driver' - 'mv:move or rename file, directory, or symlink' - 'prune:prune all unreachable objects from the object database' - 'pull:fetch from and merge with a remote repository' - 'push:update remote refs along with associated objects' - 'rebase:rebase local commits to new upstream head' - 'reset:reset current HEAD to the specified state' - 'revert:revert existing commit' - 'rm:remove files from the working tree and from the index' - 'show-branch:show branches and their commits' - 'stage:add file contents to the staging area' - 'stash:stash away changes to the working tree' - 'status:show working-tree'\''s status' - 'submodule:initialize or update or inspect submodules' - 'tag:create tag object signed with GPG' - 'verify-tag:check GPG signature of a tag') - - local -a additional_commands - additional_commands=( - 'am:apply patches from a mailbox (cooler than applymbox)' - 'annotate:annotate file lines with commit info' - 'applymbox:apply patches from a mailbox' - 'applypatch:apply one patch extracted from an e-mail' - 'archive:create an archive of files from a named tree' - 'blame:blame file lines on commits' - 'cat-file:provide content or type information for repository objects' - 'check-attr:display gitattributes information' - 'check-ref-format:makes sure that a reference-name is well formed' - 'checkout-index:copy files from the index to the working directory' - 'cherry:find commits not merged upstream' - 'clean:remove untracked files from the working tree' - 'clone-pack:clone a repository into the current repository (transport)' - 'commit-tree:create a new commit object' - 'count-objects:count unpacked objects and display their disk consumption' - 'describe:show the most recent tag that is reachable from a commit' - 'diff-files:compare files in the working tree and the index' - 'diff-index:compare content and mode of blobs between index and repository' - 'diff-stages:compare two "merge states" in the index file' - 'diff-tree:compare the content and mode of blobs found via two tree objects' - 'fetch-pack:receive missing objects from another repository' - 'imap-send:dump mailbox from stdin into imap folder' - 'index-pack:build pack index file for an existing packed archive' - 'local-fetch:duplicate another git repository on a local system' - 'ls-remote:show references in a remote or local repository' - 'ls-tree:display tree object in human-readable form' - 'mailinfo:extract patch from a single e-mail message' - 'mailsplit:split mbox file into a list of files' - 'merge-base:find as good a common ancestor as possible for a merge' - 'merge-file:run a three-way file merge' - 'merge-index:run merge for files needing merging' - 'merge-tree:show three-way merge without touching index' - 'mktag:create tag object' - 'mktree:build tree-object from ls-tree formatted text' - 'name-rev:find symbolic names for given revisions' - 'notes:add/inspect commit notes' - 'pack-objects:create packed archive of objects' - 'pack-redundant:find redundant pack files' - 'pack-refs:pack heads and tags for efficient repository access' - 'parse-remote:routines to help parsing $GIT_DIR/remotes/' - 'peek-remote:list references on a remote repository using the upload-pack protocol' - 'prune-packed:remove extra objects that are already in pack files' - 'read-tree:read tree information into the directory index' - 'reflog:manage reflog information' - 'relink:hardlink common objects in local repositories' - 'repack:pack unpacked objects in a repository' - 'request-pull:generate summary of pending changes' - 'rerere:reuse recorded resolve' - 'rev-list:list commit object in reverse chronological order' - 'shortlog:summarize git log output' - 'show:show various types of objects' - 'show-index:display contents of a pack idx file' - 'show-ref:list references in a local repository' - 'symbolic-ref:read and modify symbolic references' - 'tar-tree:create tar archive of the files in the named tree' - 'unpack-file:create temporary file with blob'\''s contents' - 'unpack-objects:unpack objects out of packed archive' - 'update-ref:update object name stored in a reference safely' - 'update-server-info:update auxiliary information on a dumb server' - 'var:display git logical variable' - 'verify-pack:validate packed git archive files' - 'whatchanged:show commit-logs and differences they introduce' - 'write-tree:create tree from the current index') - - local -a useful_commands - useful_commands=( - 'format-patch:prepare patches for e-mail submission' - 'ls-files:information about files in the index/working directory' - 'instaweb:instantly browse your working repository in gitweb' - 'remote:manage set of tracked repositories' - 'send-email:send patch-e-mails out of "format-patch" output' - 'update-index:modify index in some given way') - - local -a interoperability_commands - interoperability_commands=( - 'archimport:import an Arch repository into git' - 'cvsexportcommit:export a commit to a CVS checkout' - 'cvsimport:import a CVS "repository" into a git repository' - 'svnimport:import SVN repository into git' - 'quiltimport:apply a quilt patchset' - 'svn:bidirectional operation between a single Subversion branch and git' - 'annex:manage files without tracking content') - - local -a ancillary_commands - ancillary_commands=( - 'config:get and set repository or global options' - 'convert-objects:convert old-style git repository' - 'for-each-ref:output information on each ref' - 'get-tar-commit-id:extract commit ID from an archive created using tar-tree' - 'hash-object:compute object ID from a file' - 'patch-id:compute unique ID for a patch' - 'fsck:verify the connectivity and validity of the objects in the database' - 'lost-found:recover lost references that luckily have not yet been pruned' - 'mergetool:run merge conflict resolution tools to resolve merge conflicts') - - local -a internal_commands - internal_commands=( - 'daemon:start a really simple server for git repositories' - 'fast-import:import information into git directly' - 'fmt-merge-msg:produce merge commit message' - 'http-fetch:download remote git repository via HTTP' - 'http-push:push missing objects using HTTP/DAV' - 'merge-one-file:standard helper-program to use with merge-index' - 'receive-pack:command invoked by send-pack to receive what is pushed to it' - 'rev-parse:pick out and massage parameters for other git commands' - 'runstatus:a helper for git-status and git-commit' - 'send-pack:push to remote repository, intelligently' - 'shell:restricted login shell for GIT-only SSH access' - 'ssh-fetch:pull from remote repository over an SSH connection' - 'ssh-upload:"server-side" helper program used by ssh-fetch' - 'stripspace:filter out empty lines' - 'upload-archive:send archive back to git-archive' - 'upload-pack:command invoked by clone-pack and fetch-pack') - - local wanted_commands - zstyle -s ":completion:${curcontext}:" commands wanted_commands || wanted_commands="all -internal" - local -a user_commands - zstyle -a ":completion:${curcontext}:" user-commands user_commands || user_commands=() - - local -aU unique_wanted_commands - unique_wanted_commands=($=wanted_commands) - - integer index_of_all=$(( $unique_wanted_commands[(I)all] )) - if (( index_of_all > 0 )); then - unique_wanted_commands[index_of_all]=() - unique_wanted_commands+=(base additional useful interoperability ancillary internal) - fi - - for (( i = 0; i < $#unique_wanted_commands; i++ )); do - if [[ $unique_wanted_commands[i] == (#bq)-(*) ]]; then - unique_wanted_commands[i]=() - unique_wanted_commands[(I)$match[1]]=() - fi - done - - local -a commands - for wanted_command in $unique_wanted_commands; do - case $wanted_command in - (base) - commands+=($base_commands) ;; - (additional) - commands+=($additional_commands) ;; - (useful) - commands+=($useful_commands) ;; - (interoperability) - commands+=($interoperability_commands) ;; - (ancillary) - commands+=($ancillary_commands) ;; - (internal) - commands+=($internal_commands) ;; - esac - done - commands+=( $user_commands ) - - _describe -t commands 'git command' commands && ret=0 -} - -(( $+functions[__git_aliases] )) || -__git_aliases () { - declare -a aliases - - # TODO: See __git_config_gettable_name for discussion on how to actually get - # out the names, skipping the values. - # TODO: Should check if the terminal is unicode capable. If so, use ‘ and ’ - # instead of '. - aliases=(${^${${(M)${(f)"$(_call_program aliases git config --list)"}:#alias.*}#alias.}/(#b)=(*)/:alias for \'$match[1]}\') - __git_command_successful || return 0 - - local expl - - _describe -t aliases 'git alias' aliases -} - -(( $+functions[__git_aliases_and_commands] )) || -__git_aliases_and_commands () { - _alternative \ - 'aliases: :__git_aliases' \ - 'commands: :_git_commands' -} -# NOTE: -c is undocumented. -# TODO: Perhaps provide some sort of completion or guard for line range (-L). -# NOTE: --score-debug is undocumented. -# NOTE: --show-name is undocumented. -# NOTE: --show-number is undocumented. -(( $+functions[_git-annotate] )) || -_git-annotate () { - _arguments -S \ - '-b[show blank SHA-1 for boundary commits]' \ - '--root[do not treat root commits as boundaries]' \ - '--show-stats[include additional statistics at the end of blame output]' \ - '-c[undocumented]' \ - '-l[show long rev]' \ - '-t[show raw timestamp]' \ - '-S[use revs from revs-file]:revs-file:_files' \ - '-M-[detect moving lines in the file as well]:number of characters' \ - '*-C-[detect copied lines from other files from same commit as well]:number of characters' \ - '-L[annotate only the given line range]:line range' \ - '--contents[annotate against the given file if no rev is specified]:file:_files' \ - '--incremental[show results incrementally for machine processing]' \ - '--score-debug[uncodumented]' \ - '(-f --show-name)'{-f,--show-name}'[undocumented]' \ - '(-n --show-number)'{-n,--show-number}'[undocumented]' \ - '(-p --porcelain)'{-p,--porcelain}'[show results designed for machine processing]' \ - '(-h --help)'{-h,--help}'[show help message]' \ - ':file:__git_cached_files' \ - '::revision:__git_revisions' && ret=0 -} - -(( $+functions[_git-apply] )) || -_git-apply () { - _arguments \ - $nul_arg \ - '--allow-binary-replacement[allow binary files to be patched]' \ - '--apply[apply patches that would otherwise not be applied]' \ - '--cached[apply patches without touching the working tree]' \ - '--check[check if patches are applicable (turns off "apply")]' \ - '--include=-[include files matching specified pattern]:pattern' \ - '--exclude=-[skip files matching specified pattern]:pattern' \ - '--inaccurate-eof[work around missing-new-line-at-EOF bugs]' \ - '--index[make sure that the patch is applicable to the index]' \ - '--index-info[output information about original version of a blob if available]' \ - '--no-add[ignore additions made by the patch]' \ - '--numstat[same as --stat but in decimal notation and complete pathnames (turns off "apply")]' \ - '(-R --reverse)'{-R,--reverse}'[apply patches in reverse]' \ - '--reject[apply as much as possible, and leave rejected hunks in .rej files]' \ - '--stat[output diffstat for the input (turns off "apply")]' \ - '--summary[output summary of git-diff extended headers (turns off "apply")]' \ - '--unidiff-zero[disable unified-diff-context check]' \ - '(-v --verbose)'{-v,--verbose}'[report progress to stderr]' \ - $common_apply_args \ - '*::patch:_files' && ret=0 -} - -# NOTE: Documentation mentions options that don’t exist anymore, for example, -# --since, and shows -C twice!aa -(( $+functions[_git-blame] )) || -_git-blame () { - _git-annotate -} - -(( $+functions[_git-checkout-index] )) || -_git-checkout-index () { - _arguments -S \ - $nul_arg \ - '(-a --all :)'{-a,--all}'[check out all files in the index]' \ - '(-f --force)'{-f,--force}'[force overwrite of existing files]' \ - '(-n --no-create)'{-n,--no-create}'[do not checkout new files]' \ - '--stage=-[check out files from named stage]:stage:(1 2 3 all)' \ - '--stdin[read list of paths from the standard input]' \ - '--temp[write the content to temporary files]' \ - '--prefix=-[prefix to use when creating files]:directory:_directories' \ - '(-q --quiet)'{-q,--quiet}'[do not complain about existing files or missing files]' \ - '(-u --index)'{-u,--index}'[update stat information in index]' \ - '*::file:__git_cached_files' && ret=0 -} - -(( $+functions[_git-commit-tree] )) || -_git-commit-tree () { - if (( CURRENT == 2 )); then - __git_trees && ret=0 - elif [[ $words[CURRENT-1] == -p ]]; then - local expl - _description commits expl 'parent commit' - __git_objects $expl && ret=0 - else - compadd - '-p' - fi -} - -(( $+functions[_git-hash-object] )) || -_git-hash-object () { - _arguments -S \ - '(:)--stdin[read object from standard input]' \ - '-t[the type of object to create]:object type:((blob\:"a blob of data" - commit\:"a tree with parent commits" - tag\:"a symbolic name for another object" - tree\:"a recursive tree of blobs"))' \ - '-w[write the object to the object database]' \ - '(--stdin):file:_files' && ret=0 -} - -(( $+functions[_git-help] )) || -_git-help () { - _arguments -S \ - ':command:_git_commands' \ - - '(all)' \ - '(:)'{--all,-a}'[List all available commands]' \ - - '(format)' \ - {--man,-m}'[Display help in man page format]' \ - {--info,-i}'[Display help in info format]' \ - {--web,-w}'[Display help in web browser]' \ - && ret=0 -} - -(( $+functions[_git-index-pack] )) || -_git-index-pack () { - local -a stdin_arguments - - if (( words[(I)--stdin] )); then - stdin_arguments=( - '--fix-thin[record deltified objects, based on objects not included]' - '--keep=-[create .keep file]::reason:') - fi - - _arguments \ - '-v[report progress to stderr]' \ - '-o[write generated pack index into specified file]:file:_files' \ - '--stdin[read pack from stdin and instead write to specified file]' \ - $stdin_arguments \ - ':pack file:_files -g "*.pack"' && ret=0 -} - -(( $+functions[_git-init] )) || -_git-init () { - _arguments \ - '(-q --quiet)'{-q,--quiet}'[do not print any results to stdout]' \ - '--bare[create a bare repository]' \ - $shared_arg \ - $template_arg && ret=0 -} - -(( $+functions[_git-merge-file] )) || -_git-merge-file () { - integer n_labels=${#${(M)words[1,CURRENT-1]:#-L}} - local label_argument - - if (( n_labels < 3 )) || [[ $words[CURRENT-1] == -L ]]; then - local -a ordinals - - ordinals=(first second third) - - label_argument="*-L[label to use for the $ordinals[n_labels+1] file]:label" - fi - - _arguments \ - $label_argument \ - '(-p --stdout)'{-p,--stdout}'[send merged file to standard output instead of overwriting first file]' \ - '(-q --quiet)'{-q,--quiet}'[do not warn about conflicts]' \ - ':current file:_files' \ - ':base file:_files' \ - ':other file:_files' && ret=0 -} - -(( $+functions[_git-merge-index] )) || -_git-merge-index () { - if (( CURRENT > 2 )) && [[ $words[CURRENT-1] != -[oq] ]]; then - _arguments -S \ - '(:)-a[run merge against all files in the index that need merging]' \ - '*:index file:__git_cached_files' && ret=0 - else - declare -a arguments - - (( CURRENT == 2 )) && arguments+='-o[skip failed merges]' - (( CURRENT == 2 || CURRENT == 3 )) && arguments+='(-o)-q[do not complain about failed merges]' - (( 2 <= CURRENT && CURRENT <= 4 )) && arguments+='*:merge program:_files -g "*(*)"' - - _arguments -S $arguments && ret=0 - fi -} - -# TODO: Shouldn’t we add a __git_branches type completion? -(( $+functions[_git-merge-tree] )) || -_git-merge-tree () { - _arguments \ - ':base-tree:__git_tree_ishs' \ - ':branch 1:__git_tree_ishs' \ - ':branch 2:__git_tree_ishs' && ret=0 -} - -(( $+functions[_git-mktag] )) || -_git-mktag () { - _message 'no arguments allowed; only accepts tags on standard input' -} - -(( $+functions[_git-mktree] )) || -_git-mktree () { - _arguments \ - '-z[read NUL-terminated ls-tree -z output]' && ret=0 -} - -(( $+functions[_git-pack-objects] )) || -_git-pack-objects () { - _arguments \ - '(--revs)--all[include all refs as well as revisions already specified]' \ - '--all-progress[force progress output, even during write-out phase]' \ - '--delta-base-offset[use delta-base-offset packing]' \ - '--depth=[maximum delta depth]:number' \ - '--incremental[ignore objects that have already been packed]' \ - '--no-reuse-delta[do not reuse existing deltas, but compute them from scratch]' \ - '--non-empty[only create a package if it contains at least one object]' \ - '--local[similar to --incremental, but only ignore unpacked non-local objects]' \ - '--progress[force progress output]' \ - '--revs[read revision arguments from standard input]' \ - '(:)--stdout[write the pack to standard output]' \ - '-q[do not report progress]' \ - '(--revs)--unpacked[limit objects to pack to those not already packed]' \ - '--window=[number of objects to use per delta compression]:number' \ - '(--stdout):base-name:_files' && ret=0 -} - -(( $+functions[_git-prune-packed] )) || -_git-prune-packed () { - _arguments -S \ - '-n[only list the objects that would be removed]' \ - '-q[suppress progress output]' && ret=0 -} - -(( $+functions[_git-read-tree] )) || -_git-read-tree () { - local aggressive_arg - - if (( words[(I)-m] )); then - aggressive_arg='--aggressive[try harder to resolve merge conflicts]' - fi - - local -a ui_args - - if (( words[(I)(-m|--reset|--prefix)] )); then - ui_args=( - '( -i)-u[update the work tree after successful merge]' - '(-u )-i[update only the index; ignore changes in work tree]') - fi - - local exclude_per_directory_arg - - if (( words[(I)-u] )); then - exclude_per_directory_arg='--exclude-per-directory=-[specify .gitignore file]:.gitignore file:_files' - fi - - _arguments -A '-*' \ - '( --reset --prefix)-m[perform a merge, not just a read]' \ - '(-m --prefix)--reset[perform a merge, not just a read, ignoring unmerged entries]' \ - '(-m --reset 2 3)--prefix=-[read the contents of specified tree-ish under specified directory]:prefix:_directories -r ""' \ - $aggressive_arg \ - $ui_args \ - $exclude_per_directory_arg \ - '--trivial[restrict three-way merge to only happen if no file-level merging is required]' \ - '--index-output=[write index in the named file instead of $GIT_INDEX_FILE]:file:_files' \ - '1:first tree-ish to be read/merged:__git_tree_ishs' \ - '2:second tree-ish to be read/merged:__git_tree_ishs' \ - '3:third tree-ish to be read/merged:__git_tree_ishs' && ret=0 -} - -# TODO: Complete value regex somehow? -(( $+functions[_git-config] )) || -_git-config () { - local name_arg - - if (( words[(I)--get-regexp] )); then - name_arg=':name regex' - elif (( words[(I)--get(-all|)] )); then - name_arg=':name:__git_config_gettable_name' - else - name_arg=':name:__git_config_name' - fi - - _arguments -A '--*' \ - '( --global)--system[use system-wide config file]' \ - '(--system )--global[use user-global config file]' \ - '( --bool)--int[setting is an integer]' \ - '(--int )--bool[setting is a boolean]' \ - $name_arg \ - ":value:__git_config_values $words[CURRENT-1]" \ - '::value regex' \ - - '(actions)' \ - '(: -)--rename-section[rename the given section]:section:__git_config_section_names:new name' \ - '(: -)--remove-section[remove the given section]:section:__git_config_section_names' \ - '(3 -)--add[add new value without altering any existing ones]' \ - '(2 -)--unset[remove the first matching value of the key]' \ - '(2 -)--unset-all[remove all matching values of the key]' \ - '(2 -)--get[get the first matching value of the key]' \ - '(2 -)--get-all[get all matching values of the key]' \ - '(2 -)--get-regexp[like "--get-all", but interpret "name" as a regular expression]' \ - '(-)--replace-all[replace all values of the given key]' \ - '(: --int --bool)'{-l,--list}'[list all variables set in config file]' && ret=0 -} - -# NOTE: --track is undocumented. -# TODO: --track, -t, --master, and -m should take remote branches, I guess. -# NOTE: --master is undocumented. -# NOTE: --fetch is undocumented. -(( $+functions[_git-remote] )) || -_git-remote () { - local curcontext=$curcontext state line - declare -A opt_args - - _arguments -C \ - ':command:->command' \ - '*::options:->options' && ret=0 - - case $state in - (command) - declare -a commands - - commands=( - 'add:add a new remote' - 'show:show information about a given remote' - 'prune:delete all stale tracking branches for a given remote' - 'update:fetch updates for a set of remotes' - 'rm:remove a remote from .git/config and all associated tracking branches' - 'rename:rename a remote from .git/config and update all associated tracking branches') - - _describe -t commands 'sub-command' commands && ret=0 - ;; - (options) - case $line[1] in - (add) - _arguments \ - '*'{--track,-t}'[track given branch instead of default glob refspec]:branch:__git_branch_names' \ - '(--master -m)'{--master,-m}'[set the remote'\''s HEAD to point to given master branch]:branch:__git_branch_names' \ - '(--fetch -f)'{--fetch,-f}'[run git-fetch on the new remote after it has been created]' \ - ':branch name:__git_remotes' \ - ':url:_urls' && ret=0 - ;; - (show) - _arguments \ - '-n[do not contact the remote for a list of branches]' \ - ':remote:__git_remotes' && ret=0 - ;; - (prune) - _arguments \ - '(--dry-run -n)'{-n,--dry-run}'[do not actually prune, only list what would be done]' \ - ':remote:__git_remotes' && ret=0 - ;; - (update) - __git_remote-groups && ret=0 - ;; - (rm) - __git_remotes && ret=0 - ;; - (rename) - __git_remotes && ret=0 - ;; - esac - ;; - esac -} - -(( $+functions[_git-unpack-objects] )) || -_git-unpack-objects () { - _arguments \ - '-n[only list the objects that would be unpacked]' \ - '-q[run quietly]' \ - '-r[try recovering objects from corrupt packs]' && ret=0 -} - -(( $+functions[_git-update-index] )) || -_git-update-index () { - local nul_arg - - if (( words[(I)--stdin] )); then - nul_arg='-z[paths are separated with NUL instead of LF for --stdin]' - fi - - _arguments -S \ - $refreshables \ - '--add[add files not already in the index]' \ - '( --force-remove)--remove[remove files that are in the index but are missing from the work tree]' \ - '(--remove )--force-remove[remove files from both work tree and the index]' \ - '(-q --unmerged --ignore-missing)--refresh[refresh the index]' \ - '-q[run quietly]' \ - '--unmerged[if unmerged changes exists, ignore them instead of exiting]' \ - '--ignore-missing[ignore missing files when refreshing the index]' \ - '*--cacheinfo[insert information directly into the cache]: :_guard "[0-7]#" "octal file mode": :_guard "[[\:xdigit\:]]#" "object id":file:_files' \ - '(: -)--index-info[read index information from stdin]' \ - '--chmod=-[set the execute permissions on the updated files]:permission:((-x\:executable +x\:"not executable"))' \ - '( --no-assume-unchanged)--assume-unchanged[set the "assume unchanged" bit for the given paths]' \ - '(--assume-unchanged )--no-assume-unchanged[unset the "assume unchanged" bit for the given paths]' \ - '(-)'{-g,--again}'[run git-update-index on differing index entries]' \ - '(-)--unresolve[restore "unmerged" or "needs updating" state of files]' \ - '--info-only[only insert files object-IDs into index]' \ - '--replace[replace files already in the index if necessary]' \ - '(: -)--stdin[read list of paths from standard input]' \ - '--verbose[report what is being added and removed from the index]' \ - $nul_arg \ - '*::file:_files' && ret=0 -} - -(( $+functions[_git-write-tree] )) || -_git-write-tree () { - _arguments \ - '--missing-ok[ignore objects in the index that are missing in the object database]' \ - '--prefix=-[write tree representing given sub-directory]:sub-directory:_directories -r ""' && ret=0 -} - -# shouldn't complete objects after --batch{,-check}... -(( $+functions[_git-cat-file] )) || -_git-cat-file () { - _arguments \ - '(-t -s -e -p --batch-check 1)--batch[print the SHA1, type, size, and contents of each object provided on stdin]' \ - '(-t -s -e -p --batch 1)--batch-check[print the SHA1, type, and size of each object provided on stdin]' \ - '( -s -e -p --batch-check --batch 1)-t[show the type of the given object]' \ - '(-t -e -p --batch-check --batch 1)-s[show the size of the given object]' \ - '(-t -s -p --batch-check --batch 1)-e[exit with zero status if object exists]' \ - '(-t -s -e --batch-check --batch 1)-p[pretty-print the given object]' \ - '(-t -s -e -p --batch-check --batch ):object type:(blob commit tag tree)' \ - '(-t -s -e -p --batch-check --batch ):object:__git_objects' && ret=0 -} - -(( $+functions[_git-describe] )) || -_git-describe () { - _arguments \ - '--all[use any ref found in "$GIT_DIR/refs/"]' \ - '--tags[use any ref found in "$GIT_DIR/refs/tags"]' \ - '(--contains)--tags[use any tag found in "$GIT_DIR/refs/tags/"]' \ - $abbrev_arg \ - '--contains[find the tag after the commit instead of before]' \ - '--exact-match[only output exact matches, same as --candidates=0]' \ - '--always[show uniquely abbreviated commit object as fallback]' \ - '--long[always show full format, even for exact matches]' \ - '--match=[only consider tags matching glob pattern]:pattern' \ - '--candidates=-[consider up to given number of candidates]: :_guard "[[\:digit\:]]##" "number of candidates"' \ - '--debug[display information about the searching strategy]' \ - '*:committish:__git_committishs' && ret=0 -} - -# TODO: Use __git_modified_files instead? -(( $+functions[_git-diff-index] )) || -_git-diff-index () { - _arguments -S \ - $diff_args \ - '--cached[do not consider the work tree at all]' \ - '-m[flag non-checked-out files as up-to-date]' \ - ':tree-ish:__git_tree_ishs' \ - '*::index file:__git_cached_files' && ret=0 -} - -# TODO: Use __git_modified_files instead? -(( $+functions[_git-diff-files] )) || -_git-diff-files () { - _arguments \ - $diff_args \ - '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)-0[omit diff output for unmerged entries]' \ - '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)'{-1,--base}'[diff against "base" version]' \ - '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)'{-2,--ours}'[diff against "our branch" version]' \ - '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)'{-3,--theirs}'[diff against "their branch" version]' \ - '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)'{-c,--cc}'[compare "our branch", "their branch" and working tree files]' \ - '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index --exit-code *)--no-index[compare given files / directories]' \ - '-q[remain silent even on nonexisting files]' \ - '1:file:_files' \ - '2:file:_files' \ - '*::file:_files' && ret=0 -} - -# TODO: Use __git_modified_files instead? -(( $+functions[_git-diff-stages] )) || -_git-diff-stages () { - _arguments \ - $diff_args \ - ':stage 1:__git_stages' \ - ':stage 2:__git_stages' \ - '*::index file:_files' && ret=0 -} - -# TODO: Use __git_modified_files instead? -(( $+functions[_git-diff-tree] )) || -_git-diff-tree () { - local curcontext=$curcontext state line - declare -A opt_args - - _arguments -C -S \ - $diff_args \ - $pretty_arg \ - '--encoding=-[re-code commit log-message in given encoding]::log-message encoding:__git_encodings' \ - '--no-commit-id[skip output of commit IDs]' \ - '--root[show diff against the empty tree]' \ - '--stdin[read commit and tree information from standard input]' \ - '-m[show merge commits]' \ - '-r[recurse into subdirectories]' \ - '(-r)-t[show tree entry itself as well as subtrees (implies -r)]' \ - '-s[do not show differences]' \ - '-v[show commit message before the differences]' \ - '(-c --cc)-c[show differences from each of the parents to the merge result]' \ - '(-c --cc)--cc[how differences from each of the parents and omit differences from only one parent]' \ - '--always[always show commit itself and the commit log message]' \ - ':tree-ish:__git_tree_ishs' \ - '*::file:->files' && ret=0 - - case $state in - files) - if (( $#line > 2 )); then - # TODO: this is probably just stupid to do. - # What'd be nice would be - # common files: - # ... - # original tree: - # ... - # new tree: - # ... - _alternative \ - "original tree:original tree:__git_tree_files . $line[1]" \ - "new tree:new tree:__git_tree_files . $line[2]" && ret=0 - else - _alternative \ - ': :__git_tree_ishs' \ - ": :__git_tree_files . $line[1]" && ret=0 - fi - ;; - esac -} - -# TODO: Better completion for --format: should complete %(field) stuff, that -# is, %(refname), %(objecttype), %(objectsize), %(objectname) with optional ‘*’ -# in front. -# TODO: Documentation says that --count can be given * number of times, but -# sources beg to differ, allowing only one. -(( $+functions[_git-for-each-ref] )) || -_git-for-each-ref () { - _arguments -S \ - '--format=-[output format of ref information]:format' \ - '(-s --shell -p --perl --python --tcl)'{-s,--shell}'[use string literals suitable for sh]' \ - '(-s --shell -p --perl --python --tcl)'{-p,--perl}'[use string literals suitable for Perl]' \ - '(-s --shell -p --perl --tcl)'--python'[use string literals suitable for Python]' \ - '(-s --shell -p --perl --python )'--tcl'[use string literals suitable for Tcl]' \ - '--count=-[maximum number of refs to iterate over]: :_guard "[[\:digit\:]]#" "maximum number of refs"' \ - '--sort=-[key to sort refs by]:sort key:__git_ref_sort_keys' \ - ':: :_guard "([^-]?#|)" pattern' && ret=0 -} - -(( $+functions[_git-fmt-merge-msg] )) || -_git-fmt-merge-msg () { - arguments \ - '( --no-summary)--summary[add one-line descriptions from commits being merged]' \ - '(--summary )--no-summary[do not add one-line descriptions from commits being merged]' \ - '(-F --file)'{-F,--file}'[specify list of merged objects from file]:file:_files' && ret=0 -} - -(( $+functions[_git-fsck] )) || -_git-fsck () { - _arguments \ - '--cache[consider objects recorded in the index as head nodes for reachability traces]' \ - '--full[check all object directories]' \ - '--root[show root nodes]' \ - '--strict[do strict checking]' \ - '--tags[show tags]' \ - '--unreachable[show objects that are unreferenced in the object database]' \ - '*::object:__git_objects' && ret=0 -} - -(( $+functions[_git-ls-files] )) || -_git-ls-files () { - local no_empty_directory_arg - - if (( words[(I)--directory] )); then - no_empty_directory_arg='--no-empty-directory[do not list empty directories]' - fi - - _arguments -S \ - $nul_arg \ - '(-c --cached)'{-c,--cached}'[show cached files in the output]' \ - '(-d --deleted)'{-d,--deleted}'[show deleted files in the output]' \ - '(-i --ignored)'{-i,--ignored}'[show ignored files in the output]' \ - '(-k --killed)'{-k,--killed}'[show killed files in the output]' \ - '(-m --modified)'{-m,--modified}'[show modified files in the output]' \ - '(-o --others)'{-o,--others}'[show other files in the output]' \ - '(-s --stage)'{-s,--stage}'[show stage files in the output]' \ - '(-u --unmerged)'{-u,--unmerged}'[show unmerged files in the output]' \ - '( -v)-t[identify each files status (HMRCK?)]' \ - '(-t )-v[identify each files status (hmrck?)]' \ - '*'{-x,--exclude=-}'[skip files matching given pattern]:file pattern' \ - '*'{-X,--exclude-from=-}'[skip files matching patterns in given file]:file:_files' \ - '*--exclude-per-directory=-[skip directories matching patterns in given file]:file:_files' \ - '--directory[if a whole directory is classified as "other", show just its name]' \ - $no_empty_directory_arg \ - '--error-unmatch[if any <file> does not appear in the index, treat this as an error]' \ - '--full-name[force paths to be output relative to the project top directory]' \ - $abbrev_arg \ - '*::index file:_files' && ret=0 -} - -(( $+functions[_git-ls-tree] )) || -_git-ls-tree () { - local curcontext=$curcontext state line - declare -A opt_args - - _arguments -C \ - $nul_arg \ - $abbrev_arg \ - '(-t)-d[do not show children of given tree (implies -t)]' \ - {--name-only,--name-status}'[list only filenames, one per line]' \ - '-r[recurse into subdirectories]' \ - '-t[show tree entries even when going to recurse them]' \ - '--full-name[output full path-names]' \ - ':tree-ish:__git_tree_ishs' \ - '*::tree file:->files' && ret=0 - - case $state in - files) - __git_tree_files . $line[1] && ret=0 - ;; - esac -} - -(( $+functions[_git-imap-send] )) || -_git-imap-send () { - _message 'no arguments allowed; accepts mailbox file on standard input' -} - -(( $+functions[_git-quiltimport] )) || -_git-quiltimport () { - _arguments \ - '--dry-run[check patches and warn if they can'\''t be imported]' \ - '--author[default author name and email address to use for patches]' \ - '--patches[set directory containing patches]:patch directory:_directories' && ret=0 -} - -(( $+functions[_git-merge-base] )) || -_git-merge-base () { - _arguments \ - '(-a --all)'{-a,--all}'[show all common ancestors]' \ - ':commit 1:__git_commits' \ - ':commit 2:__git_commits' && ret=0 -} - -(( $+functions[_git-name-rev] )) || -_git-name-rev () { - _arguments -S \ - '--tags[only use tags to name the commits]' \ - '--refs=-[only use refs matching given pattern]: :_guard "?#" "shell pattern"' \ - '--always[show uniquely abbreviated commit object as fallback]' \ - '--no-undefined[die with non-zero return when a reference is undefined]' \ - '(--stdin :)--all[list all commits reachable from all refs]' \ - '(--all :)--stdin[read from stdin and append revision-name]' \ - '(--stdin --all)*:commit-ish:__git_revisions' && ret=0 -} - -(( $+functions[_git-notes] )) || -_git-notes () { - local expl - local -a notes_cmds - - notes_cmds=( - edit:"edit note" - show:"show commit note" - ) - - if (( CURRENT == 2 )); then - _describe -t command "git-notes commands" notes_cmds && ret=0 - else - case $words[2] in - (show) - _arguments \ - '*:commit id:__git_commits' && ret=0 - ;; - (edit) - _arguments \ - '-F[use file'\''s contents as the commit note]:file:_path_files' \ - '-m[use the given message as the commit note]:message' \ - '*:commit id:__git_commits' && ret=0 - ;; - (*) - _nothing - ;; - esac - fi -} - -(( $+functions[_git-pack-redundant] )) || -_git-pack-redundant () { - _arguments \ - '(:)--all[process all packs]' \ - '--alt-odb[do not require objects to be present in local packs]' \ - '--verbose[output some statistics to stderr]' \ - '(--all)*::packs:_files -g "*.pack"' && ret=0 -} - -# TODO: --timestamp undocumented. -(( $+functions[_git-rev-list] )) || -_git-rev-list () { - if (( words[(I)--] && words[(I)--] != CURRENT )); then - _arguments \ - '*:index file:__git_cached_files' && ret=0 - else - __git_setup_revision_arguments - - _arguments -S \ - $revision_arguments \ - '(--pretty)--header[show commit headers]' \ - '--remote-empty[stop when a given path disappears from the tree]' \ - '--timestamp[undocumented]' \ - '( --bisect-vars)--bisect[show only the middlemost commit object]' \ - '(--bisect )--bisect-vars[same as --bisect, outputing shell-evalable code]' \ - '--stdin[read commit objects from standard input]' \ - '*:commit id:__git_commit_ranges2' && ret=0 - fi -} - -(( $+functions[_git-show-ref] )) || -_git-show-ref () { - _arguments -S \ - - list \ - '(-h --head)'{-h,--head}'[show the HEAD reference]' \ - '--tags[show only "refs/tags"]' \ - '--heads[show only "refs/heads"]' \ - '(-d --dereference)'{-d,--dereference}'[dereference tags into object IDs as well]' \ - '(-s --hash)'{-s+,--hash=-}'[only show the SHA-1 hash, not the reference name]:: :_guard "[[\:digit\:]]#" length' \ - '--verify[enable stricter reference checking]' \ - $abbrev_arg \ - '(-q --quiet)'{-q,--quiet}'[do not print any results to stdout]' \ - '*: :_guard "([^-]?#|)" pattern' \ - - exclude \ - '--exclude-existing=-[filter out existing refs from stdin]:: :_guard "([^-]?#|)" pattern' && ret=0 -} - -(( $+functions[_git-show] )) || -_git-show () { - local curcontext=$curcontext state line - typeset -A opt_args - __git_setup_revision_arguments - - _arguments -S \ - $revision_arguments \ - '-s[do not show differences]' \ - '*:object:__git_objects' && ret=0 -} - -(( $+functions[_git-show-index] )) || -_git-show-index () { - _message 'no arguments allowed; accepts index file on standard input' -} - -(( $+functions[_git-tar-tree] )) || -_git-tar-tree () { - _arguments \ - '--remote=-[retrieve a tar archive from a remote repository]:__git_remote_repository' \ - ':tree-ish:__git_tree_ishs' \ - ':base:_files' && ret=0 -} - -(( $+functions[_git-unpack-file] )) || -_git-unpack-file () { - _arguments \ - ':blob id:__git_blobs' && ret=0 -} - -(( $+functions[_git-var] )) || -_git-var () { - _arguments \ - '(:)-l[show logical variables]' \ - '(-):variable:((GIT_AUTHOR_IDENT\:"name and email of the author" \ - GIT_COMMITTER_IDENT\:"name and email of committer"))' && ret=0 -} - -(( $+functions[_git-verify-pack] )) || -_git-verify-pack () { - _arguments -S \ - '-v[show objects contained in pack]' \ - '*:index file:_files -g "*.idx"' && ret=0 -} - -(( $+functions[_git-clone-pack] )) || -_git-clone-pack () { - _arguments \ - $exec_arg \ - ':repository:__git_any_repositories' \ - '*:head:__git_heads' && ret=0 -} - -(( $+functions[_git-fetch-pack] )) || -_git-fetch-pack () { - _arguments \ - '--all[fetch all remote refs]' \ - '(-q --quiet)'{-q,--quiet}'[make output less verbose]' \ - '(-k --keep)'{-k,--keep}'[do not invoke git-unpack-objects on received data]' \ - $thin_arg \ - '(--upload-pack --exec)'{--upload-pack=-,--exec=-}'[specify path to git-upload-pack on remote side]:remote path' \ - '--depth=-[limit fetching to ancestor-chains not longer than given number]: :_guard "[[\:digit\:]]#" "maximum ancestor-chain length"' \ - '--no-progress[do not show progress]' \ - $verbose_arg \ - ':repository:__git_any_repositories' \ - '*:references:__git_references' && ret=0 -} - -(( $+functions[_git-fast-import] )) || -_git-fast-import () { - _arguments \ - '--date-format=-[specify the types of dates being passed]:((raw\:"native git format" - rfc2822\:"standard email format" - now\:"use current time and timezone"))' \ - '--max-pack-size=-[maximum size of each packfile]: :_guard "[[\:digit\:]]#" "maximum pack size"' \ - '--depth=-[maximum delta depth for blob and tree deltification]: :_guard "[[\:digit\:]]#" "maximum delta depth"' \ - '--active-branches=-[maximum number of branches to maintain active at once]: :_guard "[[\:digit\:]]#" "maximum number of branches"' \ - '--export-marks=-[dump the internal marks table to given file]:export file:_files' \ - '--export-pack-edges=-[list packfiles and last commit on branches in them in given file]:export file:_files' \ - '--force[force updating modified existing branches]' \ - '--quiet[disable all non-fatal output]' \ - '--stats[display statistics about object created]' && ret=0 -} - -(( $+functions[_git-http-fetch] )) || -_git-http-fetch () { - _arguments \ - $fetch_args \ - '(1)--stdin[read commit ids and refs from standard input]' \ - ':commit id:__git_commits' \ - ':URL:_urls' && ret=0 -} - -(( $+functions[_git-http-push] )) || -_git-http-push () { - _arguments \ - '--all[verify that all objects in local ref history exist remotely]' \ - '--complete[do not assume that the remote repository is complete]' \ - '--force[allow refs that are not ancestors to be updated]' \ - '--verbose[report the list of objects being walked locally and sent to the remote]' \ - '( -D)-d[remove refs from remote repository]' \ - '(-d )-D[forcefully remove refs from remote repository]' \ - ':URL:_urls' \ - '*:remote refs:__git_remote_references' && ret=0 -} - -(( $+functions[_git-local-fetch] )) || -_git-local-fetch () { - _arguments \ - $fetch_args \ - '-l[hard-link objects]' \ - '-n[do not copy objects]' \ - '-s[sym-link objects]' \ - '(1)--stdin[read commit ids and refs from standard input]' \ - ':commit id:__git_commits' \ - ':directory:_directories' && ret=0 -} - -# TODO: --tags undocumented. -# TODO: --heads undocumented. -# TODO: --refs undocumented. -(( $+functions[_git-peek-remote] )) || -_git-peek-remote () { - _arguments \ - '--upload-pack=-[specify path to git-upload-pack on remote side]:remote path' \ - $exec_arg \ - '--tags[undocumented]' \ - '--heads[undocumented]' \ - '--refs[undocumented]' \ - ':repository:__git_repository' && ret=0 -} - -(( $+functions[_git-sh-setup] )) || -_git-sh-setup () { - _message "you probably should not be issuing this command; it is an internal git helper" -} - -# TODO: --dry-run undocumented. -# TODO: -n undocumented. -# TODO: --stale-fix undocumented. -# TODO: --verbose undocumented. -# TODO: -- undocumented. -(( $+functions[_git-reflog] )) || -_git-reflog () { - __git_setup_revision_arguments - - if (( CURRENT == 2 )); then - local curcontext=$curcontext state line - declare -A opt_args - - _arguments -C \ - $revision_arguments \ - ':subcommand:->subcommand' && ret=0 - - case $state in - (subcommand) - declare -a reflog_cmds - - reflog_cmds=( - 'expire:prune old reflog entries' - 'show:show log of the current branch') - - _describe -t subcommands 'subcommands' reflog_cmds && ret=0 - ;; - esac - else - case $words[2] in - (expire) - _arguments -S \ - '(-n --dry-run)'{-n,--dry-run}'[undocumented]' \ - '--expire=-[prune entries older than given time]:date' \ - '--expire-unreachable=-[prune entries older than given time and unreachable]:date' \ - '--stale-fix[undocumented]' \ - '--all[prune all refs]' \ - '--verbose' && ret=0 - ;; - (show|--*) - _arguments -S \ - $revision_arguments \ - ':subcommand:' && ret=0 - ;; - esac - fi -} - -(( $+functions[_git-receive-pack] )) || -_git-receive-pack () { - _arguments \ - ':directory to sync into:_directories' && ret=0 -} - -(( $+functions[_git-shell] )) || -_git-shell () { - local curcontext=$curcontext state line - declare -A opt_args - - _arguments -C \ - '-c[command to execute]:command:->commands' \ - ':argument to command:->arguments' && ret=0 - - case $state in - (commands) - declare -a commands - - commands=(git-receive-pack git-upload-pack) - - _describe -t commands command commands && ret=0 - ;; - (arguments) - case $line[1] in - (git-receive-pack) - local expl - - _description directories expl 'directory to sync into' - _directories $expl - ;; - (git-upload-pack) - local expl - - _description directories expl 'directory to sync from' - _directories $expl - ;; - esac - ;; - esac -} - -(( $+functions[_git-upload-archive] )) || -_git-upload-archive () { - _arguments \ - ':directory to get tar archive from:_directories' && ret=0 -} - -(( $+functions[_git-send-pack] )) || -_git-send-pack () { - _arguments \ - '(--receive-pack --exec)'{--receive-pack=-,--exec=-}'[specify path to git-receive-pack on remote side]:remote path' \ - '--all[update all refs that exist locally]' \ - '--force[update remote orphaned refs]' \ - $verbose_arg \ - $thin_arg \ - ':repository:__git_any_repositories' \ - '*:remote refs:__git_remote_references' && ret=0 -} - -(( $+functions[_git-ssh-fetch] )) || -_git-ssh-fetch () { - _arguments \ - $fetch_args \ - ':commit id:__git_commits' \ - ':URL:_urls' && ret=0 -} - -(( $+functions[_git-ssh-upload] )) || -_git-ssh-upload () { - _arguments \ - $fetch_args \ - ':commit id:__git_commits' \ - ':URL:_urls' && ret=0 -} - -(( $+functions[_git-update-server-info] )) || -_git-update-server-info () { - _arguments \ - '(-f --force)'{-f,--force}'[update the info files from scratch]' && ret=0 -} - -(( $+functions[_git-upload-pack] )) || -_git-upload-pack () { - _arguments \ - '--strict[do not try <directory>/.git/ if <directory> is not a git directory' \ - '--timeout=-[interrupt transfer after given number of seconds of inactivity]: :_guard "[[\:digit\:]]" "inactivity timeout"' \ - ':directory:_directories' && ret=0 -} +# Main Porcelain Commands (( $+functions[_git-add] )) || _git-add () { local curcontext=$curcontext state line declare -A opt_args - _arguments -C -S \ + local ignore_missing= + if (( words[(I)-n|--dry-run] )); then + ignore_missing='--ignore-missing[check if files (even missing) are ignored in dry run]' + fi + + _arguments -w -C -S -s \ '(-n --dry-run)'{-n,--dry-run}'[do not actually add files; only show which ones would be added]' \ '(-v --verbose)'{-v,--verbose}'[show files as they are added]' \ '(-f --force)'{-f,--force}'[allow adding otherwise ignored files]' \ - '(-i --interactive : -)'{-i,--interactive}'[add contents interactively to the index]' \ + '(-i --interactive : -)'{-i,--interactive}'[add contents interactively to index]' \ '(-p --patch)'{-p,--patch}'[like -i but go directly into patch mode for specified files]' \ + '(-e --edit)'{-e,--edit}'[open diff against index in editor]' \ '(-u --update -A --all)'{-u,--update}'[update only files git already knows about]' \ '(-A --all -u --update)'{-A,--all}'[act as both add . and add -u]' \ - '(-N --intent-to-add)'{-N,--intent-to-add}'[record only that the path will be added later]' \ - '--refresh[do not add files, but refresh their stat() info in the index]' \ + '(-N --intent-to-add)'{-N,--intent-to-add}'[record only that path will be added later]' \ + '--refresh[do not add files, but refresh their stat() info in index]' \ '--ignore-errors[continue adding if an error occurs]' \ - '*:file:->files' && ret=0 + $ignore_missing \ + '*:: :->file' && ret=0 case $state in - (files) + (file) + # TODO: Use __git_ignore_line_inside_arguments. declare -a ignored_files_alternatives - if (( words[(I)-f] )); then + if [[ -n ${line[(I)-f|--force]} ]]; then ignored_files_alternatives=( 'ignored-modified-files:ignored modified files:__git_modified_files --ignored' 'ignored-other-files:ignored other files:__git_other_files --ignored') fi _alternative \ - 'modified-files:modified files:__git_modified_files' \ - 'other-files:other files:__git_other_files' \ + 'modified-files::__git_modified_files' \ + 'other-files::__git_other_files' \ $ignored_files_alternatives && ret=0 ;; esac } -__git_zstyle_default ':completion::complete:git-add:argument-rest:*' ignore-line yes - -(( $+functions[_git-stage] )) || -_git-stage () { - _git-add -} (( $+functions[_git-am] )) || _git-am () { - _arguments \ - '--3way[use 3-way merge if patch does not apply cleanly]' \ - '--abort[restore the original branch and abort the patching operation]' \ - '--binary[pass "--allow-binary-replacement" to "git-apply"]' \ - '--dotest=-[use given directory as working area instead of .dotest]:directory:_directories' \ - '--interactive[apply patches interactively]' \ - '--keep[pass "-k" flag to "git-mailinfo"]' \ - '--resolved[continue after resolving patch failure by hand]' \ - '--signoff[add "Signed-off-by:" line to the commit message]' \ + local -a apply_options + __git_setup_apply_options + + # NOTE: --resolvemsg is only for internal use between git rebase and git am. + # TODO: --patch-format is undocumented. + # TODO: --ignore-date is incorrectly documented as being passed to git + # mailsplit. + # TODO: --rebasing, --rerere-autoupdate, and --no-rerere-autoupdate are + # undocumented (and not implemented here). + _arguments -S \ + '(-s --signoff)'{-s,--signoff}'[add Signed-off-by: line to the commit message]' \ + '(-k --keep)'{-k,--keep}'[pass -k to git mailinfo]' \ + '( --no-keep-cr)--keep-cr[pass --keep-cr to git mailsplit]' \ + '(--keep-cr )--no-keep-cr[do not pass --keep-cr to git mailsplit]' \ + '(-c --scissors --no-scissors)'{-c,--scissors}'[strip everything before a scissors line]' \ + '(-c --scissors --no-scissors)--no-scissors[ignore scissors lines]' \ + '(-q --quiet)'{-q,--quiet}'[only print error messages]' \ + '(-u --utf8 --no-utf8)'{-u,--utf8}'[pass -u to git mailinfo]' \ + '(-u --utf8 --no-utf8)--no-utf8[pass -n to git mailinfo]' \ + '(-3 --3way)'{-3,--3way}'[use 3-way merge if patch does not apply cleanly]' \ + $apply_options \ + '(-i --interactive)'{-i,--interactive}'[apply patches interactively]' \ + '--committer-date-is-author-date[use author date as committer date]' \ + '--ignore-date[use committer date as author date]' \ '--skip[skip the current patch]' \ - '--utf8[pass "-u" flag to "git-mailinfo"]' \ - '--no-utf8[do not pass "-u" flag to "git-mailinfo"]' \ - $common_apply_args \ + '(--continue -r --resolved)'{--continue,-r,--resolved}'[continue after resolving patch failure by hand]' \ + '--abort[restore the original branch and abort the patching operation]' \ + '--patch-format=-[specify format patches are in]:patch format:((mbox\:"mbox format" + stgit-series\:"StGit patch series" + stgit\:"stgit format"))' \ '*:mbox file:_files' && ret=0 } @@ -1476,20 +127,22 @@ _git-archive () { esac fi - _arguments -C \ + _arguments -w -C -S -s \ '--format=-[format of the resulting archive]:archive format:__git_archive_formats' \ '(- :)'{-l,--list}'[list available archive formats]' \ '(-v --verbose)'{-v,--verbose}'[report progress to stderr]' \ - '--prefix=-[prepend the given path prefix to to each filename]:path prefix:_directories -r ""' \ + '--prefix=-[prepend the given path prefix to each filename]:path prefix:_directories -r ""' \ + '--output=[write archive to argument instead of stdout]:archive:_files' \ + '--worktree-attributes[look for attributes in .gitattributes in working directory too]' \ $backend_args \ - '--remote=-[archive remote repository]:remote repository:__git_any_repositories' \ - '--exec=-[path to git-receive-pack on remote]:remote path:_files' \ - ':tree-ish:__git_tree_ishs' \ - '*:tree file:->files' && ret=0 + '--remote=[archive remote repository]:remote repository:__git_any_repositories' \ + '--exec=[path to git-receive-pack on remote]:remote path:_files' \ + ': :__git_tree_ishs' \ + '*: :->file' && ret=0 case $state in - (files) - __git_tree_files . $line[1] && ret=0 + (file) + __git_tree_files ${PREFIX:-.} $line[1] && ret=0 ;; esac } @@ -1508,152 +161,270 @@ _git-applymbox () { (( $+functions[_git-bisect] )) || _git-bisect () { - local bisect_cmds - - bisect_cmds=( - bad:"mark current or given revision as bad" - good:"mark current or given revision as good" - log:"show the log of the current bisection" - next:"find next bisection to test and check it out" - replay:"replay a bisection log" - reset:"finish bisection search and return to the given branch (or master)" - start:"reset bisection state and start a new bisection" - visualize:"show the remaining revisions in gitk" - skip:"choose a nearby commit" - run:"run evaluation script" - ) + # TODO: next subcommand is undocumented. Git-bisect.sh mentions that the + # subcommand might be removed from the UI level. + local curcontext=$curcontext state line + declare -A opt_args - if (( CURRENT == 2 )); then - _describe -t command "git-bisect commands" bisect_cmds && ret=0 - else - case $words[2] in - (bad) - _arguments \ - '2:revision:__git_commits' && ret=0 - ;; - (good|skip) - _arguments \ - '*:revision:__git_commits' && ret=0 - ;; - (replay) - _arguments \ - '2:file:_files' && ret=0 - ;; - (reset) - _arguments \ - '2:branch:__git_heads' && ret=0 - ;; - (run) - _arguments \ - '*::arguments: _normal' && ret=0 - ;; - (start) - if (( words[(I)--] < CURRENT && words[(I)--] > 0 )); then + _arguments -C \ + '--help[display git-bisect manual page]' \ + ': :->command' \ + '*:: :->option-or-argument' && ret=0 + + case $state in + (command) + declare -a commands + + commands=( + help:'display a short usage description' + start:'reset bisection state and start a new bisection' + bad:'mark current or given revision as bad' + good:'mark current or given revision as good' + skip:'choose a nearby commit' + next:'find next bisection to test and check it out' + reset:'finish bisection search and return to the given branch (or master)' + visualize:'show the remaining revisions in gitk' + view:'show the remaining revisions in gitk' + replay:'replay a bisection log' + log:'show the log of the current bisection' + run:'run evaluation script') + + _describe -t commands command commands && ret=0 + ;; + (option-or-argument) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (start) + _arguments -C \ + ':bad revision:__git_commits' \ + '*: :->revision-or-path' && ret=0 + case $state in + (revision-or-path) + if compset -N '--' || ! __git_is_committish $line[CURRENT-1]; then + __git_cached_files && ret=0 + else + _alternative \ + 'revisions::__git_revisions' \ + 'files::__git_cached_files' && ret=0 + fi + ;; + esac + ;; + (bad) _arguments \ - '*:paths:_files' && ret=0 - else + ': :__git_commits' && ret=0 + ;; + (good|skip) + # TODO: skip can take revlists. _arguments \ - '2:bad revision:__git_commits' \ - '*:good revision:__git_commits' && ret=0 - fi - ;; - - (*) - _nothing - ;; - esac - fi + '*: :__git_commits' && ret=0 + ;; + (replay) + _arguments \ + ':log file:_files' && ret=0 + ;; + (reset) + _arguments \ + ': :__git_heads' && ret=0 + ;; + (run) + _arguments \ + '*:: : _normal' && ret=0 + ;; + (view|visualize) + local -a log_options revision_options + __git_setup_log_options + __git_setup_revision_options + + _arguments -w -C -s \ + $log_options \ + $revision_options && ret=0 + (*) + _nothing + ;; + esac + ;; + esac } -# TODO: complete branch names? (( $+functions[_git-branch] )) || _git-branch () { + declare l c m d + + l='--color --no-color -r -a -v --verbose --abbrev --no-abbrev' + c='-l -f --force -t --track --no-track --set-upstream --contains --merged --no-merged' + m='-m -M' + d='-d -D' + + declare -a dependent_creation_args + if (( words[(I)-r] == 0 )); then + dependent_creation_args=( + "($l $m $d): :__git_branch_names" + "::start-point:__git_revisions") + fi + declare -a dependent_deletion_args if (( words[(I)-d] || words[(I)-D] )); then + dependent_creation_args= dependent_deletion_args=( - '-r[delete remote-tracking branches]' - '*:branch-name:__git_branch_names') + '-r[delete only remote-tracking branches]') + if (( words[(I)-r] )); then + dependent_deletion_args+='*: :__git_ignore_line_inside_arguments __git_remote_branch_names' + else + dependent_deletion_args+='*: :__git_ignore_line_inside_arguments __git_branch_names' + fi fi declare -a dependent_modification_args if (( words[(I)-m] || words[(I)-M] )); then + dependent_creation_args= dependent_modification_args=( - ':old or new branch-name:__git_branch_names' - '::new branch-name:__git_branch_names') + ':old or new branch name:__git_branch_names' + '::new branch name:__git_branch_names') fi - # TODO: I’m not happy with having to force a pattern with -A. - _arguments -S -A "-*" \ - - list \ - '( --no-color)--color[turn on branch coloring]' \ - '(--color )--no-color[turn off branch coloring]' \ - '( -a)-r[list only the remote-tracking branches]' \ - '(-r )-a[list both remote-tracking branches and local branches]' \ - '-v[show SHA1 and commit subject line for each head]' \ - $abbrev_arg \ - '--no-abbrev[do not abbreviate sha1s]' \ - - create \ - '-l[create the branch'\''s reflog]' \ - '-f[force the creation of a new branch]' \ - '--track[set up configuration so pull merges from the start point]' \ - '--no-track[override the branch.autosetupmerge configuration variable]' \ - '--contains=[only list branches which contain the specified commit]:commit:__git_committishs' \ - '--merged[only list branches which are fully contained by HEAD]' \ - '--no-merged[do not list branches which are fully contained by HEAD]' \ - ':branch-name:__git_branch_names' \ - '::start-point:__git_revisions' \ - - modify \ - '( -M)-m[rename a branch and the corresponding reflog]' \ - '(-m )-M[rename a branch even if the new branch-name already exists]' \ - $dependent_modification_args \ - - delete \ - '( -D)-d[delete a fully merged branch]' \ - '(-d )-D[delete a branch]' \ - $dependent_deletion_args && ret=0 -} -__git_zstyle_default ':completion::complete:git-branch:delete-argument-rest:*' ignore-line yes - -# TODO: __git_tree_ishs is just stupid. It should be giving us a list of tags -# and perhaps also allow all that just with ^{tree} and so on. Not quite sure -# how to do that, though. -(( $+functions[_git-checkout] )) || -_git-checkout () { + _arguments -w -S -s \ + "($c $m $d --no-color :)--color=-[turn on branch coloring]:: :__git_color_whens" \ + "($c $m $d : --color)--no-color[turn off branch coloring]" \ + "($c $m -a)-r[list or delete only remote-tracking branches]" \ + "($c $m $d : -r)-a[list both remote-tracking branches and local branches]" \ + "($c $m $d : -v --verbose)"{-v,--verbose}'[show SHA1 and commit subject line for each head]' \ + "($c $m $d :)--abbrev=[set minimum SHA1 display-length]: :__git_guard_number length" \ + "($c $m $d :)--no-abbrev[do not abbreviate sha1s]" \ + "($l $m $d)-l[create the branch's reflog]" \ + "($l $m $d -f --force)"{-f,--force}"[force the creation of a new branch]" \ + "($l $m $d -t --track)"{-t,--track}"[set up configuration so that pull merges from the start point]" \ + "($l $m $d)--no-track[override the branch.autosetupmerge configuration variable]" \ + "($l $m $d)--set-upstream[set up configuration so that pull merges]" \ + "($l $m $d)--contains=[only list branches which contain the specified commit]: :__git_committishs" \ + "($l $m $d)--merged=[only list branches which are fully contained by HEAD]: :__git_committishs" \ + "($l $m $d)--no-merged=[do not list branches which are fully contained by HEAD]: :__git_committishs" \ + $dependent_creation_args \ + "($l $c $d -M)-m[rename a branch and the corresponding reflog]" \ + "($l $c $d -m)-M[rename a branch even if the new branch-name already exists]" \ + $dependent_modification_args \ + "($l $c $m -D)-d[delete a fully merged branch]" \ + "($l $c $m -d)-D[delete a branch]" \ + $dependent_deletion_args && ret=0 +} + +(( $+functions[_git-bundle] )) || +_git-bundle () { local curcontext=$curcontext state line declare -A opt_args - local new_branch_reflog_arg + _arguments -C \ + ': :->command' \ + '*:: :->option-or-argument' && ret=0 - if (( words[(I)-b] > 0 )); then - new_branch_reflog_arg='-l[create the new branch'\''s reflog]' - fi + case $state in + (command) + declare -a commands - if compset -N '--'; then - __git_cached_files - else - _arguments -C -S \ - '-q[suppress feedback messages]' \ - - switch-branch \ - '-f[force a complete re-read]' \ - '-b[create a new branch based at given branch]: :__git_guard_branch-name' \ - {-t,--track}'[set up configuration so pull merges from the start point]' \ - '--no-track[override the branch.autosetupmerge configuration variable]' \ - '-l[create the branch'\''s reflog]' \ - $new_branch_reflog_arg \ - '-m[3way merge current branch, working tree and new branch]' \ - '::branch:__git_revisions' \ - - update-files \ - '::tree-ish:__git_tree_ishs' \ - '*::file:->files' && ret=0 + commands=( + 'create:create a bundle' + 'verify:check that a bundle is valid and will apply cleanly' + 'list-heads:list references defined in bundle' + 'unbundle:unbundle a bundle to repository') + + _describe -t commands command commands && ret=0 + ;; + (option-or-argument) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (create) + if (( CURRENT == 2 )); then + _arguments \ + ':bundle:_files' && ret=0 + else + local revision_options + __git_setup_revision_options + + _arguments -w -S -s \ + $revision_options \ + ': :_files' \ + '*: :__git_commit_ranges2' && ret=0 + fi + ;; + (verify) + _arguments \ + ':bundle:_files' && ret=0 + ;; + (list-heads|unbundle) + _arguments \ + '*: :__git_ref_specs' && ret=0 + ;; + esac + ;; + esac +} + +(( $+functions[_git-checkout] )) || +_git-checkout () { + # TODO: __git_tree_ishs is just stupid. It should be giving us a list of tags + # and perhaps also allow all that just with ^{tree} and so on. Not quite sure + # how to do that, though. + local new_branch_reflog_opt + if (( words[(I)-b|-B] )); then + new_branch_reflog_opt="(--patch)-l[create the new branch's reflog]" fi - #XXX TODO and all that: $line[1] only works if you didn't write any options. - #What's the variable that holds the tree-ish argument? Is it even reliably possible? + local curcontext=$curcontext state line + declare -A opt_args + + _arguments -w -C -s \ + '(-q --quiet)'{-q,--quiet}'[suppress feedback messages]' \ + '(-f --force -m --merge --conflict --patch)'{-f,--force}'[force branch switch/ignore unmerged entries]' \ + '(-q --quiet --theirs --patch)--ours[check out stage #2 for unmerged paths]' \ + '(-q --quiet --ours --patch)--theirs[check out stage #3 for unmerged paths]' \ + '( -B --orphan --ours --theirs --conflict --patch)-b[create a new branch based at given commit]: :__git_branch_names' \ + '(-b --orphan --ours --theirs --conflict --patch)-B[create or update branch based at given commit]: :__git_branch_names' \ + '(-t --track --orphan --patch)'{-t,--track}'[set up configuration so pull merges from the base commit]' \ + '(--patch)--no-track[override the branch.autosetupmerge configuration variable]' \ + $new_branch_reflog_opt \ + '(-b -B -t --track --patch)--orphan[create a new orphan branch based at given commit]: :__git_branch_names' \ + '(-q --quiet -f --force -m --merge --conflict --patch)'{-m,--merge}'[3way merge current branch, working tree and new branch]' \ + '(-q --quiet -f --force -m --merge --patch)--conflict[same as --merge, using given merge style]:style:(merge diff3)' \ + '(-)'{-p,--patch}'[interactively select hunks in diff between given tree-ish and working tree]' \ + '(-)--[start file arguments]' \ + '*:: :->branch-or-tree-ish-or-file' && ret=0 + case $state in - (files) - if [[ -n $line[1] ]] && __git_is_treeish $line[1]; then - __git_tree_files . $line[1] && ret=0 + (branch-or-tree-ish-or-file) + # TODO: Something about *:: brings us here when we complete at “-â€. I + # guess that this makes sense in a way, as we might want to treat it as + # an argument, but I can’t find anything in the documentation about this + # behavior. + [[ $line[CURRENT] = -* ]] && return + if (( CURRENT == 1 )) && [[ -z $opt_args[(I)--] ]]; then + # TODO: Allow A...B + local branch_arg='branches::__git_revisions' \ + tree_ish_arg='tree-ishs::__git_tree_ishs' \ + file_arg='modified-files::__git_modified_files' + + if [[ -n ${opt_args[(I)-b|-B|--orphan]} ]]; then + tree_ish_arg= + file_arg= + elif [[ -n $opt_args[(I)--track] ]]; then + branch_arg='remote-branches::__git_remote_branch_names' + tree_ish_arg= + file_arg= + elif [[ -n ${opt_args[(I)--ours|--theirs|-m|--conflict|--patch]} ]]; then + branch_arg= + fi + + _alternative \ + $branch_arg \ + $tree_ish_arg \ + $file_arg && ret=0 + elif [[ -n ${opt_args[(I)-b|-B|-t|--track|--orphan]} ]]; then + _nothing && ret=0 + elif [[ -n $line[1] ]] && __git_is_treeish $line[1]; then + __git_ignore_line __git_tree_files ${PREFIX:-.} $line[1] && ret=0 else - __git_cached_files && ret=0 + __git_ignore_line __git_modified_files && ret=0 fi ;; esac @@ -1662,127 +433,352 @@ _git-checkout () { (( $+functions[_git-cherry-pick] )) || _git-cherry-pick () { _arguments \ - '(-e --edit)'{-e,--edit}'[edit commit before committing the revert]' \ - '(-n --no-commit)'{-n,--no-commit}'[do not make the actually commit]' \ - '(-r --replay)'{-r,--replay}'[use original commit message intact]' \ + '(-e --edit --ff)'{-e,--edit}'[edit commit before committing the revert]' \ + '(--ff)-x[append information about what commit was cherry-picked]' \ '(-m --mainline)'{-m,--mainline}'[specify mainline when cherry-picking a merge commit]:parent number' \ - '-x[append information about what commit was cherry-picked]' \ - '(-s --signoff)'{-s,--signoff}'[add Signed-off-by line at the end of the commit message]' \ - ':commit:__git_revisions' && ret=0 + '(-n --no-commit --ff)'{-n,--no-commit}'[do not make the actually commit]' \ + '(-s --signoff --ff)'{-s,--signoff}'[add Signed-off-by line at the end of the commit message]' \ + '(-e --edit -x -n --no-commit -s --signoff)--ff[fast forward, if possible]' \ + ': :__git_revisions' && ret=0 +} + +(( $+functions[_git-citool] )) || +_git-citool () { + _nothing } (( $+functions[_git-clean] )) || _git-clean () { - _arguments -S -s \ + local curcontext=$curcontext state line + declare -A opt_args + + _arguments -w -C -S -s \ '-d[also remove untracked directories]' \ - '-n[do a dry run]' \ - '-f[required when clean.requireForce is true (default)]' \ - '-q[run quietly]' \ + '(-f --force)'{-f,--force}'[required when clean.requireForce is true (default)]' \ + '(-n --dry-run)'{-n,--dry-run}'[only show what would and what would not be removed]' \ + '(-q --quiet)'{-q,--quiet}'[only report errors]' \ + '*'{-e,--exclude=}'[skip files matching specified pattern]:pattern' \ '(-X )-x[also remove ignored files]' \ '( -x)-X[remove only ignored files]' \ - '*:file:_files' && ret=0 + '*: :->file' && ret=0 + + case $state in + (file) + local exclusion ignored_other_files_alt other_files_alt + declare -a exclusions + for spec in $opt_args[-e] $opt_args[--exclude]; do + integer i + for (( i = 1; i <= $#spec; i++ )); do + case $spec[i] in + (\\) + if (( i + 1 <= $#spec )) && [[ $spec[i+1] == : ]]; then + (( i++ )) + exclusion+=: + else + exclusion+=$spec[i] + fi + ;; + (:) + exclusions+=(-x $exclusion) exclusion= + ;; + (*) + exclusion+=$spec[i] + ;; + esac + done + done + [[ -n $exclusion ]] && exclusions+=(-x $exclusion) + if [[ -n ${opt_args[(I)-x|-X]} ]]; then + ignored_other_files_alt="ignored-untracked-files::__git_ignored_other_files $exclusions" + fi + if [[ -z ${opt_args[(I)-X]} ]]; then + other_files_alt="untracked-files::__git_other_files $exclusions" + fi + _alternative \ + $ignored_other_files_alt \ + $other_files_alt && ret=0 + ;; + esac } -# TODO: The --no-checkout is undocumented. (( $+functions[_git-clone] )) || _git-clone () { - _arguments -S \ - '--bare[make a bare GIT repository]' \ - '--mirror[clone refs into refs/* instead of refs/remotes/origin/*]' \ + local curcontext=$curcontext state line + declare -A opt_args + + # TODO: Argument to -o should be a remote name. + # TODO: Argument to -b should complete branch names in the repository being + # cloned. + _arguments -w -C -S -s \ '(-l --local)'{-l,--local}'[clone locally, hardlink refs and objects if possible]' \ + '--no-hardlinks[copy files instead of hardlinking when doing a local clone]' \ '(-s --shared)'{-s,--shared}'[share the objects with the source repository (warning: see man page)]' \ '--reference[reference repository]:repository:_directories' \ '(-q --quiet)'{-q,--quiet}'[operate quietly]' \ '(-v --verbose)'{-v,--verbose}'[always display the progressbar]' \ + '--progress[output progress even if stderr is not a terminal]' \ '(-n --no-checkout)'{-n,--no-checkout}'[do not checkout HEAD after clone is complete]' \ - '(-o --origin)'{-o,--origin}'[use given name instead of "origin" as branch name]:name:__git_guard_branch-name' \ - '--no-hardlinks[copy files instead of hardlinking when doing a local clone]' \ - $upload_pack_arg \ - $template_arg \ - '--depth[create a shallow clone, given number of revisions deep]: :_guard "[[\:digit\:]]##" depth' \ - ':repository:__git_any_repositories' \ - ':directory:_directories' && ret=0 + '(-o --origin)--bare[make a bare GIT repository]' \ + '(--bare)--mirror[clone refs into refs/* instead of refs/remotes/origin/*]' \ + '(-o --origin --bare)'{-o,--origin}'[use given remote name instead of "origin"]: :__git_guard_branch-name' \ + '(-b --branch)'{-b,--branch}'[point HEAD to the given branch]: :__git_guard_branch-name' \ + '(-u --upload-pack)'{-u,--upload-pack=}'[specify path to git-upload-pack on remote side]:remote path' \ + '--template=[directory to use as a template for the object database]: :_directories' \ + '--depth[create a shallow clone, given number of revisions deep]: :__git_guard_number depth' \ + '--recursive[initialize all contained submodules]' \ + ': :->repository' \ + ': :_directories' && ret=0 + + case $state in + (repository) + if [[ -n ${opt_args[(I)-l|--local|--no-hardlinks|-s|--shared|--reference]} ]]; then + __git_local_repositories && ret=0 + else + __git_any_repositories && ret=0 + fi + ;; + esac } (( $+functions[_git-commit] )) || _git-commit () { - _arguments -S \ + local amend_opt='--amend[amend the tip of the current branch]' + if __git_is_initial_commit || __git_is_in_middle_of_merge; then + amend_opt= + fi + + local reset_author_opt= + if (( words[(I)-C|--reuse-message(=*|)|-c|--reedit-message(=*|)|--amend] )); then + reset_author_opt='(--author)--reset-author[make committer the author of the commit]' + fi + + # TODO: --null is an undocumented alias. + # TODO: --interactive isn’t explicitly listed in the documentation. + _arguments -w -S -s \ + '(-a --all --interactive -o --only -i --include *)'{-a,--all}'[stage all modified and deleted paths]' \ + $reset_author_opt \ + '( --porcelain --dry-run)--short[output dry run in short format]' \ + '(--short --dry-run)--porcelain[output dry run in porcelain-ready format]' \ + '(--short --porcelain --dry-run -z --null)'{-z,--null}'[separate dry run entry output with NUL]' \ + '(--reset-author)--author[override the author name used in the commit]:author name' \ + '--date=[override the author date used in the commit]:date' \ + '(-s --signoff)'{-s,--signoff}'[add Signed-off-by line at the end of the commit message]' \ + '(-n --no-verify)'{-n,--no-verify}'[do not look for suspicious lines the commit introduces]' \ '--allow-empty[allow recording an empty commit]' \ - '(-a --all --interactive)'{-a,--all}'[update all paths in the index file]' \ - '(-a --all --interactive)--interactive[interactively update paths in the index file]' \ - '--author[override the author name used in the commit]:author name' \ - '--cleanup=-[specify how the commit message should be cleaned up]:mode:((verbatim\:"don'\''t change the commit message at all" - whitespace\:"remove leading and trailing whitespace lines" - strip\:"remove both whitespace and commentary lines" - default\:"act as '\''strip'\'' if the message is to be edited and as '\''whitespace'\'' otherwise"))' \ + '--allow-empty-message[allow recording a commit with an empty message]' \ + '--cleanup=[specify how the commit message should be cleaned up]:mode:((verbatim\:"don'\''t change the commit message at all" + whitespace\:"remove leading and trailing whitespace lines" + strip\:"remove both whitespace and commentary lines" + default\:"act as '\''strip'\'' if the message is to be edited and as '\''whitespace'\'' otherwise"))' \ '(-e --edit)'{-e,--edit}'[edit the commit message before committing]' \ - '(-o --only -i --include)'{-i,--include}'[update the given files and commit the whole index]' \ - '(-o --only -i --include)'{-o,--only}'[commit only the given files]' \ - '(-n --no-verify)'{-n,--no-verify}'[do not look for suspicious lines the commit introduces]' \ - '(-s --signoff)'{-s,--signoff}'[add Signed-off-by line at the end of the commit message]' \ - '(-q --quiet -v --verbose)'{-q,--quiet}'[suppress commit summary message]' \ + '(-a --all --interactive -o --only -i --include)'{-i,--include}'[update the given files and commit the whole index]' \ + '(-a --all --interactive -o --only -i --include)'{-o,--only}'[commit only the given files]' \ + '(-u --untracked-files)'{-u-,--untracked-files=}'[show files in untracked directories]::mode:((no\:"show no untracked files" + normal\:"show untracked files and directories" + all\:"show individual files in untracked directories"))' \ '(-q --quiet -v --verbose)'{-v,--verbose}'[show unified diff of all file changes]' \ - '(-u --untracked-files)'{-u,--untracked-files}'[show files in untracked directories]' \ - '*:file:__git_changed_files' \ + '(-q --quiet -v --verbose)'{-q,--quiet}'[suppress commit summary message]' \ + '--dry-run[only show list of paths that are to be commited or not, and any untracked]' \ + '( --no-status)--status[include the output of git status in the commit message template]' \ + '(--status )--no-status[do not include the output of git status in the commit message template]' \ + '(-a --all --interactive -o --only -i --include *)--interactive[interactively update paths in the index file]' \ + '*: :__git_ignore_line_inside_arguments __git_changed_files' \ - '(message)' \ - '--amend[amend the tip of the current branch]' \ - {-c,--reedit-message=}'[use existing commit object and edit log message]:commit:__git_commits' \ - {-C,--reuse-message=}'[use existing commit object with same log message]:commit:__git_commits' \ - {-F,--file=}'[read commit message from given file]:file:_files' \ - {-m,--message=}'[use the given message as the commit message]:message' && ret=0 + {-C,--reuse-message=}'[use existing commit object with same log message]: :__git_commits' \ + {-c,--reedit-message=}'[use existing commit object and edit log message]: :__git_commits' \ + {-F,--file=}'[read commit message from given file]: :_files' \ + {-m,--message=}'[use the given message as the commit message]:message' \ + {-t,--template=}'[use file as a template commit message]:template:_files' \ + $amend_opt && ret=0 } -__git_zstyle_default ':completion::complete:git-commit:argument-rest:*' ignore-line yes +(( $+functions[_git-describe] )) || +_git-describe () { + _arguments -w -S -s \ + '(*)--dirty=-[describe HEAD, adding mark if dirty]::mark' \ + '--all[use any ref found in "$GIT_DIR/refs/"]' \ + '--tags[use any ref found in "$GIT_DIR/refs/tags"]' \ + '(--tags)--contains[find the tag after the commit instead of before]' \ + '(--long)--abbrev=[set minimum SHA1 display-length]: :__git_guard_number length' \ + '( --exact-match)--candidates=[consider up to given number of candidates]: :__git_guard_number "number of candidates"' \ + '(--candidates )--exact-match[only output exact matches, same as --candidates=0]' \ + '--debug[display information about the searching strategy]' \ + '(--abbrev)--long[always show full format, even for exact matches]' \ + '--match=[only consider tags matching glob pattern]:pattern' \ + '--always[show uniquely abbreviated commit object as fallback]' \ + '*: :__git_committishs' && ret=0 +} -# TODO: __git_files should be __git_tree_files (do like in git-diff-tree and -# such) (( $+functions[_git-diff] )) || _git-diff () { - _arguments -S \ - $diff_args \ + local curcontext=$curcontext state line + declare -A opt_args + + local -a diff_options + __git_setup_diff_options + + _arguments -w -C -s \ + $* \ + $diff_options \ '(--cached --staged)'{--cached,--staged}'[show diff between index and named commit]' \ - '::commit range:__git_commit_ranges' \ - '::original revision:__git_objects' \ - '::new revision:__git_objects' \ - '*::index file:__git_files' && ret=0 + '(-)--[start file arguments]' \ + '*:: :->from-to-file' && ret=0 + + case $state in + (from-to-file) + case $CURRENT in + (1) + if [[ -n ${opt_args[(I)--]} ]]; then + if [[ -n ${opt_args[(I)--cached|--staged]} ]]; then + __git_changed-in-index_files && ret=0 + else + __git_changed-in-working-tree_files && ret=0 + fi + else + local files_alt='files::__git_changed-in-working-tree_files' + + if [[ -n ${opt_args[(I)--cached|--staged]} ]]; then + files_alt='files::__git_changed-in-index_files' + fi + + _alternative \ + 'commit-ranges::__git_commit_ranges' \ + 'blobs-and-trees-in-treeish::__git_blobs_and_trees_in_treeish' \ + $files_alt \ + 'blobs::__git_blobs ' && ret=0 + fi + ;; + (2) + if __git_is_committish_range $line[1]; then + __git_tree_files ${PREFIX:-.} $(__git_committish_range_last $line[1]) && ret=0 + elif __git_is_committish $line[1] || __git_is_treeish $line[1]; then + if [[ -n ${opt_args[(I)--]} ]]; then + __git_changed-in-working-tree_files && ret=0 + else + _alternative \ + 'commits::__git_commits' \ + 'blobs-and-trees-in-treeish::__git_blobs_and_trees_in_treeish' \ + 'files::__git_changed-in-working-tree_files' && ret=0 + fi + elif __git_is_blob $line[1]; then + if [[ -n ${opt_args[(I)--]} ]]; then + __git_cached_files && ret=0 + else + _alternative \ + 'files::__git_cached_files' \ + 'blobs::__git_blobs' && ret=0 + fi + elif [[ -n ${opt_args[(I)--cached|--staged]} ]]; then + __git_changed-in-index_files && ret=0 + else + __git_changed-in-working-tree_files && ret=0 + fi + ;; + (*) + if __git_is_committish_range $line[1]; then + __git_tree_files ${PREFIX:-.} $(__git_committish_range_last $line[1]) && ret=0 + elif { __git_is_committish $line[1] && __git_is_committish $line[2] } || + __git_is_treeish $line[2]; then + __git_tree_files ${PREFIX:-.} $line[2] && ret=0 + elif __git_is_blob $line[1] && __git_is_blob $line[2]; then + _nothing + else + __git_changed-in-working-tree_files && ret=0 + fi + ;; + esac + ;; + esac } (( $+functions[_git-fetch] )) || _git-fetch () { - _arguments \ - $common_fetch_args \ - ':repository:__git_any_repositories' \ - '*:refspec:__git_ref_specs' && ret=0 + local curcontext=$curcontext state line + declare -A opt_args + + local -a fetch_options + __git_setup_fetch_options + + _arguments -w -C -S -s \ + $fetch_options \ + '--multiple[allow several repository arguments]' \ + '*:: :->repository-or-group-or-refspec' && ret=0 + + case $state in + (repository-or-group-or-refspec) + if (( CURRENT > 1 )) && [[ -z ${opt_args[(I)--multiple]} ]]; then + __git_ref_specs && ret=0 + else + _alternative \ + 'remotes::__git_remotes' \ + 'remotes-groups::__git_remotes_groups' \ + 'local-repositories::__git_local_repositories' \ + 'remote-repositories::__git_remote_repositories' && ret=0 + fi + ;; + esac } (( $+functions[_git-format-patch] )) || _git-format-patch () { - _arguments \ - $diff_args \ - '(-h --help)'{-h,--help}'[display usage information]' \ - '(-k --keep-subject -n --numbered)'{-k,--keep-subject}'[do not strip/add \[PATCH\] from the first line of the commit message]' \ - '(-k --keep-subject -n --numbered)'{-n,--numbered}'[name output in \[PATCH n/m\] format]' \ - '--start-number=[start numbering patches at given number]: :_guard "[[\:digit\:]]" "patch number"' \ - '(-o --output-directory --stdout)'{-o,--output-directory}'[store resulting files in given directory]:directory:_directories' \ + local curcontext=$curcontext state line + declare -A opt_args + + local -a diff_options + __git_setup_diff_options + + # TODO: -- is wrong. + # TODO: Should filter out --name-only, --name-status, and --check from + # $diff_options. + _arguments -w -C -S -s \ + $diff_options \ + '--[limit the number of patches to prepare]: :__git_guard_number "number of patches to prepare"' \ + '(-o --output-directory --stdout)'{-o,--output-directory}'[store resulting files in given directory]: :_directories' \ + '(-n --numbered -N --no-numbered -k --keep-subject)'{-n,--numbered}'[name output in \[PATCH n/m\] format]' \ + '(-n --numbered -N --no-numbered -k --keep-subject)'{-N,--no-numbered}'[name output in \[PATCH\] format]' \ + '--start-number=[start numbering patches at given number]: :__git_guard_number "patch number"' \ + '--numbered-files[use only number for file name]' \ + '(-n --numbered -N --no-numbered -k --keep-subject --subject-prefix)'{-k,--keep-subject}'[do not strip/add \[PATCH\] from the first line of the commit message]' \ + '(-s --signoff)'{-s,--signoff}'[add Signed-off-by: line to the commit message]' \ '(-o --output-directory)--stdout[output the generated mbox on standard output (implies --mbox)]' \ - '(-s --signoff)'{-s,--signoff}'[add "Signed-off-by:" line to the commit message]' \ - '--attach=-[create attachments instead of inlining patches]::git version string' \ - '--thread[make the second and subsequent mails refer to the first]' \ + '( --no-attach --inline)--attach=-[create attachments instead of inlining patches]::boundary' \ + '(--attach --inline)--no-attach[disable creation of attachments]' \ + '(--attach --no-attach )--inline=-[inline patches]::boundary' \ + '( --no-thread)--thread=-[make the second and subsequent mails refer to the first]::style:((shallow\:"all refer to the first" + deep\:"each refers to the previous"))' \ + '(--thread )--no-thread[do not thread messages]' \ '--in-reply-to=[make the first mail a reply to the given message]:message id' \ '--ignore-if-in-upstream[do not include a patch that matches a commit in the given range]' \ - '--suffix[use the given suffix for filenames]:filename suffix' \ - '--subject-prefix=[use the given prefix instead of \[PATCH\]]:prefix' \ - '--cc=[add a Cc: header, may be given multiple times]:email address' \ + '(-k --keep-subject)--subject-prefix=[use the given prefix instead of \[PATCH\]]:prefix' \ + '*--to=[add To: header to email headers]: :_email_addresses' \ + '*--cc=[add Cc: header to email headers]: :_email_addresses' \ + '*--add-header=[add an arbitrary header to email headers]:header' \ '--cover-letter[generate a cover letter template]' \ + '( --no-signature)--signature=[add a signature]:signature' \ + '(--signature )--no-signature[do not add a signature]' \ + '--suffix=[use the given suffix for filenames]:filename suffix' \ '--no-binary[do not output contents of changes in binary files, only note that they differ]' \ - ':commit range:__git_commit_ranges' && ret=0 + '--root[treat the revision argument as a range]' \ + ': :->commit-or-commit-range' && ret=0 + + case $state in + (commit-or-commit-range) + if [[ -n ${opt_args[(I)--root]} ]]; then + __git_commits && ret=0 + else + __git_commit_ranges && ret=0 + fi + ;; + esac } (( $+functions[_git-gc] )) || _git-gc () { - _arguments \ + _arguments -w -S -s \ '--aggressive[more aggressively optimize]' \ '--auto[check whether housekeeping is required]' \ + '( --no-prune)--prune=[prune loose objects older than given date]: :__git_datetimes' \ + '(--prune )--no-prune[do not prune any loose objects]' \ '--quiet[suppress all progress reports]' && ret=0 } @@ -1790,6 +786,7 @@ _git-gc () { _git-grep () { local -a pattern_operators + # TODO: Need to deal with grouping with ( and ) if (( words[(I)-e] == CURRENT - 2 )); then pattern_operators=( '--and[both patterns must match]' @@ -1800,10 +797,14 @@ _git-grep () { local curcontext=$curcontext state line declare -A opt_args - _arguments -A '--*' \ - '--cached[grep blobs registered in index file instead of working tree]' \ + # TODO: Need to implement -<num> as a shorthand for -C<num> + _arguments -C -A '-*' \ + '(-O --open-files-in-pager --no-index)--cached[search blobs registered in index file instead of working tree]' \ + '(--cached)--no-index[search files in current directory, not just treacked files]' \ '(-a --text)'{-a,--text}'[process binary files as if they were text]' \ '(-i --ignore-case)'{-i,--ignore-case}'[ignore case when matching]' \ + '-I[do not match pattern in binary files]' \ + '--max-depth=[descend at most given levels of directories]:__git_guard_number depth' \ '(-w --word-regexp)'{-w,--word-regexp}'[match only whole words]' \ '(-v --invert-match)'{-v,--invert-match}'[select non-matching lines]' \ '( -H)-h[supress output of filenames]' \ @@ -1811,23 +812,30 @@ _git-grep () { '--full-name[output paths relative to the project top directory]' \ '(-E --extended-regexp -G --basic-regexp)'{-E,--extended-regexp}'[use POSIX extended regexes]' \ '(-E --extended-regexp -G --basic-regexp)'{-G,--basic-regexp}'[use POSIX basic regexes]' \ + '(-F --fixed-strings)'{-F,--fixed-strings}'[do not interpret pattern as a regex]' \ '-n[prefix the line number to matching lines]' \ '(-l --files-with-matches -L --files-without-match --name-only)'{-l,--files-with-matches,--name-only}'[show only names of matching files]' \ '(-l --files-with-matches -L --files-without-match)'{-L,--files-without-match}'[show only names of non-matching files]' \ - {-z,--null}'[output \0 after filenames]' \ + '(--cached -O --open-files-in-pager)'{-O,--open-files-in-pager}'=-[open matching files in pager]::_path_commands' \ + '(-z --null)'{-z,--null}'[output \0 after filenames]' \ '(-c --count)'{-c,--count}'[show number of matching lines in files]' \ - '-A[show trailing context]: :_guard "[[\:digit\:]]#" lines' \ - '-B[show leading context]: :_guard "[[\:digit\:]]#" lines' \ - '-C[show context]: :_guard "[[\:digit\:]]#" lines' \ + '( --no-color)--color=-[color matches]:: :__git_color_whens' \ + '(--color )---no-color[do not color matches]' \ + '-A[show trailing context]: :__git_guard_number lines' \ + '-B[show leading context]: :__git_guard_number lines' \ + '-C[show context]: :__git_guard_number lines' \ + '(-p --show-function)'{-p,--show-function}'[show preceding line containing function name of match]' \ '(1)*-f[read patterns from given file]:pattern file:_files' \ '(1)*-e[use the given pattern for matching]:pattern' \ $pattern_operators \ '--all-match[all patterns must match]' \ - ':pattern:' \ - '*::tree-or-file:->files' && ret=0 + ':pattern' \ + '*:: :->tree-or-file' && ret=0 + # TODO: If --cached, --no-index, -O, or --open-files-in-pager was given, + # don’t complete treeishs. case $state in - (files) + (tree-or-file) integer first_tree last_tree start end (( start = words[(I)(-f|-e)] > 0 ? 1 : 2 )) @@ -1835,7 +843,7 @@ _git-grep () { for (( i = start; i <= end; i++ )); do [[ line[i] == '--' ]] && break - git cat-file -e "${(Q)line[i]}^{tree}" 2>/dev/null || break + __git_is_treeish $line[i] || break if (( first_tree == 0 )); then (( first_tree = last_tree = i )) else @@ -1843,158 +851,313 @@ _git-grep () { fi done + # TODO: Need to respect --cached and --no-index here. if (( last_tree == 0 || last_tree == end )); then if (( first_tree == 0 )); then _alternative \ - 'tree:tree:__git_trees' \ - "file:file:__git_cached_files" && ret=0 + 'treeishs::__git_tree_ishs' \ + 'files::__git_cached_files' && ret=0 else _alternative \ - 'tree:tree:__git_trees' \ - "tree file:tree-files:__git_tree_files . $line[first_tree,last_tree]" && ret=0 + 'treeishs::__git_trees' \ + "files::__git_tree_files ${PREFIX:-.} $line[first_tree,last_tree]" && ret=0 fi else if (( first_tree == 0 )); then - __git_cached_files + __git_cached_files && ret=0 else - __git_tree_files . $line[first_tree,last_tree] + __git_tree_files ${PREFIX:-.} $line[first_tree,last_tree] && ret=0 fi fi ;; esac } -(( $+functions[_git-log] )) || -_git-log () { +(( $+functions[_git-gui] )) || +_git-gui () { local curcontext=$curcontext state line declare -A opt_args - __git_setup_revision_arguments - - _arguments -S \ - $revision_arguments \ - '--source[show which ref each commit is reached from]' \ - '--decorate[print out ref names of any commits that are shown]' \ - '*:file-or-branch:->files' && ret=0 + _arguments -C \ + '--version[display version information]' \ + ': :->command' \ + '*:: :->arg' case $state in - (files) - _arguments -S \ - '::branch:__git_commit_ranges2' \ - '*:index file:__git_cached_files' && ret=0 + (command) + local -a commands + + commands=( + blame:'start a blame viewer' + browser:'start a tree browser' + citool:'arrange to make one commit' + version:'display version information') + + _describe -t commands command commands && ret=0 + ;; + (arg) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (blame) + _git-blame + ;; + (browser) + _arguments -C \ + ':: :__git_revisions' \ + '*:: :->file' && ret=0 + + case $state in + (file) + __git_is_treeish $line[1] && __git_tree_files ${PREFIX:-.} $line[1] && ret=0 + ;; + esac + ;; + (citool) + _git-citool + ;; + (version) + _nothing + ;; + (*) + _nothing + ;; + esac ;; esac } -# TODO: repository needs fixing -(( $+functions[_git-ls-remote] )) || -_git-ls-remote () { - _arguments \ - '(-h --heads)'{-h,--heads}'[show only refs under refs/heads]' \ - '(-t --tags)'{-t,--tags}'[show only refs under refs/tags]' \ - $upload_pack_arg \ - ':repository:__git_any_repositories' \ - '*: :__git_references' && ret=0 +(( $+functions[_git-init] )) || +_git-init () { + _arguments -w -S -s \ + '(-q --quiet)'{-q,--quiet}'[do not print any results to stdout]' \ + '--bare[create a bare repository]' \ + '--template=[directory to use as a template for the object database]: :_directories' \ + '--shared=[share repository amongst several users]:: :__git_repository_permissions' \ + ':: :_directories' && ret=0 +} + +(( $+functions[_git-log] )) || +_git-log () { + local curcontext=$curcontext state line + declare -A opt_args + + local -a log_options revision_options + __git_setup_log_options + __git_setup_revision_options + + _arguments -w -C -s \ + $log_options \ + $revision_options \ + '(-)--[start file arguments]' \ + '*:: :->commit-range-or-file' && ret=0 + + case $state in + (commit-range-or-file) + case $CURRENT in + (1) + if [[ -n ${opt_args[(I)--]} ]]; then + __git_cached_files && ret=0 + else + _alternative \ + 'commit-ranges::__git_commit_ranges' \ + 'cached-files::__git_cached_files' && ret=0 + fi + ;; + (*) + # TODO: Write a wrapper function that checks whether we have a + # committish range or comittish and calls __git_tree_files + # appropriately. + if __git_is_committish_range $line[1]; then + __git_tree_files ${PREFIX:-.} $(__git_committish_range_last $line[1]) && ret=0 + elif __git_is_committish $line[1]; then + __git_tree_files ${PREFIX:-.} $line[1] && ret=0 + else + __git_cached_files && ret=0 + fi + ;; + esac + esac } (( $+functions[_git-merge] )) || _git-merge () { - _arguments \ - "$merge_args[@]" \ - '-m:merge message' \ - '*:remote:__git_commits' && ret=0 + local -a merge_options + __git_setup_merge_options + + _arguments -w -S -s \ + $merge_options \ + '-m[set the commit message to be used for the merge commit]:merge message' \ + '( --no-rerere-autoupdate)--rerere-autoupdate[allow the rerere mechanism to update the index]' \ + '(--rerere-autoupdate )--no-rerere-autoupdate[do not allow the rerere mechanism to update the index]' \ + '*: :__git_commits' && ret=0 } (( $+functions[_git-mv] )) || _git-mv () { - _arguments \ - '-f[force renaming/moving even if targets exist]' \ - '-k[skip move/renames that would lead to errors]' \ - '-n[only show what would happen]' \ - '*:source:__git_cached_files' \ - ':destination:_files' && ret=0 + local curcontext=$curcontext state line + declare -A opt_args + + _arguments -w -C -S -s \ + '(-f --force)'{-f,--force}'[rename/move even if targets exist]' \ + '-k[skip rename/move that would lead to errors]' \ + '(-n --dry-run)'{-n,--dry-run}'[only show what would happen]' \ + ':source:__git_cached_files' \ + '*:: :->source-or-destination' && ret=0 + + case $state in + (source-or-destination) + _alternative \ + 'cached-files:source:__git_cached_files' \ + 'directories:destination directory:_directories' && ret=0 + ;; + esac +} + +(( $+functions[_git-notes] )) || +_git-notes () { + local curcontext=$curcontext state line + declare -A opt_args + + _arguments -C \ + '--ref=[manipulate the notes tree in given ref]: :__git_notes_refs' \ + ': :->command' \ + '*:: :->option-or-argument' && ret=0 + + case $state in + (command) + local -a commands + + commands=( + list:'list notes object for given object' + add:'add notes for a given object' + copy:'copy notes from one object to another' + append:'append notes to a given object' + edit:'edit notes for a given object' + show:'show notes for a given object' + remove:'remove notes for a given object' + prune:'remove all notes for non-existing/unreachable objects') + + _describe -t commands command commands && ret=0 + ;; + (option-or-argument) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (list|show|edit|remove) + _arguments \ + ': :__git_commits' && ret=0 + ;; + (add) + # TODO: Only complete commits that don’t have notes already, unless + # -f or --force has been given. + _arguments -w -S -s \ + '*'{-m,--message=}'[use given note message]:message' \ + '*'{-F,--file=}'[take note message from given file]:note message file:_files' \ + '(-C --reuse-message)'{-C,--reuse-message=}'[take note message from given blob object]: :__git_blobs' \ + '(-c --reedit-message)'{-c,--reedit-message=}'[take note message from given blob object and edit it]: :__git_blobs' \ + '(-f --force)'{-f,--force}'[overwrite existing note]' \ + ': :__git_commits' && ret=0 + ;; + (copy) + # TODO: --for-rewrite is undocumented. + _arguments -w -S -s \ + '(-f --force)'{-f,--force}'[replace existing note]' \ + '(:)--stdin[read objects from stdin]' \ + '(:--stdin)--for-rewrite=[load rewriting config for given command]:command:(amend rebase)' \ + ': :__git_commits' \ + ': :__git_commits' && ret=0 + ;; + (append) + _arguments -w -S -s \ + '*'{-m,--message=}'[use given note message]:message' \ + '*'{-F,--file=}'[take note message from given file]:note message file:_files' \ + '(-C --reuse-message)'{-C,--reuse-message=}'[take note message from given blob object]: :__git_blobs' \ + '(-c --reedit-message)'{-c,--reedit-message=}'[take note message from given blob object and edit it]: :__git_blobs' \ + ': :__git_commits' && ret=0 + ;; + (*) + _nothing + ;; + esac + ;; + esac } (( $+functions[_git-pull] )) || _git-pull () { + local -a merge_options fetch_options + __git_setup_merge_options + __git_setup_fetch_options + _arguments \ - "$merge_args[@]" \ - $common_fetch_args \ - ':repository:__git_any_repositories' \ - '*:refspec:__git_ref_specs' && ret=0 + $merge_options \ + '( --no-rebase)--rebase[perform a rebase after fetching]' \ + '(--rebase )--no-rebase[do not perform a rebase after fetching]' \ + $fetch_options \ + ': :__git_any_repositories' \ + '*: :__git_ref_specs' && ret=0 } -# NOTE: For --receive-pack we use _files to complete, even though this will -# only complete files on the local end, not the remote end. Still, it may be -# helpful to get some sort of completion going, perhaps modifying the path -# later on to match the remote end. (( $+functions[_git-push] )) || _git-push () { - _arguments \ - $force_ref_arg \ + # NOTE: For --receive-pack we use _files to complete, even though this will + # only complete files on the local end, not the remote end. Still, it may be + # helpful to get some sort of completion going, perhaps modifying the path + # later on to match the remote end. + _arguments -w -S -s \ '--all[push all refs under refs/heads/]' \ '--mirror[push all refs under refs/heads/ and refs/tags/ and delete non-existing refs]' \ - '--dry-run[do everything except actually send the updates]' \ - '--tags[all tags under "$GIT_DIR/refs/tags" are pushed]' \ - '(--receive-pack --exec)'{--receive-pack=-,--exec=-}'[path to git-receive-pack on remote]:remote path:_files' \ - '--repo=-[default repository to use]:repository:__git_any_repositories' \ + '(-n --dry-run)'{-n,--dry-run}'[do everything except actually send the updates]' \ + '--porcelain[produce machine-readable output]' \ + '--delete[delete all listed refs from the remote repository]' \ + '--tags[all tags under refs/tags are pushed]' \ + '(--receive-pack --exec)'{--receive-pack=-,--exec=-}'[path to git-receive-pack on remote]:remote git-receive-pack:_files' \ + '(-f --force)'{-f,--force}'[allow refs that are not ancestors to be updated]' \ + '(:)--repo=[default repository to use]:repository:__git_any_repositories' \ + '(-u --set-upstream)'{-u,--set-upstream}'[add upstream reference for each branch that is up to date or pushed]' \ '( --no-thin)--thin[try to minimize number of objects to be sent]' \ '(--thin )--no-thin[do not try to minimize number of objects to be sent]' \ - $verbose_arg \ - '::repository:__git_any_repositories' \ - '*::refspec:__git_ref_specs' && ret=0 + '(-q --quiet -v --verbose --progress)'{-q,--quiet}'[suppress all output]' \ + '(-q --quiet -v --verbose)'{-v,--verbose}'[output additional information]' \ + '(-q --quiet)--progress[output progress information]' \ + ':: :__git_any_repositories' \ + '*: :__git_ref_specs' && ret=0 } (( $+functions[_git-rebase] )) || _git-rebase () { - if [[ $words[2] == --(abort|continue|skip) ]]; then - _message 'no more options' - else - _arguments \ - '--onto[start new branch with HEAD equal to "newbase"]:newbase:__git_revisions' \ - '--continue[continue after failure]' \ - '--abort[abort current rebase]' \ - '--skip[skip the current patch]' \ - '--whitespace=-[detect a new or modified line that ends with trailing whitespaces]: :__git_apply_whitespace_strategies' \ - '(-m --merge)'{-m,--merge}'[use merging strategies to rebase]' \ - '*'{-s,--strategy=-}'[use given merge strategy]:merge strategy:__git_merge_strategies' \ - $verbose_arg \ - '--no-verify[bypass the pre-rebase hook]' \ - '-C-[ensure that given lines of surrounding context match]: :_guard "[[\:digit\:]]##" "lines of context"' \ - '(-i --interactive)'{-i,--interactive}'[make a list of commits to be rebased and open in $EDITOR]' \ - '(-p --preserve-merges)'{-p,--preserve-merges}'[try to recreate merges instead of ignoring them]' \ - ':upstream branch:__git_revisions' \ - '::working branch:__git_revisions' && ret=0 - fi -} - -(( $+functions[_git-repack] )) || -_git-repack () { - _arguments -s -w \ - '(-A)-a[pack all objects into a single pack]' \ - '(-a)-A[pack all objects into a single pack, but unreachable objects become loose]' \ - '-d[remove redundant packs after packing]' \ - '-f[pass "--no-reuse-objects" option to "git pack-objects"]' \ - '-l[pass "--local" option to "git pack-objects"]' \ - '-n[do not update server information]' \ - '-q[pass "-q" option to "git pack-objects"]' \ - '--max-pack-size=-[maximum size of each output packfile]:MiB' \ - '--window-memory=-[scale window size dynamically to not use more than N bytes of memory]:bytes' \ - '--window=-[number of objects to consider when doing delta compression]:N' \ - '--depth=-[maximum delta depth]:N' && ret=0 -} + local -a autosquash_opts -(( $+functions[_git-rerere] )) || -_git-rerere () { - declare -a commands - - commands=( - 'clear:reset the metadata used by rerere' - 'diff:output diffs for the current state of the resolution' - 'status:like diff, but only output filesames' - 'gc:prune old records of conflicted merges') + if (( words[(I)--interactive] )); then + autosquash_opts=( + '( --no-autosquash)--autosquash[check for auto-squash boundaries]' + '(--autosquash )--no-autosquash[do not check for auto-squash boundaries]') + fi - _describe -t commands 'command' commands + _arguments -A '-*' \ + '(- :)--continue[continue after resolving merge conflict]' \ + '(- :)--abort[abort current rebase]' \ + '(- :)--skip[skip the current patch]' \ + '(-m --merge)'{-m,--merge}'[use merging strategies to rebase]' \ + '*'{-s,--strategy=}'[use given merge strategy]:merge strategy:__git_merge_strategies' \ + '*'{-X,--strategy-option=}'[pass merge-strategy-specific option to merge strategy]' \ + '(-q --quiet -v --verbose --stat -n --no-stat)'{-q,--quiet}'[suppress all output]' \ + '(-q --quiet -v --verbose --stat -n --no-stat)'{-v,--verbose}'[output additional information]' \ + '--no-verify[bypass the pre-rebase hook]' \ + '-C-[ensure that given lines of surrounding context match]: :__git_guard_number "lines of context"' \ + '(-f --force-rebase)'{-f,--force-rebase}'[force rebase even if current branch descends from commit rebasing onto]' \ + '(-i --interactive)--ignore-whitespace[ignore whitespace in context]' \ + '(-i --interactive)--whitespace=-[detect a new or modified line that has whitespace errors]: :__git_apply_whitespace_strategies' \ + '(-i --interactive)--committer-date-is-author-date[use author date as committer date]' \ + '(-i --interactive --ignore-whitespace --whitespace --committer-date-is-author-date)'{-i,--interactive}'[make a list of commits to be rebased and open in $EDITOR]' \ + '(-p --preserve-merges --interactive)'{-p,--preserve-merges}'[try to recreate merges instead of ignoring them]' \ + '(1)--root[rebase all reachable commits]' \ + $autosquash_opts \ + '--no-ff[cherry-pick all rebased commits with --interactive, otherwise synonymous to --force-rebase]' \ + '--onto[start new branch with HEAD equal to given revision]:newbase:__git_revisions' \ + ':upstream branch:__git_revisions' \ + '::working branch:__git_branch_names' && ret=0 } (( $+functions[_git-reset] )) || @@ -2002,431 +1165,1689 @@ _git-reset () { local curcontext=$curcontext state line typeset -A opt_args - _arguments -C -S -A '-*' \ - '(-q --quiet)'{-q,--quiet}'[be quiet, only report errors]' \ - '::commit:__git_revisions' \ - - reset-head \ - '( --soft --hard --merge --keep)--mixed[reset the index but not the working tree (default)]' \ - '(--mixed --hard --merge --keep)--soft[do not touch the index file nor the working tree]' \ - '(--mixed --soft --merge --keep)--hard[match the working tree and index to the given tree]' \ - '(--mixed --soft --hard --keep)--merge[reset out of a conflicted merge]' \ - '(--mixed --soft --hard --merge )--keep[like --hard, but keep local working tree changes]' \ - - reset-paths \ + _arguments -w -C -s \ + '( --mixed --hard --merge --keep -p --patch -- *)--soft[do not touch the index file nor the working tree]' \ + '(--soft --hard --merge --keep -p --patch -- *)--mixed[reset the index but not the working tree (default)]' \ + '(--soft --mixed --merge --keep -p --patch -- *)--hard[match the working tree and index to the given tree]' \ + '(--soft --mixed --hard --keep -p --patch -- *)--merge[reset out of a conflicted merge]' \ + '(--soft --mixed --hard --merge -p --patch -- *)--keep[like --hard, but keep local working tree changes]' \ '(-p --patch)'{-p,--patch}'[select diff hunks to remove from the index]' \ - '*::file:->files' && ret=0 + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '(- 1)--[start file arguments]' \ + '(--soft --mixed --hard --merge --keep):: :__git_commits' \ + '(--soft --mixed --hard --merge --keep)*:: :->file' && ret=0 case $state in - (files) - local commit + (file) + local commit=HEAD if [[ -n $line[1] ]] && __git_is_committish $line[1]; then commit=$line[1] - else - commit=HEAD fi - __git_tree_files . $commit && ret=0 + __git_tree_files ${PREFIX:-.} $commit && ret=0 ;; esac } (( $+functions[_git-revert] )) || _git-revert () { - _arguments -s -w \ - '(-e --edit)'{-e,--edit}'[edit the commit before committing the revert]' \ - '--no-edit[do not edit the commit message]' \ - '-x[append commit name when cherry-picking]' \ + _arguments -w -S -s \ + '(-e --edit --no-edit)'{-e,--edit}'[edit the commit before committing the revert]' \ '(-m --mainline)'{-m+,--mainline=}'[pick which parent is mainline]:parent number' \ + '(-e --edit)--no-edit[do not edit the commit message]' \ '(-n --no-commit)'{-n,--no-commit}'[do not commit the reversion]' \ '(-s --signoff)'{-s,--signoff}'[add Signed-off-by line at the end of the commit message]' \ - ':commit:__git_commits' && ret=0 + ': :__git_commits' && ret=0 +} + +(( $+functions[_git-rm] )) || +_git-rm () { + local curcontext=$curcontext state line + declare -A opt_args + + _arguments -w -C -S -s \ + '(-f --force)'{-f,--force}'[override the up-to-date check]' \ + '(-n --dry-run)'{-n,--dry-run}'[do not actually remove the files, just show if they exist in the index]' \ + '-r[allow recursive removal when a leading directory-name is given]' \ + '--cached[only remove files from the index]' \ + '--ignore-unmatch[exit with 0 status even if no files matched]' \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '*:: :->file' && ret=0 + + case $state in + (file) + if [[ -n ${opt_args[(I)--cached]} ]]; then + __git_changed-in-index_files && ret=0 + else + __git_cached_files && ret=0 + fi + ;; + esac } -# TODO: should take all arguments found in setup_revisions() (probably more or -# less what git-rev-list takes). (( $+functions[_git-shortlog] )) || _git-shortlog () { - __git_setup_revision_arguments + local curcontext=$curcontext state line + declare -A opt_args - _arguments -S \ - $revision_arguments \ + local -a revision_options + __git_setup_revision_options + + # TODO: should take all arguments found in setup_revisions() (probably more + # or less what git-rev-list takes). + _arguments -w -C -S -s \ '(: -)'{-h,--help}'[print a short usage message and exit]' \ '(-n --numbered)'{-n,--numbered}'[sort according to number of commits]' \ '(-s --summary)'{-s,--summary}'[suppress commit description]' \ - '*::commitish:__git_committishs' && ret=0 -} + '(-e --email)'{-e,--email}'[show email addres of each author]' \ + '-w-[linewrap the output]:: :->wrap' \ + $revision_options \ + '*: :__git_commits' && ret=0 -# TODO: --date-order is undocumented. -# TODO: Better completion of --reflog. -(( $+functions[_git-show-branch] )) || -_git-show-branch () { - _arguments -S \ - '(--more --independent --merge-base)--list[synonym to "--more=-1"]' \ - - branches \ - '(-a --all)'{-a,--all}'[show both remote-tracking branches and local branches]' \ - '(-r --remotes)'{-r,--remotes}'[show remote-tracking branches]' \ - '( --list --independent --merge-base)--more=-[go given number of commit beyond common ancestor (no ancestry if negative)]:: :_guard "[[\:digit\:]]" limit' \ - '(--more --list --merge-base)--independent[show only the reference that can not be reached from any of the other]' \ - '(--more --list --independent )--merge-base[act like "git-merge-base -a" but with two heads]' \ - '--current[include current branch to the list of revs]' \ - '( --sha1-name)--no-name[do not show naming strings for each commit]' \ - '(--no-name )--sha1-name[name commits with unique prefix of object names]' \ - '--topo-order[show commits in topological order]' \ - '--topics[show only commits that are NOT on the first branch given]' \ - '--sparse[output merges that are reachable from multiple tips being shown]' \ - '--date-order[undocumented]' \ - '*:revision:__git_revisions' \ - - reflogs \ - '(-g --reflog)'{-g,--reflog=-}'[show reflog entries for given ref]::number of entries and base' \ - ':reference:__git_references' && ret=0 -} - -(( $+functions[_git-status] )) || -_git-status () { - _git-commit + case $state in + (wrap) + if [[ -prefix [[:digit:]]#,[[:digit:]]#,[[:digit:]]# ]]; then + compset -P '[[:digit:]]#,[[:digit:]]#,' + __git_guard_number 'indent of second and subsquent wrapped lines' + elif [[ -prefix [[:digit:]]#,[[:digit:]]# ]]; then + compset -P '[[:digit:]]#,' + compset -S ',[[:digit:]]#' + __git_guard_number 'indent of first wrapped line' + else + compset -S ',[[:digit:]]#,[[:digit:]]#' + __git_guard_number 'line width' + fi + ;; + esac } -__git_zstyle_default ':completion::complete:git-status:argument-rest:*' ignore-line yes +(( $+functions[_git-show] )) || +_git-show () { + local curcontext=$curcontext state line + typeset -A opt_args -(( $+functions[__git_stashes] )) || -__git_stashes () { - local expl - declare -a st_list + local -a log_options revision_options + __git_setup_log_options + __git_setup_revision_options - st_list=(${${(f)"$(_call_program stashes git stash list 2>/dev/null)"}/: */}) - __git_command_successful || return + _arguments -w -C -s \ + $log_options \ + $revision_options \ + '*:: :->object' && ret=0 - _wanted tags expl stash-list compadd $* - $st_list + case $state in + (object) + _alternative \ + 'commits::__git_commits' \ + 'tags::__git_tags' \ + 'trees::__git_trees' \ + 'blobs::__git_blobs' && ret=0 + ;; + esac } (( $+functions[_git-stash] )) || _git-stash () { - local expl - local -a stash_cmds - - stash_cmds=( - apply:"restore the changes recorded in the stash" - branch:"branch off at the commit at which the stash was originally created" - clear:"remove all the stashed states" - drop:"remove a single stashed state from the stash list" - list:"list the stashes that you currently have" - pop:"remove and apply a single stashed state from the stash list" - save:"save your local modifications to a new stash" - show:"show the changes recorded in the stash as a diff" - ) + local curcontext=$curcontext state line + declare -A opt_args - if (( CURRENT == 2 )); then - _describe -t command "git-stash commands" stash_cmds && ret=0 - else - case $words[2] in - (apply) - _arguments \ - '--index[try to reinstate the index'\''s changes too]' \ - '*:stash:__git_stashes' && ret=0 - ;; - (branch) - _arguments \ - '2:branch name:' \ - '*:stash:__git_stashes' && ret=0 - ;; - (drop|pop|show) - _arguments \ - '*:stash:__git_stashes' && ret=0 - ;; - (save) - _arguments \ - '--keep-index[all changes already added to the index are left intact]' \ - '*: :->end' && ret=0 + _arguments -C \ + ': :->command' \ + '*:: :->option-or-argument' && ret=0 - [[ $state == 'end' ]] && _message 'message' - ;; - (*) - _nothing - ;; - esac - fi + case $state in + (command) + local -a commands + + commands=( + save:'save your local modifications to a new stash' + list:'list the stashes that you currently have' + show:'show the changes recorded in the stash as a diff' + pop:'remove and apply a single stashed state from the stash list' + apply:'apply the changes recorded in the stash' + branch:'branch off at the commit at which the stash was originally created' + clear:'remove all the stashed states' + drop:'remove a single stashed state from the stash list' + create:'create a stash without storing it in the ref namespace') + + _describe -t commands command commands && ret=0 + ;; + (option-or-argument) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (save) + _arguments -S \ + '(--keep-index)--patch[interactively select hunks from diff between HEAD and working tree to stash]' \ + '( --no-keep-index)--keep-index[all changes already added to the index are left intact]' \ + '(--keep-index )--no-keep-index[all changes already added to the index are undone]' \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '::message' && ret=0 + ;; + (list) + local -a log_options revision_options + __git_setup_log_options + __git_setup_revision_options + + _arguments -s -w \ + $log_options \ + $revision_options && ret=0 + ;; + (show) + local diff_options + __git_setup_diff_options + + _arguments -S -s -w \ + $diff_options \ + ':: :__git_stashes' && ret=0 + ;; + (pop|apply) + _arguments \ + '--index[try to reinstate the changes added to the index as well]' \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + ':: :__git_stashes' && ret=0 + ;; + (branch) + _arguments \ + ': :__git_guard_branch-name' \ + ':: :__git_stashes' && ret=0 + ;; + (clear) + _nothing + ;; + (drop) + _arguments \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + ':: :__git_stashes' && ret=0 + ;; + (create) + _nothing + ;; + (*) + _nothing + ;; + esac + ;; + esac } -(( $+functions[_git-verify-tag] )) || -_git-verify-tag () { - _arguments \ - ':tag:__git_tags' && ret=0 +(( $+functions[_git-status] )) || +_git-status () { + local -a branch_opts + + if (( $words[(I)-s|--short] )); then + branch_opts=('(-b --branch)'{-b,--branch}'[show branch and tracking info]') + fi + + _arguments -w -S -s \ + '(-s --short)'{-s,--short}'[output in short format]' \ + $branch_opts \ + '(-s --short)--porcelain[produce machine-readable output]' \ + '(-u --untracked-files)'{-u-,--untracked-files=-}'[show untracked files]::mode:((no\:"show no untracked files" \ + normal\:"show untracked files and directories" \ + all\:"also show untracked files in untracked directories (default)"))' \ + '--ignore-submodules[ignore changes to submodules]:: :__git_ignore_submodules_whens' \ + '(--porcelain)-z[use NUL termination on output]' \ + '*: :__git_ignore_line_inside_arguments _files' && ret=0 } -# TODO: This should take those arguments that git-diff-tree can take, as well. -(( $+functions[_git-whatchanged] )) || -_git-whatchanged () { - __git_setup_revision_arguments +(( $+functions[_git-submodule] )) || +_git-submodule () { + local curcontext=$curcontext state line + declare -A opt_args - _arguments -S \ - $revision_arguments \ - '1::commit id:__git_commits2' \ - '*:managed file:__git_cached_files' && ret=0 + _arguments -C -A '-*' \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + ': :->command' \ + '*:: :->option-or-argument' && ret=0 + + case $state in + (command) + declare -a commands + + commands=( + add:'add given repository as a submodule' + status:'show the status of a submodule' + init:'initialize a submodule' + update:'update a submodule' + summary:'show commit summary between given commit and working tree/index' + foreach:'evaluate shell command in each checked-out submodule' + sync:'synchronize submodule settings') + + _describe -t commands command commands && ret=0 + ;; + (option-or-argument) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (add) + # TODO: Second argument should only complete relative paths inside + # the current repository. + _arguments -S \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '(-b --branch)'{-b,--branch}'[branch of repository to add as submodule]' \ + '(-f --force)'{-f,--force}'[allow adding an otherwise ignored submodule path]' \ + '--reference=[remote repository to clone]: :__git_any_repositories' \ + ': :__git_any_repositories' \ + ':: :_directories' && ret=0 + ;; + (status) + _arguments -S \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '--cached[use commit stored in the index]' \ + '--recursive[traverse submodules recursively]' \ + '*: :__git_ignore_line_inside_arguments __git_submodules' && ret=0 + ;; + (init) + _arguments -S \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '*: :__git_ignore_line_inside_arguments __git_submodules' && ret=0 + ;; + (update) + # TODO: --init not properly documented. + _arguments -S \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '(-N --no-fetch)'{-N,--no-fetch}'[do not fetch new objects from repository]' \ + '--merge[merge commit recorded in superproject into current branch of submodule]' \ + '--rebase[rebase current branch onto commit recorded in superproject]' \ + '--reference=[remote repository to clone]: :__git_any_repositories' \ + '--recursive[traverse submodules recursively]' \ + '--init[initialize uninitialized submodules]' \ + '*: :__git_ignore_line_inside_arguments __git_submodules' && ret=0 + ;; + (summary) + _arguments -C -A '-*' \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '--cached[use commit stored in the index]' \ + '--files[compare commit in index with submodule HEAD commit]' \ + '(-n --summary-limit)'{-n,--summary-limit}'[limit summary size]: :__git_guard_number "limit"' \ + '(-)--[start submodule arguments]' \ + '*:: :->commit-or-submodule' && ret=0 + + case $state in + (commit-or-submodule) + if (( CURRENT == 1 )) && [[ -z ${opt_args[(I)--]} ]]; then + _alternative \ + 'commits::__git_commits' \ + 'submodules::__git_submodules' && ret=0 + else + __git_ignore_line __git_submodules && ret=0 + fi + ;; + esac + ;; + (foreach) + _arguments -S \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '--recursive[traverse submodules recursively]' \ + '(-):command: _command_names -e' \ + '*::arguments: _normal' && ret=0 + ;; + (sync) + _arguments -S \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '*: :__git_ignore_line_inside_arguments __git_submodules' && ret=0 + ;; + (*) + _nothing + ;; + esac + ;; + esac } -(( $+functions[_git-applypatch] )) || -_git-applypatch () { - _arguments \ - ':message file:_files' \ - ':patch file:_files' \ - ':info file:_files' \ - '::signoff file:__git_signoff_file' && ret=0 +(( $+functions[_git-tag] )) || +_git-tag () { + local -a message_opts + + if (( words[(I)-[asu]] )); then + message_opts=( + '( -F)-m+[specify tag message]:message' + '(-m )-F+[read tag message from given file]:message file:_files') + fi + + _arguments -A '-*' \ + - creation \ + '( -s -u)-a[create an unsigned, annotated tag]' \ + '(-a -u)-s[create an signed and annotated tag]' \ + '(-a -s )-u[create a tag, annotated and signed with the given key]: :__git_gpg_secret_keys' \ + '-f[replace existing tag]' \ + $message_opts \ + ': :__git_tags' \ + ':: :__git_commits' \ + - deletion \ + '-d[delete tags]' \ + '*:: :__git_ignore_line_inside_arguments __git_tags' \ + - listing \ + '-n+[limit line output of annotation]: :__git_guard_number "limit"' \ + '-l[list tags matching pattern]' \ + '--contains=[only list tags which contain the specified commit]: :__git_commits' \ + '::pattern' \ + - verification \ + '-v[verifies gpg signutare of tags]' \ + '*:: :__git_ignore_line_inside_arguments __git_tags' && ret=0 } -# TODO: Need to combine the list of attributes defined in __git_attributes. -(( $+functions[_git-check-attr] )) || -_git-check-attr () { - local -a attributes +# Ancillary Commands (Manipulators) - attributes=(crlf ident filter diff merge) +(( $+functions[_git-config] )) || +_git-config () { + local name_arg value_arg + local curcontext=$curcontext state line + declare -A opt_args - local only_attributes=1 - for (( i = 2; i < $#words; i++ )); do - if (( attributes[(I)$words[i]] == 0 )); then - only_attributes=0 - break - fi - done + if (( words[(I)--get-regexp] )); then + name_arg=':name regex' + elif (( words[(I)--get-colorbool] )); then + name_arg=':: :->is-a-tty' + elif (( words[(I)--get-color] )); then + name_arg='::default' + elif (( words[(I)--remove-section|--rename-section] )); then + name_arg=': :->section' + elif (( words[(I)--get|--get-all] )); then + name_arg=': :->gettable-option' + else + name_arg=': :->option' + fi - if (( !only_attributes || words[(I)--] )); then - __git_files && ret=0 + if (( words[(I)--rename-section] )); then + value_arg=': :->section' else - _alternative \ - 'files:file:__git_files' \ - 'attributes:attribute:__git_attributes' && ret=0 + value_arg=': :->value' fi -} -# TODO: archive/branch can use _arch_archives perhaps? -(( $+functions[_git-archimport] )) || -_git-archimport () { - _arguments \ - '-a[auto-register archives at http://mirrors.sourcecontrol.net]' \ - '-D[attempt to import trees that have been merged from]: :_guard "[[\:digit\:]]#" depth' \ - '-f[use the fast patchset import strategy]' \ - $help_arg \ - '-o[use old-style branch names]' \ - '-T[create a tag for every commit]' \ - '-t[use given directory as temporary directory]:directory:_directories' \ - $verbose_arg \ - ':archive/branch' \ - '::archive/branch' -} + # TODO --local is undocumented. + _arguments -w -C -S -s \ + '( --system --local -f --file)--global[use user-global config file]' \ + '(--global --local -f --file)--system[use system-wide config file]' \ + '(--global --system -f --file)--local[use local config file]' \ + '(--global --system -f --file)'{-f+,--file=}'[use given config file]:config file:_files' \ + '( --int --bool-or-int --path)--bool[setting is a boolean]' \ + '(--bool --bool-or-int --path)--int[setting is an integer]' \ + '(--bool --int --path)--bool-or-int[setting is an integer]' \ + '(--bool --int --bool-or-int )--path[setting is a path]' \ + '(-z --null)'{-z,--null}'[end values with NUL and newline between key and value]' \ + $name_arg \ + $value_arg \ + '::value regex' \ + - '(actions)' \ + '(-z --null)--replace-all[replace all values of the given key]' \ + '(3 -z --null)--add[add new value without altering any existing ones]' \ + '(2)--get[get the first matching value of the key]' \ + '(2)--get-all[get all matching values of the key]' \ + '(3 --bool --int --bool-or-int --path -z --null)--remove-section[remove the given section]' \ + '(3 --bool --int --bool-or-int --path -z --null)--rename-section[rename the given section]' \ + '(2 --bool --int --bool-or-int --path -z --null)--unset[remove the first matching value of the key]' \ + '(2 --bool --int --bool-or-int --path -z --null)--unset-all[remove all matching values of the key]' \ + '(: --bool --int --bool-or-int --path)'{-l,--list}'[list all variables set in config file]' \ + '(2)--get-regexp[like "--get-all", but interpret "name" as a regular expression]' \ + '(2 3 --bool --int --bool-or-int --path -z --null)--get-colorbool[check if color should be used]: :->gettable-colorbool-option' \ + '(2 3 --bool --int --bool-or-int --path -z --null)--get-color[find color setting]: :->gettable-color-option' \ + '(-e --edit --bool --int --bool-or-int --path -z --null)'{-e,--edit}'[open config file for editing]' && ret=0 + + # TODO: Most all _path_commands should be able to take arguments and so on. + # How do we deal with that and how do we quote the whole argument to git + # config? + # TODO: Add merge.*.(name|driver|recursive) and diff.*.(command|funcname) + # (see gitattributes(5)). + # TODO: .path options should take absolute paths. + declare -a git_options_static + git_options_static=( + advice.pushNonFastForward:'show advice when git push refuses non-fast-forward refs::->bool:true' + advice.statusHints:'show advice in output of git status::->bool:true' + advice.commitBeforeMerge:'show advice when git merge refuses to merge::->bool:true' + advice.resolveConflict:'show advice when conflict prevents operation from being performed::->bool:true' + advice.implicitIdentity:'show advice when identity is guessed from system settings::->bool:true' + advice.detachedHead:'show advice when entering detached-HEAD state::->bool:true' + blame.blankboundary:'show blank SHA-1 for boundary commits::->bool:false' + blame.showroot:'show root commits as normal commits::->bool:false' + blame.date:'date format to use in output::__git_date_formats:iso' + core.fileMode:'track changes to the executable bit of files::->bool:true' + core.ignoreCygwinFSTricks:'use Cygwin stat()/lstat()::->bool:true' + core.ignorecase:'use workarounds for non-case-sensitive filesystems::->bool:false' + core.trustctime:'trust inode change time::->bool:true' + core.quotepath:'escape characters in paths on output::->bool:false' + core.eol:'line ending type::->core.eol:native' + core.safecrlf:'verify that CRLF conversion is reversible::->core.safecrlf:false' + core.autocrlf:'convert CRLFs to and from system specific::->core.autocrlf:false' + core.symlinks:'create symbolic links for indexed symbolic links upon creation::->bool:true' + core.gitProxy:'command to execute to establish a connection to remote server:proxy command:_path_commands' + core.ignoreStat:'ignore modification times of files::->bool:false' + core.preferSymlinkRefs:'use symbolic links for symbolic-reference files::->bool:false' + core.bare:'use a repository without a working tree::->bool:false' + core.worktree:'path to the root of the work tree:work tree:_directories' + core.logAllRefUpdates:'log updates of references::->bool:true' + core.repositoryFormatVersion:'internal variable determining the repository version:version:->string' + core.sharedRepository:'what kind of sharing is done for this repository::->permission:false' + core.warnAmbiguousRefs:'warn if a ref name is ambiguous::->bool:true' + core.compression:'level of compression to apply to packs::->compression:-1' + core.loosecompression:'level of compression to apply to non-pack files::->compression:1' + core.packedGitWindowSize:'size of mappings of pack files:pack window size:->bytes' + core.packedGitLimit:'maximum number of bytes to map from pack files:maximum pack file map size:->bytes' + core.deltaBaseCacheLimit:'maximum size of cache for base objects:maximum base objects cache size:->bytes:16m' + core.bigFileThreshold:'maximum size of files to compress:maximum compress size:->bytes:512m' + core.excludesfile:'additional file to use for exclusion:excludes file:_files' + core.askpass:'program to use for asking for passwords:password command:_path_commands' + core.editor:'editor to use for editing messages:editor:_path_commands' + core.pager:'pager to use for paginating output:pager:_path_commands' + core.whitespace:'list of common whitespace problems to notice::->core.whitespace' + core.fsyncobjectfiles:'fsync() when writing object files::->bool:false' + core.preloadindex:'use parallel index preload for operations like git diff::->bool:false' + core.createObject:'take steps to prevent overwriting existing objects::->core.createObject:link' + core.notesRef:'show notes in given refs:refs:->string:refs/notes/commits' + core.sparseCheckout:'use sparse checkout::->bool:false' + add.ignore-errors:'ignore indexing errors when adding files::->bool:false' + am.keepcr:'keep CR characters when splitting mails::->bool:false' + apply.ignorewhitespace:'ignore whitespace changes::->apply.ignorewhitespace:no' + apply.whitespace:'default value for the --whitespace option::->apply.whitespace:error' + branch.autosetupmerge:'set up new branches for git pull::->bool:true' + branch.autosetuprebase:'rebase new branches of merge for autosetupmerge::->branch.autosetuprebase:never' + 'branch.*.remote:what remote git fetch and git push should fetch form/push to::__git_remotes' + 'branch.*.merge:default refspec to be marked for merging::__git_ref_specs' + 'branch.*.mergeoptions:default options for merging::->branch.mergeoptions' + 'branch.*.rebase:rebase on top of fetched branch::->bool:false' + 'browser.*.cmd:browser command to use:browser:_path_commands' + 'browser.*.path:path to use for the browser:absolute browser path:_files -g "*(*)"' + clean.requireForce:'require --force for git clean to actually do something::->bool:true' + color.branch:'color output of git branch::->color-bool' + color.branch.current:'color of the current branch::->color' + color.branch.local:'color of a local branch::->color' + color.branch.remote:'color of a remote branch::->color' + color.branch.plain:'color of other branches::->color' + color.diff:'color output of git diff::->color-bool' + color.diff.plain:'color of context text::->color' + color.diff.meta:'color of meta-information::->color' + color.diff.frag:'color of hunk headers::->color' + color.diff.func:'color of function in hunk header::->color' + color.diff.old:'color of removed lines::->color' + color.diff.new:'color of added lines::->color' + color.diff.commit:'color of commit headers::->color' + color.diff.whitespace:'color of whitespace errors::->color' + color.decorate.branch:'color of branches::->color' + color.decorate.remoteBranch:'color of remote branches::->color' + color.decorate.tag:'color of tags::->color' + color.decorate.stash:'color of stashes::->color' + color.decorate.HEAD:'color of HEAD::->color' + color.grep:'whether or not to color output of git grep::->color-bool' + color.grep.context:'color of non-matching text in context lines::->color' + color.grep.filename:'color of filename prefix::->color' + color.grep.function:'color of function name lines::->color' + color.grep.linenumber:'color of line number prefix::->color' + color.grep.match:'color of matching text::->color' + color.grep.selected:'color of non-matching text in selected lines::->color' + color.grep.separator:'color of separators between fields in a line::->color' + color.interactive:'whether or not to color in interactive mode::->color-bool' + color.interactive.prompt:'color of prompt::->color' + color.interactive.header:'color of header::->color' + color.interactive.help:'color of help::->color' + color.interactive.error:'color of error::->color' + color.pager:'feed colored output to pager::->bool:true' + color.showbranch:'color output of git show-branch::->color-bool' + color.status:'color output of git status::->color-bool' + color.status.header:'color of header text::->color' + color.status.added:'color of added, but not yet committed, files::->color' + color.status.updated:'color of updated, but not yet committed, files::->color' + color.status.changed:'color of changed, but not yet added in the index, files::->color' + color.status.untracked:'color of files not currently being tracked::->color' + color.status.nobranch:'color of no-branch warning::->color' + color.ui:'color output of capable git commands::->color-bool' + commit.status:'include status information in commit message template::->bool:true' + commit.template:'template file for commit messages:template:_files' + diff.autorefreshindex:'run git update-index --refresh before git diff::->bool:true' + diff.external:'command to generate diff with:diff command:_path_commands' + diff.mnemonicprefix:'use mnemonic source and destination prefixes::->bool:false' + diff.noprefix:'strip source and destination prefixes::->bool:false' + diff.renameLimit:'number of files to consider when detecting copy/renames:rename limit:->int' + diff.renames:'try to detect renames::->diff.renames:true' + diff.ignoreSubmodules:'ignore submodules::->bool:false' + diff.suppressBlankEmpty:'inbihit printing space before empty output lines::->bool:false' + diff.tool:'diff tool to use::__git_difftools' + 'difftool.*.cmd:command to invoke for the diff tool::_path_commands' + 'difftool.*.path:path to use for the diff tool:absolute diff tool path:_files -g "*(*)"' + difftool.prompt:'prompt before each invocation of the diff tool::->bool:true' + diff.wordRegex:'regex used to determine what a word is when performing word-by-word diff:regex:->string' + diff.guitool:'diff tool with gui to use::__git_difftools' + fetch.unpackLimit:'maximum number of objects to unpack when fetching:unpack limit:->int' + format.attach:'use multipart/mixed attachments::->bool:false' + format.numbered:'use sequence numbers in patch subjects::->format.numbered:auto' + format.headers:'additional email headers to include in email patches:headers:->string' + format.to:'additional email recipients of patches::->string' + format.cc:'additional carbon-copy email recipients of patches:recipients:->string' + format.subjectprefix:'prefix to use for subjects:prefix:->string' + format.signature:'signature to use:signature:->string' + format.suffix:'default suffix for output files from git-format-patch:suffix:->string' + format.pretty:'pretty format for log/show/whatchanged:format:->string' + format.thread:'threading style to use::->format.thread:false' + format.signoff:'enable --signoff by default::->bool:false' + 'gc.*.reflogexpire:grace period for git reflog expire::->days:90' + 'gc.*.reflogexpireunreachable:grace period for git reflog expire for unreachable entries::->days:30' + gc.aggressiveWindow:'window size used in delta compression algorithm:->int:250' + gc.auto:'minimum limit for packing loose objects with --auto::->int:6700' + gc.autopacklimit:'minimum limit for packing packs with --auto::->int:50' + gc.packrefs:'allow git gc to run git pack-refs::->gc.packrefs:true' + gc.pruneexpire:'grace period for pruning::->days+now' + gc.reflogexpire:'grace period for git reflog expire::->days:90' + gc.reflogexpireunreachable:'grace period for git reflog expire for unreachable entries::->days:30' + gc.rerereresolved:'number of days to keep records of resolved merges::->days:60' + gc.rerereunresolved:'number of days to keep records of unresolved merges::->days:15' + gitcvs.commitmsgannotation:'string to append to each commit message::->string' + gitcvs.enabled:'enable the cvs server interface::->bool:false' + gitcvs.logfile:'name of log file for cvs pserver:log file:_files' + gitcvs.dbname:'name of database to use:database name:->string' + gitcvs.dbdriver:'name of DBI driver to use::->gitcvs.dbdriver:SQLite' + gitcvs.dbuser:'username to connect to database as:database user:_users' + gitcvs.dbpass:'password to use when connecting to database:password:->string' + gitcvs.dbTableNamePrefix:'database table name prefix:prefix:->string' + 'gitcvs.*.commitmsgannotation:string to append to each commit message:annotation:->string' + 'gitcvs.*.enabled:enable the cvs server interface::->bool:false' + 'gitcvs.*.logfile:name of log file for cvs pserver:log file:_files' + 'gitcvs.*.dbname:name of database to use:database name:->string' + 'gitcvs.*.dbdriver:name of DBI driver to use:DBI driver:->string' + 'gitcvs.*.dbuser:username to connect to database as::_users' + 'gitcvs.*.dbpass:password to use when connecting to database:password:->string' + 'gitcvs.*.dbTableNamePrefix:database table name prefix:prefix:->string' + gitcvs.usecrlfattr:'use end-of-line conversion attributes::->bool:false' + gitcvs.allbinary:'treat all files from CVS as binary::->bool:false' + gui.commitmsgwidth:'width of commit message window:width:->int:75' + gui.diffcontext:'number of context lines used in diff window:context:->int:5' + gui.encoding:'encoding to use for displaying file contents::->encoding' + gui.matchtrackingbranch:'create branches that track remote branches::->bool:false' + gui.newbranchtemplate:'suggested name for new branches:template:->string' + gui.pruneduringfetch:'prune tracking branches when performing a fetch::->bool:false' + gui.trustmtime:'trust file modification timestamp::->bool:false' + gui.spellingdictionary:'dictionary to use for spell checking commit messages:dictionary:_files' + gui.fastcopyblame:'try harder during blame detection::->bool:false' + gui.copyblamethreshold:'threshold to use in blame location detection:threshold:->string' + gui.blamehistoryctx:'specify radius of history context in days for selected commit::->days' + guitool.cmd:'shell command line to execute::_path_commands' + guitool.needsfile:'require that a diff is selected for command to be available::->bool:false' + guitool.noconsole:'suppress command output::->bool:false' + guitool.norescan:'skip rescanning for changes to the working directory::->bool:false' + guitool.confirm:'show a confirmation dialog::->bool:false' + guitool.argprompt:'prompt for arguments:argument prompt:->string' + guitool.revprompt:'prompt for a single revision:revision prompt:->string' + guitool.revunmerged:'show only unmerged branches in revprompt::->bool:false' + guitool.title:'title of prompt dialog:prompt title:->string' + guitool.prompt:'prompt to display:prompt:->string' + help.browser:'browser used to display help in web format::__git_browsers' + help.format:'default help format used by git help::->help.format' + help.autocorrect:'execute corrected mistyped commands::->bool:false' + http.proxy:'HTTP proxy to use:proxy:_urls' + http.sslVerify:'verify the SSL certificate for HTTPS::->bool:true' + http.sslCert:'file containing SSL certificates for HTTPS:SSL certificate file:_files' + http.sslKey:'file containing the SSL private key for HTTPS:SSL private key file:_files' + http.sslCertPasswordProtected:'prompt for a password for the SSL certificate::->bool:false' + http.sslCAInfo:'file containing CA certificates to verify against for HTTPS:CA certificates file:_files' + http.sslCAPath:'directory containing files with CA certificates to verify against for HTTPS:CA certificates directory:_directories' + http.maxRequests:'how many HTTP requests to launch in parallel:maximum number of requests:->int:5' + http.minSessions:'number of curl sessions to keep across requests:mininmum number of sessions:->int:1' + http.postBuffer:'maximum size of buffer used by smart HTTP transport when POSTing:maximum POST buffer size:->bytes:1m' + http.lowSpeedLimit:'lower limit for HTTP transfer-speed:low transfer-speed limit:->int' + http.lowSpeedTime:'duration for http.lowSpeedLimit:time:->int' + http.noEPSV:'disable the use of the EPSV ftp-command::->bool:false' + http.useragent:'user agent presented to HTTP server:user agent string:->string' + http.getanyfile:'allow clients to read any file within repository::->bool:true' + http.uploadpack:'serve git fetch-pack and git ls-remote clients::->bool:true' + http.receivepack:'serve git send-pack clients::->bool:true' + i18n.commitEncoding:'character encoding commit messages are stored in::->encoding' + i18n.logOutputEncoding:'character encoding commit messages are output in::->encoding' + imap.folder:'IMAP folder to use with git imap-send:IMAP folder name::_mailboxes' + imap.tunnel:'tunneling command to use for git imap-send:tunnel command:_path_commands' + imap.host:'host git imap-send should connect to::_hosts' + # TODO: If imap.host is set, complete users on that system. + imap.user:'user git imap-send should log in as::_users' + imap.pass:'password git imap-send should use when logging in:password:->string' + imap.port:'port git imap-send should connect on::_ports' + imap.sslverify:'verify server certificate::->bool:true' + imap.preformattedHTML:'use HTML encoding when sending a patch::->bool:false' + imap.authMethod:'authentication method used::->imap.authMethod' + init.templatedir:'directory from which templates are copied:template directory:_directories' + instaweb.browser:'browser to use when browsing with gitweb::__git_browsers' + instaweb.httpd:'HTTP-daemon command-line to execute for instaweb:daemon:_path_commands' + instaweb.local:'bind to 127.0.0.1::->bool:false' + instaweb.modulepath:'module path for the Apache HTTP-daemon for instaweb:module directory:_directories' + instaweb.port:'port to bind HTTP daemon to for instaweb::_ports' + interactive.singlekey:'accept one-letter input without Enter::->bool:false' + log.date:'default date-time mode::__git_date_formats' + log.decorate:'type of ref names to show::__git_log_decorate_formats' + log.showroot:'show initial commit as a diff against an empty tree::->bool:true' + mailinfo.scissors:'remove everything in body before a scissors line::->bool:false' + mailmap.file:'augmenting mailmap file:mailmap file:_files' + man.viewer:'man viewer to use for help in man format::__git_man_viewers' + 'man.*.cmd:the command to invoke the specified man viewer:man command:_path_commands' + 'man.*.path:path to use for the man viewer:absolute man tool path:_files -g "*(*)"' + merge.conflictstyle:'style used for conflicted hunks::->merge.conflictstyle:merge' + merge.log:'include summaries of merged commits in new merge commit messsages::->bool:false' + merge.renameLimit:'number of files to consider when detecting copy/renames during merge:limit:->int' + merge.renormalize:'use canonical representation of files during merge::->bool:false' + merge.stat:'print the diffstat between ORIG_HEAD and merge at end of merge::->bool:true' + merge.tool:'tool used by git mergetool during merges::__git_mergetools' + merge.verbosity:'amount of output shown by recursive merge strategy::->merge.verbosity:2' + 'merge.*.name:human-readable name for custom low-level merge driver:name:->string' + 'merge.*.driver:command that implements a custom low-level merge driver:merge command:_path_commands' + 'merge.*.recursive:low-level merge driver to use when performing internal merge between common ancestors::__git_builtin_merge_drivers' + 'mergetool.*.path:path to use for the merge tool:absolute merge tool path:_files -g "*(*)"' + 'mergetool.*.cmd:command to invoke for the merge tool:merge command:_path_commands' + 'mergetool.*.trustExitCode:trust the exit code of the merge tool::->bool:false' + mergetool.keepBackup:'keep the original file with conflict markers::->bool:true' + mergetool.keepTemporaries:'keep temporary files::->bool:false' + mergetool.prompt:'prompt before each invocation of the merge tool::->bool:true' + notes.displayRef:'refname to show notes from::->refname' + notes.rewrite.amend:'copy notes from original to rewritten commit when running git amend::->bool:true' + notes.rewrite.rebase:'copy notes from original to rewritten commit when running git rebase::->bool:true' + notes.rewriteMode:'what to do when target commit already has a not when rewriting::->notes.rewriteMode' + notes.rewriteRef:'refname to use when rewriting::->refname' + pack.window:'size of window:window size:->int:10' + pack.depth:'maximum delta depth:maximum delta depth:->int:50' + pack.windowMemory:'window size limit:maximum window size:->bytes:0' + pack.compression:'compression level::->compression:-1' + pack.deltaCacheSize:'maximum amount of memory for caching deltas:maximum delta cache size:->bytes:256m' + pack.deltaCacheLimit:'maximum size of deltas:maximum delta size:->int:1000' + pack.threads:'number of threads to use for searching for best delta matches:number of threads:->int' + pack.indexVersion:'default pack index version:index version:->string' + pack.packSizeLimit:'maximum size of packs:maximum size of packs:->bytes' + pull.octopus:'default merge strategy to use when pulling multiple branches::__git_merge_strategies' + pull.twohead:'default merge strategy to use when pulling a single branch::__git_merge_strategies' + push.default:'action git push should take if no refspec is given::->push.default' + rebase.stat:'show a diffstat of what changed upstream since last rebase::->bool:false' + rebase.autosquash:'autosquash by default::->bool:false' + receive.autogc:'run git gc --auto after receiving data::->bool:true' + receive.fsckObjects:'check all received objects::->bool:true' + receive.unpackLimit:'maximum number of objects received for unpacking into loose objects:unpack limit:->int' + receive.denyDeletes:'deny a ref update that deletes a ref::->bool:false' + receive.denyDeleteCurrent:'deny a ref update that deletes currently checked out branch::->bool:false' + receive.denyCurrentBranch:'deny a ref update of currently checked out branch::->receive.denyCurrentBranch' + receive.denyNonFastForwards:'deny a ref update that is not a fast-forward::->bool:false' + receive.updateserverinfo:'run git update-server-info after receiving data::->bool:false' + 'remote.*.url:URL of a remote repository::__git_any_repositories' + 'remote.*.pushurl:push URL of a remote repository::__git_any_repositories' + 'remote.*.proxy:URL of proxy to use for a remote repository::_urls' + 'remote.*.fetch:default set of refspecs for git fetch::__git_ref_specs' + 'remote.*.push:default set of refspecs for git push::__git_ref_specs' + 'remote.*.mirror:push with --mirror::->bool:false' + 'remote.*.skipDefaultUpdate:skip this remote by default::->bool:false' + 'remote.*.skipFetchAll:skip this remote by default::->bool:false' + 'remote.*.receivepack:default program to execute on remote when pushing:git receive-pack command:_path_commands' + 'remote.*.uploadpack:default program to execute on remote when fetching:git upload-pack command:_path_commands' + 'remote.*.tagopt:options for retrieving remote tags::->remote.tagopt' + 'remote.*.vcs:interact with the remote through git-remote helper:remote VCS:->string' + repack.usedeltabaseoffset:'use delta-base offsets::->bool:true' + rerere.autoupdate:'update index after resolution::->bool:false' + rerere.enabled:'record resolved conflicts::->bool' + sendemail.smtpencryption:'encryption method to use::->sendemail.smtpencryption' + sendemail.aliasesfile:'file containing email aliases:email aliases file:_files' + sendemail.aliasfiletype:'format of aliasesfile::->sendemail.aliasfiletype' + sendemail.bcc:'value of Bcc\: header::_email_addresses' + sendemail.cc:'value of Cc\: header::_email_addresses' + sendemail.cccmd:'command to generate Cc\: header with:Cc\: command:_path_commands' + sendemail.chainreplyto:'send each email as a reply to the previous one::->bool:false' + sendemail.confirm:'type of confirmation required before sending::->sendemail.confirm:auto' + sendemail.envelopesender:'envelope sender to send emails as::_email_addresses' + sendemail.from:'sender email address::_email_addresses' + sendemail.multiedit:'edit all files at once::->bool:false' + sendemail.signedoffbycc:'add Signed-off-by\: or Cc\: lines to Cc\: header::->bool:true' + sendemail.smtppass:'password to use for SMTP-AUTH:password:->string' + sendemail.suppresscc:'rules for suppressing Cc\:::->sendemail.suppresscc' + sendemail.suppressfrom:'add From\: address to the Cc\: list::->bool:false' + sendemail.to:'value of To\: header::_email_addresses' + sendemail.smtpdomain:'FQDN to use for HELO/EHLO commands to SMTP server:smtp domain:_domains' + sendemail.smtpserver:'SMTP server to connect to:smtp host:_hosts' + sendemail.smtpserverport:'port to connect to SMTP server on:smtp port:_ports' + sendemail.smtpuser:'user to use for SMTP-AUTH:smtp user:_users' + sendemail.thread:'set In-Reply-To\: and References\: headers::->bool:true' + sendemail.validate:'perform sanity checks on patches::->bool:true' + 'sendemail.*.aliasesfile:file containing email aliases::_files' + 'sendemail.*.aliasfiletype:format of aliasesfile::->sendemail.aliasfiletype' + 'sendemail.*.bcc:value of Bcc\: header::_email_addresses' + 'sendemail.*.cc:value of Cc\: header::_email_addresses' + 'sendemail.*.cccmd:command to generate Cc\: header with:Cc\: command:_path_commands' + 'sendemail.*.chainreplyto:send each email as a reply to the previous one::->bool:false' + 'sendemail.*.confirm:type of confirmation required before sending::->sendemail.confirm:auto' + 'sendemail.*.envelopesender:envelope sender to send emails as::_email_addresses' + 'sendemail.*.from:sender email address::_email_addresses' + 'sendemail.*.multiedit:edit all files at once::->bool:false' + 'sendemail.*.signedoffbycc:add Signed-off-by\: or Cc\: lines to Cc\: header::->bool:true' + 'sendemail.*.smtppass:password to use for SMTP-AUTH:password:->string' + 'sendemail.*.suppresscc:rules for suppressing Cc\:::->sendemail.suppresscc' + 'sendemail.*.suppressfrom:rules for suppressing From\:::->sendemail.suppressfrom' + 'sendemail.*.to:value of To\: header::_email_addresses' + 'sendemail.*.smtpdomain:FQDN to use for HELO/EHLO commands to SMTP server:smtp domain:_domains' + 'sendemail.*.smtpserver:SMTP server to connect to:smtp host:_hosts' + 'sendemail.*.smtpserverport:port to connect to SMTP server on:smtp port:_ports' + 'sendemail.*.smtpuser:user to use for SMTP-AUTH:smtp user:_users' + 'sendemail.*.thread:set In-Reply-To\: and References\: headers::->bool:true' + 'sendemail.*.validate:perform sanity checks on patches::->bool:true' + sendemail.assume8bitEncoding:'encoding to use for non-ASCII messages::__git_encodings' + showbranch.default:'default set of branches for git show-branch::->branch' + status.relativePaths:'show paths relative to current directory::->bool:false' + status.showUntrackedFiles:'show untracked files::->status.showUntrackedFiles:normal' + status.submodulesummary:'include submodule summary::->bool:false' + 'submodule.*.path:path within project:submodule directory:_directories -qS \:' + 'submodule.*.url:URL to update from::__git_any_repositories' + 'submodule.*.update:update strategy to use::->submodule.update' + 'submodule.*.ignore:ignore modifications to submodules with git status and git diff-*::->submodule.ignore' + svn.noMetadata:'disable git-svn-id: lines at end of commits::->bool:false' + svn.useSvmProps:'use remappings of URLs and UUIDs from mirrors::->bool:false' + svn.useSvnsyncProps:'use remappings of URLs and UUIDs for the svnsync command::->bool:false' + svn.ignore-paths:'regular expression of paths to not check out:regular expression:->string' + svn.brokenSymlinkWorkaround:'apply the broken-symlink check::->bool:true' + svn.pathnameencoding:'encoding to recode pathnames into::->encoding' + svn.followparent:'follow parent commit::->bool:true' + svn.authorsFile:'default authors file:authors file:_files' + svn.quiet:'produce less output::->bool:false' + 'svn-remote.*.noMetadata:disable git-svn-id: lines at end of commits::->bool:false' + 'svn-remote.*.useSvmProps:use remappings of URLs and UUIDs from mirrors::->bool:false' + 'svn-remote.*.useSvnsyncProps:use remappings of URLs and UUIDs for the svnsync command::->bool:false' + 'svn-remote.*.rewriteRoot:alternate root URL to use:root url:_urls' + 'svn-remote.*.rewriteUUID:remap URLs and UUIDs for mirrors manually::->bool:false' + 'svn-remote.*.ignore-paths:regular expression of paths to not check out:regular expression:->string' + 'svn-remote.*.url:URL to connect to::_urls' + 'svn-remote.*.fetch:fetch specification::__git_ref_specs' + 'svn-remote.*.branches:branch mappings:branch mapping:->string' + 'svn-remote.*.tags:tag mappings:tag mapping:->string' + tar.umask:'umask to apply::->umask' + transfer.unpackLimit:'default value for fetch.unpackLimit and receive.unpackLimit:unpack limit:->int:100' + 'url.*.insteadOf:string to start URLs with:prefix:->string' + 'url.*.pushInsteadOf:string to start URLs to push to with:prefix:->string' + user.email:'email address used for commits::_email_addresses' + user.name:'full name used for commits:name:->string' + user.signingkey:'default GPG key to use when creating signed tags::__git_gpg_secret_keys' + web.browser:'web browser to use::__git_browsers') -(( $+functions[_git-convert-objects] )) || -_git-convert-objects () { - _nothing + case $state in + (section) + __git_config_sections -b '(|)' '^' section-names 'section name' $* + ;; + (is-a-tty) + declare -a values + values=( + true + false + auto) + _describe -t values 'stdout is a tty' values + ;; + (option) + local label=option + declare -a sections sections_and_options options + + [[ -prefix *. ]] && label="${line[1]%.*} option" + + if compset -P '[^.]##.*.'; then + declare -a match mbegin mend + options+=(${${${${(M)git_options_static:#(#i)${IPREFIX}[^.:]##:*}#(#i)${IPREFIX}}/#(#b)([^:]##:)([^\\:]#(\\?[^\\:]#)#:[^\\:]#(\\?[^\\:]#)#:->bool)/$match[1]whether or not to $match[2]}/#(#b)([^:]##:([^\\:]#(\\?[^\\:]#)#))*/$match[1]}) + options+=(${${${${(M)git_options_static:#(#i)${IPREFIX%%.*}.\*.[^.:]##:*}#(#i)${IPREFIX%%.*}.\*.}/#(#b)([^:]##:)([^\\:]#(\\?[^\\:]#)#:[^\\:]#(\\?[^\\:]#)#:->bool)/$match[1]whether or not to $match[2]}/#(#b)([^:]##:([^\\:]#(\\?[^\\:]#)#))*/$match[1]}) + + declare -a labels + labels=( + 'branch.*.:${${line[1]#branch.}%.*} branch option' + 'browser.*.:${${line[1]#browser.}%.*} browser option' + 'color.branch.:branch-specific color option' + 'color.diff.:diff-specific color option' + 'color.decorate.:git-log---decorate-specific color option' + 'color.grep.:git-grep-specific color option' + 'color.interactive.:interaction-specific color option' + 'color.status.:git-status-specific color option' + 'difftool.*.:${${line[1]#difftool.}%.*}-specific option' + 'gc.*.:${${line[1]#gc.}%.*}-specific gc option' + 'gitcvs.*.:gitcvs ${${line[1]#gitcvs.}%.*}-specific option' + 'guitool.*.:${${line[1]#gc.}%.*}-specific option' + 'man.*.:${${line[1]#man.}%.*}-specific man option' + 'merge.*.:${${line[1]#merge.}%.*}-specific merge option' + 'mergetool.*.:${${line[1]#mergetool.}%.*}-specific option' + 'sendemail.*.:${${line[1]#sendemail.}%.*}-specific sendemail option' + 'submodule.*.:${${line[1]#submodule.}%.*}-submodule-specific option' + 'url.*.:${${line[1]#url.}%.*}-specific option' + 'svn-remote.*.:git-svn ${${line[1]#svn-remote.}%.*}-specific option') + + local found + found=${${${(M)labels:#(${IPREFIX}|${IPREFIX%%.*}.\*.):*}[1]}#*:} + [[ -n $found ]] && label=${(Q)"$(eval "print -rn -- $found")"} + elif compset -P '[^.]##.'; then + local opt + declare -a match mbegin mend + for opt in ${${${${(M)git_options_static:#(#i)${IPREFIX}[^.:]##:*}#(#i)${IPREFIX}}/#(#b)([^:]##:)([^\\:]#(\\?[^\\:]#)#:[^\\:]#(\\?[^\\:]#)#:->bool)/$match[1]whether or not to $match[2]}/#(#b)([^:]##:([^\\:]#(\\?[^\\:]#)#))*/$match[1]}; do + if (( ${git_options_static[(I)${opt%%:*}.*]} )); then + sections_and_options+=$opt + else + options+=$opt + fi + done + + declare -a subsections + subsections=( + 'color.decorate:git log --decorate options' + 'gitcvs.ext:ext-connection-method-specific options' + 'gitcvs.pserver:pserver-connection-method-specific options' + 'notes.rewrite:commands to copy notes from original for when rewriting commits') + sections+=(${${(M)subsections:#${IPREFIX}[^.:]##(.|):*}#${IPREFIX}}) + + # TODO: Is it fine to use functions like this before _describe below, + # or do we need a tag loop? + # TODO: It would be nice to output _message -e TYPE label when the + # following functions don’t generate any output in the case of + # multi-level options. + case $IPREFIX in + (alias.) + __git_aliases && ret=0 + ;; + (branch.) + __git_branch_names -S . && ret=0 + ;; + (browser.) + __git_browsers -S . && ret=0 + ;; + (difftool.) + __git_difftools -S . && ret=0 + ;; + (gc.) + __git_config_sections '^gc\..+\.[^.]+$' refpatterns 'ref pattern' -S . && ret=0 + ;; + (guitool.) + __git_config_sections '^guitool\..+\.[^.]+$' guitools 'gui tool' -S . && ret=0 + ;; + (man.) + __git_man_viewers -S . && ret=0 + ;; + (merge.) + __git_merge_drivers -S . && ret=0 + ;; + (mergetool.) + __git_mergetools -S . && ret=0 + ;; + (pager.) + __git_aliases_and_commands && ret=0 + ;; + (pretty.) + __git_config_sections -a '(|)' '^pretty\..+\.[^.]+$' prettys 'pretty format string' && ret=0 + ;; + (remote.) + __git_remotes -S . && ret=0 + ;; + (remotes.) + __git_remote-groups && ret=0 + ;; + (sendemail.) + __git_sendemail_identities -S . && ret=0 + ;; + (submodule.) + __git_submodules -S . && ret=0 + ;; + (url.) + __git_config_sections '^url\..+\.[^.]+$' bases base -S . && ret=0 + ;; + (svn-remote.) + __git_svn-remotes -S . && ret=0 + ;; + esac + else + sections=( + advice:'options controlling advice' + core:'options controlling git core' + add:'git add options' + alias:'command aliases' + am:'git am options' + apply:'git apply options' + branch:'branch options' + browser:'browser options' + clean:'git clean options' + color:'color options' + commit:'git commit options' + diff:'diff options' + difftool:'difftools' + fetch:'git fetch options' + format:'format options' + gc:'git gc options' + gitcvs:'git-cvs options' + gui:'git gui options' + guitool:'git gui tool options' + help:'git help options' + http:'http options' + i18n:'internationalization options' + imap:'IMAP options' + init:'git init options' + instaweb:'git web options' + interactive:'options controlling interactivity' + log:'git log options' + mailmap:'mailmap options' + man:'man options' + merge:'git merge options' + mergetool:'mergetools' + notes:'git notes options' + pack:'options controlling packing' + pager:'pager options' + pretty:'pretty formats' + pull:'git pull options' + push:'git push options' + rebase:'git rebase options' + receive:'git receive options' + remote:'remotes' + remotes:'remotes groups' + repack:'repack options' + rerere:'git rerere options' + sendemail:'git send-email options' + showbranch:'showbranch options' + status:'git status options' + submodule:'git submodule options' + tar:'git tar-tree options' + transfer:'options controlling transfers' + url:'URL prefixes' + user:'options controlling user identity' + web:'web options' + svn:'git svn options' + svn-remote:'git svn remotes') + fi + + # TODO: Add equivalent of -M 'r:|.=* r:|=*' here so that we can complete + # b.d.c to browser.dillo.cmd. + _describe -t option-names $label \ + sections -M 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' -S . -- \ + sections_and_options -M 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' -qS . -- \ + options -M 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' && ret=0 + ;; + (gettable-option) + _describe -t git-options option \ + ${${${(0)"$(_call_program gettable-options git config -z --list)"}%%$'\n'*}//:/\\:} + ;; + (gettable-colorbool-option) + __git_config_sections -b '(|)' -a '(|)' '^color\.[^.]+$' gettable-colorbool-options option && ret=0 + ;; + (gettable-color-option) + __git_config_sections -b '(|)' -a '(|)' '^color\.[^.]+\..*$' gettable-color-options option && ret=0 + ;; + (value) + local current=${${(0)"$(_call_program current "git config $opt_args[(I)--system|--global|--local] ${(kv)opt_args[(I)-f|--file]} -z --get '$line[1]'")"}#*$'\n'} + case $line[1] in + (alias.*) + if [[ -n $current ]]; then + compadd - $current && ret=0 + else + _message 'command' + fi + return + ;; + (remotes.*) + # TODO: Use this strategy for all multi-item values. + compset -P '* ' + + local suffix + if [[ $words[CURRENT] == [\"\']* ]]; then + suffix=' ' + else + suffix='\ ' + fi + + # TODO: Should really only complete unique remotes, that is, not the same + # remote more than once in the list. + __git_remotes -S $suffix -q && ret=0 + return + ;; + esac + local z=$'\0' + declare -a parts + parts=("${(S@0)${git_options_static[(r)(#i)${line[1]}:*]}//(#b)(*[^\\]|):/$match[1]$z}") + if (( $#parts < 2 )) && [[ $line[1] == [^.]##.*.[^.]## ]]; then + parts=("${(S@0)${git_options_static[(r)(#i)${line[1]%%.*}.\*.${line[1]##*.}:*]}//(#b)(*[^\\]|):/$match[1]$z}") + fi + (( $#parts > 0 )) || return + case $parts[4] in + ('->'*) + case ${parts[4]#->} in + (apply.ignorewhitespace) + __git_config_values -- "$current" "$parts[5]" \ + {no,false,never,none}':do not ignore whitespace' \ + change:'ignore changes in whitespace' && ret=0 + ;; + (apply.whitespace) + __git_apply_whitespace_strategies && ret=0 + ;; + (bool) + __git_config_booleans "$current" "$parts[5]" "$parts[2]" && ret=0 + ;; + (branch) + __git_branch_names && ret=0 + ;; + (branch.autosetuprebase) + __git_config_values -- "$current" "$parts[5]" \ + never:'never set branch.*.rebase to true' \ + local:'set branch.*.rebase to true for tracked branches of local branches' \ + remote:'set branch.*.rebase to true for tracked branches of remote branches' \ + always:'set branch.*.rebase to true for all tracking branches' && ret=0 + ;; + (branch.mergeoptions) + # TODO: Complete options to git-merge(1). + _message 'git-merge options' + ;; + (bytes) + __git_guard_bytes "$parts[2]" && ret=0 + ;; + (color) + compset -P '* ' + + case ($words[CURRENT]) in + (?*' '?*' '*) + if [[ $words[CURRENT] == *(bold|dim|ul|blink|reverse)* ]]; then + __git_colors && ret=0 + else + __git_color_attributes && ret=0 + fi + ;; + (*) + local suffix q_flag + if [[ $words[CURRENT] == [\"\']* ]]; then + suffix=' ' + q_flag=-q + else + suffix='\ ' + fi + + if [[ $words[CURRENT] == *(bold|dim|ul|blink|reverse)* ]]; then + __git_colors -S $suffix $q_flag && ret=0 + else + _alternative \ + 'colors::__git_colors -S $suffix $q_flag' \ + 'attributes::__git_color_attributes -S $suffix $q_flag' && ret=0 + fi + ;; + esac + ;; + (color-bool) + __git_config_values -t booleans -l boolean -- "$current" false \ + {never,false,no,off}:"do not $parts[2]" \ + always:"always $parts[2]" \ + {auto,true,yes,on}:$parts[2] && ret=0 + ;; + (compression) + __git_compression_levels && ret=0 + ;; + (core.autocrlf) + __git_config_booleans "$current" "$parts[5]" "$parts[2]" \ + input:'convert CRLFs on input only' && ret=0 + ;; + (core.createObject) + __git_config_values -- "$current" "$parts[5]" \ + rename:'rename source objects' \ + link:'hardlink, then delete source objects' && ret=0 + ;; + (core.safecrlf) + __git_config_booleans "$current" "$parts[5]" "$parts[2]" \ + warn:'only warn about irreversible CRLF conversions' && ret=0 + ;; + (core.whitespace) + declare -a values + + values=( + 'blank-at-eol[treat whitespace at the end of the line as an error]' + 'space-before-tab[treat space character before tab character in initial indent as an error]' + 'indent-with-non-tab[treat lines indented with 8 or more space characters as an error]' + 'tab-in-indent[treat lines indented with a tab character as an error]' + 'blank-at-eof[treat blank lines at the end of the files as an error]' + 'cr-at-eol[treat carriage-return at the end of the line as part of line terminator]') + + _values -s , $parts[2] $values && ret=0 + ;; + (days) + if [[ -n $current ]]; then + compadd - $current && ret=0 + elif [[ -n $parts[5] ]]; then + compadd - $parts[5] && ret=0 + else + __git_guard_number 'number of days' + fi + ;; + (days+now) + # TODO: This needs to be improved. + if [[ -n $current ]]; then + compadd - $current && ret=0 + elif [[ -n $parts[5] ]]; then + compadd - $parts[5] && ret=0 + else + __git_guard_number 'number of days' + fi + ;; + (diff.renames) + __git_config_booleans "$current" "$parts[5]" "$parts[2]" \ + {copies,copy}:'try to detect both renames and copies' && ret=0 + ;; + (encoding) + __git_encodings && ret=0 + ;; + (eol) + __git_config_values -- "$current" "$parts[5]" \ + lf:'use LF' \ + crlf:'use CR+LF' \ + native:'use line ending of platform' && ret=0 + ;; + (format.numbered) + __git_config_booleans "$current" "$parts[5]" "$parts[2]" \ + auto:'use sequence numbers if more than one patch' && ret=0 + ;; + (format.thread) + __git_config_booleans "$current" "$parts[5]" "$parts[2]" \ + deep:'make every mail a reply to the previous one' \ + shallow:'make every mail a reply to the first one' && ret=0 + ;; + (gc.packrefs) + __git_config_booleans "$current" "$parts[5]" "$parts[2]" \ + notbare:'pack references if the repository has a working directory' && ret=0 + ;; + (gitcvs.dbdriver) + # TODO: Would be nice to only include those that are installed, but I + # couldn’t figure out a good way of doing that when I wrote this code. + __git_config_values -t dbi-drivers -l 'DBI driver' -- "$current" "$part[5]" \ + SQLite:'use the SQLite database driver' \ + Pg:'use the Pg database driver' && ret=0 + ;; + (help.format) + __git_config_values -- "$current" "$parts[5]" \ + man:'use man' \ + info:'use info' \ + {web,html}:'use HTML' && ret=0 + ;; + (imap.authMethod) + __git_config_values -- "$current" "$parts[5]" \ + CRAM-MD5:'use CRAM-MD5' && ret=0 + ;; + (int) + if [[ -n $current ]]; then + compadd - $current && ret=0 + elif [[ -n $parts[5] ]]; then + compadd - $parts[5] && ret=0 + else + __git_guard_number 'integer' + fi + ;; + (merge.conflictstyle) + __git_config_values -- "$current" "$parts[5]" \ + merge:'use standard merge style' \ + diff3:'use diff3 style' && ret=0 + ;; + (merge.verbosity) + __git_config_values -t verbosity-levels -l 'verbosity level' -- "$current" "$parts[5]" \ + 0:'only final error message if conflicts were detected' + 1:'conflicts' + 2:'conflicts and file changes' + 5:'debugging information' && ret=0 + ;; + (notes.rewriteMode) + __git_config_values -- "$current" "$parts[5]" \ + overwrite:'overwrite existing notes' \ + concatenate:'add the note to the existing ones' \ + ignore:'ignore the new note' && ret=0 + ;; + (permission) + __git_repository_permissions && ret=0 + ;; + (push.default) + __git_config_values -- "$current" "$parts[5]" \ + nothing:'do not push anything' \ + matching:'push all matching branches' \ + tracking:'push current branch to its upstream branch' \ + current:'push current branch to branch of same name' && ret=0 + ;; + (receive.denyCurrentBranch) + __git_config_values -- "$current" "$parts[5]" \ + {refuse,true,yes,on}:'update ref to current branch of non-bare repository' \ + {warn}:'warn about dangers of pushing, but perform it anyway' \ + {false,no,off}:'do not update ref to current branch of non-bare repository' && ret=0 + ;; + (remote.tagopt) + __git_config_values -- "$current" "$parts[5]" \ + --tags:'automatically follow tags' \ + --no-tags:'do not automatically follow tags' && ret=0 + ;; + (sendemail.aliasfiletype) + __git_config_values -- "$current" "$parts[5]" \ + elm:'elm(1)' \ + gnus:'gnus(1)' \ + mutt:'mutt(1)' \ + mailrc:'mailrc(5)' \ + pine:'pine(1)' && ret=0 + ;; + (sendemail.confirm) + __git_sendemail_confirm_values && ret=0 + ;; + (sendemail.smtpencryption) + __git_sendemail_smtpencryption_values && ret=0 + ;; + (sendemail.suppresscc) + __git_sendemail_suppresscc_values && ret=0 + ;; + (status.showUntrackedFiles) + __git_config_values -- "$current" "$parts[5]" \ + no:'do not show untracked files' \ + normal:'show untracked files and directories' \ + all:'show all individual files in directories' && ret=0 + ;; + (refname|string) + # TODO: Something better? + if [[ -n $current ]]; then + compadd - $current && ret=0 + elif [[ -n $parts[5] ]]; then + compadd - $parts[5] && ret=0 + else + # _message 'refname' + _message "${parts[3]:-${parts[2]:-value}}" + fi + ;; + (submodule.ignore) + __git_config_values -- "$current" "$parts[5]" \ + all:'never consider submodules modified' \ + dirty:'ignore all changes to submodule work tree, only take diff between HEAD and recorded commit' \ + untracked:'show modified tracked files' \ + none:'show modified tracked and untracked files' && ret=0 + ;; + (umask) + _alternative \ + 'values:value:(user)' \ + 'umasks::__git_guard_number umask' && ret=0 + ;; + esac + ;; + (*) + # TODO: Do we need to set up a _requested/_next_label? + declare -a action + local expl + _description values expl "$parts[2]" + eval "action=($parts[4])" + "$action[1]" "$expl[@]" "${(@)action[2,-1]}" && ret=0 + ;; + esac + ;; + esac } -# TODO: Could use _cvs_root from _cvs for completing argument to -d. -# TODO: -h is undocumented. -(( $+functions[_git-cvsexportcommit] )) || -_git-cvsexportcommit () { - _arguments \ - '-c[commit automatically if the patch applied cleanly]' \ - '-p[be pedantic (paranoid) when applying patches]' \ - '-a[add authorship information]' \ - '-d[set an alternative CVSROOT to use]:cvsroot' \ - '-f[force the merge, even if the files are not up to date]' \ - '-P[force the parent commit, even if it is not a direct parent]' \ - '-m[prepend the commit message with the provided prefix]:message prefix' \ - $verbose_arg \ - $help_arg \ - '::parent commit id:__git_commits' \ - ':commit id:__git_commits' && ret=0 +(( $+functions[_git-fast-export] )) || +_git-fast-export () { + # TODO: * should be git-rev-arg and git-rev-list arguments. + _arguments -w -S -s \ + '--progress=[insert progress statements]: :__git_guard_number interval' \ + '--signed-tags=[specify how to handle signed tags]:action:((verbatim\:"silently export" + warn\:"export, but warn" + strip\:"export unsigned tags instead" + abort\:"abort on signed tags (default)"))' \ + '--tag-of-filtered-object=[specify how to handle tags whose tagged object is filtered out]:action:((abort\:"abort on such tags" + drop\:"omit such tags" + rewrite\:"tag ancestor commit"))' \ + '-M-[detect moving lines in the file as well]: : :__git_guard_number "number of characters"' \ + '-C-[detect copies as well as renames with given scope]: :__git_guard_number size' \ + '--export-marks=[dump internal marks table when complete]: :_files' \ + '--import-marks=[load marks before processing input]: :_files' \ + '--fake-missing-tagger=[fake a tagger when tags lack them]' \ + '--no-data[do not output blocb objects, instead referring to them via their SHA-1 hash]' \ + '--full-tree[output full tree for each commit]' \ + '*: :__git_commit_ranges' && ret=0 } -# TODO: _cvs_root for -d would be nice -(( $+functions[_git-cvsimport] )) || -_git-cvsimport () { - _arguments \ - $author_conversion_file_arg \ - '-C[specify the git repository to import into]:directory:_directories' \ - '-d[specify the root of the CVS archive]:cvsroot' \ - $help_arg \ - '-i[do not perform a checkout after importing]' \ - '-k[remove keywords from source files in the CVS archive]' \ - '-m[attempt to detect merges based on the commit message]' \ - '*-M[attempt to detect merges based on the commit message with custom pattern]:pattern' \ - '-o[specify the branch into which you wish to import]:branch:__git_branch_names' \ - '-P[read cvsps output file]:file:_files' \ - '-p[specify additional options for cvsps]:cvsps-options' \ - '-r[the git remote to import into]:remote' \ - '-s[substitute the "/" character in branch names with given substitution]:substitute' \ - '-u[convert underscores in tag and branch names to dots]' \ - '-S[skip paths matching given regex]:regex' \ - '-a[import all commits, including recent ones]' \ - '-L[limit the number of commits imported]:limit' \ - $verbose_arg \ - '-z[specify timestamp fuzz factor to cvsps]:fuzz-factor' \ - ':cvsmodule' && ret=0 +(( $+functions[_git-fast-import] )) || +_git-fast-import () { + _arguments -S -A '-*' \ + '--date-format=-[type of dates used in input]:format:((raw\:"native Git format" + rfc2822\:"standard email format from RFC 2822" + now\:"use current time and timezone"' \ + '--force[force updating modified existing branches]' \ + '--max-pack-size=-[maximum size of each packfile]: :__git_guard_bytes' \ + '--big-file-threshold=-[maximum size of blob to create deltas for]: :__git_guard_bytes' \ + '--depth=-[maximum delta depth for blob and tree deltification]: :__git_guard_number "maximum delta depth"' \ + '--active-branches=-[maximum number of branches to maintain active at once]: :__git_guard_number "maximum number of branches"' \ + '--export-marks=-[dump internal marks table when complete]: :_files' \ + '--import-marks=-[load marks before processing input]: :_files' \ + '*--relative-marks[paths for export/import are relative to internal directory in current repository]' \ + '*--no-relative-marks[paths for export/import are not relative to internal directory in current repository]' \ + '--export-pack-edges=-[list packfiles and last commit on branches in them in given file]: :_files' \ + '--quiet[disable all non-fatal output]' \ + '--stats[display statistics about object created]' && ret=0 } -(( $+functions[_git-cvsserver] )) || -_git-cvsserver () { - _message "you probably should not be issuing this command; it is an internal git helper" +(( $+functions[_git-filter-branch] )) || +_git-filter-branch () { + # TODO: --*-filter should take a whole command line. + # TODO: --original should take subdirectory under .git named refs/* or some + # such. + # TODO: * should be git-rev-arg and git-rev-list arguments. + _arguments -S -A '-*' \ + '--env-filter[filter for modifying environment in which commit will be performed]: :_path_commands' \ + '--tree-filter[filter for rewriting tree and its contents]: :_path_commands' \ + '--index-filter[filter for rewriting index]: :_path_commands' \ + '--parent-filter[filter for rewriting parent list of commit]: :_path_commands' \ + '--msg-filter[filter for rewriting commit messages]: :_path_commands' \ + '--commit-filter[filter for rewriting commit]: :_path_commands' \ + '--tag-name-filter[filter for rewriting tag names]: :_path_commands' \ + '--subdirectory-filter[only look at histor that touches given directory]: :_directories' \ + '--prune-empty[ignore empty generated commits]' \ + '--original[namespace where original commits will be stored]:namespace:_directories' \ + '-d[temporary directory used for rewriting]: :_directories' \ + '(-f --force)'{-f,--force}'[force operation]' \ + '*: :__git_commit_ranges' && ret=0 } -(( $+functions[_git-lost-found] )) || -_git-lost-found () { - _nothing +(( $+functions[_git-mergetool] )) || +_git-mergetool () { + # TODO: Only complete files with merge conflicts. + _arguments -S -A '-*' \ + '(-t --tool)'{-t,--tool=}'[merge resolution program to use]: :__git_mergetools' \ + '(-y --no-prompt --prompt)'{-y,--no-prompt}'[do not prompt before invocation of merge resolution program]' \ + '(-y --no-prompt)--prompt[prompt before invocation of merge resolution program]' \ + '*:conflicted file:_files' && ret=0 } (( $+functions[_git-pack-refs] )) || _git-pack-refs () { _arguments \ - '--all[pack all refs]' \ + '( --no-all)--all[pack all refs]' \ + '(--all )--no-all[do not pack all refs]' \ '( --no-prune)--prune[remove loose refs after packing them]' \ - '(--prune )--no-prune[don'\''t remove loose refs after packing them]' && ret=0 -} - -# TODO: something better -(( $+functions[_git-merge-one-file] )) || -_git-merge-one-file () { - _message "you probably should not be issuing this command" + '(--prune )--no-prune[do not remove loose refs after packing them]' && ret=0 } (( $+functions[_git-prune] )) || _git-prune () { _arguments -S \ - '-n[do not remove anything; just report what would have been removed]' \ - '--expire:time:' \ - '*::heads:__git_heads' && ret=0 + '(-n --dry-run)'{-n,--dry-run}'[do not remove anything; just report what would be removed]' \ + '(-v --verbose)'{-v,--rerbose}'[report all removed objects]' \ + '--expire[only expire loose objects older than given date]: :__git_datetimes' \ + '*:: :__git_heads' && ret=0 +} + +(( $+functions[_git-reflog] )) || +_git-reflog () { + declare -a revision_options + __git_setup_revision_options + + if [[ $words[2] == --* ]]; then + _arguments -S \ + $revision_options \ + ':: :__git_references' && ret=0 + else + local curcontext=$curcontext state line + declare -A opt_args + + # TODO: -h is undocumented. + _arguments -C -S \ + '(- : *)-h[display usage]' \ + $revision_options \ + ': :->command' \ + '*:: :->option-or-argument' && ret=0 + + case $state in + (command) + declare -a commands + + commands=( + 'expire:prune old reflog entries' + 'delete:delete entries from reflog' + 'show:show log of ref') + + _describe -t commands command commands && ret=0 + ;; + (option-or-argument) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (expire) + # TODO: -n, --dry-run is undocumented. + _arguments -S \ + '(-n --dry-run)'{-n,--dry-run}'[undocumented]' \ + '--stale-fix[TODO\: provide a decent description for this option]' \ + '--expire=-[prune entries older than given time]: :__git_datetimes' \ + '--expire-unreachable=-[prune entries older than given time and unreachable]: :__git_datetimes' \ + '--all[prune all refs]' \ + '--updateref[update ref with SHA-1 of top reflog entry after expiring or deleting]' \ + '--rewrite[adjust reflog entries to ensure old SHA-1 points to new SHA-1 of previous entry after expring or deleting]' \ + '--verbose[output additional information]' && ret=0 + ;; + (delete) + # TODO: -n, --dry-run is undocumented. + _arguments -C -S \ + '(-n --dry-run)'{-n,--dry-run}'[undocumented]' \ + '--updateref[update ref with SHA-1 of top reflog entry after expiring or deleting]' \ + '--rewrite[adjust reflog entries to ensure old SHA-1 points to new SHA-1 of previous entry after expring or deleting]' \ + '*:: :->reflog-entry' && ret=0 + + case $state in + (reflog-entry) + # TODO: __git_ignore_line doesn’t work here for some reason. + __git_ignore_line __git_reflog_entries && ret=0 + ;; + esac + ;; + (show|--*) + _arguments -S \ + $revision_options \ + ':: :__git_references' && ret=0 + ;; + esac + esac + fi } (( $+functions[_git-relink] )) || _git-relink () { + # TODO: --help is undocumented. _arguments \ '--safe[stop if two objects with the same hash exist but have different sizes]' \ - ':directory:_directories' \ - ':directory:_directories' \ - '*:directory:_directories' && ret=0 + '--help[display help]' \ + ': :_directories' \ + ': :_directories' \ + '*: :_directories' && ret=0 } -# TODO: import stuff from _svn -# TODO: Improve completion of -P argument. -(( $+functions[_git-svnimport] )) || -_git-svnimport () { - _arguments \ - $author_conversion_file_arg \ - '-b[specify the name of the SVN branches directory]:directory:_directories' \ - '-C[specify the git repository to import into]:directory:_directories' \ - '-d[use direct HTTP-requests if possible for logs only]:path' \ - '-D[use direct HTTP-requests if possible]:path' \ - $help_arg \ - '-i[do not perform a checkout after importing]' \ - '-l[limit the number of SVN changesets to pull]: :_guard "[[\:digit\:]]#" number' \ - '-m[attempt to detect merges based on the commit message]' \ - '-M[attempt to detect merges based on the commit message with custom pattern]:pattern' \ - '-o[specify the branch into which you wish to import]:branch' \ - '-r[prepend "rX: " to commit messages, where X is the subversion revision]' \ - '-s[specify the change number to start importing from]:start-revision' \ - '-T[specify the name of the SVN tags directory]:directory:_directories' \ - '-t[specify the name of the SVN trunk]:trunk:_directories' \ - '-I[import svn:ignore directory property to files with given name]:ignored file:_files' \ - '-R[specify how often git repository should be repacked]: :_guard "[[\:digit\:]]#" "number of revisions"' \ - '-P[import only given path of the SVN tree]::_directory' \ - $verbose_arg \ - ':svn-repositry-url:_urls' \ - '::directory:_directories' && ret=0 -} - -# TODO: how do we complete argument 1? -(( $+functions[_git-symbolic-ref] )) || -_git-symbolic-ref () { - _arguments -A '-*' \ - '-q[do not issue error if specified name is not a symbolic ref]' \ - '-m[update reflog for specified name with specied reason]:reason for update' \ - ':symbolic reference' \ - '::reference:__git_references' && ret=0 -} +(( $+functions[_git-remote] )) || +_git-remote () { + local curcontext=$curcontext state line + declare -A opt_args -(( $+functions[_git-tag] )) || -_git-tag () { - local message_args= + _arguments -C \ + '(-v --verbose)'{-v,--verbose}'[show remote url after name]' \ + ': :->command' \ + '*:: :->option-or-argument' && ret=0 - if (( words[(I)-[asu]] )); then - message_args=( - '( -F)-m[specify tag message]:message' - '(-m )-F[read tag message from given file]:message file:_files') - fi + case $state in + (command) + declare -a commands - _arguments -A '-*' \ - - creation \ - '( -s -u)-a[create an unsigned, annotated tag]' \ - '(-a -u)-s[create an signed and annotated tag]' \ - '(-a -s )-u[create a tag, annotated and signed with the given key]:secret key:__git_gpg_secret_keys' \ - '( -v)-f[create a new tag even if one with the same name already exists]' \ - '(-f )-v[verifies the gpg signutare of the given tag]' \ - '--contains=[only list tags which contain the specified commit]:commit:__git_committishs' \ - $message_args \ - ':tag name:__git_tags' \ - '::head:__git_revisions' \ - - deletion \ - '-d[delete tags]:*:tag names:__git_tags' \ - - listing \ - '-l[list tags matching pattern]:pattern' && ret=0 + commands=( + 'add:add a new remote' + 'rename:rename a remote and update all associated tracking branches' + 'rm:remove a remote and all associated tracking branches' + 'set-head:set or delete default branch for a remote' + 'set-branches:change list of branches tracked by a remote' + 'set-url:change URL for a remote' + 'show:show information about a given remote' + 'prune:delete all stale tracking branches for a remote' + 'update:fetch updates for a set of remotes') + + _describe -t commands command commands && ret=0 + ;; + (option-or-argument) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (add) + # TODO: -t and --track should really list branches at url. + _arguments -w -S -s \ + '(-f --fetch)'{-f,--fetch}'[run git fetch on new remote after it has been created]' \ + '( --no-tags)--tags[tell git fetch to import every tag from remote repository]' \ + '(--tags )--no-tags[tell git fetch to not import every tag from remote repository]' \ + '*'{-t,--track=}'[track given branch instead of default glob refspec]: :__git_branch_names' \ + '(-m --master)'{-m,--master=}'[set HEAD of remote to point to given master branch]: :__git_branch_names' \ + '--mirror[do not use separate remotes]' \ + ':name:__git_remotes' \ + ':url:_urls' && ret=0 + ;; + (rename) + _arguments \ + ':old name:__git_remotes' \ + ':new name:__git_remotes' && ret=0 + ;; + (rm) + _arguments \ + ': :__git_remotes' && ret=0 + ;; + (set-head) + # TODO: Second argument should be a branch at url for remote. + _arguments -w -S -s \ + '(- 2)'{-d,--delete}'[delete default branch]' \ + '(- 2)'{-a,--auto}'[determine default branch automatically]' \ + ': :__git_remotes' \ + ': :__git_branch_names' && ret=0 + ;; + (set-branches) + # TODO: Branches should be at url. + _arguments -w -S -s \ + '--add[add branches to those already defined]' \ + ': :__git_remotes' \ + '*: :__git_branch_names' && ret=0 + ;; + (set-url) + # TODO: Old URL should be one of those defined for the remote. + _arguments -w -S -s \ + '(3)--push[manipulate push URLs instead of fetch URLs]' \ + '--add[add URL to those already defined]' \ + '(3)--delete[delete all matching URLs]' \ + ': :__git_remotes' \ + ':new url:_urls' \ + ':old url:_urls' && ret=0 + ;; + (show) + _arguments -w -S -s \ + '-n[do not contact the remote for a list of branches]' \ + '*: :__git_remotes' && ret=0 + ;; + (prune) + _arguments -w -S -s \ + '(-n --dry-run)'{-n,--dry-run}'[do not actually prune, only list what would be done]' \ + '*: :__git_remotes' && ret=0 + ;; + (update) + _arguments -w -S -s \ + '(-p --prune)'{-p,--prune}'[prune all updated remotes]' \ + ': :__git_remote-groups' && ret=0 + ;; + esac + ;; + esac } -__git_zstyle_default ':completion::complete:git-tag:deletion-option-d-rest:*' ignore-line yes -(( $+functions[_git-update-ref] )) || -_git-update-ref () { - _arguments \ - '-m[update reflog for specified name with specied reason]:reason for update' \ - '(:)-d[delete given reference after verifying its value]:symbolic reference:__git_revisions:old reference:__git_revisions' \ - ':symbolic reference:__git_revisions' \ - ':new reference:__git_revisions' \ - '::old reference:__git_revisions' && ret=0 +(( $+functions[_git-repack] )) || +_git-repack () { + # TODO: --quiet is undocumented. + _arguments -w -S -s \ + '(-A)-a[pack all objects into a single pack]' \ + '(-a)-A[pack all objects into a single pack, but unreachable objects become loose]' \ + '-d[remove redundant packs after packing]' \ + '-l[pass --local option to git pack-objects]' \ + '-f[pass --no-reuse-delta option to git pack-objects]' \ + '-F[pass --no-reuse-object option to git pack-objects]' \ + '(-q --quiet)'{-q,--quiet}'[pass -q option to git pack-objects]' \ + '-n[do not update server information]' \ + '--window=-[number of objects to consider when doing delta compression]: :__git_guard_number "number of objects"' \ + '--depth=-[maximum delta depth]: :__git_guard_number "maximum delta depth"' \ + '--window-memory=-[scale window size dynamically to not use more than N bytes of memory]: :__git_guard_bytes' \ + '--max-pack-size=-[maximum size of each output packfile]:maximum pack size:__git_guard_bytes' && ret=0 } -(( $+functions[_git-check-ref-format] )) || -_git-check-ref-format () { - _arguments \ - ':reference:__git_revisions' && ret=0 +(( $+functions[_git-replace] )) || +_git-replace () { + _arguments -w -S -s \ + '(- *)-f[overwrite existing replace ref]' \ + '(- 2)-d[delete existing replace refs]' \ + '(- : *)-l[list replace refs]:pattern' \ + ': :__git_objects' \ + ':replacement:__git_objects' \ + '*: :__git_objects' && ret=0 } +# Ancillary Commands (Interrogators) + +(( $+functions[_git-blame] )) || +_git-blame () { + local curcontext=$curcontext state line + declare -A opt_args + + declare -a revision_options + __git_setup_revision_options + + # TODO: Not sure about __git_cached_files. + _arguments -w -C -S -s \ + '-b[show blank SHA-1 for boundary commits]' \ + '--root[do not treat root commits as boundaries]' \ + '--show-stats[include additional statistics at the end of blame output]' \ + '-L[annotate only the given line range]: :->line-range' \ + '-l[show long rev]' \ + '-t[show raw timestamp]' \ + '-S[use revs from revs-file]:revs-file:_files' \ + '--reverse[walk histor forward instead of backward]' \ + '(-p --porcelain)'{-p,--porcelain}'[show results designed for machine processing]' \ + '--incremental[show results incrementally for machine processing]' \ + '--contents[annotate against the given file if no rev is specified]: :_files' \ + '(-h --help)'{-h,--help}'[show help message]' \ + '-c[use same output format as git annotate]' \ + '--score-debug[output debugging information relating to -C and -M line movement]' \ + '(-f --show-name)'{-f,--show-name}'[show the filename of the original commit]' \ + '(-n --show-number)'{-n,--show-number}'[show the line number in the original commit]' \ + '-s[suppress author name and timestamp]' \ + '-w[ignore whitespace when finding lines]' \ + $revision_options \ + ': :__git_cached_files' \ + ':: :__git_revisions' && ret=0 + + case $state in + (line-range) + if compset -P '([[:digit:]]#|/[^/]#(\\?[^/]#)#/),'; then + _alternative \ + 'line-numbers::__git_guard_number "line number"' \ + 'regexes::_guard "(/[^/]#(\\?[^/]#)#(/|)|)" regex' \ + 'offsets::_guard "([+-][[:digit:]]#|)" "line offset"' && ret=0 + else + _alternative \ + 'line-numbers::__git_guard_number "line number"' \ + 'regexes::_guard "(/[^/]#(\\?[^/]#)#(/|)|)" regex' && ret=0 + fi + ;; + esac +} (( $+functions[_git-cherry] )) || _git-cherry () { + # TODO: --abbrev is undocumented. _arguments \ - $verbose_arg \ - ':upstream:__git_revisions' \ - '::head:__git_revisions' \ - '::limit:__git_revisions' && ret=0 + '(-v --verbose)'{-v,--verbose}'[output additional information]' \ + '--abbrev=[set minimum SHA1 display-length]: :__git_guard_number length' \ + ':upstream commit:__git_commits' \ + '::head commit:__git_commits' \ + '::limit commit:__git_commits' && ret=0 } (( $+functions[_git-count-objects] )) || _git-count-objects () { _arguments \ - '-v[also report number of in-pack objects and objects that can be removed]' && ret=0 + '(-v --verbose)'{-v,--verbose}'[also report number of in-pack objects and objects that can be removed]' && ret=0 } -# TODO: do better than _directories? The directory needs to be a git-repository, -# so one could check for a required file in the given directory. -# TODO: --interpolated-path should complete %H, %CH, %IP, %P, and %D. -(( $+functions[_git-daemon] )) || -_git-daemon () { - _arguments -S \ - '--strict-paths[match paths exactly]' \ - '--base-path=-[remap all the path requests as relative to the given path]:path:_directories' \ - '--interpolated-path=-[dynamically construct alternate paths]:path:_directories' \ - '--export-all[allow pulling from all repositories without verification]' \ - '(--port --listen --user --group)--inetd[run server as an inetd service]' \ - '(--inetd)--listen=-[listen on a specific IP address or hostname]:hostname:_hosts' \ - '(--inetd)--port=-[specify port to listen to]:port:_ports' \ - '--init-timeout=-[specify timeout between connection and request]: :_guard "[[\:digit\:]]#" timeout' \ - '--timeout=-[specify timeout for sub-requests]: :_guard "[[\:digit\:]]#" timeout' \ - '--syslog[log to syslog instead of stderr]' \ - '--user-path=-[allow ~user notation to be used in requests]::path:_directories' \ - '--verbose[log details about incoming connections and requested files]' \ - '--reuseaddr[reuse addresses when already bound]' \ - '(--syslog)--detach[detach from the shell]' \ - '--pid-file=-[save the process id in given file]:pid file:_files' \ - '--user=-[set uid of daemon]:user:_users' \ - '--group=-[set gid of daemon]:group:_groups' \ - '--enable=-[enable site-wide service]:service:__git_daemon_service' \ - '--disable=-[disable site-wide service]:service:__git_daemon_service' \ - '--allow-override[allow overriding site-wide service]:service:__git_daemon_service' \ - '--forbid-override[forbid overriding site-wide service]:service:__git_daemon_service' \ - '*:repository:_directories' && ret=0 +(( $+functions[_git-difftool] )) || +_git-difftool () { + # TODO: Is this fine, or do we need to modify the context or similar? + _git-diff \ + '(-y --no-prompt --prompt)'{-y,--no-prompt}'[do not prompt before invocation of diff tool]' \ + '(-y --no-prompt)--prompt[prompt before invocation of diff tool]' \ + '(-t --tool -x --extcmd)'{-t,--tool=-}'[merge resolution program to use]: :__git_difftools' \ + '(-t --tool -x --extcmd)'{-x,--extcmd=-}'[custom diff command to use]: :_path_commands' \ + '(-g --gui)'{-g,--gui}'[use diff.guitool instead of diff.tool]' +} + +(( $+functions[_git-fsck] )) || +_git-fsck () { + # TODO: -v is undocumented. + _arguments -w -S -s \ + '--unreachable[show objects that are unreferenced in the object database]' \ + '--root[show root nodes]' \ + '--tags[show tags]' \ + '--cache[consider objects recorded in the index as head nodes for reachability traces]' \ + '--no-reflogs[do not consider commits referenced only by reflog entries to be reachable]' \ + '--full[check all object directories]' \ + '--strict[do strict checking]' \ + '(-v --verbose)'{-v,--verbose}'[output additional information]' \ + '--lost-found[write dangling objects into .git/lost-found]' \ + '*: :__git_objects' && ret=0 } (( $+functions[_git-get-tar-commit-id] )) || @@ -2434,313 +2855,579 @@ _git-get-tar-commit-id () { _message 'no arguments allowed; accepts tar-file on standard input' } +(( $+functions[_git-help] )) || +_git-help () { + _arguments -w -S -s \ + '( -i --info -m --man -w --web)'{-a,--all}'[show all available commands]' \ + '(-a --all -m --man -w --web)'{-i,--info}'[show all available commands]' \ + '(-a --all -i --info -w --web)'{-m,--man}'[show all available commands]' \ + '(-a --all -i --info -m --man )'{-w,--web}'[show all available commands]' \ + ': :__git_aliases_and_commands' && ret=0 +} + (( $+functions[_git-instaweb] )) || _git-instaweb () { - _arguments \ + local curcontext=$curcontext state line + declare -A opt_args + + _arguments -w -C -S -s \ '(-l --local)'{-l,--local}'[bind the web server to 127.0.0.1]' \ '(-d --httpd)'{-d,--httpd=}'[HTTP-daemon command-line that will be executed]:command line' \ '(-m --module-path)'{-m,--module-path=}'[module path for the Apache HTTP-daemon]:module path:_directories' \ - '(-p --port)'{-p,--port=}'[port to bind web server to]: :_guard "[[\:digit\:]]" port' \ + '(-p --port)'{-p,--port=}'[port to bind web server to]: :__git_guard_number port' \ '(-b --browser)'{-b,--browser=}'[web-browser command-line that will be executed]:command line' \ - '--start[start the HTTP-daemon and exit]' \ - '--stop[start the HTTP-daemon and exit]' \ - '--restart[restart the HTTP-daemon and exit]' && ret=0 + '(:)--start[start the HTTP-daemon and exit]' \ + '(:)--stop[stop the HTTP-daemon and exit]' \ + '(:)--restart[restart the HTTP-daemon and exit]' \ + ': :->command' && ret=0 + + case $state in + (command) + declare -a commands + + commands=( + start:'start the HTTP-daemon and exit' + stop:'stop the HTTP-daemon and exit' + restart:'restart the HTTP-daemon and exit') + + _describe -t commands command commands && ret=0 + ;; + esac } -(( $+functions[_git-mailinfo] )) || -_git-mailinfo () { +(( $+functions[_git-merge-tree] )) || +_git-merge-tree () { _arguments \ - '-k[do not strip/add \[PATCH\] from the first line of the commit message]' \ - '(-u --encoding)-u[encode commit information in UTF-8]' \ - '(-u --encoding)--encoding[encode commit information in given encoding]:encoding:__git_encodings' \ - ':message file:_files' \ - ':patch file:_files' && ret=0 + ':base-tree:__git_tree_ishs' \ + ':branch 1:__git_tree_ishs' \ + ':branch 2:__git_tree_ishs' && ret=0 } -# TODO: -# /* Backwards compatibility: if no -o specified, accept -# <mbox> <dir> or just <dir> */ -(( $+functions[_git-mailsplit] )) || -_git-mailsplit () { - _arguments -S \ - '-b[if file does not begin with "From " line, assume it is a single mail message]' \ - '-d-[specify number of leading zeros]: :_guard "[[\:digit\:]]#" precision' \ - '-f-[skip the first N numbers]: :_guard "[[\:digit\:]]#" number' \ - '-o-[directory in which to place individual messages]:directory:_directories' \ - '*::mbox file:_files' && ret=0 +(( $+functions[_git-rerere] )) || +_git-rerere () { + local curcontext=$curcontext state line + declare -A opt_args + + # TODO: --rerere-autoupdate is undocumented. + _arguments -w -C -S -s \ + '--rerere-autoupdate[register clean resolutions in index]' \ + ': :->command' && ret=0 + + case $state in + (command) + # TODO: This isn’t optimal, as forget get confused. + _values command \ + 'clear[reset metadata used by rerere]' \ + 'forget[resets metadata used by rerere for specific conflict]: :__git_cached_files' \ + 'diff[output diffs for the current state of the resolution]' \ + 'status[like diff, but only output filesames]' \ + 'gc[prune old records of conflicted merges]' && ret=0 + ;; + esac } -(( $+functions[_git-patch-id] )) || -_git-patch-id () { - _message 'no arguments allowed; accepts patch on standard input' +(( $+functions[_git-rev-parse] )) || +_git-rev-parse () { + local parseopt_opt= sq_quote_opt= local_env_vars_opt= h_opt= + declare -a quiet_opts + if (( CURRENT == 2 )); then + parseopt_opt='--parseopt[use git rev-parse in option parsing mode]' + sq_quote_opt='--sq-quote[use git rev-parse in shell quoting mode]' + local_env_vars_opt='--local-env-vars[list git environment variables local to repository]' + h_opt='-h[display usage]' + fi + + if (( words[(I)--verify] )); then + quiet_opts=({-q,--quiet}'[do not output error messages]') + fi + + if (( words[(I)--parseopt] )); then + if (( words[(I)--] )); then + _message 'argument' + else + # TODO: Parse option specification? + _arguments -w -S -s \ + '(- *)'{-h,--help}'[display usage]' \ + '--keep-dashdash[do not skip first -- option]' \ + '--stop-at-non-option[stop parsing options at first non-option argument]' \ + '*:option specification' && ret=0 + fi + elif (( words[(I)--sq-quote] )); then + _message 'argument' + elif (( words[(I)--local-env-vars|-h] )); then + _message 'no more arguments' + else + _arguments \ + $parseopt_opt \ + $sq_quote_opt \ + $local_env_vars_opt \ + $h_opt \ + '( --no-revs --verify --short)--revs-only[do not output flags and parameters not meant for git rev-list]' \ + '(--revs-only --verify --short)--no-revs[do not output flags and parameters meant for git rev-list]' \ + '( --no-flags --verify --short)--flags[do not output non-flag parameters]' \ + '(--flags --verify --short)--no-flags[do not output flag parameters]' \ + '--default[use given argument if there is no parameter given]:argument' \ + '(--revs-only --no-revs --flags --no-flags --short)--verify[verify parameter to be usable]' \ + '(-q --quiet)'{-q,--quiet}'[suppress all output]' \ + '--sq[output single shell-quoted line]' \ + '--not[toggle ^ prefix of object names]' \ + '( --symbolic-full-name)--symbolic[output in a format as true to input as possible]' \ + '(--symbolic )--symbolic-full-name[same as --symbolic, but omit non-ref inputs]' \ + '--abbrev-ref=-[a non-ambiguous short name of object]::mode:(strict loose)' \ + '--all[show all refs found in refs/]' \ + '--branches=-[show branch refs found in refs/heads/]::shell glob pattern' \ + '--tags=-[show tag refs found in refs/tags/]::shell glob pattern' \ + '--remotes=-[show tag refs found in refs/remotes/]::shell glob pattern' \ + '--glob=-[show all matching refs]::shell glob pattern' \ + '--show-toplevel[show absolute path of top-level directory]' \ + '--show-prefix[show path of current directory relative to top-level directory]' \ + '--show-cdup[show path of top-level directory relative to current directory]' \ + '--git-dir[show $GIT_DIR if defined else show path to .git directory]' \ + '--is-inside-git-dir[show whether or not current working directory is below repository directory]' \ + '--is-inside-work-tree[show whether or not current working directory is inside work tree]' \ + '--is-bare-repository[show whether or not repository is bare]' \ + '(--revs-only --no-revs --flags --no-flags --verify)--short=-[show only shorter unique name]:: :__git_guard_number length' \ + '(--since --after)'{--since=-,--after=-}'[show --max-age= parameter corresponding given date string]:datestring' \ + '(--until --before)'{--until=-,--before=-}'[show --min-age= parameter corresponding given date string]:datestring' \ + '*: :__git_objects' && ret=0 + fi } -(( $+functions[_git-request-pull] )) || -_git-request-pull () { +(( $+functions[_git-show-branch] )) || +_git-show-branch () { + local curcontext=$curcontext state line + declare -A opt_args + + _arguments -w -C -S -s -A '-*' \ + '(--more --merge-base --independent)--list[do not show any ancestry (--more=-1)]' \ + - branches \ + '(-r --remotes -a --all)'{-r,--remotes}'[show remote-tracking branches]' \ + '(-r --remotes -a --all)'{-a,--all}'[show both remote-tracking branches and local branches]' \ + '--current[include current branch to the list of revs]' \ + '( --date-order)--topo-order[show commits in topological order]' \ + '(--topo-order )--date-order[show commits in commit-date order]' \ + '--sparse[output merges that are reachable from multiple tips being shown]' \ + '( --list --merge-base --independent)--more=[go given number of commit beyond common ancestor (no ancestry if negative)]:: :_guard "(-|)[[\:digit\:]]#" limit' \ + '(--more --list --independent)--merge-base[act like git merge-base -a, but with two heads]' \ + '(--more --list --merge-base )--independent[show only the reference that can not be reached from any of the other]' \ + '( --sha1-name)--no-name[do not show naming strings for each commit]' \ + '(--no-name )--sha1-name[name commits with unique prefix of object names]' \ + '--topics[show only commits that are NOT on the first branch given]' \ + '( --no-color)--color[color status sign of commits]:: :__git_color_whens' \ + '(--color )--no-color[do not color statis sign of commits]' \ + '*: :__git_revisions' \ + - reflogs \ + '(-g --reflog)'{-g,--reflog=}'[show reflog entries for given ref]:: :->limit-and-base' \ + ': :__git_references' && ret=0 + + case $state in + (limit-and-base) + if compset -P '[[:digit:]]##,'; then + _alternative \ + 'counts::__git_guard_number count' \ + 'dates::__git_datetimes' && ret=0 + else + __git_guard_number limit + fi + ;; + esac +} + +(( $+functions[_git-verify-tag] )) || +_git-verify-tag () { + # TODO: -v and --verbose are undocumented. + _arguments -w -S -s \ + '(-v --verbose)'{-v,--verbose}'[output additional information]' \ + '*: :__git_tags' && ret=0 +} + +(( $+functions[_git-whatchanged] )) || +_git-whatchanged () { + local -a revision_options + __git_setup_revision_options + + _arguments -S \ + $revision_options \ + '1:: :__git_commits' \ + '*: :__git_cached_files' && ret=0 +} + +# Interacting With Others + +(( $+functions[_git-archimport] )) || +_git-archimport () { + # TODO: archive/branch can perhaps use _arch_archives. It should also allow + # an optional colon followed by a __git_branches. _arguments \ - ':start commit:__git_commits' \ - ':url:_urls' \ - '::end commit:__git_commits' + '-h[display usage]' \ + '-v[verbose output]' \ + '-T[create tag for every commit]' \ + '-f[use fast patchset import strategy]' \ + '-o[use old-style branch names]' \ + '-D[attempt to import trees that have been merged from]: :__git_guard_number depth' \ + '-a[auto-register archives at http://mirrors.sourcecontrol.net]' \ + '-t[use given directory as temporary directory]: :_directories' \ + '*:archive/branch' && ret=0 } -(( $+functions[_git-rev-parse] )) || -_git-rev-parse () { +(( $+functions[_git-cvsexportcommit] )) || +_git-cvsexportcommit () { + # TODO: Could use _cvs_root from _cvs for completing argument to -d. _arguments \ - '(--revs-only --no-revs)--revs-only[do not output flags and parameters not meant for "git-rev-list"]' \ - '(--revs-only --no-revs)--no-revs[do not output flags and parameters meant for "git-rev-list"]' \ - '(--flags --no-flags)--flags[do not output non-flag parameters]' \ - '(--flags --no-flags)--no-flags[do not output flag parameters]' \ - '--default[use "arg" if there is no parameter given]:arg' \ - '--verify[verify parameter to be usable]' \ - '--sq[output single shell-quoted line]' \ - '--not[toggle ^ prefix of object names]' \ - '--symbolic[output in a format as true to input as possible]' \ - '--all[show all refs found in $GIT_DIR/refs]' \ - '--branches[show branch refs found in $GIT_DIR/refs/heads]' \ - '--tags[show tag refs found in $GIT_DIR/refs/tags]' \ - '--remotes[show tag refs found in $GIT_DIR/refs/remotes]' \ - '--show-prefix[show path of current directory relative to top-level directory]' \ - '--show-cdup[show path of top-level directory relative to current directory]' \ - '--git-dir[show "$GIT_DIR" if defined else show path to ".git" directory]' \ - '--short=-[show only handful hexdigits prefix]:: :_guard "[[\:digit\:]]#" number' \ - {--after=-,--since=-}'[show "--max-age=" parameter corresponding given date string]:datestring' \ - {--before=-,--until=-}'[show "--min-age=" parameter corresponding given date string]:datestring' \ - '*:objects:__git_objects' && ret=0 -} - -(( $+functions[_git-runstatus] )) || -_git-runstatus () { + '-c[commit automatically if patch applied cleanly]' \ + '-p[be pedantic (paranoid) when applying patches]' \ + '-a[add authorship information]' \ + '-d[set an alternative CVSROOT to use]:cvsroot' \ + '-f[force the merge, even if files are not up to date]' \ + '-P[force the parent commit, even if it is not a direct parent]' \ + '-m[prepend the commit message with the provided prefix]:message prefix' \ + '-u[update affected files from CVS repository before attempting export]' \ + '-k[reverse CVS keyword expansion]' \ + '-w[specify location of CVS checkout to use for export]' \ + '-W[use current working directory for bot Git and CVS checkout]' \ + '-v[verbose output]' \ + '-h[display usage]' \ + ':: :__git_commits' \ + ': :__git_commits' && ret=0 +} + +(( $+functions[_git-cvsimport] )) || +_git-cvsimport () { + # TODO: _cvs_root for -d would be nice _arguments \ - '--color[show colored status, highlighting modified files]' \ - '--nocolor[turn of colored output]' \ - '--amend[show status based on HEAD^1 instead of HEAD]' \ - '--verbose[show unified diff of all file changes]' \ - '--untracked[show files in untracked directories]' && ret=0 + '-v[verbose output]' \ + '-d[specify the root of the CVS archive]:cvsroot' \ + '-C[specify the git repository to import into]:directory:_directories' \ + '-r[the git remote to import into]:remote' \ + '-o[specify the branch into which you wish to import]: :__git_branch_names' \ + '-i[do not perform a checkout after importing]' \ + '-k[remove keywords from source files in the CVS archive]' \ + '-u[convert underscores in tag and branch names to dots]' \ + '-s[substitute the "/" character in branch names with given substitution]:substitute' \ + '-p[specify additional options for cvsps]:cvsps-options' \ + '-z[specify timestamp fuzz factor to cvsps]:fuzz-factor' \ + '-P[read cvsps output file]:file:_files' \ + '-m[attempt to detect merges based on the commit message]' \ + '*-M[attempt to detect merges based on the commit message with custom pattern]:pattern' \ + '-S[skip paths matching given regex]:regex' \ + '-a[import all commits, including recent ones]' \ + '-L[limit the number of commits imported]:limit' \ + '-A[specify author-conversion file]:author-conversion file:_files' \ + '-R[generate cvs-revisions file mapping CVS revision numbers to commit IDs]' \ + '-h[display usage information]' \ + ':cvsmodule' && ret=0 } -(( $+functions[_git-rm] )) || -_git-rm () { - _arguments -S -A '-*' \ - '-f[override the up-to-date check]' \ - '-n[don'\''t actually remove the files, just show if they exist in the index]' \ - '-r[allow recursive removal when a leading directory-name is given]' \ - '--cached[only remove files from the index]' \ - '--ignore-unmatch[exit with 0 status even if no files matched]' \ - '(-q --quiet)'{-q,--quiet}'[do not output files deleted]' \ - '*:files:__git_cached_files' && ret=0 +(( $+functions[_git-cvsserver] )) || +_git-cvsserver () { + _arguments -w -S -s \ + '--base-path[path to prepend to requested CVSROOT]: :_directories' \ + '--strict-paths[do not allow recursing into subdirectories]' \ + '--export-all[do not check for gitcvs.enabled]' \ + '(- * -V --version)'{-V,--version}'[display version information]' \ + '(- * -h --help)'{-h,-H,--help}'[display usage information]' \ + '::type:(pserver server)' \ + '*: :_directories' && ret=0 +} + +(( $+functions[_git-imap-send] )) || +_git-imap-send () { + _message 'no arguments allowed; accepts mailbox file on standard input' +} + +(( $+functions[_git-quiltimport] )) || +_git-quiltimport () { + _arguments -S \ + '(-n --dry-run)'{-n,--dry-run}'[check patches and warn if they cannot be imported]' \ + '--author[default author name and email address to use for patches]: :_email_addresses' \ + '--patches[set directory containing patches]:patch directory:_directories' && ret=0 +} + +(( $+functions[_git-request-pull] )) || +_git-request-pull () { + _arguments -S \ + '-p[display patch text]' \ + ':start commit:__git_commits' \ + ': :_urls' \ + '::end commit:__git_commits' } (( $+functions[_git-send-email] )) || _git-send-email () { - _arguments \ - '--bcc=["Bcc:" value for each email]:email address:_email_addresses' \ - '--cc=[starting "Cc:" value for each email]:email address:_email_addresses' \ - '(--no-chain-reply-to)--chain-reply-to[each email will be sent as a reply to the previous one sent]' \ - '(--chain-reply-to)--no-chain-reply-to[all emails after the first will be sent as replies to the first one]' \ - '--compose[use $EDITOR to edit an introductory message for the patch series]' \ - '--from=[specify the sender of the emails]:email address:_email_addresses' \ - '--in-reply-to=[specify the contents of the first In-Reply-To header]:message-id' \ - '--no-signed-off-by-cc[do not add emails foudn in "Signed-off-by:" lines to the "Cc:" list]' \ - '--quiet[be less verbose]' \ - '--smtp-server=[specify the outgoing smtp server]:smtp server:_hosts' \ + _arguments -S \ + '--annotate[review and edit each patch before sending it]' \ + '--bcc=[Bcc: value for each email]: :_email_addresses' \ + '--cc=[starting Cc: value for each email]: :_email_addresses' \ + '--compose[edit introductory message for patch series]' \ + '--from=[specify sender]:email address:_email_addresses' \ + '--in-reply-to=[specify contents of first In-Reply-To header]:message-id' \ '--subject=[specify the initial subject of the email thread]:subject' \ - '--suppress-from[do not add the "From:" address to the "Cc:" list]' \ - '--dry-run[do everything except actually send the emails]' \ - '--envelope-sender[specify the envelope sender used to send the emails]:email address:_email_addresses' \ - '--to=[specify the primary recipient of the emails]:email address:_email_addresses' \ - '*:file:_files' && ret=0 -} - -# TODO: --minimize-connections is undocumented. -# TODO: --remote is undocumented. -# TODO: --log-window-size is undocumented. -# TODO: --config-dir is undocumented. -# TODO: --no-auth-cache is undocumented. -# TODO: -C and --copy-similarity are undocumented. -# TODO: --fetch-all and --all are undocumented. -# TODO: -v and --verbose are undocumented. -# TODO: -r and --revisions for show-ignore are undocumented. -# TODO: migrate is undocumented. -# TODO: --minimize for migrate is undocumented. -# TODO: -r, --color, --pager, and --non-recursive for log are undocumented. -# TODO: --message, -m, --file, -F, --revision, and -r for commit-diff are -# undocumented. + '--to=[specify the primary recipient of the emails]: :_email_addresses' \ + '--8bit-encoding=[encoding to use for non-ASCII messages]: :__git_encodings' \ + '--envelope-sender[specify the envelope sender used to send the emails]: :_email_addresses' \ + '--smtp-encryption=[specify encryption method to use]: :__git_sendemail_smtpencryption_values' \ + '--smtp-domain=[specify FQDN used in HELO/EHLO]: :_domains' \ + '--smtp-pass=[specify password to use for SMTP-AUTH]::password' \ + '--smtp-server=[specify SMTP server to connect to]:smtp server:_hosts' \ + '--smtp-server-port=[specify port to connect to SMTP server on]:smtp port:_ports' \ + '--smtp-user=[specify user to use for SMTP-AUTH]:smtp user:_users' \ + '--cc-cmd=[specify command to generate Cc\: header with]:Cc\: command:_path_commands' \ + '( --no-chain-reply-to)--chain-reply-to[send each email as a reply to previous one]' \ + '(--chain-reply-to )--no-chain-reply-to[send all emails after first as replies to first one]' \ + '--identity=[specify configuration identity]: :__git_sendemail_identities' \ + '( --no-signed-off-by-cc)--signed-off-by-cc[add emails found in Signed-off-by: lines to the Cc: list]' \ + '(--signed-off-by-cc )--no-signed-off-by-cc[do not add emails found in Signed-off-by: lines to the Cc: list]' \ + '--suppress-cc=[specify rules for suppressing Cc:]: :__git_sendemail_suppresscc_values' \ + '( --no-suppress-from)--suppress-from[do not add the From: address to the Cc: list]' \ + '(--suppress-from )--no-suppress-from[add the From: address to the Cc: list]' \ + '( --no-thread)--thread[set In-Reply-To: and References: headers]' \ + '(--thread )--no-thread[do not set In-Reply-To: and References: headers]' \ + '--confirm[specify type of confirmation required before sending]: :__git_sendemail_confirm' \ + '--dry-run[do everything except actually sending the emails]' \ + '( --no-format-patch)--format-patch[interpret ambiguous arguments as format-patch arguments]' \ + '(--format-patch )--no-format-patch[interpret ambiguous arguments file-name arguments]' \ + '--quiet[be less verbose]' \ + '( --no-validate)--validate[perform sanity checks on patches]' \ + '(--validate )--validate[do not perform sanity checks on patches]' \ + '--force[send emails even if safetiy checks would prevent it]' \ + '*: :_files' && ret=0 +} + (( $+functions[_git-svn] )) || _git-svn () { local curcontext=$curcontext state line declare -A opt_args _arguments -C \ - '(- :)--version[display version information]' \ - '(- :)--help[display help message]' \ - ':command:->command' \ - '*::options:->options' && ret=0 + '(- :)'{-V,--version}'[display version information]' \ + '(- :)'{-h,-H,--help}'[display usage information]' \ + ': :->command' \ + '*:: :->option-or-argument' && ret=0 case $state in (command) declare -a commands commands=( - 'init:initialize an empty git repository with additional svn data' - 'fetch:fetch revisions from the SVN remote' - 'clone:same as init, followed by fetch' - 'rebase:fetch revs from SVN parent of HEAD and rebase current work on it' - 'dcommit:commit diffs from given head onto SVN repository' - 'branch:create a branch in the SVN repository' - 'tag:create a tag in the SVN repository' - 'log:output SVN log-messages' - 'blame:show what revision and author last modified each line of a file:' - 'find-rev:output git commit corresponding to the given SVN revision'\''s hash' - 'set-tree:commit given commit or tree to SVN repository' - 'create-ignore:recursively finds the svn:ignore property and creates .gitignore files' - 'show-ignore:output corresponding toplevel .gitignore file of svn:ignore' - 'commit-diff:commit diff of two tree-ishs' - 'info:show information about a file or directory' - 'proplist:list the SVN properties stored for a file or directory' - 'propget:get a given SVN property for a file' - 'show-externals:show the subversion externals') - _describe -t commands command commands && ret=0 + init:'initialize an empty git repository with additional svn data' + fetch:'fetch revisions from the SVN remote' + clone:'same as init, followed by fetch' + rebase:'fetch revs from SVN parent of HEAD and rebase current work on it' + dcommit:'commit diffs from given head onto SVN repository' + branch:'create a branch in the SVN repository' + tag:'create a tag in the SVN repository' + log:'output SVN log-messages' + blame:'show what revision and author last modified each line of a file' + find-rev:'output git commit corresponding to the given SVN revision'\''s hash' + set-tree:'commit given commit or tree to SVN repository' + create-ignore:'recursively finds the svn:ignore property and creates .gitignore files' + show-ignore:'output corresponding toplevel .gitignore file of svn:ignore' + mkdirs:'recreate empty directories that Git cannot track' + commit-diff:'commit diff of two tree-ishs' + info:'show information about a file or directory' + proplist:'list the SVN properties stored for a file or directory' + propget:'get a given SVN property for a file' + show-externals:'show the subversion externals' + gc:'compress git-svn-related information' + reset:'undo effect of fetch back to specific revision') + + _describe -t commands command commands && ret=0 ;; - (options) - declare -a arguments + (option-or-argument) + curcontext=${curcontext%:*}-$line[1]: - if [[ $line[1] == (fetch|clone|dcommit|set-tree|rebase|migrate|init) ]]; then - arguments+=( - '--username=[username to use for SVN transport]:username:_users' - '--config-dir=[undocumented]:configuration directory:_directories' - '--no-auth-cache[undocumented]') - fi + declare -a remote_opts fc_opts init_opts cmt_opts opts - if [[ $line[1] == (fetch|clone|dcommit|set-tree|rebase|log) ]]; then - arguments+=( - '( --authors-file)'$author_conversion_file_arg - '(-A )'$long_author_conversion_file_arg) - fi + # TODO: --no-auth-cache is undocumented. + # TODO: --config-dir is undocumented. + remote_opts=( + '--username=[username to use for SVN transport]: :_users' + '--ignore-paths[regular expression of paths to not check out]:pattern' + '--no-auth-cache[undocumented]' + '--config-dir=[undocumented]:configuration directory:_directories') # TODO: --repack-flags can be improved by actually completing the legal # flags to git-repack. - if [[ $line[1] == (fetch|clone|dcommit|set-tree|rebase) ]]; then - arguments+=( - '(-q --quiet)'{-q,--quiet}'[make git-svn less verbose]' - '--repack=[repack files (for given number of revisions)]:: :_guard "[[\:digit\:]]#" "revision limit"' - '(--repack-flags --repack-args --repack-opts)'{--repack-flags=,--repack-args=,--repack-opts=}'[flags to pass to git-repack]:git-repack flags' - '( --no-follow-parent)--follow-parent[follow parent commit]' - '(--follow-parent )--no-follow-parent[do not follow parent commit]' - '--log-window-size=[undocumented]') - fi - - if [[ $line[1] == (clone|init) ]]; then - arguments+=( - $shared_arg - $template_arg + # TODO: --noMetadata is undocumented. + # TODO: --useSvmProps is undocumented. + # TODO: --useSvnsyncProps is undocumented. + # TODO: --log-window-size is undocumented. + # TODO: --no-checkout is undocumented. + fc_opts=( + '--localtime[store Git commit times in local timezone]' + '--use-log-author[use author from the first From: or Signed-Off-By: line, when fetching into git]' + '--add-author-from[when committing to svn, append a From: line based on the git commit'\''s author string]' + '( --no-follow-parent)--follow-parent[follow parent commit]' + '(--follow-parent )--no-follow-parent[do not follow parent commit]' + '(-A --authors-file)'{-A,--authors-file}'[specify author-conversion file]:author-conversion file:_files' + '--authors-prog=[program used to generate authors]: :_path_commands' + '(-q --quiet)'{-q,--quiet}'[make git-svn less verbose]' + '--repack=[repack files (for given number of revisions)]:: :__git_guard_number "revision limit"' + '(--repack-flags --repack-args --repack-opts)'{--repack-flags=,--repack-args=,--repack-opts=}'[flags to pass to git-repack]:git-repack flags' + '--noMetadata[undocumented]' + '--useSvmProps[undocumented]' + '--useSvnsyncProps[undocumented]' + '--log-window-size=[undocumented]' + '--no-checkout[undocumented]' + $remote_opts) + + init_opts=( '(-T --trunk)'{-T-,--trunk=}'[set trunk sub-directory]:trunk sub-directory:->subdirectory' - '(-t --tags)'{-t-,--tags=}'[set tags sub-directory]:tags sub-directory:->subdirectory' - '(-b --branches)'{-b-,--branches=}'[set branches sub-directory]:branches sub-directory:->subdirectory' - '--stdlayout[shorthand for setting trunk,tags,branches as relative paths, the SVN default]' - '--no-metadata[set svn-remote.X.noMetadata]' - '--use-svm-props[set svn-remote.X.useSvmProps]' - '--use-svnsync-props[set svn-remote.X.useSvnsyncProps]' - '--rewrite-root=[set svn-remote.X.rewriteRoot]:new root' - '--use-log-author[use author from the first From: or Signed-Off-By: line, when fetching into git]' - '--add-author-from[when committing to svn, append a From: line based on the git commit'\''s author string]' - '--prefix=[prefix to use for names of remotes]:path prefix:_directories -r ""') - fi - - if [[ $line[1] == (dcommit|set-tree|commit-diff) ]]; then + '(-t --tags)*'{-t-,--tags=}'[add tags sub-directory]:tags sub-directory:->subdirectory' + '(-b --branches)*'{-b-,--branches=}'[add branches sub-directory]:branches sub-directory:->subdirectory' + '(-s --stdlayout)'{-s,--stdlayout}'[shorthand for setting trunk, tags, branches as relative paths, the SVN default]' + '--no-metadata[set svn-remote.*.noMetadata]' + '--use-svm-props[set svn-remote.*.useSvmProps]' + '--use-svnsync-props[set svn-remote.*.useSvnsyncProps]' + '--rewrite-root=[set svn-remote.*.rewriteRoot]:new root:_urls' + '--rewrite-uuid=[set svn-remote.*.rewriteUUID]:uuid' + '--prefix=[prefix to use for names of remotes]:path prefix:_directories -r ""' + '( --no-minimize-url)--minimize-url[minimize URLs]' + '(--minimize-url )--no-minimize-url[do not minimize URLs]' + '--shared=[share repository amongst several users]:: :__git_repository_permissions' + '--template=[directory to use as a template for the object database]: :_directories' + $remote_opts) + + # TODO: -C and --copy-similarity are undocumented. + cmt_opts=( + '--rmdir[remove empty directories from SVN tree after commit]' + '(-e --edit)'{-e,--edit}'[edit commit message before committing]' + '-l-[limit number of rename/copy targets to run]: :__git_guard_number' + '--find-copies-harder[try harder to find copies]' + '(-C --copy-similarity)'{-C-,--copy-similarity=}'[undocumented]: :_guard "[[\:digit:\]]#" number') + + if [[ $line[1] == (fetch|clone) ]]; then arguments+=( - '--rmdir[remove empty directories from SVN tree after commit]' - '(-e --edit)'{-e,--edit}'[edit commit message before committing]' - $find_copies_harder_arg - $diff_l_arg - '(-C --copy-similarity)'{-C-,--copy-similarity=}'[undocumented]:number') + '(-r --revision)'{-r,--revision}'[only fetch given revision or revision range]: :__git_svn_revisions' + ':: :__git_svn-remotes') fi - if [[ $line[1] == (fetch|clone|log|create-ignore|info|propget|proplist|show-externals) ]]; then - arguments+=( - '(-r --revision)'{-r,--revision}'[only fetch given revision or revision range]:revision:->__git_svn_revisions' - '::svn remote:__git_svn-remotes') + if [[ $line[1] == (fetch|rebase|dcommit) ]]; then + # TODO: --fetch-all and --all are undocumented. + opts+=( + '(--fetch-all --all)'{--fetch-all,--all}'[undocumented]') fi - if [[ $line[1] == (dcommit|rebase) ]]; then - arguments+=( + if [[ $line[1] == (rebase|dcommit) ]]; then + opts+=( '(-m --merge)'{-m,--merge}'[use merging strategies, if necessary]' '*'{-s,--strategy=-}'[use given merge strategy]:merge strategy:__git_merge_strategies') fi - if [[ $line[1] == (fetch|dcommit|rebase) ]]; then - arguments+=( - '(--fetch-all --all)'{--fetch-all,--all}'[undocumented]') + if [[ $line[1] == (rebase|dcommit|branch) ]]; then + opts+=( + '(-n --dry-run)'{-n,--dry-run}'[only display what would be done]') fi - if [[ $line[1] == (dcommit|log|rebase) ]]; then - arguments+=( - '(-v --verbose)'{-v,--verbose}'[output extra information]') + if [[ $line[1] == (rebase|dcommit|log) ]]; then + opts+=( + '(-v --verbose)'{-v,--verbose}'[display extra information]') fi case $line[1] in + (init) + opts+=( + $init_opts) + ;; + (fetch) + opts+=( + '--parent[fetch only from SVN parent of current HEAD]' + $fc_opts) + ;; (clone) - arguments+=( + opts+=( + $init_opts + $fc_opts ':url:_urls' '::directory:_directories') ;; - (set-tree) - arguments+=('--stdin[read list of commits to commit from stdin]') - ;; - (show-ignore) - arguments+=('-r --revision)'{-r,--revision}'[undocumented]:revision:->__git_svn_revisions') + (rebase) + opts+=( + '--local[do not fetch remotely, rebase against the last fetched commit from SVN]' + $fc_opts) ;; (dcommit) arguments+=( - '(-n --dry-run)'{-n,--dry-run}'[output git-commands that would show diffs that would be committed]' '--no-rebase[do not rebase or reset after committing]' - '--commit-url[commit to a different SVN url]:SVN URL:_url') + '--commit-url[commit to a different SVN url]:SVN URL:_url' + $fc_opts + $cmt_opts) ;; - (branch) - arguments+=( + (branch|tag) + # TODO: -d/--destination should complete output of + # git config --get-all svn-remote.*.branches + # git config --get-all svn-remote.*.tags + # TODO: --username should probably use something from _svn. + # TODO: --commit-url should complete output of + # git config --get-all svn-remote.*.commiturl + opts+=( '(-m --message)'{-m,--message}'[specify the commit message]:message' - '(-t --tag)'{-t,--tag}'[create a tag]') - ;; - (migrate) - arguments+=( - '--minimize[undocumented]') + '(-d --destination)'{-d,--destination}'[location of branch or tag to create in SVN repository]: :_directories' + '--username[specify SVN username to perform commit as]: :_users' + '--commit-url[specify URL to connect to destination SVN repository]: :_urls') + + if [[ $line[1] != tag ]]; then + opts+=( + '(-t --tag)'{-t,--tag}'[create a tag]') + fi ;; (log) - __git_setup_revision_arguments - - arguments+=( - $revision_arguments + declare -a revision_options + __git_setup_revision_options + + # TODO: --color is undocumented. + # TODO: --pager is undocumented. + # TODO: --non-recursive is undocumented. + opts+=( + $revision_options '(-r --revision)'{-r-,--revision=}'[revisions to output log information for]: :__git_svn_revision_numbers' - '--limit=[like --max-count, but not counting merged/excluded commits]: :_guard "[[\:digit\:]]#" limit' + '--limit=[like --max-count, but not counting merged/excluded commits]: :__git_guard_number limit' '--incremental[give output suitable for concatenation]' '--show-commit[output git commit SHA-1, as well]' - '--oneline[similar to --pretty=oneline]' '--color[undocumented]' - '--pager[undocumented]:pager:_files -g *(*)' + '--pager[undocumented]:pager:_path_commands' '--non-recursive[undocumented]') ;; (blame) - arguments+=( + opts+=( '--git-format[produce output in git-blame format, with SVN revision numbers instead of git commit hashes]') ;; - (rebase) - arguments+=( - '--local[do not fetch remotely, rebase against the last fetched commit from SVN]') + (set-tree) + opts+=( + '--stdin[read list of commits to commit from stdin]') + ;; + (create-ignore|show-ignore|mkdirs|proplist|propget|show-externals) + # TODO: -r and --revision is undocumented for show-ignore and mkdirs. + opts+=( + '(-r --revision)'{-r,--revision}'[specify SVN revision]: :__git_svn_revisions') ;; (commit-diff) - arguments+=( + # TODO: -m and --message is undocumented. + # TODO: -F and --file is undocumented. + # TODO: -r and --revision is undocumented. + opts+=( '(-m --message)'{-m-,--message=}'[undocumented]:message' - '(-F --file)'{-F-,--file=}'[undocumented]:file:_files' - '(-r --revision)'{-r-,--revision=}'[undocumented]:revision:__git_svn_revisions') + '(-F --file)'{-F-,--file=}'[undocumented]: :_files' + '(-r --revision)'{-r-,--revision=}'[undocumented]: :__git_svn_revisions') + ;; + (info) + opts+=( + '--url[output only value of URL field]') + ;; + (reset) + opts+=( + '(-r --revision)'{-r,--revision}'[specify most recent SVN revision to keep]: :__git_svn_revisions' + '(-p --parent)'{-p,--parent}'[discard specified revision as well, keeping nearest parent instead]') ;; esac - _arguments -C \ + _arguments -w -C -S -s \ '(-h -H --help)'{-h,-H,--help}'[display usage information]' \ '(-V --version)'{-V,--version}'[display version information]' \ '--minimize-connections[undocumented]' \ '(-R --svn-remote --remote)'{-R,--svn-remote,--remote}'[svn remote to use]:svn remote:__git_svn-remotes' \ '(-i --id)'{-i,--id}'[set GIT_SVN_ID]:GIT_SVN_ID' \ - $arguments && ret=0 + $opts && ret=0 case $state in (subdirectory) @@ -2753,368 +3440,1258 @@ _git-svn () { esac } -(( $+functions[_git-stripspace] )) || -_git-stripspace () { - _message 'no arguments allowed; accepts input file on standard input' -} +# LOW-LEVEL COMMANDS (PLUMBING) -(( $+functions[_git-mergetool] )) || -_git-mergetool () { - local curcontext=$curcontext state line - typeset -A opt_args +# Manipulation commands - _arguments -C \ - '(-t --tool)'{-t,--tool=}':merge resolution tool:(kdiff3 tkdiff meld xxdiff emerge vimdiff gvimdiff opendiff)' \ - '*:conflicted file:_files' && ret=0 -} +(( $+functions[_git-apply] )) || +_git-apply () { + local -a apply_options + __git_setup_apply_options -# --- + _arguments -w -S -s \ + $apply_options \ + '--stat[output diffstat for input (turns off "apply")]' \ + '--numstat[same as --stat but in decimal notation and complete pathnames (turns off "apply")]' \ + '--summary[output summary of git-diff extended headers (turns off "apply")]' \ + '--check[check if patches are applicable (turns off "apply")]' \ + '( --cached)--index[make sure that patch is applicable to index]' \ + '(--index )--cached[apply patches without touching working tree]' \ + '--build-face-ancestor[build temporary index for blobs with ambiguous origin]:index:_files' \ + '(-R --reverse)'{-R,--reverse}'[apply patches in reverse]' \ + '-z[use NUL termination on output]' \ + '--unidiff-zero[disable unified-diff-context check]' \ + '--apply[apply patches that would otherwise not be applied]' \ + '--no-add[ignore additions made by the patch]' \ + '*--exclude=[skip files matching specified pattern]:pattern' \ + '*--include=[include files matching specified pattern]:pattern' \ + '--inaccurate-eof[work around missing-new-line-at-EOF bugs]' \ + '(-v --verbose)'{-v,--verbose}'[display progress on stderr]' \ + '--recount[do not trust line counts in hunk headers]' \ + '*:patch:_files' && ret=0 +} -(( $+functions[__git_guard] )) || -__git_guard () { - declare -A opts +(( $+functions[_git-checkout-index] )) || +_git-checkout-index () { + local z_opt= - zparseopts -K -D -A opts M: J: V: 1 2 n F: X: + if (( words[(I)--stdin] )); then + z_opt='-z[paths are separated with NUL character when reading from standard input]' + fi - [[ "$PREFIX$SUFFIX" != $~1 ]] && return 1 + _arguments -w -S -s \ + '(-u --index)'{-u,--index}'[update stat information in index]' \ + '(-q --quiet)'{-q,--quiet}'[do not complain about existing files or missing files]' \ + '(-f --force)'{-f,--force}'[force overwrite of existing files]' \ + '(-a --all --stdin *)'{-a,--all}'[check out all files in index]' \ + '(-n --no-create)'{-n,--no-create}'[do not checkout new files]' \ + '--prefix=-[prefix to use when creating files]:directory:_directories' \ + '--stage=-[check out files from named stage]:stage:(1 2 3 all)' \ + '--temp[write content to temporary files]' \ + '(-a --all *)--stdin[read list of paths from the standard input]' \ + $z_opt \ + '*: :__git_cached_files' && ret=0 +} - if (( $+opts[-X] )); then - _message -r $opts[-X] +(( $+functions[_git-commit-tree] )) || +_git-commit-tree () { + if (( CURRENT == 2 )); then + _arguments \ + '-h[display usage]' \ + ': :__git_trees' && ret=0 + elif [[ $words[CURRENT-1] == -p ]]; then + local expl + _description commits expl 'parent commit' + __git_objects $expl && ret=0 else - _message -e $2 + compadd - '-p' fi +} - [[ -n "$PREFIX$SUFFIX" ]] +(( $+functions[_git-hash-object] )) || +_git-hash-object () { + _arguments -S \ + '-t[type of object to create]:object type:((blob\:"a blob of data" + commit\:"a tree with parent commits" + tag\:"a symbolic name for another object" + tree\:"a recursive tree of blobs"))' \ + '-w[write object to object database]' \ + '(: --stdin-paths)--stdin[read object from standard input]' \ + '(: --stdin --path)--stdin-paths[read file names from standard input instead of from command line]' \ + '( --no-filters)--path=[hash object as if it were located at given path]: :_files' \ + '(--path )--no-filters[hash contents as is, ignoring any input filters]' \ + '(--stdin --stdin-paths):file:_files' && ret=0 } -__git_guard_branch-name () { - if [[ -n "$PREFIX$SUFFIX" ]]; then - _call_program check-ref-format git check-ref-format "refs/heads/$PREFIX$SUFFIX" &>/dev/null - (( ${#pipestatus:#0} > 0 )) && return 1 +(( $+functions[_git-index-pack] )) || +_git-index-pack () { + local -a stdin_opts + + if (( words[(I)--stdin] )); then + stdin_opts=( + '--fix-thin[record deltified objects, based on objects not included]' + '--keep=-[create .keep file]::reason') fi - _message -e 'branch-name' + # NOTE: --index-version is only used by the Git test suite. + # TODO: --pack_header is undocumented. + _arguments \ + '-v[display progress on stderr]' \ + '-o[write generated pack index into specified file]: :_files' \ + '--stdin[read pack from stdin and instead write to specified file]' \ + $stdin_opts \ + '--strict[die if the pack contains broken objects or links]' \ + ':pack file:_files -g "*.pack"' && ret=0 +} - [[ -n "$PREFIX$SUFFIX" ]] +(( $+functions[_git-merge-file] )) || +_git-merge-file () { + integer n_labels=${#${(M)words[1,CURRENT-1]:#-L}} + local label_opt= + + if (( n_labels < 3 )) || [[ $words[CURRENT-1] == -L ]]; then + local -a ordinals + + ordinals=(first second third) + + label_opt="*-L[label to use for the $ordinals[n_labels+1] file]:label" + fi + + # TODO: --marker-size in undocumented. + # TODO: --diff3 is undocumented. + _arguments \ + $label_opt \ + '(-p --stdout)'{-p,--stdout}'[send merged file to standard output instead of overwriting first file]' \ + '(-q --quiet)'{-q,--quiet}'[do not warn about conflicts]' \ + '( --theirs --union)--ours[resolve conflicts favoring our side of the lines]' \ + '(--ours --union)--theirs[resolve conflicts favoring their side of the lines]' \ + '(--ours --theirs )--union[resolve conflicts favoring both sides of the lines]' \ + '--marker-size[specify length of conflict markers]: :__git_guard_number "marker length"' \ + '--diff3[undocumented]' \ + ':current file:_files' \ + ':base file:_files' \ + ':other file:_files' && ret=0 } -__git_guard_diff-stat-width () { - if [[ $PREFIX == *,* ]]; then - compset -P '*,' - _guard "[[:digit:]]#" "filename width" +(( $+functions[_git-merge-index] )) || +_git-merge-index () { + if (( CURRENT > 2 )) && [[ $words[CURRENT-1] != -[oq] ]]; then + _arguments -S \ + '(:)-a[run merge against all files in index that need merging]' \ + '*: :__git_cached_files' && ret=0 else - compset -S ',*' - _guard "[[:digit:]]#" "width" + declare -a arguments + + (( CURRENT == 2 )) && arguments+='-o[skip failed merges]' + (( CURRENT == 2 || CURRENT == 3 )) && arguments+='(-o)-q[do not complain about failed merges]' + (( 2 <= CURRENT && CURRENT <= 4 )) && arguments+='*:merge program:_files -g "*(*)"' + + _arguments -S $arguments && ret=0 fi } -(( $+functions[__git_command_successful] )) || -__git_command_successful () { - if (( ${#pipestatus:#0} > 0 )); then - _message 'not a git repository' - return 1 +(( $+functions[_git-mktag] )) || +_git-mktag () { + _message 'no arguments allowed; only accepts tags on standard input' +} + +(( $+functions[_git-mktree] )) || +_git-mktree () { + _arguments -w -S -s \ + '-z[read NUL-terminated ls-tree -z output]' \ + '--missing[allow missing objects]' \ + '--batch[allow creation of more than one tree]' && ret=0 +} + +(( $+functions[_git-pack-objects] )) || +_git-pack-objects () { + local thin_opt= + + if (( words[(I)--stdout] )); then + thin_opt='--thin[create a thin pack]' fi - return 0 + + # NOTE: --index-version is only used by the Git test suite. + # TODO: --reflog is undocumented. + # TODO: --keep-unreachable is undocumented. + # TODO: --unpack-unreachable is undocumented. + _arguments -A '-*' \ + '(: --max-pack-size)--stdout[write pack contents to standard output]' \ + '--revs[read revision arguments from standard input]' \ + '(--revs)--unpacked[limit objects to pack to those not already packed]' \ + '(--revs)--all[include all refs as well as revisions already specified]' \ + '--include-tag[include unasked-for annotated tags if object they reference is included]' \ + '--window=-[number of objects to use per delta compression]: :__git_guard_number "window size"' \ + '--depth=-[maximum delta depth]: :__git_guard_number "maximum delta depth"' \ + '--window-memory=-[window size in memory]:window size:__git_guard_bytes' \ + '(--stdout)--max-pack-size=[maximum size of each output packfile]:maximum pack size:__git_guard_bytes' \ + '--honor-pack-keep[ignore objects in local pack with .keep file]' \ + '( --local)--incremental[ignore objects that have already been packed]' \ + '(--incremental )--local[similar to --incremental, but only ignore unpacked non-local objects]' \ + '--non-empty[only create a package if it contains at least one object]' \ + '( --all-progress)--progress[display progress on standard error]' \ + '(--progress --all-progress-implied)--all-progress[display progress output on standard error, even during write-out phase]' \ + '(--all-progress)--all-progress-implied[like --all-progress, but only if --progress was also passed]' \ + '-q[do not report progress]' \ + '--no-reuse-delta[do not reuse existing deltas, but compute them from scratch]' \ + '--no-reuse-object[do not reuse existing object data]' \ + '--compression=-[specify compression level]: :__git_compression_levels' \ + $thin_opt \ + '--delta-base-offset[use delta-base-offset packing]' \ + '--threads=-[specify number of threads for searching for best delta matches]: :__git_guard_number "number of threads"' \ + '--keep-true-parents[pack parents hidden by grafts]' \ + '( --unpack-unreachable)--keep-unreachable[undocumented]' \ + '(--keep-unreachable )--unpack-unreachable[undocumented]' \ + ':base-name:_files' && ret=0 } -(( $+functions[__git_objects] )) || -__git_objects () { - compset -P '*:' - if [[ -n $IPREFIX ]]; then - __git_tree_files "$PREFIX" "${IPREFIX%:}" - else - _alternative \ - 'revisions:revision:__git_revisions' \ - 'files:file:__git_files' +(( $+functions[_git-prune-packed] )) || +_git-prune-packed () { + _arguments -w -S -s \ + '(-n --dry-run)'{-n,--dry-run}'[only list objects that would be removed]' \ + '(-q --quiet)'{-q,--quiet}'[do not display progress on standard error]' && ret=0 +} + +(( $+functions[_git-read-tree] )) || +_git-read-tree () { + local trivial_opt= aggressive_opt= + + if (( words[(I)-m] )); then + trivial_opt='--trivial[restrict three-way merge to only happen if no file-level merging is required]' + aggressive_opt='--aggressive[try harder to resolve merge conflicts]' + fi + + local -a ui_opts + + if (( words[(I)(-m|--reset|--prefix)] )); then + ui_opts=( + '( -i)-u[update the work tree after successful merge]' + '(-u )-i[update only the index; ignore changes in work tree]') + fi + + local exclude_per_directory_opt + + if (( words[(I)-u] )); then + exclude_per_directory_opt='--exclude-per-directory=-[specify .gitignore file]:.gitignore file:_files' fi + + _arguments -w -S -s \ + '( --reset --prefix)-m[perform a merge, not just a read]' \ + '(-m --prefix)--reset[perform a merge, not just a read, ignoring unmerged entries]' \ + '(-m --reset 2 3)--prefix=-[read the contents of specified tree-ish under specified directory]:prefix:_directories -r ""' \ + $ui_opts \ + '-v[display progress on standard error]' \ + $trivial_opt \ + $aggressive_opt \ + $exclude_per_directory_opt \ + '--index-output=[write index in the named file instead of $GIT_INDEX_FILE]: :_files' \ + '--no-sparse-checkout[display sparse checkout support]' \ + '1:first tree-ish to be read/merged:__git_tree_ishs' \ + '2::second tree-ish to be read/merged:__git_tree_ishs' \ + '3::third tree-ish to be read/merged:__git_tree_ishs' && ret=0 } -(( $+functions[__git_trees] )) || -__git_trees () { - __git_objects +(( $+functions[_git-symbolic-ref] )) || +_git-symbolic-ref () { + _arguments -w -S -s \ + '(-q --quiet)'{-q,--quiet}'[do not issue error if specified name is not a symbolic ref]' \ + '-m[update reflog for specified name with specied reason]:reason for update' \ + ':symbolic reference:__git_heads' \ + ':: :__git_references' && ret=0 } -(( $+functions[__git_tree_ishs] )) || -__git_tree_ishs () { - __git_commits +(( $+functions[_git-unpack-objects] )) || +_git-unpack-objects () { + _arguments \ + '-n[only list the objects that would be unpacked]' \ + '-q[run quietly]' \ + '-r[try recovering objects from corrupt packs]' \ + '--strict[do not write objects with broken content or links]' && ret=0 } -(( $+functions[__git_blobs] )) || -__git_blobs () { - __git_objects +(( $+functions[_git-update-index] )) || +_git-update-index () { + local z_opt + + if (( words[(I)--stdin|--index-info] )); then + z_opt='-z[paths are separated with NUL character when reading from stdin]' + fi + + _arguments -S \ + $refreshables \ + '(-)'{-h,--help}'[display usage information]' \ + '--add[add files not already in index]' \ + '( --force-remove)--remove[remove files that are in the index but are missing from the work tree]' \ + '(--remove )--force-remove[remove files from both work tree and index]' \ + '(-q --unmerged --ignore-missing --really-refresh)--refresh[refresh index]' \ + '-q[run quietly]' \ + '--ignore-submodules[do not try to update submodules]' \ + '--unmerged[if unmerged changes exists, ignore them instead of exiting]' \ + '--ignore-missing[ignore missing files when refreshing the index]' \ + '*--cacheinfo[insert information directly into the cache]: :_guard "[0-7]#" "octal file mode": :_guard "[[\:xdigit\:]]#" "object id": :_files' \ + '(: -)--index-info[read index information from stdin]' \ + '--chmod=-[set execute permissions on updated files]:permission:((-x\:executable +x\:"not executable"))' \ + '( --no-assume-unchanged)--assume-unchanged[set "assume unchanged" bit for given paths]' \ + '(--assume-unchanged )--no-assume-unchanged[unset "assume unchanged" bit for given paths]' \ + '(-q --unmerged --ignore-missing --refresh)--really-refresh[refresh index, unconditionally checking stat information]' \ + '( --no-skip-worktree)--skip-worktree[set "skip-worktree" bit for given paths]' \ + '(--skip-worktree )--no-skip-worktree[unset "skip-worktree" bit for given paths]' \ + '(-)'{-g,--again}'[run git-update-index on differing index entries]' \ + '(-)--unresolve[restore "unmerged" or "needs updating" state of files]' \ + '--info-only[only insert files object-IDs into index]' \ + '(--remove)--force-remove[remove file from index even when working directory has no such file]' \ + '--replace[replace files already in index, if necessary]' \ + '(: -)--stdin[read list of paths from standard input]' \ + '--verbose[report what is being added and removed from the index]' \ + $z_opt \ + '*:: :_files' && ret=0 } -(( $+functions[__git_stages] )) || -__git_stages () { - __git_guard $* "[[:digit:]]#" 'stage' +(( $+functions[_git-update-ref] )) || +_git-update-ref () { + _arguments -w -S -s \ + '-m[update reflog for specified name with specied reason]:reason for update' \ + '(:)-d[delete given reference after verifying its value]:symbolic reference:__git_revisions:old reference:__git_revisions' \ + '--no-deref[overwrite ref itself, not what it points to]' \ + ':symbolic reference:__git_revisions' \ + ':new reference:__git_revisions' \ + '::old reference:__git_revisions' && ret=0 } -(( $+functions[__git_files_relative] )) || -__git_files_relative () { - local rawfiles files file f_parts prefix p_parts tmp +(( $+functions[_git-write-tree] )) || +_git-write-tree () { + # NOTE: --ignore-cache-tree is only used for debugging. + _arguments -w -S -s \ + '--missing-ok[ignore objects in index that are missing in object database]' \ + '--prefix=[write tree representing given sub-directory]:sub-directory:_directories -r ""' && ret=0 +} - prefix=$(_call_program gitprefix git rev-parse --show-prefix 2>/dev/null) - __git_command_successful || return +# Interrogation commands - # Empty prefix, no modifications - if (( $#prefix == 0 )); then - print $1 - return +(( $+functions[_git-cat-file] )) || +_git-cat-file () { + _arguments -w -S -s \ + '(- 1)-t[show type of given object]' \ + '(- 1)-s[show size of given object]' \ + '(- 1)-e[exit with zero status if object exists]' \ + '(- 1)-p[pretty-print given object]' \ + '(- 1)--textconv[show content as transformed by a textconv filter]' \ + '(- :)--batch[print SHA1, type, size, and contents of each object provided on stdin]' \ + '(- :)--batch-check[print SHA1, type, and size of each object provided on stdin]' \ + '(-):object type:(blob commit tag tree)' \ + ': :__git_objects' && ret=0 +} + +(( $+functions[_git-diff-files] )) || +_git-diff-files () { + declare -a revision_options + __git_setup_revision_options + + _arguments -w -S -s \ + $revision_options \ + ': :__git_changed-in-working-tree_files' \ + ': :__git_changed-in-working-tree_files' \ + '*: :__git_changed-in-working-tree_files' && ret=0 +} + +(( $+functions[_git-diff-index] )) || +_git-diff-index () { + local -a revision_options + __git_setup_revision_options + + # TODO: Description of -m doesn’t match that for git-rev-list. What’s going + # on here? + # TODO: With --cached, shouldn’t we only list files changed in index compared + # to given tree-ish? This should be done for git-diff as well, in that case. + _arguments -S \ + $revision_options \ + '--cached[do not consider the work tree at all]' \ + '-m[flag non-checked-out files as up-to-date]' \ + ': :__git_tree_ishs' \ + '*: :__git_cached_files' && ret=0 +} + +(( $+functions[_git-diff-tree] )) || +_git-diff-tree () { + local curcontext=$curcontext state line + declare -A opt_args + + declare -a revision_options + __git_setup_revision_options + + # NOTE: -r, -t, --root are actually parsed for all + # __git_setup_revision_options, but only used by this command, so only have + # them here. + _arguments -w -C -S -s \ + $revision_options \ + '-r[recurse into subdirectories]' \ + '(-r )-t[disply tree objects in diff output]' \ + '--root[display root diff]' \ + '-m[do not ignore merges]' \ + '-s[do not show differences]' \ + '(--pretty --header)-v[display commit message before differences]' \ + '--no-commit-id[do not display commit IDs]' \ + '(-c --cc)-c[show differences from each of parents to merge result]' \ + '(-c --cc)--cc[how differences from each of parents and omit differences from only one parent]' \ + '--always[always show commit itself and commit log message]' \ + ': :__git_tree_ishs' \ + '*:: :->files' && ret=0 + + case $state in + (files) + if (( $#line > 2 )); then + # TODO: It would be better to output something like + # + # common files: + # ... + # original tree: + # ... + # new tree: + # ... + _alternative \ + "original-tree-files:original tree:__git_tree_files ${PREFIX:-.} $line[1]" \ + "new-tree-files:new tree:__git_tree_files ${PREFIX:-.} $line[2]" && ret=0 + else + _alternative \ + 'tree-ishs::__git_tree_ishs' \ + "tree-files::__git_tree_files ${PREFIX:-.} $line[1]" && ret=0 + fi + ;; + esac +} + +(( $+functions[_git-for-each-ref] )) || +_git-for-each-ref () { + # TODO: Better completion for --format: should complete %(field) stuff, that + # is, %(refname), %(objecttype), %(objectsize), %(objectname) with optional ‘*’ + # in front. + _arguments -w -S -s \ + '--count=[maximum number of refs to iterate over]: :__git_guard_number "maximum number of refs"' \ + '--sort=[key to sort refs by]: :__git_ref_sort_keys' \ + '--format=-[output format of ref information]:format' \ + '(-s --shell -p --perl --python --tcl)'{-s,--shell}'[use string literals suitable for sh]' \ + '(-s --shell -p --perl --python --tcl)'{-p,--perl}'[use string literals suitable for Perl]' \ + '(-s --shell -p --perl --tcl)'--python'[use string literals suitable for Python]' \ + '(-s --shell -p --perl --python )'--tcl'[use string literals suitable for Tcl]' \ + ':: :_guard "([^-]?#|)" pattern' && ret=0 +} + +(( $+functions[_git-ls-files] )) || +_git-ls-files () { + local no_empty_directory_opt= + + if (( words[(I)--directory] )); then + no_empty_directory_opt='--no-empty-directory[do not list empty directories]' fi - rawfiles=(${(ps:\0:)1}) - files=() + # TODO: --resolve-undo is undocumented. + # TODO: Replace _files with something more intelligent based on seen options. + # TODO: Apply excludes like we do for git-clean. + _arguments -w -S -s \ + '(-c --cached)'{-c,--cached}'[show cached files in output]' \ + '(-d --deleted)'{-d,--deleted}'[show deleted files in output]' \ + '(-m --modified)'{-m,--modified}'[show modified files in output]' \ + '(-o --others)'{-o,--others}'[show other files in output]' \ + '(-i --ignored)'{-i,--ignored}'[show ignored files in output]' \ + '(-s --stage --with-tree)'{-s,--stage}'[show stage files in output]' \ + '--directory[if a whole directory is classified as "other", show just its name]' \ + $no_empty_directory_opt \ + '(-s --stage -u --unmerged --with-tree)'{-u,--unmerged}'[show unmerged files in output]' \ + '(-k --killed)'{-k,--killed}'[show killed files in output]' \ + '-z[use NUL termination on output]' \ + '*'{-x,--exclude=-}'[skip files matching given pattern]:file pattern' \ + '*'{-X,--exclude-from=-}'[skip files matching patterns in given file]: :_files' \ + '*--exclude-per-directory=-[skip directories matching patterns in given file]: :_files' \ + '--exclude-standard[skip files in standard Git exclusion lists]' \ + '--error-unmatch[if any file does not appear in index, treat this as an error]' \ + '(-s --stage -u --unmerged)--with-tree=[treat paths removed since given tree-ish as still present]: :__git_tree_ishs' \ + '-v[identify each files status (hmrck?)]' \ + '--full-name[force paths to be output relative to the project top directory]' \ + '--abbrev=[set minimum SHA1 display-length]: :__git_guard_number length' \ + '*:: :_files' && ret=0 +} - # Now we assume that we've given "absolute" paths list with "root" - # being repository top directory. $prefix is also "absolute" path. - for file in $rawfiles; do - # Collapse "/./" and "//", strip "/." and "/" from tail (I know, - # this is a bit paranoid). - f_parts=(${(s:/:)"${${${${file//\/\///}//\/.\///}%%/.}%%/}"}) - p_parts=(${(s:/:)"${${${${prefix//\/\///}//\/.\///}%%/.}%%/}"}) - tmp=() - - # Strip common path prefix. - while (( $#f_parts > 0 )) && (( $#p_parts > 0 )) && [[ $f_parts[1] == $p_parts[1] ]]; do - f_parts[1]=() - p_parts[1]=() - done +(( $+functions[_git-ls-remote] )) || +_git-ls-remote () { + # TODO: repository needs fixing + _arguments -A '-*' \ + '(-h --heads)'{-h,--heads}'[show only refs under refs/heads]' \ + '(-t --tags)'{-t,--tags}'[show only refs under refs/tags]' \ + '(-u --upload-pack)'{-u,--upload-pack=-}'[specify path to git-upload-pack on remote side]:remote path' \ + ': :__git_any_repositories' \ + '*: :__git_references' && ret=0 +} - # If prefix still not empty, ascend up. - while (( $#p_parts > 0 )); do - tmp+=.. - p_parts[1]=() - done +(( $+functions[_git-ls-tree] )) || +_git-ls-tree () { + local curcontext=$curcontext state line + declare -A opt_args - # Add remaining path. - tmp=("$tmp[@]" "$f_parts[@]") + _arguments -w -C -S -s \ + '(-t)-d[do not show children of given tree (implies -t)]' \ + '-r[recurse into subdirectories]' \ + '-t[show tree entries even when going to recurse them]' \ + '(-l --long)'{-l,--long}'[show object size of blob entries]' \ + '-z[use NUL termination on output]' \ + '(--name-only --name-status)'{--name-only,--name-status}'[list only filenames, one per line]' \ + '--abbrev=[set minimum SHA1 display-length]: :__git_guard_number length' \ + '--full-name[output full path-names]' \ + '(--full-name)--full-tree[do not limit listing to current working-directory]' \ + ': :__git_tree_ishs' \ + '*:: :->file' && ret=0 - files+=${(j:/:)tmp} - done + case $state in + (file) + __git_ignore_line __git_tree_files ${PREFIX:-.} $line[1] && ret=0 + ;; + esac +} - print ${(pj:\0:)files} +(( $+functions[_git-merge-base] )) || +_git-merge-base () { + _arguments -w -S -s \ + '(-a --all)'{-a,--all}'[display all common ancestors]' \ + '--octopus[compute best common ancestors of all supplied commits]' \ + '(-)--independent[display minimal subset of supplied commits with same ancestors]' \ + ': :__git_commits' \ + '*: :__git_commits' && ret=0 } -(( $+functions[__git_files] )) || -__git_files () { - local expl files ls_opts opts gitdir gitcdup +(( $+functions[_git-name-rev] )) || +_git-name-rev () { + _arguments -S \ + '--tags[only use tags to name commits]' \ + '--refs=[only use refs matching given pattern]: :_guard "?#" "shell pattern"' \ + '(--stdin :)--all[list all commits reachable from all refs]' \ + '(--all :)--stdin[read from stdin and append revision-name]' \ + '--name-only[display only name of commits]' \ + '--no-undefined[die with non-zero return when a reference is undefined]' \ + '--always[show uniquely abbreviated commit object as fallback]' \ + '(--stdin --all)*: :__git_commits' && ret=0 +} - zparseopts -D -E -a opts -- -cached -deleted -modified -others -ignored -unmerged -killed +(( $+functions[_git-pack-redundant] )) || +_git-pack-redundant () { + _arguments -S -A '-*' \ + '(:)--all[process all packs]' \ + '--alt-odb[do not require objects to be present in local packs]' \ + '--verbose[output some statistics to standard error]' \ + '(--all)*::packs:_files -g "*.pack"' && ret=0 +} - gitdir=$(_call_program gitdir git rev-parse --git-dir 2>/dev/null) - __git_command_successful || return +(( $+functions[_git-rev-list] )) || +_git-rev-list () { + local curcontext=$curcontext state line + declare -A opt_args - gitcdup=$(_call_program gitcdup git rev-parse --show-cdup 2>/dev/null) - __git_command_successful || return + declare -a revision_options + __git_setup_revision_options - ls_opts=("--exclude-per-directory=.gitignore") - [[ -f "$gitdir/info/exclude" ]] && ls_opts+="--exclude-from=$gitdir/info/exclude" + _arguments -C -S \ + $revision_options \ + '(--pretty)--header[display contents of commit in raw-format]' \ + '--timestamp[print raw commit timestamp]' \ + '( --bisect-vars --bisect-all)--bisect[show only middlemost commit object]' \ + '(--bisect)--bisect-vars[same as --bisect, displaying shell-evalable code]' \ + '(--bisect)--bisect-all[display all commit objects beteen included and excluded commits]' \ + '*:: :->commit-or-path' && ret=0 - files=$(_call_program files git ls-files -z --full-name $ls_opts $opts -- $gitcdup 2>/dev/null) - __git_command_successful || return - files=(${(ps:\0:)"$(__git_files_relative $files)"}) - __git_command_successful || return + case $state in + (commit-or-path) + # TODO: What paths should we be completing here? + if [[ -n ${opt_args[(I)--]} ]]; then + __git_cached_files && ret=0 + else + _alternative \ + 'commit-ranges::__git_commit_ranges' \ + 'cached-files::__git_cached_files' && ret=0 + fi + ;; + esac +} - _wanted files expl 'index file' _multi_parts $@ - / files +(( $+functions[_git-show-index] )) || +_git-show-index () { + _message 'no arguments allowed; accepts index file on standard input' } -(( $+functions[__git_cached_files] )) || -__git_cached_files () { - __git_files $* --cached +(( $+functions[_git-show-ref] )) || +_git-show-ref () { + _arguments -S \ + - list \ + '(-h --head)'{-h,--head}'[show HEAD reference]' \ + '--tags[show only refs/tags]' \ + '--heads[show only refs/heads]' \ + '(-d --dereference)'{-d,--dereference}'[dereference tags into object IDs as well]' \ + '(-s --hash)'{-s+,--hash=-}'[only show the SHA-1 hash, not the reference name]:: :__git_guard_number length' \ + '--verify[enable stricter reference checking]' \ + '--abbrev=[set minimum SHA1 display-length]: :__git_guard_number length' \ + '(-q --quiet)'{-q,--quiet}'[do not print any results]' \ + '*: :_guard "([^-]?#|)" pattern' \ + - exclude \ + '--exclude-existing=-[filter out existing refs from stdin]:: :_guard "([^-]?#|)" pattern' && ret=0 } -(( $+functions[__git_deleted_files] )) || -__git_deleted_files () { - __git_files $* --deleted +(( $+functions[_git-unpack-file] )) || +_git-unpack-file () { + _arguments -A '-*' \ + '(:)-h[display usage information]' \ + '(-): :__git_blobs' && ret=0 } -(( $+functions[__git_killed_files] )) || -__git_killed_files () { - __git_files $* --killed +(( $+functions[_git-var] )) || +_git-var () { + _arguments \ + '(:)-l[show logical variables]' \ + '(-):variable:((GIT_AUTHOR_IDENT\:"name and email of author" \ + GIT_COMMITTER_IDENT\:"name and email of committer" \ + GIT_EDITOR\:"text editor used by git commands" \ + GIT_PAGER\:"text viewer used by git commands"))' && ret=0 } -(( $+functions[__git_modified_files] )) || -__git_modified_files () { - __git_files $* --modified +(( $+functions[_git-verify-pack] )) || +_git-verify-pack () { + _arguments -w -S -s \ + '(-v --verbose)'{-v,--verbose}'[show objects contained in pack]' \ + '(-s --stat-only)'{-s,--stat-only}'[do not verify pack contents; only display histogram of delta chain length]' \ + '*:index file:_files -g "*.idx"' && ret=0 } -(( $+functions[__git_other_files] )) || -__git_other_files () { - __git_files $* --others +# Synching Repositories + +(( $+functions[_git-daemon] )) || +_git-daemon () { + # TODO: do better than _directories? The directory needs to be a git-repository, + # so one could check for a required file in the given directory. + # TODO: --interpolated-path should complete %H, %CH, %IP, %P, and %D. + _arguments -S \ + '--strict-paths[match paths exactly]' \ + '--base-path=-[remap all the path requests as relative to the given path]:path:_directories' \ + '--base-path-relaxed[allow lookup of base path witout prefix]' \ + '--interpolated-path=-[dynamically construct alternate paths]:path:_directories' \ + '--export-all[allow pulling from all repositories without verification]' \ + '(--port --listen --user --group)--inetd[run server as an inetd service]' \ + '(--inetd)--listen=-[listen on a specific IP address or hostname]: :_hosts' \ + '(--inetd)--port=-[specify port to listen to]: :_ports' \ + '--init-timeout=-[specify timeout between connection and request]: :__git_guard_number timeout' \ + '--timeout=-[specify timeout for sub-requests]: :__git_guard_number timeout' \ + '--max-connections=-[specify maximum number of concurrent clients]: :__git_guard_number "connection limit"' \ + '--syslog[log to syslog instead of standard error]' \ + '--user-path=-[allow ~user notation to be used in requests]::path:_directories' \ + '--verbose[log details about incoming connections and requested files]' \ + '--reuseaddr[reuse addresses when already bound]' \ + '(--syslog)--detach[detach from the shell]' \ + '--pid-file=-[save the process id in given file]:pid file:_files' \ + '--user=-[set uid of daemon]: :_users' \ + '--group=-[set gid of daemon]: :_groups' \ + '--enable=-[enable site-wide service]: :__git_daemon_service' \ + '--disable=-[disable site-wide service]: :__git_daemon_service' \ + '--allow-override[allow overriding site-wide service]: :__git_daemon_service' \ + '--forbid-override[forbid overriding site-wide service]: :__git_daemon_service' \ + '*:repository:_directories' && ret=0 } -(( $+functions[__git_unmerged_files] )) || -__git_unmerged_files () { - __git_files $* --unmerged +(( $+functions[_git-fetch-pack] )) || +_git-fetch-pack () { + # TODO: Limit * to __git_head_references? + _arguments -A '-*' \ + '--all[fetch all remote refs]' \ + '(-q --quiet)'{-q,--quiet}'[make output less verbose]' \ + '(-k --keep)'{-k,--keep}'[do not invoke git-unpack-objects on received data]' \ + '--thin[fetch a thin pack]' \ + '--include-tag[download referenced annotated tags]' \ + '(--upload-pack --exec)'{--upload-pack=-,--exec=-}'[specify path to git-upload-pack on remote side]:remote path' \ + '--depth=-[limit fetching to ancestor-chains not longer than given number]: :__git_guard_number "maximum ancestor-chain length"' \ + '--no-progress[do not display progress]' \ + '-v[produce verbose output]' \ + ': :__git_any_repositories' \ + '*: :__git_references' && ret=0 } -#this is for git-commit which can take files both git-added and not -(( $+functions[__git_changed_files] )) || -__git_changed_files () { - local files +(( $+functions[_git-http-backend] )) || +_git-http-backend () { + _nothing +} + +(( $+functions[_git-send-pack] )) || +_git-send-pack () { + # TODO: --mirror is undocumented. + # TODO: --stateless-rpc is undocumented. + # TODO: --helper-status is undocumented. + _arguments -A '-*' \ + '(--receive-pack --exec)'{--receive-pack=-,--exec=-}'[specify path to git-receive-pack on remote side]:remote path' \ + '--all[update all refs that exist locally]' \ + '--dry-run[do everything except actually sending the updates]' \ + '--force[update remote orphaned refs]' \ + '-v[produce verbose output]' \ + '--thin[send a thin pack]' \ + '--mirror[undocumented]' \ + '--stateless-rpc[undocumented]' \ + '--helper-status[undocumented]' \ + ': :__git_any_repositories' \ + '*: :__git_remote_references' && ret=0 +} - files=$(_call_program files git diff-index -z --name-only --no-color HEAD 2>/dev/null) - __git_command_successful || return - files=(${(ps:\0:)"$(__git_files_relative $files)"}) - __git_command_successful || return +(( $+functions[_git-update-server-info] )) || +_git-update-server-info () { + _arguments -w -S -s \ + '(-f --force)'{-f,--force}'[update the info files from scratch]' && ret=0 +} - _wanted files expl 'index file' _multi_parts $@ - / files +(( $+functions[_git-http-fetch] )) || +_git-http-fetch () { + _arguments \ + '-c[fetch commit objects]' \ + '-t[fetch trees associated with commit objects]' \ + '-a[fetch all objects]' \ + '-v[report what is downloaded]' \ + '-w[write commit-id into the filename under "$GIT_DIR/refs/<filename>"]:filename' \ + '--recover[recover from a failed fetch]' \ + '(1)--stdin[read commit ids and refs from standard input]' \ + ': :__git_commits' \ + ': :_urls' && ret=0 } -(( $+functions[__git_tree_files] )) || -__git_tree_files () { - local multi_parts_opts - local tree Path - integer at_least_one_tree_added - local -a tree_files compadd_opts +(( $+functions[_git-http-push] )) || +_git-http-push () { + _arguments \ + '--all[verify that all objects in local ref history exist remotely]' \ + '--force[allow refs that are not ancestors to be updated]' \ + '--dry-run[do everything except actually sending the updates]' \ + '--verbose[report the list of objects being walked locally and sent to remote]' \ + '( -D)-d[remove refs from remote repository]' \ + '(-d )-D[forcefully remove refs from remote repository]' \ + ': :_urls' \ + '*: :__git_remote_references' && ret=0 +} - zparseopts -D -E -a compadd_opts V: J: 1 2 n f X: M: P: S: r: R: q F: +# NOTE: git-parse-remote isn’t a user command. - [[ "$1" == */ ]] && Path="$1" || Path="${1:h}/" - shift - (( at_least_one_tree_added = 0 )) - for tree in $*; do - tree_files+=(${(ps:\0:)"$(_call_program tree-files git ls-tree --name-only -z $tree $Path 2>/dev/null)"}) - __git_command_successful && (( at_least_one_tree_added = 1 )) - done +(( $+functions[_git-receive-pack] )) || +_git-receive-pack () { + # TODO: --advertise-refs is undocumented. + # TODO: --stateless-rpc is undocumented. + _arguments -A '-*' \ + '--advertise-refs[undocumented]' \ + '--stateless-rpc[undocumented]' \ + ':directory to sync into:_directories' && ret=0 +} - if (( !at_least_one_tree_added )); then - return 1 +(( $+functions[_git-shell] )) || +_git-shell () { + local curcontext=$curcontext state line + declare -A opt_args + + _arguments -C \ + '-c[command to execute]: :->command' \ + ': :->argument' && ret=0 + + case $state in + (command) + declare -a commands + + commands=( + git-receive-pack + git-upload-pack + git-upload-archive + cvs) + + _describe -t commands command commands && ret=0 + ;; + (argument) + case $line[1] in + (git-receive-pack) + local expl + + _description directories expl 'directory to sync into' + _directories $expl && ret=0 + ;; + (git-upload-pack|git-upload-archive) + local expl + + _description directories expl 'directory to sync from' + _directories $expl && ret=0 + ;; + (cvs) + compadd - server && ret=0 + esac + ;; + esac +} + + +(( $+functions[_git-upload-archive] )) || +_git-upload-archive () { + _arguments \ + ':directory to get tar archive from:_directories' && ret=0 +} + +(( $+functions[_git-upload-pack] )) || +_git-upload-pack () { + # TODO: --advertise-refs is undocumented. + # TODO: --stateless-rpc is undocumented. + _arguments -S -A '-*' \ + '--strict[do not try <directory>/.git/ if <directory> is not a git directory' \ + '--timeout=-[interrupt transfer after given number of seconds of inactivity]: :__git_guard_number "inactivity timeout"' \ + '--advertise-refs[undocumented]' \ + '--stateless-rpc[undocumented]' \ + ': :_directories' && ret=0 +} + +# Internal Helper Commands + +(( $+functions[_git-check-attr] )) || +_git-check-attr () { + local z_opt= + + local curcontext=$curcontext state line + declare -A opt_args + + if (( words[(I)--stdin] )); then + z_opt='-z[paths are separated with NUL character when reading from stdin]' fi - local expl - _wanted files expl 'tree file' _multi_parts -f $compadd_opts -- / tree_files + _arguments -C \ + '--stdin[read file names from stdin instead of from command line]' \ + $z_opt \ + '(-)--[interpret preceding arguments as attributes and following arguments as path names]' \ + '*:: :->attribute-or-file' && ret=0 + + case $state in + (attribute-or-file) + local -a attributes + + attributes=(crlf ident filter diff merge) + + local only_attributes=1 + for (( i = 2; i < $#words; i++ )); do + if (( attributes[(I)$words[i]] == 0 )); then + only_attributes=0 + break + fi + done + + if (( !only_attributes )) || [[ -n ${opt_args[(I)--]} ]]; then + __git_cached_files && ret=0 + else + _alternative \ + 'attributes::__git_attributes' \ + 'files::__git_cached_files' && ret=0 + fi + ;; + esac } -# TODO: deal with things that __git_heads and __git_tags has in common (i.e., -# if both exists, they need to be completed to heads/x and tags/x. -(( $+functions[__git_commits] )) || -__git_commits () { - _alternative \ - 'heads::__git_heads' \ - 'tags::__git_tags' +(( $+functions[_git-check-ref-format] )) || +_git-check-ref-format () { + _arguments \ + '-h[display usage information]' \ + '--print[display canonicalized name of hypothetical reference of given name]' \ + '--branch[expand previous branch syntax]' \ + ': :__git_references' && ret=0 } -(( $+functions[__git_committishs] )) || -__git_committishs () { - __git_commits +(( $+functions[_git-fmt-merge-msg] )) || +_git-fmt-merge-msg () { + _arguments -w -S -s \ + '( --no-log)--log[display one-line descriptions from actual commits being merged]' \ + '(--log )--no-log[do not display one-line descriptions from actual commits being merged]' \ + '(-m --message)'{-m+,--message=}'[use given message instead of branch names for first line in log message]:message' \ + '(-F --file)'{-F,--file}'[specify list of merged objects from file]: :_files' && ret=0 } -# TODO: deal with prefixes and suffixes listed in git-rev-parse -(( $+functions[__git_revisions] )) || -__git_revisions () { - __git_commits $* +(( $+functions[_git-mailinfo] )) || +_git-mailinfo () { + # TODO: --no-inbody-headers is undocumented. + _arguments -A '-*' \ + '-k[do not strip/add \[PATCH\] from first line of commit message]' \ + '(-u --encoding)-u[encode commit information in UTF-8]' \ + '(-u --encoding)--encoding=-[encode commit information in given encoding]: :__git_encodings' \ + '-n[disable all charset re-coding of metadata]' \ + '( --no-scissors)--scissors[remove everything in body before a scissors line]' \ + '(--scissors )--no-scissors[do not remove everything in body before a scissors line]' \ + '--no-inbody-headers[undocumented]' \ + ':message file:_files' \ + ':patch file:_files' && ret=0 } -(( $+functions[__git_commits2] )) || -__git_commits2 () { - compset -P '\\\^' - __git_commits +(( $+functions[_git-mailsplit] )) || +_git-mailsplit () { + _arguments -S -A '-*' \ + '-o-[directory in which to place individual messages]:directory:_directories' \ + '-b[if file does not begin with "From " line, assume it is a single mail message]' \ + '-d-[specify number of leading zeros]: :__git_guard_number precision' \ + '-f-[skip the first N numbers]: :__git_guard_number' \ + '--keep-cr[do not remove CR from lines ending with CR+LF]' \ + '*::mbox file:_files' && ret=0 } -(( $+functions[__git_commit_ranges] )) || -__git_commit_ranges () { - compset -P '*..' - __git_commits $* +(( $+functions[_git-merge-one-file] )) || +_git-merge-one-file () { + _message 'you probably should not be issuing this command' } -(( $+functions[__git_commit_ranges2] )) || -__git_commit_ranges2 () { - _alternative \ - 'commits::__git_commits2' \ - 'ranges::__git_commit_ranges' +(( $+functions[_git-patch-id] )) || +_git-patch-id () { + _message 'no arguments allowed; accepts patch on standard input' } -# FIXME: these should be imported from _ssh -# TODO: this should take -/ to only get directories -_remote_files () { - # There should be coloring based on all the different ls -F classifiers. - local expl rempat remfiles remdispf remdispd args suf ret=1 +# NOTE: git-sh-setup isn’t a user command. - if zstyle -T ":completion:${curcontext}:files" remote-access; then - zparseopts -D -E -a args p: 1 2 4 6 F: - if [[ -z $QIPREFIX ]] - then rempat="${PREFIX%%[^./][^/]#}\*" - else rempat="${(q)PREFIX%%[^./][^/]#}\*" - fi - remfiles=(${(M)${(f)"$(_call_program files ssh $args -a -x ${IPREFIX%:} ls -d1FL "$rempat" 2>/dev/null)"}%%[^/]#(|/)}) - compset -P '*/' - compset -S '/*' || suf='remote file' +(( $+functions[_git-stripspace] )) || +_git-stripspace () { + _arguments \ + '(-s --strip-comments)'{-s,--strip-comments}'[also strip lines starting with #]' && ret=0 +} -# remdispf=(${remfiles:#*/}) - remdispd=(${(M)remfiles:#*/}) +# INTERNAL GIT COMPLETION FUNCTIONS - _tags files - while _tags; do - while _next_label files expl ${suf:-remote directory}; do -# [[ -n $suf ]] && compadd "$@" "$expl[@]" -d remdispf \ -# ${(q)remdispf%[*=@|]} && ret=0 - compadd ${suf:+-S/} "$@" "$expl[@]" -d remdispd \ - ${(q)remdispd%/} && ret=0 - done - (( ret )) || return 0 - done - return ret - else - _message -e remote-files 'remote file' +# Generic Helpers + +(( $+functions[__git_command_successful] )) || +__git_command_successful () { + if (( ${#*:#0} > 0 )); then + _message 'not a git repository' + return 1 fi + return 0 } -(( $+functions[__git_remote_repository] )) || -__git_remote_repository () { - local service +(( $+functions[__git_committish_range_first] )) || +__git_committish_range_first () { + print -r -- ${1%..(.|)*} +} - service= _ssh +(( $+functions[__git_committish_range_last] )) || +__git_committish_range_last () { + print -r -- ${1##*..(.|)} +} - if compset -P '*:'; then - _remote_files - else - _ssh_hosts -S: - fi +(( $+functions[__git_pattern_escape] )) || +__git_pattern_escape () { + print -r -n ${1//(#m)[\[\]()\\*?#<>~\^]/\\$MATCH} } -(( $+functions[__git_repository] )) || -__git_repository () { - _alternative \ - 'directories::_directories' \ - 'remote repositories::__git_remote_repository' +(( $+functions[__git_is_type] )) || +__git_is_type () { + git rev-parse -q --verify "$2^{$1}" 2>/dev/null >/dev/null } -# should also be $GIT_DIR/remotes/origin -(( $+functions[__git_any_repositories] )) || -__git_any_repositories () { - _alternative \ - 'directories::_directories' \ - 'remotes::__git_remotes' \ - 'remote repositories::__git_remote_repository' +(( $+functions[__git_is_blob] )) || +__git_is_blob () { + __git_is_type blob $1 +} +(( $+functions[__git_is_committish] )) || +__git_is_committish () { + __git_is_type commit $1 } -(( $+functions[__git_remotes] )) || -__git_remotes () { - local expl gitdir remotes +(( $+functions[__git_is_treeish] )) || +__git_is_treeish () { + __git_is_type tree $1 +} + +(( $+functions[__git_is_committish_range] )) || +__git_is_committish_range () { + # TODO: This isn’t quite right. We would like to do parts=${(~s:..(.|))}, + # but that doesn’t work. (This would allow us to make sure that parts only + # contains two elements and then apply __git_is_committish on them. + [[ $1 == *..(.|)* ]] && + __git_is_committish $(__git_committish_range_first $1) && + __git_is_committish $(__git_committish_range_last $1) +} + +(( $+functions[__git_is_initial_commit] )) || +__git_is_initial_commit () { + git rev-parse -q --verify HEAD >/dev/null 2>/dev/null + (( $? == 1 )) +} + +(( $+functions[__git_is_in_middle_of_merge] )) || +__git_is_in_middle_of_merge () { + local gitdir gitdir=$(_call_program gitdir git rev-parse --git-dir 2>/dev/null) - __git_command_successful || return + __git_command_successful $pipestatus || return -# zparseopts -a opts X+: -# -# if (( !$opts[(I)-X] )); then -# descr=remote -# fi + [[ -f $gitdir/MERGE_HEAD ]] +} - remotes=(${${(f)"$(_call_program remotes git config --get-regexp '"^remote\..*\.url$"')"}//#(#b)remote.(*).url */$match[1]}) - __git_command_successful || return +# Completion Wrappers - # TODO: Should combine the two instead of either or. - if (( $#remotes > 0 )); then - _wanted remotes expl remote compadd $* - $remotes - else - _wanted remotes expl remote _files $* - -W "($gitdir/remotes)" -g "$gitdir/remotes/*" - fi +(( $+functions[__git_ignore_line] )) || +__git_ignore_line () { + declare -a ignored + ignored=() + ((CURRENT > 1)) && + ignored+=(${line[1,CURRENT-1]//(#m)[\[\]()\\*?#<>~\^]/\\$MATCH}) + ((CURRENT < $#line)) && + ignored+=(${line[CURRENT+1,-1]//(#m)[\[\]()\\*?#<>~\^]/\\$MATCH}) + $* -F ignored +} + +(( $+functions[__git_ignore_line_inside_arguments] )) || +__git_ignore_line_inside_arguments () { + __git_ignore_line ${*[-1]} ${*[1,-2]} +} + +# Common Argument Types + +(( $+functions[_git_commands] )) || +_git_commands () { + local -a main_porcelain_commands + main_porcelain_commands=( + add:'add file contents to index' + am:'apply patches from a mailbox' + archive:'create archive of files from named tree' + bisect:'find, by binary search, change that introduced a bug' + branch:'list, create, or delete branches' + bundle:'move objects and refs by archive' + checkout:'checkout branch or paths to working tree' + cherry-pick:'apply changes introduced by some existing commits' + citool:'graphical alternative to git commit' + clean:'remove untracked files from working tree' + clone:'clone repository into new directory' + commit:'record changes to repository' + describe:'show most recent tag that is reachable from a commit' + diff:'show changes between commits, commit and working tree, etc.' + fetch:'download objects and refs from another repository' + format-patch:'prepare patches for e-mail submission' + gc:'cleanup unnecessary files and optimize local repository' + grep:'print lines matching a pattern' + gui:'run portable graphical interface to git' + init:'create empty git repository or re-initialize an existing one' + log:'show commit logs' + merge:'join two or more development histories together' + mv:'move or rename file, directory, or symlink' + notes:'add or inspect object notes' + pull:'fetch from and merge with another repository or local branch' + push:'update remote refs along with associated objects' + rebase:'fasforward-port local commits to the updated upstream head' + reset:'reset current HEAD to specified state' + revert:'revert existing commits' + rm:'remove files from the working tree and from the index' + shortlog:'summarize git log output' + show:'show various types of objects' + stash:'stash away changes to dirty working directory' + status:'show working-tree status' + submodule:'initialize, update, or inspect submodules' + tag:'create, list, delete or verify tag object signed with GPG') + + local -a ancillary_manipulator_commands + ancillary_manipulator_commands=( + config:'get and set repository or global options' + fast-export:'data exporter' + fast-import:'import information into git directly' + filter-branch:'rewrite branchers' + mergetool:'run merge conflict resolution tools to resolve merge conflicts' + pack-refs:'pack heads and tags for efficient repository access' + prune:'prune all unreachable objects from the object database' + reflog:'manage reflog information' + relink:'hardlink common objects in local repositories' + remote:'manage set of tracked repositories' + repack:'pack unpacked objects in a repository' + replace:'create, list, delete refs to replace objects') + + local -a ancillary_interrogator_commands + ancillary_interrogator_commands=( + blame:'show what revision and author last modified each line of a file' + cherry:'find commits not merged upstream' + count-objects:'count unpacked objects and display their disk consumption' + difftool:'show changes using common diff tools' + fsck:'verify connectivity and validity of objects in database' + get-tar-commit-id:'extract commit ID from an archive created using git archive' + help:'display help information about git' + instaweb:'instantly browse your working repository in gitweb' + merge-tree:'show three-way merge without touching index' + rerere:'reuse recorded resolution of conflicted merges' + rev-parse:'pick out and massage parameters for other git commands' + show-branch:'show branches and their commits' + verify-tag:'check GPG signature of tags' + whatchanged:'show commit-logs and differences they introduce') + + local -a interaction_commands + interaction_commands=( + archimport:'import an Arch repository into git' + cvsexportcommit:'export a single commit to a CVS checkout' + cvsimport:'import a CVS "repository" into a git repository' + cvsserver:'run a CVS server emulator for git' + imap-send:'send a collection of patches to an IMAP folder' + quiltimport:'apply a quilt patchset' + request-pull:'generate summary of pending changes' + send-email:'send collection of patches as emails' + svn:'bidirectional operation between a Subversion repository and git') + + local -a plumbing_manipulator_commands + plumbing_manipulator_commands=( + apply:'apply patch to files and/or to index' + checkout-index:'copy files from index to working directory' + commit-tree:'create new commit object' + hash-object:'compute object ID and optionally create a blob from a file' + index-pack:'build pack index file for an existing packed archive' + merge-file:'run a three-way file merge' + merge-index:'run merge for files needing merging' + mktag:'create tag object' + mktree:'build tree-object from git ls-tree formatted text' + pack-objects:'create packed archive of objects' + prune-packed:'remove extra objects that are already in pack files' + read-tree:'read tree information into directory index' + symbolic-ref:'read and modify symbolic references' + unpack-objects:'unpack objects from packed archive' + update-index:'register file contents in the working directory to the index' + update-ref:'update object name stored in a reference safely' + write-tree:'create tree from the current index') + + local -a plumbing_interrogator_commands + plumbing_interrogator_commands=( + cat-file:'provide content or type information for repository objects' + diff-files:'compare files in working tree and index' + diff-index:'compare content and mode of blobs between index and repository' + diff-tree:'compare content and mode of blobs found via two tree objects' + for-each-ref:'output information on each ref' + ls-files:'information about files in index/working directory' + ls-remote:'show references in a remote repository' + ls-tree:'list contents of a tree object' + merge-base:'find as good a common ancestor as possible for a merge' + name-rev:'find symbolic names for given revisions' + pack-redundant:'find redundant pack files' + rev-list:'list commit object in reverse chronological order' + show-index:'show packed archive index' + show-ref:'list references in a local repository' + unpack-file:'create temporary file with blob'\''s contents' + var:'show git logical variable' + verify-pack:'validate packed git archive files') + + local -a plumbing_sync_commands + plumbing_sync_commands=( + daemon:'run a really simple server for git repositories' + fetch-pack:'receive missing objects from another repository' + http-backend:'run a server side implementation of Git over HTTP' + send-pack:'push objects over git protocol to another repository' + update-server-info:'update auxiliary information file to help dumb servers') + + local -a plumbing_sync_helper_commands + plumbing_sync_helper_commands=( + http-fetch:'download from remote git repository via HTTP' + http-push:'push objects over HTTP/DAV to another repository' + parse-remote:'routines to help parsing remote repository access parameters' + receive-pack:'receive what is pushed into repository' + shell:'restricted login shell for GIT-only SSH access' + upload-archive:'send archive back to git-archive' + upload-pack:'send objects packed back to git fetch-pack') + + local -a plumbing_internal_helper_commands + plumbing_internal_helper_commands=( + check-attr:'display gitattributes information' + check-ref-format:'ensure that a reference name is well formed' + fmt-merge-msg:'produce merge commit message' + mailinfo:'extract patch and authorship from a single email message' + mailsplit:'split mbox file into a list of files' + merge-one-file:'standard helper-program to use with git merge-index' + patch-id:'compute unique ID for a patch' + stripspace:'filter out empty lines') + + integer ret=1 + # TODO: Is this the correct way of doing it? + # TODO: Should we be chaining them together with || instead? + _describe -t main-porcelain-commands 'main porcelain command' main_porcelain_commands && ret=0 + _describe -t ancillary-manipulator-commands 'ancillary manipulator command' ancillary_manipulator_commands && ret=0 + _describe -t ancillary-interrogator-commands 'ancillary interrogator command' ancillary_interrogator_commands && ret=0 + _describe -t interaction-commands 'interaction command' interaction_commands && ret=0 + _describe -t plumbing-manipulator-commands 'plumbing manipulator command' plumbing_manipulator_commands && ret=0 + _describe -t plumbing-interrogator-commands 'plumbing interrogator command' plumbing_interrogator_commands && ret=0 + _describe -t plumbing-sync-commands 'plumbing sync command' plumbing_sync_commands && ret=0 + _describe -t plumbing-sync-helper-commands 'plumbing sync helper command' plumbing_sync_helper_commands && ret=0 + _describe -t plumbing-internal-helper-commands 'plumbing internal helper command' plumbing_internal_helper_commands && ret=0 + return ret +} + +(( $+functions[__git_aliases] )) || +__git_aliases () { + declare -a aliases + + aliases=(${^${${(0)"$(_call_program aliases "git config -z --get-regexp '^alias.'")"}#alias.}/$'\n'/:alias for \'}\') + + _describe -t aliases alias aliases $* +} + +(( $+functions[__git_aliases_and_commands] )) || +__git_aliases_and_commands () { + _alternative \ + 'aliases::__git_aliases' \ + 'commands::_git_commands' +} +(( $+functions[__git_date_formats] )) || +__git_date_formats () { + declare -a date_formats + + date_formats=( + relative:'show dates relative to the current time' + local:'show timestamps in local timezone' + iso:'show timestamps in ISO 8601 format' + rfc:'show timestamps in RFC 2822 format' + short:'show only date but not time' + raw:'show date in internal raw git format (%s %z)' + default:'show timestamp in the original timezone') + + _describe -t date-formats 'date format' date_formats $* +} + +(( $+functions[__git_gpg_secret_keys] )) || +__git_gpg_secret_keys () { + local expl + + _wanted secret-keys expl 'secret key' compadd \ + ${${(Mo)$(_call_program secret-keys gpg --list-secret-keys 2>/dev/null):%<*>}//(<|>)/} +} + +(( $+functions[__git_merge_strategies] )) || +__git_merge_strategies () { + local expl + local -a merge_strategies + + merge_strategies=(${=${${(M)${(f)"$(_call_program merge-strategies "git merge -s '' 2>&1")"}:#[Aa]vailable (custom )#strategies are: *}#[Aa]vailable (custom )#strategies are: }%.}) + __git_command_successful $pipestatus || return + + _wanted merge-strategies expl 'merge strategy' compadd $* - $merge_strategies +} + +(( $+functions[__git_encodings] )) || +__git_encodings () { + # TODO: Use better algorithm, as shown in iconv completer (separate it to a + # new Type). + local expl + _wanted encodings expl 'encoding' compadd "$@" \ + -M 'm:{a-zA-Z}={A-Za-z} r:|-=* r:|=*' \ + ${${${(f)"$(_call_program encodings iconv --list)"}## #}%//} +} + +(( $+functions[__git_apply_whitespace_strategies] )) || +__git_apply_whitespace_strategies () { + declare -a strategies + + strategies=( + 'nowarn:turn off the trailing-whitespace warning' + 'warn:output trailing-whitespace warning, but apply patch' + 'fix:output trailing-whitespace warning and strip trailing whitespace' + 'error:output trailing-whitespace warning and refuse to apply patch' + 'error-all:same as "error", but output warnings for all files') + + _describe -t strategies 'trailing-whitespace resolution strategy' strategies $* +} + +(( $+functions[__git_remotes] )) || +__git_remotes () { + local remotes expl + + remotes=(${(f)"$(_call_program remotes git remote 2>/dev/null)"}) + + _wanted remotes expl remote compadd $* - $remotes } (( $+functions[__git_ref_specs] )) || __git_ref_specs () { + # TODO: This needs to deal with a lot more types of things. if compset -P '*:'; then __git_heads else @@ -3123,1405 +4700,1336 @@ __git_ref_specs () { __git_heads else _alternative \ - 'tags:tag:__git_tags' \ - 'heads:head:__git_heads -qS :' + 'commit-tags::__git_commit_tags' \ + 'heads::__git_heads -qS :' fi fi } -(( $+functions[__git_signoff_file] )) || -__git_signoff_file () { - _alternative \ - 'signoffs:signoff:(yes true me please)' \ - 'files:signoff file:_files' +(( $+functions[__git_color_whens] )) || +__git_color_whens () { + local -a whens + + whens=( + 'always:always use colors' + 'never:never use colors' + 'auto:use colors if output is to a terminal') + + _describe -t whens when whens $* } -(( $+functions[__git_tag_ids] )) || -__git_tag_ids () { +(( $+functions[__git_ignore_submodules_whens] )) || +__git_ignore_submodules_whens () { + local -a whens + + whens=( + none:'submodule is dirty when it contains untracked or modified files' + untracked:'submodule is dirty when it contains untracket files' + dirty:'ignore all changes to submodules, showing only changes to commits stored in superproject' + all:'ignore all changes to submodules (default)') + + _describe -t whens when whens $* } -(( $+functions[__git_heads] )) || -__git_heads () { +# (Currently) Command-specific Argument Types +(( $+functions[__git_archive_formats] )) || +__git_archive_formats () { local expl - declare -a branch_names - branch_names=(${${(f)"$(_call_program headrefs git for-each-ref --format='"%(refname)"' refs/heads refs/remotes 2>/dev/null)"}#refs/(heads|remotes)/}) - __git_command_successful || return + _wanted archive-formats expl 'archive format' \ + compadd $* - ${${(f)"$(_call_program archive-formats git archive --list)"}} +} - _wanted heads expl branch-name compadd $* - $branch_names HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD +(( $+functions[__git_compression_levels] )) || +__git_compression_levels () { + __git_config_values -t compression-levels -l 'compression level' -- "$current" "$parts[5]" \ + '-1:default level of compression' \ + '0:do not deflate files' \ + '1:minimum compression' \ + '2:a little more compression' \ + '3:slightly more compression' \ + '4:a bit more compression' \ + '5:even more compression' \ + '6:slightly even more compression' \ + '7:getting there' \ + '8:close to maximum compression' \ + '9:maximum compression' } -(( $+functions[__git_tags] )) || -__git_tags () { - local expl - declare -a tag_names +(( $+functions[__git_attributes] )) || +__git_attributes () { + local -a attributes - tag_names=(${${(f)"$(_call_program tagrefs git for-each-ref --format='"%(refname)"' refs/tags 2>/dev/null)"}#refs/tags/}) - __git_command_successful || return + attributes=( + 'crlf:line-ending convention' + 'ident:ident substitution' + 'filter:filters' + 'diff:textual diff' + 'merge:merging strategy') - _wanted tags expl tag-name compadd $* - $tag_names + _describe -t attributes attribute attributes $* } -# TODO: depending on what options are on the command-line already, complete -# only tags or heads -# TODO: perhaps caching is unnecessary. usually won’t contain that much data -# TODO: perhaps provide alternative here for both heads and tags (and use -# __git_heads and __git_tags) -# TODO: instead of "./.", we should be looking in the repository specified as -# an argument to the command (but default to "./." I suppose (why not "."?)) -(( $+functions[__git_references] )) || -__git_references () { -# _alternative \ -# 'heads::__git_heads' \ -# 'tags::__git_tags' && ret=0 +(( $+functions[__git_daemon_service] )) || +__git_daemon_service () { + local -a services + + services=( + 'upload-pack:serve git fetch-pack and git ls-remote clients' + 'upload-archive:serve git archive --remote clients') + + _describe -t services service services $* +} + +(( $+functions[__git_log_decorate_formats] )) || +__git_log_decorate_formats () { + declare -a log_decorate_formats + + log_decorate_formats=( + short:'do not show ref name prefixes' + full:'show ref name prefixes' + no:'do not show ref names') + + _describe -t log-decorate-formats 'log decorate format' log_decorate_formats $* +} + +(( $+functions[__git_repository_permissions] )) || +__git_repository_permissions () { + if [[ -prefix [0-7] ]]; then + _message -e number 'numeric mode' + else + declare -a permissions + + permissions=( + {umask,false,no,off}':use permissions reported by umask()' + {group,true,yes,on}':files and objects are group-writable' + {all,world,everybody}':files and objects are readable by all users and group-shareable') + + _describe -t permissions permission permissions $* + fi +} + +(( $+functions[__git_reflog_entries] )) || +__git_reflog_entries () { local expl + declare -a reflog_entries - # TODO: deal with GIT_DIR - if [[ $_git_refs_cache_pwd != $PWD ]]; then - _git_refs_cache=(${${${(f)"$(_call_program references git ls-remote ./. 2>/dev/null)"}#*$'\t'}#refs/(heads|tags)/}) - __git_command_successful || return - _git_refs_cache_pwd=$PWD + reflog_entries=(${${${(f)"$(_call_program reflog-entries git reflog 2>/dev/null)"}#* }%%:*}) + __git_command_successful $pipestatus || return + + if compset -P '*@'; then + reflog_entries=(${${(M)reflog_entries:#$IPREFIX*}#$IPREFIX}) + _wanted reflog-entries expl 'reflog entry' compadd $* - $reflog_entries + else + reflog_entries=(${reflog_entries%@*}) + _wanted reflog-entries expl 'reflog entry' compadd -qS @ $* - $reflog_entries fi +} - _wanted references expl 'references' compadd - $_git_refs_cache +(( $+functions[__git_ref_sort_keys] )) || +__git_ref_sort_keys () { + compset -P '-' + + local -a sort_keys + + # TODO: numparent is undocumented. + sort_keys=( + 'refname:the name of the ref' + 'objecttype:the type of the object' + 'objectsize:the size of the object' + 'objectname:the object name (SHA-1)' + 'tree:the tree header-field' + 'parent:the parent header-field' + 'numparent:undocumented' + 'object:the object header-field' + 'type:the type header-field' + 'tag:the tag header-field' + 'author:the author header-field' + 'authorname:the name component of the author header-field' + 'authoremail:the email component of the author header-field' + 'authordate:the date component of the author header-field' + 'committername:the name component of the committer header-field' + 'committeremail:the email component of the committer header-field' + 'committerdate:the date component of the committer header-field' + 'taggername:the name component of the tagger header-field' + 'taggeremail:the email component of the tagger header-field' + 'taggerdate:the date component of the tagger header-field' + 'creatorname:the name component of the creator header-field' + 'creatordate:the date component of the creator header-field' + 'subject:the subject of the message' + 'body:the body of the message' + 'body:the contents of the message (subject and body)') + + _describe -t sort-keys 'sort key' sort_keys $* } -(( $+functions[__git_local_references] )) || -__git_local_references () { +(( $+functions[__git_signoff_file] )) || +__git_signoff_file () { + _alternative \ + 'signoffs:signoff:(yes true me please)' \ + 'files:signoff file:_files' +} + +(( $+functions[__git_stashes] )) || +__git_stashes () { local expl + declare -a stashes - if [[ $_git_local_refs_cache_pwd != $PWD ]]; then - _git_local_refs_cache=(${${${(f)"$(_call_program references git ls-remote ./. 2>/dev/null)"}#*$'\t'}#refs/}) - __git_command_successful || return - _git_local_refs_cache_pwd=$PWD - fi + stashes=(${${(f)"$(_call_program stashes git stash list 2>/dev/null)"}/: */}) + __git_command_successful $pipestatus || return - _wanted references expl 'references' compadd - $_git_local_refs_cache + _wanted stashes expl stash compadd $* - $stashes } -(( $+functions[__git_remote_references] )) || -__git_remote_references () { - __git_references +(( $+functions[__git_svn_revisions] )) || +__git_svn_revisions () { + if [[ -prefix *: ]]; then + compset -P '*:' + + _alternative \ + 'revision-numbers::__git_svn_revision_numbers' \ + 'symbolic-revisions:symbolic revision:((HEAD:"the topmost revision of the SVN repository"))' + else + _alternative \ + 'revision-numbers::__git_svn_revision_numbers' \ + 'symbolic-revisions:symbolic revision:__git_svn_base_revisions' + fi } +(( $+functions[__git_svn_base_revisions] )) || +__git_svn_base_revisions () { + declare -a symbolic_revisions + + symbolic_revisions=( + 'BASE:the bottommost revision of the SVN repository') + + # TODO: How do we deal with $*? + _describe -t symbolic-revisions 'symbolic revision' symbolic_revisions -S ':' -r ': ' +} + +# Object Type Argument Types + (( $+functions[__git_branch_names] )) || __git_branch_names () { local expl declare -a branch_names branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads 2>/dev/null)"}#refs/heads/}) - __git_command_successful || return + __git_command_successful $pipestatus || return _wanted branch-names expl branch-name compadd $* - $branch_names } -# TODO: Add merge.*.(name|driver|recursive) and diff.*.(command|funcname) (see -# gitattributes(5)). -(( $+functions[__git_config_name] )) || -__git_config_name () { - local label=names - - declare -a names +(( $+functions[__git_remote_branch_names] )) || +__git_remote_branch_names () { + local expl + declare -a branch_names - if [[ -prefix alias.* ]]; then - _message 'command-alias name' - elif [[ -prefix branch.*.* ]]; then - compset -P 'branch.*.' + branch_names=(${${(f)"$(_call_program remote-branch-refs git for-each-ref --format='"%(refname)"' refs/remotes 2>/dev/null)"}#refs/remotes/}) + __git_command_successful $pipestatus || return - names=( - 'remote:what remote git-fetch should fetch' - 'merge:default refspec to be marked for merging') - elif [[ -prefix branch.* ]]; then - compset -P 'branch.' + _wanted remote-branch-names expl 'remote branch name' compadd $* - $branch_names +} - __git_branch_names -S '.' -r '.' - return - elif [[ -prefix remote.*.* ]]; then - compset -P 'remote.*.' - - names=( - 'url:URL of a remote repository' - 'fetch:default set of refspecs for git-fetch' - 'push:default set of refspecs for git-push' - 'skipDefaultUpdate:whether to skip this remote when running git-remote' - 'receivepack:default program to execute on remote when pushing' - 'uploadpack:default program to execute on remote when fetching' - 'tagopt:options for retrieving remote tags') - elif [[ -prefix remote.* ]]; then - compset -P 'remote.' - - __git_remotes -S '.' -r '.' - return - elif [[ -prefix remotes.* ]]; then - compset -P 'remotes.' +(( $+functions[__git_commits] )) || +__git_commits () { + # TODO: deal with things that __git_heads and __git_tags has in common (i.e., + # if both exists, they need to be completed to heads/x and tags/x. + _alternative \ + 'heads::__git_heads' \ + 'commit-tags::__git_commit_tags' \ + 'commit-objects::__git_commit_objects' +} - __git_remote-groups - return - elif [[ -prefix gitcvs.* ]]; then - names=( - 'enabled:whether the cvs pserver interface is enabled' - 'logfile:name of log file for cvs pserver' - 'allbinary:whether to treat all files from CVS as binary') +(( $+functions[__git_heads] )) || +__git_heads () { + local gitdir expl start + declare -a heads - if [[ -prefix gitcvs.*.* ]]; then - compset -P 'gitcvs.*.' + heads=(${${(f)"$(_call_program headrefs git for-each-ref --format='"%(refname)"' refs/heads refs/remotes 2>/dev/null)"}#refs/(heads|remotes)/}) + gitdir=$(_call_program gitdir git rev-parse --git-dir 2>/dev/null) + if __git_command_successful $pipestatus; then + for f in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do + [[ -f $gitdir/$f ]] && heads+=$f + done + fi - label="gitcvs ${${words[CURRENT]#gitcvs.}%.*}-specific setting" - else - compset -P 'gitcvs.' + _wanted heads expl head compadd $* - $heads +} - label='gitcvs setting' +(( $+functions[__git_commit_objects] )) || +__git_commit_objects () { + _guard '[[:xdigit:]](#c,40)' 'commit object name' +} - names+=( - 'dbname:name of database to use' - 'dbdriver:name of DBI driver to use' - 'dbuser:username to connect to database as' - 'dbpass:password to use when connecting to database') +(( $+functions[__git_blob_objects] )) || +__git_blob_objects () { + _guard '[[:xdigit:]](#c,40)' 'blob object name' +} - declare -a suffixed_names - suffixed_names=( - 'ext:ext-connection-method-specific settings' - 'pserver:pserver-connection-method-specific settings') +(( $+functions[__git_blobs] )) || +__git_blobs () { + _alternative \ + 'blob-tags::__git_blob_tags' \ + 'blob-objects::__git_blob_objects' +} - _describe -t suffixed-names 'gitcvs connection-specific setting' suffixed_names -M 'm:{a-zA-Z}={A-Za-z}' -M 'r:|.=* r:|=*' -S '.' -r '.' && ret=0 - fi - elif [[ -prefix svn-remote.*.* ]]; then - compset -P 'svn.*.' +(( $+functions[__git_blobs_and_trees_in_treeish] )) || +__git_blobs_and_trees_in_treeish () { + compset -P '*:' + [[ -n ${IPREFIX} ]] || return 1 + if [[ -n ${IPREFIX%:} ]]; then + __git_is_treeish ${IPREFIX%:} && __git_tree_files ${PREFIX:-.} ${IPREFIX%:} + else + __git_changed-in-index_files + fi +} - label="git-svn ${${words[CURRENT]#svn.}%.*}-specific setting" +(( $+functions[__git_committishs] )) || +__git_committishs () { + __git_commits +} - names=( - 'noMetadata:disable git-svn-id\: lines at end of commits (fetch, clone, dcommit, set-tree, rebase)' - 'useSvmProps:whether to use remappings of URLs and UUIDs from mirrors (fetch, clone, dcommit, set-tree, rebase)' - 'useSvnsyncProps:similar to useSvmProps, but for the svnsync command (fetch, clone, dcommit, set-tree, rebase)' - 'rewriteRoot:alternate root URL to use') +(( $+functions[__git_revisions] )) || +__git_revisions () { + # TODO: deal with prefixes and suffixes listed in git-rev-parse + __git_commits $* +} - elif [[ -prefix svn-remote.* ]]; then - compset -P 'svn-remote.' +(( $+functions[__git_commits2] )) || +__git_commits2 () { + compset -P '\\\^' + __git_commits +} - __git_svn-remotes -M 'm:{a-zA-Z}={A-Za-z}' -M 'r:|.=* r:|=*' -S '.' -r '.' && ret=0 - return +(( $+functions[__git_commit_ranges] )) || +__git_commit_ranges () { + if compset -P '*..(.|)'; then + __git_commits $* else - names=( - 'core.fileMode:whether differences in the executable bit is relevant' - 'core.autocrlf:what type of conversion of CRLF'\''s git should do' - 'core.symlinks:whether symlinks are treated as special files or not' - 'core.gitProxy:command to execute to establish a connection to remote server' - 'core.ignoreStat:whether modification times of files are ignored' - 'core.preferSymlinkRefs:whether symbolic-reference files should be symlinks' - 'core.bare:whether this repository has a working tree or not' - 'core.logAllRefUpdates:whether to log updates of references' - 'core.repositoryFormatVersion:internal variable determining the repository version' - 'core.sharedRepository:what kind of sharing is done for this repository' - 'core.warnAmbiguousRefs:whether to warn if a ref name is ambiguous' - 'core.compression:level of compression to apply to packs' - 'core.legacyheaders:whether to use the legacy object-header-format' - 'core.packedGitWindowSize:size of mappings of pack files' - 'core.packedGitLimit:maximum number of bytes to map from pack files' - 'core.deltaBaseCacheLimit:maximum size of cache for base objects' - 'apply.whitespace:default value for the --whitespace option to git-apply' - 'color.branch:when to color output of git-branch' - 'color.branch.current:color of the current branch' - 'color.branch.local:color of a local branch' - 'color.branch.remote:color of a remote branch' - 'color.branch.plain:color of other branches' - 'color.diff:when to color diff output' - 'color.diff.plain:color of context text' - 'color.diff.meta:color of metainformation' - 'color.diff.frag:color of hunk headers' - 'color.diff.old:color of removed lines' - 'color.diff.new:color of added lines' - 'color.diff.commit:color of commit headers' - 'color.diff.whitespace:color of dubious whitespace' - 'color.interactive:when to color in interactive mode' - 'color.interactive.header:color of header' - 'color.interactive.help:color of help' - 'color.interactive.prompt:color of prompt' - 'color.pager:whether the pager is fed colored output' - 'color.status:when to color output of git-status' - 'color.status.header:color of header text' - 'color.status.added:color of added, but not yet committed, files' - 'color.status.updated:color of updated, but not yet committed, files' - 'color.status.changed:color of changed, but not yet added in the index, files' - 'color.status.untracked:color of files not currently being tracked' - 'commit.template:template file for commit messages' - 'color.ui:when to color if output is capable; most generic option, overriding by more specific ones' - 'diff.renameLimit:number of files to consider when detecting copy/renames' - 'diff.renames:how hard to try to detect renames' - 'fetch.unpackLimit:maximum number of objects to unpack when fetching' - 'format.headers:additional email headers to include in email patches' - 'format.suffix:default suffix for output files from git-format-patch' - 'gc.packrefs:whether to allow git-gc to run git-pack-refs or not' - 'gc.reflogexpire:default age for "git reflog expire"' - 'gc.reflogexpireunreachable:default age for "git reflog expire" for unreachable' - 'gc.rerereresolved:number of days to keep records of resolved merges' - 'gc.rerereunresolved:number of days to keep records of unresolved merges' - 'http.sslVerify:whether to verify the SSL certificate for HTTPS' - 'http.sslCert:file containing SSL certificates for HTTPS' - 'http.sslKey:file containing the SSL private key for HTTPS' - 'http.sslCAInfo:file containing CA certificates to verify against for HTTPS' - 'http.sslCAPath:path containing files with CA certificates to verify against for HTTPS' - 'http.maxRequests:how many HTTP requests to launch in parallel' - 'http.lowSpeedLimit:lower limit for HTTP transfer-speed' - 'http.lowSpeedTime:duration for http.lowSpeedLimit' - 'http.noEPSV:whether to disable the use of the EPSV ftp-command' - 'i18n.commitEncoding:character encoding commit messages are stored in' - 'i18n.logOutputEncoding:character encoding commit messages are output in' - 'log.showroot:whether to show initial commit as a diff against an empty tree or not' - 'merge.summary:whether to include summaries of merged commits' - 'merge.tool:tool to use for merges (by git-mergetool)' - 'merge.verbosity:amount of output shown by recursive merge strategy' - 'pack.window:size of window used by git-pack-objects' - 'pull.octopus:default merge strategy to use when pulling multiple branches' - 'pull.twohead:default merge strategy to use when pulling a single branch' - 'repack.usedeltabaseoffset:whether to allow git-repack to use delta-base offsets' - 'show.difftree:default git-diff-tree options for git-show' - 'showbranch.default:default set of branches for git-show-branch' - 'tar.umask:umask to apply for git-tar-tree' - 'user.email:email address used for commits' - 'user.name:full name used for commits' - 'user.signingkey:default GPG key to use when creating signed tags' - 'whatchanged.difftree:default git-diff-tree arguments for git-whatchanged' - 'receive.unpackLimit:maximum number of objects to unpack when pushing' - 'receive.denyNonFastforwards:whether git-receive-pack denies ref updates which are not fast-forwards' - 'transfer.unpackLimit:default value for fetch.unpackLimit and receive.unpackLimit' - 'imap.Folder:IMAP folder to use with git-imap-send' - 'imap.Tunnel:tunneling command to use for git-imap-send' - 'imap.Host:host git-imap-send should connect to' - 'imap.User:user git-imap-send should log in as' - 'imap.Pass:password git-imap-send should use when logging in' - 'imap.Port:port git-imap-send should connect on' - 'instaweb.local:whether instaweb should bind to 127.0.0.1' - 'instaweb.httpd:HTTP-daemon command-line to execute for instaweb' - 'instaweb.port:port to bind HTTP daemon to for instaweb' - 'instaweb.browser:web-browser command-line to execute for instaweb' - 'instaweb.modulepath:module path for the Apache HTTP-daemon for instaweb' - 'svn.noMetadata:disable git-svn-id\: lines at end of commits (fetch, clone, dcommit, set-tree, rebase)' - 'svn.useSvmProps:whether to use remappings of URLs and UUIDs from mirrors (fetch, clone, dcommit, set-tree, rebase)' - 'svn.useSvnsyncProps:similar to useSvmProps, but for the svnsync command (fetch, clone, dcommit, set-tree, rebase)' - 'svn.followparent:whether to follow parent commit (fetch, clone, dcommit, set-tree, rebase)' - 'svn.authorsfile:default authors file to use (fetch, clone, dcommit, set-tree, rebase)' - 'svn.username:username to use for SVN transport (fetch, clone, dcommit, set-tree, rebase, init)' - 'svn.configdir:configuration directory to use (fetch, clone, dcommit, set-tree, rebase, init)' - 'svn.noauthcache:undocumented (fetch, clone, dcommit, set-tree, rebase, init)' - 'svn.quiet:make git-svn less verbose (fetch, clone, dcommit, set-tree, rebase)' - 'svn.repack:repack files (for given number of revisions) (fetch, clone, dcommit, set-tree, rebase)' - 'svn.repackflags:flags to pass to git-repack (fetch, clone, dcommit, set-tree, rebase)' - 'svn.logwindowsize:undocumented (fetch, clone, dcommit, set-tree, rebase)' - 'svn.shared:share repository amongst several users (init, clone)' - 'svn.template:directory to use as a template for the object database (init, clone)' - 'svn.trunk:trunk sub-directory to use (init, clone)' - 'svn.tags:tags sub-directory to use (init, clone)' - 'svn.branches:branches sub-directory to use (init, clone)' - 'svn.prefix:prefix to use for names on remotes (init, clone)' - 'svn.rmdir:remove empty directories from SVN tree after commit (dcommit, set-tree, commit-diff)' - 'svn.edit:edit commit message before committing (dcommit, set-tree, commit-diff)' - 'svn.findcopiesharder:try harder to find copies (dcommit, set-tree, commit-diff)' - 'svn.l:limit number of rename/copy targets to run (dcommit, set-tree, commit-diff)' - 'svn.copysimilarity:undocumented (dcommit, set-tree, commit-diff)' - 'svn.revision:only use given revision or revision range (fetch, clone, show-ignore, log, commit-diff)' - 'svn.merge:use merging strategies, if necessary (dcommit, rebase)' - 'svn.fetch-all:undocumented (fetch, dcommit, rebase)' - 'svn.stdin:read list of commits to commit from stdin (set-tree)' - 'svn.strategy:use given merge strategy (dcommit, rebase)' - 'svn.verbose:output extra information (dcommit, log, rebase)' - 'svn.dryrun:output git-commands that would show diffs that would be committed (dcommit)' - 'svn.minimize:undocumented (migrate)' - 'svn.limit:like --max-count, but not counting merged/excluded commits (log)' - 'svn.incremental:give output suitable for concatenation (log)' - 'svn.showcommit:output git commit SHA-1, as well (log)' - 'svn.oneline:similar to --pretty=oneline (log)' - 'svn.color:undocumented (log)' - 'svn.pager:undocumented (log)' - 'svn.nonrecursive:undocumented (log)' - 'svn.local:undocumented (rebase)' - 'svn.message:undocumented (commit-diff)' - 'svn.file:(commit-diff) undocumented') - - declare -a suffixed_names - - suffixed_names=( - 'alias:command aliases' - 'branch:prefix for branch-specific variables' - 'remote:prefix for remote-repository variables' - 'remotes:prefix for remote-groups' - 'gitcvs:prefix for git-cvsserver-specific variables' - 'svn-remote:prefix for git-svn remote-repository variables') - - _describe -t suffixed-names 'special name' suffixed_names -M 'm:{a-zA-Z}={A-Za-z}' -M 'r:|.=* r:|=*' -S '.' -r '.' && ret=0 + __git_commits $* -qS .. fi +} - _describe -t names $label names -M 'm:{a-zA-Z}={A-Za-z}' -M 'r:|.=* r:|=*' && ret=0 +(( $+functions[__git_commit_ranges2] )) || +__git_commit_ranges2 () { + _alternative \ + 'commits::__git_commits2' \ + 'ranges::__git_commit_ranges' } -(( $+functions[__git_config_gettable_name] )) || -__git_config_gettable_name () { - local expl - declare -a names +(( $+functions[__git_trees] )) || +__git_trees () { + __git_objects +} - # TODO: This is strictly not correct, as names can have equal signs in them - # as well. However, there’s no good way to tell from the output of - # git-config, so this’ll have to do until we write our own .git/config - # parser (which will never happen because it’s not worth the trouble). - names=(${${(f)"$(_call_program names git config --list)"}%%\=*}) - __git_command_successful || return +(( $+functions[__git_tree_ishs] )) || +__git_tree_ishs () { + __git_commits +} - _wanted names expl 'names' compadd $names +(( $+functions[__git_objects] )) || +__git_objects () { + compset -P '*:' + if [[ -n $IPREFIX ]]; then + __git_tree_files "$PREFIX" "${IPREFIX%:}" + else + _alternative \ + 'revisions::__git_revisions' \ + 'files::__git_cached_files' + fi } -(( $+functions[__git_config_filtered_gettable_name] )) || -__git_config_filtered_gettable_name () { +(( $+functions[__git_submodules] )) || +__git_submodules () { local expl - declare -a names + declare -a submodules - # TODO: See __git_config_gettable_name for discussion on how to actually get - # out the names, skipping the values. - names=(${${(M)${${(f)"$(_call_program $2 git config --list)"}%%\=*}:#$1.*}#$1.}) - __git_command_successful || return + submodules=(${${(f)"$(_call_program submodules git submodule 2>/dev/null)"}#* }) + __git_command_successful $pipestatus || return - _wanted $2 expl $3 compadd $names + _wanted submodules expl submodule compadd $* - $submodules } -(( $+functions[__git_remote-groups] )) || -__git_remote-groups () { - __git_config_filtered_gettable_name 'remotes' remote-groups 'remote-groups' -} +# Tag Argument Types -(( $+functions[__git_svn-remotes] )) || -__git_svn-remotes () { +(( $+functions[__git_tags] )) || +__git_tags () { local expl - declare -a names + declare -a tags - # TODO: See __git_config_gettable_name for discussion on how to actually get - # out the names, skipping the values. - names=(${${${(M)${${(f)"$(_call_program $2 git config --list)"}%%\=*}:#svn-remote.*}#svn-remote.}%%.*}) - __git_command_successful || return + tags=(${${(f)"$(_call_program tagrefs git for-each-ref --format='"%(refname)"' refs/tags 2>/dev/null)"}#refs/tags/}) + __git_command_successful $pipestatus || return - _wanted svn-remotes expl 'svn remote' compadd $names + _wanted tags expl tag compadd $* - $tags } -# TODO: It’d be really cool if both the default and the current value could be -# shown for all values. -(( $+functions[__git_config_values] )) || -__git_config_values () { - local compadd_opts +(( $+functions[__git_commit_tags] )) || +__git_commit_tags () { + __git_tags_of_type commit $* +} - zparseopts -D -E -a compadd_opts M: J: V: 1 2 n F: X: +(( $+functions[__git_blob_tags] )) || +__git_blob_tags () { + __git_tags_of_type blob $* +} - case $1 in - ((#i)core.fileMode) - declare -a booleans +(( $+functions[__git_tags_of_type] )) || +__git_tags_of_type () { + local type expl + declare -a tags - booleans=( - {true,yes}':track changes to executable bit of files' - {false,no}':ignore changes to executable bit of files') + type=$1; shift - _describe -t boolean 'boolean' booleans - ;; - ((#i)core.autocrlf) - declare -a modes + tags=(${${(M)${(f)"$(_call_program $type-tag-refs "git for-each-ref --format='%(*objecttype)%(objecttype) %(refname)' refs/tags 2>/dev/null")"}:#$type(tag|) *}#$type(tag|) refs/tags/}) + __git_command_successful $pipestatus || return - modes=( - {true,yes}':convert CRLF to LF when reading and LF to CRLF when writing' - {false,no}':leave CRLF at the end of lines in text files as is' - 'input:convert CRLF to LF when reading') + _wanted $type-tags expl "$type tag" compadd $* - $tags +} - _describe -t crlfmode 'crlf mode' modes - ;; - ((#i)core.symlinks) - declare -a booleans +(( $+functions[__git_tag_ids] )) || +__git_tag_ids () { +} - booleans=( - {true,yes}':record symlink files as such' - {false,no}':check out symlinks as plain files that contain the link text') +# Reference Argument Types - _describe -t boolean 'boolean' booleans - ;; - ((#i)core.gitProxy) - _message 'proxy command' - ;; - ((#i)core.ignoreStat) - declare -a booleans +(( $+functions[__git_references] )) || +__git_references () { + local expl - booleans=( - {true,yes}':working-copy files are unchanged until marked as changed' - {false,no}':use lstat() to determine if a file has changed') + # TODO: depending on what options are on the command-line already, complete + # only tags or heads + # TODO: perhaps caching is unnecessary. usually won’t contain that much data + # TODO: perhaps provide alternative here for both heads and tags (and use + # __git_heads and __git_tags) + # TODO: instead of "./.", we should be looking in the repository specified as + # an argument to the command (but default to "./." I suppose (why not "."?)) + # TODO: deal with GIT_DIR + if [[ $_git_refs_cache_pwd != $PWD ]]; then + _git_refs_cache=(${${${(f)"$(_call_program references git ls-remote ./. 2>/dev/null)"}#*$'\t'}#refs/(heads|tags)/}) + __git_command_successful $pipestatus || return + _git_refs_cache_pwd=$PWD + fi - _describe -t boolean 'boolean' booleans - ;; - ((#i)core.preferSymlinkRefs) - declare -a booleans + _wanted references expl 'references' compadd - $_git_refs_cache +} - booleans=( - {true,yes}':use symbolic links for symbolic reference files' - {false,no}':use "symref" files for symbolic reference files') +(( $+functions[__git_local_references] )) || +__git_local_references () { + local expl - _describe -t boolean 'boolean' booleans - ;; - ((#i)core.bare) - declare -a booleans + if [[ $_git_local_refs_cache_pwd != $PWD ]]; then + _git_local_refs_cache=(${${${(f)"$(_call_program references git ls-remote ./. 2>/dev/null)"}#*$'\t'}#refs/}) + __git_command_successful $pipestatus || return + _git_local_refs_cache_pwd=$PWD + fi - booleans=( - {true,yes}':the repository does not have a working directory' - {false,no}':the repository has a working directory') + _wanted references expl 'references' compadd - $_git_local_refs_cache +} - _describe -t boolean 'boolean' booleans - ;; - ((#i)core.logAllRefUpdates) - declare -a booleans +(( $+functions[__git_remote_references] )) || +__git_remote_references () { + __git_references +} - booleans=( - {true,yes}':create ref files for branch heads' - {false,no}':don'\''t automatically create ref files') +(( $+functions[__git_note_references] )) || +__git_local_references () { + local references expl - _describe -t boolean 'boolean' booleans - ;; - ((#i)core.repositoryFormatVersion) - _message 'repository format version string (internal)' - ;; - ((#i)core.sharedRepository) - __git_repository_permissions - ;; - ((#i)core.warnAmbiguousRefs) - declare -a booleans + references=(${${(M)${${(f)"$(_call_program references git ls-remote ./. 2>/dev/null)"}#*$'\t'}:#refs/notes/*}#refs/notes/}) + __git_command_successful $pipestatus || return - booleans=( - {true,yes}':warn if a ref name matches multiple refs' - {false,no}':ignore ambiguous ref names') + _wanted references expl reference compadd - $references +} +(( $+functions[__git_notes_refs] )) || +__git_notes_refs () { + local expl + declare -a notes_refs - _describe -t boolean 'boolean' booleans - ;; - ((#i)core.compression) - declare -a levels - - levels=( - '-1:default level of compression' - '0:do not deflate files' - '1:minimum compression' - '2:a little more compression' - '3:slightly more compression' - '4:a bit more compression' - '5:even more compression' - '6:slightly even more compression' - '7:getting there' - '8:close to maximum compression' - '9:maximum compression') - - _describe -t compression-level 'compression level' levels - ;; - ((#i)core.legacyheaders) - declare -a booleans + notes_refs=(${${(f)"$(_call_program notes-refs git for-each-ref --format='"%(refname)"' refs/notes 2>/dev/null)"}#$type refs/notes/}) + __git_command_successful $pipestatus || return - booleans=( - {true,yes}':use compatiblity format for loose objects' - {false,no}':use new, more efficient, format for loose objects') + _wanted notes-refs expl "notes ref" compadd $* - $notes_refs +} - _describe -t boolean 'boolean' booleans - ;; - ((#i)core.(packedGit(WindowSize|Limit)|deltaBaseCacheLimit)) - _guard '[[:digit:]]#([kmg]|)' 'number of bytes' - ;; - ((#i)alias.*) - _message 'git sub-command with arguments' - ;; - ((#i)apply.whitespace) - __git_apply_whitespace_strategies - ;; - ((#i)branch.*.remote) - __git_remotes - ;; - ((#i)branch.*.merge) - __git_references - ;; - ((#i)color.(branch|diff|pager|status)) - declare -a booleans +# File Argument Types - booleans=( - {always,true}':always output in color' - {never,false}':never output in color' - 'auto:output in color if to a terminal') +(( $+functions[__git_files_relative] )) || +__git_files_relative () { + local files file f_parts prefix p_parts tmp - _describe -t boolean 'boolean' booleans - ;; - ((#i)color.*.*) - compset -P '* ' + prefix=$(_call_program gitprefix git rev-parse --show-prefix 2>/dev/null) + __git_command_successful $pipestatus || return - case ($words[CURRENT]) in - (?*' '?*' '*) - if [[ $words[CURRENT] == *(bold|dim|ul|blink|reverse)* ]]; then - __git_colors - else - __git_color_attributes - fi - ;; - (*) - local suffix q_flag - if [[ $words[CURRENT] == [\"\']* ]]; then - suffix=' ' - q_flag=-q - else - suffix='\ ' - fi + if (( $#prefix == 0 )); then + print $1 + return + fi - if [[ $words[CURRENT] == *(bold|dim|ul|blink|reverse)* ]]; then - __git_colors -S $suffix $q_flag - else - _alternative \ - 'colors:color:__git_colors -S $suffix $q_flag' \ - 'attributes:attribute:__git_color_attributes -S $suffix $q_flag' - fi - ;; - esac - ;; - ((#i)diff.renameLimit) - _guard "[[:digit:]]#" number - ;; - ((#i)diff.renames) - declare -a settings + files=() - settings=( - {true,yes}':enable basic rename detection' - {false,no}':don'\''t try to detect renames' - {copies,copy}':detect file renames and copies') + # Collapse “//†and “/./†into “/â€. Strip any remaining “/.†and “/â€. + for file in ${${${${${(0)1}//\/\///}//\/.\///}%/.}%/}; do + integer i n + (( n = $#file > $#prefix ? $#file : $#prefix )) + for (( i = 1; i <= n; i++ )); do + if [[ $file[i] != $prefix[i] ]]; then + while (( i > 0 )) && [[ $file[i-1] != / ]]; do + (( i-- )) + done + break + fi + done - _describe -t values 'rename-detection setting' settings - ;; - ((#i)(fetch|receive|transfer).unpackLimit) - _guard "[[:digit:]]#" 'maximum number of objects to unpack' - ;; - ((#i)format.headers) - _message 'email header' - ;; - ((#i)format.suffix) - _message 'filename suffix' - ;; - ((#i)gc.packrefs) - declare -a values + files+=${(l@${#prefix[i,-1]//[^\/]}*3@@../@)}${file[i,-1]} + done - values=( - {true,yes}':pack references when collecting garbage' - {false,no}':leave references alone when collecting garbage' - 'notbare:pack references if the repository has a working directory') + print ${(pj:\0:)files} +} - _describe -t values 'value' values - ;; - ((#i)gc.(reflogexpire(unreachable|)|rerere(un|)resolved)) - # TODO: It would be nice if the default value was shown under a separate - # description/tag. - __git_datetimes - ;; - ((#i)gitcvs.(*.|)enabled) - declare -a booleans +(( $+functions[__git_files] )) || +__git_files () { + local compadd_opts opts tag description gitcdup gitprefix files expl - booleans=( - {true,yes}':enable the cvs server interface' - {false,no}':don'\''t enable the cvs server interface') + zparseopts -D -E -a compadd_opts V: J: 1 2 n f X: M: P: S: r: R: q F: + zparseopts -D -E -a opts -- -cached -deleted -modified -others -ignored -unmerged -killed x+: --exclude+: + tag=$1 description=$2; shift 2 - _describe -t booleans 'boolean' booleans - ;; - ((#i)gitcvs.(*.|)logfile) - _files - ;; - ((#i)gitcvs.(*.|)allbinary) - declare -a booleans + gitcdup=$(_call_program gitcdup git rev-parse --show-cdup 2>/dev/null) + __git_command_successful $pipestatus || return - booleans=( - {true,yes}':tell the client to treat all files as binary' - {false,no}':treat files normally') + gitprefix=$(_call_program gitprefix git rev-parse --show-prefix 2>/dev/null) + __git_command_successful $pipestatus || return - _describe -t booleans 'boolean' booleans - ;; - ((#i)gitcvs.dbname) - # TODO: In the future, when computers are self-aware and this won’t - # really matter anymore, one could inspect what gitcvs.dbdriver is set to - # and complete possible databases for that DBI driver. - _message -e 'database name' - ;; - ((#i)gitcvs.dbdriver) - declare -a drivers + # TODO: --directory should probably be added to $opts when --others is given. - # TODO: Would be nice to only include those that are installed, but I - # couldn’t figure out a good way of doing that when I wrote this code. - drivers=( - 'SQLite:use the SQLite database driver (default)' - 'Pg:use the Pg database driver') + local pref=$gitcdup$gitprefix$PREFIX + files=(${(0)"$(_call_program files git ls-files -z --exclude-standard $opts -- ${pref:+$pref\*} 2>/dev/null)"}) + __git_command_successful $pipestatus || return - _describe -t dbi-drivers 'DBI driver' drivers - ;; - ((#i)gitcvs.dbuser) - local expl + _wanted $tag expl $description _multi_parts -f $compadd_opts - / files +} - _description users expl 'database user' - _users $expl - ;; - ((#i)gitcvs.dbpass) - _message -e 'database password' - ;; - ((#i)http.sslVerify) - declare -a booleans +(( $+functions[__git_cached_files] )) || +__git_cached_files () { + __git_files --cached cached-files 'cached file' $* +} - booleans=( - {true,yes}':verify SSL certificates when fetching or pushing over HTTP' - {false,no}':skip verification of SSL certificates') +(( $+functions[__git_deleted_files] )) || +__git_deleted_files () { + __git_files --deleted deleted-files 'deleted file' $* +} - _describe -t booleans 'boolean' booleans - ;; - ((#i)http.sslCert) - local expl +(( $+functions[__git_modified_files] )) || +__git_modified_files () { + __git_files --modified modified-files 'modified file' $* +} - _wanted files expl 'SSL certificate file' _files - ;; - ((#i)http.sslKey) - local expl +(( $+functions[__git_other_files] )) || +__git_other_files () { + __git_files --others untracked-files 'untracked file' $* +} - _wanted files expl 'SSL private-key file' _files - ;; - ((#i)http.sslCAInfo) - local expl +(( $+functions[__git_ignored_cached_files] )) || +__git_ignored_cached_files () { + __git_files --ignored --cached ignored-cached-files 'ignored cached file' $* +} - _wanted files expl 'certificates file' _files - ;; - ((#i)http.sslCAPath) - local expl +(( $+functions[__git_ignored_other_files] )) || +__git_ignored_other_files () { + __git_files --ignored --others ignored-untracked-files 'ignored untracked file' $* +} - _wanted files expl 'CA certificates file' _files - ;; - ((#i)http.maxRequests) - _guard "[[:digit:]]#" 'maximum number of requests' - ;; - ((#i)http.lowSpeedLimit) - # TODO: Need a better description - _guard "[[:digit:]]#([kmg]|)" number - ;; - ((#i)http.lowSpeedTime) - _guard "[[:digit:]]#" seconds - ;; - ((#i)http.noEPSV) - declare -a booleans +(( $+functions[__git_unmerged_files] )) || +__git_unmerged_files () { + __git_files --unmerged unmerged-files 'unmerged file' $* +} - booleans=( - {true,yes}':don'\''t use EPSV mode over FTP (for stupid servers)' - {false,no}':use EPSV mode over FTP') +(( $+functions[__git_killed_files] )) || +__git_killed_files () { + __git_files --killed killed-files 'killed file' $* +} - _describe -t booleans 'boolean' booleans - ;; - ((#i)i18n.(commitEncoding|logOutputEncoding)) - __git_encodings - ;; - ((#i)log.showroot) - declare -a booleans +(( $+functions[__git_changed-in-index_files] )) || +__git_changed-in-index_files () { + local files expl - booleans=( - {true,yes}':show initial commit as a diff against an empty tree' - {false,no}':hide initial commit') + files=$(_call_program files git diff-index -z --name-only --no-color --cached HEAD 2>/dev/null) + __git_command_successful $pipestatus || return + files=(${(0)"$(__git_files_relative $files)"}) + __git_command_successful $pipestatus || return - _describe -t booleans 'boolean' booleans - ;; - ((#i)merge.summary) - declare -a booleans + _wanted changed-in-index-files expl 'changed in index file' _multi_parts $@ - / files +} - # TODO: Use (default) in more descriptions. - booleans=( - {true,yes}':include summaries in merge commit messages' - {false,no}':don'\''t add summaries to merge commit messages (default)') +(( $+functions[__git_changed-in-working-tree_files] )) || +__git_changed-in-working-tree_files () { + local files expl - _describe -t booleans 'boolean' booleans - ;; - ((#i)merge.tool) - declare -a tools + files=$(_call_program changed-in-working-tree-files git diff -z --name-only --no-color 2>/dev/null) + __git_command_successful $pipestatus || return + files=(${(0)"$(__git_files_relative $files)"}) + __git_command_successful $pipestatus || return - tools=(kdiff3 tkdiff meld xxdiff emerge vimdiff) + _wanted changed-in-working-tree-files expl 'changed in working tree file' _multi_parts $@ -f - / files +} - _describe -t merge-tools 'merge tool' tools - ;; - ((#i)merge.verbosity) - declare -a levels +(( $+functions[__git_changed_files] )) || +__git_changed_files () { + _alternative \ + 'changed-in-index-files::__git_changed-in-index_files' \ + 'changed-in-working-tree-files::__git_changed-in-working-tree_files' +} - levels=( - '0:only final error message if conflicts were detected' - '1:conflicts' - '2:conflicts and file changes' - '5:debugging information') +(( $+functions[__git_tree_files] )) || +__git_tree_files () { + local multi_parts_opts + local tree Path + integer at_least_one_tree_added + local -a tree_files compadd_opts - _describe -t verbosity-levels 'verbosity level' levels - ;; - ((#i)pack.window) - _guard '[[:digit:]]#' 'window size' - ;; - ((#i)pull.(octopus|twohead)) - __git_merge_strategies - ;; - ((#i)remote.*.url) - _urls - ;; - ((#i)remote.*.fetch) - : TODO - ;; - ((#i)remote.*.push) - : TODO - ;; - ((#i)remote.*.skipDefaultUpdate) - declare -a booleans + zparseopts -D -E -a compadd_opts V: J: 1 2 n f X: M: P: S: r: R: q F: - booleans=( - {true,yes}':skip this remote by default' - {false,no}':update this remote by default') + [[ "$1" == */ ]] && Path="$1" || Path="${1:h}/" + shift + (( at_least_one_tree_added = 0 )) + for tree in $*; do + tree_files+=(${(ps:\0:)"$(_call_program tree-files git ls-tree --name-only -z $tree $Path 2>/dev/null)"}) + __git_command_successful $pipestatus && (( at_least_one_tree_added = 1 )) + done - _describe -t booleans 'boolean' booleans - ;; - ((#i)remote.*.(receivepack|uploadpack)) - # TODO: Perhaps actually use SSH here? - local expl + if (( !at_least_one_tree_added )); then + return 1 + fi - _wanted files expl "remote git-${${1##*.}%pack}-pack program" _files -g *(*) - ;; - ((#i)remote.*.tagopt) - declare -a opts + local expl + _wanted files expl 'tree file' _multi_parts -f $compadd_opts -- / tree_files +} - opts=( - '--no-tags:don'\''t fetch tags automatically' - '"":fetch tags as usual') +# Repository Argument Types - _describe -t tag-options 'tag retrieval' opts - ;; - ((#i)remotes.*) - compset -P '* ' +# _remote_files +_remote_files () { + # FIXME: these should be imported from _ssh + # TODO: this should take -/ to only get directories + # There should be coloring based on all the different ls -F classifiers. + local expl rempat remfiles remdispf remdispd args suf ret=1 - local suffix - if [[ $words[CURRENT] == [\"\']* ]]; then - suffix=' ' - else - suffix='\ ' - fi + if zstyle -T ":completion:${curcontext}:files" remote-access; then + zparseopts -D -E -a args p: 1 2 4 6 F: + if [[ -z $QIPREFIX ]] + then rempat="${PREFIX%%[^./][^/]#}\*" + else rempat="${(q)PREFIX%%[^./][^/]#}\*" + fi + remfiles=(${(M)${(f)"$(_call_program files ssh $args -a -x ${IPREFIX%:} ls -d1FL "$rempat" 2>/dev/null)"}%%[^/]#(|/)}) + compset -P '*/' + compset -S '/*' || suf='remote file' - # TODO: Should really only complete unique remotes, that is, not the same - # remote more than once in the list. - __git_remotes -S $suffix -q - ;; - ((#i)repack.usedeltabaseoffset) - declare -a booleans + remdispd=(${(M)remfiles:#*/}) - booleas=( - {true,yes}':allow creation of delta-base-offset packs' - {false,no}':don'\''t create delta-base-offset packs') + _tags files + while _tags; do + while _next_label files expl ${suf:-remote directory}; do + compadd ${suf:+-S/} "$@" "$expl[@]" -d remdispd \ + ${(q)remdispd%/} && ret=0 + done + (( ret )) || return 0 + done + return ret + else + _message -e remote-files 'remote file' + fi +} - _describe -t booleans 'boolean' booleans - ;; - ((#i)show.difftree) - # TODO: This should complete the options available to these two commands. - _message 'default options to git-diff-tree and git-show' - ;; - ((#i)showbranch.default) - __git_branch_names - ;; - ((#i)tar.umask) - _alternative \ - 'number: :_guard "[0-7]#" "numeric mode"' \ - 'values:special value:((user:"use user'\''s current umask"))' - ;; - ((#i)user.email) - _email_addresses - ;; - ((#i)user.name) - _users - ;; - ((#i)user.signingkey) - __git_gpg_secret_keys - ;; - ((#i)whatchanged.difftree) - # TODO: This should complete the options available to git-diff-tree. - _message 'default options to git-diff-tree when invoking git-whatchanged' - ;; - ((#i)receive.denyNonFastForwards) - declare -a booleans +(( $+functions[__git_remote_repositories] )) || +__git_remote_repositories () { + local service - booleans=( - {true,yes}':git-receive-pack will deny a ref update that isn'\''t a fast forward' - {false,no}':allow a ref update that isn'\''t a fast forward') + service= _ssh - _describe -t booleans 'boolean' booleans - ;; - ((#i)imap.folder) - _mailboxes - ;; - ((#i)imap.tunnel) - _message -e commands 'imap tunneling command' - ;; - ((#i)imap.host) - _hosts - ;; - ((#i)imap.user) - # TODO: If imap.host is set, complete users on that system? - _users - ;; - ((#i)imap.pass) - _message -e passwords 'imap password' - ;; - ((#i)imap.port) - _ports - ;; - ((#i)instaweb.local) - declare -a booleans + if compset -P '*:'; then + _remote_files + else + _ssh_hosts -S: + fi +} - booleans=( - {true,yes}':bind the HTTP daemon to 127.0.0.1' - {false,no}':don'\''t bind the HTTP daemon to a specific address') +(( $+functions[__git_repositories] )) || +__git_repositories () { + _alternative \ + 'local-repositories::__git_local_repositories' \ + 'remote-repositories::__git_remote_repositories' +} - _describe -t booleans 'boolean' booleans - ;; - ((#i)instaweb.httpd) - _message -e command-lines 'HTTP-daemon command-line' - ;; - ((#i)instaweb.port) - _ports - ;; - ((#i)instaweb.browser) - _message -e command-lines 'web-browser command-line' - ;; - ((#i)instaweb.modulepath) - local expl +(( $+functions[__git_local_repositories] )) || +__git_local_repositories () { + local expl - _description directories expl 'module path' - _directories $expl - ;; - ((#i)(svn.|svn-remote.*.)noMetaData) - declare -a booleans + _wanted local-repositories expl 'local repositories' _directories +} - booleans=( - {true,yes}':disable git-svn-id: lines at end of commits' - {false,no}':add git-svn-id: lines at end of commits') +(( $+functions[__git_any_repositories] )) || +__git_any_repositories () { + # TODO: should also be $GIT_DIR/remotes/origin + _alternative \ + 'local-repositories::__git_local_repositories' \ + 'remotes: :__git_remotes' \ + 'remote-repositories::__git_remote_repositories' +} - _describe -t booleans 'boolean' booleans - ;; - ((#i)(svn.|svn-remote.*.)(useSvmProps|useSvnsyncProps)) - declare -a booleans +# Common Guards + +(( $+functions[__git_guard] )) || +__git_guard () { + declare -A opts - booleans=( - {true,yes}':remap URLs and UUIDs for mirrors' - {false,no}':don'\''t remap URLs and UUIDs for mirrors') + zparseopts -K -D -A opts M: J: V: 1 2 n F: X: - _describe -t booleans 'boolean' booleans - ;; - ((#i)svn.followparent) - __git_boolean_settings true 'follow parent commit' - ;; - ((#i)svn.authorsfile) - local expl + [[ "$PREFIX$SUFFIX" != $~1 ]] && return 1 - _description files expl 'authors-conversion file' - _files $expl - ;; - ((#i)svn.username) - _users - ;; - ((#i)svn.configdir) - _directories - ;; - ((#i)svn.noauthcache) - # TODO: Update description once this gets documented. - __git_boolean_settings false 'use auth cache' - ;; - ((#i)svn.quiet) - __git_boolean_settings false 'make git-svn less verbose' 'let git-svn produce verbose output' - ;; - ((#i)svn.repack) - _guard '[[:digit:]]#' 'revision limit' - ;; - ((#i)svn.repackflags) - # TODO: Should complete git-repack arguments - _message -e 'git-repack flags' - ;; - ((#i)svn.logwindowsize) - # TODO: Update description once this gets documented. - _guard '[[:digit:]]#' 'log-window size' - ;; - ((#i)svn.shared) - __git_repository_permissions - ;; - ((#i)svn.template) - # NOTE: This is of course ridiculous, as this can never be useful. Only - # here for completeness. - _directories - ;; - ((#i)svn.(trunk|tags|branches)) - _alternative \ - 'sub-directories:sub-directory:_directories' \ - 'urls: :_urls' && ret=0 - ;; - ((#i)svn.prefix) - _message -e 'prefix' - ;; - ((#i)svn.rmdir) - __git_boolean_settings false 'remove empty directories from SVN tree after commit' 'leave empty directories from SVN tree after commit' - ;; - ((#i)svn.edit) - __git_boolean_settings false 'edit commit message before committing' 'use commit message from SVN' - ;; - ((#i)svn.findcopiesharder) - __git_boolean_settings false 'try harder to find copies' 'use simple copy-finding algorithm' - ;; - ((#i)svn.l) - _guard "[[:digit:]]#" number - ;; - ((#i)svn.copysimilarity) - __git_boolean_settings false 'undocumented' - ;; - ((#i)svn.revision) - __git_svn_revisions - ;; - ((#i)svn.merge) - __git_boolean_settings false 'use merging strategies' 'don'\''t try to merge' - ;; - ((#i)svn.fetch-all) - __git_boolean_settings false 'undocumented' - ;; - ((#i)svn.stdin) - __git_boolean_settings false 'read list of commits to commit from stdin' 'don'\''t necessarily read list of commits to commit from stdin' - ;; - ((#i)svn.strategy) - __git_merge_strategies - ;; - ((#i)svn.verbose) - __git_boolean_settings false 'output extra information' - ;; - ((#i)svn.dryrun) - __git_boolean_settings false 'output git-commands that would show diffs that would be committed' 'actually run the git commands' - ;; - ((#i)svn.minimize) - __git_boolean_settings false 'undocumented' - ;; - ((#i)svn.limit) - _guard "[[:digit:]]#" limit - ;; - ((#i)svn.incremental) - __git_boolean_settings false 'give output suitable for concatenation' - ;; - ((#i)svn.showcommit) - __git_boolean_settings false 'output git commit SHA-1, as well' 'don'\''t output git commit SHA-1' - ;; - ((#i)svn.online) - __git_boolean_settings false 'produce output similar to --pretty=oneline' - ;; - ((#i)svn.color) - __git_boolean_settings false 'undocumented' - ;; - ((#i)svn.pager) - _message -e 'undocumented' - ;; - ((#i)svn.nonrecursive) - __git_boolean_settings false 'undocumented' - ;; - ((#i)svn.local) - __git_boolean_settings false 'undocumented' - ;; - ((#i)svn.message) - _message -e 'undocumented' - ;; - ((#i)svn.file) - _message -e 'undocumented' - ;; - ((#i)svn-remote.*.rewriteRoot) - _message -e 'new root' - ;; - (*) - _message 'value' - ;; - esac -} + if (( $+opts[-X] )); then + _message -r $opts[-X] + else + _message -e $2 + fi -# __git_boolean_settings [-t TAG] [-l LABEL] DEFAULT 'follow parent commit' ['follow HEAD commit'] -# -# -t can be used to specify a tag to use (default: booleans). -# -l can be used to specify a label to use (default: 'boolean'). -# -# The first argument is the default value, so that the description of the -# default value can be suffixed with " (default)". The second argument -# is the description for the true value. If a third argument is given, -# it is used as the description for the false value. If it is not given, -# the description will be the true value's description with the prefix -# "don't ". -(( $+functions[__git_boolean_settings] )) || -__git_boolean_settings () { - local tag label garbage + [[ -n "$PREFIX$SUFFIX" ]] +} - zparseopts -D -E -a garba S: M: J: V: 1 2 n F: X: -t=tag -l=label +__git_guard_branch-name () { + if [[ -n $PREFIX$SUFFIX ]]; then + _call_program check-ref-format git check-ref-format "refs/heads/$PREFIX$SUFFIX" &>/dev/null + (( ${#pipestatus:#0} > 0 )) && return 1 + fi - declare -A descriptions + _message -e 'branch name' - descriptions=(true $2 false 'don'\''t '"$2") + [[ -n $PREFIX$SUFFIX ]] +} - if (( $# > 2 )); then - descriptions[false]=$3 +__git_guard_diff-stat-width () { + if [[ $PREFIX == *,* ]]; then + compset -P '*,' + __git_guard_number "filename width" + else + compset -S ',*' + __git_guard_number width fi +} - descriptions[$1]+=" (default)" +(( $+functions[__git_guard_number] )) || +__git_guard_number () { + declare -A opts - declare -a booleans + zparseopts -K -D -A opts M: J: V: 1 2 n F: X: - booleans=( - {true,yes}':'$descriptions[true] - {false,no}':'$descriptions[false]) + _guard "[[:digit:]]#" ${1:-number} +} - _describe -t ${tag:-booleans} ${label:-boolean} booleans +(( $+functions[__git_guard_bytes] )) || +__git_guard_bytes () { + _guard '[[:digit:]]#([kKmMgG]|)' $* } -# TODO: Use this function in other places. -(( $+functions[__git_colors] )) || -__git_colors () { - declare -a colors +(( $+functions[__git_datetimes] )) || +__git_datetimes () { + # TODO: Use this in more places. + _guard "*" 'time specification' +} - colors=(black red green yellow blue magenta cyan white) +(( $+functions[__git_stages] )) || +__git_stages () { + __git_guard $* "[[:digit:]]#" 'stage' +} + +(( $+functions[__git_svn_revision_numbers] )) || +__git_svn_revision_numbers () { + __git_guard_number "revision number" +} + +# _arguments Helpers + +(( $+functions[__git_setup_log_options] )) || +__git_setup_log_options () { + # TODO: Need to implement -<n> for limiting the number of commits to show. + log_options=( + '(- *)-h[display help]' + '( --no-decorate)--decorate=-[print out ref names of any commits that are shown]: :__git_log_decorate_formats' + '(--decorate )--no-decorate[do not print out ref names of any commits that are shown]' + '--source[show which ref each commit is reached from]') +} + +(( $+functions[__git_setup_diff_options] )) || +__git_setup_diff_options () { + local diff_types='(-p -u --patch -U --unified --raw --patch-with-raw --stat --numstat --shortstat --dirstat --dirstat-by-file --summary --patch-with-stat --name-only --name-status --cumulative)' + + diff_options=( + $diff_types{-p,-u,--patch}'[generate diff in patch format]' + $diff_types{-U,--unified=}'[generate diff with given lines of context]: :__git_guard_number lines' + $diff_types'--raw[generate default raw diff output]' + $diff_types'--patch-with-raw[generate patch but also keep the default raw diff output]' + '--patience[generate diffs with patience algorithm]' + $diff_types'--stat=-[generate diffstat instead of patch]:: :__git_guard_diff-stat-width' + $diff_types'--numstat[generate more machine-friendly diffstat]' + $diff_types'--shortstat[generate summary diffstat]' + $diff_types'--dirstat=-[generate dirstat by amount of changes]:: :__git_guard_number limit' + $diff_types'--dirstat-by-file=-[generate dirstat by number of files]:: :__git_guard_number limit' + $diff_types'--summary[generate condensed summary of extended header information]' + $diff_types'--patch-with-stat[generate patch and prepend its diffstat]' + '-z[use NUL termination on output]' + $diff_types'--name-only[show only names of changed files]' + $diff_types'--name-status[show only names and status of changed files]' + '--submodule=-[select output format for submodule differences]::format:((short\:"show pairs of commit names" + log\:"list commits like git submodule does (default)"))' + '( --no-color --color-words)--color=-[show colored diff]:: :__git_color_whens' + '(--color --color-words)--no-color[turn off colored diff]' + '--word-diff=-[show word diff]::mode:((color\:"highlight changed words using color" + plain\:"wrap deletions and insertions with markers" + porcelain\:"use special line-based format for scripts" + none\:"disable word diff"))' + '--word-diff-regex=-[specify what constitutes a word]:word regex' + '(--color --no-color )--color-words=-[show colored-word diff]::word regex' + '--no-renames[turn off rename detection]' + '--check[warn if changes introduce trailing whitespace or space/tab indents]' + '--full-index[show full object name of pre- and post-image blob]' + '(--full-index)--binary[in addition to --full-index, output binary diffs for git-apply]' + '--abbrev=[set minimum SHA1 display-length]: :__git_guard_number length' + # TODO: --break-rewrites is undocumented. + '(-B --break-rewrites)'{-B-,--break-rewrites=-}'[break complete rewrite changes into pairs of given size]:: :__git_guard_number size' + # TODO: --detect-renames is undocumented. + '(-M --detect-renames)'{-M-,--detect-renames=-}'[detect renames with given scope]:: :__git_guard_number size' + # TODO: --detect-copies is undocumented. + '(-C --detect-copies)'{-C-,--detect-copies=-}'[detect copies as well as renames with given scope]:: :__git_guard_number size' + '--find-copies-harder[try harder to find copies]' + '-l-[limit number of rename/copy targets to run]: :__git_guard_number' + '--diff-filter=-[select certain kinds of files for diff]: :_guard "[ACDMRTUXB*]#" kinds' + '-S-[look for differences that contain the given string]:string' + '--pickaxe-all[when -S finds a change, show all changes in that changeset]' + '--pickaxe-regex[treat argument of -S as regular expression]' + '-O-[output patch in the order of glob-pattern lines in given file]: :_files' + '-R[do a reverse diff]' + '--relative=-[exclude changes outside and output relative to given directory]:: :_directories' + '(-a --text)'{-a,--text}'[treat all files as text]' + '--ignore-space-at-eol[ignore changes in whitespace at end of line]' + '(-b --ignore-space-change -w --ignore-all-space)'{-b,--ignore-space-change}'[ignore changes in amount of white space]' + '(-b --ignore-space-change -w --ignore-all-space)'{-w,--ignore-all-space}'[ignore white space when comparing lines]' + '--inter-hunk-context=[combine hunks closer than n lines]:n' + '--exit-code[report exit code 1 if differences, 0 otherwise]' + '(--exit-code)--quiet[disable all output]' + '( --no-ext-diff)--ext-diff[allow external diff helper to be executed]' + '(--ext-diff )--no-ext-diff[disallow external diff helper to be executed]' + '--ignore-submodules[ignore changes to submodules]:: :__git_ignore_submodules_whens' + '(--no-prefix)--src-prefix=[use given prefix for source]:prefix' + '(--no-prefix)--dst-prefix=[use given prefix for destination]:prefix' + '(--src-prefix --dst-prefix)--no-prefix[do not show any source or destination prefix]' + + '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)'{-1,--base}'[diff against "base" version]' + '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)'{-2,--ours}'[diff against "our branch" version]' + '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)'{-3,--theirs}'[diff against "their branch" version]' + '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)-0[omit diff output for unmerged entries]' + '(-0 -1 -2 -3 --base --ours --theirs -c --cc --no-index)'{-c,--cc}'[compare "our branch", "their branch" and working tree files]' + '-q[remain silent even on nonexisting files]' + + # TODO: --cumulative is undocumented. + '--cumulative[undocumented]' + # TODO: --follow is undocumented. + '--follow[undocumented]' + # TODO: --textconv is undocumented. + '--textconv[undocumented]' + # TODO: --no-textconv is undocumented. + '--no-textconv[undocumented]' + # TODO: -G is undocumented. + '-G[undocumented]' + # TODO: --output is undocumented. + '--output[undocumented]:undocumented') +} + +(( $+functions[__git_setup_revision_options] )) || +__git_setup_revision_options () { + local -a diff_options + __git_setup_diff_options + + revision_options=( + $diff_options + # TODO: format pretty print format is a lot more advanced than this. + # TODO: You can’t actually specify --format without a format. + '(-v --header)'{--pretty=-,--format=-}'[pretty print commit messages]::format:((oneline\:"commit-ids and subject of messages" + short\:"few headers and only subject of messages" + medium\:"most parts of messages" + full\:"all parts of commit messages" + fuller\:"like full and includes dates" + email\:"use email headers like From and Subject" + raw\:"the raw commits" + format\:"specify own format"))' + '--abbrev-commit[show only partial prefixes of commit object names]' + '--oneline[shorthand for --pretty=oneline --abbrev-commit]' + '--encoding=-[output log messages in given encoding]:: :__git_encodings' + '(--no-notes --show-notes --standard-notes --no-standard-notes)--no-notes[do not show notes that annotate commit]' + '(--no-notes --show-notes --standard-notes --no-standard-notes)--show-notes[do not show notes that annotate commit]:: :__git_note_references' + '(--no-notes --show-notes --standard-notes --no-standard-notes)--no-standard-notes[enable populating notes ref list from core.notesRef and notes.displayRef]' + '(--no-notes --show-notes --standard-notes --no-standard-notes)--no-standard-notes[disable populating notes ref list from core.notesRef and notes.displayRef]' + '( --date)--relative-date[show dates relative to current time]' + '(--relative-date )--date=-[format of date output]: :__git_date_formats' + '--parents[display parents of commit]' + '--children[display children of commit]' + '--left-right[mark which side of symmetric diff commit is reachable from]' + '--graph[display graphical representation of commit history]' + '--count[display how many commits would have been listed]' + '(-n --max-count)'{-n+,--max-count=}'[maximum number of commits to display]: :__git_guard_number' + '--skip=[skip given number of commits before output]: :__git_guard_number' + '(--max-age --since --after)'{--since=,--after=}'[show commits more recent than given date]:date' + '(--min-age --until --before)'{--until=,--before=}'[show commits older than given date]: :__git_guard_number timestamp' + '( --since --after)--max-age=-[maximum age of commits to output]: :__git_guard_number timestamp' + '( --until --before)--min-age[minimum age of commits to output]: :__git_guard_number timestamp' + '*--author=[limit commits to those by given author]:author' + '*--committer=[limit commits to those by given committer]:committer' + '*--grep=[limit commits to those with log messages matching the given pattern]:pattern' + '--all-match[limit commits to ones matching all --grep, --author, and --committer]' + '(-i --regexp-ignore-case)'{-i,--regexp-ignore-case}'[match regexps ignoring case]' + '(-E --extended-regexp)'{-E,--extended-regexp}'[use POSIX extended regexps]' + '(-F --fixed-strings)'{-F,--fixed-strings}'[do not interpret patterns as regexps]' + '--remove-empty[stop when given path disappears from tree]' + '--merges[display only merge commits]' + '--no-merges[do not display commits with more than one parent]' + '--first-parent[follow only first parent from merge commits]' + '*--not[reverses meaning of ^ prefix for revisions that follow]' + '--all[show all commits from refs]' + '--branches=-[show all commits from refs/heads]::pattern' + '--tags=[-show all commits from refs/tags]::pattern' + '--remotes=[-show all commits from refs/remotes]::pattern' + '--glob=[show all commits from refs matching glob]:pattern' + '--stdin[read commit objects from standard input]' + '--cherry-pick[omit any same-change commits]' + '(-g --walk-reflogs --reverse)'{-g,--walk-reflogs}'[walk reflog entries from most recent to oldest]' + '--merge[after a failed merge, show refs that touch files having a conflict]' + '--boundary[output uninteresting commits at boundary]' + '--simplify-by-decoration[show only commits that are referenced by a ref]' + '( --dense --sparse --simplify-merges --ancestry-path)--full-history[do not prune history]' + '(--full-history --sparse --simplify-merges --ancestry-path)--dense[only display selected commits, plus meaningful history]' + '(--full-history --dense --simplify-merges --ancestry-path)--sparse[when paths are given, display only commits that changes any of them]' + '(--full-history --dense --sparse --ancestry-path)--simplify-merges[milder version of --full-history]' + '(--full-history --dense --sparse --simplify-merges )--ancestry-path[only display commits that exists directly on ancestry chains]' + '( --date-order)--topo-order[display commits in topological order]' + '(--topo-order )--date-order[display commits in date order]' + '(-g --walk-reflogs)--reverse[display commits in reverse order]' + '( --objects-edge)--objects[display object ids of objects referenced by listed commits]' + '(--objects )--objects-edge[display object ids of objects referenced by listed and excluded commits]' + '( --do-walk)--no-walk[only display given revs, do not traverse their ancestors]' + '(--no-walk )--do-walk[only display given revs, traversing their ancestors]' + + # TODO: --reflog is undocumented. + '--reflog[show all commits from reflogs]' + # TODO: --default is undocumented. + '--default[use argument as default revision]:default revision:__git_revisions' + # TODO: --full-diff is undocumented. + '(-c --cc )--full-diff[undocumented]' + # TODO: --abrev is undocumented. + '--abbrev=[set minimum SHA1 display-length]: :__git_guard_number length' + # TODO: --no-abbrev is undocumented. + '--no-abbrev[undocumented]' + # TODO: --early-output is undocumented. + '--early-output=-[undocumented]::undocumented' + # TODO: --log-size is undocumented. + '--log-size[undocumented]') - _describe -t colors 'color' colors $* + if (( words[(I)--objects(|-edge)] )); then + revision_options+=('--unpacked[print object IDs not in packs]') + fi } -# TODO: Use this function in other places. -(( $+functions[__git_color_attributes] )) || -__git_color_attributes () { - declare -a attributes +(( $+functions[__git_setup_merge_options] )) || +__git_setup_merge_options () { + merge_options=( + '( --no-commit)--commit[perform the merge and commit the result]' + '(--commit )--no-commit[perform the merge but do not commit the result]' + '( --no-ff)--ff[do not generate a merge commit if the merge resolved as a fast-forward]' + '(--ff )--no-ff[generate a merge commit even if the merge resolved as a fast-forward]' + '( --no-log)--log[fill in one-line descriptions of the commits being merged in the log message]' + '(--log )--no-log[do not list one-line descriptions of the commits being merged in the log message]' + '(-n --no-stat)--stat[show a diffstat at the end of the merge]' + '(--stat -n --no-stat)'{-n,--no-stat}'[do not show diffstat at the end of the merge]' + '( --no-squash)--squash[merge, but do not commit]' + '(--squash )--no-squash[merge and commit]' + '*'{-s,--strategy=}'[use given merge strategy]:merge strategy:__git_merge_strategies' + '*'{-X,--strategy-option=}'[pass merge-strategy-specific option to merge strategy]' + '(-q --quiet -v --verbose)'{-q,--quiet}'[suppress all output]' + '(-q --quiet -v --verbose)'{-v,--verbose}'[output additional information]') +} + +(( $+functions[__git_setup_fetch_options] )) || +__git_setup_fetch_options () { + fetch_options=( + '(: *)--all[fetch all remotes]' + '(-a --append)'{-a,--append}'[append ref names and object names of fetched refs to "$GIT_DIR/FETCH_HEAD"]' + '--depth=[deepen the history of a shallow repository by the given number of commits]: :__git_guard_number depth' + '--dry-run[show what would be done, without making any changes]' + '(-f --force)'{-f,--force}'[allow refs that are not ancestors to be updated]' + '(-k --keep)'{-k,--keep}'[keep downloaded pack]' + '(-p --prune)'{-p,--prune}'[remove any remote tracking branches that no longer exist remotely]' + '(-n --no-tags -t --tags)'{-n,--no-tags}'[disable automatic tag following]' + '(--no-tags -t --tags)'{-t,--tags}'[fetch remote tags]' + '(-u --update-head-ok)'{-u,--update-head-ok}'[allow updates of current branch head]' + '--upload-pack=[specify path to git-upload-pack on remote side]:remote path' + '(-q --quiet -v --verbose --progress)'{-q,--quiet}'[suppress all output]' + '(-q --quiet -v --verbose)'{-v,--verbose}'[output additional information]' + '(-q --quiet)--progress[output progress information]') +} + +(( $+functions[__git_setup_apply_options] )) || +__git_setup_apply_options () { + apply_options=( + '--whitespace=[detect a new or modified line that ends with trailing whitespaces]: :__git_apply_whitespace_strategies' + '-p-[remove N leading slashes from traditional diff paths]: :_guard "[[\:digit\:]]#" "number of slashes to remove"' + '-C-[ensure at least N lines of context match before and after each change]: :_guard "[[\:digit\:]]#" "number of lines of context"' + '--reject[apply hunks that apply and leave rejected hunks in .rej files]' + '(--ignore-space-change --ignore-whitespace)'{--ignore-space-change,--ignore-whitespace}'[ignore changes in whitespace in context lines]' + '--directory=[root to prepend to all filenames]:root:_directories') +} + +# Git Config Helpers + +(( $+functions[__git_config_get_regexp] )) || +__git_config_get_regexp () { + declare -A opts - attributes=(bold dim ul blink reverse) + zparseopts -A opts -D b: a: + [[ -n $opts[-b] ]] || opts[-b]='*.' + [[ -n $opts[-a] ]] || opts[-a]='.[^.]##' + [[ $1 == -- ]] && shift - _describe -t attributes 'attribute' attributes $* + set -A $2 ${${${(0)"$(_call_program ${3:-$2} "git config -z --get-regexp -- '$1'")"}#${~opts[-b]}}%%${~opts[-a]}$'\n'*} } -(( $+functions[__git_config_section_names] )) || -__git_config_section_names () { - # TODO: Come up with a good way of extracting this information. - _guard "?#" "section name" +(( $+functions[__git_config_sections] )) || +__git_config_sections () { + declare -a opts + local regex tag desc + local -a groups + + zparseopts -a opts -D b: a: + regex=$1 + tag=$2 + desc=$3 + shift 3 + + __git_config_get_regexp $opts -- $regex groups $tag + # TODO: Should escape : with \: in groups. + _describe -t $tag $desc groups $* } -(( $+functions[__git_archive_formats] )) || -__git_archive_formats () { - local expl - declare -a formats +# __git_config_booleans [-t TAG] [-l LABEL] CURRENT DEFAULT DESCRIPTION [OTHER]... +# +# -t can be used to specify a tag to use (default: booleans). +# -l can be used to specify a label to use (default: boolean). +# +# The first argument is the current value, so that the description of the +# current value can be suffixed with “ (current)â€. +# +# The second argument is the default value, so that the description of the +# default value can be suffixed with “ (default)â€. +# +# The third argument is the description to use for the true and false values. +# +# The rest of the arguments can be used to provide additional “boolean†values +# that should be included. They should be of the form that _describe expects. +(( $+functions[__git_config_booleans] )) || +__git_config_booleans () { + local tag label current default description + declare -a booleans - formats=(${${(f)"$(_call_program archive-formats git archive --list)"}}) - __git_command_successful || return + zparseopts -D t=tag l=label + current=$1 + default=${2:-true} + description=$3 + shift 3 + booleans=( + {true,yes,on}":$description" + {false,no,off}":do not $description" + $*) - _wanted archive-formats expl 'archive format' compadd $formats + __git_config_values -t ${tag:-booleans} -l ${label:-boolean} -- "$current" $default $booleans } -(( $+functions[__git_gpg_secret_keys] )) || -__git_gpg_secret_keys () { - local expl +# __git_config_values [-t TAG] [-l LABEL] CURRENT DEFAULT [VALUES]... +# +# -t can be used to specify a tag to use (default: values). +# -l can be used to specify a label to use (default: value). +# +# The first argument is the current value, so that the description of the +# current value can be suffixed with “ (current)â€. +# +# The second argument is the default value, so that the description of the +# default value can be suffixed with “ (default)â€. +# +# The rest of the arguments are values of the form VALUE:DESCRIPTION to be +# passed to _describe. +(( $+functions[__git_config_values] )) || +__git_config_values () { + declare -A opts + local current default key + declare -a values - _wanted secret-keys expl 'secret key' compadd \ - ${${(Mo)$(_call_program secret-keys gpg --list-secret-keys 2>/dev/null):%<*>}//(<|>)/} + zparseopts -A opts -D t: l: + [[ $1 == -- ]] && shift + current=$1 + default=$2 + shift 2 + values=($*) + [[ -n $current ]] && values[(r)$(__git_pattern_escape $default):*]+=' (current)' + values[(r)$(__git_pattern_escape $default):*]+=' (default)' + + _describe -t ${opts[-t]:-values} ${opts[-l]:-value} values } -(( $+functions[__git_merge_strategies] )) || -__git_merge_strategies () { +# Git Config Sections and Types +(( $+functions[__git_browsers] )) || +__git_browsers () { + integer ret=1 local expl - local -a merge_strategies - - if ! merge_strategies=(${=${${(M)${(f)"$(_call_program strategies git merge -s '' 2>&1)"}:#[Aa]vailable (custom )#strategies are: *}#[Aa]vailable (custom )#strategies are: }%.}); then - merge_strategies=(${=${${(M)${(f)"$(<$(git --exec-path)/git-merge)"}:#all_strategies*}##all_strategies=\'}%%\'}) - fi + declare -a userbrowsers builtinbrowsers + + __git_config_get_regexp '^browser\..+\.cmd$' userbrowsers + builtinbrowsers=( + firefox + iceweasel + konquerer + w3m + links + lynx + dillo + open + start) + + _tags user-browsers builtin-browsers + + while _tags; do + _requested user-browsers expl 'user-defined browser' compadd $* - $userbrowsers && ret=0 + _requested builtin-browsers expl 'builtin browser' compadd $* - $builtinbrowsers && ret=0 + + (( ret )) || break + done - _wanted merge-strategies expl 'merge strategy' compadd -a merge_strategies "$@" + return ret } -# TODO: Use this in more places. -(( $+functions[__git_datetimes] )) || -__git_datetimes () { - _guard "*" 'time specification' +(( $+functions[__git_difftools] )) || +__git_difftools () { + __git_diff-or-merge-tools diff $* } -# TODO: Use this in more places. -# TODO: Use better algorithm, as shown in iconv completer (separate it to a new -# Type). -(( $+functions[__git_encodings] )) || -__git_encodings () { +(( $+functions[__git_diff-or-merge-tools] )) || +__git_diff-or-merge-tools () { + local type=$1; shift + integer ret=1 local expl - _wanted encodings expl 'encoding' compadd "$@" \ - -M 'm:{a-zA-Z}={A-Za-z} r:|-=* r:|=*' \ - ${${${(f)"$(_call_program encodings iconv --list)"}## #}%//} -} + declare -a userdifftools usermergetools builtintools builtindifftools builtinmergetools + + [[ $type == diff ]] && __git_config_get_regexp '^difftool\..+\.cmd$' userdifftools + __git_config_get_regexp '^mergetool\..+\.cmd$' usermergetools + builtintools=( + kdiff3 + tkdiff + xxdiff + meld + opendiff + vimdiff + gvimdiff + vimdiff2 + gvimdiff2 + emerge + ecmerge + diffuse + araxis + p4merge) + + builtindifftools=($builtintools kompare) + builtinmergetools=($builtintools tortoisemerge) + + case $type in + (diff) _tags user-difftools builtin-difftools user-mergetools ;; + (merge) _tags user-mergetools builtin-mergetools ;; + esac -(( $+functions[__git_repository_permissions] )) || -__git_repository_permissions () { - declare -a permissions + while _tags; do + _requested user-difftools expl 'user-defined difftool' compadd $* - $userdifftools && ret=0 + _requested user-mergetools expl 'user-defined mergetool' compadd $* - $usermergetools && ret=0 + _requested builtin-difftools expl 'builtin difftool' compadd $* - $builtindifftools && ret=0 + _requested builtin-mergetools expl 'builtin mergetool' compadd $* - $builtinmergetools && ret=0 - permissions=( - {group,true,yes}':files and objects are group-writable' - {all,world,everybody}':files and objects are readable by all users and group-shareable' - {umask,false}':use permissions reported by umask()') + (( ret )) || break + done - _describe -t permissions 'permission' permissions + return ret } -(( $+functions[__git_apply_whitespace_strategies] )) || -__git_apply_whitespace_strategies () { - declare -a strategies +(( $+functions[__git_mergetools] )) || +__git_mergetools () { + __git_diff-or-merge-tools merge $* +} - strategies=( - 'nowarn:turn off the trailing-whitespace warning' - 'warn:output trailing-whitespace warning, but apply patch' - 'error:output trailing-whitespace warning and refuse to apply patch' - 'error-all:same as "error", but output warnings for all files' - 'strip:output trailing-whitespace warning and strip trailing whitespace') +(( $+functions[__git_merge_drivers] )) || +__git_merge_drivers () { + __git_config_sections '^merge\..+\.name$' merge-drivers 'merge driver' $* +} - _describe -t strategies 'trailing-whitespace resolution strategy' strategies +(( $+functions[__git_builtin_merge_drivers] )) || +__git_builtin_merge_drivers () { + local -a builtin_merge_drivers + builtin_merge_drivers=( + text:'normal 3-way file-level merge for text files' + binary:'binary file merge driver' + union:'run 3-way file-levele merge with lines from both versions') + _describe -t builtin-merge-drivers 'builtin merge driver' builtin_merge_drivers $* } -(( $+functions[__git_svn_revisions] )) || -__git_svn_revisions () { - if [[ -prefix *: ]]; then - compset -P '*:' +(( $+functions[__git_man_viewers] )) || +__git_man_viewers () { + # TODO: Add support for standard commands. + __git_config_sections '^man\..+\.cmd$' man-viewers 'man viewer' $* +} - _alternative \ - 'revision-numbers: :__git_svn_revision_numbers' \ - 'symbolic-revisions:symbolic revision:((HEAD\:"the topmost revision of the SVN repository"))' - else - _alternative \ - 'revision-numbers: :__git_svn_revision_numbers' \ - 'symbolic-revisions:symbolic revision:__git_svn_base_revisions' - fi +(( $+functions[__git_svn-remotes] )) || +__git_svn-remotes () { + __git_config_sections -a '(|)' '^svn-remote\..+$' svn-remotes 'svn remote' $* } -(( $+functions[__git_svn_revision_numbers] )) || -__git_svn_revision_numbers () { - _guard "[[:digit:]]#" "revision number" +(( $+functions[__git_remote-groups] )) || +__git_remote-groups () { + __git_config_sections -a '(|)' '^remotes\..+$' remotes-groups 'remotes group' $* } -(( $+functions[__git_svn_base_revisions] )) || -__git_svn_base_revisions () { - declare -a revisions +(( $+functions[__git_remotes_groups] )) || +__git_remotes_groups () { + local expl - revisions=( - 'BASE:the bottommost revision of the SVN repository') + _wanted remotes-groups expl 'remotes group' \ + compadd $* - ${${${(0)"$(_call_program remotes-groups git config --get-regexp -z '"^remotes\..*$"')"}%%$'\n'*}#remotes.} - # TODO: How do we deal with $*? - _describe -t symbolic-revisions 'symbolic revision' revisions -S ':' -r ': ' } -# TODO: numparent is undocumented. -(( $+functions[__git_ref_sort_keys] )) || -__git_ref_sort_keys () { - compset -P '-' +(( $+functions[__git_sendemail_identities] )) || +__git_sendemail_identities () { + __git_config_sections '^sendemail\..+\.[^.]+$' identities 'sendemail identity' $* +} - local -a keys +(( $+functions[__git_sendemail_smtpencryption_values] )) || +__git_sendemail_smtpencryption_values () { + __git_config_values -- "$current" "$parts[5]" \ + ssl:'use SSL' \ + tls:'use TLS' +} - keys=( - 'refname:the name of the ref' - 'objecttype:the type of the object' - 'objectsize:the size of the object' - 'objectname:the object name (SHA-1)' - 'tree:the tree header-field' - 'parent:the parent header-field' - 'numparent:undocumented' - 'object:the object header-field' - 'type:the type header-field' - 'tag:the tag header-field' - 'author:the author header-field' - 'authorname:the name component of the author header-field' - 'authoremail:the email component of the author header-field' - 'authordate:the date component of the author header-field' - 'committername:the name component of the committer header-field' - 'committeremail:the email component of the committer header-field' - 'committerdate:the date component of the committer header-field' - 'taggername:the name component of the tagger header-field' - 'taggeremail:the email component of the tagger header-field' - 'taggerdate:the date component of the tagger header-field' - 'creatorname:the name component of the creator header-field' - 'creatordate:the date component of the creator header-field' - 'subject:the subject of the message' - 'body:the body of the message' - 'body:the contents of the message (subject and body)') +(( $+functions[__git_sendemail_confirm_values] )) || +__git_sendemail_confirm_values () { + __git_config_values -- "$current" "$parts[5]" \ + always:'always confirm before sending' \ + never:'never confirm before sending' \ + cc:'confirm before sending to automatically added Cc-addresses' \ + compose:'confirm before sending first message when using --compose' \ + auto:'same as cc together with compose' +} - _describe -t sort-keys 'sort key' keys +(( $+functions[__git_sendemail_suppresscc_values] )) || +__git_sendemail_suppresscc_values () { + __git_config_values -- "$current" "$parts[5]" \ + author:'avoid including patch author' \ + self:'avoid including sender' \ + cc:'avoid including anyone mentioned in Cc lines except for self' \ + bodycc:'avoid including anyone mentiond in Cc lines in patch body except for self' \ + sob:'avoid including anyone mentiond in Signed-off-by lines except for self' \ + cccmd:'avoid running --cc-cmd' \ + body:'equivalent to sob + bodycc' \ + all:'avoid all auto Cc values' } -(( $+functions[__git_daemon_service] )) || -__git_daemon_service () { - local -a services +(( $+functions[__git_colors] )) || +__git_colors () { + declare -a colors - services=( - 'upload-pack:serve git-fetch-pack and git-peek-remote clients' - 'upload-archive:serve git-archive --remote clients') + colors=(black red green yellow blue magenta cyan white) - _describe -t services 'service' services + _describe -t colors color colors $* } -(( $+functions[__git_attributes] )) || -__git_attributes () { - local -a attributes - - attributes=( - 'crlf:line-ending convention' - 'ident:ident substitution' - 'filter:filters' - 'diff:textual diff' - 'merge:merging strategy') +(( $+functions[__git_color_attributes] )) || +__git_color_attributes () { + declare -a attributes - _describe -t attributes 'attribute' attributes -} - -# --- - -# TODO: How do we do -/n/ here? -# --reflog undocumented -# -m undocumented -# -v undocumented -# --root undocumented -# --no-commit-id undocumented -# --always undocumented -# --abbrev undocumented -# --abbrev-commit undocumented -# --full-diff undocumented -# --full-history undocumented -# --all-match undocumented -# optional argument to --unpacked undocumented -(( $+functions[__git_setup_revision_arguments] )) || -__git_setup_revision_arguments () { - revision_arguments=( - '(-n --max-count -)'{-n+,--max-count=-}'[maximum number of commits to output]: :_guard "[[\:digit\:]]#" number' - '--skip=-[skip given number of commits before output]: :_guard "[[\:digit\:]]#" number' - '( --since --after)--max-age=-[maximum age of commits to output]: :_guard "[[\:digit\:]]#" timestamp' - '(--max-age --since --after)'{--since=-,--after=-}'[show commits more recent than given date]:date' - '( --until --before)--min-age[minimum age of commits to output]: :_guard "[[\:digit\:]]#" timestamp' - '(--min-age --until --before)'{--until=-,--before=-}'[show commits older than given date]: :_guard "[[\:digit\:]]#" timestamp' - '--all[show all commits from refs]' - '--branches[show all commits from refs/heads]' - '--tags[show all commits from refs/tags]' - '--remotes[show all commits from refs/remotes]' - '--cherry-pick[omit any same-change commits]' - '--graph[draw a graphical representation of the commit history]' - '--reflog[show all commits from reflogs]' - '(-g --walk-reflogs --reverse)'{-g,--walk-reflogs}'[walk reflog entries from most recent to oldest]' - '*--not[reverses meaning of ^ prefix for revisions that follow]' - '--default[use argument as default revision]:default revision:__git_revisions' - '--merge[after a failed merge, show refs that touch files having a conflict]' - '( --date-order)--topo-order[show commits in topological order]' - '(--topo-order )--date-order[show commits in date order]' - '(-g --walk-reflogs)--reverse[show commits in reverse order]' - '--parents[show parent commits]' - '( --sparse)--dense[this is the inverse of --sparse, and is also the default]' - '(--dense )--sparse[when paths are given, output only commits that changes any of them]' - '--remove-empty[stop when a given path disappears from the tree]' - '--no-merges[do not print commits with more than one parent]' - '--first-parent[follow only the first parent from merge commits]' - '--boundary[output uninteresting commits at the boundary]' - '--left-right[mark which side of a symmetric diff a commit is reachable from]' - '( --objects-edge)--objects[show object ids of objects referenced by the listed commits]' - '(--objects )--objects-edge[show object ids of objects referenced by the listed and excluded commits]' - '( -t)-r[show recursive diffs]' - '(-r )-t[show the tree objects in the diff output]' - '-m[do not ignore merges]' - '( --cc --full-diff)-c[show merge diffs from parents simultaneously]' - '(-c --full-diff)--cc[show merge diffs from parents simultaneously without one-parent diffs]' - '(-c --cc )--full-diff[undocumented]' - '( --pretty --header)-v[show verbose header]' - '(-v --header)'$pretty_arg - '--root[show root diff]' - '--no-commit-id[do not show commit ids]' - '--always[always show header]' - $abbrev_arg - '--abbrev-commit[undocumented]' - '--simplify-merges[milder version of --full-history]' - '--full-history[undocumented]' - '--simplify-by-decoration[show only commits that are referenced by a ref]' - '--relative-date[show dates relative to the current time]' - '--date=-[format of date output]:date format:((relative\:"show dates relative to the current time" - local\:"show timestamps in user'\''s local timezone" - iso\:"show timestamps in ISO 8601 format" - rfc\:"show timestamps in RFC 2822 format" - short\:"show only date but not time" - default\:"show timestamp in the original timezone"))' - '--author=-[limit commits to those by the given author]:author' - '--committer=-[limit commits to those by the given committer]:committer' - '--grep=-[limit commits to those with log messages matching the given pattern]:pattern' - '--all-match[undocumented]' - '--encoding=-[output log messages in given encoding]::encoding:__git_encodings' - $diff_args) + attributes=(bold dim ul blink reverse) - if (( words[(I)--objects(|-edge)] )); then - revision_arguments+=('--unpacked=-[print object IDs that are not in packs]::object') - fi + _describe -t attributes attribute attributes $* } -# --- - -(( $+functions[__git_is_type] )) || -__git_is_type () { - local sha1 - sha1="$(git rev-parse $2 2> /dev/null)" && - [[ "$(git cat-file -t "${sha1}^{$1}" 2> /dev/null)" == $1 ]] +(( $+functions[_gitk] )) || +_gitk () { + _git-log } -(( $+functions[__git_is_committish] )) || -__git_is_committish () { - __git_is_type commit $1 +(( $+functions[_tig] )) || +_tig () { + _git-log } -(( $+functions[__git_is_treeish] )) || -__git_is_treeish () { - __git_is_type tree $1 -} +# Now, for the main driver… +_git() { + if (( CURRENT > 2 )); then + local -a aliases + local -A git_aliases + # TODO: Should use -z here, but I couldn’t get it to work. + aliases=(${(f)${${${(f)"$(_call_program aliases git config --get-regexp '\^alias\.')"}#alias.}/ /$'\n'}/(#e)/$'\n'}) + (( $#aliases % 2 == 0 )) && git_aliases=($aliases) + + if [[ -n ${git_aliases[$words[2]]} ]] ; then + local -a tmpwords expalias + expalias=(${(z)git_aliases[$words[2]]}) + tmpwords=(${words[1]} ${expalias}) + if [[ -n "${words[3,-1]}" ]] ; then + tmpwords+=(${words[3,-1]}) + fi + [[ -n ${words[$CURRENT]} ]] || tmpwords+=('') + (( CURRENT += ${#expalias} - 1 )) + words=("${tmpwords[@]}") + unset tmpwords expalias + fi -(( $+functions[__git_is_indexed] )) || -__git_is_indexed () { - [[ -n $(git ls-files $REPLY) ]] -} + unset git_aliases aliases + fi -local curcontext=$curcontext ret=1 + local ret=1 + if [[ $service == git ]]; then + local curcontext=$curcontext state line + declare -A opt_args -# fun with $words[] and $CURRENT to enable completion for args -# to git aliases (eg. git co <TAB>) -local -A git_aliases -local -a git_aliases__ -git_aliases__=(${(f)${${${(f)"$(_call_program alias_expansion git config --get-regexp '\^alias\.')"}#alias.}/ /$'\n'}/(#e)/$'\n'}) -if (( ( ${#git_aliases__} % 2 ) == 0 )) ; then - git_aliases=(${git_aliases__}) -fi -unset git_aliases__ + # TODO: This needs an update + # TODO: How do we fix -c argument? + _arguments -C \ + '(- :)--version[display version information]' \ + '(- :)--help[display help message]' \ + '-c[pass configuration parameter to command]:parameter' \ + '--exec-path=-[path containing core git-programs]:: :_directories' \ + '--html-path[display path to HTML documentation and exit]' \ + '(-p --paginate)'{-p,--paginate}'[pipe output into $PAGER]' \ + '--no-pager[do not pipe git output into a pager]' \ + '--git-dir=-[path to repository]: :_directories' \ + '--work-tree=-[path to working tree]: :_directories' \ + '--bare[use $PWD as repository]' \ + '--no-replace-objects[do not use replacement refs to replace git objects]' \ + '(-): :->command' \ + '(-)*:: :->option-or-argument' && return + case $state in + (command) + __git_aliases_and_commands && ret=0 + ;; + (option-or-argument) + curcontext=${curcontext%:*:*}:git-$words[1]: -if (( CURRENT >= 3 )) && [[ -n ${git_aliases[$words[2]]} ]] ; then - local -a tmpwords expalias - expalias=(${(z)git_aliases[$words[2]]}) - tmpwords=(${words[1]} ${expalias}) - if [[ -n "${words[3,-1]}" ]] ; then - tmpwords+=(${words[3,-1]}) + _call_function ret _git-$words[1] + ;; + esac + else + _call_function ret _$service fi - [[ -n ${words[$CURRENT]} ]] || tmpwords+=('') - (( CURRENT += ${#expalias} - 1 )) - words=("${tmpwords[@]}") - unset tmpwords expalias -fi - -if [[ $service == git ]]; then - local state line - declare -A opt_args - _arguments -C \ - '(- :)--version[display version information]' \ - '(- :)--help[display help message]' \ - '--exec-path=-[path containing core git-programs]::directory:_directories' \ - '(-p --paginate)'{-p,--paginate}'[pipe output into $PAGER]' \ - '--no-pager[do not pipe git output into a pager]' \ - '--git-dir=-[path to repository]:directory:_directories' \ - '--work-tree=-[path to working tree]:directory:_directories' \ - '--bare[use $PWD as repository]' \ - '*::arg:->cmd_or_options' && return - case $state in - (cmd_or_options) - if (( CURRENT == 1 )); then - __git_aliases_and_commands - else - curcontext="${curcontext%:*:*}:git-$words[1]:" - if (( $+functions[_git-$words[1]] )); then - _call_function ret _git-$words[1] - else - _files - fi - return ret - fi - ;; - esac -else - _call_function ret _$service return ret -fi } _git diff --git a/Completion/Unix/Command/_gnutls b/Completion/Unix/Command/_gnutls index 64f8e3cf5..169e38b38 100644 --- a/Completion/Unix/Command/_gnutls +++ b/Completion/Unix/Command/_gnutls @@ -8,7 +8,7 @@ local _gnutls_cli_common_args _gnutls_cli_common_args=( '(-d --debug)'{-d,--debug}':debug level' '(-p --port)'{-p,--port}':port' - '(-h --help)'{-h,--help}'[help]' \ + '(-h --help)'{-h,--help}'[help]' ) case "$service" in diff --git a/Completion/Unix/Command/_go b/Completion/Unix/Command/_go new file mode 100644 index 000000000..30a2bf88f --- /dev/null +++ b/Completion/Unix/Command/_go @@ -0,0 +1,18 @@ +#compdef gccgo gofmt 5l 6l 8l 5g 6g 8g + +# This is for the computer language go, +# http://golang.org. + +local expl pat + +case $service in + (<->l) + pat="*.${service[1,-2]}" + ;; + + (*) + pat="*.go" + ;; +esac + +_wanted files expl "input file" _files -g "$pat" diff --git a/Completion/Unix/Command/_gpg b/Completion/Unix/Command/_gpg index 3f86411f6..6f2fd4834 100644 --- a/Completion/Unix/Command/_gpg +++ b/Completion/Unix/Command/_gpg @@ -22,7 +22,7 @@ gpgbasic=('(-e --encrypt)'{-e,--encrypt}'[encrypt data. this option may be combi '(-c --symmetric)'{-c,--symmetric}'[encrypt with symmetric cypher only]' '(-s --sign)'{-s,--sign}'[make a signature]' '*'{-r+,--recipient}'[specify user to encrypt for]:recipient:->public-keys' - '(-u --local-user)'{-u+,--local-user}'[use name as the user ID to sign]:user attachment:_users'\ + '(-u --local-user)'{-u+,--local-user}'[use name as the user ID to sign]:user attachment:_users' '(-o --output)'{-o+,--output}'[write output to file]:output file:_files' '(-h --help)'{-h,--help}'[display usage information]' '--version[print info on program version and supported algorithms]') @@ -44,7 +44,7 @@ gpgextra=('--decrypt-files[decrypt multiple files]' '--list-packets[list only the sequence of packets]' '--gen-key[generate a new pair key]' '--edit-key[a menu for edit yours keys]:key attachment:->public-keys' - '--sign-key[sign a key]:key attachment:->public-keys'\ + '--sign-key[sign a key]:key attachment:->public-keys' '--lsign-key[sign a key but mark as non-exportable]:key attachment:->public-keys' '--nrsign-key[sign a key non-revocably]' '--delete-key[remove key from public keyring]:key attachment:->public-keys' @@ -193,15 +193,15 @@ gpgextra=('--decrypt-files[decrypt multiple files]' case "$service" in gpg) - _arguments -C -s -S -A "-*" $gpgbasic $gpgextra $gpgv '*:args:->args' + _arguments -C -s -S -A "-*" $gpgbasic $gpgextra $gpgv '*:args:->args' && ret=0 ;; gpgv) - _arguments -C -s -S -A "-*" $gpgv '*:args:->args' + _arguments -C -s -S -A "-*" $gpgv '*:args:->args' && ret=0 ;; gpg-zip) - _arguments -C -s -S -A "-*" $gpgbasic $gpgzip '*:args:->args' + _arguments -C -s -S -A "-*" $gpgbasic $gpgzip '*:args:->args' && ret=0 ;; esac diff --git a/Completion/Unix/Command/_growisofs b/Completion/Unix/Command/_growisofs index 09a04c6e4..dcccf64a4 100644 --- a/Completion/Unix/Command/_growisofs +++ b/Completion/Unix/Command/_growisofs @@ -75,13 +75,13 @@ find_expressions=( '*-size[true if the size of the file is in the given range]:range' '*-sparse[true if the file appears to be sparse]' '*-true[always true]' - '*-type[true if the file is of the given type]:file type:((b\:"block (buffered) special" \ - c\:"character (unbuffered) special" \ - d\:directory \ - p\:"named pipe (FIFO)" \ - f\:"regular file" \ - l\:"symbolic link" \ - s\:socket \ + '*-type[true if the file is of the given type]:file type:((b\:"block (buffered) special" + c\:"character (unbuffered) special" + d\:directory + p\:"named pipe (FIFO)" + f\:"regular file" + l\:"symbolic link" + s\:socket D\:"door (Solaris)" e\:unknown))' '*-user[true if the file is owned by the given user]:user:_users' diff --git a/Completion/Unix/Command/_initctl b/Completion/Unix/Command/_initctl new file mode 100644 index 000000000..11bd59b50 --- /dev/null +++ b/Completion/Unix/Command/_initctl @@ -0,0 +1,184 @@ +#compdef initctl start stop restart reload status +# Written by Bernhard Tittelbach +# based on completion script by Mildred + +typeset -g -a -U _initctl_events_list _initctl_eventargs_list + +# run show-config -e and if possible parse out all events and KEY= argumnts +# otherwise provide some common values +_initctl_fillarray_events_args () +{ + setopt extendedglob + local showconfig="$(initctl show-config -e 2>| /dev/null)" + if [[ -n "$showconfig" ]]; then + _initctl_events_list=() + _initctl_eventargs_list=() + for cline in "${(f)showconfig}"; do + if [[ "$cline" == (#s)\ \ (stop\ on|start\ on|emit)\ (#b)([[:alpha:]-_]##)(*)(#e) ]]; then + _initctl_events_list+=($match[1]) + # this is a bit tricky, we take the string right of the matched event + # and parse for \sUPPERCASE=\S (in perl-re syntax) substrings until there are no more matches + # since we can't do multiple matches, we concatenated the remaing strings and try again + local stml="$match[2]" + while [[ "$stml" == (#b)(*)\ ([[:upper:]_]##\=)[^[:space:]](#b)(*) ]]; do + _initctl_eventargs_list+=($match[2]) + stml="$match[1] $match[3]" + done + unset stml + fi + done + else + _initctl_events_list=( socket login-session-start desktop-session-start virtual-filesystems local-filesystems remote-filesystems all-swaps filesystem mounting mounted net-device-up start-portmap runlevel unmounted-remote-filesystems ) + _initctl_eventargs_list=( PRIMARY_DEVICE_FOR_DISPLAY= EXIT_STATUS= EXIT_SIGNAL= RUNLEVEL= MOUNTPOINT= TYPE= INTERFACE= ) + fi + return 0 +} + +# list all upstart jobs, i.e. all files in /etc/init/ +_initctl_helper_jobs() +{ + _path_files -W "/etc/init/" -g "*.conf(.:r)" +} + +# list events, generate array if necessary +_initctl_known_events() +{ + [[ ${#_initctl_events_list} -eq 0 ]] && _initctl_fillarray_events_args + _values "Event" "$_initctl_events_list[@]" +} + +# list events, allow multiple choices, generate array if necessary +_initctl_multiple_known_events() +{ + [[ ${#_initctl_events_list} -eq 0 ]] && _initctl_fillarray_events_args + _values -s "," "Events" "$_initctl_events_list[@]" +} + +# list KEY= arguments, generate array if necessary +_initctl_known_eventargs() +{ + [[ ${#_initctl_eventargs_list} -eq 0 ]] && _initctl_fillarray_events_args + _values "Argument Keys" "$_initctl_eventargs_list[@]" +} + +# describe and offer commands for initctl, then call matching completion function +_initctl_command() +{ + local cmds + cmds=( + start:"Start jobs" + stop:"Stop jobs" + restart:"Restart jobs" + reload:"Send SIGHUP to process instance" + status:"Query status of jobs" + list:"List known jobs" + emit:"Emit an event" + reload-configuration:"tell init to reload config files (generally inotify is used)" + version:"Request the version of the init daemon" + log-priority:"Change the minimum priority of log messages from the init daemon" + show-config:"Show start/stop/emit for processes" + check-config:"Find jobs than can't be started" + help:"display list of commands" + ) + + if (( CURRENT == 1 )); then + _describe -t command "initctl Commands" cmds + fi + + local cmd=$words[1] + + local curcontext="${curcontext%:*}:initctl-${cmd}" + _call_function ret _initctl_${cmd_completion_funcs[${cmd}]-${cmd_completion_default}} +} + +# completion for start/stop/restart/reload i.e. anything that take one job and multiple KEY= arguments's +_initctl_startstop() +{ + _arguments \ + '--no-wait[do not wait for operation to complete before exiting]' \ + "${common_args[@]}" \ + ':Upstart Jobs:_initctl_helper_jobs' \ + '*::Argument Keys:_initctl_known_eventargs' +} + +# completion for anything that takes one job +_initctl_argjob() +{ + _arguments \ + "${common_args[@]}" \ + ':Upstart Jobs:_initctl_helper_jobs' \ + '*::' +} + +# completion for emit, providing options, one event and multiple KEY= arguments's +_initctl_emit() +{ + _arguments \ + '--no-wait[do not wait for event to finish before exiting]' \ + "${common_args[@]}" \ + ':Events:_initctl_known_events' \ + '*::Argument Keys:_initctl_known_eventargs' +} + +# the fallback, just the options +_initctl_basic() +{ + _arguments \ + "${common_args[@]}" +} + +# completion for show-config, additional option and one job +_initctl_show-config() +{ + _arguments \ + "(-e --enumerate)"{-e,--enumerate}"[enumerate emit lines]" \ + "${common_args[@]}" \ + '::Upstart Jobs:_initctl_helper_jobs' \ + '*::' +} + +# completion for show-config, additional options and one job +_initctl_check-config() +{ + _arguments \ + "(-i --ignore-events)"{-i,--ignore-events}"[list of comma-separated events to ignore]:Events:_initctl_multiple_known_events" \ + "(-w --warn)"{-w,--warn}"[treat any unknown jobs or events as error]" \ + "${common_args[@]}" \ + '::Upstart Jobs:_initctl_helper_jobs' \ + '*::' +} + +# after defining above functions, overwrite _initctl function so helper-functions are loaded only once +_initctl() +{ + local -a common_args + common_args=( + '--session[use D-Bus session bus to connect to init daemon (for testing)]' + '--system[talk via DBUS system bus instead of socket]' + '(-q --quiet)'{-q,--quiet}'[reduce output to errors only]' + '(-v --verbose)'{-v,--verbose}'[increase output to include informational messages]' + '--dest=[D-Bus name for init, defaults to com.ubuntu.Upstart]' + '--help[display help and exit]' + '--version[output version information and exit]' + ) + + # map each initctl function to a completion function + local -A cmd_completion_funcs + cmd_completion_funcs=( start startstop stop startstop restart startstop reload startstop show-config show-config status argjob emit emit check-config check-config ) + + # define fallback completion function + local cmd_completion_default=basic + + # depending on which command was used, call different completion funtions + case $service in + initctl) + _arguments "${common_args[@]}" '*::Initctl Commands:_initctl_command' + ;; + start|stop|restart|reload|status) + _call_function ret _initctl_${cmd_completion_funcs[${service}]-${cmd_completion_default}} + ;; + *) return 1 ;; + esac +} + +_initctl "$@" diff --git a/Completion/Unix/Command/_lp b/Completion/Unix/Command/_lp index ab0d53821..5d46a75bb 100644 --- a/Completion/Unix/Command/_lp +++ b/Completion/Unix/Command/_lp @@ -1,52 +1,227 @@ -#compdef lp lpr lpq lprm +#compdef lp lpr lpq lprm lpoptions lpstat -local expl ret=1 printer list disp strs shown +_lp_get_printer() +{ + # No reason to call _lp_get_printer when service == lpstat. Others matched + # below. + case $service in + (lpr|lpq|lprm) + [[ "$words" == (#I)*-P* ]] && printer="${${words##*(#I)-P( |)}%% *}" + ;; + (lp) + [[ "$words" == (#I)*-d* ]] && printer="${${words##*(#I)-d( |)}%% *}" + ;; + (lpoptions) + [[ "$words" == (#I)*-(d|p)* ]] && \ + printer="${${words##*(#I)-(d|p)( |)}%% *}" + ;; + esac +} -if compset -P '-[dP]' || [[ "$words[CURRENT-1]" = -[dP] ]]; then - _printers -else - if [[ "$service" = (lpq|lprm) ]]; then - if [[ "$words" = *-P* ]]; then - printer=(-P "${${words##*-P( |)}%% *}") - else - printer=() - fi - list=( ${(M)"${(f@)$(_call_program jobs lpq $printer 2> /dev/null)}":#[0-9]*} ) - - if (( $#list )); then - _tags users jobs - - while _tags; do - if _requested users; then - strs=( "${(@)${(@)list##[^ ]##[ ]##[^ ]##[ ]##}%%[ ]*}" ) - if [[ -z "$shown" ]] && - zstyle -T ":completion:${curcontext}:users" verbose; then - disp=(-ld list) - shown=yes - else - disp=() - fi - _all_labels users expl user compadd "$disp[@]" -a strs || - _users && ret=0 - fi - if _requested jobs; then - strs=( "${(@)${(@)list##[^ ]##[ ]##[^ ]##[ ]##[^ ]##[ ]##}%%[ ]*}" ) - if [[ -z "$shown" ]] && - zstyle -T ":completion:${curcontext}:jobs" verbose; then - disp=(-ld list) - shown=yes - else - disp=() - fi - _all_labels jobs expl job compadd "$disp[@]" -a strs && ret=0 - fi - (( ret )) || return 0 - done +_lp_job_options() +{ + local expl printer + local -a lopts_with_args lopts_no_args + + # Generic options (from lp manual page) + lopts_with_args=( media orientation-requested sides number-up scaling cpi lpi + page-{bottom,left,right,top} ) + + lopts_no_args=(fitplot landscape) + + _lp_get_printer + [[ -n "$printer" ]] && printer=(-p $printer) + + # The program specified by the style list-printer-options should list jobs in + # the same style as lpoptions -l. + if compset -P '*='; then + # List values for the option + case ${IPREFIX%=} in + (media) + compadd "$@" a4 letter legal + ;; + (orientation-requested) + compadd "$@" 4 + ;; + (sides) + compadd "$@" one-sided two-sided-{long,short}-edge + ;; + (number-up) + _description -V option-o-1 expl "pages per sheet" + compadd "$expl[@]" 2 4 6 9 16 + ;; + (scaling|cpi|lpi|page-(bottom|left|right|top)) + return 0; # Don't complete anything + ;; + (*) + compadd "$@" \ + $(_call_program list-printer-options lpoptions $printer -l | \ + grep "^${IPREFIX%=}" | cut -d: -f2 | tr -d \* ) + ;; + esac + else + # List options + local eq_suffix + + # Don't add an '=' suffix when completing lpoptions -r + if [[ $service == lpoptions && $words[CURRENT-1] == "-r" ]]; then + eq_suffix=() else - _message 'no print jobs' + eq_suffix=(-S '=') fi - return 1 + + _description lpopts expl "generic printer options" + compadd "$expl[@]" $eq_suffix $lopts_with_args + compadd "$expl[@]" $lopts_no_args + + _description printeropts expl "printer specific options" + compadd "$expl[@]" $eq_suffix \ + $(_call_program list-printer-options \ + lpoptions $printer -l | cut -d/ -f1) + fi +} + +_lp_list_jobs() +{ + local ret=1 printer shown + local -a list disp strs + + _lp_get_printer + [[ -n "$printer" ]] && printer=(-P $printer) + + list=( ${(M)"${(f@)$(_call_program jobs lpq $printer 2> /dev/null)}":#[0-9]*} ) + + if (( $#list )); then + _tags users jobs + + while _tags; do + if _requested users; then + strs=( "${(@)${(@)list##[^ ]##[ ]##[^ ]##[ ]##}%%[ ]*}" ) + if [[ -z "$shown" ]] && + zstyle -T ":completion:${curcontext}:users" verbose; + then + disp=(-ld list) + shown=yes + else + disp=() + fi + _all_labels users expl user compadd "$disp[@]" -a strs || + _users && ret=0 + fi + if _requested jobs; then + strs=( "${(@)${(@)list##[^ ]##[ ]##[^ ]##[ ]##[^ ]##[ ]##}%%[ ]*}" ) + if [[ -z "$shown" ]] && + zstyle -T ":completion:${curcontext}:jobs" verbose; then + disp=(-ld list) + shown=yes + else + disp=() + fi + _all_labels jobs expl job compadd "$disp[@]" -a strs && ret=0 + fi + (( ret )) || return 0 + done else - _pspdf + _message 'no print jobs' fi -fi + return 1 +} + + +_lp() +{ + case $service in + (lpq) + _arguments \ + '-E[Force encryption]' \ + '-U:username (for connection to server):_users' \ + '-h:alternate server:_hosts' \ + '(-a)-P+[destination printer]:printers:_printers' \ + '(-P)-a[all printers]' \ + '-l[long listing]' \ + '*:poll interval (+seconds):' + ;; + + (lprm) + _arguments \ + '-E[Force encryption]' \ + '-U:username (for connection to server):_users' \ + '-h:alternate server:_hosts' \ + '-P+[destination printer]:printers:_printers' \ + '*:job ids:_lp_list_jobs' + ;; + + (lpoptions) + _arguments \ + '-E[Force encryption]' \ + '-U:username (for connection to server):_users' \ + '-h:alternate server:_hosts' \ + '(-p -l -r -x)-d[set default printer]:printers:_printers' \ + '(-l -x)*-o:job options:_lp_job_options' \ + '(-d -x)-p[destination printer for options]:printers:_printers' \ + '(-d -o -r -x)-l[list options]' \ + '(-d -l -x)*-r:remove option:_lp_job_options' \ + '(-d -l -r -o)-x[remove all options]:printers:_printers' + ;; + + (lpstat) + _arguments \ + '-E[Force encryption]' \ + '-R[Shows print job ranking]' \ + '-U:username (for connection to server):_users' \ + '-W:which jobs:(completed not-completed)' \ + '-a[Show accepting state]:printers:_printers' \ + '-c:printer classes:' \ + '-d[Show current default destination]' \ + '-h:hostname (alternate server):_hosts' \ + '-l[long listing]' \ + '-o[destinations]:printers:_printers' \ + '-p:printers:_printers' \ + '-r[CUPS server running status]' \ + '-s[Status summary]' \ + '-t[All status info]' \ + '-u[list jobs by users]:users:_users' \ + '-v[show devices]:printers:_printers' + ;; + + (lpr) + _arguments \ + '-E[Force encryption]' \ + '-H:hostname (alternate server):_hosts' \ + '(-C -J -T)'-{C,J,T}':job name:' \ + '-P+[destination printer]:printers:_printers' \ + '-U:username (for connection to server):_users' \ + '-#[Copies]:copies (1--100):' \ + '-h[Disables banner printing]' \ + '-l[raw file]' \ + '-m[Send an email on job completion]' \ + '*-o:print job options:_lp_job_options' \ + '-p[format with shaded header incl. date, time etc.]' \ + '-q[Hold job for printing.]' \ + '-r[delete files after printing]' \ + '*:PS/PDF files:_pspdf' + ;; + + (lp) + _arguments \ + '-E[Force encryption]' \ + '-U[username (for connection to server)]:username:_users' \ + '-c[(OBSOLETE) copy to spool dir before printing]' \ + '-d[destination printer]:printers:_printers' \ + '-h:hostname (alternate server):_hosts' \ + '-i[job id to modify]:job id:' \ + '-m[Send an email on job completion]' \ + '-n[Copies]:copies (1--100):' \ + '*-o:print job options:_lp_job_options' \ + '-q[Job priority -- 1 (lowest) to 100 (highest)]:priority:' \ + '-s[Dont report resulting job IDs]' \ + '-t[Sets the job name]:job name:' \ + '-u[job submission username]:username:_users' \ + '-H[Time to print]:print time (or enter hh\:mm):(hold immediate restart resume)' \ + '-P:page range list:' \ + '*:PS/PDF files:_pspdf' + ;; + esac +} + +_lp "$@" diff --git a/Completion/Unix/Command/_make b/Completion/Unix/Command/_make index e404d162d..53e2e1b3e 100644 --- a/Completion/Unix/Command/_make +++ b/Completion/Unix/Command/_make @@ -3,10 +3,7 @@ # TODO: Based on targets given on the command line, show only variables that # are used in those targets and their dependencies. -local prev="$words[CURRENT-1]" file expl tmp is_gnu dir incl match -local -A TARGETS VARIABLES - -expandVars() { +_make-expandVars() { local open close var val front ret tmp=$1 front=${tmp%%\$*} @@ -28,7 +25,7 @@ expandVars() { ;; (\$*) # Escaped $. - print -- "${front}\$$(expandVars ${tmp#\$})" + print -- "${front}\$$(_make-expandVars ${tmp#\$})" return ;; @@ -58,10 +55,10 @@ expandVars() { ;; esac - print -- "${front}$(expandVars ${ret})" + print -- "${front}$(_make-expandVars ${ret})" } -parseMakefile () { +_make-parseMakefile () { local input var val target dep TAB=$'\t' dir=$1 tmp while read input @@ -81,14 +78,14 @@ parseMakefile () { var=${input%%[ $TAB]#:=*} val=${input#*=} val=${val##[ $TAB]#} - val=$(expandVars $val) + val=$(_make-expandVars $val) VARIABLES[$var]=$val ;; # TARGET: dependencies # TARGET1 TARGET2 TARGET3: dependencies ([[:alnum:]][^$TAB:=]#:[^=]*) - input=$(expandVars $input) + input=$(_make-expandVars $input) target=${input%%:*} dep=${input#*:} dep=${(z)dep} @@ -107,7 +104,7 @@ parseMakefile () { f=${f#[\"<]} f=${f%[\">]} fi - f=$(expandVars $f) + f=$(_make-expandVars $f) case $f in (/*) ;; (*) f=$dir/$f ;; @@ -115,14 +112,14 @@ parseMakefile () { if [[ -r $f ]] then - parseMakefile ${f%%/[^/]##} < $f + _make-parseMakefile ${f%%/[^/]##} < $f fi ;; esac done } -findBasedir () { +_make-findBasedir () { local file index basedir basedir=$PWD for (( index=0; index < $#@; index++ )) @@ -148,75 +145,86 @@ findBasedir () { print -- $basedir } -_pick_variant -r is_gnu gnu=GNU unix -v -f - -if [[ $is_gnu == gnu ]] -then - incl="(-|)include" -else - incl=.include -fi - -if [[ "$prev" == -[CI] ]] -then - _files -W ${(q)$(findBasedir ${words[1,CURRENT-1]})} -/ -elif [[ "$prev" == -[foW] ]] -then - _files -W ${(q)$(findBasedir $words)} -else - file="$words[(I)-f]" - if (( file )) +_make() { + + local prev="$words[CURRENT-1]" file expl tmp is_gnu dir incl match + local -A TARGETS VARIABLES + local ret=1 + + _pick_variant -r is_gnu gnu=GNU unix -v -f + + if [[ $is_gnu == gnu ]] then - file=${~words[file+1]} - [[ $file == [^/]* ]] && file=${(q)$(findBasedir $words)}/$file - [[ -r $file ]] || file= + incl="(-|)include" else - local basedir - basedir=${(q)$(findBasedir $words)} - if [[ $is_gnu == gnu && -r $basedir/GNUmakefile ]] - then - file=$basedir/GNUmakefile - elif [[ -r $basedir/makefile ]] - then - file=$basedir/makefile - elif [[ -r $basedir/Makefile ]] + incl=.include + fi + + if [[ "$prev" == -[CI] ]] + then + _files -W ${(q)$(_make-findBasedir ${words[1,CURRENT-1]})} -/ && ret=0 + elif [[ "$prev" == -[foW] ]] + then + _files -W ${(q)$(_make-findBasedir $words)} && ret=0 + else + file="$words[(I)-f]" + if (( file )) then - file=$basedir/Makefile + file=${~words[file+1]} + [[ $file == [^/]* ]] && file=${(q)$(_make-findBasedir $words)}/$file + [[ -r $file ]] || file= else - file='' + local basedir + basedir=${$(_make-findBasedir $words)} + if [[ $is_gnu == gnu && -r $basedir/GNUmakefile ]] + then + file=$basedir/GNUmakefile + elif [[ -r $basedir/makefile ]] + then + file=$basedir/makefile + elif [[ -r $basedir/Makefile ]] + then + file=$basedir/Makefile + else + file='' + fi fi - fi - if [[ -n "$file" ]] - then - if [[ $is_gnu == gnu ]] && zstyle -t ":completion:${curcontext}:targets" call-command + if [[ -n "$file" ]] + then + if [[ $is_gnu == gnu ]] && zstyle -t ":completion:${curcontext}:targets" call-command + then + _make-parseMakefile $PWD < <(_call_program targets "$words[1]" -nsp --no-print-directory -f "$file" .PHONY 2> /dev/null) + else + case "$OSTYPE" in + freebsd*) + _make-parseMakefile $PWD < <(_call_program targets "$words[1]" -nsp -f "$file" .PHONY 2> /dev/null) + ;; + *) + _make-parseMakefile $PWD < $file + esac + fi + fi + + if [[ $PREFIX == *'='* ]] then - parseMakefile $PWD < <(_call_program targets "$words[1]" -nsp --no-print-directory -f "$file" .PHONY 2> /dev/null) + # Complete make variable as if shell variable + compstate[parameter]="${PREFIX%%\=*}" + compset -P 1 '*=' + _value "$@" && ret=0 else - case "$OSTYPE" in - freebsd*) - parseMakefile $PWD < <(_call_program targets "$words[1]" -nsp -f "$file" .PHONY 2> /dev/null) - ;; - *) - parseMakefile $PWD < $file - esac + _tags targets variables + while _tags + do + _requested targets expl 'make targets' \ + compadd -- ${(k)TARGETS} && ret=0 + _requested variables expl 'make variables' \ + compadd -S '=' -- ${(k)VARIABLES} && ret=0 + done fi fi - if [[ $PREFIX == *'='* ]] - then - # Complete make variable as if shell variable - compstate[parameter]="${PREFIX%%\=*}" - compset -P 1 '*=' - _value "$@" - else - _tags targets variables - while _tags - do - _requested targets expl 'make targets' \ - compadd -- ${(k)TARGETS} - _requested variables expl 'make variables' \ - compadd -S '=' -- ${(k)VARIABLES} - done - fi -fi + return ret +} + +_make "$@" diff --git a/Completion/Unix/Command/_mkdir b/Completion/Unix/Command/_mkdir index 927b9dfe9..b5f75198f 100644 --- a/Completion/Unix/Command/_mkdir +++ b/Completion/Unix/Command/_mkdir @@ -60,9 +60,8 @@ case "$state" in if (( $ret )) && [[ ! -prefix - ]] || \ [[ $variant == zsh && ${#${${words[2,-1]}:#-*}} -gt 0 ]]; then _wanted directories expl \ - 'parent directory (alternatively specify name of directory)' \ - _path_files -/ || _message 'name of directory' - ret=0 + 'parent directory (alternatively specify name of directory)' \ + _path_files -/ && ret=0 || _message 'name of directory' fi ;; esac diff --git a/Completion/Unix/Command/_mount b/Completion/Unix/Command/_mount index 7334481ba..409d253ab 100644 --- a/Completion/Unix/Command/_mount +++ b/Completion/Unix/Command/_mount @@ -44,7 +44,8 @@ local args deffs=iso9660 tmp typeops=-t _nfs_access _fs_nfs _nfs_ufs \ _fs_ufs _fs_efs _fs_cd9660 _fs_iso9660 _fs_cachefs _fs_s5fs _fs_tmpfs _fs_pcfs \ _fs_hsfs _fs_advfs _fs_cdfs _fs_affs _fs_ext2 _fs_fat _fs_ext3 _fs_msdos \ _fs_msdosfs _fs_umsdos _fs_vfat _fs_hpfs _fs_ntfs _fs_reiserfs _fs_smbfs \ -_fs_xfs _fs_std _fs_devfs _fs_fdesc _fs_kernfs _fs_linprocfs _fs_procfs +_fs_xfs _fs_std _fs_devfs _fs_fdesc _fs_kernfs _fs_linprocfs _fs_linsysfs \ +_fs_procfs typeset -A opt_args @@ -566,6 +567,7 @@ if (( ! $+_fs_any )); then _fs_fdesc=( "$_fs_std[@]" ) _fs_kernfs=( "$_fs_std[@]" ) _fs_linprocfs=( "$_fs_std[@]" ) + _fs_linsysfs=( "$_fs_std[@]" ) _fs_procfs=( "$_fs_std[@]" ) _fs_msdos=( 'shortnames[]' @@ -868,7 +870,7 @@ devordir) # add glabel devices _glabel=(${(M)${(f)"$(/sbin/glabel list)"}:#*Name:[[:space:]]*/*}) for mline ($_glabel);do - dev_tmp+=( mline[(w)3] ) + dev_tmp+=( /dev/$mline[(w)3] ) done _alternative \ diff --git a/Completion/Unix/Command/_notmuch b/Completion/Unix/Command/_notmuch new file mode 100644 index 000000000..0c23aa5f6 --- /dev/null +++ b/Completion/Unix/Command/_notmuch @@ -0,0 +1,69 @@ +#compdef notmuch + +_notmuch_commands() +{ + local -a notmuch_commands + notmuch_commands=( + 'setup:interactively set up notmuch for first use' + 'new:find and import any new message to the database' + 'search:search for messages matching the search terms, display matching threads as results' + 'reply:constructs a reply template for a set of messages' + 'show:show all messages matching the search terms' + 'tag:add or remove tags for all messages matching the search terms' + 'dump:creates a plain-text dump of the tags of each message' + 'restore:restores the tags from the given file' + 'help:show details on a command' + ) + + _describe -t command 'command' notmuch_commands +} + +_notmuch_dump() +{ + _files +} + +_notmuch_help_topics() +{ + local -a notmuch_help_topics + notmuch_help_topics=( + 'search-terms:show common search-terms syntax' + ) + _describe -t notmuch-help-topics 'topic' notmuch_help_topics +} + +_notmuch_help() +{ + _alternative \ + _notmuch_commands \ + _notmuch_help_topics +} + +_notmuch_restore() +{ + _files +} + +_notmuch_search() +{ + _arguments -s : \ + '--max-threads=[display only the first x threads from the search results]:number of threads to show: ' \ + '--first=[omit the first x threads from the search results]:number of threads to omit: ' \ + '--sort=[sort results]:sorting:((newest-first\:"reverse chronological order" oldest-first\:"chronological order"))' +} + +_notmuch() +{ + if (( CURRENT > 2 )) ; then + local cmd=${words[2]} + curcontext="${curcontext%:*:*}:notmuch-$cmd" + (( CURRENT-- )) + shift words + _call_function ret _notmuch_$cmd + return ret + else + _notmuch_commands + fi +} + +_notmuch "$@" diff --git a/Completion/Unix/Command/_npm b/Completion/Unix/Command/_npm new file mode 100644 index 000000000..24b536188 --- /dev/null +++ b/Completion/Unix/Command/_npm @@ -0,0 +1,19 @@ +#compdef npm + +# Node Package Manager 0.3.15 completion, letting npm do all the completion work + +_npm() { + compadd -- $(_npm_complete $words) +} + +# We want to show all errors of any substance, but never the "npm (not )ok" one. +# (Also doesn't consider "ERR! no match found" worth breaking the terminal for.) +_npm_complete() { + local ask_npm + ask_npm=(npm completion --color false --loglevel error -- $@) + { _call_program npm $ask_npm 2>&1 >&3 \ + | egrep -v '^(npm (not |)ok|ERR! no match found)$' >&2; \ + } 3>&1 +} + +_npm "$@" diff --git a/Completion/Unix/Command/_osc b/Completion/Unix/Command/_osc index 2808f92ee..c15b40af2 100644 --- a/Completion/Unix/Command/_osc +++ b/Completion/Unix/Command/_osc @@ -4,7 +4,7 @@ # # This file is released under the GPLv2. # -# Based on the the zsh guide from http://zsh.dotsrc.org/Guide/zshguide06.html +# Based on the zsh guide from http://zsh.dotsrc.org/Guide/zshguide06.html # # Toggle verbose completions: zstyle ':completion:*:osc:*' verbose no # zstyle ':completion:*:osc-subcommand:*' verbose no diff --git a/Completion/Unix/Command/_perforce b/Completion/Unix/Command/_perforce index b6fc18150..08c42cbce 100644 --- a/Completion/Unix/Command/_perforce +++ b/Completion/Unix/Command/_perforce @@ -322,6 +322,9 @@ _perforce() { local p4cmd==p4 match mbegin mend integer _perforce_cmd_ind + # Localise variables used at different levels of the hierarchy. + local _perforce_exclude_change + if [[ $1 = -l ]]; then # Run to load _perforce and associated functions but do # nothing else. @@ -857,28 +860,65 @@ _perforce_whole_path() { } # +# Helper function for the helper function _perforce_retreive_files +# for the helper functions for the helper function _perforce files. +# +# This code retrieves the list of files with a glob filter and +# possibly a line filter specified by the caller. The line filter +# must match the entire line. +# +# Result returned in $files. +# +(( $+functions[_perforce_filter_files] )) || +_perforce_filter_files() { + local call="$1" + local globfilter="$2" + local linefilter="$3" + local line + + if [[ -n $linefilter ]]; then + files=( + ${${${(f)"$(_perforce_call_p4 $call $call $globfilter 2>/dev/null)"}:#${~linefilter}}%%\#*} + ) + else + files=( + ${${(f)"$(_perforce_call_p4 $call $call $globfilter 2>/dev/null)"}%%\#*} + ) + fi +} + +# # Helper function for the helper functions for the helper function # _perforce_files. This is common code to retrieve a list of files # from Perforce. # # First argument is the p4 subcommand used to list the files. # This is also used as a tag for the style to decide whether -# to limit the list within Perforce. +# to limit the list within Perforce. It may have a colon +# followed by a shell pattern to match lines to be excluded +# from the match. +# # Remaining arguments are additional arguments to compadd. # (( $+functions[_perforce_retrieve_files] )) || _perforce_retrieve_files() { - local pfx - local -a files + local pfx exclude + local -a files match mbegin mend + + if [[ $1 = (#b)([^:]##):(*) ]]; then + 1=$match[1] + exclude=$match[2] + fi if _perforce_whole_path $1; then - files=(${${(f)"$(_perforce_call_p4 $1 $1 2>/dev/null)"}%%\#*}) + _perforce_filter_files $1 '' $exclude elif zstyle -t ":completion:${curcontext}:$1" glob; then # Limit the list by using Perforce to glob the pattern. # This may be faster, but won't use matcher specs etc. pfx=${(Q)PREFIX} compset -P '*/' - files=(${${${(f)"$(_perforce_call_p4 $1 $1 \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%%\#*}##*/}) + _perforce_filter_files $1 '"$pfx*${(Q)SUFFIX}"' $exclude + files=(${files##*/}) else # We need to limit the list to a directory. if [[ $PREFIX = */* ]]; then @@ -887,7 +927,8 @@ _perforce_retrieve_files() { pfx="*" fi compset -P '*/' - files=(${${${(f)"$(_perforce_call_p4 $1 $1 \$pfx 2>/dev/null)"}%%\#*}##*/}) + _perforce_filter_files $1 '$pfx' $exclude + files=(${files##*/}) fi [[ $#files -eq 1 && $files[1] = '' ]] && files=() shift @@ -912,10 +953,17 @@ _perforce_integrated_files() { (( $+functions[_perforce_opened_files] )) || _perforce_opened_files() { - local type - local -a files + local csuf - _perforce_retrieve_files opened "$@" + if [[ -n $_perforce_exclude_change ]]; then + if [[ $_perforce_exclude_change = default ]]; then + csuf=":* default change [^#]#" + else + csuf=":* change $_perforce_exclude_change [^#]#" + fi + fi + + _perforce_retrieve_files opened$csuf "$@" } @@ -2391,6 +2439,14 @@ _perforce_cmd_protects() { (( $+functions[_perforce_cmd_reopen] )) || _perforce_cmd_reopen() { + # Assume user doesn't want to reopen to same changelist. + integer pos=${words[(I)-c]} + if (( pos )); then + _perforce_exclude_change=${words[pos+1]} + elif [[ -n ${words[(R)-c?*]} ]]; then + _perforce_exclude_change=${${words[(R)-c?*]}##-c} + fi + _arguments -s : \ '-c+[select change to reopen on]:change:_perforce_changes -tc' \ '-t+[set file type]:file type:_perforce_filetypes' \ @@ -2474,7 +2530,7 @@ _perforce_cmd_set() { (( $+functions[_perforce_cmd_shelve] )) || _perforce_cmd_shelve() { _arguments -s : \ - '(-i)-c[specify changlist if not default]:change:_perforce_changes -tc' \ + '(-i)-c[specify changelist if not default]:change:_perforce_changes -tc' \ '(-i -r)-d[delete shelved files]' \ '(-r)-f[force by admin user or force to overwrite]' \ '(-c)-i[read from standard input]' \ @@ -2549,7 +2605,7 @@ _perforce_cmd_tickets() { _perforce_cmd_triggers() { _arguments -s : \ '-o[output form to stdout]' \ - '-i[read from from stdin]' + '-i[read from stdin]' } diff --git a/Completion/Unix/Command/_pgrep b/Completion/Unix/Command/_pgrep new file mode 100644 index 000000000..f65324a81 --- /dev/null +++ b/Completion/Unix/Command/_pgrep @@ -0,0 +1,112 @@ +#compdef pgrep pkill + +local context state line +typeset -A opt_args +typeset -a arguments + +arguments=('-P[parent process id]:parent process id:->ppid' + '-g[match only in process group ids]:group:->pgid' + '-G[match only real group id]:group:->group' + '-s[match only session id]:session id:->sid' + '-t[match only controlled by terminal]:terminal device:->tty' + '-u[match only effective user id]:user:->user' + '-U[match only real user id]:user:->user' + '(-n)-o[oldest process]' + '(-o)-n[newest process]' + '-f[match against full command line]' + '-v[negate matching]' + '-x[match exactly]' + '*:process name:->pname') + +if [[ $service == 'pkill' ]] +then + arguments+=('-'${^signals}'[signal]') +elif [[ $service == 'pgrep' ]] +then + arguments+=('-d[output delimiter]:delimiter:compadd ${(s\:\:)IFS}' + '-l[list name in addition to id]') +fi + +_arguments -s -w $arguments + +case $state in + (tty) + compset -P '*,' + + local -a used + used=(${(s:,:)IPREFIX}) + + compadd -S ',' -q -F used /dev/tty*(:t) + ;; + + (sid) + compset -P '*,' + + local -a used sid + used=(${(s:,:)IPREFIX}) + sid=(${(uon)$(ps -A o sid=)}) + + compadd -S ',' -q -F used $sid + ;; + + (ppid) + compset -P '*,' + + local -a used ppid + used=(${(s:,:)IPREFIX}) + ppid=(${(uon)$(ps -A o ppid=)}) + + compadd -S ',' -q -F used $ppid + ;; + + (pgid) + compset -P '*,' + + local -a used pgid + used=(${(s:,:)IPREFIX}) + pgid=(${(uon)$(ps -A o pgid=)}) + + compadd -S ',' -q -F used $pgid + ;; + + (pname) + if (( ${+opt_args[-x]} )) && (( ${+opt_args[-f]} )) + then + compadd ${(u)${(f)"$(ps -A o cmd=)"}} + else + compadd ${(u)${(f)"$(ps -A co cmd=)"}} + fi + ;; + + (group) + compset -P '*,' + + local group + group=$(getent group) + + local -a groups ids + groups=(${${(f)group}%%:*}) + ids=(${${${(f)group}#*:*:}%%:*}) + + local -a used + used=(${(s:,:)IPREFIX}) + + compadd -S ',' -q -F used -d ids $groups $groups + ;; + + (user) + compset -P '*,' + + local passwd + passwd=$(getent passwd) + + local -a users ids + users=(${${(f)passwd}%%:*}) + ids=(${${${(f)passwd}#*:*:}%%:*}) + + local -a used + used=(${(s:,:)IPREFIX}) + + compadd -S ',' -q -F used -d ids $users $users + ;; +esac diff --git a/Completion/Unix/Command/_php b/Completion/Unix/Command/_php index 7688dd571..bbb6a667b 100644 --- a/Completion/Unix/Command/_php +++ b/Completion/Unix/Command/_php @@ -31,7 +31,7 @@ args+=( '(- 1 *)'{-i,--info}'[PHP information]' '(- *)'{-l,--syntax-check}'[syntax check only (lint)]' '(- 1 *)'{-m,--modules}'[show compiled in modules]' - "(-r --run -f --file $exclusions -l --syntax-check -s --syntax-highlight -w --strip 1)"{-r,--run}'[run the specified PHP code without using script tags <?..?>]:PHP code:'\ + "(-r --run -f --file $exclusions -l --syntax-check -s --syntax-highlight -w --strip 1)"{-r,--run}'[run the specified PHP code without using script tags <?..?>]:PHP code:' '(- 1 *)'{-s,--syntax-highlight}'[display colour syntax highlighted source]' '(- 1 *)'{-v,--version}'[display version information]' '(- *)'{-w,--strip}'[display source with stripped comments and whitespace]' diff --git a/Completion/Unix/Command/_ri b/Completion/Unix/Command/_ri index a7f26923c..feb10ec91 100644 --- a/Completion/Unix/Command/_ri +++ b/Completion/Unix/Command/_ri @@ -21,17 +21,23 @@ _arguments \ '*:ri name:->ri-name' && ret=0 if [[ "$state" = ri-name ]]; then - local -a ri_dirs ri_names ri_wants ri_names + local -a ri_dirs ri_ext ri_names ri_wants ri_names local class_dir esc_name dir curtag tag descr expl ret=1 - if "ruby${words[1]#ri}" -rrdoc/ri/ri_options.rb -e 1 >/dev/null 2>&1; then + if "ruby${words[1]#ri}" -rrdoc/ri/ri_options -e 1 >/dev/null 2>&1; then # Old-style Ruby 1.8.x RI ri_dirs=( ${(f)"$(_call_program ri-names "ruby${words[1]#ri}" -rrdoc/ri/ri_options -e '"o = RI::Options.instance; o.parse(ARGV); o.path.each { |p| puts p }"' -- ${(kv)opt_args[(I)-d|--doc-dir|--(system|site|gems|home)]})"} ) + ri_ext=yaml + elif "ruby${words[1]#ri}" -rrdoc/ri -rrdoc/ri/store -e 1 >/dev/null 2>&1; then + # Newer-style Ruby 1.9.2 RI + ri_dirs=( ${(f)"$(_call_program ri-names "$words[1]" ${(kv)opt_args[(I)-d|--doc-dir|--((no-|)(system|site|gems|home)|standard-docs)]} --list-doc-dirs -f bs -T)"} ) + ri_ext=ri else # New-style Ruby 1.9+ RI ri_dirs=( ${(f)"$(_call_program ri-names "$words[1]" ${(kv)opt_args[(I)-d|--doc-dir|--((no-|)(system|site|gems|home)|standard-docs)]} --list-doc-dirs -f plain -T)"} ) + ri_ext=yaml fi if compset -P '?*(::|\#|.)'; then @@ -64,14 +70,14 @@ if [[ "$state" = ri-name ]]; then ;; (class-methods) for dir in $ri_dirs[@]; do - fnames=( $dir/$class_dir*-c.yaml(-.:t) ) - ri_wants+=( ${${fnames%-c.yaml}//(#b)%(??)/$(print "\\x$match[1]")} ) + fnames=( $dir/$class_dir*-c.$ri_ext(-.:t) ) + ri_wants+=( ${${fnames%-c.$ri_ext}//(#b)%(??)/$(print "\\x$match[1]")} ) done ;; (instance-methods) for dir in $ri_dirs[@]; do - fnames=( $dir/$class_dir*-i.yaml(-.:t) ) - ri_wants+=( ${${fnames%-i.yaml}//(#b)%(??)/$(print "\\x$match[1]")} ) + fnames=( $dir/$class_dir*-i.$ri_ext(-.:t) ) + ri_wants+=( ${${fnames%-i.$ri_ext}//(#b)%(??)/$(print "\\x$match[1]")} ) done ;; esac diff --git a/Completion/Unix/Command/_sccs b/Completion/Unix/Command/_sccs index 8d7babfb7..4083fe54e 100644 --- a/Completion/Unix/Command/_sccs +++ b/Completion/Unix/Command/_sccs @@ -109,7 +109,9 @@ case $service in sact|print) _sccs_files;; create|enter) _files;; deledit|delget|delta) - _arguments '-s[silent]' '-y+[specify delta commentary]:comment' + _arguments "$sfiles" \ + '-s[silent]' \ + '-y+[specify delta commentary]:comment' \ ;; diffs) _diff_options diff "$sfiles" "$ropt" "$copt" \ diff --git a/Completion/Unix/Command/_screen b/Completion/Unix/Command/_screen index 4d3b08934..931946c78 100644 --- a/Completion/Unix/Command/_screen +++ b/Completion/Unix/Command/_screen @@ -3,6 +3,18 @@ local curcontext="$curcontext" state line expl local scr_cmds sessions +function __screen_normal() { + if (( CURRENT == 1 )) && [[ $PREFIX == /dev/* ]]; then + _path_files -g '*(%)' + elif (( CURRENT == 2 )) && [[ ${words[1]} == /dev/* ]]; then + _message "baud rate" + elif (( CURRENT > 2 )) && [[ ${words[1]} == /dev/* ]]; then + _message "no more parameters" + else + _normal "$@" + fi +} + scr_cmds=( acladd aclchg acldel aclgrp aclumask activity addacl allpartial @@ -91,7 +103,7 @@ _arguments -C \ '-Dx: :->any-sessions' \ '-dx: :->any-sessions' \ '-X[execute command as a screen command in the specified session]:screencmd:(${scr_cmds[@]})' \ - '*::arguments: _normal' + '*::arguments: __screen_normal' if [[ -n $state ]]; then case $state in diff --git a/Completion/Unix/Command/_sh b/Completion/Unix/Command/_sh index 9e72a2918..7258e4260 100644 --- a/Completion/Unix/Command/_sh +++ b/Completion/Unix/Command/_sh @@ -5,7 +5,10 @@ if [[ $service == zsh ]]; then if [[ ${words[CURRENT-1]} == -o ]]; then _options # no other possibilities - return + return 0 + fi + if _arguments -S -s -- '*:'; then + return 0 fi fi diff --git a/Completion/Unix/Command/_subversion b/Completion/Unix/Command/_subversion index f0dbb5fc2..88142d805 100644 --- a/Completion/Unix/Command/_subversion +++ b/Completion/Unix/Command/_subversion @@ -4,6 +4,12 @@ _svn () { local curcontext="$curcontext" state line expl ret=1 typeset -A opt_args + local update_policy + zstyle -s ":completion:*:*:$service:*" cache-policy update_policy + if [[ -z "$update_policy" ]]; then + zstyle ":completion:*:*:$service:*" cache-policy _svn_caching_policy + fi + _arguments -C \ '(-)--help[print help information]' \ '(- *)--version[print client version information]' \ @@ -12,9 +18,12 @@ _svn () { if [[ -n $state ]] && (( ! $+_svn_cmds )); then typeset -gHA _svn_cmds - _svn_cmds=( - ${=${(f)${${"$(LC_ALL=C _call_program commands svn help)"#l#*Available subcommands:}%%Subversion is a tool*}}/(#s)[[:space:]]#(#b)([a-z]##)[[:space:]]#(\([a-z, ?]##\))#/$match[1] :$match[1]${match[2]:+:${${match[2]//[(),]}// /:}}:} - ) + if _cache_invalid svn-cmds || ! _retrieve_cache svn-cmds; then + _svn_cmds=( + ${=${(f)${${"$(LC_ALL=C _call_program commands svn help)"#l#*Available subcommands:}%%Subversion is a tool*}}/(#s)[[:space:]]#(#b)([a-z]##)[[:space:]]#(\([a-z, ?]##\))#/$match[1] :$match[1]${match[2]:+:${${match[2]//[(),]}// /:}}:} + ) + _store_cache svn-cmds _svn_cmds + fi fi case $state in @@ -29,10 +38,20 @@ _svn () { if (( $#cmd )); then curcontext="${curcontext%:*:*}:svn-${cmd}:" - usage=${${(M)${(f)"$(LC_ALL=C _call_program options svn help $cmd)"}:#usage:*}#usage:*$cmd] } - args=( - ${=${${${(M)${(f)"$(LC_ALL=C _call_program options svn help $cmd)"#(*Valid options:|(#e))}:#* :*}%% #:*}/ (arg|ARG)/:arg:}/(#b)-([[:alpha:]]) \[--([a-z-]##)\](:arg:)#/(--$match[2])-$match[1]$match[3] (-$match[1])--$match[2]$match[3]} - ) + if _cache_invalid svn-${cmd}-usage || \ + ! _retrieve_cache svn-${cmd}-usage; + then + usage=${${(M)${(f)"$(LC_ALL=C _call_program options svn help $cmd)"}:#usage:*}#usage:*$cmd] } + _store_cache svn-${cmd}-usage usage + fi + if _cache_invalid svn-${cmd}-usage || \ + ! _retrieve_cache svn-${cmd}-args; + then + args=( + ${=${${${(M)${(f)"$(LC_ALL=C _call_program options svn help $cmd)"#(*Valid options:|(#e))}:#* :*}%% #:*}/ (arg|ARG)/:arg:}/(#b)-([[:alpha:]]) \[--([a-z-]##)\](:arg:)#/(--$match[2])-$match[1]$match[3] (-$match[1])--$match[2]$match[3]} + ) + _store_cache svn-${cmd}-args args + fi case $cmd in; (add) @@ -297,4 +316,8 @@ _subversion () { esac } +_svn_caching_policy() { + [[ =$service -nt $1 ]] +} + _subversion "$@" diff --git a/Completion/Unix/Command/_tex b/Completion/Unix/Command/_tex new file mode 100644 index 000000000..9943fe10c --- /dev/null +++ b/Completion/Unix/Command/_tex @@ -0,0 +1,29 @@ +#compdef tex latex slitex pdftex pdflatex jadetex pdfjadetex xetex=tex xelatex=latex latexmk + +_arguments : \ + '-enc[enable encTeX extensions]' \ + '(-no-file-line-error -file-line-error)'{-no,}'-file-line-error[enable/disable file\:line\:error style messages]' \ + '-fmt=-[use FMTNAME instead of program name or a %& line]:FMTNAME:' \ + '-halt-on-error[stop processing at the first error]' \ + '-ini[be initex, for dumping formats]' \ + '-interaction[set interaction mode]:STRING:(batchmode nonstopmode scrollmode errorstopmode)' \ + '-ipc[send DVI output to a socket as well as the usual output file]' \ + '-ipc-start[as -ipc, and also start the server at the other end]' \ + '-jobname=-[set the job name]:STRING:' \ + '-kpathsea-debug=-[set path searching debugging flags according to the bits of NUMBER]:NUMBER:' \ + '(-no-mktex -mktex)'{-no,}'-mktex=-[enable/disable mktexFMT generation]:FMT:(tex tfm)' \ + '-mltex[enable MLTeX extensions]' \ + '-output-comment=-[DVI file comment]:STRING:' \ + '-output-directory=-[directory to write files to]:DIR:' \ + '(-no-parse-first-line -parse-first-line)'{-no,}'-parse-first-line[disable/enable parsing of the first line of the input file]' \ + '-progname=-[set program (and fmt) name]:STRING:' \ + '-recorder[enable filename recorder]' \ + '(-no-shell-escape -shell-escape)'{-no,}-shell-escape'[enable/disable \\write18{SHELL COMMAND}]' \ + '-shell-restricted[enable restricted \\write18]' \ + '-src-specials[insert source specials into the DVI file]' \ + '-src-specials=-[insert source specials in certain places of the DVI file]:WHERE:_values -s , WHERE cr display hbox math par parend vbox' \ + '-translate-file=-[use the TCX file TCXNAME]:TCXNAME:' \ + '-8bit[make all characters printable by default]' \ + '-help[display this help and exit]' \ + '-version[output version information and exit]' \ + '*:TeX or LaTeX file:_files -g "*.(tex|TEX|texinfo|texi)(-.)"' diff --git a/Completion/Unix/Command/_unison b/Completion/Unix/Command/_unison new file mode 100644 index 000000000..bb8edd489 --- /dev/null +++ b/Completion/Unix/Command/_unison @@ -0,0 +1,92 @@ +#compdef unison + +local context state line +typeset -A opt_args + +_arguments \ + '-auto[automatically accept default (nonconflicting) actions]' \ + '-batch[batch mode\: ask no questions at all]' \ + '-doc[show documentation]:topics:(about people lists status copying ack install tutorial basics failures running ssh news all topics)' \ + '-follow[add a pattern to the follow list]:pattern:' \ + '-force[force changes from this replica to the other]:replica:' \ + '-group[synchronize group attributes]' \ + '-ignore[add a pattern to the ignore list]:pattern:' \ + '-ignorenot[add a pattern to the ignorenot list]:pattern:' \ + '-owner[synchronize owner]' \ + '-path[path to synchronize]:path:_files' \ + '-perms[part of the permissions which is synchronized]:perms:' \ + '-prefer[choose this replicas version for conflicting changes]:replica:' \ + '-root[root of a replica (should be used exactly twice)]:path:_files -/' \ + '-silent[print nothing except error messages]' \ + '-terse[suppress status messages]' \ + '-testserver[exit immediately after the connection to the server]' \ + '-times[synchronize modification times]' \ + '-version[print version and exit]' \ + '-addprefsto[add new prefs to]:file:_files' \ + '-addversionno[add version number to name of unison on server]' \ + '-backup[add a pattern to the backup list]:pattern:' \ + '-backupcurr[add a pattern to the backupcurr list]:pattern:' \ + '-backupcurrnot[add a pattern to the backupcurrnot list]:pattern:' \ + '-backupdir[directory for storing centralized backups]:directory:_files -/' \ + '-backuploc[where backups are stored]:backup location:(local central)' \ + '-backupnot[add a pattern to the backupnot list]:pattern:' \ + '-backupprefix[prefix for the names of backup files]:prefix:' \ + '-backups[keep backup copies of all files]' \ + '-backupsuffix[a suffix to be added to names of backup files]:suffix:' \ + '-confirmbigdel[ask about whole-replica (or path) deletes (default true)]' \ + '-confirmmerge[ask for confirmation before commiting results of a merge]' \ + '-contactquietly[suppress the "contacting server" message during startup]' \ + '-copyprog[external program for copying large files]:program:_files -g "*(-x)"' \ + '-copyprogrest[variant of copyprog for resuming partial transfers]:program:_files -g "*(-x)"' \ + '-copyquoterem[add quotes to remote file name for copyprog]:quote style:(true false default)]' \ + '-copythreshold[use copyprog on files bigger than this]:size (kb):' \ + '-debug:debug module:(all verbose)' \ + '-diff[command for showing differences between files]:program:_files -g "*(-x)"' \ + '-dontchmod[When set, never use the chmod system call]' \ + '-dumbtty[do not change terminal settings in text UI]' \ + '-fastcheck:fast update detection:(true false default)' \ + '-forcepartial[add a pattern to the forcepartial list]:pattern:' \ + '-height[height of main window in graphical interface]:number (lines):' \ + '-host[bind the socket to this host name in server socket mode]:host:_hosts' \ + '-ignorecase[identify upper/lowercase filenames]:ignorecase:(true false default)' \ + '-ignorelocks[ignore locks left over from previous run (dangerous!)]' \ + '-immutable[add a pattern to the immutable list]:pattern:' \ + '-immutablenot[add a pattern to the immutablenot list]:pattern:' \ + '-key[define a keyboard shortcut for this profile (in some UIs)]:shortcut:' \ + '-killserver[kill server when done (even when using sockets)]' \ + '-label[provide a descriptive string label for this profile]:label:' \ + '-log[record actions in logfile (default true)]' \ + '-logfile:logfile name:_files' \ + '-maxbackups[number of backed up versions of a file]:number:' \ + '-maxthreads[maximum number of simultaneous file transfers]:number:' \ + '-merge[add a pattern to the merge list]:pattern:' \ + '-mountpoint[abort if this path does not exist]:mountpoint:_files -/' \ + '-numericids[dont map uid/gid values by user/group names]' \ + '-preferpartial[add a pattern to the preferpartial list]:pattern:' \ + '-pretendwin[Use creation times for detecting updates]' \ + '-repeat[synchronize repeatedly (text interface only)]:repeat:' \ + '-retry[re-try failed synchronizations N times (text ui only)]:retry times:' \ + '-rootalias[register alias for canonical root names]:root alias:' \ + '-rsrc:synchronize resource forks:(true false default)' \ + '-rsync[activate the rsync transfer mode (default true)]' \ + '-selftest[run internal tests and exit]' \ + '-servercmd[name of unison executable on remote server]:program:_files -g "*(-x)"' \ + '-showarchive[show "true names" (for rootalias) of roots and archive]' \ + '-socket[act as a server on a socket]:socket:_files -g "*(-=)"' \ + '-sortbysize[list changed files by size, not name]' \ + '-sortfirst[add a pattern to the sortfirst list]:pattern:' \ + '-sortlast[add a pattern to the sortlast list]:pattern:' \ + '-sortnewfirst[list new before changed files]' \ + '-sshargs[other arguments (if any) for remote shell command]:ssh args:' \ + '-sshcmd[path to the ssh executable]:program:_files -g "*(-x)"' \ + '-ui:user interface:(text graphic)' \ + '-xferbycopying[optimize transfers using local copies (default true)]' \ + '*:profile:->profile' + +if [[ $state == profile ]]; then + local -a profiles + + profiles=( ~/.unison/*.prf(N) ) + (( $#profiles )) && \ + compadd "$@" - ${${profiles#~/.unison/}%.prf} +fi diff --git a/Completion/Unix/Command/_vim b/Completion/Unix/Command/_vim index 8244466f4..af5afd347 100644 --- a/Completion/Unix/Command/_vim +++ b/Completion/Unix/Command/_vim @@ -28,7 +28,7 @@ arguments=( '-g[start with GUI]' '-l[lisp mode]' '-C[start in compatible mode]' - '-N[start in incompatibile mode]' + '-N[start in incompatible mode]' '(--nofork -f)'{--nofork,-f}'[do not detach the GUI version from the shell]' '-V-[verbosity level]::verbosity:((0\:"do not display any messages" 1\:"display when viminfo file is read or written" diff --git a/Completion/Unix/Type/.distfiles b/Completion/Unix/Type/.distfiles index 05942770a..4c0d688ac 100644 --- a/Completion/Unix/Type/.distfiles +++ b/Completion/Unix/Type/.distfiles @@ -41,7 +41,6 @@ _services _signals _tar_archive _terminals -_tex _texi _tilde_files _time_zone diff --git a/Completion/Unix/Type/_file_systems b/Completion/Unix/Type/_file_systems index 26053c8ed..3415bb163 100644 --- a/Completion/Unix/Type/_file_systems +++ b/Completion/Unix/Type/_file_systems @@ -21,8 +21,8 @@ case $OSTYPE in ntfs null nwfs portal procfs std udf ufs umap union ) ;; freebsd*) - fss=( cd9660 devfs ext2fs fdesc kernfs linprocfs mfs msdosfs nfs - ntfs nullfs nwfs portal procfs smbfs std udf ufs umap unionfs + fss=( cd9660 devfs ext2fs fdescfs kernfs linprocfs linsysfs mfs msdosfs nfs + ntfs nullfs nwfs portalfs procfs smbfs std udf ufs unionfs reiserfs xfs) ;; darwin*) diff --git a/Completion/Unix/Type/_have_glob_qual b/Completion/Unix/Type/_have_glob_qual index d174406df..7b558bfd5 100644 --- a/Completion/Unix/Type/_have_glob_qual +++ b/Completion/Unix/Type/_have_glob_qual @@ -16,9 +16,9 @@ local complete [[ $2 = complete ]] && complete=")" [[ -z $compstate[quote] && - ( -o bareglobqual && + ( $_comp_caller_options[bareglobqual] == on && $1 = (#b)(((*[^\\\$]|)(\\\\)#)\()([^\)\|\~]#)$complete && ${#match[1]} -gt 1 || - -o extendedglob && + $_comp_caller_options[extendedglob] == on && $1 = (#b)(((*[^\\\$]|)(\\\\)#)"(#q")([^\)]#)$complete ) ]] diff --git a/Completion/Unix/Type/_path_files b/Completion/Unix/Type/_path_files index 1f8be09b8..858fe3f74 100644 --- a/Completion/Unix/Type/_path_files +++ b/Completion/Unix/Type/_path_files @@ -16,7 +16,7 @@ local -a match mbegin mend # The later test looks for an outstanding quote. if _have_glob_qual $PREFIX; then compset -p ${#match[1]} - if [[ -o extendedglob ]] && compset -P '\#'; then + if [[ $_comp_caller_options[extendedglob] == on ]] && compset -P '\#'; then _globflags else _globquals @@ -574,7 +574,7 @@ for prepath in "$prepaths[@]"; do # slash be added. tmp1=( ${tmp1//(#b)([][()|*?^#~<>\\=])/\\${match[1]}} ) - tmp2="${(M)tpre##((.|..|)/)##}" + tmp2="${(M)tpre##${~skips}}" if [[ -n "$tmp2" ]]; then skipped="/$tmp2" tpre="${tpre#$tmp2}" @@ -617,7 +617,8 @@ for prepath in "$prepaths[@]"; do # enough to handle multiple components with patterns. if (( tmp4 )); then - # It is. For menu completion we now add the possible completions + # The component we're checking is ambiguous. + # For menu completion we now add the possible completions # for this component with the unambiguous prefix we have built # and the rest of the string from the line as the suffix. # For normal completion we add the rests of the filenames @@ -719,6 +720,7 @@ for prepath in "$prepaths[@]"; do fi fi tmp4=- + # Found an ambiguity, stop the loop over components. break fi @@ -764,27 +766,49 @@ for prepath in "$prepaths[@]"; do done if [[ -z "$tmp4" ]]; then + # I think this means it's finally time to add the matches, + # now we've collected contributions from all components. if [[ "$mid" = */ ]]; then + # This seems to mean we're completing in the middle of the + # command line argument, i.e. not in the last component. + # There are two cases, depending on whether this part of + # the path itself has multiple directories or not. PREFIX="${opre}" SUFFIX="${osuf}" tmp4="${testpath#${mid}}" - tmp3="${mid%/*/}" - tmp2="${${mid%/}##*/}" - if [[ -n "$linepath" ]]; then - compquote -p tmp3 + if [[ $mid = */*/* ]]; then + # Multiple levels of directory involved. + tmp3="${mid%/*/}" + tmp2="${${mid%/}##*/}" + if [[ -n "$linepath" ]]; then + compquote -p tmp3 + else + compquote tmp3 + fi + compquote tmp4 tmp2 tmp1 + for i in "$tmp1[@]"; do + _list_files tmp2 "$prepath$realpath${mid%/*/}" + compadd $Uopt -Qf "$mopts[@]" -p "${Uopt:+$IPREFIX}$linepath$tmp3/" \ + -s "/$tmp4$i${Uopt:+$ISUFFIX}" \ + -W "$prepath$realpath${mid%/*/}/" \ + "$pfxsfx[@]" $Mopts $listopts - "$tmp2" + done else - compquote tmp3 + # Simpler case with fewer directories: avoid double counting. + tmp2="${${mid%/}##*/}" + compquote tmp4 tmp2 tmp1 + for i in "$tmp1[@]"; do + _list_files tmp2 "$prepath$realpath${mid%/*/}" + compadd $Uopt -Qf "$mopts[@]" -p "${Uopt:+$IPREFIX}$linepath" \ + -s "/$tmp4$i${Uopt:+$ISUFFIX}" \ + -W "$prepath$realpath" \ + "$pfxsfx[@]" $Mopts $listopts - "$tmp2" + done fi - compquote tmp4 tmp2 tmp1 - for i in "$tmp1[@]"; do - _list_files tmp2 "$prepath$realpath${mid%/*/}" - compadd $Uopt -Qf "$mopts[@]" -p "${Uopt:+$IPREFIX}$linepath$tmp3/" \ - -s "/$tmp4$i${Uopt:+$ISUFFIX}" \ - -W "$prepath$realpath${mid%/*/}/" \ - "$pfxsfx[@]" $Mopts $listopts - "$tmp2" - done else + # This would seem to be where we're completing the last + # component of the path -- the normal one, in other words. if [[ "$osuf" = */* ]]; then PREFIX="${opre}${osuf}" SUFFIX= @@ -803,6 +827,7 @@ for prepath in "$prepaths[@]"; do fi if [[ -z "$_comp_correct" && -n "$compstate[pattern_match]" && "${PREFIX#\~}$SUFFIX" = (|*[^\\])[][*?#~^\|\<\>]* ]]; then + # Pattern match, we need to be clever with matchers. tmp1=("$linepath$tmp4${(@)^tmp1}") _list_files tmp1 "$prepath$realpath" compadd -Qf -W "$prepath$realpath" "$pfxsfx[@]" "$mopts[@]" \ diff --git a/Completion/Unix/Type/_pdf b/Completion/Unix/Type/_pdf index 994f08fdd..a2fbbc552 100644 --- a/Completion/Unix/Type/_pdf +++ b/Completion/Unix/Type/_pdf @@ -1,4 +1,4 @@ -#compdef pdf2dsc pdf2ps pdfimages pdfinfo pdftopbm pdftops pdftotext pdfopt pdffonts kpdf okular +#compdef pdf2dsc pdf2ps pdfimages pdfinfo pdftopbm pdftops pdftotext pdfopt pdffonts kpdf local expl ext='' diff --git a/Completion/Unix/Type/_pids b/Completion/Unix/Type/_pids index ea5ed79ee..3f99dfdf0 100644 --- a/Completion/Unix/Type/_pids +++ b/Completion/Unix/Type/_pids @@ -37,7 +37,7 @@ else desc=() fi -_wanted processes expl 'process ID' \ +_wanted -V processes expl 'process ID' \ compadd "$@" "$desc[@]" "$all[@]" -a - pids && ret=0 if [[ -n "$all" ]]; then diff --git a/Completion/Unix/Type/_tex b/Completion/Unix/Type/_tex deleted file mode 100644 index 3c16dcac7..000000000 --- a/Completion/Unix/Type/_tex +++ /dev/null @@ -1,6 +0,0 @@ -#compdef tex latex slitex pdflatex jadetex pdfjadetex xetex=tex xelatex=latex latexmk - -local expl - -_description files expl 'TeX or LaTeX file' -_files "$@" "$expl[@]" -g '*.(tex|TEX|texinfo|texi)(-.)' diff --git a/Completion/X/Command/.distfiles b/Completion/X/Command/.distfiles index 8ad17e1ac..3b6dc49fa 100644 --- a/Completion/X/Command/.distfiles +++ b/Completion/X/Command/.distfiles @@ -1,14 +1,35 @@ DISTFILES_SRC=' .distfiles -_acroread _dcop -_gnome-gv _gqview _gv _kfmclient -_mozilla _mplayer _nautilus -_nedit _netscape -_qiv +_acroread +_dcop +_gnome-gv +_gqview +_gv +_kfmclient +_matlab +_mozilla +_mplayer +_nautilus +_nedit +_netscape +_okular +_pdftk +_qiv _setxkbmap -_urxvt _vnc -_x_utils _xauth _xdvi _xfig _xloadimage -_xmodmap _xpdf _xscreensaver _xset _xterm -_xv _xwit +_urxvt +_vnc +_x_utils +_xauth +_xdvi +_xfig +_xloadimage +_xmodmap +_xournal +_xpdf +_xscreensaver +_xset +_xterm +_xv +_xwit _xrandr ' diff --git a/Completion/X/Command/_gv b/Completion/X/Command/_gv index 6075de508..d4dbed089 100644 --- a/Completion/X/Command/_gv +++ b/Completion/X/Command/_gv @@ -34,7 +34,7 @@ _arguments \ '--arguments=:ghostscript arguments:' \ '--page=:label of first page:' \ '--media=:page size:(Letter Legal Statement Tabloid Ledger Folio Quarto 10x14 Executive A3 A4 A5 B4 B5)' \ - '--orientation=:orientation:' \ + '--orientation=:orientation:(landscape seascape upsidedown portrait)' \ '--scale=:scale entry:' \ '--scalebase=:scale base:' \ '--ad=:resource file:_files' \ diff --git a/Completion/X/Command/_matlab b/Completion/X/Command/_matlab new file mode 100644 index 000000000..64d076f43 --- /dev/null +++ b/Completion/X/Command/_matlab @@ -0,0 +1,19 @@ +#compdef matlab + +_arguments : \ + {-h,-help}'[Display arguments.]' \ + '(-e)-n[Display final environment variables, and exit]' \ + '(-n)-e[Display ALL the environment variables and values, and exit]' \ + '-arch[Start MATLAB assuming architecture arch]:architecture:' \ + '-c[Set location of the license file]:licensefile:_files' \ + '(-nodisplay)-display:display:_x_display' \ + '(-display)-nodisplay[Do not display any X commands.]' \ + '-nosplash[Do not display the splash screen during startup.]' \ + '-mwvisual[The default X visual to use for figure windows.]:visualid:' \ + '-debug[Provide debugging information especially for X based problems.]' \ + '(-nodesktop -nojvm)-desktop[Allow the MATLAB desktop to be started by a process without a controlling terminal.]' \ + '(-desktop -nojvm)-nodesktop[Do not start the MATLAB desktop.]' \ + '(-nodesktop -desktop)-nojvm[Shut off all Java support by not starting the Java virtual machine.]' \ + '-r[Start MATLAB and execute the MATLAB_command.]:MATLAB_command:' \ + '-logfile[Make a copy of any output to the command window in file log.]:log file:' \ + '-D-:debugger:_path_commands' diff --git a/Completion/X/Command/_okular b/Completion/X/Command/_okular new file mode 100644 index 000000000..0b81e2f9d --- /dev/null +++ b/Completion/X/Command/_okular @@ -0,0 +1,10 @@ +#compdef okular +local extns + +extns="{pdf,ps,eps,dvi}(.gz|.bz2)(#c,1)|djvu|tiff|chm|cbr|cbz" + +_arguments \ + '(-p --page)'{-p,--page}'[Page of the document to be shown]:page: ' \ + '--presentation[Start the document in presentation mode]' \ + '--unique[Unique instance control]' \ + "*:Okular documents:_files -g '*.(#i)($extns)(-.)'" diff --git a/Completion/X/Command/_pdftk b/Completion/X/Command/_pdftk new file mode 100644 index 000000000..b8c43f754 --- /dev/null +++ b/Completion/X/Command/_pdftk @@ -0,0 +1,63 @@ +#compdef pdftk + +_pdfwithhandle() +{ + compset -P '(#I)[A-Z]=' + _files "$@" -g '(#i)*.pdf' +} + +local expl +local -a opts operations + +opts=(output encrypt_40bit encrypt_128bit allow owner_pw user_pw flatten + compress uncompress keep_first_id keep_final_id drop_xfa verbose + dont_ask do_ask) +operations=(cat attach_files unpack_files burst fill_form background stamp + generate_fdf multibackground multistamp dump_data dump_data_fields + update_info) + +case $words[CURRENT-1] in + ((input|owner|user)_pw) + _message "password, or PROMPT" + ;; + + (allow) + #_description permissions expl "permission" + #compadd $expl \ + _values -s , permissions \ + Printing DegradedPrinting ModifyContents Assembly CopyContents \ + ScreenReaders ModifyAnnotations FillIn AllFeatures + ;; + + (attach_files) + _files "$@" + ;; + + (fill_form) + _description files expl 'FDF and XFDF files' + _files "$@" $expl -g '(#i)*.(fdf|xfdf)' + ;; + + ((multibackground|background|stamp|multistamp|output)) + _description files expl 'PDF files' + _files "$@" $expl -g '(#i)*.pdf' + ;; + + (update_info) + _files + ;; + + (*) + false + ;; +esac && return 0 + +if [[ -n $words[(r)(${(j:|:)operations})] ]]; then + _description options expl "options" + compadd $@ $expl $opts +else + _tags files operations + _alternative \ + 'files:PDF files:_pdfwithhandle' \ + "operations:operations:($operations)" +fi diff --git a/Completion/X/Command/_vnc b/Completion/X/Command/_vnc index 347eb8ef4..70b897e47 100644 --- a/Completion/X/Command/_vnc +++ b/Completion/X/Command/_vnc @@ -6,13 +6,78 @@ displays=( \\${^displays} ) case $service in vncserver) - # currently lacking Xvnc arguments + # currently missing: bc, c, nologo, r, ttyxx, v + # Don't know values for -nolisten (other than tcp). _arguments \ - start \ '-name:desktop name:_x_name' \ + '-a[mouse acceleration (pixels)]:#:' \ + '-ac[disable access control restrictions]' \ + '-audit[set audit trail level]:int:' \ + '-auth[select authorization file]:file:_files' \ + '-bs[disable any backing store support]' \ + '-c[turns off key-click]' \ + '-cc[default color visual class]:int:' \ + '-co[color database file]:file:_files' \ + '-core[generate core dump on fatal error]' \ + '-dpi[screen resolution in dots per inch]:int:' \ + '-deferglyphs[defer loading of glyphs]:type:(none all 16)' \ + '-f[bell base]:level (0-100):' \ + '-fc[cursor font]:string:' \ + '-fn[default font name]:string:' \ + '-fp[default font path]:string:' \ + '-help[prints message with these options]' \ + '-I[ignore all remaining arguments]' \ + '-ld[limit data space to N Kb]:int:' \ + '-lf[limit number of open files to N]:int:' \ + '-ls[limit stack space to N Kb]:int:' \ + '-nolock[disable the locking mechanism]' \ + '-logo[enable logo in screen saver]' \ + '-nolisten[dont listen on protocol]:protocol:(tcp)' \ + '-p[screen-saver pattern duration (minutes)]:time (minutes):' \ + '-pn[accept failure to listen on all ports]' \ + '-nopn[reject failure to listen on all ports]' \ + '-r[turns off auto-repeat]' \ + '-s[screen-saver timeout (minutes)]:timeout (minutes):' \ + '-su[disable any save under support]' \ + '-t[mouse threshold]:pixels:' \ + '-terminate[terminate at server reset]' \ + '-to[connection time out]:time:' \ + '-tst[disable testing extensions]' \ + '-v[screen-saver without video blanking]' \ + '-wm[WhenMapped default backing-store]' \ + '-x[loads named extension at init time ]:string:' \ + '-query[contact named host for XDMCP]:host-name:_hosts' \ + '-broadcast[broadcast for XDMCP]' \ + '-indirect[contact named host for indirect XDMCP]:host-name:_hosts' \ + '-port[UDP port number to send messages to]:port:' \ + '-once[Terminate server after one session]' \ + '-class[specify display class to send in manage]:display-class:' \ + '-cookie[specify the magic cookie for XDMCP]:xdm-auth-bits:' \ + '-displayID[manufacturer display ID for request]:display-id:' \ '-geometry:geometry:(1600x1200 1280x1024 1152x864 1024x768 800x600 640x480)' \ '-depth:pixel depth:(8 16 24 32)' \ '-pixelformat:pixel format' \ + '-udpinputport[UDP port for keyboard/pointer data]:port:' \ + '-rfbport[TCP port for RFB protocol]:port:' \ + '-rfbwait[max time in ms to wait for RFB client]:time:' \ + '-nocursor[dont put up a cursor]' \ + '-rfbauth[use authentication on RFB protocol]:passwd-file:_files' \ + '-httpd[serve files via HTTP from here]:dir:_files -/' \ + '-httpport[port for HTTP]:port:' \ + '-deferupdate[time in ms to defer updates (default 40)]:time (ms):' \ + '-economictranslate[less memory-hungry translation]' \ + '-lazytight[disable "gradient" filter in tight encoding]' \ + '-desktop[VNC desktop name (default x11)]:name:' \ + '-alwaysshared[always treat new clients as shared]' \ + '-nevershared[never treat new clients as shared]' \ + '-dontdisconnect[dont disconnect existing clients for new non-shared connections]' \ + '-viewonly[let clients only to view the desktop]' \ + '-localhost[only allow connections from localhost]' \ + '-interface[only bind to specified interface address]:ipaddr:' \ + '-inetd[Xvnc is launched by inetd]' \ + '-compatiblekbd[set META key = ALT key as in the original VNC]' \ + '-version[report Xvnc version on stderr]' \ '1:: :_guard "(|:[0-9]#)" "display number"' \ - kill \ "-kill:display number:($displays)" \ @@ -25,6 +90,7 @@ case $service in '-depth:depth' \ '-passwd:file:_files' \ '(1)-listen:display number' \ + '-via:host:_hosts' \ '(-listen)1::display:_x_display' ;; esac diff --git a/Completion/X/Command/_xournal b/Completion/X/Command/_xournal new file mode 100644 index 000000000..066ef55f5 --- /dev/null +++ b/Completion/X/Command/_xournal @@ -0,0 +1,6 @@ +#compdef xournal + +local expl + +_description files expl 'PDF and Xournal files' +_files "$@" "$expl[@]" -g '*.(#i){xoj,pdf}(-.)' diff --git a/Completion/X/Command/_xrandr b/Completion/X/Command/_xrandr index 56d770e4d..2e51d0d23 100644 --- a/Completion/X/Command/_xrandr +++ b/Completion/X/Command/_xrandr @@ -1,4 +1,11 @@ #compdef xrandr +local context state line +typeset -A opt_args +local outputs modes expl + +# User configurable. TODO -- styles? +outputs=(LVDS1 TV1 VGA1) +modes=(1280x800 1024x768 800x600 640x480) _arguments \ '(-d -display)'{-d,-display}':X display:_x_display' \ @@ -6,28 +13,50 @@ _arguments \ '(-o --orientation)'{-o,--orientation}':rotation:(normal inverted left right 0 1 2 3)' \ '(-q --query)'{-q,--query}'[display current state]' \ '(-s --size)'{-s,--size}':size:' \ - '(-r --rate --refresh)'{-r,--rate,--refresh}':target refresh rate:' \ + '(-r --rate --refresh)'{*-r,*--rate,*--refresh}':target refresh rate:' \ '(-v --version)'{-v,--version}'[display version]' \ '-x[reflect across X axis]' \ '-y[reflect across Y axis]' \ '--screen:X screen number' \ '--verbose[be more verbose]' \ '--dryrun' \ + '--nograb' \ '(--prop --properties)'{--prop,--properties}'[display the contents of properties for each output]' \ '--fb:size:' \ '--fbmm:size:' \ '--dpi:dpi:' \ - '--output:output to reconfigure:' \ - '--auto' \ - '--mode:mode:' \ - '--preferred' \ - '--pos:position:' \ - '--reflect:axes:(normal x y xy)' \ - '--rotate:rotation:(normal inverted left right)' \ - '--left-of:output' \ - '--right-of:output' \ - '--above:output' \ - '--below:output' \ - '--same-as:output' \ - '--off[disable the output]' \ - '--crtc:crtc to use:' + "*--output:output to reconfigure:($outputs)" \ + '*--auto' \ + "*--mode:mode:($modes)" \ + '*--preferred' \ + '*--pos:position:' \ + '*--reflect:axes:(normal x y xy)' \ + '*--rotate:rotation:(normal inverted left right)' \ + "*--left-of:relative position to:($outputs)" \ + "*--right-of:relative position to:($outputs)" \ + "*--above:relative position to:($outputs)" \ + "*--below:relative position to:($outputs)" \ + "*--same-as:relative position to:($outputs)" \ + '*--set:property:(Backlight scaling\ mode):value:->value' \ + '*--scale:output scaling:' \ + '*--transform:transformation matrix:' \ + '*--off[disable the output]' \ + '*--crtc:crtc to use:' \ + '*--panning:panning:' \ + '*--gamma:r\:g\:b:' \ + '*--primary' \ + '--noprimary' \ + '*--newmode:name: :clock MHz: :hdisp: :hsync-start: :hsync-end: :htotal: :vdisp: :vsync-start: :vsync-end: :vtotal:' \ + '*--rmmode:Mode name:' \ + "*--addmode:output:($outputs):name:" \ + "*--delmode:output:($outputs):name:" \ + && return 0 + +if [[ $state == value ]]; then + case $words[CURRENT-1] in + (scaling* mode) + _description value expl "output property 'scaling mode'" + compadd "$@" "$expl[@]" None Full Center Full\ aspect && return 0 + ;; + esac +fi diff --git a/Completion/X/Command/_xset b/Completion/X/Command/_xset index 819a2040d..53ec635d4 100644 --- a/Completion/X/Command/_xset +++ b/Completion/X/Command/_xset @@ -27,8 +27,8 @@ _xset_compopts () { tmp=("$tmp[@]" "$opt") fi done - _describe -o options tmp -- || - _describe -o options allopts -- + _describe -O options tmp -- || + _describe -O options allopts -- } _xset_compfpadd () { diff --git a/Completion/Zsh/Context/_dynamic_directory_name b/Completion/Zsh/Context/_dynamic_directory_name index 5f7fe9a90..f449c3b12 100644 --- a/Completion/Zsh/Context/_dynamic_directory_name +++ b/Completion/Zsh/Context/_dynamic_directory_name @@ -1,7 +1,15 @@ #autoload -if [[ -n $functions[zsh_directory_name] ]]; then - zsh_directory_name c +local func +integer ret=1 + +if [[ -n $functions[zsh_directory_name] || \ + ${+zsh_directory_name_functions} -ne 0 ]] ; then + [[ -n $functions[zsh_directory_name] ]] && zsh_directory_name c && ret=0 + for func in $zsh_directory_name_functions; do + $func c && ret=0 + done + return ret else _message 'dynamic directory name: implemented as zsh_directory_name c' fi diff --git a/Completion/Zsh/Function/.distfiles b/Completion/Zsh/Function/.distfiles index c7de2b175..20b5dc6a6 100644 --- a/Completion/Zsh/Function/.distfiles +++ b/Completion/Zsh/Function/.distfiles @@ -1,4 +1,5 @@ DISTFILES_SRC=' .distfiles +_zargs _zsh-mime-handler ' diff --git a/Completion/Zsh/Function/_zargs b/Completion/Zsh/Function/_zargs new file mode 100644 index 000000000..a4cf0a89e --- /dev/null +++ b/Completion/Zsh/Function/_zargs @@ -0,0 +1,24 @@ +#compdef zargs -value-,-default-,-command- +# atom smasher - jan 2011 + +local arguments + +arguments=( $arguments[@] + '(--eof -e)'{--eof=,-e+}'[Change the end-of-input-args string from "--" to eof-str]' + '(--exit, -x)'{--exit,-x}'[Exit if the size (see --max-chars) is exceeded]' + '--help[Print summary and exit]' + '(--interactive, -p)'{--interactive,-p}'[Prompt before executing each command line]' + '(--max-args, -n)'{--max-args=,-n+}'[Use at most max-args arguments per command line]' + '(--max-chars, -s)'{--max-chars=,-s+}'[Use at most max-chars characters per command line]' + '(--max-lines, -l)'{--max-lines=,-l+}'[Use at most max-lines of the input-args per command line]' + '(--max-procs, -P)'{--max-procs=,-P+}'[Run up to max-procs command lines in the background at once]' + '(--no-run-if-empty, -r)'{--no-run-if-empty,-r}'[Do nothing if there are no input arguments before the eof-str]' + '(--null, -0)'{--null,-0}'[Split each input-arg at null bytes, for xargs compatibility]' + '(--replace, -i)'{--replace=,-i}'[Substitute replace-str in the initial-args by each initial-arg]' + '(--verbose, -t)'{--verbose,-t}'[Print each command line to stderr before executing it]' + '--version[Print the version number of zargs and exit]' +) + +_arguments -S -s $arguments[@] + +_command_names -e diff --git a/Completion/Zsh/Type/_command_names b/Completion/Zsh/Type/_command_names index f57d05226..24933c234 100644 --- a/Completion/Zsh/Type/_command_names +++ b/Completion/Zsh/Type/_command_names @@ -4,10 +4,14 @@ # complete only external commands and executable files. This and a # `-' as the first argument is then removed from the arguments. -local args defs +local args defs ffilt zstyle -t ":completion:${curcontext}:commands" rehash && rehash +zstyle -t ":completion:${curcontext}:functions" prefix-needed && \ + [[ $PREFIX != [_.]* ]] && \ + ffilt='[(I)[^_.]*]' + defs=( 'commands:external command:_path_commands' ) @@ -24,7 +28,7 @@ else defs=( "$defs[@]" 'builtins:builtin command:compadd -k builtins' - 'functions:shell function:compadd -k functions' + "functions:shell function:compadd -k 'functions$ffilt'" 'aliases:alias:compadd -k aliases' 'suffix-aliases:suffix alias:_suffix_alias_files' 'reserved-words:reserved word:compadd -k reswords' diff --git a/Completion/Zsh/Type/_functions b/Completion/Zsh/Type/_functions index 912a7f134..4d336695d 100644 --- a/Completion/Zsh/Type/_functions +++ b/Completion/Zsh/Type/_functions @@ -1,5 +1,9 @@ #compdef unfunction -local expl +local expl ffilt -_wanted functions expl 'shell function' compadd -k "$@" - functions +zstyle -t ":completion:${curcontext}:functions" prefix-needed && \ + [[ $PREFIX != [_.]* ]] && \ + ffilt='[(I)[^_.]*]' + +_wanted functions expl 'shell function' compadd -k "$@" - "functions$ffilt" diff --git a/Completion/Zsh/Type/_parameters b/Completion/Zsh/Type/_parameters index 097a96760..5156e3e2d 100644 --- a/Completion/Zsh/Type/_parameters +++ b/Completion/Zsh/Type/_parameters @@ -6,7 +6,7 @@ # If you specify a -g option with a pattern, the pattern will be used to # restrict the type of parameters matched. -local expl pattern fakes faked tmp +local expl pattern fakes faked tmp pfilt pattern=(-g \*) zparseopts -D -K -E g:=pattern @@ -23,8 +23,12 @@ if zstyle -a ":completion:${curcontext}:" fake-parameters tmp; then done fi +zstyle -t ":completion:${curcontext}:parameters" prefix-needed && \ + [[ $PREFIX != [_.]* ]] && \ + pfilt='[^_.]' + _wanted parameters expl parameter \ compadd "$@" -Q - \ - "${(@k)parameters[(R)${pattern[2]}~*local*]}" \ + "${(@M)${(@k)parameters[(R)${pattern[2]}~*local*]}:#${~pfilt}*}" \ "$fakes[@]" \ "${(@)${(@M)faked:#${~pattern[2]}}%%:*}" diff --git a/Completion/bashcompinit b/Completion/bashcompinit index cba436a55..63101a9c8 100644 --- a/Completion/bashcompinit +++ b/Completion/bashcompinit @@ -12,14 +12,14 @@ _bash_complete() { (( COMP_CWORD = CURRENT - 1)) COMP_WORDS=( $words ) BASH_VERSINFO=( 2 05b 0 1 release ) - + savejobstates=( ${(kv)jobstates} ) savejobtexts=( ${(kv)jobtexts} ) - + [[ ${argv[${argv[(I)nospace]:-0}-1]} = -o ]] && suf=( -S '' ) - + matches=( ${(f)"$(compgen $@)"} ) - + if [[ -n $matches ]]; then if [[ ${argv[${argv[(I)filenames]:-0}-1]} = -o ]]; then compset -P '*/' && matches=( ${matches##*/} ) @@ -41,11 +41,18 @@ _bash_complete() { return ret } +_compgen_opt_words() { + typeset -a words + words=( ${~=1} ) + local find="$2" + results=(${(M)words[@]:#$find*}) +} + compgen() { - local opts prefix suffix job OPTARG OPTIND ret=1 + local opts prefix suffix job OPTARG OPTIND ret=1 local -a name res results jids local -A shortopts - + emulate -L sh setopt kshglob noshglob braceexpand nokshautoload @@ -120,7 +127,13 @@ compgen() { ;; F) COMPREPLY=() - $OPTARG "${words[0]}" "${words[CURRENT-1]}" "${words[CURRENT-2]}" + (){ + set -- "${words[0]}" "${words[CURRENT-1]}" "${words[CURRENT-2]}" + # There may be more things we need to add to this typeset to + # protect bash functions from compsys special variable names + typeset -h words + $OPTARG "$@" + } results+=( "${COMPREPLY[@]}" ) ;; G) @@ -128,7 +141,7 @@ compgen() { results+=( ${~OPTARG} ) unsetopt nullglob ;; - W) eval "results+=( $OPTARG )" ;; + W) _compgen_opt_words "$OPTARG" "${@[-1]}" ;; C) results+=( $(eval $OPTARG) ) ;; P) prefix="$OPTARG" ;; S) suffix="$OPTARG" ;; diff --git a/Completion/compinit b/Completion/compinit index aa42a12de..a0f2348a9 100644 --- a/Completion/compinit +++ b/Completion/compinit @@ -26,7 +26,7 @@ # expand-or-complete, expand-or-complete-prefix, list-choices, # menu-complete, menu-expand-or-complete, or reverse-menu-complete). # This creates a widget behaving like <style> so that the -# completions are chosen as given in the the rest of the file, +# completions are chosen as given in the rest of the file, # rather than by the context. The widget has the same name as # the autoload file and can be bound using bindkey in the normal way. # @@ -160,7 +160,9 @@ _comp_options=( # have a valid stdin descriptor (zle closes it before calling widgets) # and don't get confused by user's ZERR trap handlers. -typeset -g _comp_setup='setopt localoptions localtraps ${_comp_options[@]}; +typeset -g _comp_setup='local -A _comp_caller_options; + _comp_caller_options=(${(kv)options}); + setopt localoptions localtraps ${_comp_options[@]}; local IFS=$'\'\ \\t\\r\\n\\0\'' exec </dev/null; trap - ZERR @@ -229,7 +231,7 @@ comppostfuncs=() # delete the definitions for the command names `bar' and `baz' compdef() { - local opt autol type func delete new i ret=0 cmd svc + local opt autol type func delete eval new i ret=0 cmd svc local -a match mbegin mend emulate -L zsh @@ -242,7 +244,7 @@ compdef() { return 1 fi - while getopts "anpPkKd" opt; do + while getopts "anpPkKde" opt; do case "$opt" in a) autol=yes;; n) new=yes;; @@ -263,6 +265,7 @@ compdef() { fi ;; d) delete=yes;; + e) eval=yes;; esac done shift OPTIND-1 @@ -276,7 +279,7 @@ compdef() { # If the first word contains an equal sign, all words must contain one # and we define which services to use for the commands. - if [[ "$1" = *\=* ]]; then + if [[ -z "$eval" ]] && [[ "$1" = *\=* ]]; then while (( $# )); do if [[ "$1" = *\=* ]]; then cmd="${1%%\=*}" diff --git a/Completion/openSUSE/Command/.distfiles b/Completion/openSUSE/Command/.distfiles new file mode 100644 index 000000000..301ef12b3 --- /dev/null +++ b/Completion/openSUSE/Command/.distfiles @@ -0,0 +1,8 @@ +DISTFILES_SRC=' +.distfiles +_hwinfo +_osc +_SuSEconfig +_yast2 +_zypper +' diff --git a/Completion/openSUSE/Command/_SuSEconfig b/Completion/openSUSE/Command/_SuSEconfig new file mode 100644 index 000000000..d50828529 --- /dev/null +++ b/Completion/openSUSE/Command/_SuSEconfig @@ -0,0 +1,28 @@ +#compdef SuSEconfig + +local curcontext="$curcontext" state line +typeset -A opt_args + +if [[ -z "$_SuSEconfig_modules" ]]; then + for i in /sbin/conf.d/SuSEconfig.*; do + case $i in *.rpm*|*.swap|*.bak|*.orig|*~|\#*) continue;; esac + _SuSEconfig_modules=($_SuSEconfig_modules ${i##*/SuSEconfig.}) + done +fi + + +_arguments \ + '--help' \ + '--quick' \ + '--force' \ + '--verbose' \ + '--nonewpackage' \ + '--module:module:->module' && return 0 + +case $state in + module) compadd $_SuSEconfig_modules ;; +esac + +# Usage: SuSEconfig [--quick|--nonewpackage|--force|--verbose] [--module name] + + diff --git a/Completion/openSUSE/Command/_hwinfo b/Completion/openSUSE/Command/_hwinfo new file mode 100644 index 000000000..aac0a05ad --- /dev/null +++ b/Completion/openSUSE/Command/_hwinfo @@ -0,0 +1,79 @@ +#compdef hwinfo + +_arguments \ + '--help[show usage info]' \ + '--version[show libhd version]' \ + '--short[just a short listing]' \ + '--log[write info to logfile]:logfile:_files' \ + '--debug[set debuglevel]:debuglevels:(1 2 3 4 5 6 7 8 9)' \ + '--dump-db[dump hardware data base, 0: external, 1: internal]:dumpdb:(0 1)' \ + '--bios' \ + '--block' \ + '--bluetooth' \ + '--braille' \ + '--bridge' \ + '--camera' \ + '--cdrom' \ + '--chipcard' \ + '--cpu' \ + '--disk' \ + '--dsl' \ + '--dvb' \ + '--floppy' \ + '--framebuffer' \ + '--gfxcard' \ + '--hub' \ + '--ide' \ + '--isapnp' \ + '--isdn' \ + '--joystick' \ + '--keyboard' \ + '--memory' \ + '--modem' \ + '--monitor' \ + '--mouse' \ + '--netcard' \ + '--network' \ + '--partition' \ + '--pci' \ + '--pcmcia' \ + '--pcmcia-ctrl' \ + '--pppoe' \ + '--printer' \ + '--scanner' \ + '--scsi' \ + '--smp' \ + '--sound' \ + '--storage-ctrl' \ + '--sys' \ + '--tape' \ + '--tv' \ + '--usb' \ + '--usb-ctrl' \ + '--vbe' \ + '--wlan' \ + '--zip' \ + '--all' \ + '--reallyall' && return 0 + + +# hwinfo-9.31-1.1 +# +# Usage: hwinfo [options] +# Probe for hardware. +# --short just a short listing +# --log logfile write info to logfile +# --debug level set debuglevel +# --version show libhd version +# --dump-db n dump hardware data base, 0: external, 1: internal +# --hw_item probe for hw_item +# hw_item is one of: +# all, bios, block, bluetooth, braille, bridge, camera, cdrom, chipcard, cpu, +# disk, dsl, dvb, floppy, framebuffer, gfxcard, hub, ide, isapnp, isdn, +# joystick, keyboard, memory, modem, monitor, mouse, netcard, network, +# partition, pci, pcmcia, pcmcia-ctrl, pppoe, printer, scanner, scsi, smp, +# sound, storage-ctrl, sys, tape, tv, usb, usb-ctrl, vbe, wlan, zip +# +# Note: debug info is shown only in the log file. (If you specify a +# log file the debug level is implicitly set to a reasonable value.) + diff --git a/Completion/openSUSE/Command/_osc b/Completion/openSUSE/Command/_osc new file mode 100644 index 000000000..c15b40af2 --- /dev/null +++ b/Completion/openSUSE/Command/_osc @@ -0,0 +1,149 @@ +#compdef osc +# +# Copyright (C) 2009,2010 Holger Macht <holger@homac.de> +# +# This file is released under the GPLv2. +# +# Based on the zsh guide from http://zsh.dotsrc.org/Guide/zshguide06.html +# +# Toggle verbose completions: zstyle ':completion:*:osc:*' verbose no +# zstyle ':completion:*:osc-subcommand:*' verbose no +# +# Use the variables $ZSH_OSC_BUILD_TARGETS_EXTRA and $ZSH_OSC_PROJECTS_EXTRA to +# extend the list of possible completions in your ~/.zshrc like that: +# export OSC_PROJECTS_EXTRA="Base:System Base:shells" +# +# version 0.2 +# + +OSC_BUILD_TARGETS="openSUSE_10.2 openSUSE_10.3 openSUSE_11.0 openSUSE_11.1 openSUSE_11.2 openSUSE_11.3 openSUSE_Factory" +OSC_PROJECTS="openSUSE:Factory openSUSE:11.2 openSUSE:11.3 openSUSE:11.1 openSUSE:11.0 openSUSE:10.3" + +# user defined variables $OSC_BUILD_TARGETS_EXTRA and +# $OSC_PROJECTS_EXTRA can add to the project/build target list +OSC_BUILD_TARGETS="$OSC_BUILD_TARGETS $ZSH_OSC_BUILD_TARGETS_EXTRA" +OSC_PROJECTS="$OSC_PROJECTS $ZSH_OSC_PROJECTS_EXTRA" + +# Main dispatcher + +_osc() { + if (( CURRENT > 2 )) && [[ ${words[2]} != "help" ]]; then + # Remember the subcommand name + local cmd=${words[2]} + # Set the context for the subcommand. + curcontext="${curcontext%:*:*}:osc-subcommand" + # Narrow the range of words we are looking at to exclude `osc' + (( CURRENT-- )) + shift words + # Run the completion for the subcommand + if [ "$cmd" = "submitreq" -o "$cmd" = "sr" ]; then + _osc_cmd_submitreq + elif [ "$cmd" = "getbinaries" ]; then + _osc_cmd_getbinaries + elif [ "$cmd" = "checkout" -o "$cmd" = "co" -o "$cmd" = "branch" ]; then + _osc_cmd_checkout + elif [ "$cmd" = "buildlog" -o "$cmd" = "buildinfo" -o "$cmd" = "bl" ]; then + _osc_cmd_buildlog + else + _osc_cmd_do $cmd + fi + else + local hline + local -a cmdlist + local tag=0 + _call_program help-commands osc help | while read -A hline; do + # start parsing with "commands:" + [[ $hline[1] = "commands:" ]] && tag=1 + # stop parsing at the line starting with "For" + [[ $hline[1] = "For" ]] && tag=0 + [[ $tag = 0 ]] && continue + # all commands have to start with lower case letters + [[ $hline[1] =~ ^[A-Z] ]] && continue + (( ${#hline} < 2 )) && continue + + # ${hline[1]%,} truncates the last ',' + cmdlist=($cmdlist "${hline[1]%,}:${hline[2,-1]}") + done + _describe -t osc-commands 'osc command' cmdlist + fi +} + +_osc_cmd_getbinaries() { + _arguments \ + '1:PROJECT:( `echo $OSC_PROJECTS` )' \ + '2:PACKAGE:(PACKAGE)' \ + '3:REPOSITORY:( `echo $OSC_BUILD_TARGETS` )' \ + '4:ARCHITECTURE:(i586 x86_64)' +} + +_osc_cmd_checkout() { + _arguments \ + '1:PROJECT:( `echo $OSC_PROJECTS` )' \ + '2:PACKAGE:(PACKAGE)' +} + +_osc_cmd_buildlog() { + _arguments \ + '1:REPOSITORY:( `echo $OSC_BUILD_TARGETS` )' \ + '2:ARCHITECTURE:(i586 x86_64)' +} + +_osc_cmd_submitreq() { + local hline + local -a cmdlist + local tag=0 + _call_program help-commands osc help $cmd | while read -A hline; do + # start parsing from "usage:" + [[ $hline[1] = "usage:" ]] && tag=1 + [[ $tag = 0 ]] && continue + + if [[ $hline[1] =~ ^osc ]]; then + shift hline; shift hline + elif ! [[ $hline[1] =~ ^- ]]; then + # Option has to start with a '-' or 'osc submitrequest' + continue + fi + + (( ${#hline} < 2 )) && continue + + cmdlist=($cmdlist "${hline[1]%,}:${hline[2,-1]}") + + done + + _describe -t osc-commands 'osc command' cmdlist +} + + +_osc_cmd_do() { + local hline + local -a cmdlist + local tag=0 + + # only start completion if theres some '-' on the line + if ! [ "$words[2]" = "-" ]; then + _complete + return + fi + + _call_program help-commands osc help $cmd | while read -A hline; do + # start parsing from "Options:" + [[ $hline[1] = "Options:" ]] && tag=1 + [[ $tag = 0 ]] && continue + # Option has to start with a '-' + [[ $hline[1] =~ ^- ]] || continue + (( ${#hline} < 2 )) && continue + + cmdlist=($cmdlist "${hline[1]%,}:${hline[2,-1]}") + done + + if [ -n "$cmdlist" ]; then + _describe -t osc-commands 'osc command' cmdlist + else + _complete + fi +} + +# Code to make sure _osc is run when we load it +_osc "$@" + + diff --git a/Completion/openSUSE/Command/_yast2 b/Completion/openSUSE/Command/_yast2 new file mode 100644 index 000000000..b9c7f2489 --- /dev/null +++ b/Completion/openSUSE/Command/_yast2 @@ -0,0 +1,30 @@ +#compdef yast2 yast + +local curcontext="$curcontext" state line +typeset -A opt_args + +if [[ -z "$_yast2_modules" ]]; then + for i in $(/sbin/yast2 --list | grep -v "Available.*modules"); do + _yast2_modules=($_yast2_modules $i) + done +fi + +_arguments -s \ + '(--list)-l[list all available modules]' '(-l)--list' \ + '(--help)-h[help]' '(-h)--help'\ + \ + {'(--geometry)-g[default window size (qt only)]','(-g)--geometry'}':geometry:(800x600+0+0)' \ + '(--style)-s[widget style (qt only)]' '(-s)--style' \ + \ + {'(--install)-i[install rpm package]','(-i)--install'}':filename:_files' \ + \ + '--noborder[no window manager border for main window]' '--noborder' \ + '--fullscreen[use full screen]' '--fullscreen' \ + \ + ':module:->module' && return 0 + +case $state in + module) compadd $_yast2_modules; _files -g "*.ycp";; +esac + + diff --git a/Completion/openSUSE/Command/_zypper b/Completion/openSUSE/Command/_zypper new file mode 100644 index 000000000..03818eaa5 --- /dev/null +++ b/Completion/openSUSE/Command/_zypper @@ -0,0 +1,73 @@ +#compdef zypper +# +# Copyright (C) 2009 Holger Macht <holger@homac.de> +# +# This file is released under the GPLv2. +# +# Based on the zsh guide from http://zsh.dotsrc.org/Guide/zshguide06.html +# +# Toggle verbose completions: zstyle ':completion:*:zypper:*' verbose no +# zstyle ':completion:*:zypper-subcommand:*' verbose no +# +# version 0.1 +# +# Main dispatcher + +_zypper() { + if (( CURRENT > 2 )) && [[ ${words[2]} != "help" ]]; then + # Remember the subcommand name + local cmd=${words[2]} + # Set the context for the subcommand. + curcontext="${curcontext%:*:*}:zypper-subcommand" + # Narrow the range of words we are looking at to exclude `zypper' + (( CURRENT-- )) + shift words + + _zypper_cmd_do $cmd + else + local hline + local -a cmdlist + local tag=0 + _call_program help-commands zypper help | while read -A hline; do + # start parsing with "Global Options:" + [[ $hline =~ "^Global Options:" ]] && tag=1 + [[ $tag = 0 ]] && continue + [[ $hline[1] =~ ^\t\t\t\t ]] && continue + # all commands have to start with lower case letters + [[ $hline[1] =~ ^[A-Z] ]] && continue + (( ${#hline} < 2 )) && continue + + # cut comma at end of command + hline[1]=`echo $hline[1] | sed -e 's/\(^.*\),/\1/'` + + # ${hline[1]%,} truncates the last ',' + cmdlist=($cmdlist "${hline[1]%,}:${hline[2,-1]}") + done + _describe -t zypper-commands 'zypper command' cmdlist + fi +} + +_zypper_cmd_do() { + local hline + local -a cmdlist + local tag=0 + _call_program help-commands zypper help $cmd | while read -A hline; do + # start parsing from "Options:" + [[ $hline =~ "^Command options:" ]] && tag=1 + [[ $tag = 0 ]] && continue + # Option has to start with a '-' + [[ $hline[1] =~ ^- ]] || continue + (( ${#hline} < 2 )) && continue + + cmdlist=($cmdlist "${hline[1]%,}:${hline[2,-1]}") + done + + if [ -n "$cmdlist" ]; then + _describe -t zypper-commands 'zypper command' cmdlist + else + _complete + fi +} + +# Code to make sure _zypper is run when we load it +_zypper "$@" diff --git a/Config/defs.mk.in b/Config/defs.mk.in index 69edf7005..58ef11066 100644 --- a/Config/defs.mk.in +++ b/Config/defs.mk.in @@ -73,9 +73,9 @@ IMPOPT = @IMPOPT@ # utilities AWK = @AWK@ ANSI2KNR = @ANSI2KNR@ -YODL = @YODL@ -YODL2TXT = $(YODL)2txt -YODL2HTML = $(YODL)2html +YODL = @YODL@ @YODL_OPTIONS@ +YODL2TXT = @YODL@2txt +YODL2HTML = @YODL@2html PDFETEX = @PDFETEX@ TEXI2PDF = @TEXI2PDF@ @@ -86,6 +86,9 @@ INSTALL_DATA = @INSTALL_DATA@ # variables used in determining what to install FUNCTIONS_SUBDIRS = @FUNCTIONS_SUBDIRS@ +# Additional fpath entries (eg. for vendor specific directories). +additionalfpath = @additionalfpath@ + # flags passed to recursive makes in subdirectories MAKEDEFS = \ prefix='$(prefix)' exec_prefix='$(exec_prefix)' bindir='$(bindir)' \ diff --git a/Config/version.mk b/Config/version.mk index 91ae13043..37193970a 100644 --- a/Config/version.mk +++ b/Config/version.mk @@ -27,5 +27,5 @@ # This must also serve as a shell script, so do not add spaces around the # `=' signs. -VERSION=4.3.11 -VERSION_DATE='December 20, 2010' +VERSION=4.3.12 +VERSION_DATE='May 31, 2011' diff --git a/Doc/Makefile.in b/Doc/Makefile.in index 3374ea705..f7f5915c1 100644 --- a/Doc/Makefile.in +++ b/Doc/Makefile.in @@ -73,7 +73,8 @@ YODLSRC = zmacros.yo zman.yo ztexi.yo Zsh/arith.yo Zsh/builtins.yo \ Zsh/calsys.yo \ Zsh/compat.yo Zsh/compctl.yo Zsh/compsys.yo Zsh/compwid.yo Zsh/cond.yo \ Zsh/contrib.yo Zsh/exec.yo Zsh/expn.yo \ -Zsh/filelist.yo Zsh/files.yo Zsh/func.yo Zsh/grammar.yo Zsh/manual.yo \ +Zsh/filelist.yo Zsh/files.yo Zsh/ftp_sites.yo \ +Zsh/func.yo Zsh/grammar.yo Zsh/manual.yo \ Zsh/index.yo Zsh/intro.yo Zsh/invoke.yo Zsh/jobs.yo Zsh/metafaq.yo \ Zsh/modules.yo Zsh/modlist.yo Zsh/modmenu.yo Zsh/manmodmenu.yo $(MODDOCSRC) \ Zsh/options.yo Zsh/params.yo Zsh/prompt.yo Zsh/redirect.yo Zsh/restricted.yo \ @@ -161,9 +162,9 @@ zshall.1: zsh.yo $(YODL) -I$(sdir) -DZSHALL -w zman.yo version.yo zsh.yo | sed -e '1s/\\-/-/g' -e '/^\.'\''/d' > $$target \ ;; esac; \ -../META-FAQ: META-FAQ.yo Zsh/metafaq.yo +../META-FAQ: META-FAQ.yo Zsh/metafaq.yo Zsh/ftp_sites.yo case '$(YODL)' in :*) touch $(sdir_top)/META-FAQ ;; *) \ - $(YODL) -I$(sdir) META-FAQ.yo | sed -e '/NEXTLINE/N' -e '/DELLINE/d' -e '/^SECTHEAD$$/{N;s/^SECTHEAD.//;h;s/./-/g;H;g;}' -e 's/ *$$//' > $(sdir_top)/META-FAQ \ + $(YODL) -I$(sdir) META-FAQ.yo | sed -e '/NEXTLINE/N' -e '/DELLINE/d' -e '/^SECTHEAD$$/{N;s/^SECTHEAD.//;h;s/./-/g;H;g;}' -e 's/ *$$//' -e '/comment(.*)/d' > $(sdir_top)/META-FAQ \ ;; esac $(YODLDOC): version.yo @@ -176,7 +177,8 @@ man: $(MAN) $(MAN): zmacros.yo zman.yo zsh.1 zshall.1: Zsh/intro.yo Zsh/metafaq.yo Zsh/invoke.yo Zsh/files.yo \ - Zsh/filelist.yo Zsh/filelist.yo Zsh/seealso.yo + Zsh/filelist.yo Zsh/filelist.yo Zsh/seealso.yo \ + Zsh/ftp_sites.yo zshbuiltins.1: Zsh/builtins.yo diff --git a/Doc/Zsh/.distfiles b/Doc/Zsh/.distfiles index dcca24e07..4f521e91c 100644 --- a/Doc/Zsh/.distfiles +++ b/Doc/Zsh/.distfiles @@ -14,6 +14,7 @@ exec.yo expn.yo filelist.yo files.yo +ftp_sites.yo func.yo grammar.yo index.yo diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 3be4a8b21..7170b13b9 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -621,7 +621,7 @@ ifnzman(noderef(Arithmetic Evaluation))\ . By default var(mathfn) may take any number of comma-separated arguments. If var(min) is given, it must have exactly var(min) args; if var(min) and var(max) are -both given, it must have at least var(min) and and at most var(max) +both given, it must have at least var(min) and at most var(max) args. var(max) may be -1 to indicate that there is no upper limit. By default the function is implemented by a shell function of the same @@ -1290,10 +1290,6 @@ all parameters are printed on the standard output. If the only argument is For historical reasons, `tt(set -)' is treated as `tt(set +xv)' and `tt(set -) var(args)' as `tt(set +xv --) var(args)' when in any other emulation mode than zsh's native mode. - -The tt(sched) builtin is not made available by default when the shell -starts in a mode emulating another shell. It can be made available -with the command `tt(zmodload -F zsh/sched b:sched)'. ) module(setcap)(zsh/cap) findex(setopt) diff --git a/Doc/Zsh/calsys.yo b/Doc/Zsh/calsys.yo index f4bd4eaa4..259eb23b3 100644 --- a/Doc/Zsh/calsys.yo +++ b/Doc/Zsh/calsys.yo @@ -363,7 +363,7 @@ entry. `tt(-B 1)' is equivalent to `tt(-b)'. ) item(tt(-C) var(calfile))( Explicitly specify a calendar file instead of the value of -the tt(calendar-file) style or the the default tt(~/calendar). +the tt(calendar-file) style or the default tt(~/calendar). ) item(tt(-d))( Move any events that have passed from the calendar file to the diff --git a/Doc/Zsh/compctl.yo b/Doc/Zsh/compctl.yo index 2c84f853f..fa13a747e 100644 --- a/Doc/Zsh/compctl.yo +++ b/Doc/Zsh/compctl.yo @@ -69,7 +69,7 @@ search is retried with the last pathname component. If the command starts with a tt(=), completion is tried with the pathname of the command. Any of the var(command) strings may be patterns of the form normally -used for filename generation. These should be be quoted to protect them +used for filename generation. These should be quoted to protect them from immediate expansion; for example the command string tt('foo*') arranges for completion of the words of any command beginning with tt(foo). When completion is attempted, all pattern completions are diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 4a24df74e..ad2562a26 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -447,7 +447,7 @@ directly. findex(compdef) cindex(completion system, adding definitions) startitem() -xitem(tt(compdef) [ tt(-an) ] var(function names...) [ tt(-[pP]) var(patterns...) [ tt(-N) var(names...) ] ]) +xitem(tt(compdef) [ tt(-ane) ] var(function names...) [ tt(-[pP]) var(patterns...) [ tt(-N) var(names...) ] ]) xitem(tt(compdef -d) var(names...)) xitem(tt(compdef -k) [ tt(-an) ] var(function style key-sequences...)) item(tt(compdef -K) [ tt(-an) ] var(function name style key-sequences ...))( @@ -460,11 +460,14 @@ defined by `var(cmd1)tt(=)var(service)' lines in tt(#compdef) files, as described above. The argument for var(cmd) will be completed in the same way as var(service). -The var(function) argument may alternatively be a string containing any -shell code. The string will be executed using the tt(eval) builtin -command to generate completions. This provides a way of avoiding having -to define a new completion function. For example, to complete -files ending in `tt(.h)' as arguments to the command tt(foo): +The var(function) argument may alternatively be a string containing +almost any shell code. If the string contains an equal sign, the above +will take precedence. The option tt(-e) may be used to specify the first +argument is to be evaluated as shell code even if it contains an equal +sign. The string will be executed using the tt(eval) builtin command to +generate completions. This provides a way of avoiding having to define +a new completion function. For example, to complete files ending in +`tt(.h)' as arguments to the command tt(foo): example(compdef '_files -g "*.h"' foo) @@ -783,7 +786,9 @@ for names of device special files ) kindex(directories, completion tag) item(tt(directories))( -for names of directories +for names of directories DASH()- tt(local-directories) is used instead +when completing arguments of tt(cd) and related builtin commands when +the tt(cdpath) array is set ) kindex(directory-stack, completion tag) item(tt(directory-stack))( @@ -876,7 +881,8 @@ kindex(local-directories, completion tag) item(tt(local-directories))( for names of directories that are subdirectories of the current working directory when completing arguments of tt(cd) and related builtin -commands (compare tt(path-directories)) +commands (compare tt(path-directories)) DASH()- when the tt(cdpath) +array is unset, tt(directories) is used instead ) kindex(manuals, completion tag) item(tt(manuals))( @@ -1931,7 +1937,7 @@ changing the foreground background colour, are also available, as is the form (or, with a numeric argument, some other) width. After deleting this prompt the variable tt(LISTPROMPT) should be unset for -the the removal to take effect. +the removal to take effect. ) kindex(list-rows-first, completion style) item(tt(list-rows-first))( @@ -2298,13 +2304,29 @@ The default value for this style is `false'. ) kindex(prefix-needed, completion style) item(tt(prefix-needed))( -This, too, is used for matches with a common prefix. If it is set to -`true' this common prefix must be typed by the user to generate the -matches. In the case of command options, this means that the initial -`tt(-)', `tt(+)', or `tt(-)tt(-)' must be typed explicitly before option -names will be completed. +This style is also relevant for matches with a common prefix. If it is +set to `true' this common prefix must be typed by the user to generate +the matches. -The default value for this style is `true'. +The style is applicable to the tt(options), tt(signals), tt(jobs), +tt(functions), and tt(parameters) completion tags. + +For command options, this means that the initial `tt(-)', `tt(+)', or +`tt(-)tt(-)' must be typed explicitly before option names will be +completed. + +For signals, an initial `tt(-)' is required before signal names will +be completed. + +For jobs, an initial `tt(%)' is required before job names will be +completed. + +For function and parameter names, an initial `tt(_)' or `tt(.)' is +required before function or parameter names starting with those +characters will be completed. + +The default value for this style is `false' for tt(function) and +tt(parameter) completions, and `true' otherwise. ) kindex(preserve-prefix, completion style) item(tt(preserve-prefix))( @@ -2646,7 +2668,7 @@ most commands. ) kindex(urls, completion style) item(tt(urls))( -This is used together with the the tt(urls) tag by +This is used together with the tt(urls) tag by functions completing URLs. If the value consists of more than one string, or if the only string @@ -2667,11 +2689,11 @@ descend as deep as necessary. For example, example(zstyle ':completion:*' urls ~/.urls -mkdir -p ~/.urls/ftp/ftp.zsh.org/pub/development +mkdir -p ~/.urls/ftp/ftp.zsh.org/pub ) allows completion of all the components of the URL -tt(ftp://ftp.zsh.org/pub/development) after suitable commands such as +tt(ftp://ftp.zsh.org/pub) after suitable commands such as `tt(netscape)' or `tt(lynx)'. Note, however, that access methods and files are completed separately, so if the tt(hosts) style is set hosts can be completed without reference to the tt(urls) style. @@ -2717,17 +2739,6 @@ where the tt(hosts) style is set; note also it must be set before the cache of host names is generated (typically the first completion attempt). ) -kindex(use-perl, completion style) -item(tt(use-perl))( -Various parts of the function system use awk to extract words from -files or command output as it is universally available. However, many -versions of awk have arbitrary limits on the size of input. If this -style is set, perl will be used instead. This is almost always -preferable if perl is available on your system. - -Currently this is only used in completions for `make', but it may be -extended depending on authorial frustration. -) kindex(users, completion style) item(tt(users))( This may be set to a list of usernames to be completed. @@ -3400,7 +3411,7 @@ tt(compadd) with additional options which will take precedence over those generated by tt(_all_labels). ) findex(_alternative) -item(tt(_alternative) [ tt(-C) var(name) ] var(spec) ...)( +item(tt(_alternative) [ tt(-O) var(name) ] [ tt(-C) var(name) ] var(spec) ...)( This function is useful in simple cases where multiple tags are available. Essentially it implements a loop like the one described for the tt(_tags) function below. @@ -3427,6 +3438,10 @@ the actions, which will loop over all sets of tags. Special handling is only required if there is an additional valid tag, for example inside a function called from tt(_alternative). +The option `tt(-O) var(name)' is used in the same way as by the +tt(_arguments) function. In other words, the elements of the var(name) +array will be passed to tt(compadd) when executing an action. + Like tt(_tags) this function supports the tt(-C) option to give a different name for the argument context field. ) diff --git a/Doc/Zsh/compwid.yo b/Doc/Zsh/compwid.yo index 06689746c..3042fa373 100644 --- a/Doc/Zsh/compwid.yo +++ b/Doc/Zsh/compwid.yo @@ -239,7 +239,7 @@ one more than the maximum selects the first. Unless the value of this key ends in a space, the match is inserted as in a menu completion, i.e. without automatically appending a space. -Both tt(menu) and tt(automenu) may also specify the the number of the +Both tt(menu) and tt(automenu) may also specify the number of the match to insert, given after a colon. For example, `tt(menu:2)' says to start menu completion, beginning with the second match. diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index c02d33cf1..cf42e28a9 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -302,10 +302,13 @@ called at the same point; these are so-called `hook functions'. The shell function tt(add-zsh-hook) provides a simple way of adding or removing functions from the array. -var(hook) is one of tt(chpwd), tt(periodic), tt(precmd) or tt(preexec), -the special functions in question. +var(hook) is one of tt(chpwd), tt(periodic), tt(precmd), tt(preexec), +tt(zshaddhistory), tt(zshexit), or tt(zsh_directory_name), +the special functions in question. Note that tt(zsh_directory_name) +is called in a different way from the other functions, but may +still be manipulated as a hook. -var(functions) is name of an ordinary shell function. If no options +var(function) is name of an ordinary shell function. If no options are given this will be added to the array of functions to be executed in the given context. @@ -315,6 +318,10 @@ the array of functions to be executed. If the option tt(-D) is given, the var(function) is treated as a pattern and any matching names of functions are removed from the array of functions to be executed. + +The options tt(-U), tt(-z) and tt(-k) are passed as arguments to +tt(autoload) for var(function). For functions contributed with zsh, the +options tt(-Uz) are appropriate. ) enditem() @@ -355,7 +362,7 @@ subsect(Use) All direct user interaction is via the tt(cdr) function. The argument to cdr is a number var(N) corresponding to the var(N)th most -recently changed-to directory. 1 is the immediately preceeding directory; +recently changed-to directory. 1 is the immediately preceding directory; the current directory is remembered but is not offered as a destination. Note that if you have multiple windows open 1 may refer to a directory changed to in another window; you can avoid this by having per-terminal @@ -544,36 +551,15 @@ enditem() subsect(Use with dynamic directory naming) It is possible to refer to recent directories using the dynamic directory -name syntax that appeared in zsh version 4.3.7. If you create and -autoload a function tt(zsh_directory_name) containing the following code, -tt(~[1]) will refer to the most recent directory other than $PWD, and so on. -This also includes completion. - -example(if [[ $1 = n ]]; then - if [[ $2 = <-> ]]; then - # Recent directory - typeset -ga reply - autoload -Uz cdr - cdr -r - if [[ -n ${reply[$2]} ]]; then - reply=LPAR()${reply[$2]}RPAR() - return 0 - else - reply=LPAR()RPAR() - return 1 - fi - fi -elif [[ $1 = c ]]; then - if [[ $PREFIX = <-> || -z $PREFIX ]]; then - typeset -a keys values - values=LPAR()${${(f)"$+LPAR()cdr -l+RPAR()"}/ ##/:}RPAR() - keys=LPAR()${values%%:*}RPAR() - _describe -t dir-index 'recent directory index' \ - values keys -V unsorted -S']' - return - fi -fi -return 1) +name syntax by using the supplied function tt(zsh_directory_name_cdr) +a hook: + +example(autoload -Uz add-zsh-hook +add-zsh-hook -Uz zsh_directory_name zsh_directory_name_cdr) + +When this is done, tt(~[1]) will refer to the most recent +directory other than $PWD, and so on. Completion after tt(~[)var(...) +also works. subsect(Details of directory handling) @@ -614,6 +600,7 @@ sitem(Bazaar (tt(bzr)))(http://bazaar-vcs.org/) sitem(Codeville (tt(cdv)))(http://codeville.org/) sitem(Concurrent Versioning System (tt(cvs)))(http://www.nongnu.org/cvs/) sitem(Darcs (tt(darcs)))(http://darcs.net/) +sitem(Fossil (tt(fossil)))(http://fossil-scm.org/) sitem(Git (tt(git)))(http://git-scm.com/) sitem(GNU arch (tt(tla)))(http://www.gnu.org/software/gnu-arch/) sitem(Mercurial (tt(hg)))(http://mercurial.selenic.com/) @@ -663,6 +650,7 @@ bzr cdv cvs darcs +fossil git hg mtn @@ -706,8 +694,9 @@ example(:vcs_info:<vcs-string>:<user-context>:<repo-root-name>) startitem() item(tt(<vcs-string>))( is one of: git, git-svn, git-p4, hg, hg-git, hg-hgsubversion, hg-hgsvn, -darcs, bzr, cdv, mtn, svn, cvs, svk, tla or p4. When hooks are active the -hooks name is added after a `+'. (See tt(Hooks in vcs_info) below.) +darcs, bzr, cdv, mtn, svn, cvs, svk, tla, p4 or fossil. When hooks are +active the hooks name is added after a `+'. (See tt(Hooks in vcs_info) +below.) ) item(tt(<user-context>))( is a freely configurable string, assignable by @@ -767,11 +756,11 @@ revision number. This style lets you modify how that string should look. ) kindex(nvcsformats) item(tt(nvcsformats))( -These "formats" are exported when we didn't detect -a version control system for the current directory. This is useful if you -want var(vcs_info) to completely take over the generation of your prompt. -You would do something like tt(PS1='${vcs_info_msg_0_}') to accomplish -that. +These "formats" are exported when we didn't detect a version control system +for the current directory or var(vcs_info) was disabled. This is useful if +you want var(vcs_info) to completely take over the generation of your +prompt. You would do something like tt(PS1='${vcs_info_msg_0_}') to +accomplish that. ) kindex(hgrevformat) item(tt(hgrevformat))( @@ -837,6 +826,10 @@ these escapes can be controlled via the var(stagedstr) and var(unstagedstr) styles. The only backends that currently support this option are tt(git) and tt(hg) (tt(hg) only supports unstaged). +For this style to be evaluated with the tt(hg) backend, the var(get-revision) +style needs to be set and the var(use-simple) style needs to be unset. The +latter is the default; the former is not. + Note, the actions taken if this style is enabled are potentially expensive (read: they may be slow, depending on how big the current repository is). Therefore, it is disabled by default. @@ -1128,6 +1121,24 @@ tt(Variable description) below). If an argument is given, that string will be used instead of tt(default) in the tt(user-context) field of the style context. ) +findex(vcs_info_hookadd) +item(tt(vcs_info_hookadd))( +Statically registers a number of functions to a given hook. The hook needs +to be given as the first argument; what follows is a list of hook-function +names to register to the hook. The `tt(+vi-)' prefix needs to be left out +here. See tt(Hooks in vcs_info) below for details. +) +findex(vcs_info_hookdel) +item(tt(vcs_info_hookdel))( +Remove hook-functions from a given hook. The hook needs to be given as the +first non-option argument; what follows is a list of hook-function +names to un-register from the hook. If `tt(-a)' is used as the first +argument, tt(all) occurances of the functions are unregistered. Otherwise +only the last occurance is removed (if a function was registered to a hook +more than once) . The `tt(+vi-)' prefix needs to be left out here. See +tt(Hooks in vcs_info) below for details. +) +findex(vcs_info_lastmsg) item(tt(vcs_info_lastmsg))( Outputs the last var(${vcs_info_msg_*_}) value. Takes into account the value of the tt(use-prompt-escapes) style in @@ -1140,6 +1151,7 @@ Prints a list of all supported version control systems. Useful to find out possible contexts (and which of them are enabled) or values for the var(disable) style. ) +findex(vcs_info_setsys) item(tt(vcs_info_setsys))( Initializes var(vcs_info)'s internal list of available backends. With this function, you can add support for new VCSs @@ -1187,13 +1199,20 @@ avoid namespace problems, all registered function names are prepended by a `+vi-', so the actual functions called for the `foo' hook are `tt(+vi-bar)' and `tt(+vi-baz)'. +If you would like to register a function to a hook regardless of the +current context, you may use the var(vcs_info_hookadd) function. To remove +a function that was added like that, the var(vcs_info_hookdel) function +can be used. + If something seems weird, you can enable the `debug' boolean style in the proper context and the hook-calling code will print what it tried to execute and whether the function in question existed. When you register more than one function to a hook, all functions are executed one after another until one function returns non-zero or until -all functions have been called. +all functions have been called. Context-sensitive hook functions are +executed tt(before) statically registered ones (the ones added by +var(vcs_info_hookadd)). You may pass data between functions via an associative array, tt(user_data). For example: @@ -1292,6 +1311,11 @@ When setting tt(ret) to non-zero, the string in tt(${hook_com[guards-string]}) will be used in the var(%g) escape in the tt(patch-format) and tt(nopatch-format) styles. ) +item(tt(no-vcs))( +This hooks is called when no version control system was detected. + +The `hook_com' parameter is not used. +) item(tt(post-quilt))( Called after the tt(quilt) support is done. The following information is passed as arguments to the hook: 1. the quilt-support mode (`addon' or @@ -1309,7 +1333,7 @@ The `tt(hook_com)' keys considered are `tt(branch)' and `tt(revision)'. They are set to the values figured out so far by var(vcs_info) and any change will be used directly when the actual replacement is done. -If tt(ret) is set to to non-zero, the string in +If tt(ret) is set to non-zero, the string in tt(${hook_com[branch-replace]}) will be used unchanged as the `tt(%b)' replacement in the variables set by var(vcs_info). ) @@ -1321,7 +1345,7 @@ The `tt(hook_com)' keys considered are `tt(hash)' and `tt(localrev)'. They are set to the values figured out so far by var(vcs_info) and any change will be used directly when the actual replacement is done. -If tt(ret) is set to to non-zero, the string in +If tt(ret) is set to non-zero, the string in tt(${hook_com[rev-replace]}) will be used unchanged as the `tt(%i)' replacement in the variables set by var(vcs_info). ) @@ -1346,7 +1370,7 @@ so even if you changed a value to your liking you can still get the original value in the next run. Changing the `tt(_orig)' values is probably not a good idea. -If tt(ret) is set to to non-zero, the string in +If tt(ret) is set to non-zero, the string in tt(${hook_com[message]}) will be used unchanged as the message by var(vcs_info). ) @@ -1771,22 +1795,6 @@ The tt(word-context) style is implemented by the function tt(match-word-context). This should not usually need to be called directly. ) -tindex(delete-whole-word-match) -item(tt(delete-whole-word-match))( -This is another function which works like the tt(-match) functions -described immediately above, i.e. using styles to decide the word -boundaries. However, it is not a replacement for any existing function. - -The basic behaviour is to delete the word around the cursor. There is no -numeric prefix handling; only the single word around the cursor is -considered. If the widget contains the string tt(kill), the removed text -will be placed in the cutbuffer for future yanking. This can be obtained -by defining tt(kill-whole-word-match) as follows: - -example(zle -N kill-whole-word-match delete-whole-word-match) - -and then binding the widget tt(kill-whole-word-match). -) tindex(copy-earlier-word) item(tt(copy-earlier-word))( This widget works like a combination of tt(insert-last-word) and @@ -1818,6 +1826,33 @@ This widget allows the cursor to be easily moved to the other interesting spots. It can be invoked repeatedly to cycle between all positions reported by the completion system. ) +tindex(delete-whole-word-match) +item(tt(delete-whole-word-match))( +This is another function which works like the tt(-match) functions +described immediately above, i.e. using styles to decide the word +boundaries. However, it is not a replacement for any existing function. + +The basic behaviour is to delete the word around the cursor. There is no +numeric prefix handling; only the single word around the cursor is +considered. If the widget contains the string tt(kill), the removed text +will be placed in the cutbuffer for future yanking. This can be obtained +by defining tt(kill-whole-word-match) as follows: + +example(zle -N kill-whole-word-match delete-whole-word-match) + +and then binding the widget tt(kill-whole-word-match). +) +tindex(down-line-or-beginning-search) +tindex(up-line-or-beginning-search) +item(tt(up-line-or-beginning-search), tt(down-line-or-beginning-search))( +These widgets are similar to the builtin functions tt(up-line-or-search) +and tt(down-line-or-search): if in a multiline buffer they move up or +down within the buffer, otherwise they search for a history line matching +the start of the current line. In this case, however, they search for +a line which matches the current line up to the current cursor position, in +the manner of tt(history-beginning-search-backward) and tt(-forward), rather +than the first word on the line. +) tindex(edit-command-line) item(tt(edit-command-line))( Edit the command line using your visual editor, as in tt(ksh). @@ -1890,17 +1925,6 @@ example(autoload -U history-pattern-search zle -N history-pattern-search-backward history-pattern-search zle -N history-pattern-search-forward history-pattern-search) ) -tindex(up-line-or-beginning-search) -tindex(down-line-or-beginning-search) -item(tt(up-line-or-beginning-search), tt(down-line-or-beginning-search))( -These widgets are similar to the builtin functions tt(up-line-or-search) -and tt(down-line-or-search): if in a multiline buffer they move up or -down within the buffer, otherwise they search for a history line matching -the start of the current line. In this case, however, they search for -a line which matches the current line up to the current cursor position, in -the manner of tt(history-beginning-search-backward) and tt(-forward), rather -than the first word on the line. -) tindex(incarg) vindex(incarg, use of) item(tt(incarg))( @@ -1964,7 +1988,7 @@ See tt(insert-unicode-char) for an alternative way of inserting Unicode characters using their hexadecimal character number. The set of accented characters is reasonably complete up to Unicode -character U+0180, the set of special characters less so. However, it it +character U+0180, the set of special characters less so. However, it is very sporadic from that point. Adding new characters is easy, however; see the function tt(define-composed-chars). Please send any additions to tt(zsh-workers@zsh.org). @@ -2130,6 +2154,17 @@ into the command line. example(bindkey '^Xf' insert-files) ) +tindex(insert-unicode-char) +item(tt(insert-unicode-char))( +When first executed, the user inputs a set of hexadecimal digits. +This is terminated with another call to tt(insert-unicode-char). +The digits are then turned into the corresponding Unicode character. +For example, if the widget is bound to tt(^XU), the character sequence +`tt(^XU 4 c ^XU)' inserts tt(L) (Unicode U+004c). + +See tt(insert-composed-char) for a way of inserting characters +using a two-character mnemonic. +) tindex(narrow-to-region) tindex(narrow-to-region-invisible) xitem(tt(narrow-to-region [ -p) var(pre) tt(] [ -P) var(post) tt(])) @@ -2187,17 +2222,6 @@ narrow-to-region -p $'Editing restricted region\n' \ zle recursive-edit narrow-to-region -R state) ) -tindex(insert-unicode-char) -item(tt(insert-unicode-char))( -When first executed, the user inputs a set of hexadecimal digits. -This is terminated with another call to tt(insert-unicode-char). -The digits are then turned into the corresponding Unicode character. -For example, if the widget is bound to tt(^XU), the character sequence -`tt(^XU 4 c ^XU)' inserts tt(L) (Unicode U+004c). - -See tt(insert-composed-char) for a way of inserting characters -using a two-character mnemonic. -) tindex(predict-on) tindex(predict-off) item(tt(predict-on))( @@ -2325,6 +2349,25 @@ tt(narrow-to-region-invisible) widget. One limitation of the current version is that tt(undo) will cycle through changes to the replacement and source strings before undoing the replacement itself. ) +tindex(send-invisible) +item(tt(send-invisible))( +This is similar to read-from-minibuffer in that it may be called as a +function from a widget or as a widget of its own, and interactively reads +input from the keyboard. However, the input being typed is concealed and +a string of asterisks (`tt(*)') is shown instead. The value is saved in +the paramter tt($INVISIBLE) to which a reference is inserted into the +editing buffer at the restored cursor position. If the read was aborted +by a keyboard break (typically tt(^G)) or another escape from editing such +as tt(push-line), tt($INVISIBLE) is set to empty and the original buffer +is restored unchanged. + +If one argument is supplied to the function it is taken as a prompt, +otherwise `tt(Non-echoed text: )' is used (as in emacs). If a second and +third argument are supplied they are used to begin and end the reference +to tt($INVISIBLE) that is inserted into the buffer. The default is to +open with tt(${), then tt(INVISIBLE), and close with tt(}), but many +other effects are possible. +) tindex(smart-insert-last-word) item(tt(smart-insert-last-word))( This function may replace the tt(insert-last-word) widget, like so: @@ -3000,7 +3043,7 @@ tt(firefox mozilla netscape opera konqueror). ) item(tt(tty-browsers))( An array similar to tt(x-browsers), except that it gives browsers to -use use when no X Window display is available. The default is +use when no X Window display is available. The default is tt(elinks links lynx). ) item(tt(command))( diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index d246c3c23..ce122cade 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -381,7 +381,7 @@ Each part of a command argument that takes the form `tt(<LPAR())var(list)tt(RPAR())', `tt(>LPAR())var(list)tt(RPAR())' or `tt(=LPAR())var(list)tt(RPAR())' -is subject to process substitution. The expression may be preceeded +is subject to process substitution. The expression may be preceded or followed by other strings except that, to prevent clashes with commonly occurring strings and patterns, the last form must occur at the start of a command argument, and the forms @@ -588,7 +588,7 @@ remove the non-matched elements). xitem(tt(${)var(name)tt(:)var(offset)tt(})) item(tt(${)var(name)tt(:)var(offset)tt(:)var(length)tt(}))( This syntax gives effects similar to parameter subscripting -in the form tt($)var(name)tt({)var(start)tt(,)var(end)tt(}), but is +in the form tt($)var(name)tt([)var(start)tt(,)var(end)tt(]), but is compatible with other shells; note that both var(offset) and var(length) are interpreted differently from the components of a subscript. @@ -608,8 +608,12 @@ the option tt(KSH_ARRAYS). A negative offset counts backwards from the end of the scalar or array, so that -1 corresponds to the last character or element, and so on. -var(length) is always treated directly as a length and hence may not be -negative. The option tt(MULTIBYTE) is obeyed, i.e. the offset and length +When positive, var(length) counts from the var(offset) position +toward the end of the scalar or array. When negative, var(length) +counts back from the end. If this results in a position smaller +than var(offset), a diagnostic is printed and nothing is substituted. + +The option tt(MULTIBYTE) is obeyed, i.e. the offset and length count multibyte characters where appropriate. var(offset) and var(length) undergo the same set of shell substitutions @@ -635,7 +639,7 @@ tt(${)var(name)tt(:-)var(word)tt(}) form of substitution. Instead, a space may be inserted before the tt(-). Furthermore, neither var(offset) nor var(length) may begin with an alphabetic character or tt(&) as these are used to indicate history-style modifiers. To substitute a value from a -variable, the recommended approach is to proceed it with a tt($) as this +variable, the recommended approach is to precede it with a tt($) as this signifies the intention (parameter substitution can easily be rendered unreadable); however, as arithmetic substitution is performed, the expression tt(${var: offs}) does work, retrieving the offset from @@ -809,7 +813,7 @@ item(tt(@))( In double quotes, array elements are put into separate words. E.g., `tt("${(@)foo}")' is equivalent to `tt("${foo[@]}")' and `tt("${(@)foo[1,2]}")' is the same as `tt("$foo[1]" "$foo[2]")'. -This is distinct from em(field splitting) by the the tt(f), tt(s) +This is distinct from em(field splitting) by the tt(f), tt(s) or tt(z) flags, which still applies within each array element. ) item(tt(A))( @@ -859,6 +863,14 @@ item(tt(F))( Join the words of arrays together using newline as a separator. This is a shorthand for `tt(pj:\n:)'. ) +item(tt(g:opts:))( +Process escape sequences like the echo builtin when no options are given +(tt(g::)). With the tt(o) option, octal escapes don't take a leading +zero. With the tt(c) option, sequences like `tt(^X)' are also processed. +With the tt(e) option, processes `tt(\M-t)' and similar sequences like the +print builtin. With both of the tt(o) and tt(e) options, behaves like the +print builtin except that in none of these modes is `tt(\c)' interpreted. +) item(tt(i))( Sort case-insensitively. May be combined with `tt(n)' or `tt(O)'. ) @@ -1104,7 +1116,9 @@ Force field splitting at the separator var(string). Note that a var(string) of two or more characters means that all of them must match in sequence; this differs from the treatment of two or more characters in the tt(IFS) parameter. -See also the tt(=) flag and the tt(SH_WORD_SPLIT) option. +See also the tt(=) flag and the tt(SH_WORD_SPLIT) option. An empty +string may also be given in which case every character will be a separate +element. For historical reasons, the usual behaviour that empty array elements are retained inside double quotes is disabled for arrays generated @@ -1288,8 +1302,9 @@ item(tt(11.) em(Case modification))( Any case modification from one of the flags tt((L)), tt((U)) or tt((C)) is applied. ) -item(tt(12.) em(Prompt evaluation))( -Any prompt-style formatting from the tt((%)) family of flags is applied. +item(tt(12.) em(Escape sequence replacement))( +First any replacements from the tt((g)) flag are performed, then any +prompt-style formatting from the tt((%)) family of flags is applied. ) item(tt(13.) em(Quote application))( Any quoting or unquoting using tt((q)) and tt((Q)) and related flags @@ -1517,8 +1532,12 @@ cindex(directories, named, dynamic) cindex(named directories, dynamic) cindex(dynamic named directories) -The feature described here is only available if the shell function -tt(zsh_directory_name) exists. +If the function tt(zsh_directory_name) exists, or the shell variable +tt(zsh_directory_name_functions) exists and contains an array of +function names, then the functions are used to implement dynamic +directory naming. The functions are tried in order until one returns +status zero, so it is important that functions test whether they can +handle the case in question and return an appropriate status. A `tt(~)' followed by a string var(namstr) in unquoted square brackets is treated specially as a dynamic directory name. Note that the first @@ -1529,11 +1548,12 @@ which is the directory corresponding to the name and return status zero (executing an assignment as the last statement is usually sufficient), or it should return status non-zero. In the former case the element of reply is used as the directory; in the latter case the substitution is deemed to -have failed and tt(NOMATCH) handling is applied if the option is set. +have failed. If all functions fail and the option tt(NOMATCH) is set, +an error results. -The function tt(zsh_directory_name) is also used to see if a directory can +The functions defined as above are also used to see if a directory can be turned into a name, for example when printing the directory stack or -when expanding tt(%~) in prompts. In this case the function is passed two +when expanding tt(%~) in prompts. In this case each function is passed two arguments: the string tt(d) (for directory) and the candidate for dynamic naming. The function should either return non-zero status, if the directory cannot be named by the function, or it should set the array reply @@ -1551,7 +1571,15 @@ parts of the directory path, as described below; it is used if the prefix length matched (16 in the example) is longer than that matched by any static name. -The completion system calls `tt(zsh_directory_name c)' in order to +It is not a requirement that a function implements both +tt(n) and tt(d) calls; for example, it might be appropriate for certain +dynamic forms of expansion not to be contracted to names. In that case +any call with the first argument tt(d) should cause a non-zero status to +be returned. + +The completion system calls `tt(zsh_directory_name c)' followed by +equivalent calls to elements of the array +tt(zsh_directory_name_functions), if it exists, in order to complete dynamic names for directories. The code for this should be as for any other completion function as described in ifnzman(noderef(Completion System))\ diff --git a/Doc/Zsh/ftp_sites.yo b/Doc/Zsh/ftp_sites.yo new file mode 100644 index 000000000..3ed675ab1 --- /dev/null +++ b/Doc/Zsh/ftp_sites.yo @@ -0,0 +1,28 @@ +startitem() +item(Primary site)( +nofill(tt(ftp://ftp.zsh.org/pub/) +tt(http://www.zsh.org/pub/)) +) +item(Australia)( +nofill(tt(ftp://ftp.zsh.org/pub/) +tt(http://www.zsh.org/pub/)) +) +item(Denmark)( +nofill(tt(ftp://mirrors.dotsrc.org/zsh/)) +) +item(Finland)( +nofill(tt(ftp://ftp.funet.fi/pub/unix/shells/zsh/)) +) +item(France)( +nofill(tt(ftp://nephtys.lip6.fr/pub/unix/shells/zsh/)) +) +item(Germany)( +nofill(tt(ftp://ftp.fu-berlin.de/pub/unix/shells/zsh/)) +) +item(Hungary)( +nofill(tt(ftp://ftp.kfki.hu/pub/packages/zsh/)) +) +item(Poland)( +nofill(tt(ftp://sunsite.icm.edu.pl/pub/unix/shells/zsh/)) +) +enditem() diff --git a/Doc/Zsh/func.yo b/Doc/Zsh/func.yo index 5f8df990e..28bc6329a 100644 --- a/Doc/Zsh/func.yo +++ b/Doc/Zsh/func.yo @@ -348,19 +348,32 @@ enditem() findex(trap, use of) The functions beginning `tt(TRAP)' may alternatively be defined with the -tt(trap) builtin: this may be preferable for some uses, as they are then -run in the environment of the calling process, rather than in their own -function environment. Apart from the difference in calling procedure and -the fact that the function form appears in lists of functions, the forms +tt(trap) builtin: this may be preferable for some uses. Setting a trap +with one form removes any trap of the other form for the same signal; +removing a trap in either form removes all traps for the same signal. +The forms example(TRAPNAL+LPAR()RPAR() { # code }) -and +('function traps') and example(trap ' # code ' NAL) -are equivalent. +('list traps') are equivalent in most ways, the exceptions being the +following: + +startitemize() +itemiz(Function traps have all the properties of normal functions, +appearing in the list of functions and being called with their own +function context rather than the context where the trap was triggered.) +itemiz(The return status from function traps is special, whereas a return +from a list trap causes the surrounding context to return with the given +status.) +itemiz(Function traps are not reset within subshells, in accordance with +zsh behaviour; list traps are reset, in accordance with POSIX +behaviour.) +enditemize() diff --git a/Doc/Zsh/metafaq.yo b/Doc/Zsh/metafaq.yo index 838c93815..34cd70e32 100644 --- a/Doc/Zsh/metafaq.yo +++ b/Doc/Zsh/metafaq.yo @@ -25,65 +25,7 @@ mirroring tt(ftp.cs.elte.hu) instead of the primary site. cindex(FTP sites for zsh) cindex(acquiring zsh by FTP) cindex(availability of zsh) -startitem() -item(Primary site)( -nofill(tt(ftp://ftp.zsh.org/pub/zsh/) -tt(http://www.zsh.org/pub/zsh/)) -) -item(Australia)( -nofill(tt(ftp://ftp.zsh.org/pub/zsh/) -tt(http://www.zsh.org/pub/zsh/)) -) -item(Finland)( -nofill(tt(ftp://ftp.funet.fi/pub/unix/shells/zsh/)) -) -item(Germany)( -nofill(tt(ftp://ftp.fu-berlin.de/pub/unix/shells/zsh/) em((H)) -tt(ftp://ftp.gmd.de/packages/zsh/) -tt(ftp://ftp.uni-trier.de/pub/unix/shell/zsh/)) -) -item(Hungary)( -nofill(tt(ftp://ftp.cs.elte.hu/pub/zsh/) -tt(http://www.cs.elte.hu/pub/zsh/) -tt(ftp://ftp.kfki.hu/pub/packages/zsh/)) -) -item(Israel)( -nofill(tt(ftp://ftp.math.technion.ac.il/pub/zsh/) -tt(http://www.math.technion.ac.il/pub/zsh/)) -) -item(Japan)( -nofill(tt(ftp://ftp.win.ne.jp/pub/shell/zsh/)) -) -item(Korea)( -nofill(tt(ftp://linux.sarang.net/mirror/system/shell/zsh/)) -) -item(Netherlands)( -nofill(tt(ftp://ftp.demon.nl/pub/mirrors/zsh/)) -) -item(Norway)( -nofill(tt(ftp://ftp.uit.no/pub/unix/shells/zsh/)) -) -item(Poland)( -nofill(tt(ftp://sunsite.icm.edu.pl/pub/unix/shells/zsh/)) -) -item(Romania)( -nofill(tt(ftp://ftp.roedu.net/pub/mirrors/ftp.zsh.org/pub/zsh/) -tt(ftp://ftp.kappa.ro/pub/mirrors/ftp.zsh.org/pub/zsh/)) -) -item(Slovenia)( -nofill(tt(ftp://ftp.siol.net/mirrors/zsh/)) -) -item(Sweden)( -nofill(tt(ftp://ftp.lysator.liu.se/pub/unix/zsh/)) -) -item(UK)( -nofill(tt(ftp://ftp.net.lut.ac.uk/zsh/) -tt(ftp://sunsite.org.uk/packages/zsh/)) -) -item(USA)( -nofill(tt(http://zsh.open-mirror.com/)) -) -enditem() +INCLUDEFILE(Zsh/ftp_sites.yo)\ The up-to-date source code is available via anonymous CVS and Git from Sourceforge. See tt(http://sourceforge.net/projects/zsh/) for details. diff --git a/Doc/Zsh/mod_complist.yo b/Doc/Zsh/mod_complist.yo index 954710cbc..09b2b4f8b 100644 --- a/Doc/Zsh/mod_complist.yo +++ b/Doc/Zsh/mod_complist.yo @@ -383,8 +383,8 @@ make the longest unambiguous string be inserted in the command line and tt(undo) and tt(backward-delete-char) go back to the previous set of matches ) -item(tt(history-incremental-search-forward), -tt(history-incremental-search-backward))( +xitem(tt(history-incremental-search-forward)) +item(tt(history-incremental-search-backward))( this starts incremental searches in the list of completions displayed; in this mode, tt(accept-line) only leaves incremental search, going back to the normal menu selection mode diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo index d553070a8..5948d74f2 100644 --- a/Doc/Zsh/mod_parameter.yo +++ b/Doc/Zsh/mod_parameter.yo @@ -164,6 +164,12 @@ item(tt(userdirs))( This associative array maps user names to the pathnames of their home directories. ) +vindex(usergroups) +item(tt(usergroups))( +This associative array maps names of system groups of which the current +user is a member to the corresponding group identifiers. The contents +are the same as the groups output by the tt(id) command. +) vindex(funcfiletrace) item(tt(funcfiletrace))( This array contains the absolute line numbers and corresponding file diff --git a/Doc/Zsh/mod_sched.yo b/Doc/Zsh/mod_sched.yo index 03ef3e54b..948001baf 100644 --- a/Doc/Zsh/mod_sched.yo +++ b/Doc/Zsh/mod_sched.yo @@ -39,6 +39,10 @@ the shell to clear the command line before the event and redraw it afterwards. This should be used with any scheduled event that produces visible output to the terminal; it is not needed, for example, with output that updates a terminal emulator's title bar. + +The tt(sched) builtin is not made available by default when the shell +starts in a mode emulating another shell. It can be made available +with the command `tt(zmodload -F zsh/sched b:sched)'. ) enditem() diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo index d3699b158..1838eab5e 100644 --- a/Doc/Zsh/mod_zutil.yo +++ b/Doc/Zsh/mod_zutil.yo @@ -178,7 +178,7 @@ item(tt(zregexparse))( This implements some internals of the tt(_regex_arguments) function. ) findex(zparseopts) -item(tt(zparseopts) [ tt(-D) ] [ tt(-K) ] [ tt(-E) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] var(specs))( +item(tt(zparseopts) [ tt(-D) ] [ tt(-K) ] [ tt(-M) ] [ tt(-E) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] var(specs))( This builtin simplifies the parsing of options in positional parameters, i.e. the set of arguments given by tt($*). Each var(spec) describes one option and must be of the form `var(opt)[tt(=)var(array)]'. If an option @@ -255,6 +255,15 @@ options and with the `tt(=)var(array)' forms are kept unchanged when none of the var(specs) for them is used. This allows assignment of default values to them before calling tt(zparseopts). ) +item(tt(-M))( +This changes the assignment rules to implement a map among equivalent +option names. If any var(spec) uses the `tt(=)var(array)' form, the +string var(array) is interpreted as the name of another var(spec), +which is used to choose where to store the values. If no other var(spec) +is found, the values are stored as usual. This changes only the way the +values are stored, not the way tt($*) is parsed, so results may be +unpredicable if the `var(name)tt(+)' specifier is used inconsistently. +) item(tt(-E))( This changes the parsing rules to em(not) stop at the first string that isn't described by one of the var(spec)s. It can be used to test @@ -288,5 +297,15 @@ set -- -a x -c z arg1 arg2) I.e., the option tt(-b) and its arguments are taken from the positional parameters and put into the array tt(bar). + +The tt(-M) option can be used like this: + +example(set -- -a -bx -c y -cz baz -cend +zparseopts -A bar -M a=foo b+: c:=b) + +to have the effect of + +example(foo=(-a) +bar=(-a '' -b xyz)) ) enditem() diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index a96597157..0e0176227 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -683,8 +683,12 @@ item(tt(SH_GLOB) <K> <S>)( Disables the special meaning of `tt(LPAR())', `tt(|)', `tt(RPAR())' and 'tt(<)' for globbing the result of parameter and command substitutions, and in some other places where -the shell accepts patterns. This option is set by default if zsh is -invoked as tt(sh) or tt(ksh). +the shell accepts patterns. If tt(SH_GLOB) is set but tt(KSH_GLOB) is +not, the shell allows the interpretation of +subshell expressions enclosed in parentheses in some cases where there +is no space before the opening parenthesis, e.g. tt(!LPAR()true+RPAR()) +is interpreted as if there were a space after the tt(!). This option is +set by default if zsh is invoked as tt(sh) or tt(ksh). ) pindex(UNSET) pindex(NO_UNSET) @@ -1866,6 +1870,10 @@ tt(source), tt(times), tt(trap) and tt(unset). + +In addition, various error conditions associated with the above builtins +or tt(exec) cause a non-interactive shell to exit and an interactive +shell to return to its top-level processing. ) pindex(POSIX_IDENTIFIERS) pindex(NO_POSIX_IDENTIFIERS) @@ -2016,7 +2024,7 @@ pindex(NO_LOGIN) pindex(NOLOGIN) item(tt(LOGIN) (tt(-l), ksh: tt(-l)))( This is a login shell. -If this option is not explicitly set, the shell is a login shell if +If this option is not explicitly set, the shell becomes a login shell if the first character of the tt(argv[0]) passed to the shell is a `tt(-)'. ) pindex(PRIVILEGED) diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index d0255af5a..22a00f5c2 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -1158,8 +1158,8 @@ item(tt(PROMPT_EOL_MARK))( When the tt(PROMPT_CR) and tt(PROMPT_SP) options are set, the tt(PROMPT_EOL_MARK) parameter can be used to customize how the end of partial lines are shown. This parameter undergoes prompt expansion, with -the tt(PROMPT_PERCENT) option set. If not set or empty, the default -behavior is equivalent to the value `tt(%B%S%#%s%b)'. +the tt(PROMPT_PERCENT) option set. If not set, the default behavior is +equivalent to the value `tt(%B%S%#%s%b)'. ) vindex(PS1) item(tt(PS1) <S>)( @@ -1273,6 +1273,13 @@ is necessary to make such an assignment upon any change to the terminal definition database or terminal type in order for the new settings to take effect. ) +vindex(TERMINFO) +item(tt(TERMINFO) <S>)( +A reference to a compiled description of the terminal, used by the +`terminfo' library when the system has it; see manref(terminfo)(5). +If set, this causes the shell to reinitialise the terminal, making +the workaround `tt(TERM=$TERM)' unnecessary. +) vindex(TIMEFMT) item(tt(TIMEFMT))( The format of process time reports with the tt(time) keyword. diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 591593d38..5f4d639d3 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -842,10 +842,7 @@ specifies that the first twenty characters of the text including any predisplay string should be highlighted in bold. Note that the effect of tt(region_highlight) is not saved and disappears -as soon as the line is accepted. The line editor makes no attempt to -keep the highlighting effect synchronised with the line as it is edited; -hence region highlighting is best limited to static effects within -user widgets. +as soon as the line is accepted. ) vindex(WIDGET) item(tt(WIDGET) (scalar))( @@ -857,7 +854,7 @@ The name of the shell function that implements a widget defined with either tt(zle -N) or tt(zle -C). In the former case, this is the second argument to the tt(zle -N) command that defined the widget, or the first argument if there was no second argument. In the latter case -this is the the third argument to the tt(zle -C) command that defined the +this is the third argument to the tt(zle -C) command that defined the widget. Read-only. ) vindex(WIDGETSTYLE) @@ -926,6 +923,10 @@ item(tt(zle-line-finish))( This is similar to tt(zle-line-init) but is executed every time the line editor has finished reading a line of input. ) +tindex(zle-history-line-set) +item(tt(zle-history-line-set))( +Executed when the history line changes. +) tindex(zle-keymap-select) item(tt(zle-keymap-select))( Executed every time the keymap changes, i.e. the special parameter @@ -1865,7 +1866,7 @@ executed as a shell command. tindex(accept-line-and-down-history) item(tt(accept-line-and-down-history) (^O) (unbound) (unbound))( Execute the current line, and push the next history -event on the the buffer stack. +event on the buffer stack. ) tindex(auto-suffix-remove) item(tt(auto-suffix-remove))( @@ -2149,7 +2150,7 @@ column of the cursor in the current line. ) tindex(where-is) item(tt(where-is))( -Read the name of an editor command and and print the listing of key +Read the name of an editor command and print the listing of key sequences that invoke the specified command. A restricted set of editing functions is available in the mini-buffer. Keys are looked up in the special @@ -2350,6 +2351,11 @@ Not all systems support this: for it to work, the system's representation of wide characters must be code values from the Universal Character Set, as defined by IS0 10646 (also known as Unicode). ) +item(Wrapped double-width characters)( +When a double-width character appears in the final column of a line, it +is instead shown on the next line. The empty space left in the original +position is highlighted as a special character. +) enditem() If tt(zle_highlight) is not set or no value applies to a particular diff --git a/Etc/CONTRIBUTORS b/Etc/CONTRIBUTORS index c3b80d7f9..6a0ea33ce 100644 --- a/Etc/CONTRIBUTORS +++ b/Etc/CONTRIBUTORS @@ -43,9 +43,9 @@ NISHIYAMA, Omari Norman, Mustafa Oezkan, Tomasz Pala, Peter Palfrader, Carlos Phillips, Daniel Qarras, Jean-Baptiste Quenot, David Riebenbauer, Haakon Riiser, Ingo Rohlfs, Felix Rosencrantz, Simon Ruderich, Stephen Rüger, William Scott, Kris Shannon, Jörg Sommer, Travis Spencer, Vincent -Steman, MÃ¥rten Svantesson, Evgenii Terechkov, Magnus Therning, Ingmar -Vanhassel, Markus Waldeck, Motoi Washida, Nikolai Weibull, Jesse -Weinstein. +Steman, MÃ¥rten Svantesson, Evgenii Terechkov, Magnus Therning, Bernhard +Tittelbach, Ingmar Vanhassel, Markus Waldeck, Motoi Washida, Nikolai +Weibull, Jesse Weinstein. Version 4.2 ----------- @@ -271,7 +271,7 @@ Version 3.0 including further texinfo documentation updates and maintained the zsh web pages during their tenure at www.mal.com. -* Wayne Davison <wayne@clari.net> improved the the zle search functions +* Wayne Davison <wayne@clari.net> improved the zle search functions and made them 8-bit clean. Some other little bugfixes. * Bart Schaefer <schaefer@zsh.org> submitted several bugfixes, reported diff --git a/Etc/ChangeLog-3.0 b/Etc/ChangeLog-3.0 index c53b2fb38..b55186822 100644 --- a/Etc/ChangeLog-3.0 +++ b/Etc/ChangeLog-3.0 @@ -2557,7 +2557,7 @@ Fri Jul 12 17:19:02 1996 Zoltán Hidvégi <hzoli@cs.elte.hu> noshortloops. If CSHJUNKIELOOPS is set accept repeat word list end. - * Doc/zshmisc.man: more precise definition the the syntax of + * Doc/zshmisc.man: more precise definition the syntax of complex commands * Src/parse.c: the repeat word sublist syntax does not work if diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo index a74d62ac5..509d924c5 100644 --- a/Etc/FAQ.yo +++ b/Etc/FAQ.yo @@ -42,7 +42,12 @@ whenhtml(report(ARG1)(ARG2)(ARG3))\ whenlatex(report(ARG1)(ARG2)(ARG3))\ whenman(report(ARG1)(ARG2)(ARG3))\ whenms(report(ARG1)(ARG2)(ARG3))\ -whensgml(report(ARG1)(ARG2)(ARG3))) +whensgml(report(ARG1)(ARG2)(ARG3)))\ +def(startitem)(0)() \ +def(enditem)(0)()\ +def(item)(2)( +ARG1: ARG2)\ +def(nofill)(1)(ARG1) myreport(Z-Shell Frequently-Asked Questions)(Peter Stephenson)(2010/02/15) COMMENT(-- the following are for Usenet and must appear first)\ description(\ @@ -297,7 +302,7 @@ sect(On what machines will it run?) sect(What's the latest version?) Zsh 4.2.7 is the latest production version. The latest development - version is 4.3.11; this contains support for multibyte character strings + version is 4.3.12; this contains support for multibyte character strings (such as UTF-8 locales). All the main features for multibyte support are now in place and this is likely soon to become the stable series 4.4. @@ -334,43 +339,7 @@ label(16) the shell. The following list also appears on the WWW at url(http://www.zsh.org/)(http://www.zsh.org/) . - description( - mydit(Home site) url(ftp://ftp.zsh.org/)(ftp://ftp.zsh.org/) - mydit() (also url(http://www.zsh.org/pub/zsh/) -(http://www.zsh.org/pub/zsh/)) - mydit(Denmark) url(ftp://mirrors.dotsrc.org/zsh/) -(ftp://mirrors.dotsrc.org/zsh/) - mydit() (also url(http://mirrors.dotsrc.org/zsh/) -(http://mirrors.dotsrc.org/zsh/)) - mydit(Finland) url(ftp://ftp.funet.fi/pub/unix/shells/zsh/) -(ftp://ftp.funet.fi/pub/unix/shells/zsh/) - mydit(France) url(ftp://nephtys.lip6.fr/pub/unix/shells/zsh/) -(ftp://nephtys.lip6.fr/pub/unix/shells/zsh/) - mydit(Germany) url(ftp://ftp.fu-berlin.de/pub/unix/shells/zsh/) -(ftp://ftp.fu-berlin.de/pub/unix/shells/zsh/) - mydit(Hungary) url(ftp://ftp.cs.elte.hu/pub/zsh/) -(ftp://ftp.cs.elte.hu/pub/zsh/) - mydit() (also url(http://www.cs.elte.hu/pub/zsh/) -(http://www.cs.elte.hu/pub/zsh/)) - mydit() url(ftp://ftp.kfki.hu/pub/packages/zsh/) -(ftp://ftp.kfki.hu/pub/packages/zsh/) - mydit(Israel) url(ftp://ftp.math.technion.ac.il/pub/zsh/) -(ftp://ftp.math.technion.ac.il/pub/zsh/) - mydit() (also url(http://www.math.technion.ac.il/pub/zsh/) -(http://www.math.technion.ac.il/pub/zsh/)) - mydit(Netherlands) url(ftp://ftp.demon.nl/pub/mirrors/zsh/) -(ftp://ftp.demon.nl/pub/mirrors/zsh/) - mydit(Poland) url(ftp://sunsite.icm.edu.pl/pub/unix/shells/zsh/) -(ftp://sunsite.icm.edu.pl/pub/unix/shells/zsh/) - mydit(Romania) url(ftp://ftp.kappa.ro/pub/mirrors/ftp.zsh.org/pub/zsh/) -(ftp://ftp.kappa.ro/pub/mirrors/ftp.zsh.org/pub/zsh/) - mydit(Sweden) url(ftp://ftp.lysator.liu.se/pub/unix/zsh/) -(ftp://ftp.lysator.liu.se/pub/unix/zsh/) - mydit(UK) url(ftp://sunsite.org.uk/packages/zsh/) -(ftp://sunsite.org.uk/packages/zsh/) - mydit(USA) url(http://zsh.open-mirror.com/) -(http://zsh.open-mirror.com/) - ) +includefile(../Doc/Zsh/ftp_sites.yo) A Windows port was created by Amol Deshpandem based on 3.0.5 (which is now rather old). This has now been restored and can be found at diff --git a/Functions/Calendar/calendar_parse b/Functions/Calendar/calendar_parse index 1025a9a25..fabaf7413 100644 --- a/Functions/Calendar/calendar_parse +++ b/Functions/Calendar/calendar_parse @@ -1,7 +1,7 @@ # Parse the line passed down in the first argument as a calendar entry. # Sets the values parsed into the associative array reply, consisting of: # time The time as an integer (as per EPOCHSECONDS) of the (next) event. -# text1 The text from the the line not including the date/time, but +# text1 The text from the line not including the date/time, but # including any WARN or RPT text. This is useful for rescheduling # events, since the keywords need to be retained in this case. # warntime Any warning time (WARN keyword) as an integer, else an empty diff --git a/Functions/Chpwd/.distfiles b/Functions/Chpwd/.distfiles index 39ccd830c..89779a686 100644 --- a/Functions/Chpwd/.distfiles +++ b/Functions/Chpwd/.distfiles @@ -5,4 +5,5 @@ _cdr chpwd_recent_add chpwd_recent_dirs chpwd_recent_filehandler +zsh_directory_name_cdr ' diff --git a/Functions/Chpwd/cdr b/Functions/Chpwd/cdr index 3025a9d5c..4f399106b 100644 --- a/Functions/Chpwd/cdr +++ b/Functions/Chpwd/cdr @@ -15,7 +15,7 @@ # changing directory permanently, see below. # # The argument to cdr is a number corresponding to the Nth most recently -# changed-to directory starting at 1 for the immediately preceeding +# changed-to directory starting at 1 for the immediately preceding # directory (the current directory is remembered but is not offered as a # destination). You can use directory arguments if you set the # recent-dirs-default style, see below; however, it should be noted diff --git a/Functions/Chpwd/zsh_directory_name_cdr b/Functions/Chpwd/zsh_directory_name_cdr new file mode 100644 index 000000000..09aa35a93 --- /dev/null +++ b/Functions/Chpwd/zsh_directory_name_cdr @@ -0,0 +1,25 @@ +if [[ $1 = n ]]; then + if [[ $2 = <-> ]]; then + # Recent directory + typeset -ga reply + autoload -Uz cdr + cdr -r + if [[ -n ${reply[$2]} ]]; then + reply=(${reply[$2]}) + return 0 + else + reply=() + return 1 + fi + fi +elif [[ $1 = c ]]; then + if [[ $PREFIX = <-> || -z $PREFIX ]]; then + typeset -a keys values + values=(${${(f)"$(cdr -l)"}/ ##/:}) + keys=(${values%%:*}) + _describe -t dir-index 'recent directory index' \ + values keys -V unsorted -S']' + return + fi +fi +return 1 diff --git a/Functions/Misc/add-zsh-hook b/Functions/Misc/add-zsh-hook index aedc1e754..c49688643 100644 --- a/Functions/Misc/add-zsh-hook +++ b/Functions/Misc/add-zsh-hook @@ -1,6 +1,6 @@ # Add to HOOK the given FUNCTION. # HOOK is one of chpwd, precmd, preexec, periodic, zshaddhistory, -# zshexit (the _functions subscript is not required). +# zshexit, zsh_directory_name (the _functions subscript is not required). # # With -d, remove the function from the hook instead; delete the hook # variable if it is empty. @@ -15,7 +15,10 @@ emulate -L zsh local -a hooktypes -hooktypes=(chpwd precmd preexec periodic zshaddhistory zshexit) +hooktypes=( + chpwd precmd preexec periodic zshaddhistory zshexit + zsh_directory_name +) local opt local -a autoopts diff --git a/Functions/Misc/colors b/Functions/Misc/colors index bef93c8c3..027ca9a14 100644 --- a/Functions/Misc/colors +++ b/Functions/Misc/colors @@ -1,6 +1,8 @@ # Put standard ANSI color codes in shell parameters for easy use. # Note that some terminals do not support all combinations. +emulate -L zsh + typeset -Ag color colour color=( diff --git a/Functions/Misc/sticky-note b/Functions/Misc/sticky-note index cfe9ea684..efe5ec1eb 100644 --- a/Functions/Misc/sticky-note +++ b/Functions/Misc/sticky-note @@ -19,7 +19,7 @@ # # Otherwise, invoke the line editor with the previous notes available # as an editor history. Two quick taps on the return/enter key finish -# the note, or you can use use ^X^W as usual (ZZ in vicmd mode). +# the note, or you can use ^X^W as usual (ZZ in vicmd mode). # The application is configured by three zstyles, all using the context # ":sticky-note". The first two styles are "notefile" and "maxnotes" diff --git a/Functions/Prompts/prompt_bigfade_setup b/Functions/Prompts/prompt_bigfade_setup index 4e9aafdb1..2d95f3143 100644 --- a/Functions/Prompts/prompt_bigfade_setup +++ b/Functions/Prompts/prompt_bigfade_setup @@ -31,7 +31,7 @@ prompt_bigfade_setup () { autoload -Uz prompt_special_chars prompt_special_chars - PS1="%B%F{$fadebar}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$userhost}%K{$fadebar}%n@%m%b%k%f%F{$fadebar}%K{black}$schars[260]$schars[261]$schars[262]$schars[333]%b%f%k%F{$fadebar}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$date}%K{black} %D{%a %b %d} %D{%I:%M:%S%P}$prompt_newline%B%F{$cwd}%K{black}$PWD>%b%f%k " + PS1="%B%F{$fadebar}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$userhost}%K{$fadebar}%n@%m%b%k%f%F{$fadebar}%K{black}$schars[260]$schars[261]$schars[262]$schars[333]%b%f%k%F{$fadebar}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$date}%K{black} %D{%a %b %d} %D{%I:%M:%S%P}$prompt_newline%B%F{$cwd}%K{black}%d>%b%f%k " PS2="%B%F{$fadebar}$schars[333]$schars[262]$schars[261]$schars[260]%b%F{$fadebar}%K{black}$schars[260]$schars[261]$schars[262]$schars[333]%F{$fadebar}%K{black}$schars[333]$schars[262]$schars[261]$schars[260]%B%F{$fadebar}>%b%f%k " prompt_opts=(cr subst percent) diff --git a/Functions/TCP/tcp_read b/Functions/TCP/tcp_read index 7d8acf865..f880395dd 100644 --- a/Functions/TCP/tcp_read +++ b/Functions/TCP/tcp_read @@ -1,7 +1,7 @@ # Helper function for reading input from a TCP connection. # Actually, the input doesn't need to be a TCP connection at all, it # is simply an input file descriptor. However, it must be contained -# in ${tcp_by_fd[$TCP_SESS]}. This is set set by tcp_open, but may be +# in ${tcp_by_fd[$TCP_SESS]}. This is set by tcp_open, but may be # set by hand. (Note, however, the blocking/timeout behaviour is usually # not implemented for reading from regular files.) # diff --git a/Functions/VCS_Info/.distfiles b/Functions/VCS_Info/.distfiles index 988e7ada4..b6e55d2fc 100644 --- a/Functions/VCS_Info/.distfiles +++ b/Functions/VCS_Info/.distfiles @@ -1,6 +1,8 @@ DISTFILES_SRC=' .distfiles vcs_info +vcs_info_hookadd +vcs_info_hookdel VCS_INFO_adjust VCS_INFO_bydir_detect VCS_INFO_check_com diff --git a/Functions/VCS_Info/Backends/.distfiles b/Functions/VCS_Info/Backends/.distfiles index 46e9d6e67..67fb06cda 100644 --- a/Functions/VCS_Info/Backends/.distfiles +++ b/Functions/VCS_Info/Backends/.distfiles @@ -4,6 +4,7 @@ VCS_INFO_detect_bzr VCS_INFO_detect_cdv VCS_INFO_detect_cvs VCS_INFO_detect_darcs +VCS_INFO_detect_fossil VCS_INFO_detect_git VCS_INFO_detect_hg VCS_INFO_detect_mtn @@ -15,6 +16,7 @@ VCS_INFO_get_data_bzr VCS_INFO_get_data_cdv VCS_INFO_get_data_cvs VCS_INFO_get_data_darcs +VCS_INFO_get_data_fossil VCS_INFO_get_data_git VCS_INFO_get_data_hg VCS_INFO_get_data_mtn diff --git a/Functions/VCS_Info/Backends/VCS_INFO_detect_fossil b/Functions/VCS_Info/Backends/VCS_INFO_detect_fossil new file mode 100644 index 000000000..551528361 --- /dev/null +++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_fossil @@ -0,0 +1,13 @@ +## vim:ft=zsh +## fossil support by: Mike Meyer <mwm@mired.org> +## Distributed under the same BSD-ish license as zsh itself. + +setopt localoptions NO_shwordsplit + +[[ $1 == '--flavours' ]] && return 1 + +VCS_INFO_check_com ${vcs_comm[cmd]} || return 1 +vcs_comm[detect_need_file]=_FOSSIL_ +VCS_INFO_bydir_detect . || return 1 + +return 0 diff --git a/Functions/VCS_Info/Backends/VCS_INFO_detect_hg b/Functions/VCS_Info/Backends/VCS_INFO_detect_hg index e2866afd5..a22c1ee0f 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_detect_hg +++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_hg @@ -7,7 +7,7 @@ setopt localoptions NO_shwordsplit [[ $1 == '--flavours' ]] && { print -l hg-git hg-hgsubversion hg-hgsvn; return 0 } VCS_INFO_check_com ${vcs_comm[cmd]} || return 1 -vcs_comm[detect_need_file]=store +vcs_comm[detect_need_file]="store data" VCS_INFO_bydir_detect '.hg' || return 1 if [[ -d ${vcs_comm[basedir]}/.hg/svn ]] ; then diff --git a/Functions/VCS_Info/Backends/VCS_INFO_detect_svn b/Functions/VCS_Info/Backends/VCS_INFO_detect_svn index bb9d083ac..a777ecc43 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_detect_svn +++ b/Functions/VCS_Info/Backends/VCS_INFO_detect_svn @@ -7,5 +7,5 @@ setopt localoptions NO_shwordsplit [[ $1 == '--flavours' ]] && return 1 VCS_INFO_check_com ${vcs_comm[cmd]} || return 1 -[[ -d ".svn" ]] && return 0 +{ [[ -f ".svn/entries" ]] || [[ -f ".svn/format" ]] } && return 0 return 1 diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_fossil b/Functions/VCS_Info/Backends/VCS_INFO_get_data_fossil new file mode 100644 index 000000000..fd0f8389e --- /dev/null +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_fossil @@ -0,0 +1,24 @@ +## vim:ft=zsh +## fossil support by: Mike Meyer (mwm@mired.org) +## Distributed under the same BSD-ish license as zsh itself. + +setopt localoptions extendedglob +local a b +local -A fsinfo +local fshash fsbranch changed merging action + +${vcs_comm[cmd]} status | + while IFS=: read a b; do + fsinfo[${a//-/_}]="${b## #}" + done + +fshash=${fsinfo[checkout]%% *} +fsbranch=${fsinfo[tags]%%, *} +changed=${(Mk)fsinfo:#(ADDED|EDITED|DELETED|UPDATED)*} +merging=${(Mk)fsinfo:#*_BY_MERGE*} +if [ -n "$merging" ]; then + action="merging" +fi + +VCS_INFO_formats "$action" "${fsbranch}" "${fsinfo[local_root]}" '' "$changed" "${fshash}" "${fsinfo[repository]}" +return 0 diff --git a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg index 8e91d2651..a1b87f59e 100644 --- a/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg +++ b/Functions/VCS_Info/Backends/VCS_INFO_get_data_hg @@ -50,7 +50,7 @@ if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-revision ; then "check-for-changes" || hgid_args+=( -r. ) local HGRCPATH - HGRCPATH="/dev/null" ${vcs_comm[cmd]} ${(z)hgid_args} \ + HGRCPATH="/dev/null" ${vcs_comm[cmd]} ${(z)hgid_args} 2> /dev/null \ | read -r r_csetid r_lrev r_branch fi fi diff --git a/Functions/VCS_Info/VCS_INFO_bydir_detect b/Functions/VCS_Info/VCS_INFO_bydir_detect index 0b5996fd8..70b0fb6fa 100644 --- a/Functions/VCS_Info/VCS_INFO_bydir_detect +++ b/Functions/VCS_Info/VCS_INFO_bydir_detect @@ -4,15 +4,17 @@ setopt localoptions NO_shwordsplit local dirname=$1 -local basedir="." realbasedir +local basedir="." realbasedir file realbasedir="$(VCS_INFO_realpath ${basedir})" while [[ ${realbasedir} != '/' ]]; do [[ -r ${realbasedir} ]] || return 1 if [[ -n ${vcs_comm[detect_need_file]} ]] ; then - [[ -d ${basedir}/${dirname} ]] && \ - [[ -e ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \ - break + [[ -d ${basedir}/${dirname} ]] && { + for file in ${(s: :)${vcs_comm[detect_need_file]}}; do + [[ -e ${basedir}/${dirname}/${file} ]] && break 2 + done + } else [[ -d ${basedir}/${dirname} ]] && break fi diff --git a/Functions/VCS_Info/VCS_INFO_hook b/Functions/VCS_Info/VCS_INFO_hook index 7274d726f..479f5968b 100644 --- a/Functions/VCS_Info/VCS_INFO_hook +++ b/Functions/VCS_Info/VCS_INFO_hook @@ -2,24 +2,36 @@ ## Written by Frank Terbeck <ft@bewatermyfriend.org> ## Distributed under the same BSD-ish license as zsh itself. -local hook func +local hook static func local -x context hook_name local -xi ret -local -a hooks +local -a hooks tmp local -i debug ret=0 hook_name="$1" shift context=":vcs_info:${vcs}+${hook_name}:${usercontext}:${rrn}" +static=":vcs_info-static_hooks:${hook_name}" zstyle -t "${context}" debug && debug=1 || debug=0 if (( debug )); then printf 'VCS_INFO_hook: running hook: "%s"\n' "${hook_name}" printf 'VCS_INFO_hook: current context: "%s"\n' "${context}" + printf 'VCS_INFO_hook: static context: "%s"\n' "${static}" fi -zstyle -a "${context}" hooks hooks || return 0 +zstyle -a "${static}" hooks hooks +if (( debug )); then + printf '+ static hooks: %s\n' "${(j:, :)hooks}" +fi +zstyle -a "${context}" hooks tmp +if (( debug )); then + printf '+ context hooks: %s\n' "${(j:, :)tmp}" +fi +hooks+=( "${tmp[@]}" ) +(( ${#hooks} == 0 )) && return 0 + # Protect some internal variables in hooks. The `-g' parameter to # typeset does *not* make the parameters global here (they are already # "*-local-export). It prevents typeset from creating *new* *local* diff --git a/Functions/VCS_Info/VCS_INFO_set b/Functions/VCS_Info/VCS_INFO_set index a2b838cdb..5087be43f 100644 --- a/Functions/VCS_Info/VCS_INFO_set +++ b/Functions/VCS_Info/VCS_INFO_set @@ -5,17 +5,13 @@ setopt localoptions noksharrays NO_shwordsplit local -i i j -if [[ $1 == '--clear' ]] ; then - for i in {0..9} ; do - unset vcs_info_msg_${i}_ - done -fi if [[ $1 == '--nvcs' ]] ; then [[ $2 == '-preinit-' ]] && (( maxexports == 0 )) && (( maxexports = 1 )) for i in {0..$((maxexports - 1))} ; do typeset -gx vcs_info_msg_${i}_= done VCS_INFO_nvcsformats $2 + [[ $2 != '-preinit-' ]] && VCS_INFO_hook "no-vcs" fi (( ${#msgs} - 1 < 0 )) && return 0 diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info index 6ce1cd702..513489b70 100644 --- a/Functions/VCS_Info/vcs_info +++ b/Functions/VCS_Info/vcs_info @@ -26,6 +26,8 @@ static_functions=( VCS_INFO_reposub VCS_INFO_set + vcs_info_hookadd + vcs_info_hookdel vcs_info_lastmsg vcs_info_printsys vcs_info_setsys @@ -35,6 +37,7 @@ for func in ${static_functions} ; do autoload -Uz ${func} done +[[ -n ${(Mk)parameters:#vcs_info_msg_<->_} ]] && unset ${parameters[(I)vcs_info_msg_<->_]} VCS_INFO_set --nvcs '-preinit-' vcs_info_setsys @@ -75,7 +78,7 @@ vcs_info () { (( ${#enabled} == 0 )) && enabled=( all ) if [[ -n ${(M)enabled:#(#i)none} ]] ; then - [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --clear + [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --nvcs return 0 fi @@ -88,7 +91,7 @@ vcs_info () { for pat in ${dps} ; do if [[ ${PWD} == ${~pat} ]] ; then - [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --clear + [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --nvcs return 0 fi done diff --git a/Functions/VCS_Info/vcs_info_hookadd b/Functions/VCS_Info/vcs_info_hookadd new file mode 100644 index 000000000..867f7e271 --- /dev/null +++ b/Functions/VCS_Info/vcs_info_hookadd @@ -0,0 +1,22 @@ +## vim:ft=zsh +## Written by Frank Terbeck <ft@bewatermyfriend.org> +## Distributed under the same BSD-ish license as zsh itself. + +emulate -L zsh +setopt extendedglob + +if (( ${#argv} < 2 )); then + print 'usage: vcs_info_hookadd <HOOK> <FUNCTION(s)...>' + return 1 +fi + +local hook func context +local -a old + +hook=$1 +shift +context=":vcs_info-static_hooks:${hook}" + +zstyle -a "${context}" hooks old +zstyle "${context}" hooks "${old[@]}" "$@" +return $? diff --git a/Functions/VCS_Info/vcs_info_hookdel b/Functions/VCS_Info/vcs_info_hookdel new file mode 100644 index 000000000..e09a0575e --- /dev/null +++ b/Functions/VCS_Info/vcs_info_hookdel @@ -0,0 +1,45 @@ +## vim:ft=zsh +## Written by Frank Terbeck <ft@bewatermyfriend.org> +## Distributed under the same BSD-ish license as zsh itself. + +emulate -L zsh +setopt extendedglob + +local -i all + +if [[ "x$1" == 'x-a' ]]; then + all=1 + shift +else + all=0 +fi + +if (( ${#argv} < 2 )); then + print 'usage: vcs_info_hookdel [-a] <HOOK> <FUNCTION(s)...>' + return 1 +fi + +local hook func context +local -a old + +hook=$1 +shift +context=":vcs_info-static_hooks:${hook}" + +zstyle -a "${context}" hooks old || return 0 +for func in "$@"; do + if [[ -n ${(M)old:#$func} ]]; then + old[(Re)$func]=() + else + printf 'Not statically registered to `%s'\'': "%s"\n' \ + "${hook}" "${func}" + continue + fi + if (( all )); then + while [[ -n ${(M)old:#$func} ]]; do + old[(Re)$func]=() + done + fi +done +zstyle "${context}" hooks "${old[@]}" +return $? diff --git a/Functions/Zftp/zfcput b/Functions/Zftp/zfcput index d8a8a60a3..85141b68d 100644 --- a/Functions/Zftp/zfcput +++ b/Functions/Zftp/zfcput @@ -23,7 +23,7 @@ if [[ $(echo abcd | tail +2c) = bcd ]]; then elif [[ $(echo abcd | tail --bytes=+2) = bcd ]]; then tailtype=b else - print "I can't get your \`tail' to start from from arbitrary characters.\n" \ + print "I can't get your \`tail' to start from arbitrary characters.\n" \ "If you know how to do this, let me know." 2>&1 return 1 fi diff --git a/Functions/Zle/.distfiles b/Functions/Zle/.distfiles index 2ec4adc22..22eef1e6e 100644 --- a/Functions/Zle/.distfiles +++ b/Functions/Zle/.distfiles @@ -33,6 +33,7 @@ read-from-minibuffer replace-string replace-string-again select-word-style +send-invisible smart-insert-last-word split-shell-arguments transpose-lines diff --git a/Functions/Zle/modify-current-argument b/Functions/Zle/modify-current-argument index 92ca7bdab..92851d600 100644 --- a/Functions/Zle/modify-current-argument +++ b/Functions/Zle/modify-current-argument @@ -14,7 +14,7 @@ setopt localoptions noksharrays multibyte local -a reply -integer REPLY REPLY2 +integer REPLY REPLY2 fromend endoffset autoload -Uz split-shell-arguments split-shell-arguments @@ -30,6 +30,13 @@ if (( REPLY & 1 )); then (( REPLY2 = ${#reply[REPLY]} + 1 )) fi +# Work out offset from end of string +(( fromend = $REPLY2 - ${#reply[REPLY]} - 1 )) +if (( fromend >= -1 )); then + # Cursor is near the end of the word, we'll try to keep it there. + endoffset=1 +fi + # Length of all characters before current. # Force use of character (not index) counting and join without IFS. integer wordoff="${(cj..)#reply[1,REPLY-1]}" @@ -37,15 +44,32 @@ integer wordoff="${(cj..)#reply[1,REPLY-1]}" # Replacement for current word. This could do anything to ${reply[REPLY]}. local ARG="${reply[REPLY]}" repl eval repl=\"$1\" + +if (( !endoffset )) && [[ ${repl[fromend,-1]} = ${ARG[fromend,-1]} ]]; then + # If the part of the string from here to the end hasn't changed, + # leave the cursor this distance from the end instead of the beginning. + endoffset=1 +fi + # New line: all words before and after current word, with # no additional spaces since we've already got the whitespace # and the replacement word in the middle. -BUFFER="${(j..)reply[1,REPLY-1]}${repl}${(j..)reply[REPLY+1,-1]}" - -# Keep cursor at same position in replaced word. -# Redundant here, but useful if $repl changes the length. -# Limit to the next position after the end of the word. -integer repmax=$(( ${#repl} + 1 )) -# Remember CURSOR starts from offset 0 for some reason, so -# subtract 1 from positions. -(( CURSOR = wordoff + (REPLY2 > repmax ? repmax : REPLY2) - 1 )) +local left="${(j..)reply[1,REPLY-1]}${repl}" +local right="${(j..)reply[REPLY+1,-1]}" + +if [[ endoffset -ne 0 && ${#repl} -ne 0 ]]; then + # Place cursor relative to end. + LBUFFER="$left" + RBUFFER="$right" + (( CURSOR += fromend )) +else + BUFFER="$left$right" + + # Keep cursor at same position in replaced word. + # Redundant here, but useful if $repl changes the length. + # Limit to the next position after the end of the word. + integer repmax=$(( ${#repl} + 1 )) + # Remember CURSOR starts from offset 0 for some reason, so + # subtract 1 from positions. + (( CURSOR = wordoff + (REPLY2 > repmax ? repmax : REPLY2) - 1 )) +fi diff --git a/Functions/Zle/send-invisible b/Functions/Zle/send-invisible new file mode 100644 index 000000000..d31fc76ae --- /dev/null +++ b/Functions/Zle/send-invisible @@ -0,0 +1,85 @@ +#autoload + +# send-invisible reads a line from the terminal, displaying an +# asterisk for each character typed. It stores the line in the +# global variable INVISIBLE, and when finished reading, inserts +# the string ${INVISIBLE} into the original command buffer. + +# If one argument is given, it is the prompt. The default is +# "Non-echoed text: " + +# If two or three arguments are given, they form the prefix and +# suffix of the inserted INVISIBLE. Defaults are '${' and '}' +# but these can be replaced, for example with '"${' and '}"' to +# enclose the whole word in double quotes, or '${(z)' and '}' to +# split the value of $INVISIBLE like the shell parser. + +# To use: +# autoload -Uz send-invisible +# zle -N send-invisible +# bindkey '^X ' send-invisible +# Or more elaborately: +# hidden-command() { send-invisible '% ' '${(z)' '}' } +# zle -N hidden-command +# bindkey '^X%' hidden-command + +# Shamelessly cribbed from read-from-minibuffer. + +emulate -L zsh + +# Hide the value of INVISIBLE in any output of set and typeset +typeset -g -H INVISIBLE= + +local pretext="$PREDISPLAY$LBUFFER$RBUFFER$POSTDISPLAY"$'\n' + +# Can't directly make these locals because send-invisible is +# called as a widget, so these special variables are already +# local at the current level and wouldn't get restored +local save_lbuffer=$LBUFFER +local save_rbuffer=$RBUFFER +local save_predisplay=$PREDISPLAY +local save_postdisplay=$POSTDISPLAY +local -a save_region_highlight +save_region_highlight=("${region_highlight[@]}") + +{ + local lb rb opn=${2:-'${'} cls=${3:-'}'} + LBUFFER= + RBUFFER= + PREDISPLAY="$pretext${1:-Non-echoed text: }" + POSTDISPLAY= + region_highlight=("P${(m)#pretext} ${(m)#PREDISPLAY} bold") + + while zle -R && zle .read-command + do + # There are probably more commands that should go into + # the first clause here to harmlessly beep, because ... + case $REPLY in + (send-invisible|run-help|undefined-key|where-is|which-command) + zle .beep;; + (push-*|send-break) INVISIBLE=;& + (accept-*) break;; + (*) + LBUFFER=$lb + RBUFFER=$rb + zle $REPLY # ... this could expose something + lb=$LBUFFER + rb=$RBUFFER + INVISIBLE=$BUFFER + LBUFFER=${(l:$#LBUFFER::*:):-} + RBUFFER=${(l:$#RBUFFER::*:):-} + ;; + esac + done +} always { + LBUFFER=$save_lbuffer + RBUFFER=$save_rbuffer + PREDISPLAY=$save_predisplay + POSTDISPLAY=$save_postdisplay + region_highlight=("${save_region_highlight[@]}") + zle -R + + # Now that the highlight has been restored with all the old + # text and cursor positioning, insert the new text. + LBUFFER+=${INVISIBLE:+${opn}INVISIBLE${cls}} +} diff --git a/Functions/Zle/split-shell-arguments b/Functions/Zle/split-shell-arguments index ee737a067..32b04fcb5 100644 --- a/Functions/Zle/split-shell-arguments +++ b/Functions/Zle/split-shell-arguments @@ -15,7 +15,7 @@ local -a bufwords lbufwords local word integer pos=1 cpos=$((CURSOR+1)) opos iword ichar -bufwords=(${(z)BUFFER}) +bufwords=(${(Z+n+)BUFFER}) reply=() while [[ ${BUFFER[pos]} = [[:space:]] ]]; do @@ -472,6 +472,14 @@ $fpath array on shell startup. This directory will not be affected by `make uninstall' or `make uninstall.fns', although the version-specific directory and its contents will be deleted. +The --enable-additional-fpath option may be used to add arbitrary +directories to the shell's default $fpath array. This may be useful to +have vendor specific function directories available for vendor specific +addons. You may add more than one directory this way by listing them with +the option separated by commas. The additional directories will be added +after the site specific directory (--enable-site-fndir) in the same order +in which they are supplied. + Function depth -------------- @@ -593,6 +601,7 @@ fndir=directory # the directory where shell functions will go # [DATADIR/zsh/VERSION/functions] site-fndir=directory # the directory where site-specific functions can go # [DATADIR/zsh/site-functions] +additional-path # add directories to default function path [<none>] function-subdirs # if functions will be installed into subdirectories [no] dynamic # allow dynamically loaded binary modules [yes] largefile # allow configure check for large files [yes] @@ -4,6 +4,31 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH Note also the list of incompatibilities in the README file. +Changes since 4.3.11 +-------------------- + +The zsh/parameter module has a new readonly associative array +$usergroups whose keys are the names of system groups of which the +current user is a member and whose values are the corresponding +group identifiers. + +The region_highlight array, which controls highlighting of the +command line from zle widgets, is now updated dynamically as +the command line is edited. + +In POSIX emulation ("emulate sh") the shell is more accurate about +when it should or should not exit on errors. + +The ${NAME:OFFSET:LENGTH} syntax now supports negative LENGTH, which +counts back from the end of the string. + +The (g:opts:) flag in parameter expansion processes escape sequences like +the echo and print builtins. opts can be any combination of o, e and c. +With e, acts like print rather than echo except for octal escapes which +are controlled separately by the o option. With c, interpret control +sequences like "^X" as bindkey does. Regardless of the opts, \c is not +interpreted. + Changes between versions 4.3.10 and 4.3.11 ------------------------------------------ @@ -5,11 +5,11 @@ THE Z SHELL (ZSH) Version ------- -This is version 4.3.11 of the shell. This is a development release, +This is version 4.3.12 of the shell. This is a development release, but is believed to be reasonably stable. Sites where the users need to edit command lines with multibyte characters (in particular UTF-8) will probably want to upgrade. The previous widely released version -of the shell was 4.3.10. +of the shell was 4.3.11. Installing Zsh -------------- diff --git a/Src/.distfiles b/Src/.distfiles index 1b0bc4ec7..1da58ea17 100644 --- a/Src/.distfiles +++ b/Src/.distfiles @@ -1,13 +1,53 @@ DISTFILES_SRC=' - .cvsignore .distfiles .exrc .indent.pro - Makefile.in Makemod.in.in - signames1.awk signames2.awk - modentry.c - builtin.c compat.c cond.c exec.c glob.c hashtable.c hashtable.h - hist.c init.c input.c jobs.c lex.c linklist.c loop.c main.c makepro.awk - math.c mem.c mkbltnmlst.sh mkmakemod.sh - module.c options.c params.c parse.c pattern.c prompt.c prototypes.h - signals.c signals.h sort.c string.c subst.c system.h text.c utils.c - watch.c zsh.h zsh.mdd ztype.h - zsh.rc zsh.ico +.cvsignore +.distfiles +.exrc +.indent.pro +Makefile.in +Makemod.in.in +signames1.awk +signames2.awk +modentry.c +builtin.c +compat.c +cond.c +exec.c +glob.c +hashtable.c +hashtable.h +hashnameddir.c +hist.c +init.c +input.c +jobs.c +lex.c +linklist.c +loop.c +main.c +makepro.awk +math.c +mem.c +mkbltnmlst.sh +mkmakemod.sh +module.c +options.c +params.c +parse.c +pattern.c +prompt.c +prototypes.h +signals.c +signals.h +sort.c +string.c +subst.c +text.c +utils.c +watch.c +zsh.h +zsh.mdd +zsh_system.h +ztype.h +zsh.rc +zsh.ico ' diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c index 7ee0de012..ffcb92052 100644 --- a/Src/Builtins/rlimits.c +++ b/Src/Builtins/rlimits.c @@ -954,7 +954,6 @@ int cleanup_(Module m) { return setfeatureenables(m, &module_features, NULL); - return 0; } /**/ diff --git a/Src/Makefile.in b/Src/Makefile.in index bcbecad8e..0577554f8 100644 --- a/Src/Makefile.in +++ b/Src/Makefile.in @@ -221,10 +221,7 @@ mostlyclean-modules clean-modules distclean-modules realclean-modules: install.modules uninstall.modules \ modobjs modules headers proto $(MAIN_OBJS) zsh.export: Makemod - @if [ ! -f Builtins/Makefile.in ]; then \ - $(MAKE) prep; \ - fi @$(MAKE) -f Makemod $(MAKEDEFS) $@ -.PHONY: headers proto +.PHONY: install.modules uninstall.modules headers proto $(MAIN_OBJS): $(sdir)/zsh.h diff --git a/Src/Makemod.in.in b/Src/Makemod.in.in index 3ba9f9b04..ea0cdc3a4 100644 --- a/Src/Makemod.in.in +++ b/Src/Makemod.in.in @@ -47,8 +47,8 @@ dir_src = $(dir_top)/Src DNCFLAGS = -COMPILE = $(CC) -c -I. $(CPPFLAGS) $(DEFS) $(CFLAGS) $(D@L@CFLAGS) -DLCOMPILE = $(CC) -c -I. $(CPPFLAGS) $(DEFS) -DMODULE $(CFLAGS) $(DLCFLAGS) +COMPILE = $(CC) -c -I. -I$(dir_top)/Src -I$(sdir_top)/Src -I$(sdir_top)/Src/Zle -I$(sdir) $(CPPFLAGS) $(DEFS) $(CFLAGS) $(D@L@CFLAGS) +DLCOMPILE = $(CC) -c -I. -I$(dir_top)/Src -I$(sdir_top)/Src -I$(sdir_top)/Src/Zle -I$(sdir) $(CPPFLAGS) $(DEFS) -DMODULE $(CFLAGS) $(DLCFLAGS) LINK = $(CC) $(LDFLAGS) $(EXELDFLAGS) $(EXTRA_LDFLAGS) -o $@ DLLINK = $(DLLD) $(LDFLAGS) $(LIBLDFLAGS) $(DLLDFLAGS) -o $@ @@ -116,8 +116,9 @@ prep: done .PHONY: prep -headers prep: $(dir_src)/modules.stamp +headers: $(dir_src)/modules.stamp $(dir_src)/modules.stamp: $(MDDS) + $(MAKE) -f $(makefile) $(MAKEDEFS) prep echo 'timestamp for *.mdd files' > $@ .PHONY: headers diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c index 29e088c70..41ad2c6e4 100644 --- a/Src/Modules/curses.c +++ b/Src/Modules/curses.c @@ -1069,8 +1069,47 @@ zccmd_input(const char *nam, char **args) } #endif + /* + * Some documentation for wgetch() says: + + The behavior of getch and friends in the presence of handled signals + is unspecified in the SVr4 and XSI Curses documentation. Under his- + torical curses implementations, it varied depending on whether the + operating system's implementation of handled signal receipt interrupts + a read(2) call in progress or not, and also (in some implementations) + depending on whether an input timeout or non-blocking mode has been + set. + + Programmers concerned about portability should be prepared for either + of two cases: (a) signal receipt does not interrupt getch; (b) signal + receipt interrupts getch and causes it to return ERR with errno set to + EINTR. Under the ncurses implementation, handled signals never inter- + rupt getch. + + * The observed behavior, however, is different: wgetch() consistently + * returns ERR with EINTR when a signal is handled by the shell "trap" + * command mechanism. Further, it consistently returns ERR twice, the + * second time without even attempting to repeat the interrupted read, + * which has the side-effect of NOT updating errno. A third call will + * then begin reading again. + * + * Therefore, to properly implement signal trapping, we must (1) call + * wgetch() in a loop as long as errno remains EINTR, and (2) clear + * errno only before beginning the loop, not on every pass. + * + * There remains a potential bug here in that, if the caller has set + * a timeout for the read [see zccmd_timeout()] the countdown is very + * likely restarted on every call to wgetch(), so an interrupted call + * might wait much longer than desired. + */ + errno = 0; + #ifdef HAVE_WGET_WCH - switch (wget_wch(w->win, &wi)) { + while ((ret = wget_wch(w->win, &wi)) == ERR) { + if (errno != EINTR || errflag || retflag || breaks || exit_pending) + break; + } + switch (ret) { case OK: ret = wctomb(instr, (wchar_t)wi); if (ret == 0) { @@ -1092,9 +1131,10 @@ zccmd_input(const char *nam, char **args) return 1; } #else - ci = wgetch(w->win); - if (ci == ERR) - return 1; + while ((ci = wgetch(w->win)) == ERR) { + if (errno != EINTR || errflag || retflag || breaks || exit_pending) + return 1; + } if (ci >= 256) { keypadnum = ci; *instr = '\0'; diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c index 0dc42fda8..45818b968 100644 --- a/Src/Modules/datetime.c +++ b/Src/Modules/datetime.c @@ -146,7 +146,7 @@ bin_strftime(char *nam, char **argv, Options ops, UNUSED(int func)) } static zlong -getcurrentsecs() +getcurrentsecs(UNUSED(Param pm)) { return (zlong) time(NULL); } diff --git a/Src/Modules/files.c b/Src/Modules/files.c index 3fbccf576..f86b9c1e9 100644 --- a/Src/Modules/files.c +++ b/Src/Modules/files.c @@ -195,7 +195,7 @@ bin_rmdir(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) static int bin_ln(char *nam, char **args, Options ops, int func) { - MoveFunc move; + MoveFunc movefn; int flags, have_dir, err = 0; char **a, *ptr, *rp, *buf; struct stat st; @@ -203,7 +203,7 @@ bin_ln(char *nam, char **args, Options ops, int func) if(func == BIN_MV) { - move = (MoveFunc) rename; + movefn = (MoveFunc) rename; flags = OPT_ISSET(ops,'f') ? 0 : MV_ASKNW; flags |= MV_ATOMIC; } else { @@ -212,11 +212,11 @@ bin_ln(char *nam, char **args, Options ops, int func) if(OPT_ISSET(ops,'h') || OPT_ISSET(ops,'n')) flags |= MV_NOCHASETARGET; if(OPT_ISSET(ops,'s')) - move = (MoveFunc) symlink; + movefn = (MoveFunc) symlink; else #endif { - move = (MoveFunc) link; + movefn = (MoveFunc) link; if(!OPT_ISSET(ops,'d')) flags |= MV_NODIRS; } @@ -267,7 +267,7 @@ bin_ln(char *nam, char **args, Options ops, int func) else args[1] = args[0]; } - return domove(nam, move, args[0], args[1], flags); + return domove(nam, movefn, args[0], args[1], flags); havedir: buf = ztrdup(*a); *a = NULL; @@ -283,7 +283,7 @@ bin_ln(char *nam, char **args, Options ops, int func) buf[blen] = 0; buf = appstr(buf, ptr); - err |= domove(nam, move, *args, buf, flags); + err |= domove(nam, movefn, *args, buf, flags); } zsfree(buf); return err; @@ -291,7 +291,7 @@ bin_ln(char *nam, char **args, Options ops, int func) /**/ static int -domove(char *nam, MoveFunc move, char *p, char *q, int flags) +domove(char *nam, MoveFunc movefn, char *p, char *q, int flags) { struct stat st; char *pbuf, *qbuf; @@ -341,7 +341,7 @@ domove(char *nam, MoveFunc move, char *p, char *q, int flags) if(doit && !(flags & MV_ATOMIC)) unlink(qbuf); } - if(move(pbuf, qbuf)) { + if(movefn(pbuf, qbuf)) { zwarnnam(nam, "%s: %e", p, errno); zsfree(pbuf); return 1; diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 793249f32..092efa0c3 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -1820,6 +1820,141 @@ scanpmdissaliases(HashTable ht, ScanFunc func, int flags) scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX|DISABLED); } + +/* Functions for the usergroups special parameter */ + +/* + * Get GID and names for groups of which the current user is a member. + */ + +/**/ +static Groupset get_all_groups(void) +{ + Groupset gs = zhalloc(sizeof(*gs)); + Groupmap gaptr; + gid_t *list, *lptr, egid; + int add_egid; + struct group *grptr; + + egid = getegid(); + add_egid = 1; + gs->num = getgroups(0, NULL); + if (gs->num > 0) { + list = zhalloc(gs->num * sizeof(*list)); + if (getgroups(gs->num, list) < 0) { + return NULL; + } + + /* + * It's unspecified whether $EGID is included in the + * group set, so check. + */ + for (lptr = list; lptr < list + gs->num; lptr++) { + if (*lptr == egid) { + add_egid = 0; + break; + } + } + gs->array = zhalloc((gs->num + add_egid) * sizeof(*gs->array)); + /* Put EGID if needed first */ + gaptr = gs->array + add_egid; + for (lptr = list; lptr < list + gs->num; lptr++) { + gaptr->gid = *lptr; + gaptr++; + } + gs->num += add_egid; + } else { + /* Just use effective GID */ + gs->num = 1; + gs->array = zhalloc(sizeof(*gs->array)); + } + if (add_egid) { + gs->array->gid = egid; + } + + /* Get group names */ + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + grptr = getgrgid(gaptr->gid); + if (!grptr) { + return NULL; + } + gaptr->name = dupstring(grptr->gr_name); + } + + return gs; +} + +/* Standard hash element lookup. */ + +/**/ +static HashNode +getpmusergroups(UNUSED(HashTable ht), const char *name) +{ + Param pm = NULL; + Groupset gs = get_all_groups(); + Groupmap gaptr; + + pm = (Param)hcalloc(sizeof(struct param)); + pm->node.nam = dupstring(name); + pm->node.flags = PM_SCALAR | PM_READONLY; + pm->gsu.s = &nullsetscalar_gsu; + + if (!gs) { + zerr("failed to retrieve groups for user: %e", errno); + pm->u.str = dupstring(""); + pm->node.flags |= PM_UNSET; + return &pm->node; + } + + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + if (!strcmp(name, gaptr->name)) { + char buf[DIGBUFSIZE]; + + sprintf(buf, "%d", (int)gaptr->gid); + pm->u.str = dupstring(buf); + return &pm->node; + } + } + + pm->u.str = dupstring(""); + pm->node.flags |= PM_UNSET; + return &pm->node; +} + +/* Standard hash scan. */ + +/**/ +static void +scanpmusergroups(UNUSED(HashTable ht), ScanFunc func, int flags) +{ + struct param pm; + Groupset gs = get_all_groups(); + Groupmap gaptr; + + if (!gs) { + zerr("failed to retrieve groups for user: %e", errno); + return; + } + + memset((void *)&pm, 0, sizeof(pm)); + pm.node.flags = PM_SCALAR | PM_READONLY; + pm.gsu.s = &nullsetscalar_gsu; + + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + pm.node.nam = gaptr->name; + if (func != scancountparams && + ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) || + !(flags & SCANPM_WANTKEYS))) { + char buf[DIGBUFSIZE]; + + sprintf(buf, "%d", (int)gaptr->gid); + pm.u.str = dupstring(buf); + } + func(&pm.node, flags); + } +} + + /* Table for defined parameters. */ struct pardef { @@ -1926,7 +2061,9 @@ static struct paramdef partab[] = { SPECIALPMDEF("saliases", 0, &pmsaliases_gsu, getpmsalias, scanpmsaliases), SPECIALPMDEF("userdirs", PM_READONLY, - NULL, getpmuserdir, scanpmuserdirs) + NULL, getpmuserdir, scanpmuserdirs), + SPECIALPMDEF("usergroups", PM_READONLY, + NULL, getpmusergroups, scanpmusergroups) }; static struct features module_features = { diff --git a/Src/Modules/termcap.c b/Src/Modules/termcap.c index 7367dade7..cd0e85885 100644 --- a/Src/Modules/termcap.c +++ b/Src/Modules/termcap.c @@ -35,34 +35,11 @@ */ #include "../../config.h" -#ifdef HAVE_TGETENT -# if defined(ZSH_HAVE_CURSES_H) && defined(ZSH_HAVE_TERM_H) -# define USES_TERM_H 1 -# else -# ifdef HAVE_TERMCAP_H -# define USES_TERMCAP_H 1 -# endif -# endif -#endif - #include "termcap.mdh" #include "termcap.pro" /**/ #ifdef HAVE_TGETENT -# ifdef USES_TERM_H -# ifdef HAVE_TERMIO_H -# include <termio.h> -# endif -# ifdef ZSH_HAVE_CURSES_H -# include "../zshcurses.h" -# endif -# include "../zshterm.h" -# else -# ifdef USES_TERMCAP_H -# include <termcap.h> -# endif -# endif #ifndef HAVE_BOOLCODES static char *boolcodes[] = { diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index 1558d354f..8d688abd4 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -50,6 +50,7 @@ struct zftp_session; typedef struct zftp_session *Zftp_session; #include "tcp.h" +#include "tcp.mdh" #include "zftp.mdh" #include "zftp.pro" diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index 2a81e68cb..25ec7dfea 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -351,8 +351,8 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock) struct ttyinfo info; if (ioctl(slave, TIOCGWINSZ, (char *) &info.winsize) == 0) { - info.winsize.ws_row = lines; - info.winsize.ws_col = columns; + info.winsize.ws_row = zterm_lines; + info.winsize.ws_col = zterm_columns; ioctl(slave, TIOCSWINSZ, (char *) &info.winsize); } } diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 3c71edfa7..399c45f46 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1405,6 +1405,8 @@ struct zoptdesc { #define ZOF_OPT 2 #define ZOF_MULT 4 #define ZOF_SAME 8 +#define ZOF_MAP 16 +#define ZOF_CYC 32 struct zoptarr { Zoptarr next; @@ -1459,6 +1461,34 @@ get_opt_arr(char *name) return NULL; } +static Zoptdesc +map_opt_desc(Zoptdesc start) +{ + Zoptdesc map = NULL; + + if (!start || !(start->flags & ZOF_MAP)) + return start; + + map = get_opt_desc(start->arr->name); + + if (!map) + return start; + + if (map == start) { + start->flags &= ~ZOF_MAP; /* optimize */ + return start; + } + + if (map->flags & ZOF_CYC) + return NULL; + + start->flags |= ZOF_CYC; + map = map_opt_desc(map); + start->flags &= ~ZOF_CYC; + + return map; +} + static void add_opt_val(Zoptdesc d, char *arg) { @@ -1466,6 +1496,10 @@ add_opt_val(Zoptdesc d, char *arg) char *n = dyncat("-", d->name); int new = 0; + Zoptdesc map = map_opt_desc(d); + if (map) + d = map; + if (!(d->flags & ZOF_MULT)) v = d->vals; if (!v) { @@ -1513,7 +1547,7 @@ static int bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np; - int del = 0, f, extract = 0, keep = 0; + int del = 0, flags = 0, extract = 0, keep = 0; Zoptdesc sopts[256], d; Zoptarr a, defarr = NULL; Zoptval v; @@ -1531,6 +1565,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) case '-': if (o[2]) args--; + /* else unreachable, default parsing removes "--" */ o = NULL; break; case 'D': @@ -1557,6 +1592,14 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } keep = 1; break; + case 'M': + if (o[2]) { + args--; + o = NULL; + break; + } + flags |= ZOF_MAP; + break; case 'a': if (defarr) { zwarnnam(nam, "default array given more than once"); @@ -1578,6 +1621,10 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) opt_arrs = defarr; break; case 'A': + if (assoc) { + zwarnnam(nam, "associative array given more than once"); + return 1; + } if (o[2]) assoc = o + 2; else if (*args) @@ -1587,6 +1634,11 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) return 1; } break; + default: + /* Anything else is an option description */ + args--; + o = NULL; + break; } if (!o) { o = ""; @@ -1602,11 +1654,11 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) return 1; } while ((o = dupstring(*args++))) { + int f = 0; if (!*o) { zwarnnam(nam, "invalid option description: %s", o); return 1; } - f = 0; for (p = o; *p; p++) { if (*p == '\\' && p[1]) p++; @@ -1633,6 +1685,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) a = NULL; if (*p == '=') { *p++ = '\0'; + f |= flags; if (!(a = get_opt_arr(p))) { a = (Zoptarr) zhalloc(sizeof(*a)); a->name = p; @@ -1666,6 +1719,10 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) opt_descs = d; if (!o[1]) sopts[STOUC(*o)] = d; + if ((flags & ZOF_MAP) && !map_opt_desc(d)) { + zwarnnam(nam, "cyclic option mapping: %s", args[-1]); + return 1; + } } np = cp = pp = ((extract && del) ? arrdup(pparams) : pparams); for (; (o = *pp); pp++) { @@ -1732,12 +1789,20 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) add_opt_val(d, NULL); } } + + if (flags & ZOF_MAP) { + for (d = opt_descs; d; d = d->next) + if (d->arr && !d->vals && (d->flags & ZOF_MAP)) { + if (d->arr->num == 0 && get_opt_desc(d->arr->name)) + d->arr->num = -1; /* this is not a real array */ + } + } if (extract && del) while (*pp) *cp++ = *pp++; for (a = opt_arrs; a; a = a->next) { - if (!keep || a->num) { + if (a->num >= 0 && (!keep || a->num)) { aval = (char **) zalloc((a->num + 1) * sizeof(char *)); for (ap = aval, v = a->vals; v; ap++, v = v->next) { if (v->str) diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h index e96c4217c..34da2cabb 100644 --- a/Src/Zle/comp.h +++ b/Src/Zle/comp.h @@ -76,6 +76,9 @@ struct cmgroup { int totl; /* total length */ int shortest; /* length of shortest match */ Cmgroup perm; /* perm. alloced version of this group */ +#ifdef ZSH_HEAP_DEBUG + Heapid heap_id; +#endif }; @@ -323,8 +326,8 @@ struct cadata { typedef struct cldata *Cldata; struct cldata { - int columns; /* screen width */ - int lines; /* screen height */ + int zterm_columns; /* screen width */ + int zterm_lines; /* screen height */ int menuacc; /* value of global menuacc */ int valid; /* no need to calculate anew */ int nlist; /* number of matches to list */ diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index c59815874..5514e2e1d 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -405,6 +405,11 @@ do_completion(UNUSED(Hookdef dummy), Compldat dat) } else if (nmatches == 1 || (nmatches > 1 && !diffmatches)) { /* Only one match. */ Cmgroup m = amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(m->heap_id)) { + HEAP_ERROR(m->heap_id); + } +#endif while (!m->mcount) m = m->next; @@ -509,6 +514,11 @@ after_complete(UNUSED(Hookdef dummy), int *dat) int ret; cdat.matches = amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(cdat.matches->heap_id)) { + HEAP_ERROR(cdat.matches->heap_id); + } +#endif cdat.num = nmatches; cdat.nmesg = nmessages; cdat.cur = NULL; @@ -987,6 +997,11 @@ makecomplist(char *s, int incmd, int lst) diffmatches = odm; validlist = 1; amatches = lastmatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif lmatches = lastlmatches; if (pmatches) { freematches(pmatches, 1); @@ -1395,8 +1410,6 @@ set_comp_sep(void) LinkNode n; /* Save word position */ int owe = we, owb = wb; - /* Save cursor position and line length */ - int ocs, oll; /* * Values of word beginning and end and cursor after subtractions * due to separators. I think these are indexes into zlemetaline, @@ -1481,8 +1494,7 @@ set_comp_sep(void) /* Put the string in the lexer buffer and call the lexer to * * get the words we have to expand. */ - ocs = zlemetacs; - oll = zlemetall; + zle_save_positions(); ol = zlemetaline; addedx = 1; noerrs = 1; @@ -1639,9 +1651,8 @@ set_comp_sep(void) lexrestore(); wb = owb; we = owe; - zlemetacs = ocs; zlemetaline = ol; - zlemetall = oll; + zle_restore_positions(); if (cur < 0 || i < 1) return 1; owb = offs; @@ -2333,7 +2344,7 @@ addmatches(Cadata dat, char **argv) dat->pre = dupstring(dat->pre); if (dat->suf) dat->suf = dupstring(dat->suf); - if (!dat->prpre && (dat->prpre = oppre)) { + if (!dat->prpre && (dat->prpre = dupstring(oppre))) { singsub(&(dat->prpre)); untokenize(dat->prpre); } else @@ -2963,6 +2974,11 @@ begcmgroup(char *n, int flags) Cmgroup p = amatches; while (p) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(p->heap_id)) { + HEAP_ERROR(p->heap_id); + } +#endif if (p->name && flags == (p->flags & (CGF_NOSORT|CGF_UNIQALL|CGF_UNIQCON)) && !strcmp(n, p->name)) { @@ -2979,6 +2995,9 @@ begcmgroup(char *n, int flags) } } mgroup = (Cmgroup) zhalloc(sizeof(struct cmgroup)); +#ifdef ZSH_HEAP_DEBUG + mgroup->heap_id = last_heap_id; +#endif mgroup->name = dupstring(n); mgroup->lcount = mgroup->llcount = mgroup->mcount = mgroup->ecount = mgroup->ccount = 0; @@ -3299,6 +3318,11 @@ permmatches(int last) fi = 1; } while (g) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif if (fi != ofi || !g->perm || g->new) { if (fi) /* We have no matches, try ignoring fignore. */ @@ -3327,6 +3351,9 @@ permmatches(int last) diffmatches = 1; n = (Cmgroup) zshcalloc(sizeof(struct cmgroup)); +#ifdef ZSH_HEAP_DEBUG + n->heap_id = HEAPID_PERMANENT; +#endif if (g->perm) { g->perm->next = NULL; diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 873d9287a..0143370c7 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1838,6 +1838,11 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat) diffmatches = odm; validlist = 1; amatches = lastmatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif lmatches = lastlmatches; if (pmatches) { freematches(pmatches, 1); @@ -1891,7 +1896,7 @@ cccleanuphookfn(UNUSED(Hookdef dummy), UNUSED(void *dat)) /* This adds a match to the list of matches. The string to add is given * * in s, the type of match is given in the global variable addwhat and * - * the parameter t (if not NULL) is a pointer to a hash node node which * + * the parameter t (if not NULL) is a pointer to a hash node which * * may be used to give other information to this function. * * * * addwhat contains either one of the special values (negative, see below) * diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index f6e253afd..fdca7a99f 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -656,7 +656,7 @@ clprintfmt(char *p, int ml) tcout(TCCLEAREOL); cc = 0; } - if (ml == mlend - 1 && (cc % columns) == columns - 1) + if (ml == mlend - 1 && (cc % zterm_columns) == zterm_columns - 1) return 0; if (*p == Meta) { @@ -664,9 +664,9 @@ clprintfmt(char *p, int ml) putc(*p ^ 32, shout); } else putc(*p, shout); - if ((beg = !(cc % columns))) + if ((beg = !(cc % zterm_columns))) ml++; - if (mscroll && !(cc % columns) && + if (mscroll && !(cc % zterm_columns) && !--mrestlines && (ask = asklistscroll(ml))) return ask; } @@ -765,7 +765,7 @@ clnicezputs(int do_colors, char *s, int ml) /* Input is metafied... */ int nc = (*t == Meta) ? STOUC(*++t ^ 32) : STOUC(*t); /* Is the screen full? */ - if (ml == mlend - 1 && col == columns - 1) { + if (ml == mlend - 1 && col == zterm_columns - 1) { mlprinted = ml - oml; return 0; } @@ -787,13 +787,13 @@ clnicezputs(int do_colors, char *s, int ml) * There might be problems with characters of printing width * greater than one here. */ - if (col > columns) { + if (col > zterm_columns) { ml++; if (mscroll && !--mrestlines && (ask = asklistscroll(ml))) { mlprinted = ml - oml; return ask; } - col -= columns; + col -= zterm_columns; if (do_colors) fputs(" \010", shout); } @@ -820,12 +820,12 @@ clnicezputs(int do_colors, char *s, int ml) for (t = nicechar(cc); *t; t++) { int nc = (*t == Meta) ? STOUC(*++t ^ 32) : STOUC(*t); - if (ml == mlend - 1 && col == columns - 1) { + if (ml == mlend - 1 && col == zterm_columns - 1) { mlprinted = ml - oml; return 0; } putc(nc, shout); - if (++col > columns) { + if (++col > zterm_columns) { ml++; if (mscroll && !--mrestlines && (ask = asklistscroll(ml))) { mlprinted = ml - oml; @@ -991,7 +991,7 @@ asklistscroll(int ml) !strcmp(cmd->nam, "expand-or-complete-prefix") || !strcmp(cmd->nam, "menu-complete") || !strcmp(cmd->nam, "menu-expand-or-complete")) - mrestlines = lines - 1; + mrestlines = zterm_lines - 1; else if (cmd == Th(z_acceptsearch)) ret = 1; else { @@ -1001,7 +1001,7 @@ asklistscroll(int ml) selectlocalmap(NULL); settyinfo(&shttyinfo); putc('\r', shout); - for (i = columns - 1; i-- > 0; ) + for (i = zterm_columns - 1; i-- > 0; ) putc(' ', shout); putc('\r', shout); @@ -1213,8 +1213,8 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) /* nc only contains ASCII text */ int l = strlen(nc); - if (l + cc > columns - 2) - nc[l -= l + cc - (columns - 2)] = '\0'; + if (l + cc > zterm_columns - 2) + nc[l -= l + cc - (zterm_columns - 2)] = '\0'; fputs(nc, shout); cc += l; } else if (dopr && m == 1) { @@ -1230,16 +1230,17 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) } else { cc += width; - if ((cc >= columns - 2 || cchar == ZWC('\n')) && stat) + if ((cc >= zterm_columns - 2 || cchar == ZWC('\n')) && stat) dopr = 2; if (cchar == ZWC('\n')) { if (dopr == 1 && mlbeg >= 0 && tccan(TCCLEAREOL)) tcout(TCCLEAREOL); - l += 1 + ((cc - 1) / columns); + l += 1 + ((cc - 1) / zterm_columns); cc = 0; } if (dopr == 1) { - if (ml == mlend - 1 && (cc % columns) == columns - 1) { + if (ml == mlend - 1 && (cc % zterm_columns) == + zterm_columns - 1) { dopr = 0; p += len; continue; @@ -1256,7 +1257,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) * TODO: the following doesn't allow for * character widths greater than 1. */ - if ((beg = !(cc % columns)) && !stat) { + if ((beg = !(cc % zterm_columns)) && !stat) { ml++; fputs(" \010", shout); } @@ -1264,7 +1265,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) *stop = 1; if (stat && n) mfirstl = -1; - mlprinted = l + (cc ? ((cc-1) / columns) : 0); + mlprinted = l + (cc ? ((cc-1) / zterm_columns) : 0); return mlprinted; } } @@ -1273,7 +1274,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) } } if (dopr) { - if (!(cc % columns)) + if (!(cc % zterm_columns)) fputs(" \010", shout); if (mlbeg >= 0 && tccan(TCCLEAREOL)) tcout(TCCLEAREOL); @@ -1285,7 +1286,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) * *Not* subtracting 1 from cc at this point appears to be * correct. C.f. printfmt in zle_tricky.c. */ - mlprinted = l + (cc / columns); + mlprinted = l + (cc / zterm_columns); return mlprinted; } @@ -1309,7 +1310,7 @@ compzputs(char const *s, int ml) putc(c, shout); if (c == '\n' && mlbeg >= 0 && tccan(TCCLEAREOL)) tcout(TCCLEAREOL); - if (mscroll && (++col == columns || c == '\n')) { + if (mscroll && (++col == zterm_columns || c == '\n')) { ml++; if (!--mrestlines && (ask = asklistscroll(ml))) return ask; @@ -1344,10 +1345,11 @@ compprintlist(int showall) lastml = 0; lastnlnct = -1; } - cl = (listdat.nlines > lines - nlnct - mhasstat ? - lines - nlnct - mhasstat : listdat.nlines) - (lastnlnct > nlnct); + cl = (listdat.nlines > zterm_lines - nlnct - mhasstat ? + zterm_lines - nlnct - mhasstat : + listdat.nlines) - (lastnlnct > nlnct); lastnlnct = nlnct; - mrestlines = lines - 1; + mrestlines = zterm_lines - 1; lastinvcount = invcount; if (cl < 2) { @@ -1361,6 +1363,11 @@ compprintlist(int showall) while (g) { char **pp = g->ylist; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif if ((e = g->expls)) { int l; @@ -1643,20 +1650,20 @@ compprintlist(int showall) /* Move the cursor up to the prompt, if always_last_prompt * * is set and all that... */ if (mlbeg >= 0) { - if ((nl = listdat.nlines + nlnct) >= lines) { + if ((nl = listdat.nlines + nlnct) >= zterm_lines) { if (mhasstat) { putc('\n', shout); compprintfmt(NULL, 0, 1, 1, mline, NULL); mstatprinted = 1; } - nl = lines - 1; + nl = zterm_lines - 1; } else nl--; tcmultout(TCUP, TCMULTUP, nl); showinglist = -1; lastlistlen = listdat.nlines; - } else if ((nl = listdat.nlines + nlnct - 1) < lines) { + } else if ((nl = listdat.nlines + nlnct - 1) < zterm_lines) { if (mlbeg >= 0 && tccan(TCCLEAREOL)) tcout(TCCLEAREOL); tcmultout(TCUP, TCMULTUP, nl); @@ -1666,12 +1673,12 @@ compprintlist(int showall) } else { clearflag = 0; if (!asked) { - mrestlines = (ml + nlnct > lines); + mrestlines = (ml + nlnct > zterm_lines); compprintnl(ml); } } } else if (!asked) { - mrestlines = (ml + nlnct > lines); + mrestlines = (ml + nlnct > zterm_lines); compprintnl(ml); } listshown = (clearflag ? 1 : -1); @@ -1789,7 +1796,7 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width) if (!dolist(ml)) { int nc = ZMB_nicewidth(m->disp ? m->disp : m->str); if (nc) - mlprinted = (nc-1) / columns; + mlprinted = (nc-1) / zterm_columns; else mlprinted = 0; return 0; @@ -1831,7 +1838,7 @@ clprintm(Cmgroup g, Cmatch *mp, int mc, int ml, int lastc, int width) return 1; } len = ZMB_nicewidth(m->disp ? m->disp : m->str); - mlprinted = len ? (len-1) / columns : 0; + mlprinted = len ? (len-1) / zterm_columns : 0; modec = (mcolors.flags & LC_FOLLOW_SYMLINKS) ? m->fmodec : m->modec; if ((g->flags & CGF_FILES) && modec) { @@ -1864,9 +1871,11 @@ static int singlecalc(int *cp, int l, int *lcp) { int c = *cp, n, j, first = 1; - Cmatch **p, *op, *mp = mtab[l * columns + c]; + Cmatch **p, *op, *mp = mtab[l * zterm_columns + c]; - for (n = 0, j = c, p = mtab + l * columns + c, op = NULL; j >= 0; j--, p--) { + for (n = 0, j = c, p = mtab + l * zterm_columns + c, op = NULL; + j >= 0; + j--, p--) { if (*p == mp) c = j; if (!first && *p != op) @@ -1876,7 +1885,7 @@ singlecalc(int *cp, int l, int *lcp) } *cp = c; *lcp = 1; - for (p = mtab + l * columns + c; c < columns; c++, p++) + for (p = mtab + l * zterm_columns + c; c < zterm_columns; c++, p++) if (*p && mp != *p) *lcp = 0; @@ -1906,9 +1915,9 @@ singledraw() tc_downcurs(md1); if (mc1) tcmultout(TCRIGHT, TCMULTRIGHT, mc1); - DPUTS(ml1 * columns + mc1 >= mgtabsize, "BUG: invalid position"); - g = mgtab[ml1 * columns + mc1]; - clprintm(g, mtab[ml1 * columns + mc1], mcc1, ml1, lc1, + DPUTS(ml1 * zterm_columns + mc1 >= mgtabsize, "BUG: invalid position"); + g = mgtab[ml1 * zterm_columns + mc1]; + clprintm(g, mtab[ml1 * zterm_columns + mc1], mcc1, ml1, lc1, (g->widths ? g->widths[mcc1] : g->width)); if (mlprinted) (void) tcmultout(TCUP, TCMULTUP, mlprinted); @@ -1918,20 +1927,20 @@ singledraw() tc_downcurs(md2 - md1); if (mc2) tcmultout(TCRIGHT, TCMULTRIGHT, mc2); - DPUTS(ml2 * columns + mc2 >= mgtabsize, "BUG: invalid position"); - g = mgtab[ml2 * columns + mc2]; - clprintm(g, mtab[ml2 * columns + mc2], mcc2, ml2, lc2, + DPUTS(ml2 * zterm_columns + mc2 >= mgtabsize, "BUG: invalid position"); + g = mgtab[ml2 * zterm_columns + mc2]; + clprintm(g, mtab[ml2 * zterm_columns + mc2], mcc2, ml2, lc2, (g->widths ? g->widths[mcc2] : g->width)); if (mlprinted) (void) tcmultout(TCUP, TCMULTUP, mlprinted); putc('\r', shout); if (mstatprinted) { - int i = lines - md2 - nlnct; + int i = zterm_lines - md2 - nlnct; tc_downcurs(i - 1); compprintfmt(NULL, 0, 1, 1, mline, NULL); - tcmultout(TCUP, TCMULTUP, lines - 1); + tcmultout(TCUP, TCMULTUP, zterm_lines - 1); } else tcmultout(TCUP, TCMULTUP, md2 + nlnct); @@ -1948,10 +1957,15 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat) Cmgroup oamatches = amatches; amatches = dat->matches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif noselect = 0; - if ((minfo.asked == 2 && mselect < 0) || nlnct >= lines) { + if ((minfo.asked == 2 && mselect < 0) || nlnct >= zterm_lines) { showinglist = 0; amatches = oamatches; return (noselect = 1); @@ -1971,7 +1985,7 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat) getcols(); - mnew = ((calclist(mselect >= 0) || mlastcols != columns || + mnew = ((calclist(mselect >= 0) || mlastcols != zterm_columns || mlastlines != listdat.nlines) && mselect >= 0); if (!listdat.nlines || (mselect >= 0 && @@ -2006,7 +2020,7 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat) mscroll = 1; } else { clearflag = 1; - minfo.asked = (listdat.nlines + nlnct <= lines); + minfo.asked = (listdat.nlines + nlnct <= zterm_lines); } } else { unqueue_signals(); @@ -2019,7 +2033,7 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat) } } if (mlbeg >= 0) { - mlend = mlbeg + lines - nlnct - mhasstat; + mlend = mlbeg + zterm_lines - nlnct - mhasstat; while (mline >= mlend) mlbeg++, mlend++; } else @@ -2030,7 +2044,7 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat) mtab_been_reallocated = 1; - i = columns * listdat.nlines; + i = zterm_columns * listdat.nlines; free(mtab); mtab = (Cmatch **) zalloc(i * sizeof(Cmatch **)); memset(mtab, 0, i * sizeof(Cmatch **)); @@ -2040,7 +2054,7 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat) mgtabsize = i; #endif memset(mgtab, 0, i * sizeof(Cmgroup)); - mlastcols = mcols = columns; + mlastcols = mcols = zterm_columns; mlastlines = mlines = listdat.nlines; } last_cap = (char *) zhalloc(max_caplen + 1); @@ -2067,13 +2081,13 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat) static int adjust_mcol(int wish, Cmatch ***tabp, Cmgroup **grp) { - Cmatch **tab = *tabp; + Cmatch **matchtab = *tabp; int p, n, c; - tab -= mcol; + matchtab -= mcol; - for (p = wish; p >= 0 && (!tab[p] || mmarked(tab[p])); p--); - for (n = wish; n < mcols && (!tab[n] || mmarked(tab[n])); n++); + for (p = wish; p >= 0 && (!matchtab[p] || mmarked(matchtab[p])); p--); + for (n = wish; n < mcols && (!matchtab[n] || mmarked(matchtab[n])); n++); if (n == mcols) n = -1; @@ -2086,7 +2100,7 @@ adjust_mcol(int wish, Cmatch ***tabp, Cmgroup **grp) else c = ((mcol - p) < (n - mcol) ? p : n); - *tabp = tab + c; + *tabp = matchtab + c; if (grp) *grp = *grp + c - mcol; @@ -2177,7 +2191,7 @@ setmstatus(char *status, char *sline, int sll, int scs, } pl = strlen(p); sl = strlen(s); - max = (columns < MAX_STATUS ? columns : MAX_STATUS) - 14; + max = (zterm_columns < MAX_STATUS ? zterm_columns : MAX_STATUS) - 14; if (max > 12) { int h = (max - 2) >> 1; @@ -2394,9 +2408,9 @@ domenuselect(Hookdef dummy, Chdata dat) if ((s = getsparam("MENUSCROLL"))) { if (!(step = mathevali(s))) - step = (lines - nlnct) >> 1; + step = (zterm_lines - nlnct) >> 1; else if (step < 0) - if ((step += lines - nlnct) < 0) + if ((step += zterm_lines - nlnct) < 0) step = 1; } if ((s = getsparam("MENUMODE"))) { @@ -2473,34 +2487,34 @@ domenuselect(Hookdef dummy, Chdata dat) } if (mlbeg && lbeg != mlbeg) { - Cmatch **p = mtab + ((mlbeg - 1) * columns), **q; + Cmatch **p = mtab + ((mlbeg - 1) * zterm_columns), **q; int c; while (mlbeg) { - for (q = p, c = columns; c > 0; q++, c--) + for (q = p, c = zterm_columns; c > 0; q++, c--) if (*q && !mmarked(*q)) break; if (c) break; - p -= columns; + p -= zterm_columns; mlbeg--; } } - if ((space = lines - pl - mhasstat)) + if ((space = zterm_lines - pl - mhasstat)) while (mline >= mlbeg + space) if ((mlbeg += step) + space > mlines) mlbeg = mlines - space; if (lbeg != mlbeg) { - Cmatch **p = mtab + (mlbeg * columns), **q; + Cmatch **p = mtab + (mlbeg * zterm_columns), **q; int c; while (mlbeg < mlines) { - for (q = p, c = columns; c > 0; q++, c--) + for (q = p, c = zterm_columns; c > 0; q++, c--) if (*q) break; if (c) break; - p += columns; + p += zterm_columns; mlbeg++; } } @@ -2636,6 +2650,11 @@ domenuselect(Hookdef dummy, Chdata dat) s->mlbeg = mlbeg; memcpy(&(s->info), &minfo, sizeof(struct menuinfo)); s->amatches = amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif s->pmatches = pmatches; s->lastmatches = lastmatches; s->lastlmatches = lastlmatches; @@ -2699,6 +2718,8 @@ domenuselect(Hookdef dummy, Chdata dat) else selfinsertunmeta(zlenoargs); metafy_line(); + minfo.len++; + minfo.end++; saveline = (char *) zhalloc(zlemetall); memcpy(saveline, zlemetaline, zlemetall); @@ -2829,6 +2850,11 @@ domenuselect(Hookdef dummy, Chdata dat) if (lastmatches) freematches(lastmatches, 0); amatches = u->amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(amatches->heap_id)) { + HEAP_ERROR(amatches->heap_id); + } +#endif pmatches = u->pmatches; lastmatches = u->lastmatches; lastlmatches = u->lastlmatches; @@ -2953,7 +2979,7 @@ domenuselect(Hookdef dummy, Chdata dat) cmd == Th(z_viforwardword) || cmd == Th(z_viforwardwordend) || cmd == Th(z_forwardword)) { - int i = lines - pl - 1, oi = i, ll = 0; + int i = zterm_lines - pl - 1, oi = i, ll = 0; Cmatch **lp = NULL; mode = 0; @@ -2981,7 +3007,7 @@ domenuselect(Hookdef dummy, Chdata dat) } else if (cmd == Th(z_emacsbackwardword) || cmd == Th(z_vibackwardword) || cmd == Th(z_backwardword)) { - int i = lines - pl - 1, oi = i, ll = 0; + int i = zterm_lines - pl - 1, oi = i, ll = 0; Cmatch **lp = NULL; mode = 0; diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c index b59f5a2e1..4cd3b9ffe 100644 --- a/Src/Zle/compmatch.c +++ b/Src/Zle/compmatch.c @@ -1268,7 +1268,7 @@ pattern_match_equivalence(Cpattern lp, convchar_t wind, int wmtp, /**/ static int pattern_match_restrict(Cpattern p, Cpattern wp, convchar_t *wsc, int wsclen, - Cpattern prestrict, ZLE_STRING_T newline) + Cpattern prestrict, ZLE_STRING_T new_line) { convchar_t c; convchar_t ind, wind; @@ -1356,7 +1356,7 @@ pattern_match_restrict(Cpattern p, Cpattern wp, convchar_t *wsc, int wsclen, } /* We need to assemble the line */ - *newline++ = (ZLE_CHAR_T)c; + *new_line++ = (ZLE_CHAR_T)c; prestrict = prestrict->next; wsc++; wsclen--; @@ -1393,7 +1393,7 @@ pattern_match_restrict(Cpattern p, Cpattern wp, convchar_t *wsc, int wsclen, if (!pattern_match1(p, c, &mt)) return 0; p = p->next; - *newline++ = (ZLE_CHAR_T)c; + *new_line++ = (ZLE_CHAR_T)c; prestrict = prestrict->next; } diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index bdfcfd739..c0e5ff3d8 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -698,8 +698,10 @@ hasbrpsfx(Cmatch m, char *pre, char *suf) { char *op = lastprebr, *os = lastpostbr; VARARR(char, oline, zlemetall); - int oll = zlemetall, ocs = zlemetacs, ole = lastend, opcs = brpcs, oscs = brscs, ret; + int oll = zlemetall, newll, ole = lastend; + int opcs = brpcs, oscs = brscs, ret; + zle_save_positions(); memcpy(oline, zlemetaline, zlemetall); lastprebr = lastpostbr = NULL; @@ -710,7 +712,10 @@ hasbrpsfx(Cmatch m, char *pre, char *suf) foredel(zlemetall, CUT_RAW); spaceinline(oll); memcpy(zlemetaline, oline, oll); - zlemetacs = ocs; + /* we do not want to restore zlemetall */ + newll = zlemetall; + zle_restore_positions(); + zlemetall = newll; lastend = ole; brpcs = opcs; brscs = oscs; @@ -901,7 +906,14 @@ do_allmatches(UNUSED(int end)) for (minfo.group = amatches; minfo.group && !(minfo.group)->mcount; - minfo.group = (minfo.group)->next); + minfo.group = (minfo.group)->next) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(minfo.group->heap_id)) { + HEAP_ERROR(minfo.group->heap_id); + } +#endif + } + mc = (minfo.group)->matches; @@ -1167,6 +1179,11 @@ do_single(Cmatch m) struct chdata dat; dat.matches = amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(dat.matches->heap_id)) { + HEAP_ERROR(dat.matches->heap_id); + } +#endif dat.num = nmatches; dat.cur = m; @@ -1205,8 +1222,14 @@ do_menucmp(int lst) do { if (!*++(minfo.cur)) { do { - if (!(minfo.group = (minfo.group)->next)) + if (!(minfo.group = (minfo.group)->next)) { minfo.group = amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(minfo.group->heap_id)) { + HEAP_ERROR(minfo.group->heap_id); + } +#endif + } } while (!(minfo.group)->mcount); minfo.cur = minfo.group->matches; } @@ -1286,12 +1309,18 @@ accept_last(void) Cmgroup g; Cmatch *m; - for (g = amatches, m = NULL; g && (!m || !*m); g = g->next) + for (g = amatches, m = NULL; g && (!m || !*m); g = g->next) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif for (m = g->matches; *m; m++) if (!hasbrpsfx(*m, minfo.prebr, minfo.postbr)) { showinglist = -2; break; } + } } } menuacc++; @@ -1376,7 +1405,13 @@ do_ambig_menu(void) insgnum = comp_mod(insgnum, lastpermgnum); for (minfo.group = amatches; minfo.group && (minfo.group)->num != insgnum + 1; - minfo.group = (minfo.group)->next); + minfo.group = (minfo.group)->next) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(minfo.group->heap_id)) { + HEAP_ERROR(minfo.group->heap_id); + } +#endif + } if (!minfo.group || !(minfo.group)->mcount) { minfo.cur = NULL; minfo.asked = 0; @@ -1388,8 +1423,14 @@ do_ambig_menu(void) insmnum = comp_mod(insmnum, lastpermmnum); for (minfo.group = amatches; minfo.group && (minfo.group)->mcount <= insmnum; - minfo.group = (minfo.group)->next) + minfo.group = (minfo.group)->next) { insmnum -= (minfo.group)->mcount; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(minfo.group->heap_id)) { + HEAP_ERROR(minfo.group->heap_id); + } +#endif + } if (!minfo.group) { minfo.cur = NULL; minfo.asked = 0; @@ -1468,15 +1509,21 @@ calclist(int showall) if (lastinvcount == invcount && listdat.valid && onlyexpl == listdat.onlyexpl && menuacc == listdat.menuacc && showall == listdat.showall && - lines == listdat.lines && columns == listdat.columns) + zterm_lines == listdat.zterm_lines && + zterm_columns == listdat.zterm_columns) return 0; lastinvcount = invcount; for (g = amatches; g; g = g->next) { char **pp = g->ylist; - int nl = 0, l, glong = 1, gshort = columns, ndisp = 0, totl = 0; + int nl = 0, l, glong = 1, gshort = zterm_columns, ndisp = 0, totl = 0; int hasf = 0; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif g->flags |= CGF_PACKED | CGF_ROWS; if (!onlyexpl && pp) { @@ -1490,7 +1537,7 @@ calclist(int showall) /* We have an ylist, lets see, if it contains newlines. */ hidden = 1; while (!nl && *pp) { - if (MB_METASTRWIDTH(*pp) >= columns) + if (MB_METASTRWIDTH(*pp) >= zterm_columns) nl = 1; else nl = !!strchr(*pp++, '\n'); @@ -1506,11 +1553,12 @@ calclist(int showall) while (*sptr) { if ((nlptr = strchr(sptr, '\n'))) { *nlptr = '\0'; - nlines += 1 + (MB_METASTRWIDTH(sptr)-1) / columns; + nlines += 1 + (MB_METASTRWIDTH(sptr)-1) / + zterm_columns; *nlptr = '\n'; sptr = nlptr + 1; } else { - nlines += (MB_METASTRWIDTH(sptr)-1) / columns; + nlines += (MB_METASTRWIDTH(sptr)-1) / zterm_columns; break; } } @@ -1602,7 +1650,7 @@ calclist(int showall) g->dcount = ndisp; g->width = glong + CM_SPACE; g->shortest = gshort + CM_SPACE; - if ((g->cols = columns / g->width) > g->dcount) + if ((g->cols = zterm_columns / g->width) > g->dcount) g->cols = g->dcount; if (g->cols) { i = g->cols * g->width - CM_SPACE; @@ -1617,6 +1665,11 @@ calclist(int showall) for (g = amatches; g; g = g->next) { glines = 0; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif zfree(g->widths, 0); g->widths = NULL; @@ -1631,9 +1684,10 @@ calclist(int showall) } else { g->cols = 1; g->width = 1; - + while (*pp) - glines += 1 + (MB_METASTRWIDTH(*pp++) / columns); + glines += 1 + (MB_METASTRWIDTH(*pp++) / + zterm_columns); } } } else { @@ -1645,15 +1699,17 @@ calclist(int showall) } else if (!(g->flags & CGF_LINES)) { g->cols = 1; g->width = 0; - + for (p = g->matches; (m = *p); p++) if (!(m->flags & CMF_HIDE)) { if (m->disp) { if (!(m->flags & CMF_DISPLINE)) - glines += 1 + ((mlens[m->gnum] - 1) / columns); + glines += 1 + ((mlens[m->gnum] - 1) / + zterm_columns); } else if (showall || !(m->flags & (CMF_NOLIST | CMF_MULT))) - glines += 1 + (((mlens[m->gnum]) - 1) / columns); + glines += 1 + (((mlens[m->gnum]) - 1) / + zterm_columns); } } } @@ -1664,8 +1720,8 @@ calclist(int showall) if (!(g->flags & CGF_PACKED)) continue; - ws = g->widths = (int *) zalloc(columns * sizeof(int)); - memset(ws, 0, columns * sizeof(int)); + ws = g->widths = (int *) zalloc(zterm_columns * sizeof(int)); + memset(ws, 0, zterm_columns * sizeof(int)); tlines = g->lins; tcols = g->cols; width = 0; @@ -1681,14 +1737,14 @@ calclist(int showall) if (g->flags & CGF_ROWS) { int nth, tcol, len; - for (tcols = columns / (g->shortest + CM_SPACE); + for (tcols = zterm_columns / (g->shortest + CM_SPACE); tcols > g->cols; tcols--) { memset(ws, 0, tcols * sizeof(int)); for (width = nth = tcol = 0, tlines = 1; - width < columns && nth < g->dcount; + width < zterm_columns && nth < g->dcount; nth++, tcol++) { m = *p; @@ -1704,13 +1760,13 @@ calclist(int showall) ws[tcol] = len; } } - if (width < columns) + if (width < zterm_columns) break; } } else { int nth, tcol, tline, len; - for (tcols = columns / (g->shortest + CM_SPACE); + for (tcols = zterm_columns / (g->shortest + CM_SPACE); tcols > g->cols; tcols--) { @@ -1720,7 +1776,7 @@ calclist(int showall) memset(ws, 0, tcols * sizeof(int)); for (width = nth = tcol = tline = 0; - width < columns && nth < g->dcount; + width < zterm_columns && nth < g->dcount; nth++, tline++) { m = *p; @@ -1740,7 +1796,7 @@ calclist(int showall) ws[tcol] = len; } } - if (width < columns) + if (width < zterm_columns) break; } } @@ -1749,7 +1805,7 @@ calclist(int showall) if (g->flags & CGF_ROWS) { int nth, tcol, len; - for (tcols = columns / (g->shortest + CM_SPACE); + for (tcols = zterm_columns / (g->shortest + CM_SPACE); tcols > g->cols; tcols--) { @@ -1757,7 +1813,7 @@ calclist(int showall) for (width = nth = tcol = 0, tlines = 1, p = skipnolist(g->matches, showall); - *p && width < columns && nth < g->dcount; + *p && width < zterm_columns && nth < g->dcount; nth++, p = skipnolist(p + 1, showall), tcol++) { m = *p; @@ -1774,13 +1830,13 @@ calclist(int showall) ws[tcol] = len; } } - if (width < columns) + if (width < zterm_columns) break; } } else { int nth, tcol, tline, len; - for (tcols = columns / (g->shortest + CM_SPACE); + for (tcols = zterm_columns / (g->shortest + CM_SPACE); tcols > g->cols; tcols--) { @@ -1791,7 +1847,7 @@ calclist(int showall) for (width = nth = tcol = tline = 0, p = skipnolist(g->matches, showall); - *p && width < columns && nth < g->dcount; + *p && width < zterm_columns && nth < g->dcount; nth++, p = skipnolist(p + 1, showall), tline++) { m = *p; @@ -1812,7 +1868,7 @@ calclist(int showall) ws[tcol] = len; } } - if (width < columns) { + if (width < zterm_columns) { if (++tcol < tcols) tcols = tcol; break; @@ -1823,7 +1879,7 @@ calclist(int showall) if (tcols <= g->cols) tlines = g->lins; if (tlines == g->lins) { - zfree(ws, columns * sizeof(int)); + zfree(ws, zterm_columns * sizeof(int)); g->widths = NULL; } else { nlines += tlines - g->lins; @@ -1848,6 +1904,11 @@ calclist(int showall) else for (g = amatches; g; g = g->next) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif zfree(g->widths, 0); g->widths = NULL; } @@ -1857,8 +1918,8 @@ calclist(int showall) listdat.nlines = nlines; listdat.menuacc = menuacc; listdat.onlyexpl = onlyexpl; - listdat.columns = columns; - listdat.lines = lines; + listdat.zterm_columns = zterm_columns; + listdat.zterm_lines = zterm_lines; listdat.showall = showall; return 1; @@ -1879,7 +1940,7 @@ asklist(void) if ((!minfo.cur || !minfo.asked) && ((complistmax > 0 && listdat.nlist >= complistmax) || (complistmax < 0 && listdat.nlines <= -complistmax) || - (!complistmax && listdat.nlines >= lines))) { + (!complistmax && listdat.nlines >= zterm_lines))) { int qup, l; zsetterm(); @@ -1888,7 +1949,7 @@ asklist(void) listdat.nlist, listdat.nlines) : fprintf(shout, "zsh: do you wish to see all %d lines? ", listdat.nlines)); - qup = ((l + columns - 1) / columns) - 1; + qup = ((l + zterm_columns - 1) / zterm_columns) - 1; fflush(shout); if (!getzlequery()) { if (clearflag) { @@ -1935,6 +1996,11 @@ printlist(int over, CLPrintFunc printm, int showall) for (g = amatches; g; g = g->next) { char **pp = g->ylist; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif if ((e = g->expls)) { int l; @@ -1982,7 +2048,7 @@ printlist(int over, CLPrintFunc printm, int showall) while ((p = *pp++)) { zputs(p, shout); if (*pp) { - if (MB_METASTRWIDTH(p) % columns) + if (MB_METASTRWIDTH(p) % zterm_columns) putc('\n', shout); else fputs(" \010", shout); @@ -2108,7 +2174,7 @@ printlist(int over, CLPrintFunc printm, int showall) if (clearflag) { /* Move the cursor up to the prompt, if always_last_prompt * * is set and all that... */ - if ((ml = listdat.nlines + nlnct - 1) < lines) { + if ((ml = listdat.nlines + nlnct - 1) < zterm_lines) { tcmultout(TCUP, TCMULTUP, ml); showinglist = -1; @@ -2129,12 +2195,18 @@ bld_all_str(Cmatch all) { Cmgroup g; Cmatch *mp, m; - int len = columns - 5, t, add = 0; - VARARR(char, buf, columns + 1); + int len = zterm_columns - 5, t, add = 0; + VARARR(char, buf, zterm_columns + 1); buf[0] = '\0'; - for (g = amatches; g && !g->mcount; g = g->next); + for (g = amatches; g && !g->mcount; g = g->next) { +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(g->heap_id)) { + HEAP_ERROR(g->heap_id); + } +#endif + } mp = g->matches; while (1) { @@ -2252,6 +2324,11 @@ list_matches(UNUSED(Hookdef dummy), UNUSED(void *dummy2)) #endif dat.matches = amatches; +#ifdef ZSH_HEAP_DEBUG + if (memory_validate(dat.matches->heap_id)) { + HEAP_ERROR(dat.matches->heap_id); + } +#endif dat.num = nmatches; dat.cur = NULL; ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat); diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index 7c5bc2181..cd508d0ac 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -226,8 +226,8 @@ cd_prep() runp = &(cd_state.runs); if (cd_state.groups) { - int lines = cd_state.groups + cd_state.descs; - VARARR(Cdstr, grps, lines); + int preplines = cd_state.groups + cd_state.descs; + VARARR(Cdstr, grps, preplines); VARARR(int, wids, cd_state.maxg); Cdstr gs, gp, gn, *gpp; int i, j, d; @@ -275,7 +275,7 @@ cd_prep() if (cd_state.gprew > cd_state.maxmlen && cd_state.maxglen > 1) return 1; - for (i = 0; i < lines; i++) { + for (i = 0; i < preplines; i++) { Cdstr s = grps[i]; int dummy; @@ -283,9 +283,9 @@ cd_prep() unmetafy(s->sortstr, &dummy); } - qsort(grps, lines, sizeof(Cdstr), cd_sort); + qsort(grps, preplines, sizeof(Cdstr), cd_sort); - for (i = lines, strp = grps; i > 1; i--, strp++) { + for (i = preplines, strp = grps; i > 1; i--, strp++) { strp2 = strp + 1; if (!strcmp((*strp)->desc, (*strp2)->desc)) continue; @@ -303,9 +303,9 @@ cd_prep() expl = (Cdrun) zalloc(sizeof(*run)); expl->type = CRT_EXPL; expl->strs = grps[0]; - expl->count = lines; + expl->count = preplines; - for (i = lines, strp = grps, strp2 = NULL; i; i--, strp++) { + for (i = preplines, strp = grps, strp2 = NULL; i; i--, strp++) { str = *strp; *strp = str->other; if (strp2) @@ -321,7 +321,7 @@ cd_prep() *strp2 = NULL; for (i = cd_state.maxg - 1; i; i--) { - for (d = 0, j = lines, strp = grps; j; j--, strp++) { + for (d = 0, j = preplines, strp = grps; j; j--, strp++) { if ((str = *strp)) { if (d) { *runp = run = (Cdrun) zalloc(sizeof(*run)); @@ -465,7 +465,7 @@ cd_init(char *nam, char *hide, char *mlen, char *sep, cd_state.showd = disp; cd_state.maxg = cd_state.groups = cd_state.descs = 0; cd_state.maxmlen = atoi(mlen); - itmp = columns - cd_state.swidth - 4; + itmp = zterm_columns - cd_state.swidth - 4; if (cd_state.maxmlen > itmp) cd_state.maxmlen = itmp; if (cd_state.maxmlen < 4) @@ -545,7 +545,7 @@ cd_init(char *nam, char *hide, char *mlen, char *sep, args++; } if (disp && grp) { - int mg = columns; + int mg = zterm_columns; do { cd_group(mg); @@ -651,7 +651,8 @@ cd_get(char **params) * is available. Leave 1 character at the end of screen * as safety margin */ - remw = columns - cd_state.premaxw - cd_state.swidth - 3; + remw = zterm_columns - cd_state.premaxw - + cd_state.swidth - 3; d = str->desc; w = MB_METASTRWIDTH(d); if (w <= remw) @@ -727,7 +728,8 @@ cd_get(char **params) case CRT_EXPL: { /* add columns as safety margin */ - VARARR(char, dbuf, cd_state.suf + cd_state.slen + columns); + VARARR(char, dbuf, cd_state.suf + cd_state.slen + + zterm_columns); char buf[20], *p, *pp, *d; int i = run->count, remw, w, l; @@ -743,7 +745,8 @@ cd_get(char **params) } strcpy(dbuf, cd_state.sep); - remw = columns - cd_state.gprew - cd_state.swidth - CM_SPACE; + remw = zterm_columns - cd_state.gprew - + cd_state.swidth - CM_SPACE; p = pp = dbuf + cd_state.slen; d = str->desc; w = MB_METASTRWIDTH(d); @@ -1904,7 +1907,7 @@ ca_parse_line(Cadef d, int multi, int first) state.argbeg = state.optbeg = state.nargbeg = state.restbeg = state.actopts = state.nth = state.inopt = state.inarg = state.opt = state.arg = 1; state.argend = argend = arrlen(compwords) - 1; - state.inrest = state.doff = state.singles = state.doff = state.oopt = 0; + state.inrest = state.doff = state.singles = state.oopt = 0; state.curpos = compcurrent; state.args = znewlinklist(); state.oargs = (LinkList *) zalloc(d->nopts * sizeof(LinkList)); @@ -3355,7 +3358,6 @@ bin_compvalues(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) return 0; } - return 1; case 'D': /* This returns the description and action to use if we are at diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h index 32f3e59f6..bedf28f17 100644 --- a/Src/Zle/zle.h +++ b/Src/Zle/zle.h @@ -385,6 +385,47 @@ enum suffixflags { SUFFLAGS_SPACE = 0x0001 /* Add a space when removing suffix */ }; + +/* Flags for the region_highlight structure */ +enum { + /* Offsets include predisplay */ + ZRH_PREDISPLAY = 1 +}; + +/* + * Attributes used for highlighting regions. + * and mark. + */ +struct region_highlight { + /* Attributes turned on in the region */ + int atr; + /* Start of the region */ + int start; + /* Start of the region in metafied ZLE line */ + int start_meta; + /* + * End of the region: position of the first character not highlighted + * (the same system as for point and mark). + */ + int end; + /* End of the region in metafied ZLE line */ + int end_meta; + /* + * Any of the flags defined above. + */ + int flags; +}; + +/* + * Count of special uses of region highlighting, which account + * for the first few elements of region_highlights. + * 0: region between point and mark + * 1: isearch region + * 2: suffix + */ +#define N_SPECIAL_HIGHLIGHTS (3) + + #ifdef MULTIBYTE_SUPPORT /* * We use a wint_t here, since we need an invalid character as a @@ -420,15 +461,28 @@ typedef REFRESH_ELEMENT *REFRESH_STRING; #if defined(MULTIBYTE_SUPPORT) && defined(__STDC_ISO_10646__) +/* + * With ISO 10646 there is a private range defined within + * the encoding. We use this for storing single-byte + * characters in sections of strings that wouldn't convert to wide + * characters. This allows to preserve the string when transformed + * back to multibyte strings. + */ + +/* The start of the private range we use, for 256 characters */ #define ZSH_INVALID_WCHAR_BASE (0xe000U) +/* Detect a wide character within our range */ #define ZSH_INVALID_WCHAR_TEST(x) \ ((unsigned)(x) >= ZSH_INVALID_WCHAR_BASE && \ (unsigned)(x) <= (ZSH_INVALID_WCHAR_BASE + 255u)) +/* Turn a wide character in that range back to single byte */ #define ZSH_INVALID_WCHAR_TO_CHAR(x) \ ((char)((unsigned)(x) - ZSH_INVALID_WCHAR_BASE)) +/* Turn a wide character in that range to an integer */ #define ZSH_INVALID_WCHAR_TO_INT(x) \ ((int)((unsigned)(x) - ZSH_INVALID_WCHAR_BASE)) -#define ZSH_CHAR_TO_INVALID_WCHAR(x) \ +/* Turn a single byte character into a private wide character */ +#define ZSH_CHAR_TO_INVALID_WCHAR(x) \ ((wchar_t)(STOUC(x) + ZSH_INVALID_WCHAR_BASE)) #endif diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index b5ff05cd1..bd5bc36d5 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -470,7 +470,7 @@ historysearchbackward(char **args) histpos++; /* ensure we're not on a combining character */ CCRIGHTPOS(histpos); - /* histpos from now on on is an index into the metafied string */ + /* histpos from now on is an index into the metafied string */ srch_str = zlelineasstring(zleline, histpos, 0, NULL, NULL, 0); } free(line); @@ -765,6 +765,7 @@ zle_setline(Histent he) histline = he->histnum; setline(GETZLETEXT(he), ZSL_COPY|ZSL_TOEND); + zlecallhook("zle-history-line-set", NULL); setlastline(); clearlist = 1; if (remetafy) diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 0ac45431d..6acedee70 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -633,7 +633,7 @@ raw_getbyte(long do_keytmout, char *cptr) /* * Make sure a user interrupt gets passed on straight away. */ - if (selret < 0 && errflag) + if (selret < 0 && (errflag || retflag || breaks || exit_pending)) break; /* * Try to avoid errors on our special fd's from @@ -875,7 +875,7 @@ getbyte(long do_keytmout, int *timeout) icnt = 0; if (errno == EINTR) { die = 0; - if (!errflag && !retflag && !breaks) + if (!errflag && !retflag && !breaks && !exit_pending) continue; errflag = 0; breaks = obreaks; diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c index f15b114f5..0e940bc21 100644 --- a/Src/Zle/zle_move.c +++ b/Src/Zle/zle_move.c @@ -30,7 +30,7 @@ #include "zle.mdh" #include "zle_move.pro" -static int vimarkcs[27], vimarkline[27]; +static int vimarkcs[26], vimarkline[26]; #ifdef MULTIBYTE_SUPPORT /* @@ -536,6 +536,9 @@ vimatchbracket(UNUSED(char **args)) int ocs = zlecs, dir, ct; unsigned char oth, me; + if ((zlecs == zlell || zleline[zlecs] == '\n') && zlecs > 0) + DECCS(); + otog: if (zlecs == zlell || zleline[zlecs] == '\n') { zlecs = ocs; @@ -803,16 +806,11 @@ int vigotomark(UNUSED(char **args)) { ZLE_INT_T ch; - LASTFULLCHAR_T lfc = LASTFULLCHAR; ch = getfullchar(0); - if (ch == lfc) - ch = 26; - else { - if (ch < ZWC('a') || ch > ZWC('z')) - return 1; - ch -= ZWC('a'); - } + if (ch < ZWC('a') || ch > ZWC('z')) + return 1; + ch -= ZWC('a'); if (!vimarkline[ch]) return 1; if (curhist != vimarkline[ch] && !zle_goto_hist(vimarkline[ch], 0, 0)) { diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c index 1a23d3c67..3fdb5f8ed 100644 --- a/Src/Zle/zle_params.c +++ b/Src/Zle/zle_params.c @@ -230,8 +230,10 @@ get_cursor(UNUSED(Param pm)) /* A lot of work for one number, but still... */ ZLE_STRING_T tmpline; int tmpcs, tmpll, tmpsz; - tmpline = stringaszleline(zlemetaline, zlemetacs, + char *tmpmetaline = ztrdup(zlemetaline); + tmpline = stringaszleline(tmpmetaline, zlemetacs, &tmpll, &tmpsz, &tmpcs); + free(tmpmetaline); free(tmpline); return tmpcs; } diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c index 3b60285c9..797f86251 100644 --- a/Src/Zle/zle_refresh.c +++ b/Src/Zle/zle_refresh.c @@ -210,50 +210,21 @@ int predisplaylen, postdisplaylen; static int default_atr_on, special_atr_on; -/* Flags for the region_highlight structure */ -enum { - /* Offsets include predisplay */ - ZRH_PREDISPLAY = 1 -}; - -/* - * Attributes used for highlighting regions. - * and mark. - */ -struct region_highlight { - /* Attributes turned on in the region */ - int atr; - /* Start of the region */ - int start; - /* - * End of the region: position of the first character not highlighted - * (the same system as for point and mark). - */ - int end; - /* - * Any of the flags defined above. - */ - int flags; -}; /* * Array of region highlights, no special termination. * The first element (0) always describes the region between * point and mark. Any other elements are set by the user * via the parameter region_highlight. */ + +/**/ struct region_highlight *region_highlights; -/* - * Count of special uses of region highlighting, which account - * for the first few elements of region_highlights. - * 0: region between point and mark - * 1: isearch region - * 2: suffix - */ -#define N_SPECIAL_HIGHLIGHTS (3) + /* * Number of elements in region_highlights. * This includes the special elements above. */ +/**/ int n_region_highlights; /* @@ -717,12 +688,12 @@ resetvideo(void) { int ln; - winw = columns; /* terminal width */ + winw = zterm_columns; /* terminal width */ if (termflags & TERM_SHORT) winh = 1; else - winh = (lines < 2) ? 24 : lines; - rwinh = lines; /* keep the real number of lines */ + winh = (zterm_lines < 2) ? 24 : zterm_lines; + rwinh = zterm_lines; /* keep the real number of lines */ vln = vmaxln = winprompt = 0; winpos = -1; if (winw_alloc != winw || winh_alloc != winh) { @@ -1111,7 +1082,7 @@ zrefresh(void) cleareol = 0; /* unset */ more_start = more_end = 0; /* unset */ - if (isset(SINGLELINEZLE) || lines < 3 + if (isset(SINGLELINEZLE) || zterm_lines < 3 || (termflags & (TERM_NOUP | TERM_BAD | TERM_UNKNOWN))) termflags |= TERM_SHORT; else @@ -1167,7 +1138,7 @@ zrefresh(void) } fflush(shout); clearf = clearflag; - } else if (winw != columns || rwinh != lines) + } else if (winw != zterm_columns || rwinh != zterm_lines) resetvideo(); /* now winw equals columns and winh equals lines @@ -2033,7 +2004,7 @@ refreshline(int ln) * last line lest undesired scrolling occurs due to `illegal' * characters on screen */ - if (tccan(TCINS) && (vln != lines - 1)) { + if (tccan(TCINS) && (vln != zterm_lines - 1)) { /* not on last line */ for (i = 1; nl[i].chr; i++) { if (tcinscost(i) < wpfxlen(ol, nl + i)) { diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 566537761..8f7c2aac1 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -1899,7 +1899,7 @@ get_comp_string(void) *dbeg = '{'; i -= len; boffs -= len; - strcpy(dbeg, dbeg + len); + memmove(dbeg, dbeg + len, 1+strlen(dbeg+len)); dp -= len; } bbeg = lastp = p; @@ -1948,7 +1948,7 @@ get_comp_string(void) *dbeg = '{'; i -= len; boffs -= len; - strcpy(dbeg, dbeg + len); + memmove(dbeg, dbeg + len, 1+strlen(dbeg+len)); dp -= len; } bbeg = NULL; @@ -2013,7 +2013,7 @@ get_comp_string(void) new->qpos = strlen(quotename(predup, NULL)); *dbeg = '{'; boffs -= len; - strcpy(dbeg, dbeg + len); + memmove(dbeg, dbeg + len, 1+strlen(dbeg+len)); } if (brend) { Brinfo bp, prev = NULL; @@ -2026,7 +2026,7 @@ get_comp_string(void) l = bp->qpos; bp->pos = strlen(predup + p + l); bp->qpos = strlen(quotename(predup + p + l, NULL)); - strcpy(predup + p, predup + p + l); + memmove(predup + p, predup + p + l, 1+bp->pos); } } if (hascom) { @@ -2419,13 +2419,13 @@ printfmt(char *fmt, int n, int dopr, int doesc) if (tccan(TCCLEAREOL)) tcout(TCCLEAREOL); else { - int s = columns - 1 - (cc % columns); + int s = zterm_columns - 1 - (cc % zterm_columns); while (s-- > 0) putc(' ', shout); } } - l += 1 + ((cc - 1) / columns); + l += 1 + ((cc - 1) / zterm_columns); cc = 0; if (dopr) putc('\n', shout); @@ -2445,18 +2445,18 @@ printfmt(char *fmt, int n, int dopr, int doesc) } else p += clen; cc += WCWIDTH_WINT(cchar); - if (dopr && !(cc % columns)) + if (dopr && !(cc % zterm_columns)) fputs(" \010", shout); } } } if (dopr) { - if (!(cc % columns)) + if (!(cc % zterm_columns)) fputs(" \010", shout); if (tccan(TCCLEAREOL)) tcout(TCCLEAREOL); else { - int s = columns - 1 - (cc % columns); + int s = zterm_columns - 1 - (cc % zterm_columns); while (s-- > 0) putc(' ', shout); @@ -2467,7 +2467,7 @@ printfmt(char *fmt, int n, int dopr, int doesc) * cc is correct, i.e. if just misses wrapping we still add 1. * (Why?) */ - return l + (cc / columns); + return l + (cc / zterm_columns); } /* This is used to print expansions. */ @@ -2481,8 +2481,8 @@ listlist(LinkList l) LinkNode node; char **p; VARARR(int, lens, num); - VARARR(int, widths, columns); - int longest = 0, shortest = columns, totl = 0; + VARARR(int, widths, zterm_columns); + int longest = 0, shortest = zterm_columns, totl = 0; int len, ncols, nlines, tolast, col, i, max, pack = 0, *lenp; for (node = firstnode(l), p = data; node; incnode(node), p++) @@ -2500,7 +2500,7 @@ listlist(LinkList l) shortest = len; totl += len; } - if ((ncols = ((columns + 2) / longest))) { + if ((ncols = ((zterm_columns + 2) / longest))) { int tlines = 0, tline, tcols = 0, maxlen, nth, width; nlines = (num + ncols - 1) / ncols; @@ -2509,7 +2509,7 @@ listlist(LinkList l) if (isset(LISTROWSFIRST)) { int count, tcol, first, maxlines = 0, llines; - for (tcols = columns / shortest; tcols > ncols; + for (tcols = zterm_columns / shortest; tcols > ncols; tcols--) { for (nth = first = maxlen = width = maxlines = llines = tcol = 0, @@ -2522,7 +2522,7 @@ listlist(LinkList l) nth += tcols; tlines++; if (nth >= num) { - if ((width += maxlen) >= columns) + if ((width += maxlen) >= zterm_columns) break; widths[tcol++] = maxlen; maxlen = 0; @@ -2536,13 +2536,13 @@ listlist(LinkList l) widths[tcol++] = maxlen; width += maxlen; } - if (!count && width < columns) + if (!count && width < zterm_columns) break; } if (tcols > ncols) tlines = maxlines; } else { - for (tlines = ((totl + columns) / columns); + for (tlines = ((totl + zterm_columns) / zterm_columns); tlines < nlines; tlines++) { for (p = data, nth = tline = width = maxlen = tcols = 0; @@ -2550,7 +2550,7 @@ listlist(LinkList l) if (lens[nth] > maxlen) maxlen = lens[nth]; if (++tline == tlines) { - if ((width += maxlen) >= columns) + if ((width += maxlen) >= zterm_columns) break; widths[tcols++] = maxlen; maxlen = tline = 0; @@ -2560,7 +2560,7 @@ listlist(LinkList l) widths[tcols++] = maxlen; width += maxlen; } - if (nth == num && width < columns) + if (nth == num && width < zterm_columns) break; } } @@ -2572,7 +2572,7 @@ listlist(LinkList l) } else { nlines = 0; for (p = data; *p; p++) - nlines += 1 + (strlen(*p) / columns); + nlines += 1 + (strlen(*p) / zterm_columns); } /* Set the cursor below the prompt. */ trashzle(); @@ -2581,7 +2581,7 @@ listlist(LinkList l) clearflag = (isset(USEZLE) && !termflags && tolast); max = getiparam("LISTMAX"); - if ((max && num > max) || (!max && nlines > lines)) { + if ((max && num > max) || (!max && nlines > zterm_lines)) { int qup, l; zsetterm(); @@ -2589,7 +2589,7 @@ listlist(LinkList l) fprintf(shout, "zsh: do you wish to see all %d possibilities (%d lines)? ", num, nlines) : fprintf(shout, "zsh: do you wish to see all %d lines? ", nlines)); - qup = ((l + columns - 1) / columns) - 1; + qup = ((l + zterm_columns - 1) / zterm_columns) - 1; fflush(shout); if (!getzlequery()) { if (clearflag) { @@ -2650,11 +2650,13 @@ listlist(LinkList l) } else { for (p = data; *p; p++) { nicezputs(*p, shout); - putc('\n', shout); + /* One column: newlines between elements, not after the last */ + if (p[1]) + putc('\n', shout); } } if (clearflag) { - if ((nlines += nlnct - 1) < lines) { + if ((nlines += nlnct - 1) < zterm_lines) { tcmultout(TCUP, TCMULTUP, nlines); showinglist = -1; } else @@ -2675,14 +2677,13 @@ int doexpandhist(void) { char *ol; - int oll, ocs, ne = noerrs, err, ona = noaliases; + int ne = noerrs, err, ona = noaliases; UNMETACHECK(); pushheap(); metafy_line(); - oll = zlemetall; - ocs = zlemetacs; + zle_save_positions(); ol = dupstring(zlemetaline); expanding = 1; excs = zlemetacs; @@ -2725,8 +2726,7 @@ doexpandhist(void) } strcpy(zlemetaline, ol); - zlemetall = oll; - zlemetacs = ocs; + zle_restore_positions(); unmetafy_line(); popheap(); diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 291bdd3cb..45e30445e 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -179,6 +179,8 @@ zlecharasstring(ZLE_CHAR_T inchar, char *buf) * string length, without the NULL byte. * * If outcsp is non-NULL, assign the new character position. + * If outcsp is &zlemetacs, update the positions in the region_highlight + * array, too. This is a bit of a hack. * * If useheap is 1, memory is returned from the heap, else is allocated * for later freeing. @@ -189,7 +191,8 @@ mod_export char * zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, int *outcsp, int useheap) { - int outcs, outll; + int outcs, outll, sub; + struct region_highlight *rhp; #ifdef MULTIBYTE_SUPPORT char *s; @@ -201,9 +204,26 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, outcs = 0; memset(&mbs, 0, sizeof(mbs)); - for (i=0; i < inll; i++, incs--) { + for (i=0; i < inll; i++) { if (incs == 0) outcs = mb_len; + incs--; + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->flags & ZRH_PREDISPLAY) + sub = predisplaylen; + else + sub = 0; + if (rhp->start - sub == 0) + rhp->start_meta = sub + mb_len; + rhp->start--; + if (rhp->end - sub == 0) + rhp->end_meta = sub + mb_len; + rhp->end--; + } + } #ifdef __STDC_ISO_10646__ if (ZSH_INVALID_WCHAR_TEST(instr[i])) { s[mb_len++] = ZSH_INVALID_WCHAR_TO_CHAR(instr[i]); @@ -222,12 +242,34 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, } if (incs == 0) outcs = mb_len; + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->flags & ZRH_PREDISPLAY) + sub = predisplaylen; + else + sub = 0; + if (rhp->start - sub == 0) + rhp->start_meta = sub + mb_len; + if (rhp->end - sub == 0) + rhp->end_meta = sub + mb_len; + } + } s[mb_len] = '\0'; outll = mb_len; #else outll = inll; outcs = incs; + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + rhp->start_meta = rhp->start; + rhp->end_meta = rhp->end; + } + } #endif /* @@ -243,11 +285,37 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, #endif char *stopcs = strp + outcs; char *stopll = strp + outll; - + char *startp = strp; + + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + /* Used as temporary storage */ + rhp->start = rhp->start_meta; + rhp->end = rhp->end_meta; + } + } while (strp < stopll) { if (imeta(*strp)) { if (strp < stopcs) outcs++; + if (region_highlights && outcsp == &zlemetacs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->flags & ZRH_PREDISPLAY) + sub = predisplaylen; + else + sub = 0; + if (strp < startp + rhp->start - sub) { + rhp->start_meta++; + } + if (strp < startp + rhp->end - sub) { + rhp->end_meta++; + } + } + } outll++; } strp++; @@ -290,6 +358,9 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp, * each metafied character) is converted into the corresponding * character position in *outcs. * + * If, further, outcs is &zlecs, we update the positions in the + * region_highlight array, too. (This is a bit of a hack.) + * * Note that instr is modified in place, hence should be copied * first if necessary; * @@ -303,7 +374,8 @@ mod_export ZLE_STRING_T stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) { ZLE_STRING_T outstr; - int ll, sz; + int ll, sz, sub; + struct region_highlight *rhp; #ifdef MULTIBYTE_SUPPORT mbstate_t mbs; #endif @@ -316,10 +388,36 @@ stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) * is all the processing required to calculate outcs. */ char *inptr = instr, *cspos = instr + incs; - while (*inptr && inptr < cspos) { + if (region_highlights && outcs == &zlecs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + rhp->start = rhp->start_meta; + rhp->end = rhp->end_meta; + } + } + while (*inptr) { if (*inptr == Meta) { + if (inptr < cspos) { + incs--; + } + if (region_highlights && outcs == &zlecs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->flags & ZRH_PREDISPLAY) + sub = predisplaylen; + else + sub = 0; + if (inptr - instr < rhp->start - sub) { + rhp->start_meta--; + } + if (inptr - instr < rhp->end - sub) { + rhp->end_meta--; + } + } + } inptr++; - incs--; } inptr++; } @@ -385,6 +483,24 @@ stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) int offs = inptr - instr; if (offs <= incs && incs < offs + (int)cnt) *outcs = outptr - outstr; + if (region_highlights && outcs == &zlecs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->flags & ZRH_PREDISPLAY) + sub = predisplaylen; + else + sub = 0; + if (offs <= rhp->start_meta - sub && + rhp->start_meta - sub < offs + (int)cnt) { + rhp->start = outptr - outstr + sub; + } + if (offs <= rhp->end_meta - sub && + rhp->end_meta - sub < offs + (int)cnt) { + rhp->end = outptr - outstr + sub; + } + } + } } inptr += cnt; @@ -404,6 +520,14 @@ stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs) *outll = ll; if (outcs) *outcs = incs; + if (region_highlights && outcs == &zlecs) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + rhp->start = rhp->start_meta; + rhp->end = rhp->end_meta; + } + } #endif return outstr; @@ -432,6 +556,158 @@ zlegetline(int *ll, int *cs) } +/* Forward reference */ +struct zle_region; + +/* A non-special entry in region_highlight */ +struct zle_region { + struct zle_region *next; + /* Entries of region_highlight, as needed */ + int atr; + int start; + int end; + int flags; +}; + +/* Forward reference */ +struct zle_position; + +/* A saved set of position information */ +struct zle_position { + /* Link pointer */ + struct zle_position *next; + /* Cursor position */ + int cs; + /* Mark */ + int mk; + /* Line length */ + int ll; + struct zle_region *regions; +}; + +/* LIFO stack of positions */ +struct zle_position *zle_positions; + +/* + * Save positions including cursor, end-of-line and + * (non-special) region highlighting. + * + * Must be matched by a subsequent zle_restore_positions(). + */ + +/**/ +mod_export void +zle_save_positions(void) +{ + struct region_highlight *rhp; + struct zle_position *newpos; + struct zle_region **newrhpp, *newrhp; + + newpos = (struct zle_position *)zalloc(sizeof(*newpos)); + + newpos->mk = mark; + if (zlemetaline) { + /* Use metafied information */ + newpos->cs = zlemetacs; + newpos->ll = zlemetall; + } else { + /* Use unmetafied information */ + newpos->cs = zlecs; + newpos->ll = zlell; + + } + + newrhpp = &newpos->regions; + *newrhpp = NULL; + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + /* + * This is a FIFO stack, so we preserve the order + * of entries when we restore region_highlights. + */ + newrhp = *newrhpp = (struct zle_region *)zalloc(sizeof(**newrhpp)); + newrhp->next = NULL; + newrhp->atr = rhp->atr; + newrhp->flags = rhp->flags; + if (zlemetaline) { + newrhp->start = rhp->start_meta; + newrhp->end = rhp->end_meta; + } else { + newrhp->start = rhp->start; + newrhp->end = rhp->end; + } + newrhpp = &newrhp->next; + } + } + + newpos->next = zle_positions; + zle_positions = newpos; +} + +/* + * Restore positions previously saved. + * Relies on zlemetaline being restored correctly beforehand, + * so that it can tell whether to use metafied positions or not. + */ + +/**/ +mod_export void +zle_restore_positions(void) +{ + struct zle_position *oldpos = zle_positions; + struct zle_region *oldrhp; + struct region_highlight *rhp; + int nreg; + + zle_positions = oldpos->next; + + mark = oldpos->mk; + if (zlemetaline) { + /* Use metafied information */ + zlemetacs = oldpos->cs; + zlemetall = oldpos->ll; + } else { + /* Use unmetafied information */ + zlecs = oldpos->cs; + zlell = oldpos->ll; + } + + /* Count number of regions and see if the array needs resizing */ + for (nreg = 0, oldrhp = oldpos->regions; + oldrhp; + nreg++, oldrhp = oldrhp->next) + ; + if (nreg + N_SPECIAL_HIGHLIGHTS != n_region_highlights) { + n_region_highlights = nreg + N_SPECIAL_HIGHLIGHTS; + region_highlights = (struct region_highlight *) + zrealloc(region_highlights, + sizeof(struct region_highlight) * n_region_highlights); + } + oldrhp = oldpos->regions; + rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + while (oldrhp) { + struct zle_region *nextrhp = oldrhp->next; + + rhp->atr = oldrhp->atr; + rhp->flags = oldrhp->flags; + if (zlemetaline) { + rhp->start_meta = oldrhp->start; + rhp->end_meta = oldrhp->end; + } else { + rhp->start = oldrhp->start; + rhp->end = oldrhp->end; + } + + zfree(oldrhp, sizeof(*oldrhp)); + oldrhp = nextrhp; + rhp++; + } + + zfree(oldpos, sizeof(*oldpos)); +} + /* * Basic utility functions for adding to line or removing from line. * At this level the counts supplied are raw character counts, so @@ -449,7 +725,8 @@ zlegetline(int *ll, int *cs) mod_export void spaceinline(int ct) { - int i; + int i, sub; + struct region_highlight *rhp; if (zlemetaline) { sizeline(ct + zlemetall); @@ -460,6 +737,23 @@ spaceinline(int ct) if (mark > zlemetacs) mark += ct; + + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->flags & ZRH_PREDISPLAY) + sub = predisplaylen; + else + sub = 0; + if (rhp->start_meta - sub >= zlemetacs) { + rhp->start_meta += ct; + } + if (rhp->end_meta - sub >= zlemetacs) { + rhp->end_meta += ct; + } + } + } } else { sizeline(ct + zlell); for (i = zlell; --i >= zlecs;) @@ -469,26 +763,98 @@ spaceinline(int ct) if (mark > zlecs) mark += ct; + + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->flags & ZRH_PREDISPLAY) + sub = predisplaylen; + else + sub = 0; + if (rhp->start - sub >= zlecs) { + rhp->start += ct; + } + if (rhp->end - sub >= zlecs) { + rhp->end += ct; + } + } + } } region_active = 0; } +/* + * Within the ZLE line, cut the "cnt" characters from position "to". + */ + /**/ void shiftchars(int to, int cnt) { + struct region_highlight *rhp; + int sub; + if (mark >= to + cnt) mark -= cnt; else if (mark > to) mark = to; if (zlemetaline) { + /* before to is updated... */ + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->flags & ZRH_PREDISPLAY) + sub = predisplaylen; + else + sub = 0; + if (rhp->start_meta - sub > to) { + if (rhp->start_meta - sub > to + cnt) + rhp->start_meta -= cnt; + else + rhp->start_meta = to; + } + if (rhp->end_meta - sub > to) { + if (rhp->end_meta - sub > to + cnt) + rhp->end_meta -= cnt; + else + rhp->end_meta = to; + } + } + } + while (to + cnt < zlemetall) { zlemetaline[to] = zlemetaline[to + cnt]; to++; } zlemetaline[zlemetall = to] = '\0'; } else { + /* before to is updated... */ + if (region_highlights) { + for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS; + rhp < region_highlights + n_region_highlights; + rhp++) { + if (rhp->flags & ZRH_PREDISPLAY) + sub = predisplaylen; + else + sub = 0; + if (rhp->start - sub > to) { + if (rhp->start - sub > to + cnt) + rhp->start -= cnt; + else + rhp->start = to; + } + if (rhp->end - sub > to) { + if (rhp->end - sub > to + cnt) + rhp->end -= cnt; + else + rhp->end = to; + } + } + } + while (to + cnt < zlell) { zleline[to] = zleline[to + cnt]; to++; @@ -891,7 +1257,7 @@ showmsg(char const *msg) p++; putc('\n', shout); - up += 1 + cc / columns; + up += 1 + cc / zterm_columns; cc = 0; } else { /* @@ -942,7 +1308,7 @@ showmsg(char const *msg) c = *++p ^ 32; if(c == '\n') { putc('\n', shout); - up += 1 + cc / columns; + up += 1 + cc / zterm_columns; cc = 0; } else { char const *n = nicechar(c); @@ -951,7 +1317,7 @@ showmsg(char const *msg) } } #endif - up += cc / columns; + up += cc / zterm_columns; if (clearflag) { putc('\r', shout); @@ -1085,8 +1451,10 @@ mkundoent(void) struct change *ch; UNMETACHECK(); - if(lastll == zlell && !ZS_memcmp(lastline, zleline, zlell)) + if(lastll == zlell && !ZS_memcmp(lastline, zleline, zlell)) { + lastcs = zlecs; return; + } for(pre = 0; pre < sh && zleline[pre] == lastline[pre]; ) pre++; for(suf = 0; suf < sh - pre && diff --git a/Src/builtin.c b/Src/builtin.c index 411b834e7..fc98eb1b1 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -2420,12 +2420,12 @@ bin_typeset(char *name, char **argv, Options ops, int func) } if (!strcmp(asg0.name, asg->name)) { unqueue_signals(); - zerrnam(name, "can't tie a variable to itself"); + zerrnam(name, "can't tie a variable to itself: %s", asg0.name); return 1; } if (strchr(asg0.name, '[') || strchr(asg->name, '[')) { unqueue_signals(); - zerrnam(name, "can't tie array elements"); + zerrnam(name, "can't tie array elements: %s", asg0.name); return 1; } /* @@ -2440,6 +2440,11 @@ bin_typeset(char *name, char **argv, Options ops, int func) if ((pm = (Param) paramtab->getnode(paramtab, asg0.name)) && !(pm->node.flags & PM_UNSET) && (locallevel == pm->level || !(on & PM_LOCAL))) { + if (pm->node.flags & PM_TIED) { + unqueue_signals(); + zerrnam(name, "can't tie already tied scalar: %s", asg0.name); + return 1; + } if (!asg0.value && !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))) oldval = ztrdup(getsparam(asg0.name)); on |= (pm->node.flags & PM_EXPORTED); @@ -3898,7 +3903,7 @@ bin_print(char *name, char **args, Options ops, int func) * nc: number of columns (at least one) */ sc = l + 2; - nc = (columns + 1) / sc; + nc = (zterm_columns + 1) / sc; if (!nc) nc = 1; nr = (n + nc - 1) / nc; @@ -4708,7 +4713,7 @@ zexit(int val, int from_where) */ in_exit = -1; /* - * We want to do all remaining processing regardless of preceeding + * We want to do all remaining processing regardless of preceding * errors. */ errflag = 0; @@ -4821,8 +4826,14 @@ bin_dot(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) freearray(pparams); pparams = old; } - if (ret == SOURCE_NOT_FOUND) - zwarnnam(name, "%e: %s", errno, enam); + if (ret == SOURCE_NOT_FOUND) { + if (isset(POSIXBUILTINS)) { + /* hard error in POSIX (we'll exit later) */ + zerrnam(name, "%e: %s", errno, enam); + } else { + zwarnnam(name, "%e: %s", errno, enam); + } + } zsfree(arg0); if (old0) { zsfree(argzero); @@ -5280,9 +5291,16 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func)) *bptr = readchar; val = 1; readchar = -1; - } else if ((val = read(readfd, bptr, nchars)) <= 0) { - eof = 1; - break; + } else { + while ((val = read(readfd, bptr, nchars)) < 0) { + if (errno != EINTR || + errflag || retflag || breaks || contflag) + break; + } + if (val <= 0) { + eof = 1; + break; + } } #ifdef MULTIBYTE_SUPPORT @@ -5710,7 +5728,12 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func)) } return 1; } - return 0; + /* + * The following is to ensure a failure to set the parameter + * causes a non-zero status return. There are arguments for + * turning a non-zero status into errflag more widely. + */ + return errflag; } /**/ diff --git a/Src/cond.c b/Src/cond.c index b911bfb33..c67354297 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -403,7 +403,6 @@ evalcond(Estate state, char *fromtest) zwarnnam(fromtest, "bad cond code"); return 2; } - return 1; } diff --git a/Src/exec.c b/Src/exec.c index 4576fc031..2558185c8 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -181,7 +181,15 @@ struct execstack *exstack; /**/ mod_export Funcstack funcstack; -#define execerr() if (!forked) { lastval = 1; goto done; } else _exit(1) +#define execerr() \ + do { \ + if (!forked) { \ + redir_err = lastval = 1; \ + goto done; \ + } else { \ + _exit(1); \ + } \ + } while (0) static int doneps4; static char *STTYval; @@ -2312,11 +2320,11 @@ execcmd(Estate state, int input, int output, int how, int last1) struct multio *mfds[10]; char *text; int save[10]; - int fil, dfil, is_cursh, type, do_exec = 0, i, htok = 0; + int fil, dfil, is_cursh, type, do_exec = 0, redir_err = 0, i, htok = 0; int nullexec = 0, assign = 0, forked = 0; int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0; /* Various flags to the command. */ - int cflags = 0, checked = 0, oautocont = -1; + int cflags = 0, orig_cflags = 0, checked = 0, oautocont = -1; LinkList redir; wordcode code; Wordcode beg = state->pc, varspc; @@ -2408,6 +2416,9 @@ execcmd(Estate state, int input, int output, int how, int last1) checked = !(cflags & BINF_BUILTIN); break; } + orig_cflags |= cflags; + cflags &= ~BINF_BUILTIN & ~BINF_COMMAND; + cflags |= hn->flags; if (!(hn->flags & BINF_PREFIX)) { is_builtin = 1; @@ -2417,8 +2428,6 @@ execcmd(Estate state, int input, int output, int how, int last1) assign = (hn->flags & BINF_MAGICEQUALS); break; } - cflags &= ~BINF_BUILTIN & ~BINF_COMMAND; - cflags |= hn->flags; checked = 0; if ((cflags & BINF_COMMAND) && nextnode(firstnode(args))) { /* check for options to command builtin */ @@ -2748,7 +2757,7 @@ execcmd(Estate state, int input, int output, int how, int last1) * A `fake exec' is possible if we have all the following conditions: * * 1) last1 flag is 1. This indicates that the current shell will not * * be needed after the current command. This is typically the case * - * when when the command is the last stage in a subshell, or is the * + * when the command is the last stage in a subshell, or is the * * last command after the option `-c'. * * 2) We don't have any traps set. * * 3) We don't have any files to delete. * @@ -2999,10 +3008,11 @@ execcmd(Estate state, int input, int output, int how, int last1) if (!checkclobberparam(fn)) fil = -1; else if (fn->fd2 > 9 && - ((fdtable[fn->fd2] != FDT_UNUSED && - fdtable[fn->fd2] != FDT_EXTERNAL) || - fn->fd2 == coprocin || - fn->fd2 == coprocout)) { + (fn->fd2 > max_zsh_fd || + (fdtable[fn->fd2] != FDT_UNUSED && + fdtable[fn->fd2] != FDT_EXTERNAL) || + fn->fd2 == coprocin || + fn->fd2 == coprocout)) { fil = -1; errno = EBADF; } else { @@ -3069,7 +3079,6 @@ execcmd(Estate state, int input, int output, int how, int last1) if (mfds[i] && mfds[i]->ct >= 2) closemn(mfds, i); - xtrerr = stderr; if (nullexec) { if (nullexec == 1) { /* @@ -3218,10 +3227,14 @@ execcmd(Estate state, int input, int output, int how, int last1) _exit(1); } closem(FDT_INTERNAL); - if (coprocin) + if (coprocin != -1) { zclose(coprocin); - if (coprocout) + coprocin = -1; + } + if (coprocout != -1) { zclose(coprocout); + coprocout = -1; + } #ifdef HAVE_GETRLIMIT if (!forked) setlimits(NULL); @@ -3285,6 +3298,25 @@ execcmd(Estate state, int input, int output, int how, int last1) fixfds(save); done: + if (isset(POSIXBUILTINS) && + (cflags & (BINF_PSPECIAL|BINF_EXEC)) && + !(orig_cflags & BINF_COMMAND)) { + /* + * For POSIX-compatible behaviour with special + * builtins (including exec which we don't usually + * classify as a builtin) we treat all errors as fatal. + * The "command" builtin is not special so resets this behaviour. + */ + if (redir_err || errflag) { + if (!isset(INTERACTIVE)) { + if (forked) + _exit(1); + else + exit(1); + } + errflag = 1; + } + } if (newxtrerr) { fil = fileno(newxtrerr); fclose(newxtrerr); @@ -4227,6 +4259,7 @@ execshfunc(Shfunc shf, LinkList args) cmdsp = 0; if ((osfc = sfcontext) == SFC_NONE) sfcontext = SFC_DIRECT; + xtrerr = stderr; doshfunc(shf, args, 0); sfcontext = osfc; free(cmdstack); @@ -4365,7 +4398,7 @@ loadautofn(Shfunc shf, int fksh, int autol) mod_export int doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) { - char **tab, **x, *oargv0; + char **pptab, **x, *oargv0; int oldzoptind, oldlastval, oldoptcind, oldnumpipestats, ret; int *oldpipestats = NULL; char saveopts[OPT_SIZE], *oldscriptname = scriptname; @@ -4399,7 +4432,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) starttrapscope(); - tab = pparams; + pptab = pparams; if (!(flags & PM_UNDEFINED)) scriptname = dupstring(name); oldzoptind = zoptind; @@ -4515,7 +4548,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) zsfree(argzero); argzero = oargv0; } - pparams = tab; + pparams = pptab; optcind = oldoptcind; zoptind = oldzoptind; scriptname = oldscriptname; diff --git a/Src/glob.c b/Src/glob.c index 5f6813589..bfc7f0416 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -1111,7 +1111,7 @@ zglob(LinkList list, LinkNode np, int nountok) struct globdata saved; /* saved glob state */ int nobareglob = !isset(BAREGLOBQUAL); - if (unset(GLOBOPT) || !haswilds(ostr)) { + if (unset(GLOBOPT) || !haswilds(ostr) || unset(EXECOPT)) { if (!nountok) untokenize(ostr); return; @@ -2000,7 +2000,7 @@ hasbraces(char *str) /**/ int -xpandredir(struct redir *fn, LinkList tab) +xpandredir(struct redir *fn, LinkList redirtab) { char *nam; struct redir *ff; @@ -2048,7 +2048,7 @@ xpandredir(struct redir *fn, LinkList tab) ff = (struct redir *) zhalloc(sizeof *ff); *ff = *fn; ff->name = nam; - addlinknode(tab, ff); + addlinknode(redirtab, ff); ret = 1; } } diff --git a/Src/hashnameddir.c b/Src/hashnameddir.c new file mode 100644 index 000000000..bed43d025 --- /dev/null +++ b/Src/hashnameddir.c @@ -0,0 +1,307 @@ +/* + * hashtable.c - hash tables + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1992-1997 Paul Falstad + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Paul Falstad or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Paul Falstad and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Paul Falstad and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Paul Falstad and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "../config.h" + +/* + * On Solaris 8 there's a clash between "bool" in curses and RPC. + * We don't need curses here, so ensure it doesn't get included. + */ +#define ZSH_NO_TERM_HANDLING + +#include "zsh.mdh" +#include "hashnameddir.pro" + +/****************************************/ +/* Named Directory Hash Table Functions */ +/****************************************/ + +#ifdef HAVE_NIS_PLUS +# include <rpcsvc/nis.h> +#else +# ifdef HAVE_NIS +# include <rpc/types.h> +# include <rpc/rpc.h> +# include <rpcsvc/ypclnt.h> +# include <rpcsvc/yp_prot.h> +# endif +#endif + +/* hash table containing named directories */ + +/**/ +mod_export HashTable nameddirtab; + +/* != 0 if all the usernames have already been * + * added to the named directory hash table. */ + +static int allusersadded; + +/* Create new hash table for named directories */ + +/**/ +void +createnameddirtable(void) +{ + nameddirtab = newhashtable(201, "nameddirtab", NULL); + + nameddirtab->hash = hasher; + nameddirtab->emptytable = emptynameddirtable; + nameddirtab->filltable = fillnameddirtable; + nameddirtab->cmpnodes = strcmp; + nameddirtab->addnode = addnameddirnode; + nameddirtab->getnode = gethashnode; + nameddirtab->getnode2 = gethashnode2; + nameddirtab->removenode = removenameddirnode; + nameddirtab->disablenode = NULL; + nameddirtab->enablenode = NULL; + nameddirtab->freenode = freenameddirnode; + nameddirtab->printnode = printnameddirnode; + + allusersadded = 0; + finddir(NULL); /* clear the finddir cache */ +} + +/* Empty the named directories table */ + +/**/ +static void +emptynameddirtable(HashTable ht) +{ + emptyhashtable(ht); + allusersadded = 0; + finddir(NULL); /* clear the finddir cache */ +} + +/* Add all the usernames in the password file/database * + * to the named directories table. */ + +#ifdef HAVE_NIS_PLUS +static int +add_userdir(nis_name table, nis_object *object, void *userdata) +{ + if (object->zo_data.objdata_u.en_data.en_cols.en_cols_len >= 6) { + static char name[40], dir[PATH_MAX + 1]; + register entry_col *ec = + object->zo_data.objdata_u.en_data.en_cols.en_cols_val; + register int nl = minimum(ec[0].ec_value.ec_value_len, 39); + register int dl = minimum(ec[5].ec_value.ec_value_len, PATH_MAX); + + memcpy(name, ec[0].ec_value.ec_value_val, nl); + name[nl] = '\0'; + memcpy(dir, ec[5].ec_value.ec_value_val, dl); + dir[dl] = '\0'; + + adduserdir(name, dir, ND_USERNAME, 1); + } + return 0; +} +#else +# ifdef HAVE_NIS +static int +add_userdir(int status, char *key, int keylen, char *val, int vallen, char *dummy) +{ + char *p, *d, *de; + + if (status != YP_TRUE) + return 1; + + if (vallen > keylen && *(p = val + keylen) == ':') { + *p++ = '\0'; + for (de = val + vallen - 1; *de != ':' && de > val; de--); + if (de > val) { + *de = '\0'; + if ((d = strrchr(p, ':'))) { + if (*++d && val[0]) + adduserdir(val, d, ND_USERNAME, 1); + } + } + } + return 0; +} +# endif /* HAVE_NIS */ +#endif /* HAVE_NIS_PLUS */ + +/**/ +static void +fillnameddirtable(UNUSED(HashTable ht)) +{ + if (!allusersadded) { +#if defined(HAVE_NIS) || defined(HAVE_NIS_PLUS) + FILE *pwf; + char buf[BUFSIZ], *p, *d, *de; + int skipping, oldct = nameddirtab->ct, usepwf = 1; + +# ifndef HAVE_NIS_PLUS + char domain[YPMAXDOMAIN]; + struct ypall_callback cb; + + /* Get potential matches from NIS and cull those without local accounts */ + if (getdomainname(domain, YPMAXDOMAIN) == 0) { + cb.foreach = (int (*)()) add_userdir; + cb.data = NULL; + yp_all(domain, PASSWD_MAP, &cb); + } +# else /* HAVE_NIS_PLUS */ + /* Maybe we should turn this string into a #define'd constant...? */ + + nis_list("passwd.org_dir", EXPAND_NAME|ALL_RESULTS|FOLLOW_LINKS|FOLLOW_PATH, + add_userdir, 0); +# endif + if (nameddirtab->ct == oldct) { + /* Using NIS or NIS+ didn't add any user directories. This seems + * fishy, so we fall back to using getpwent(). If we don't have + * that, we only use the passwd file. */ +#ifdef HAVE_GETPWENT + struct passwd *pw; + + setpwent(); + + /* loop through the password file/database * + * and add all entries returned. */ + while ((pw = getpwent()) && !errflag) + adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1); + + endpwent(); + usepwf = 0; +#endif /* HAVE_GETPWENT */ + } + if (usepwf) { + /* Don't forget the non-NIS matches from the flat passwd file */ + if ((pwf = fopen(PASSWD_FILE, "r")) != NULL) { + skipping = 0; + while (fgets(buf, BUFSIZ, pwf) != NULL) { + if (strchr(buf, '\n') != NULL) { + if (!skipping) { + if ((p = strchr(buf, ':')) != NULL) { + *p++ = '\0'; + if ((de = strrchr(p, ':'))) { + *de = '\0'; + if ((d = strrchr(p, ':'))) { + if (*++d && buf[0]) + adduserdir(buf, d, ND_USERNAME, 1); + } + } + } + } else + skipping = 0; + } else + skipping = 1; + } + fclose(pwf); + } + } +#else /* no NIS or NIS_PLUS */ +#ifdef USE_GETPWENT + struct passwd *pw; + + setpwent(); + + /* loop through the password file/database * + * and add all entries returned. */ + while ((pw = getpwent()) && !errflag) + adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1); + + endpwent(); +#endif /* HAVE_GETPWENT */ +#endif + allusersadded = 1; + } +} + +/* Add an entry to the named directory hash * + * table, clearing the finddir() cache and * + * initialising the `diff' member. */ + +/**/ +static void +addnameddirnode(HashTable ht, char *nam, void *nodeptr) +{ + Nameddir nd = (Nameddir) nodeptr; + + nd->diff = strlen(nd->dir) - strlen(nam); + finddir(NULL); /* clear the finddir cache */ + addhashnode(ht, nam, nodeptr); +} + +/* Remove an entry from the named directory * + * hash table, clearing the finddir() cache. */ + +/**/ +static HashNode +removenameddirnode(HashTable ht, const char *nam) +{ + HashNode hn = removehashnode(ht, nam); + + if(hn) + finddir(NULL); /* clear the finddir cache */ + return hn; +} + +/* Free up the memory used by a named directory hash node. */ + +/**/ +static void +freenameddirnode(HashNode hn) +{ + Nameddir nd = (Nameddir) hn; + + zsfree(nd->node.nam); + zsfree(nd->dir); + zfree(nd, sizeof(struct nameddir)); +} + +/* Print a named directory */ + +/**/ +static void +printnameddirnode(HashNode hn, int printflags) +{ + Nameddir nd = (Nameddir) hn; + + if (printflags & PRINT_NAMEONLY) { + zputs(nd->node.nam, stdout); + putchar('\n'); + return; + } + + if (printflags & PRINT_LIST) { + printf("hash -d "); + + if(nd->node.nam[0] == '-') + printf("-- "); + } + + quotedzputs(nd->node.nam, stdout); + putchar('='); + quotedzputs(nd->dir, stdout); + putchar('\n'); +} + +#include "../config.h" diff --git a/Src/hashtable.c b/Src/hashtable.c index 6d7179412..6fca256e3 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -59,7 +59,7 @@ struct scanstatus { int sorted; union { struct { - HashNode *tab; + HashNode *hashtab; int ct; } s; HashNode u; @@ -187,11 +187,11 @@ addhashnode2(HashTable ht, char *nam, void *nodeptr) hn->next = hp->next; if(ht->scan) { if(ht->scan->sorted) { - HashNode *tab = ht->scan->u.s.tab; + HashNode *hashtab = ht->scan->u.s.hashtab; int i; for(i = ht->scan->u.s.ct; i--; ) - if(tab[i] == hp) - tab[i] = hn; + if(hashtab[i] == hp) + hashtab[i] = hn; } else if(ht->scan->u.u == hp) ht->scan->u.u = hn; } @@ -286,11 +286,11 @@ removehashnode(HashTable ht, const char *nam) ht->ct--; if(ht->scan) { if(ht->scan->sorted) { - HashNode *tab = ht->scan->u.s.tab; + HashNode *hashtab = ht->scan->u.s.hashtab; int i; for(i = ht->scan->u.s.ct; i--; ) - if(tab[i] == hp) - tab[i] = NULL; + if(hashtab[i] == hp) + hashtab[i] = NULL; } else if(ht->scan->u.u == hp) ht->scan->u.u = hp->next; } @@ -397,7 +397,7 @@ scanmatchtable(HashTable ht, Patprog pprog, int sorted, qsort((void *)hnsorttab, ct, sizeof(HashNode), hnamcmp); st.sorted = 1; - st.u.s.tab = hnsorttab; + st.u.s.hashtab = hnsorttab; st.u.s.ct = ct; ht->scan = &st; @@ -1196,272 +1196,6 @@ printaliasnode(HashNode hn, int printflags) putchar('\n'); } -/****************************************/ -/* Named Directory Hash Table Functions */ -/****************************************/ - -#ifdef HAVE_NIS_PLUS -# include <rpcsvc/nis.h> -#else -# ifdef HAVE_NIS -# include <rpc/types.h> -# include <rpc/rpc.h> -# include <rpcsvc/ypclnt.h> -# include <rpcsvc/yp_prot.h> -# endif -#endif - -/* hash table containing named directories */ - -/**/ -mod_export HashTable nameddirtab; - -/* != 0 if all the usernames have already been * - * added to the named directory hash table. */ - -static int allusersadded; - -/* Create new hash table for named directories */ - -/**/ -void -createnameddirtable(void) -{ - nameddirtab = newhashtable(201, "nameddirtab", NULL); - - nameddirtab->hash = hasher; - nameddirtab->emptytable = emptynameddirtable; - nameddirtab->filltable = fillnameddirtable; - nameddirtab->cmpnodes = strcmp; - nameddirtab->addnode = addnameddirnode; - nameddirtab->getnode = gethashnode; - nameddirtab->getnode2 = gethashnode2; - nameddirtab->removenode = removenameddirnode; - nameddirtab->disablenode = NULL; - nameddirtab->enablenode = NULL; - nameddirtab->freenode = freenameddirnode; - nameddirtab->printnode = printnameddirnode; - - allusersadded = 0; - finddir(NULL); /* clear the finddir cache */ -} - -/* Empty the named directories table */ - -/**/ -static void -emptynameddirtable(HashTable ht) -{ - emptyhashtable(ht); - allusersadded = 0; - finddir(NULL); /* clear the finddir cache */ -} - -/* Add all the usernames in the password file/database * - * to the named directories table. */ - -#ifdef HAVE_NIS_PLUS -static int -add_userdir(nis_name table, nis_object *object, void *userdata) -{ - if (object->zo_data.objdata_u.en_data.en_cols.en_cols_len >= 6) { - static char name[40], dir[PATH_MAX + 1]; - register entry_col *ec = - object->zo_data.objdata_u.en_data.en_cols.en_cols_val; - register int nl = minimum(ec[0].ec_value.ec_value_len, 39); - register int dl = minimum(ec[5].ec_value.ec_value_len, PATH_MAX); - - memcpy(name, ec[0].ec_value.ec_value_val, nl); - name[nl] = '\0'; - memcpy(dir, ec[5].ec_value.ec_value_val, dl); - dir[dl] = '\0'; - - adduserdir(name, dir, ND_USERNAME, 1); - } - return 0; -} -#else -# ifdef HAVE_NIS -static int -add_userdir(int status, char *key, int keylen, char *val, int vallen, char *dummy) -{ - char *p, *d, *de; - - if (status != YP_TRUE) - return 1; - - if (vallen > keylen && *(p = val + keylen) == ':') { - *p++ = '\0'; - for (de = val + vallen - 1; *de != ':' && de > val; de--); - if (de > val) { - *de = '\0'; - if ((d = strrchr(p, ':'))) { - if (*++d && val[0]) - adduserdir(val, d, ND_USERNAME, 1); - } - } - } - return 0; -} -# endif /* HAVE_NIS */ -#endif /* HAVE_NIS_PLUS */ - -/**/ -static void -fillnameddirtable(UNUSED(HashTable ht)) -{ - if (!allusersadded) { -#if defined(HAVE_NIS) || defined(HAVE_NIS_PLUS) - FILE *pwf; - char buf[BUFSIZ], *p, *d, *de; - int skipping, oldct = nameddirtab->ct, usepwf = 1; - -# ifndef HAVE_NIS_PLUS - char domain[YPMAXDOMAIN]; - struct ypall_callback cb; - - /* Get potential matches from NIS and cull those without local accounts */ - if (getdomainname(domain, YPMAXDOMAIN) == 0) { - cb.foreach = (int (*)()) add_userdir; - cb.data = NULL; - yp_all(domain, PASSWD_MAP, &cb); - } -# else /* HAVE_NIS_PLUS */ - /* Maybe we should turn this string into a #define'd constant...? */ - - nis_list("passwd.org_dir", EXPAND_NAME|ALL_RESULTS|FOLLOW_LINKS|FOLLOW_PATH, - add_userdir, 0); -# endif - if (nameddirtab->ct == oldct) { - /* Using NIS or NIS+ didn't add any user directories. This seems - * fishy, so we fall back to using getpwent(). If we don't have - * that, we only use the passwd file. */ -#ifdef HAVE_GETPWENT - struct passwd *pw; - - setpwent(); - - /* loop through the password file/database * - * and add all entries returned. */ - while ((pw = getpwent()) && !errflag) - adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1); - - endpwent(); - usepwf = 0; -#endif /* HAVE_GETPWENT */ - } - if (usepwf) { - /* Don't forget the non-NIS matches from the flat passwd file */ - if ((pwf = fopen(PASSWD_FILE, "r")) != NULL) { - skipping = 0; - while (fgets(buf, BUFSIZ, pwf) != NULL) { - if (strchr(buf, '\n') != NULL) { - if (!skipping) { - if ((p = strchr(buf, ':')) != NULL) { - *p++ = '\0'; - if ((de = strrchr(p, ':'))) { - *de = '\0'; - if ((d = strrchr(p, ':'))) { - if (*++d && buf[0]) - adduserdir(buf, d, ND_USERNAME, 1); - } - } - } - } else - skipping = 0; - } else - skipping = 1; - } - fclose(pwf); - } - } -#else /* no NIS or NIS_PLUS */ -#ifdef USE_GETPWENT - struct passwd *pw; - - setpwent(); - - /* loop through the password file/database * - * and add all entries returned. */ - while ((pw = getpwent()) && !errflag) - adduserdir(pw->pw_name, pw->pw_dir, ND_USERNAME, 1); - - endpwent(); -#endif /* HAVE_GETPWENT */ -#endif - allusersadded = 1; - } -} - -/* Add an entry to the named directory hash * - * table, clearing the finddir() cache and * - * initialising the `diff' member. */ - -/**/ -static void -addnameddirnode(HashTable ht, char *nam, void *nodeptr) -{ - Nameddir nd = (Nameddir) nodeptr; - - nd->diff = strlen(nd->dir) - strlen(nam); - finddir(NULL); /* clear the finddir cache */ - addhashnode(ht, nam, nodeptr); -} - -/* Remove an entry from the named directory * - * hash table, clearing the finddir() cache. */ - -/**/ -static HashNode -removenameddirnode(HashTable ht, const char *nam) -{ - HashNode hn = removehashnode(ht, nam); - - if(hn) - finddir(NULL); /* clear the finddir cache */ - return hn; -} - -/* Free up the memory used by a named directory hash node. */ - -/**/ -static void -freenameddirnode(HashNode hn) -{ - Nameddir nd = (Nameddir) hn; - - zsfree(nd->node.nam); - zsfree(nd->dir); - zfree(nd, sizeof(struct nameddir)); -} - -/* Print a named directory */ - -/**/ -static void -printnameddirnode(HashNode hn, int printflags) -{ - Nameddir nd = (Nameddir) hn; - - if (printflags & PRINT_NAMEONLY) { - zputs(nd->node.nam, stdout); - putchar('\n'); - return; - } - - if (printflags & PRINT_LIST) { - printf("hash -d "); - - if(nd->node.nam[0] == '-') - printf("-- "); - } - - quotedzputs(nd->node.nam, stdout); - putchar('='); - quotedzputs(nd->dir, stdout); - putchar('\n'); -} - /*************************************/ /* History Line Hash Table Functions */ /*************************************/ diff --git a/Src/hist.c b/Src/hist.c index c94d3e4aa..01a97da2b 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -303,7 +303,7 @@ ihgetc(void) /* If the result is a bangchar which came from history or alias * * expansion, we treat it as an escaped bangchar, unless history * * is disabled. If stophist == 1 it only means that history is * - * temporarily disabled by a !" which won't appear in in the * + * temporarily disabled by a !" which won't appear in the * * history, so we still have an escaped bang. stophist > 1 if * * history is disabled with NOBANGHIST or by someone else (e.g. * * when the lexer scans single quoted text). */ @@ -2406,6 +2406,13 @@ readhistfile(char *fn, int err, int readflags) uselex = 0; break; } + } else if (!strcmp(word, ";") && strpfx(";;", pt)) { + /* + * Don't get confused between a semicolon that's + * probably really a newline and a double + * semicolon that's terminating a case. + */ + continue; } words[nwordpos++] = pt - start; pt += strlen(word); diff --git a/Src/init.c b/Src/init.c index 3ce482488..30cd40e6c 100644 --- a/Src/init.c +++ b/Src/init.c @@ -243,6 +243,7 @@ parseargs(char **argv, char **runscript) * still 2 at the end, we set it to the value of INTERACTIVE. */ opts[MONITOR] = 2; /* may be unset in init_io() */ + opts[HASHDIRS] = 2; /* same relationship to INTERACTIVE */ opts[SHINSTDIN] = 0; opts[SINGLECOMMAND] = 0; @@ -351,6 +352,8 @@ parseargs(char **argv, char **runscript) opts[INTERACTIVE] = !!opts[INTERACTIVE]; if (opts[MONITOR] == 2) opts[MONITOR] = opts[INTERACTIVE]; + if (opts[HASHDIRS] == 2) + opts[HASHDIRS] = opts[INTERACTIVE]; pparams = x = (char **) zshcalloc((countlinknodes(paramlist) + 1) * sizeof(char *)); while ((*x++ = (char *)getlinknode(paramlist))); @@ -673,11 +676,15 @@ setupvals(void) struct timezone dummy_tz; char *ptr; int i, j; -#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) +#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined (ADDITIONAL_FPATH) char **fpathptr; # if defined(FPATH_DIR) && defined(FPATH_SUBDIRS) char *fpath_subdirs[] = FPATH_SUBDIRS; # endif +# if defined(ADDITIONAL_FPATH) + char *more_fndirs[] = ADDITIONAL_FPATH; + int more_fndirs_len; +# endif # ifdef SITEFPATH_DIR int fpathlen = 1; # else @@ -761,7 +768,7 @@ setupvals(void) manpath = mkarray(NULL); fignore = mkarray(NULL); -#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) +#if defined(SITEFPATH_DIR) || defined(FPATH_DIR) || defined(ADDITIONAL_FPATH) # ifdef FPATH_DIR # ifdef FPATH_SUBDIRS fpathlen += sizeof(fpath_subdirs)/sizeof(char *); @@ -769,15 +776,28 @@ setupvals(void) fpathlen++; # endif # endif +# if defined(ADDITIONAL_FPATH) + more_fndirs_len = sizeof(more_fndirs)/sizeof(char *); + fpathlen += more_fndirs_len; +# endif fpath = fpathptr = (char **)zalloc((fpathlen+1)*sizeof(char *)); # ifdef SITEFPATH_DIR *fpathptr++ = ztrdup(SITEFPATH_DIR); fpathlen--; # endif +# if defined(ADDITIONAL_FPATH) + for (j = 0; j < more_fndirs_len; j++) + *fpathptr++ = ztrdup(more_fndirs[j]); +# endif # ifdef FPATH_DIR # ifdef FPATH_SUBDIRS +# ifdef ADDITIONAL_FPATH + for (j = more_fndirs_len; j < fpathlen; j++) + *fpathptr++ = tricat(FPATH_DIR, "/", fpath_subdirs[j - more_fndirs_len]); +# else for (j = 0; j < fpathlen; j++) *fpathptr++ = tricat(FPATH_DIR, "/", fpath_subdirs[j]); +#endif # else *fpathptr++ = ztrdup(FPATH_DIR); # endif @@ -888,8 +908,8 @@ setupvals(void) /* columns and lines are normally zero, unless something different * * was inhereted from the environment. If either of them are zero * * the setiparam calls below set them to the defaults from termcap */ - setiparam("COLUMNS", columns); - setiparam("LINES", lines); + setiparam("COLUMNS", zterm_columns); + setiparam("LINES", zterm_lines); #endif #ifdef HAVE_GETRLIMIT diff --git a/Src/jobs.c b/Src/jobs.c index fd785a0e9..b3ec0008c 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -173,11 +173,28 @@ findproc(pid_t pid, Job *jptr, Process *pptr, int aux) for (pn = aux ? jobtab[i].auxprocs : jobtab[i].procs; pn; pn = pn->next) - if (pn->pid == pid) { + { + /* + * Make sure we match a process that's still running. + * + * When a job contains two pids, one terminated pid and one + * running pid, then the condition (jobtab[i].stat & + * STAT_DONE) will not stop these pids from being candidates + * for the findproc result (which is supposed to be a + * RUNNING pid), and if the terminated pid is an identical + * process number for the pid identifying the running + * process we are trying to find (after pid number + * wrapping), then we need to avoid returning the terminated + * pid, otherwise the shell would block and wait forever for + * the termination of the process which pid we were supposed + * to return in a different job. + */ + if (pn->pid == pid && pn->status == SP_RUNNING) { *pptr = pn; *jptr = jobtab + i; return 1; } + } } return 0; @@ -514,7 +531,7 @@ update_job(Job jn) /* When MONITOR is set, the foreground process runs in a different * * process group from the shell, so the shell will not receive * - * terminal signals, therefore we we pretend that the shell got * + * terminal signals, therefore we pretend that the shell got * * the signal too. */ if (inforeground == 2 && isset(MONITOR) && WIFSIGNALED(status)) { int sig = WTERMSIG(status); @@ -876,7 +893,7 @@ printjob(Job jn, int lng, int synch) { Process pn; int job, len = 9, sig, sflag = 0, llen; - int conted = 0, lineleng = columns, skip = 0, doputnl = 0; + int conted = 0, lineleng = zterm_columns, skip = 0, doputnl = 0; int doneprint = 0, skip_print = 0; FILE *fout = (synch == 2 || !shout) ? stdout : shout; @@ -877,7 +877,7 @@ gettok(void) dbparens = 1; return DINPAR; } - if (incmdpos) { + if (incmdpos || (isset(SHGLOB) && !isset(KSHGLOB))) { len = 0; bptr = tokstr = (char *) hcalloc(bsiz = 32); switch (cmd_or_math(CS_MATH)) { @@ -1141,6 +1141,8 @@ gettokstr(int c, int sub) break; if (incasepat && !len) return INPAR; + if (!isset(KSHGLOB) && len) + goto brk; } if (!in_brace_param) { if (!sub) { @@ -1753,7 +1755,7 @@ parse_subst_string(char *s) * additional memory should come off the heap or * otherwise. So we cheat by copying the unquoted string * into place, unless it's too long. That's not the - * normal case, but I'm worried there are are pathological + * normal case, but I'm worried there are pathological * cases with converting metafied multibyte strings. * If someone can prove there aren't I will be very happy. */ @@ -1823,7 +1825,7 @@ exalias(void) int zp = lexflags; gotword(); - if (zp == 1 && !lexflags) { + if ((zp & LEXFLAGS_ZLE) && !lexflags) { if (zshlextext == copy) zshlextext = tokstr; return 0; diff --git a/Src/loop.c b/Src/loop.c index 40dbe6f8f..90a0761b3 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -324,13 +324,13 @@ selectlist(LinkList l, size_t start) while (t0) t0 /= 10, longest++; /* to compensate for added ')' */ - fct = (columns - 1) / (longest + 3); + fct = (zterm_columns - 1) / (longest + 3); if (fct == 0) fct = 1; else - fw = (columns - 1) / fct; + fw = (zterm_columns - 1) / fct; colsz = (ct + fct - 1) / fct; - for (t1 = start; t1 != colsz && t1 - start < lines - 2; t1++) { + for (t1 = start; t1 != colsz && t1 - start < zterm_lines - 2; t1++) { ap = arr + t1; do { size_t t2 = strlen(*ap) + 2; diff --git a/Src/math.c b/Src/math.c index caff06de9..beef74525 100644 --- a/Src/math.c +++ b/Src/math.c @@ -46,7 +46,7 @@ mod_export mnumber zero_mnumber; /* * The last value we computed: note this isn't cleared - * until the next computation, unlike unlike yyval. + * until the next computation, unlike yyval. * Everything else is saved and returned to allow recursive calls. */ /**/ @@ -1156,7 +1156,8 @@ op(int what) if (tp & (OP_E2|OP_E2IO)) { struct mathvalue *mvp = stack + sp + 1; lv = stack[sp+1].lval; - push(setmathvar(mvp,c), mvp->lval, 0); + c = setmathvar(mvp, c); + push(c, mvp->lval, 0); } else push(c,NULL, 0); return; @@ -123,6 +123,60 @@ static Heap heaps; static Heap fheap; +/**/ +#ifdef ZSH_HEAP_DEBUG +/* + * The heap ID we'll allocate next. + * + * We'll avoid using 0 as that means zero-initialised memory + * containing a heap ID is (correctly) marked as invalid. + */ +static Heapid next_heap_id = (Heapid)1; + +/* + * The ID of the heap from which we last allocated heap memory. + * In theory, since we carefully avoid allocating heap memory during + * interrupts, after any call to zhalloc() or wrappers this should + * be the ID of the heap containing the memory just returned. + */ +/**/ +mod_export Heapid last_heap_id; + +/* + * Stack of heaps saved by new_heaps(). + * Assumes old_heaps() will come along and restore it later + * (outputs an error if old_heaps() is called out of sequence). + */ +LinkList heaps_saved; + +/* + * Debugging verbosity. This must be set from a debugger. + * An 'or' of bits from the enum heap_debug_verbosity. + */ +volatile int heap_debug_verbosity; + +/* + * Generate a heap identifier that's unique up to unsigned integer wrap. + * + * For the purposes of debugging we won't bother trying to make a + * heap_id globally unique, which would require checking all existing + * heaps every time we create an ID and still wouldn't do what we + * ideally want, which is to make sure the IDs of valid heaps are + * different from the IDs of no-longer-valid heaps. Given that, + * we'll just assume that if we haven't tracked the problem when the + * ID wraps we're out of luck. We could change the type to a long long + * if we wanted more room + */ + +static Heapid +new_heap_id(void) +{ + return next_heap_id++; +} + +/**/ +#endif + /* Use new heaps from now on. This returns the old heap-list. */ /**/ @@ -137,6 +191,15 @@ new_heaps(void) fheap = heaps = NULL; unqueue_signals(); +#ifdef ZSH_HEAP_DEBUG + if (heap_debug_verbosity & HDV_NEW) { + fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT + " saved, new heaps created.\n", h->heap_id); + } + if (!heaps_saved) + heaps_saved = znewlinklist(); + zpushnode(heaps_saved, h); +#endif return h; } @@ -152,6 +215,12 @@ old_heaps(Heap old) for (h = heaps; h; h = n) { n = h->next; DPUTS(h->sp, "BUG: old_heaps() with pushed heaps"); +#ifdef ZSH_HEAP_DEBUG + if (heap_debug_verbosity & HDV_FREE) { + fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT + "freed in old_heaps().\n", h->heap_id); + } +#endif #ifdef USE_MMAP munmap((void *) h, h->size); #else @@ -159,6 +228,21 @@ old_heaps(Heap old) #endif } heaps = old; +#ifdef ZSH_HEAP_DEBUG + if (heap_debug_verbosity & HDV_OLD) { + fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT + "restored.\n", heaps->heap_id); + } + { + Heap myold = heaps_saved ? getlinknode(heaps_saved) : NULL; + if (old != myold) + { + fprintf(stderr, "HEAP DEBUG: invalid old heap " HEAPID_FMT + ", expecting " HEAPID_FMT ".\n", old->heap_id, + myold->heap_id); + } + } +#endif fheap = NULL; unqueue_signals(); } @@ -174,6 +258,12 @@ switch_heaps(Heap new) queue_signals(); h = heaps; +#ifdef ZSH_HEAP_DEBUG + if (heap_debug_verbosity & HDV_SWITCH) { + fprintf(stderr, "HEAP DEBUG: heap temporarily switched from " + HEAPID_FMT " to " HEAPID_FMT ".\n", h->heap_id, new->heap_id); + } +#endif heaps = new; fheap = NULL; unqueue_signals(); @@ -202,6 +292,15 @@ pushheap(void) hs->next = h->sp; h->sp = hs; hs->used = h->used; +#ifdef ZSH_HEAP_DEBUG + hs->heap_id = h->heap_id; + h->heap_id = new_heap_id(); + if (heap_debug_verbosity & HDV_PUSH) { + fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT " pushed, new id is " + HEAPID_FMT ".\n", + hs->heap_id, h->heap_id); + } +#endif } unqueue_signals(); } @@ -220,8 +319,28 @@ freeheap(void) h_free++; #endif + /* At this point we used to do: fheap = NULL; - for (h = heaps; h; h = hn) { + * + * When pushheap() is called, it sweeps over the entire heaps list of + * arenas and marks every one of them with the amount of free space in + * that arena at that moment. zhalloc() is then allowed to grab bits + * out of any of those arenas that have free space. + * + * With the above reset of fheap, the loop below sweeps back over the + * entire heap list again, resetting the free space in every arena to + * the amount stashed by pushheap() and finding the first arena with + * free space to optimize zhalloc()'s next search. When there's a lot + * of stuff already on the heap, this is an enormous amount of work, + * and performance goes to hell. + * + * However, there doesn't seem to be any reason to reset fheap before + * beginning this loop. Either it's already correct, or it has never + * been set and this loop will do it, or it'll be reset from scratch + * on the next popheap(). So all that's needed here is to pick up + * the scan wherever the last pass [or the last popheap()] left off. + */ + for (h = (fheap ? fheap : heaps); h; h = hn) { hn = h->next; if (h->sp) { #ifdef ZSH_MEM_DEBUG @@ -231,6 +350,22 @@ freeheap(void) if (!fheap && h->used < ARENA_SIZEOF(h)) fheap = h; hl = h; +#ifdef ZSH_HEAP_DEBUG + /* + * As the free makes the heap invalid, give it a new + * identifier. We're not popping it, so don't use + * the one in the heap stack. + */ + { + Heapid new_id = new_heap_id(); + if (heap_debug_verbosity & HDV_FREE) { + fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT + " freed, new id is " HEAPID_FMT ".\n", + h->heap_id, new_id); + } + h->heap_id = new_id; + } +#endif } else { #ifdef USE_MMAP munmap((void *) h, h->size); @@ -242,7 +377,7 @@ freeheap(void) if (hl) hl->next = NULL; else - heaps = NULL; + heaps = fheap = NULL; unqueue_signals(); } @@ -271,6 +406,14 @@ popheap(void) memset(arena(h) + hs->used, 0xff, h->used - hs->used); #endif h->used = hs->used; +#ifdef ZSH_HEAP_DEBUG + if (heap_debug_verbosity & HDV_POP) { + fprintf(stderr, "HEAP DEBUG: heap " HEAPID_FMT + " popped, old heap was " HEAPID_FMT ".\n", + h->heap_id, hs->heap_id); + } + h->heap_id = hs->heap_id; +#endif if (!fheap && h->used < ARENA_SIZEOF(h)) fheap = h; zfree(hs, sizeof(*hs)); @@ -373,6 +516,13 @@ zhalloc(size_t size) h->used = n; ret = arena(h) + n - size; unqueue_signals(); +#ifdef ZSH_HEAP_DEBUG + last_heap_id = h->heap_id; + if (heap_debug_verbosity & HDV_ALLOC) { + fprintf(stderr, "HEAP DEBUG: allocated memory from heap " + HEAPID_FMT ".\n", h->heap_id); + } +#endif return ret; } } @@ -404,6 +554,13 @@ zhalloc(size_t size) h->used = size; h->next = NULL; h->sp = NULL; +#ifdef ZSH_HEAP_DEBUG + h->heap_id = new_heap_id(); + if (heap_debug_verbosity & HDV_CREATE) { + fprintf(stderr, "HEAP DEBUG: create new heap " HEAPID_FMT ".\n", + h->heap_id); + } +#endif if (hp) hp->next = h; @@ -412,6 +569,13 @@ zhalloc(size_t size) fheap = h; unqueue_signals(); +#ifdef ZSH_HEAP_DEBUG + last_heap_id = h->heap_id; + if (heap_debug_verbosity & HDV_ALLOC) { + fprintf(stderr, "HEAP DEBUG: allocated memory from heap " + HEAPID_FMT ".\n", h->heap_id); + } +#endif return arena(h); } } @@ -475,6 +639,9 @@ hrealloc(char *p, size_t old, size_t new) * don't use the heap for anything else.) */ if (p == arena(h)) { +#ifdef ZSH_HEAP_DEBUG + Heapid heap_id = h->heap_id; +#endif /* * Zero new seems to be a special case saying we've finished * with the specially reallocated memory, see scanner() in glob.c. @@ -534,6 +701,9 @@ hrealloc(char *p, size_t old, size_t new) heaps = h; } h->used = new; +#ifdef ZSH_HEAP_DEBUG + h->heap_id = heap_id; +#endif unqueue_signals(); return arena(h); } @@ -556,6 +726,55 @@ hrealloc(char *p, size_t old, size_t new) } } +/**/ +#ifdef ZSH_HEAP_DEBUG +/* + * Check if heap_id is the identifier of a currently valid heap, + * including any heap buried on the stack, or of permanent memory. + * Return 0 if so, else 1. + * + * This gets confused by use of switch_heaps(). That's because so do I. + */ + +/**/ +mod_export int +memory_validate(Heapid heap_id) +{ + Heap h; + Heapstack hs; + LinkNode node; + + if (heap_id == HEAPID_PERMANENT) + return 0; + + queue_signals(); + for (h = heaps; h; h = h->next) { + if (h->heap_id == heap_id) + return 0; + for (hs = heaps->sp; hs; hs = hs->next) { + if (hs->heap_id == heap_id) + return 0; + } + } + + if (heaps_saved) { + for (node = firstnode(heaps_saved); node; incnode(node)) { + for (h = (Heap)getdata(node); h; h = h->next) { + if (h->heap_id == heap_id) + return 0; + for (hs = heaps->sp; hs; hs = hs->next) { + if (hs->heap_id == heap_id) + return 0; + } + } + } + } + + return 1; +} +/**/ +#endif + /* allocate memory from the current memory pool and clear it */ /**/ diff --git a/Src/mkmakemod.sh b/Src/mkmakemod.sh index 2e0963f8e..2633c27d4 100644 --- a/Src/mkmakemod.sh +++ b/Src/mkmakemod.sh @@ -383,11 +383,7 @@ if $first_stage; then if test -n "$headers"; then echo " echo '/* Extra headers for this module */'; \\" echo " for hdr in $headers; do \\" - echo " if test -f \$\$hdr; then \\" - echo " echo '# include \"'\$\$hdr'\"'; \\" - echo " else \\" - echo " echo '# include \"\$(sdir)/'\$\$hdr'\"'; \\" - echo " fi; \\" + echo " echo '# include \"'\$\$hdr'\"'; \\" echo " done; \\" echo " echo; \\" fi diff --git a/Src/params.c b/Src/params.c index 92e0e5368..a59c51767 100644 --- a/Src/params.c +++ b/Src/params.c @@ -86,6 +86,7 @@ mod_export char *ifs, /* $IFS */ *postedit, /* $POSTEDIT */ *term, /* $TERM */ + *zsh_terminfo, /* $TERMINFO */ *ttystrname, /* $TTY */ *pwd; /* $PWD */ @@ -94,8 +95,8 @@ mod_export zlong lastval, /* $? */ mypid, /* $$ */ lastpid, /* $! */ - columns, /* $COLUMNS */ - lines, /* $LINES */ + zterm_columns, /* $COLUMNS */ + zterm_lines, /* $LINES */ ppid, /* $PPID */ zsh_subshell; /* $ZSH_SUBSHELL */ /**/ @@ -202,6 +203,8 @@ static const struct gsu_scalar home_gsu = { homegetfn, homesetfn, stdunsetfn }; static const struct gsu_scalar term_gsu = { termgetfn, termsetfn, stdunsetfn }; +static const struct gsu_scalar terminfo_gsu = +{ terminfogetfn, terminfosetfn, stdunsetfn }; static const struct gsu_scalar wordchars_gsu = { wordcharsgetfn, wordcharssetfn, stdunsetfn }; static const struct gsu_scalar ifs_gsu = @@ -276,6 +279,7 @@ IPDEF2("-", dash_gsu, PM_READONLY), IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT), IPDEF2("HOME", home_gsu, PM_UNSET), IPDEF2("TERM", term_gsu, 0), +IPDEF2("TERMINFO", terminfo_gsu, PM_UNSET), IPDEF2("WORDCHARS", wordchars_gsu, 0), IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT), IPDEF2("_", underscore_gsu, PM_READONLY), @@ -312,8 +316,8 @@ IPDEF4("PPID", &ppid), IPDEF4("ZSH_SUBSHELL", &zsh_subshell), #define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(varinteger_gsu),10,0,NULL,NULL,NULL,0} -IPDEF5("COLUMNS", &columns, zlevar_gsu), -IPDEF5("LINES", &lines, zlevar_gsu), +IPDEF5("COLUMNS", &zterm_columns, zlevar_gsu), +IPDEF5("LINES", &zterm_lines, zlevar_gsu), IPDEF5("OPTIND", &zoptind, varinteger_gsu), IPDEF5("SHLVL", &shlvl, varinteger_gsu), IPDEF5("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu), @@ -974,7 +978,7 @@ copyparam(Param tpm, Param pm, int fakecopy) * called from inside an associative array), we need the gets and sets * functions to be useful. * - * In this case we assume the the saved parameter is not itself special, + * In this case we assume the saved parameter is not itself special, * so we just use the standard functions. This is also why we switch off * PM_SPECIAL. */ @@ -1009,6 +1013,8 @@ isident(char *s) * definitely not a valid identifier. */ if (!*ss) return 1; + if (s == ss) + return 0; if (*ss != '[') return 0; @@ -1055,6 +1061,14 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w, zlong num = 1, beg = 0, r = 0, quote_arg = 0; Patprog pprog = NULL; + /* + * If in NO_EXEC mode, the parameters won't be set up + * properly, so there's no point even doing any sanity checking. + * Just return 0 now. + */ + if (unset(EXECOPT)) + return 0; + ishash = (v->pm && PM_TYPE(v->pm->node.flags) == PM_HASHED); if (prevcharlen) *prevcharlen = 1; @@ -2230,6 +2244,8 @@ export_param(Param pm) mod_export void setstrvalue(Value v, char *val) { + if (unset(EXECOPT)) + return; if (v->pm->node.flags & PM_READONLY) { zerr("read-only variable: %s", v->pm->node.nam); zsfree(val); @@ -2361,6 +2377,8 @@ setnumvalue(Value v, mnumber val) { char buf[BDIGBUFSIZE], *p; + if (unset(EXECOPT)) + return; if (v->pm->node.flags & PM_READONLY) { zerr("read-only variable: %s", v->pm->node.nam); return; @@ -2398,6 +2416,8 @@ setnumvalue(Value v, mnumber val) mod_export void setarrvalue(Value v, char **val) { + if (unset(EXECOPT)) + return; if (v->pm->node.flags & PM_READONLY) { zerr("read-only variable: %s", v->pm->node.nam); freearray(val); @@ -2442,8 +2462,6 @@ setarrvalue(Value v, char **val) v->start--; v->end--; } - if (v->end < v->start) - v->end = v->start; q = old = v->pm->gsu.a->getfn(v->pm); n = arrlen(old); if (v->start < 0) { @@ -2456,6 +2474,8 @@ setarrvalue(Value v, char **val) if (v->end < 0) v->end = 0; } + if (v->end < v->start) + v->end = v->start; ll = v->start + arrlen(val); if (v->end <= n) @@ -2808,6 +2828,8 @@ sethparam(char *s, char **val) errflag = 1; return NULL; } + if (unset(EXECOPT)) + return NULL; queue_signals(); if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) createparam(t, PM_HASHED); @@ -2846,6 +2868,8 @@ setnparam(char *s, mnumber val) errflag = 1; return NULL; } + if (unset(EXECOPT)) + return NULL; queue_signals(); ss = strchr(s, '['); v = getvalue(&vbuf, &s, 1); @@ -3249,8 +3273,8 @@ zlevarsetfn(Param pm, zlong x) zlong *p = pm->u.valptr; *p = x; - if (p == &lines || p == &columns) - adjustwinsize(2 + (p == &columns)); + if (p == &zterm_lines || p == &zterm_columns) + adjustwinsize(2 + (p == &zterm_columns)); } /* Function to set value of generic special scalar * @@ -4025,6 +4049,18 @@ underscoregetfn(UNUSED(Param pm)) return u; } +/* Function used when we need to reinitialise the terminal */ + +static void +term_reinit_from_pm(void) +{ + /* If non-interactive, delay setting up term till we need it. */ + if (unset(INTERACTIVE) || !*term) + termflags |= TERM_UNKNOWN; + else + init_term(); +} + /* Function to get value for special parameter `TERM' */ /**/ @@ -4042,12 +4078,35 @@ termsetfn(UNUSED(Param pm), char *x) { zsfree(term); term = x ? x : ztrdup(""); + term_reinit_from_pm(); +} - /* If non-interactive, delay setting up term till we need it. */ - if (unset(INTERACTIVE) || !*term) - termflags |= TERM_UNKNOWN; - else - init_term(); +/* Function to get value of special parameter `TERMINFO' */ + +/**/ +char * +terminfogetfn(UNUSED(Param pm)) +{ + return zsh_terminfo ? zsh_terminfo : dupstring(""); +} + +/* Function to set value of special parameter `TERMINFO' */ + +/**/ +void +terminfosetfn(Param pm, char *x) +{ + zsfree(zsh_terminfo); + zsh_terminfo = x; + + /* + * terminfo relies on the value being exported before + * we reinitialise the terminal. This is a bit inefficient. + */ + if ((pm->node.flags & PM_EXPORTED) && x) + addenv(pm, x); + + term_reinit_from_pm(); } /* Function to get value for special parameter `pipestatus' */ diff --git a/Src/prompt.c b/Src/prompt.c index a91ac541f..d15b7c0d4 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -1008,7 +1008,7 @@ countprompt(char *str, int *wp, int *hp, int overf) #endif for (; *str; str++) { - if (w >= columns && overf >= 0) { + if (w >= zterm_columns && overf >= 0) { w = 0; h++; } @@ -1092,8 +1092,8 @@ countprompt(char *str, int *wp, int *hp, int overf) * This isn't easy to handle generally; just assume there's no * output. */ - if(w >= columns && overf >= 0) { - if (!overf || w > columns) { + if(w >= zterm_columns && overf >= 0) { + if (!overf || w > zterm_columns) { w = 0; h++; } @@ -1205,7 +1205,7 @@ prompttrunc(int arg, int truncchar, int doprint, int endchar, if (truncatleft) { /* * To truncate at the left, selectively copy - * maxwidth bytes from the main prompt, preceeded + * maxwidth bytes from the main prompt, preceded * by the truncation string in full. * * We're overwriting the string containing the diff --git a/Src/prototypes.h b/Src/prototypes.h index 07fe2d0c5..f059b6620 100644 --- a/Src/prototypes.h +++ b/Src/prototypes.h @@ -34,12 +34,24 @@ char *calloc _((size_t, size_t)); #endif #if !(defined(USES_TERMCAP_H) || defined(USES_TERM_H)) -extern int tgetent _((char *bp, char *name)); +/* + * These prototypes are only used where we don't have the + * headers. In some cases they need tweaking. + * TBD: we'd much prefer to get hold of the header where + * these are defined. + */ +#ifdef _AIX +#define TC_CONST const +#else +#define TC_CONST +#endif +extern int tgetent _((char *bp, TC_CONST char *name)); extern int tgetnum _((char *id)); extern int tgetflag _((char *id)); extern char *tgetstr _((char *id, char **area)); -extern char *tgoto _((char *cm, int destcol, int destline)); -extern int tputs _((char *cp, int affcnt, int (*outc) (int))); +extern char *tgoto _((TC_CONST char *cm, int destcol, int destline)); +extern int tputs _((TC_CONST char *cp, int affcnt, int (*outc) (int))); +#undef TC_CONST #endif /* MISSING PROTOTYPES FOR VARIOUS OPERATING SYSTEMS */ diff --git a/Src/string.c b/Src/string.c index 2bd1baea3..04e7446c9 100644 --- a/Src/string.c +++ b/Src/string.c @@ -64,7 +64,7 @@ wcs_ztrdup(const wchar_t *s) if (!s) return NULL; - t = (wchar_t *)zalloc(wcslen((wchar_t *)s) + 1); + t = (wchar_t *)zalloc(sizeof(wchar_t) * (wcslen((wchar_t *)s) + 1)); wcscpy(t, s); return t; } diff --git a/Src/subst.c b/Src/subst.c index 24d515d06..f9c48404b 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -579,7 +579,6 @@ filesubstr(char **namptr, int assign) char *str = *namptr; if (*str == Tilde && str[1] != '=' && str[1] != Equals) { - Shfunc dirfunc; char *ptr, *tmp, *res, *ptr2; int val; @@ -594,12 +593,11 @@ filesubstr(char **namptr, int assign) *namptr = dyncat((tmp = oldpwd) ? tmp : pwd, str + 2); return 1; } else if (str[1] == Inbrack && - (dirfunc = getshfunc("zsh_directory_name")) && (ptr2 = strchr(str+2, Outbrack))) { char **arr; untokenize(tmp = dupstrpfx(str+2, ptr2 - (str+2))); remnulargs(tmp); - arr = subst_string_by_func(dirfunc, "n", tmp); + arr = subst_string_by_hook("zsh_directory_name", "n", tmp); res = arr ? *arr : NULL; if (res) { *namptr = dyncat(res, ptr2+1); @@ -1596,7 +1594,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) int arrasg = 0; /* * The (e) flag. As we need to do extra work not quite - * at the end, the effect of this is kludged in in several places. + * at the end, the effect of this is kludged in several places. */ int eval = 0; /* @@ -1609,11 +1607,15 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) */ int presc = 0; /* + * The (g) flag. Process escape sequences with various GETKEY_ flags. + */ + int getkeys = -1; + /* * The (@) flag; interacts obscurely with qt and isarr. * This is one of the things that decides whether multsub * will produce an array, but in an extremely indirect fashion. */ - int nojoin = 0; + int nojoin = isset(SHWORDSPLIT) ? !(ifs && *ifs) : 0; /* * != 0 means ${...}, otherwise $... What works without braces * is largely a historical artefact (everything works with braces, @@ -1719,7 +1721,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) ++arrasg; break; case '@': - nojoin = 1; + nojoin = 2; /* nojoin = 2 means force */ break; case 'M': flags |= SUB_MATCH; @@ -1934,6 +1936,36 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) presc++; break; + case 'g': + t = get_strarg(++s, &arglen); + if (getkeys < 0) + getkeys = 0; + if (*t) { + sav = *t; + *t = 0; + while (*++s) { + switch (*s) { + case 'e': + getkeys |= GETKEY_EMACS; + break; + case 'o': + getkeys |= GETKEY_OCTAL_ESC; + break; + case 'c': + getkeys |= GETKEY_CTRL; + break; + + default: + *t = sav; + goto flagerr; + } + } + *t = sav; + s = t + arglen - 1; + } else + goto flagerr; + break; + case 'z': shsplit = LEXFLAGS_ACTIVE; break; @@ -2035,12 +2067,20 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) /* SH_WORD_SPLIT on or off (doubled). spbreak = 2 means force */ if ((c = *++s) == '=' || c == Equals) { spbreak = 0; + if (nojoin < 2) + nojoin = 0; s++; - } else + } else { spbreak = 2; + if (nojoin < 2) + nojoin = !(ifs && *ifs); + } } else if ((c == '#' || c == Pound) && (itype_end(s+1, IIDENT, 0) != s + 1 || (cc = s[1]) == '*' || cc == Star || cc == '@' + || cc == '?' || cc == Quest + || cc == '$' || cc == String || cc == Qstring + || cc == '#' || cc == Pound || cc == '-' || (cc == ':' && s[2] == '-') || (isstring(cc) && (s[2] == Inbrace || s[2] == Inpar)))) { getlen = 1 + whichlen, s++; @@ -2652,14 +2692,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) *idend = sav; copied = 1; if (isarr) { - if (nojoin) - isarr = -1; - if (qt && !getlen && isarr > 0 && !spsep && spbreak < 2) { - val = sepjoin(aval, sep, 1); - isarr = 0; - } - sep = spsep = NULL; - spbreak = 0; + if (nojoin) + isarr = -1; + if (qt && !getlen && isarr > 0 && !spsep && spbreak < 2) { + val = sepjoin(aval, sep, 1); + isarr = 0; + } + sep = spsep = NULL; + spbreak = 0; } } break; @@ -2799,7 +2839,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) char *check_offset = check_colon_subscript(s, &check_offset2); if (check_offset) { zlong offset = mathevali(check_offset); - zlong length = (zlong)-1; + zlong length; + int length_set = 0; int offset_hack_argzero = 0; if (errflag) return NULL; @@ -2814,12 +2855,11 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) zerr("invalid length: %s", check_offset); return NULL; } - length = mathevali(check_offset); - if (errflag) - return NULL; - if (length < (zlong)0) { - zerr("invalid length: %s", check_offset); - return NULL; + if (check_offset) { + length = mathevali(check_offset); + length_set = 1; + if (errflag) + return NULL; } } if (horrible_offset_hack) { @@ -2847,8 +2887,16 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) } if (offset_hack_argzero) alen++; - if (length < 0) - length = alen; + if (length_set) { + if (length < 0) + length += alen - offset; + if (length < 0) { + zerr("substring expression: %d < %d", + (int)(length + offset), (int)offset); + return NULL; + } + } else + length = alen; if (offset > alen) offset = alen; if (offset + length > alen) @@ -2867,6 +2915,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) aval = newarr; } else { char *sptr, *eptr; + int given_offset; if (offset < 0) { MB_METACHARINIT(); for (sptr = val; *sptr; ) { @@ -2876,12 +2925,28 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) if (offset < 0) offset = 0; } + given_offset = offset; MB_METACHARINIT(); + if (length_set && length < 0) + length -= offset; for (sptr = val; *sptr && offset; ) { sptr += MB_METACHARLEN(sptr); offset--; } - if (length >= 0) { + if (length_set) { + if (length < 0) { + MB_METACHARINIT(); + for (eptr = val; *eptr; ) { + eptr += MB_METACHARLEN(eptr); + length++; + } + if (length < 0) { + zerr("substring expression: %d < %d", + (int)(length + given_offset), + (int)given_offset); + return NULL; + } + } for (eptr = sptr; *eptr && length; ) { eptr += MB_METACHARLEN(eptr); length--; @@ -2979,7 +3044,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) * TODO: again. one might naively have thought this had the * same sort of effect as the ${(t)...} flag and the ${+...} * test, although in this case we do need the value rather - * the the parameter, so maybe it's a bit different. + * the parameter, so maybe it's a bit different. */ if (getlen) { long len = 0; @@ -3015,7 +3080,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) /* At this point we make sure that our arrayness has affected the * arrayness of the linked list. Then, we can turn our value into * a scalar for convenience sake without affecting the arrayness - * of the resulting value. */ + * of the resulting value. ## This is the YUK chunk. ## */ if (isarr) l->list.flags |= LF_ARRAY; else @@ -3037,7 +3102,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) * done any requested splitting of the word value with quoting preserved. * "ssub" is true when we are called from singsub (via prefork): * it means that we must join arrays and should not split words. */ - if (ssub || spbreak || spsep || sep) { + if (ssub || (spbreak && isarr >= 0) || spsep || sep) { if (isarr) { val = sepjoin(aval, sep, 1); isarr = 0; @@ -3075,6 +3140,28 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) } } /* + * Process echo- and print-style escape sequences. + */ + if (getkeys >= 0) { + int len; + + copied = 1; /* string is always copied */ + if (isarr) { + char **ap, **ap2; + + ap = aval; + aval = (char **) zhalloc(sizeof(char *) * (arrlen(aval)+1)); + for (ap2 = aval; *ap; ap++, ap2++) { + *ap2 = getkeystring(*ap, &len, getkeys, NULL); + *ap2 = metafy(*ap2, len, META_USEHEAP); + } + *ap2++ = NULL; + } else { + val = getkeystring(val, &len, getkeys, NULL); + val = metafy(val, len, META_USEHEAP); + } + } + /* * Perform prompt-style modifications. */ if (presc) { diff --git a/Src/text.c b/Src/text.c index e6dd8d7ff..669037a2d 100644 --- a/Src/text.c +++ b/Src/text.c @@ -785,8 +785,7 @@ gettext2(Estate state) taddstr(" "); taddstr(ecgetstr(state, EC_NODUP, NULL)); if (ctype == COND_STREQ || - ctype == COND_STRNEQ || - ctype == COND_REGEX) + ctype == COND_STRNEQ) state->pc++; } else { /* Unary test: `-f foo' etc. */ @@ -894,13 +893,13 @@ getredirs(LinkList redirs) taddstr(f->here_terminator); taddpending(f->name, f->munged_here_terminator); } else { + int fnamelen, sav; taddstr(fstr[REDIR_HERESTR]); /* * Just a quick and dirty representation. * Remove a terminating newline, if any. */ - int fnamelen = strlen(f->name); - int sav; + fnamelen = strlen(f->name); if (fnamelen > 0 && f->name[fnamelen-1] == '\n') { sav = 1; f->name[fnamelen-1] = '\0'; diff --git a/Src/utils.c b/Src/utils.c index b64530bcc..066710e1e 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1,4 +1,3 @@ - /* * utils.c - miscellaneous utilities * @@ -891,7 +890,8 @@ finddir(char *s) { static struct nameddir homenode = { {NULL, "", 0}, NULL, 0 }; static int ffsz; - Shfunc func = getshfunc("zsh_directory_name"); + char **ares; + int len; /* Invalidate directory cache if argument is NULL. This is called * * whenever a node is added to or removed from the hash table, and * @@ -907,9 +907,16 @@ finddir(char *s) return finddir_last = NULL; } - /* It's not safe to use the cache while we have function transformations.*/ - if(!func && !strcmp(s, finddir_full) && *finddir_full) +#if 0 + /* + * It's not safe to use the cache while we have function + * transformations, and it's not clear it's worth the + * complexity of guessing here whether subst_string_by_hook + * is going to turn up the goods. + */ + if (!strcmp(s, finddir_full) && *finddir_full) return finddir_last; +#endif if ((int)strlen(s) >= ffsz) { free(finddir_full); @@ -921,18 +928,15 @@ finddir(char *s) finddir_scan(&homenode.node, 0); scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0); - if (func) { - char **ares = subst_string_by_func(func, "d", finddir_full); - int len; - if (ares && arrlen(ares) >= 2 && - (len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) { - /* better duplicate this string since it's come from REPLY */ - finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir)); - finddir_last->node.nam = zhtricat("[", dupstring(ares[0]), "]"); - finddir_last->dir = dupstrpfx(finddir_full, len); - finddir_last->diff = len - strlen(finddir_last->node.nam); - finddir_best = len; - } + ares = subst_string_by_hook("zsh_directory_name", "d", finddir_full); + if (ares && arrlen(ares) >= 2 && + (len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) { + /* better duplicate this string since it's come from REPLY */ + finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir)); + finddir_last->node.nam = zhtricat("[", dupstring(ares[0]), "]"); + finddir_last->dir = dupstrpfx(finddir_full, len); + finddir_last->diff = len - strlen(finddir_last->node.nam); + finddir_best = len; } return finddir_last; @@ -1292,7 +1296,8 @@ preprompt(void) countprompt(str, &w, 0, -1); opts[PROMPTPERCENT] = percents; zputs(str, shout); - fprintf(shout, "%*s\r%*s\r", (int)columns - w - !hasxn, "", w, ""); + fprintf(shout, "%*s\r%*s\r", (int)zterm_columns - w - !hasxn, + "", w, ""); fflush(shout); free(str); } @@ -1554,49 +1559,49 @@ mod_export int winchanged; static int adjustlines(int signalled) { - int oldlines = lines; + int oldlines = zterm_lines; #ifdef TIOCGWINSZ - if (signalled || lines <= 0) - lines = shttyinfo.winsize.ws_row; + if (signalled || zterm_lines <= 0) + zterm_lines = shttyinfo.winsize.ws_row; else - shttyinfo.winsize.ws_row = lines; + shttyinfo.winsize.ws_row = zterm_lines; #endif /* TIOCGWINSZ */ - if (lines <= 0) { + if (zterm_lines <= 0) { DPUTS(signalled, "BUG: Impossible TIOCGWINSZ rows"); - lines = tclines > 0 ? tclines : 24; + zterm_lines = tclines > 0 ? tclines : 24; } - if (lines > 2) + if (zterm_lines > 2) termflags &= ~TERM_SHORT; else termflags |= TERM_SHORT; - return (lines != oldlines); + return (zterm_lines != oldlines); } static int adjustcolumns(int signalled) { - int oldcolumns = columns; + int oldcolumns = zterm_columns; #ifdef TIOCGWINSZ - if (signalled || columns <= 0) - columns = shttyinfo.winsize.ws_col; + if (signalled || zterm_columns <= 0) + zterm_columns = shttyinfo.winsize.ws_col; else - shttyinfo.winsize.ws_col = columns; + shttyinfo.winsize.ws_col = zterm_columns; #endif /* TIOCGWINSZ */ - if (columns <= 0) { + if (zterm_columns <= 0) { DPUTS(signalled, "BUG: Impossible TIOCGWINSZ cols"); - columns = tccolumns > 0 ? tccolumns : 80; + zterm_columns = tccolumns > 0 ? tccolumns : 80; } - if (columns > 2) + if (zterm_columns > 2) termflags &= ~TERM_NARROW; else termflags |= TERM_NARROW; - return (columns != oldcolumns); + return (zterm_columns != oldcolumns); } /* check the size of the window and adjust if necessary. * @@ -1630,8 +1635,8 @@ adjustwinsize(int from) ttycols = shttyinfo.winsize.ws_col; } else { /* Set to value from environment on failure */ - shttyinfo.winsize.ws_row = lines; - shttyinfo.winsize.ws_col = columns; + shttyinfo.winsize.ws_row = zterm_lines; + shttyinfo.winsize.ws_col = zterm_columns; resetzle = (from == 1); } #else @@ -1651,9 +1656,9 @@ adjustwinsize(int from) * but I'm concerned about what happens on race conditions; e.g., * * suppose the user resizes his xterm during `eval $(resize)'? */ if (adjustlines(from) && zgetenv("LINES")) - setiparam("LINES", lines); + setiparam("LINES", zterm_lines); if (adjustcolumns(from) && zgetenv("COLUMNS")) - setiparam("COLUMNS", columns); + setiparam("COLUMNS", zterm_columns); getwinsz = 1; break; case 2: @@ -2406,8 +2411,10 @@ getquery(char *valid_chars, int purge) } zbeep(); } - if (c >= 0) - write_loop(SHTTY, &c, 1); + if (c >= 0) { + char buf = (char)c; + write_loop(SHTTY, &buf, 1); + } if (nl) write_loop(SHTTY, "\n", 1); @@ -3211,7 +3218,7 @@ getshfunc(char *nam) char ** subst_string_by_func(Shfunc func, char *arg1, char *orig) { - int osc = sfcontext; + int osc = sfcontext, osm = stopmsg; LinkList l = newlinklist(); char **ret; @@ -3227,6 +3234,47 @@ subst_string_by_func(Shfunc func, char *arg1, char *orig) ret = getaparam("reply"); sfcontext = osc; + stopmsg = osm; + return ret; +} + +/** + * Front end to subst_string_by_func to use hook-like logic. + * name can refer to a function, and name + "_hook" can refer + * to an array containing a list of functions. The functions + * are tried in order until one returns success. + */ +/**/ +char ** +subst_string_by_hook(char *name, char *arg1, char *orig) +{ + Shfunc func; + char **ret = NULL; + + if ((func = getshfunc(name))) { + ret = subst_string_by_func(func, arg1, orig); + } + + if (!ret) { + char **arrptr; + int namlen = strlen(name); + VARARR(char, arrnam, namlen + HOOK_SUFFIX_LEN); + memcpy(arrnam, name, namlen); + memcpy(arrnam + namlen, HOOK_SUFFIX, HOOK_SUFFIX_LEN); + + if ((arrptr = getaparam(arrnam))) { + /* Guard against internal modification of the array */ + arrptr = arrdup(arrptr); + for (; *arrptr; arrptr++) { + if ((func = getshfunc(*arrptr))) { + ret = subst_string_by_func(func, arg1, orig); + if (ret) + break; + } + } + } + } + return ret; } @@ -3637,6 +3685,8 @@ spname(char *oldname) thresh = (int)(p - spnameguess) / 4 + 1; if (thresh < 3) thresh = 3; + else if (thresh > 100) + thresh = 100; if ((thisdist = mindist(newname, spnameguess, spnamebest)) >= thresh) { /* The next test is always true, except for the first path * * component. We could initialize bestdist to some large * @@ -3667,16 +3717,22 @@ mindist(char *dir, char *mindistguess, char *mindistbest) int mindistd, nd; DIR *dd; char *fn; - char buf[PATH_MAX]; + char *buf; if (dir[0] == '\0') dir = "."; mindistd = 100; + + buf = zalloc(strlen(dir) + strlen(mindistguess) + 2); sprintf(buf, "%s/%s", dir, mindistguess); + if (access(unmeta(buf), F_OK) == 0) { strcpy(mindistbest, mindistguess); + free(buf); return 0; } + free(buf); + if (!(dd = opendir(unmeta(dir)))) return mindistd; while ((fn = zreaddir(dd, 0))) { @@ -5517,6 +5573,8 @@ getkeystring(char *s, int *len, int how, int *misc) } *t++ = zstrtol(s + (*s == 'x'), &s, (*s == 'x') ? 16 : 8); + if ((how & GETKEY_PRINTF_PERCENT) && t[-1] == '%') + *t++ = '%'; if (svchar) { u[3] = svchar; svchar = '\0'; @@ -1731,6 +1731,23 @@ struct nameddir { #define ND_USERNAME (1<<1) /* nam is actually a username */ #define ND_NOABBREV (1<<2) /* never print as abbrev (PWD or OLDPWD) */ +/* Storage for single group/name mapping */ +typedef struct { + /* Name of group */ + char *name; + /* Group identifier */ + gid_t gid; +} groupmap; +typedef groupmap *Groupmap; + +/* Storage for a set of group/name mappings */ +typedef struct { + /* The set of name to gid mappings */ + Groupmap array; + /* A count of the valid entries in groupmap. */ + int num; +} groupset; +typedef groupset *Groupset; /* flags for controlling printing of hash table nodes */ #define PRINT_NAMEONLY (1<<0) @@ -2310,11 +2327,68 @@ enum { * Memory management * *********************/ +/* + * A Heapid is a type for identifying, uniquely up to the point where + * the count of new identifiers wraps. all heaps that are or + * (importantly) have been valid. Each valid heap is given an + * identifier, and every time we push a heap we save the old identifier + * and give the heap a new identifier so that when the heap is popped + * or freed we can spot anything using invalid memory from the popped + * heap. + * + * We could make this unsigned long long if we wanted a big range. + */ +typedef unsigned int Heapid; + +#ifdef ZSH_HEAP_DEBUG + +/* printf format specifier corresponding to Heapid */ +#define HEAPID_FMT "%x" + +/* Marker that memory is permanently allocated */ +#define HEAPID_PERMANENT (UINT_MAX) + +/* + * Heap debug verbosity. + * Bits to be 'or'ed into the variable also called heap_debug_verbosity. + */ +enum heap_debug_verbosity { + /* Report when we push a heap */ + HDV_PUSH = 0x01, + /* Report when we pop a heap */ + HDV_POP = 0x02, + /* Report when we create a new heap from which to allocate */ + HDV_CREATE = 0x04, + /* Report every time we free a complete heap */ + HDV_FREE = 0x08, + /* Report when we temporarily install a new set of heaps */ + HDV_NEW = 0x10, + /* Report when we restore an old set of heaps */ + HDV_OLD = 0x20, + /* Report when we temporarily switch heaps */ + HDV_SWITCH = 0x40, + /* + * Report every time we allocate memory from the heap. + * This is very verbose, and arguably not very useful: we + * would expect to allocate memory from a heap we create. + * For much debugging heap_debug_verbosity = 0x7f should be sufficient. + */ + HDV_ALLOC = 0x80 +}; + +#define HEAP_ERROR(heap_id) \ + fprintf(stderr, "%s:%d: HEAP DEBUG: invalid heap: " HEAPID_FMT ".\n", \ + __FILE__, __LINE__, heap_id) +#endif + /* heappush saves the current heap state using this structure */ struct heapstack { struct heapstack *next; /* next one in list for this heap */ size_t used; +#ifdef ZSH_HEAP_DEBUG + Heapid heap_id; +#endif }; /* A zsh heap. */ @@ -2325,6 +2399,10 @@ struct heap { size_t used; /* bytes used from the heap */ struct heapstack *sp; /* used by pushheap() to save the value used */ +#ifdef ZSH_HEAP_DEBUG + unsigned int heap_id; +#endif + /* Uncomment the following if the struct needs padding to 64-bit size. */ /* Make sure sizeof(heap) is a multiple of 8 #if defined(PAD_64_BIT) && !defined(__GNUC__) @@ -2492,7 +2570,11 @@ enum { * Yes, I know that doesn't seem to make much sense. * It's for use in completion, comprenez? */ - GETKEY_UPDATE_OFFSET = (1 << 7) + GETKEY_UPDATE_OFFSET = (1 << 7), + /* + * When replacing numeric escapes for printf format strings, % -> %% + */ + GETKEY_PRINTF_PERCENT = (1 << 8) }; /* @@ -2501,8 +2583,9 @@ enum { */ /* echo builtin */ #define GETKEYS_ECHO (GETKEY_BACKSLASH_C) -/* printf format string: \123 -> S, \0123 -> NL 3 */ -#define GETKEYS_PRINTF_FMT (GETKEY_OCTAL_ESC|GETKEY_BACKSLASH_C) +/* printf format string: \123 -> S, \0123 -> NL 3, \045 -> %% */ +#define GETKEYS_PRINTF_FMT \ + (GETKEY_OCTAL_ESC|GETKEY_BACKSLASH_C|GETKEY_PRINTF_PERCENT) /* printf argument: \123 -> \123, \0123 -> S */ #define GETKEYS_PRINTF_ARG (GETKEY_BACKSLASH_C) /* Full print without -e */ diff --git a/Src/zsh.mdd b/Src/zsh.mdd index 537aa4d8e..6e9077676 100644 --- a/Src/zsh.mdd +++ b/Src/zsh.mdd @@ -9,13 +9,14 @@ alwayslink=1 # autobins not specified because of alwayslink -objects="builtin.o compat.o cond.o exec.o glob.o hashtable.o \ +objects="builtin.o compat.o cond.o exec.o glob.o hashtable.o hashnameddir.o \ hist.o init.o input.o jobs.o lex.o linklist.o loop.o math.o \ mem.o module.o options.o params.o parse.o pattern.o prompt.o signals.o \ signames.o sort.o string.o subst.o text.o utils.o watch.o" -headers="../config.h system.h zsh.h sigcount.h signals.h \ +headers="../config.h zsh_system.h zsh.h sigcount.h signals.h \ prototypes.h hashtable.h ztype.h" +hdrdeps="zshcurses.h zshterm.h" :<<\Make @CONFIG_MK@ @@ -35,9 +36,6 @@ init.o params.o parse.o: version.h params.o: patchlevel.h -# The main shell doesn't currently need zshcurses.h and zshterm.h, -# but make sure these are built with the headers. -# If it did need need them they would be in headers at the top instead. version.h: $(sdir_top)/Config/version.mk zshcurses.h zshterm.h echo '#define ZSH_VERSION "'$(VERSION)'"' > $@ @@ -86,6 +84,10 @@ zshpaths.h: Makemod $(CONFIG_INCS) >>zshpaths.h.tmp; \ fi; \ fi + @if test x$(additionalfpath) != x; then \ + fpath_tmp="`echo $(additionalfpath) | sed -e 's:,:\", \":g'`"; \ + echo "#define ADDITIONAL_FPATH { \"$$fpath_tmp\" }" >> zshpaths.h.tmp; \ + fi @if cmp -s zshpaths.h zshpaths.h.tmp; then \ rm -f zshpaths.h.tmp; \ echo "\`zshpaths.h' is up to date." ; \ @@ -123,7 +125,7 @@ clean.zsh: # This is not properly part of this module, but it is built as if it were. main.o: main.c zsh.mdh main.epro - $(CC) -c -I. $(CPPFLAGS) $(DEFS) $(CFLAGS) -o $@ $(sdir)/main.c + $(CC) -c -I. -I$(sdir_top)/Src $(CPPFLAGS) $(DEFS) $(CFLAGS) -o $@ $(sdir)/main.c main.syms: $(PROTODEPS) proto.zsh: main.epro diff --git a/Src/system.h b/Src/zsh_system.h index 1c737087f..f38533023 100644 --- a/Src/system.h +++ b/Src/zsh_system.h @@ -37,13 +37,16 @@ #endif #endif -#if defined(__linux) || defined(__GNU__) || defined(__GLIBC__) +#if defined(__linux) || defined(__GNU__) || defined(__GLIBC__) || defined(LIBC_MUSL) /* * Turn on numerous extensions. * This is in order to get the functions for manipulating /dev/ptmx. */ #define _GNU_SOURCE 1 #endif +#ifdef LIBC_MUSL +#define _POSIX_C_SOURCE 200809L +#endif /* NeXT has half-implemented POSIX support * * which currently fools configure */ @@ -847,3 +850,27 @@ extern short ospeed; #elif HAVE_STRUCT_STAT_ST_CTIMENSEC # define GET_ST_CTIME_NSEC(st) (st).st_ctimensec #endif + +#if defined(HAVE_TGETENT) && !defined(ZSH_NO_TERM_HANDLING) +# if defined(ZSH_HAVE_CURSES_H) && defined(ZSH_HAVE_TERM_H) +# define USES_TERM_H 1 +# else +# ifdef HAVE_TERMCAP_H +# define USES_TERMCAP_H 1 +# endif +# endif + +# ifdef USES_TERM_H +# ifdef HAVE_TERMIO_H +# include <termio.h> +# endif +# ifdef ZSH_HAVE_CURSES_H +# include "zshcurses.h" +# endif +# include "zshterm.h" +# else +# ifdef USES_TERMCAP_H +# include <termcap.h> +# endif +# endif +#endif diff --git a/Test/.distfiles b/Test/.distfiles index 0e691743b..8a5d716f4 100644 --- a/Test/.distfiles +++ b/Test/.distfiles @@ -1,6 +1,7 @@ DISTFILES_SRC=' .cvsignore .distfiles +compgentest A01grammar.ztst A02alias.ztst A03quoting.ztst @@ -42,6 +43,7 @@ V06parameter.ztst Y01completion.ztst Y02compmatch.ztst Y03arguments.ztst +Y04compgen.ztst comptest runtests.zsh ztst.zsh diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst index c8bf91cff..f04dddaa8 100644 --- a/Test/A01grammar.ztst +++ b/Test/A01grammar.ztst @@ -266,7 +266,7 @@ ## Select now reads from stdin if the shell is not interactive. ## Its own output goes to stderr. - (COLUMNS=80 + (COLUMNS=80 LINES=3 PS3="input> " select name in one two three; do print $name @@ -577,3 +577,15 @@ 0:$0 is traditionally if bizarrely set to the first argument with -c >myargzero >myargone + + (setopt shglob + eval ' + if ! (echo success1); then echo failure1; fi + if !(echo success2); then echo failure2; fi + print -l one two | while(read foo)do(print read it)done + ') +0:Parentheses in shglob +>success1 +>success2 +>read it +>read it diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst index 1c63b6377..4d96d8bb9 100644 --- a/Test/A04redirect.ztst +++ b/Test/A04redirect.ztst @@ -366,3 +366,71 @@ >more output: >This file contains data. >This file contains data. + + $ZTST_testdir/../Src/zsh -fc 'exec >/nonexistent/nonexistent + echo output' +0:failed exec redir, no POSIX_BUILTINS +>output +?zsh:1: no such file or directory: /nonexistent/nonexistent + + $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c ' + exec >/nonexistent/nonexistent + echo output' +1:failed exec redir, POSIX_BUILTINS +?zsh:2: no such file or directory: /nonexistent/nonexistent + + $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c ' + set >/nonexistent/nonexistent + echo output' +1:failed special builtin redir, POSIX_BUILTINS +?zsh:2: no such file or directory: /nonexistent/nonexistent + + $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c ' + command set >/nonexistent/nonexistent + echo output' +0:failed special builtin redir with command prefix, POSIX_BUILTINS +>output +?zsh:2: no such file or directory: /nonexistent/nonexistent + + $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c ' + echo >/nonexistent/nonexistent + echo output' +0:failed unspecial builtin redir, POSIX_BUILTINS +>output +?zsh:2: no such file or directory: /nonexistent/nonexistent + + $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS -c ' + . /nonexistent/nonexistent + echo output' +1:failed dot, POSIX_BUILTINS +?zsh:.:2: no such file or directory: /nonexistent/nonexistent + + $ZTST_testdir/../Src/zsh -f -c ' + . /nonexistent/nonexistent + echo output' +0:failed dot, NO_POSIX_BUILTINS +>output +?zsh:.:2: no such file or directory: /nonexistent/nonexistent + + $ZTST_testdir/../Src/zsh -f <<<' + readonly foo + foo=bar set output + echo output' +0:failed assignment on posix special, NO_POSIX_BUILTINS +>output +?zsh: read-only variable: foo + + $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS <<<' + readonly foo + foo=bar set output + echo output' +1:failed assignment on posix special, POSIX_BUILTINS +?zsh: read-only variable: foo + + $ZTST_testdir/../Src/zsh -f -o POSIX_BUILTINS <<<' + readonly foo + foo=bar echo output + echo output' +0:failed assignment on non-posix-special, POSIX_BUILTINS +>output +?zsh: read-only variable: foo diff --git a/Test/A06assign.ztst b/Test/A06assign.ztst index 44c8e3193..84500f605 100644 --- a/Test/A06assign.ztst +++ b/Test/A06assign.ztst @@ -7,6 +7,127 @@ 1:assign to association with odd no. of values ?(eval):2: bad set of key/value pairs for associative array +# tests of array element assignment + + array=(1 2 3 4 5) + array[1]=42 + print $array +0:Replacement of array element +>42 2 3 4 5 + + array=(1 2 3 4 5) + array[1]=(42 43) + print $array +0:Replacement of array element with array +>42 43 2 3 4 5 + + array=(1 2 3 4 5) + array[1,2]=(42 43) + print $array +0:Replacement of start of array +>42 43 3 4 5 + + array=(1 2 3 4 5) + array[1,4]=(42 43) + print $array +0:Replacement of start of array with shorter slice +>42 43 5 + + array=(1 2 3 4 5) + array[1,6]=(42 43) + print $array +0:Replacement of array by extending slice +>42 43 + + array=(1 2 3 4 5) + array[3]=(42 43) + print $array +0:Replacement of middle element with array +>1 2 42 43 4 5 + + array=(1 2 3 4 5) + array[3,4]=(42 43 44) + print $array +0:Replacement of slice in middle +>1 2 42 43 44 5 + + array=(1 2 3 4 5) + array[7,8]=(42 43) + print $array + # check that [6] was left empty... + array[6]=41 + print $array +0:Appending by replacing elements off the end +>1 2 3 4 5 42 43 +>1 2 3 4 5 41 42 43 + + array=(1 2 3 4 5) + array[-1]=42 + print $array +0:Replacement of last element of array, negative indices +>1 2 3 4 42 + + array=(1 2 3 4 5) + array[-1]=(42 43) + print $array +0:Replacement of last element of array with array, negative indices +>1 2 3 4 42 43 + + array=(1 2 3 4 5) + array[-3,-2]=(42 43 44) + print $array +0:Replacement of middle of array, negative indices +>1 2 42 43 44 5 + + array=(1 2 3 4 5) + array[-5,-1]=(42 43) + print $array +0:Replacement of entire array, negative indices +>42 43 + + array=(1 2 3 4 5) + array[-7,-1]=(42 43) + print $array +0:Replacement of more than entire array, negative indices +>42 43 + + array=(1 2 3 4 5) + array[-7]=42 + print $array +0:Replacement of element off start of array. +>42 1 2 3 4 5 + + array=(1 2 3 4 5) + array[-7]=42 + array[-6]=43 + print $array +0:Replacement off start doesn't leave gaps. Hope this is right. +>43 1 2 3 4 5 + + array=(1 2 3 4 5) + array[1,-1]=(42 43) + print $array + array[-3,3]=(1 2 3 4 5) + print $array +0:Replacement of entire array, mixed indices +>42 43 +>1 2 3 4 5 + + array=(1 2 3 4 5) + array[-7,7]=(42 43) + print $array +0:Replacement of more than entire array, mixed indices +>42 43 + + array=(1 2 3 4 5) + array[3,-2]=(42 43 44) + print $array + array[-3,5]=(100 99) + print $array +0:Replacement of slice in middle, mixed indices +>1 2 42 43 44 5 +>1 2 42 100 99 5 + # tests of var+=scalar s+=foo diff --git a/Test/B03print.ztst b/Test/B03print.ztst index 92a24d6b6..48574c227 100644 --- a/Test/B03print.ztst +++ b/Test/B03print.ztst @@ -105,10 +105,9 @@ 0:numeric value of high numbered character >f0 -# code will probably be changed to print the literal `%s' in this case printf '\x25s\n' arg -0:using \x25 to introduce a format specifier ->arg +0:using \x25 to print a literal % in format +>%s printf '%3c\n' c 0:width specified in format specifier diff --git a/Test/B04read.ztst b/Test/B04read.ztst index 2c87aa67a..ad427dc0d 100644 --- a/Test/B04read.ztst +++ b/Test/B04read.ztst @@ -88,3 +88,8 @@ print ${#line} 0:read with trailing metafied characters >24 + + (typeset -r foo + read foo) <<<bar +1:return status on failing to set parameter +?(eval):2: read-only variable: foo diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst index 00e22c182..629fdd206 100644 --- a/Test/C02cond.ztst +++ b/Test/C02cond.ztst @@ -306,6 +306,21 @@ F:Failures in these cases do not indicate a problem in the shell. 2:Error message for unknown infix condition ?(eval):1: unknown condition: -fail + crashme() { + if [[ $1 =~ ^http:* ]] + then + url=${1#*=} + fi + } + which crashme +0:Regression test for examining code with regular expression match +>crashme () { +> if [[ $1 =~ ^http:* ]] +> then +> url=${1#*=} +> fi +>} + %clean # This works around a bug in rm -f in some versions of Cygwin chmod 644 unmodish diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index 8ba08b29c..6379c8cd0 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -175,6 +175,14 @@ 0:${#...}, $#... >8 8 8 8 8 8 8 8 + set 1 2 3 4 5 6 7 8 9 + print ${##} + set 1 2 3 4 5 6 7 8 9 10 + print ${##} +0:${##} is length of $# +>1 +>2 + array=(once bitten twice shy) print IF${array}THEN print IF${^array}THEN @@ -290,6 +298,26 @@ >Howzat >usay + foo='\u65\123' + print -r ${(g:o:)foo} + foo='\u65\0123' + print -r ${(g::)foo} + foo='\u65^X' + print -r ${(V)${(g:c:)foo}} + foo='\u65\C-x\M-a' + print -r ${(V)${(g:e:)foo}} + foo='\u65\123\C-x' + print -r ${(V)${(g:eo:)foo}} + foo=('\u65' '\0123' '^X\M-a') + print -r ${(V)${(g:e:)foo}} +0:${(g)...} +>eS +>eS +>e^X +>e^X\M-a +>eS^X +>e S ^X\M-a + foo='I'\''m nearly out of my mind with tedium' bar=foo print ${(P)bar} @@ -1338,6 +1366,7 @@ print ${foo:$(echo 3 + 3):`echo 4 - 3`} print ${foo: -1} print ${foo: -10} + print ${foo:5:-2} 0:Bash-style offsets, scalar >456789 >56789 @@ -1349,6 +1378,7 @@ >7 >9 >123456789 +>67 foo=(1 2 3 4 5 6 7 8 9) print ${foo:3} @@ -1361,6 +1391,7 @@ print ${foo:$(echo 3 + 3):`echo 4 - 3`} print ${foo: -1} print ${foo: -10} + print ${foo:5:-2} 0:Bash-style offsets, array >4 5 6 7 8 9 >5 6 7 8 9 @@ -1372,6 +1403,7 @@ >7 >9 >1 2 3 4 5 6 7 8 9 +>6 7 testfn() { emulate -L sh @@ -1401,3 +1433,22 @@ >a >b >c + + printf "%n" '[0]' +1:Regression test for identifier test +?(eval):1: not an identifier: [0] + + str=rts + print ${str:0:} +1:Regression test for missing length after offset +?(eval):2: unrecognized modifier + + foo="123456789" + print ${foo:5:-6} +1:Regression test for total length < 0 in string +?(eval):2: substring expression: 3 < 5 + + foo=(1 2 3 4 5 6 7 8 9) + print ${foo:5:-6} +1:Regression test for total length < 0 in array +?(eval):2: substring expression: 3 < 5 diff --git a/Test/E01options.ztst b/Test/E01options.ztst index be83ceccd..4b53840c6 100644 --- a/Test/E01options.ztst +++ b/Test/E01options.ztst @@ -344,6 +344,15 @@ 0:NO_EXEC option >before + (setopt noexec + typeset -A hash + hash['this is a string']) +0:NO_EXEC option should not attempt to parse subscripts + + (setopt noexec nomatch + echo *NonExistentFile*) +0:NO_EXEC option should not do globbing + setopt NO_eval_lineno eval 'print $LINENO' setopt eval_lineno diff --git a/Test/E02xtrace.ztst b/Test/E02xtrace.ztst index a0c2e9660..2420aebd7 100644 --- a/Test/E02xtrace.ztst +++ b/Test/E02xtrace.ztst @@ -7,6 +7,11 @@ local regression_test_dummy_variable print "$*" } + function xtfx { + local regression_test_dummy_variable + print "Tracing: (){ builtin 2>file }" 2>>xtrace.err + { print "Tracing: (){ { builtin } 2>file }" } 2>>xtrace.err + } echo 'print "$*"' > xt.in %test @@ -31,6 +36,7 @@ repeat 1 do cat <<<'Tracing: do external done 2>file'; done 2>>xtrace.err xtf 'Tracing: function' xtf 'Tracing: function 2>file' 2>>xtrace.err + xtfx . ./xt.in 'Tracing: source' . ./xt.in 'Tracing: source 2>file' 2>>xtrace.err set +x @@ -54,23 +60,23 @@ >Tracing: do external done 2>file >Tracing: function >Tracing: function 2>file +>Tracing: (){ builtin 2>file } +>Tracing: (){ { builtin } 2>file } >Tracing: source >Tracing: source 2>file ->+(eval):4> print 'Tracing: builtin 2>file' ->+(eval):6> cat >+(eval):8> print 'Tracing: ( builtin ) 2>file' >+(eval):10> cat >+(eval):12> print 'Tracing: { builtin } 2>file' >+(eval):14> cat >+(eval):16> print 'Tracing: do builtin done 2>file' >+(eval):18> cat ->+(eval):20> xtf 'Tracing: function 2>file' >+xtf:1> local regression_test_dummy_variable >+xtf:2> print 'Tracing: function 2>file' ->+(eval):22> . ./xt.in 'Tracing: source 2>file' ->+./xt.in:1> print 'Tracing: source 2>file' +>+xtfx:3> print 'Tracing: (){ { builtin } 2>file }' ?+(eval):3> print 'Tracing: builtin' +?+(eval):4> print 'Tracing: builtin 2>file' ?+(eval):5> cat +?+(eval):6> cat ?+(eval):7> print 'Tracing: ( builtin )' ?+(eval):9> cat ?+(eval):11> print 'Tracing: { builtin }' @@ -80,9 +86,15 @@ ?+(eval):19> xtf 'Tracing: function' ?+xtf:1> local regression_test_dummy_variable ?+xtf:2> print 'Tracing: function' -?+(eval):21> . ./xt.in 'Tracing: source' +?+(eval):20> xtf 'Tracing: function 2>file' +?+(eval):21> xtfx +?+xtfx:1> local regression_test_dummy_variable +?+xtfx:2> print 'Tracing: (){ builtin 2>file }' +?+(eval):22> . ./xt.in 'Tracing: source' ?+./xt.in:1> print 'Tracing: source' -?+(eval):23> set +x +?+(eval):23> . ./xt.in 'Tracing: source 2>file' +?+./xt.in:1> print 'Tracing: source 2>file' +?+(eval):24> set +x typeset -ft xtf xtf 'Tracing: function' diff --git a/Test/Y04compgen.ztst b/Test/Y04compgen.ztst new file mode 100644 index 000000000..90dce6148 --- /dev/null +++ b/Test/Y04compgen.ztst @@ -0,0 +1,21 @@ +# Tests for bash compgen compatibility. + +%prep + if ( zmodload zsh/parameter ) >/dev/null 2>&1; then + . $ZTST_srcdir/compgentest + comptestinit -z $ZTST_testdir/../Src/zsh && + else + ZTST_unimplemented="the zsh/parameter module is not available" + fi + +%test + + comptest $': \t\t\t\t\t\t\t' +0:bash compatibility: compgen -W +>abc +>abe +>ab + +%clean + + zmodload -ui zsh/parameter diff --git a/Test/compgentest b/Test/compgentest new file mode 100644 index 000000000..26b202c43 --- /dev/null +++ b/Test/compgentest @@ -0,0 +1,15 @@ +comptestinit () { + + setopt extendedglob + [[ -d $ZTST_testdir/Modules/zsh ]] && module_path=( $ZTST_testdir/Modules ) + + zmodload -i zsh/parameter || return $? + autoload -Uz bashcompinit || return $? + bashcompinit || return $? + +} + +comptest () { + compgen -W 'abc abe ab a def' ab +} + diff --git a/configure.ac b/configure.ac index a93eb5115..1ce815ca5 100644 --- a/configure.ac +++ b/configure.ac @@ -105,6 +105,18 @@ AC_HELP_STRING([--enable-zsh-secure-free], [turn on error checking for free()]), AC_DEFINE(ZSH_SECURE_FREE) fi]) +dnl Do you want to debug zsh heap allocation? +dnl Does not depend on zsh-mem. +ifdef([zsh-heap-debug],[undefine([zsh-heap-debug])])dnl +AH_TEMPLATE([ZSH_HEAP_DEBUG], +[Define to 1 if you want to turn on error checking for heap allocation.]) +AC_ARG_ENABLE(zsh-heap-debug, +AC_HELP_STRING([--enable-zsh-heap-debug], +[turn on error checking for heap allocation]), +[if test x$enableval = xyes; then + AC_DEFINE(ZSH_HEAP_DEBUG) +fi]) + dnl Do you want debugging information on internal hash tables. dnl This turns on the `hashinfo' builtin command. ifdef([zsh-hash-debug],[undefine([zsh-hash-debug])])dnl @@ -276,6 +288,16 @@ else FUNCTIONS_SUBDIRS=no fi +ifdef([additionalfpath],[undefine([additionalfpath])])dnl +AC_ARG_ENABLE(additional-fpath, +AC_HELP_STRING([--enable-additional-fpath=DIR], [add directories to default function path]), +[if test x$enableval = xyes; then + additionalfpath="" +else + additionalfpath="${enableval}" +fi], [additionalfpath=""]) + +AC_SUBST(additionalfpath)dnl AC_SUBST(fndir)dnl AC_SUBST(sitefndir)dnl AC_SUBST(FUNCTIONS_SUBDIRS)dnl @@ -539,6 +561,15 @@ AC_PROG_AWK dnl Check for mawk,gawk,nawk, then awk. AC_PROG_LN dnl Check for working ln, for "make install" AC_PROG_EGREP dnl sets $EGREP to grep -E or egrep AC_CHECK_PROGS([YODL], [yodl], [: yodl]) + +YODL_OPTIONS='' +if test "x$ac_cv_prog_YODL" = xyodl; then + case `yodl --version` in + *"version 3."*) YODL_OPTIONS='-L' ;; + esac +fi +AC_SUBST(YODL_OPTIONS) + AC_CHECK_PROGS([PDFETEX], [pdfetex], [: pdfetex]) AC_CHECK_PROGS([TEXI2PDF], [texi2pdf], []) AC_CHECK_PROGS([TEXI2HTML], [texi2html], []) @@ -983,7 +1014,8 @@ dnl <sys/types.h> and <signal.h>. Others might need dnl to be added. AC_CACHE_CHECK(for sigset_t, zsh_cv_type_sigset_t, [AC_TRY_COMPILE( -[#include <sys/types.h> +[#define _POSIX_C_SOURCE 200809L +#include <sys/types.h> #include <signal.h>], [sigset_t tempsigset;], zsh_cv_type_sigset_t=yes, zsh_cv_type_sigset_t=no)]) AH_TEMPLATE([sigset_t], @@ -1005,6 +1037,7 @@ AC_CHECK_MEMBERS([struct stat.st_atim.tv_nsec, dnl Check for struct timezone since some old SCO versions do not define it zsh_TYPE_EXISTS([ +#define _GNU_SOURCE 1 #ifdef HAVE_SYS_TIME_H # include <sys/time.h> #endif @@ -2455,6 +2488,17 @@ if test x$zsh_cv_c_unicode_support = xyes; then fi dnl +dnl musl support +dnl +AH_TEMPLATE([LIBC_MUSL], +[Define to 1 if musl is being used as the C library]) +AC_ARG_ENABLE(libc-musl, +AC_HELP_STRING([--enable-libc-musl], [compile with musl as the C library]), +[if test x$enableval = xyes; then + AC_DEFINE(LIBC_MUSL) +fi]) + +dnl dnl static user lookup dnl AC_ARG_ENABLE(dynamic-nss, @@ -3066,6 +3110,9 @@ info install path : ${zshinfo}" if test "$zshfndir" != no; then echo "functions install path : ${zshfndir}" fi +if test "x$additionalfpath" != x; then + echo "additional fpath entries : ${additionalfpath}" +fi echo "See config.modules for installed modules and functions. " |