{"thread":{"id":"24877","subject":"[PATCHv2] completion: make compatible with zsh","startedAt":"2010-08-27T02:45:56Z","lastAt":"2010-08-31T07:52:02Z","messageCount":5,"participants":["Mark Lodato","Ævar Arnfjörð Bjarmason","SZEDER Gábor","Peter Kjellerstedt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"149099","messageId":"1282877156-16149-1-git-send-email-lodatom@gmail.com","threadId":"24877","inReplyTo":null,"subject":"[PATCHv2] completion: make compatible with zsh","fromName":"Mark Lodato","fromEmail":"lodatom@gmail.com","sentAt":"2010-08-27T02:45:56Z","receivedAt":"2010-08-27T02:45:56Z","isPatch":false,"sender":{"key":"lodatom@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58860?v=4"},"body":"Modify git-completion.bash so that it also works with zsh when using\nbashcompinit.  In particular:\n\ndeclare -F\n    Zsh doesn't have the same 'declare -F' as bash, but 'declare -f'\n    is the same, and it works just as well for our purposes.\n\n${var:2}\n    Zsh does not implement ${var:2} to skip the first 2 characters, but\n    ${var#??} works in both shells to replace the first 2 characters\n    with nothing.  Thanks to Jonathan Nieder for the suggestion.\n\nfor (( n=1; \"$n\" ... ))\n    Zsh does not allow \"$var\" in arithmetic loops.  Instead, pre-compute\n    the endpoint and use the variables without $'s or quotes.\n\nshopt\n    Zsh uses 'setopt', which has a different syntax than 'shopt'.  Since\n    'shopt' is used infrequently in git-completion, we provide\n    a bare-bones emulation.\n\nemulate -L bash\nKSH_TYPESET\n    Zsh offers bash emulation, which turns on a set of features to\n    closely resemble bash. In particular, this enables SH_WORDSPLIT,\n    which splits scalar variables on word boundaries in 'for' loops.\n    We also need to set KSH_TYPESET, to fix \"local var=$(echo foo bar)\"\n    issues.\n\nThe last set of options are turned on only in _git and _gitk.  Some of\nthe sub-functions may not work correctly if called directly.\n\nSigned-off-by: Mark Lodato <lodatom@gmail.com>\n---\n\nThose on the CC list either responded to the original patch or are the authors\nof the lines affected by this patch:\n    - Andrew wrote __git_ps1_show_upstream().\n    - SZEDER wrote the part using 'declare -F'.\n\n contrib/completion/git-completion.bash |   50 +++++++++++++++++++++++++++++--\n 1 files changed, 46 insertions(+), 4 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 6756990..6a7aae6 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -21,6 +21,11 @@\n #    2) Added the following line to your .bashrc:\n #        source ~/.git-completion.sh\n #\n+#       Or, add the following lines to your .zshrc:\n+#        autoload bashcompinit\n+#        bashcompinit\n+#        source ~/.git-completion.sh\n+#\n #    3) Consider changing your PS1 to also show the current branch:\n #        PS1='[\\u@\\h \\W$(__git_ps1 \" (%s)\")]\\$ '\n #\n@@ -138,11 +143,12 @@ __git_ps1_show_upstream ()\n \t\t# get the upstream from the \"git-svn-id: ...\" in a commit message\n \t\t# (git-svn uses essentially the same procedure internally)\n \t\tlocal svn_upstream=($(git log --first-parent -1 \\\n-\t\t\t\t\t--grep=\"^git-svn-id: \\(${svn_url_pattern:2}\\)\" 2>/dev/null))\n+\t\t\t\t\t--grep=\"^git-svn-id: \\(${svn_url_pattern#??}\\)\" 2>/dev/null))\n \t\tif [[ 0 -ne ${#svn_upstream[@]} ]]; then\n \t\t\tsvn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}\n \t\t\tsvn_upstream=${svn_upstream%@*}\n-\t\t\tfor ((n=1; \"$n\" <= \"${#svn_remote[@]}\"; ++n)); do\n+\t\t\tlocal n_stop=\"${#svn_remote[@]}\"\n+\t\t\tfor ((n=1; n <= n_stop; ++n)); do\n \t\t\t\tsvn_upstream=${svn_upstream#${svn_remote[$n]}}\n \t\t\tdone\n \n@@ -2339,6 +2345,11 @@ _git ()\n {\n \tlocal i c=1 command __git_dir\n \n+\tif [[ -n $ZSH_VERSION ]]; then\n+\t\temulate -L bash\n+\t\tsetopt KSH_TYPESET\n+\tfi\n+\n \twhile [ $c -lt $COMP_CWORD ]; do\n \t\ti=\"${COMP_WORDS[c]}\"\n \t\tcase \"$i\" in\n@@ -2372,17 +2383,22 @@ _git ()\n \tfi\n \n \tlocal completion_func=\"_git_${command//-/_}\"\n-\tdeclare -F $completion_func >/dev/null && $completion_func && return\n+\tdeclare -f $completion_func >/dev/null && $completion_func && return\n \n \tlocal expansion=$(__git_aliased_command \"$command\")\n \tif [ -n \"$expansion\" ]; then\n \t\tcompletion_func=\"_git_${expansion//-/_}\"\n-\t\tdeclare -F $completion_func >/dev/null && $completion_func\n+\t\tdeclare -f $completion_func >/dev/null && $completion_func\n \tfi\n }\n \n _gitk ()\n {\n+\tif [[ -n $ZSH_VERSION ]]; then\n+\t\temulate -L bash\n+\t\tsetopt KSH_TYPESET\n+\tfi\n+\n \t__git_has_doubledash && return\n \n \tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n@@ -2417,3 +2433,29 @@ if [ Cygwin = \"$(uname -o 2>/dev/null)\" ]; then\n complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \\\n \t|| complete -o default -o nospace -F _git git.exe\n fi\n+\n+if [[ -z $ZSH_VERSION ]]; then\n+\tshopt () {\n+\t\tlocal option\n+\t\tif [ $# -ne 2 ]; then\n+\t\t\techo \"USAGE: $0 (-q|-s|-u) <option>\" >&2\n+\t\t\treturn 1\n+\t\tfi\n+\t\tcase \"$2\" in\n+\t\tnullglob)\n+\t\t\toption=\"$2\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\techo \"$0: invalid option: $2\" >&2\n+\t\t\treturn 1\n+\t\tesac\n+\t\tcase \"$1\" in\n+\t\t-q)\tsetopt | grep -q \"$option\" ;;\n+\t\t-u)\tunsetopt \"$option\" ;;\n+\t\t-s)\tsetopt \"$option\" ;;\n+\t\t*)\n+\t\t\techo \"$0: invalid flag: $1\" >&2\n+\t\t\treturn 1\n+\t\tesac\n+\t}\n+fi\n-- \n1.7.2.2\n"},{"id":"149163","messageId":"AANLkTin7rARxLbCUvKOgQUG0s8KhVYZmYxhs+ZafTPW8@mail.gmail.com","threadId":"24877","inReplyTo":"1282877156-16149-1-git-send-email-lodatom@gmail.com","subject":"Re: [PATCHv2] completion: make compatible with zsh","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2010-08-28T10:43:13Z","receivedAt":"2010-08-28T10:43:13Z","isPatch":false,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Fri, Aug 27, 2010 at 02:45, Mark Lodato <lodatom@gmail.com> wrote:\n> Modify git-completion.bash so that it also works with zsh when using\n> bashcompinit.  In particular:\n\nFWIW:\n\nReviewed-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n"},{"id":"149326","messageId":"20100830141927.GA16495@neumann","threadId":"24877","inReplyTo":"1282877156-16149-1-git-send-email-lodatom@gmail.com","subject":"Re: [PATCHv2] completion: make compatible with zsh","fromName":"SZEDER Gábor","fromEmail":"szeder@ira.uka.de","sentAt":"2010-08-30T14:19:27Z","receivedAt":"2010-08-30T14:19:27Z","isPatch":false,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Hi,\n\n\nOn Thu, Aug 26, 2010 at 10:45:56PM -0400, Mark Lodato wrote:\n> Modify git-completion.bash so that it also works with zsh when using\n> bashcompinit.  In particular:\n> \n> declare -F\n>     Zsh doesn't have the same 'declare -F' as bash, but 'declare -f'\n>     is the same, and it works just as well for our purposes.\n\n> @@ -2372,17 +2383,22 @@ _git ()\n>  \tfi\n>  \n>  \tlocal completion_func=\"_git_${command//-/_}\"\n> -\tdeclare -F $completion_func >/dev/null && $completion_func && return\n> +\tdeclare -f $completion_func >/dev/null && $completion_func && return\n>  \n>  \tlocal expansion=$(__git_aliased_command \"$command\")\n>  \tif [ -n \"$expansion\" ]; then\n>  \t\tcompletion_func=\"_git_${expansion//-/_}\"\n> -\t\tdeclare -F $completion_func >/dev/null && $completion_func\n> +\t\tdeclare -f $completion_func >/dev/null && $completion_func\n>  \tfi\n>  }\n\nI chose -F back then because it does not print the definition of the\ncompletion function, so there is less stuff to throw away immediately.\nHowever, the run-time difference seems to be barely measureable (i.e.\n'time declare -f _git_config >/dev/null' vs. 'declare -F _git_config\n >/dev/null' sometimes shows 0.001s difference), so I'm fine with this\nchange.\n\n\n> @@ -2417,3 +2433,29 @@ if [ Cygwin = \"$(uname -o 2>/dev/null)\" ]; then\n>  complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \\\n>  \t|| complete -o default -o nospace -F _git git.exe\n>  fi\n> +\n> +if [[ -z $ZSH_VERSION ]]; then\n\n-z?  I think you wanted to use -n here, like at the other places.\n\nNit: why \"if [[ ... ]]\"?  FWIW \"if [ ... ]\" would be enough.\n\n> +\tshopt () {\n> +\t\tlocal option\n> +\t\tif [ $# -ne 2 ]; then\n> +\t\t\techo \"USAGE: $0 (-q|-s|-u) <option>\" >&2\n> +\t\t\treturn 1\n> +\t\tfi\n> +\t\tcase \"$2\" in\n> +\t\tnullglob)\n> +\t\t\toption=\"$2\"\n> +\t\t\t;;\n> +\t\t*)\n> +\t\t\techo \"$0: invalid option: $2\" >&2\n> +\t\t\treturn 1\n> +\t\tesac\n> +\t\tcase \"$1\" in\n> +\t\t-q)\tsetopt | grep -q \"$option\" ;;\n> +\t\t-u)\tunsetopt \"$option\" ;;\n> +\t\t-s)\tsetopt \"$option\" ;;\n> +\t\t*)\n> +\t\t\techo \"$0: invalid flag: $1\" >&2\n> +\t\t\treturn 1\n> +\t\tesac\n> +\t}\n> +fi\n> -- \n> 1.7.2.2\n> \n"},{"id":"149387","messageId":"AANLkTimNULQNVZ4hzaNY1ZobPRtj_zj545Xi29guGu4g@mail.gmail.com","threadId":"24877","inReplyTo":"20100830141927.GA16495@neumann","subject":"Re: [PATCHv2] completion: make compatible with zsh","fromName":"Mark Lodato","fromEmail":"lodatom@gmail.com","sentAt":"2010-08-31T00:55:46Z","receivedAt":"2010-08-31T00:55:46Z","isPatch":false,"sender":{"key":"lodatom@gmail.com","avatar":"https://avatars.githubusercontent.com/u/58860?v=4"},"body":"2010/8/30 SZEDER Gábor <szeder@ira.uka.de>\n> On Thu, Aug 26, 2010 at 10:45:56PM -0400, Mark Lodato wrote:\n> > @@ -2417,3 +2433,29 @@ if [ Cygwin = \"$(uname -o 2>/dev/null)\" ]; then\n> >  complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \\\n> >       || complete -o default -o nospace -F _git git.exe\n> >  fi\n> > +\n> > +if [[ -z $ZSH_VERSION ]]; then\n>\n> -z?  I think you wanted to use -n here, like at the other places.\n\nOh, yes, sorry.  This was a mistake.  Thanks for catching it.\n\n\n> Nit: why \"if [[ ... ]]\"?  FWIW \"if [ ... ]\" would be enough.\n\nBecause you don't need to quote variables with [[ ... ]] --- e.g. [\n$lines = 0 ] fails, though in this case this feature does not matter\n--- and because [[ ... ]] is faster.\n\nBash 4.1.5:\n> time (for (( i = 0; i < 200000; i++ )); do [ -z $foo ]; done)\nreal    0m3.430s\nuser    0m3.240s\nsys     0m0.180s\n> time (for (( i = 0; i < 200000; i++ )); do [[ -z $foo ]]; done)\nreal    0m2.219s\nuser    0m2.090s\nsys     0m0.100s\n\nZsh 4.3.10:\n> time (for (( i = 0; i < 2000000; i++ )); do [ -z $foo ]; done)\n(; for ((i = 0; i < 2000000; i++ )) do; [ -z $foo ]; done; )  13.56s\nuser 1.64s system 99% cpu 15.327 total\n> time (for (( i = 0; i < 2000000; i++ )); do [[ -z $foo ]]; done)\n(; for ((i = 0; i < 2000000; i++ )) do; [[ -z $foo ]]; done; )  4.62s\nuser 0.01s system 99% cpu 4.644 total\n\nIs there a reason to prefer [ ... ] ?\n"},{"id":"149400","messageId":"A612847CFE53224C91B23E3A5B48BAC749BF0BEBB9@xmail3.se.axis.com","threadId":"24877","inReplyTo":"AANLkTimNULQNVZ4hzaNY1ZobPRtj_zj545Xi29guGu4g@mail.gmail.com","subject":"RE: [PATCHv2] completion: make compatible with zsh","fromName":"Peter Kjellerstedt","fromEmail":"peter.kjellerstedt@axis.com","sentAt":"2010-08-31T07:52:02Z","receivedAt":"2010-08-31T07:52:02Z","isPatch":false,"sender":{"key":"peter.kjellerstedt@axis.com","avatar":"https://gravatar.com/avatar/6d5a0182283c8eccd7b134a54dbfd5f30038f3ad4d38b96f424884b614a61ca2?d=mp&s=160"},"body":"> -----Original Message-----\n> From: git-owner@vger.kernel.org [mailto:git-owner@vger.kernel.org] On\n> Behalf Of Mark Lodato\n> Sent: den 31 augusti 2010 02:56\n> To: SZEDER Gábor\n> Cc: Shawn O. Pearce; git@vger.kernel.org; avarab@gmail.com; Jonathan\n> Nieder; Andrew Sayers\n> Subject: Re: [PATCHv2] completion: make compatible with zsh\n> \n> 2010/8/30 SZEDER Gábor <szeder@ira.uka.de>\n> > On Thu, Aug 26, 2010 at 10:45:56PM -0400, Mark Lodato wrote:\n> > > @@ -2417,3 +2433,29 @@ if [ Cygwin = \"$(uname -o 2>/dev/null)\" ]; then\n> > >  complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \\\n> > >       || complete -o default -o nospace -F _git git.exe\n> > >  fi\n> > > +\n> > > +if [[ -z $ZSH_VERSION ]]; then\n> >\n> > -z?  I think you wanted to use -n here, like at the other places.\n> \n> Oh, yes, sorry.  This was a mistake.  Thanks for catching it.\n> \n> \n> > Nit: why \"if [[ ... ]]\"?  FWIW \"if [ ... ]\" would be enough.\n> \n> Because you don't need to quote variables with [[ ... ]] --- e.g. [\n> $lines = 0 ] fails, though in this case this feature does not matter\n> --- and because [[ ... ]] is faster.\n> \n> Bash 4.1.5:\n> > time (for (( i = 0; i < 200000; i++ )); do [ -z $foo ]; done)\n> real    0m3.430s\n> user    0m3.240s\n> sys     0m0.180s\n> > time (for (( i = 0; i < 200000; i++ )); do [[ -z $foo ]]; done)\n> real    0m2.219s\n> user    0m2.090s\n> sys     0m0.100s\n> \n> Zsh 4.3.10:\n> > time (for (( i = 0; i < 2000000; i++ )); do [ -z $foo ]; done)\n> (; for ((i = 0; i < 2000000; i++ )) do; [ -z $foo ]; done; )  13.56s\n> user 1.64s system 99% cpu 15.327 total\n> > time (for (( i = 0; i < 2000000; i++ )); do [[ -z $foo ]]; done)\n> (; for ((i = 0; i < 2000000; i++ )) do; [[ -z $foo ]]; done; )  4.62s\n> user 0.01s system 99% cpu 4.644 total\n> \n> Is there a reason to prefer [ ... ] ?\n\nThe [ command is defined by POSIX, while [[ is an extension to the \nshell language implemented by bash (and zsh). Thus the [[ construct \nwould fail on a stricter POSIX implementation of the shell language, \ne.g., as implemented by dash. Thus to be POSIX compliant (which is\nrequired for shell scripts installed by a multi system supporting \napplication like git), the [[ construct cannot be used. \n\nOf course, this does not really apply to a script explicitly written \nfor bash, but that is the common reason to prefer [ over [[ in shell \nscripts.\n\n//Peter\n\n"}]}