Adding a generic accept-line wrapper
authorFrank Terbeck <ft@grml.org>
Wed, 26 Dec 2007 11:43:57 +0000 (12:43 +0100)
committerFrank Terbeck <ft@grml.org>
Wed, 26 Dec 2007 11:43:57 +0000 (12:43 +0100)
See

<http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>

for details.

etc/zsh/zshrc

index f50d1bc..cddcf7a 100644 (file)
@@ -414,6 +414,144 @@ bindkey '^Xi' insert-unicode-char
 #  bindkey '\eq' push-line-or-edit
 # }}}
 
+# a generic accept-line wrapper {{{
+
+# This widget can prevent unwanted autocorrections from command-name
+# to _command-name, rehash automatically on enter and call any number
+# of builtin and user-defined widgets in different contexts.
+#
+# For a broader description, see:
+# <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
+
+# A newly added command will may not be found or will cause false
+# correction attempts, if you got auto-correction set. By setting the
+# following style, we force accept-line() to rehash, if it cannot
+# find the first word on the command line in the $command[] hash.
+zstyle ':acceptline:*' rehash true
+
+function Accept-Line() {
+    setopt localoptions noksharrays
+    local -a subs
+    local -xi aldone
+    local sub
+
+    zstyle -a ":acceptline:${alcontext}" actions subs
+
+    (( ${#subs} < 1 )) && return 0
+
+    (( aldone = 0 ))
+    for sub in ${subs} ; do
+        [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
+        zle ${sub}
+
+        (( aldone > 0 )) && break
+    done
+}
+
+function Accept-Line-getdefault() {
+    local default_action
+
+    zstyle -s ":acceptline:${alcontext}" default_action default_action
+    case ${default_action} in
+        ((accept-line|))
+            printf ".accept-line"
+            ;;
+        (*)
+            printf ${default_action}
+            ;;
+    esac
+}
+
+function accept-line() {
+    setopt localoptions noksharrays
+    local -a cmdline
+    local -x alcontext
+    local buf com fname format msg default_action
+
+    alcontext='default'
+    buf="${BUFFER}"
+    cmdline=(${(z)BUFFER})
+    com="${cmdline[1]}"
+    fname="_${com}"
+
+    zstyle -t ":acceptline:${alcontext}" rehash \
+        && [[ -z ${commands[$com]} ]]           \
+        && rehash
+
+    if    [[ -n ${reswords[(r)$com]} ]] \
+       || [[ -n ${aliases[$com]}     ]] \
+       || [[ -n ${functions[$com]}   ]] \
+       || [[ -n ${builtins[$com]}    ]] \
+       || [[ -n ${commands[$com]}    ]] ; then
+
+        # there is something sensible to execute, just do it.
+        alcontext='normal'
+        zle Accept-Line
+
+        default_action=$(Accept-Line-getdefault)
+        zstyle -T ":acceptline:${alcontext}" call_default \
+            && zle ${default_action}
+        return
+    fi
+
+    if    [[ -o correct              ]] \
+       || [[ -o correctall           ]] \
+       && [[ -n ${functions[$fname]} ]] ; then
+
+        # nothing there to execute but there is a function called
+        # _command_name; a completion widget. Makes no sense to
+        # call it on the commandline, but the correct{,all} options
+        # will ask for it nevertheless, so warn the user.
+        if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
+            # Okay, we warned the user before, he called us again,
+            # so have it his way.
+            alcontext='force'
+            zle Accept-Line
+
+            default_action=$(Accept-Line-getdefault)
+            zstyle -T ":acceptline:${alcontext}" call_default \
+                && zle ${default_action}
+            return
+        fi
+
+        # prepare warning message for the user, configurable via zstyle.
+        zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
+
+        if [[ -z ${msg} ]] ; then
+            msg="%c will not execute and completion %f exists."
+        fi
+
+        zformat -f msg "${msg}" "c:${com}" "f:${fname}"
+
+        zle -M -- "${msg}"
+        return
+    elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
+        # If we are here, the commandline contains something that is not
+        # executable, which is neither subject to _command_name correction
+        # and is not empty. might be a variable assignment
+        alcontext='misc'
+        zle Accept-Line
+
+        default_action=$(Accept-Line-getdefault)
+        zstyle -T ":acceptline:${alcontext}" call_default \
+            && zle ${default_action}
+        return
+    fi
+
+    # If we got this far, the commandline only contains whitespace, or is empty.
+    alcontext='empty'
+    zle Accept-Line
+
+    default_action=$(Accept-Line-getdefault)
+    zstyle -T ":acceptline:${alcontext}" call_default \
+        && zle ${default_action}
+}
+
+zle -N accept-line
+zle -N Accept-Line
+
+# }}}
+
 # power completion - abbreviation expansion {{{
 # power completion / abbreviation expansion / buffer expansion
 # see http://zshwiki.org/home/examples/zleiab for details