Add git-escape-magic
authorJoerg Jaspert <joerg@debian.org>
Thu, 25 Apr 2013 08:25:42 +0000 (10:25 +0200)
committerJoerg Jaspert <joerg@debian.org>
Thu, 25 Apr 2013 08:26:26 +0000 (10:26 +0200)
small helper to use setopt extended_glob and still have it nice
with git things like ~, ^, @{...

.zsh/06_Modules.zsh
.zsh/README.org
.zsh/functions/git-escape-magic [new file with mode: 0644]

index b90074e..242dfa8 100644 (file)
@@ -20,6 +20,11 @@ autoload run-help-svn
 autoload -U url-quote-magic
 zle -N self-insert url-quote-magic
 
+# we use extended_glob, which breaks some things in git. Like,
+# git log @{1}..@{1}. This module from Akinori MUSHA helps.
+autoload -Uz git-escape-magic
+git-escape-magic
+
 ## Allow known mime types to be used as 'command'
 if is42 && zstyle -t ':ganneff:config' mimesetup true; then
     autoload -U zsh-mime-setup
index b5289b2..c88a3e6 100644 (file)
@@ -254,6 +254,10 @@ The prompt i use is based on various others.
 - extract/ls_archive is from [[https://github.com/sorin-ionescu][Sorin Ionescu]] and available under the MIT
   License.
 
+- git-escape-magic is Copyright (c) 2011, 2012 Akinori MUSHA and
+  licensed under the 2-clause BSD license. It is available
+  [[https://github.com/knu/zsh-git-escape-magic][from his github]] repository.
+
 * Footnotes
 
 [fn:1] Actually, the symlink points to the file zshenv.home inside that directory
diff --git a/.zsh/functions/git-escape-magic b/.zsh/functions/git-escape-magic
new file mode 100644 (file)
index 0000000..e148d7c
--- /dev/null
@@ -0,0 +1,136 @@
+# -*- mode: sh -*-
+#
+# git-escape-magic - zle tweak for git command line arguments
+#
+# Copyright (c) 2011, 2012 Akinori MUSHA
+# Licensed under the 2-clause BSD license.
+#
+# This tweak eliminates the need for manually escaping shell
+# meta-characters such as [~^{}] that are used for specifying a git
+# object (commit or tree).  Every time you type one of these
+# characters on a git command line, it is automatically escaped with a
+# backslash as necessary and as appropriate.
+#
+# If you want to use this with url-quote-magic, make sure to enable it
+# first.
+#
+# Usage:
+#     autoload -Uz git-escape-magic
+#     git-escape-magic
+#
+
+git-escape-magic.self-insert() {
+    emulate -L zsh
+    setopt extendedglob
+    local self_insert_function
+    zstyle -s ':git-escape-magic' self-insert-function self_insert_function
+
+    if [[ "$KEYS" == [{}~^]* ]] && {
+        local qkey="${(q)KEYS}"
+        [[ "$KEYS" != "$qkey" ]]
+    } && {
+        local lbuf="$LBUFFER$qkey"
+        [[ "${(Q)LBUFFER}$KEYS" == "${(Q)lbuf}" ]]
+    } && {
+        local -a words
+        words=("${(@Q)${(z)lbuf}}")
+        [[ "$words[(i)(*/|)git(|-[^/]##)]" -le $#words ]]
+    }
+    then
+        local i
+        i="$words[(I)([;(){\&]|\&[\&\!]|\|\||[=<>]\(*)]"
+        if [[ $i -gt 0 ]]; then
+            shift $((i-1)) words
+            if [[ "$words[1]" == [\=\<\>]\(* ]]; then
+                words[1]="${words[1]#[=<>]\(}"
+            else
+                [[ "$words[1]" == \; && $words[2] == (then|else|elif|do) ]] && shift words
+                shift words
+            fi
+        fi
+        while [[ "$words[1]" == (if|while|until|\!) ]]; do
+            shift words
+        done
+        while [[ "$words[1]" == [A-Za-z_][A-Za-z0-9_]#=* ]]; do
+            shift words
+        done
+        [[ "$words[1]" == (*/|)git(|-[^/]##) ]] && {
+            local subcommand
+            subcommand="${words[1]##*/git-}"
+            if [[ -z "$subcommand" ]]; then
+                shift words
+                subcommand="$words[1]"
+            fi
+            [[ $#words -ge 2 ]]
+        } &&
+        case "$subcommand" in
+            # commands that may take pathspec but never take refspec with [{}~^]
+            (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)
+                false ;;
+            # commands that may take pathspec but rarely take refspec with [{}~^]
+            (for-each-ref|grep|ls-files|update-index)
+                false ;;
+            (archive|ls-tree)
+                ! [[ $#words -ge 3 &&
+                        "$words[-2]" == [^-]* ]] ;;
+            (diff-tree)
+                ! [[ $#words -ge 4 &&
+                        "$words[-2]" == [^-]* &&
+                        "$words[-3]" == [^-]* ]] ;;
+            (*)
+                [[ $words[(i)--] -gt $#words ]] ;;
+        esac &&
+        case "${words[-1]%%"$KEYS"}" in
+            (*@)
+                [[ "$KEYS" == \{* ]] ;;
+            (*\^)
+                [[ "$KEYS" == [{~^]* ]] ;;
+            (*[@^]\{[^}]##)
+                [[ "$KEYS" == \}* ]] ;;
+            (?*)
+                [[ "$KEYS" == [~^]* ]] ;;
+            (*)
+                false ;;
+        esac &&
+        LBUFFER="$LBUFFER\\"
+    fi
+
+    zle "$self_insert_function"
+}
+
+git-escape-magic.on() {
+    emulate -L zsh
+    local self_insert_function="${$(zle -lL | awk \
+        '$1=="zle"&&$2=="-N"&&$3=="self-insert"{print $4;exit}'):-.self-insert}"
+
+    [[ "$self_insert_function" == git-escape-magic.self-insert ]] &&
+        return 0
+
+    # For url-quote-magic which does not zle -N itself
+    zle -la "$self_insert_function" || zle -N "$self_insert_function"
+
+    zstyle ':git-escape-magic' self-insert-function "$self_insert_function"
+
+    zle -A git-escape-magic.self-insert self-insert
+    return 0
+}
+
+git-escape-magic.off() {
+    emulate -L zsh
+    local self_insert_function
+    zstyle -s ':git-escape-magic' self-insert-function self_insert_function
+
+    [[ -n "$self_insert_function" ]] &&
+        zle -A "$self_insert_function" self-insert
+    return 0
+}
+
+zle -N git-escape-magic.self-insert
+zle -N git-escape-magic.on
+zle -N git-escape-magic.off
+
+git-escape-magic() {
+        git-escape-magic.on
+}
+
+[[ -o kshautoload ]] || git-escape-magic "$@"