git-escape-magic 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. git-escape-magic.self-insert() {
  22. emulate -L zsh
  23. setopt extendedglob
  24. local self_insert_function
  25. zstyle -s ':git-escape-magic' self-insert-function self_insert_function
  26. if [[ "$KEYS" == [{}~^]* ]] && {
  27. local qkey="${(q)KEYS}"
  28. [[ "$KEYS" != "$qkey" ]]
  29. } && {
  30. local lbuf="$LBUFFER$qkey"
  31. [[ "${(Q)LBUFFER}$KEYS" == "${(Q)lbuf}" ]]
  32. } && {
  33. local -a words
  34. words=("${(@Q)${(z)lbuf}}")
  35. [[ "$words[(i)(*/|)git(|-[^/]##)]" -le $#words ]]
  36. }
  37. then
  38. local i
  39. i="$words[(I)([;(){\&]|\&[\&\!]|\|\||[=<>]\(*)]"
  40. if [[ $i -gt 0 ]]; then
  41. shift $((i-1)) words
  42. if [[ "$words[1]" == [\=\<\>]\(* ]]; then
  43. words[1]="${words[1]#[=<>]\(}"
  44. else
  45. [[ "$words[1]" == \; && $words[2] == (then|else|elif|do) ]] && shift words
  46. shift words
  47. fi
  48. fi
  49. while [[ "$words[1]" == (if|while|until|\!) ]]; do
  50. shift words
  51. done
  52. while [[ "$words[1]" == [A-Za-z_][A-Za-z0-9_]#=* ]]; do
  53. shift words
  54. done
  55. [[ "$words[1]" == (*/|)git(|-[^/]##) ]] && {
  56. local subcommand
  57. subcommand="${words[1]##*/git-}"
  58. if [[ -z "$subcommand" ]]; then
  59. shift words
  60. subcommand="$words[1]"
  61. fi
  62. [[ $#words -ge 2 ]]
  63. } &&
  64. case "$subcommand" in
  65. # commands that may take pathspec but never take refspec with [{}~^]
  66. (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)
  67. false ;;
  68. # commands that may take pathspec but rarely take refspec with [{}~^]
  69. (for-each-ref|grep|ls-files|update-index)
  70. false ;;
  71. (archive|ls-tree)
  72. ! [[ $#words -ge 3 &&
  73. "$words[-2]" == [^-]* ]] ;;
  74. (diff-tree)
  75. ! [[ $#words -ge 4 &&
  76. "$words[-2]" == [^-]* &&
  77. "$words[-3]" == [^-]* ]] ;;
  78. (*)
  79. [[ $words[(i)--] -gt $#words ]] ;;
  80. esac &&
  81. case "${words[-1]%%"$KEYS"}" in
  82. (*[@^])
  83. [[ "$KEYS" == [{~^]* ]] ;;
  84. (*[@^]\{[^}]##)
  85. [[ "$KEYS" == \}* ]] ;;
  86. (?*)
  87. [[ "$KEYS" == [~^]* ]] ;;
  88. (*)
  89. false ;;
  90. esac &&
  91. LBUFFER="$LBUFFER\\"
  92. fi
  93. zle "$self_insert_function"
  94. }
  95. git-escape-magic.on() {
  96. emulate -L zsh
  97. local self_insert_function="${$(zle -lL | awk \
  98. '$1=="zle"&&$2=="-N"&&$3=="self-insert"{print $4;exit}'):-.self-insert}"
  99. [[ "$self_insert_function" == git-escape-magic.self-insert ]] &&
  100. return 0
  101. # For url-quote-magic which does not zle -N itself
  102. zle -la "$self_insert_function" || zle -N "$self_insert_function"
  103. zstyle ':git-escape-magic' self-insert-function "$self_insert_function"
  104. zle -A git-escape-magic.self-insert self-insert
  105. return 0
  106. }
  107. git-escape-magic.off() {
  108. emulate -L zsh
  109. local self_insert_function
  110. zstyle -s ':git-escape-magic' self-insert-function self_insert_function
  111. [[ -n "$self_insert_function" ]] &&
  112. zle -A "$self_insert_function" self-insert
  113. return 0
  114. }
  115. zle -N git-escape-magic.self-insert
  116. zle -N git-escape-magic.on
  117. zle -N git-escape-magic.off
  118. git-escape-magic() {
  119. git-escape-magic.on
  120. }
  121. [[ -o kshautoload ]] || git-escape-magic "$@"