Parent directory

git-escape-magic

4333 bytes
  1# -*- mode: sh -*-
  2#
  3# git-escape-magic - zle tweak for git command line arguments
  4#
  5# Copyright (c) 2011, 2012, 2014 Akinori MUSHA
  6# Licensed under the 2-clause BSD license.
  7#
  8# This tweak eliminates the need for manually escaping shell
  9# meta-characters such as [~^{}] that are used for specifying a git
 10# object (commit or tree).  Every time you type one of these
 11# characters on a git command line, it is automatically escaped with a
 12# backslash as necessary and as appropriate.
 13#
 14# If you want to use this with url-quote-magic, make sure to enable it
 15# first.
 16#
 17# Usage:
 18#     autoload -Uz git-escape-magic
 19#     git-escape-magic
 20#
 21
 22git-escape-magic.self-insert() {
 23    emulate -L zsh
 24    setopt extendedglob
 25    local self_insert_function
 26    zstyle -s ':git-escape-magic' self-insert-function self_insert_function
 27
 28    if [[ "$KEYS" == [{}~^]* ]] && {
 29        local qkey="${(q)KEYS}"
 30        [[ "$KEYS" != "$qkey" ]]
 31    } && {
 32        local lbuf="$LBUFFER$qkey"
 33        [[ "${(Q)LBUFFER}$KEYS" == "${(Q)lbuf}" ]]
 34    } && {
 35        local -a words
 36        words=("${(@Q)${(z)lbuf}}")
 37        [[ "$words[(i)(*/|)git(|-[^/]##)]" -le $#words ]]
 38    }
 39    then
 40        local i
 41        i="$words[(I)([;(){\&]|\&[\&\!]|\|\||[=<>]\(*)]"
 42        if [[ $i -gt 0 ]]; then
 43            shift $((i-1)) words
 44            if [[ "$words[1]" == [\=\<\>]\(* ]]; then
 45                words[1]="${words[1]#[=<>]\(}"
 46            else
 47                [[ "$words[1]" == \; && $words[2] == (then|else|elif|do) ]] && shift words
 48                shift words
 49            fi
 50        fi
 51        while [[ "$words[1]" == (if|while|until|\!) ]]; do
 52            shift words
 53        done
 54        while [[ "$words[1]" == [A-Za-z_][A-Za-z0-9_]#=* ]]; do
 55            shift words
 56        done
 57        [[ "$words[1]" == (*/|)git(|-[^/]##) ]] && {
 58            local subcommand
 59            subcommand="${words[1]##*/git-}"
 60            if [[ -z "$subcommand" ]]; then
 61                shift words
 62                subcommand="$words[1]"
 63            fi
 64            [[ $#words -ge 2 ]]
 65        } &&
 66        case "$subcommand" in
 67            # commands that may take pathspec but never take refspec with [{}~^]
 68            (add|rm|am|apply|check-attr|checkout-index|clean|clone|config|diff-files|hash-object|help|index-pack|mailinfo|mailsplit|merge-file|merge-index|mergetool|mktag|mv|pack-objects|pack-redundant|relink|send-email|show-index|show-ref|stage|status|verify-pack)
 69                false ;;
 70            # commands that may take pathspec but rarely take refspec with [{}~^]
 71            (for-each-ref|grep|ls-files|update-index)
 72                false ;;
 73            (archive|ls-tree)
 74                ! [[ $#words -ge 3 &&
 75                        "$words[-2]" == [^-]* ]] ;;
 76            (diff-tree)
 77                ! [[ $#words -ge 4 &&
 78                        "$words[-2]" == [^-]* &&
 79                        "$words[-3]" == [^-]* ]] ;;
 80            (*)
 81                [[ $words[(i)--] -gt $#words ]] ;;
 82        esac &&
 83        case "${words[-1]%%"$KEYS"}" in
 84            (*[@^])
 85                [[ "$KEYS" == [{~^]* ]] ;;
 86            (*[@^]\{[^}]##)
 87                [[ "$KEYS" == \}* ]] ;;
 88            (?*)
 89                [[ "$KEYS" == [~^]* ]] ;;
 90            (*)
 91                false ;;
 92        esac &&
 93        LBUFFER="$LBUFFER\\"
 94    fi
 95
 96    zle "$self_insert_function"
 97}
 98
 99git-escape-magic.on() {
100    emulate -L zsh
101    local self_insert_function="${$(zle -lL | awk \
102        '$1=="zle"&&$2=="-N"&&$3=="self-insert"{print $4;exit}'):-.self-insert}"
103
104    [[ "$self_insert_function" == git-escape-magic.self-insert ]] &&
105        return 0
106
107    # For url-quote-magic which does not zle -N itself
108    zle -la "$self_insert_function" || zle -N "$self_insert_function"
109
110    zstyle ':git-escape-magic' self-insert-function "$self_insert_function"
111
112    zle -A git-escape-magic.self-insert self-insert
113    return 0
114}
115
116git-escape-magic.off() {
117    emulate -L zsh
118    local self_insert_function
119    zstyle -s ':git-escape-magic' self-insert-function self_insert_function
120
121    [[ -n "$self_insert_function" ]] &&
122        zle -A "$self_insert_function" self-insert
123    return 0
124}
125
126zle -N git-escape-magic.self-insert
127zle -N git-escape-magic.on
128zle -N git-escape-magic.off
129
130git-escape-magic() {
131        git-escape-magic.on
132}
133
134[[ -o kshautoload ]] || git-escape-magic "$@"
135