UNIX (s)hell, pt3 · Neg blog

UNIX (s)hell, pt3

Продолжение статей про zsh, здесь будет приведен обзор автодополнения, одной из основных фич, которая существенно выделяет zsh на фоне bash и других оболочек. Кто-то может сказать что fish не лучше, но он совершенно не настраиваемый и далеко не такой гибкий. Причем эту ситуацию разработчики изменять не планируют.

Оригинал автокомплита можно посмотреть здесь: https://github.com/neg-serg/dotfiles/blob/master/.zsh/12-completion.zsh

Автокомплит основан, большей частью на конфиге zsh из GRML.

Почти весь представляет собой большую функцию mycompletion. Просто потому что я почему-то люблю представлять скрипты в виде функций.

    zstyle ':acceptline:*' rehash true

Указывает на то, что при выполнении команды будет обновлены PATH и тому подобные вещи до актуального состояния. Можно рассматривать это также как ребилд индексов автокомплита.

    # allow one error for every three characters typed in approximate completer
    zstyle ':completion:*:approximate:' \
                                                max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'

Задает толерантность к ошибкам, которая может быть исправлена по [tab]-[tab].

    # don't complete backup files as executables
    zstyle ':completion:*:complete:-command-::commands' \
                                                ignored-patterns '(aptitude-*|*\~)'

Убирает из автокомплита файлы с атрибутом +x, которые выглядят как временные(у меня заканчиваются на тильду, можно и что-то emacs-специфичное добавить).

    # start menu completion only if it could find no unambiguous initial string
    zstyle ':completion:*:correct:*'            insert-unambiguous true

Не выдавать меню в том случае, когда выбирать не из чего.

    zstyle ':completion:*:corrections'          format "%{${fg[blue]}%}--%{${reset_color}%} %d%{${reset_color}%} - (%{${fg[cyan]}%}errors %e%{${reset_color}%})"
    zstyle ':completion:*:descriptions'         format "%{${fg[blue]}%}--%{${reset_color}%} %d%{${reset_color}%}%{${reset_color}%}"

Подсветка возможных исправлений либо меню автокомплита.

    zstyle ':completion:*:correct:*'            original true

То, что уже было написано вне зависимости от того видит это zsh как валидное, будет также отражено в меню автокомплита.

    zstyle ':completion:*:-tilde-:*'            group-order 'named-directories'

Первыми в автокомплите для тильды будут hash-директории. Hash это такие глобальные алиасы для директорий. Например hash -d v=”${HOME}/vid” задает соответствие ~v -> ~/vid/

    # insert all expansions for expand completer
    zstyle ':completion:*:expand:*'             tag-order all-expansions

Эффект, который похож на glob_complete, только для expand completer. expand completer это, например /u/b/z -> /usr/bin/z и далее после второго tab будет меню. Must have.

    zstyle ':completion:*:history-words'        list false
    # activate menu                            
    zstyle ':completion:*:history-words'        menu yes
    # ignore duplicate entries                 
    zstyle ':completion:*:history-words'        remove-all-dups yes
    zstyle ':completion:*:history-words'        stop yes

Меню, а не список для истории. Без дубликатов.

    # match uppercase from lowercase           
    zstyle ':completion:*'                      matcher-list 'm:{a-z}={A-Z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*'

Задает соответствие символов, которые могут быть автоматически преобразованы при автокомлите, в частности это делает автокомплит нечувствительным к регистру. Must have.

    # separate matches into groups          
    zstyle ':completion:*:matches'              group 'yes'
    zstyle ':completion:*'                      group-name ''

Группировка автокомлита по группам. Часто бывает что для одного варианта есть несколько возможных источников, которые выдают разные варианты комплита, в том случае когда семантику предугадать нельзя.

    zstyle ':completion:*'                      menu select=5

Выводить меню только в случае, если число подходящих вариантов в списке 5 или больше, в противном случае прыгать по этому списку в цикле по tab по аналогии с tcsh или zsh по-умолчанию.

    zstyle ':completion:*:messages'             format "- %{${fg[cyan]}%}%d%{${reset_color}%} -"
    zstyle ':completion:*:options'              auto-description '%d'
    zstyle ':completion:*:options'              description 'yes'

Украшательства описаний для автокомлита.

    zstyle ':completion:*'                      verbose true
    zstyle ':completion:*:-command-:*:'         verbose false

Убирает описания для команд при автокомплите, потмоу что они медленно работают.

    zstyle ':completion:*:warnings'             format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
    zstyle ':completion:correct:'               prompt 'correct to: %e'

Украшательства warning’ов и предложений для коррекции.

    zstyle ':completion:*:*:zcompile:*'         ignored-patterns '(*~|*.zwc)'

Временные файлы не учавствуют в автодополнении.

    zstyle ':completion::(^approximate*):*:functions' \
                                                ignored-patterns '_*'

Также в автодополнении не учавствуют сами файлы автокомплита, которые начинаются с _.

    zstyle ':completion:*:manuals'              separate-sections true
    zstyle ':completion:*:manuals.*'            insert-sections   true
    zstyle ':completion:*:man:*'                menu yes select

Разделение секций для автокомплита man-страниц.

    zstyle ':completion:*'                      special-dirs ..

Автокомплит для предыдущей директории, must have.

    zstyle ':completion:*:(mv|cp|file|m|mplayer|mp|mpv):*' \
                                                ignored-patterns '(#i)*.(url|mht)'

Игнорировать url и mht для плеера, копирования, перемещения и др.

    zstyle ':completion:*:*:(mplayer|mp|mpv):*' tag-order files
    zstyle ':completion:*:*:(mplayer|mp|mpv):*' file-sort name
    zstyle ':completion:*:*:(mplayer|mp|mpv):*' menu select auto
    zstyle ':completion:*:*:(mplayer*|mp):*'    file-patterns '(#i)*.(rmvb|mkv|vob|ts|mp4|m4a|iso|wmv|webm|flv|ogv|avi|mpg|mpeg|iso|nrg|mp3|flac|rm|wv|m4v):files:mplayer\ play *(-/):directories:directories'

Сортировка по отсортированному списку файлов, из списка, который представляет собой расширение файлов аудио или видео, без учета регистра, для медиаплеера. Нужно чтобы автодополнение не выдывало всякую ненужную ерунду.

    zstyle ':completion:*:default'      \
        select-prompt \
        "%{${fg[cyan]}%}Match %{${fg_bold[cyan]}%}%m%{${fg_no_bold[cyan]}%}  Line %{${fg_bold[cyan]}%}%l%{${fg_no_bold[blue]}%}  %p%{${reset_color}%}"
        zstyle ':completion:*:default'      \
        list-prompt   \
        "%{${fg[cyan]}%}Line %{${fg_bold[cyan]}%}%l%{${fg_no_bold[cyan]}%}  Continue?%{${reset_color}%}"
        zstyle ':completion:*:warnings'     \
        format        \
        "- %{${fg_no_bold[blue]}%}no match%{${reset_color}%} - %{${fg_no_bold[cyan]}%}%d%{${reset_color}%}"

Украшательства для длинного меню. Это нужно в том случае, когда есть очень много вариантов, которые не влезают на экран.

    zstyle ':completion:*:default'  list-colors ${${(s.:.)LS_COLORS}%ec=*}

Использовать при автокомплите файлов подсветку наиболее быстрым известным мне способом. Некоторые другие будут тормозить, особенно на больших списках. Возможно можно реализовать подстановку LS_COLORS и быстрее.

    zstyle ':completion:*' squeeze-slashes true # e.g. ls foo//bar -> ls foo/bar

Впихивает два слеша в один.

    [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}%%:*}#\[}%\]}) ||
    _ssh_hosts=()
    [[ -r ~/.ssh/config ]] && _ssh_config_hosts=($(sed -rn 's/host\s+(.+)/\1/ip' "$HOME/.ssh/config" | grep -v "\*" )) ||
    _ssh_config_hosts=()
    hosts=($HOST "$_ssh_hosts[@]" $_ssh_config_hosts[@] localhost)
    zstyle ':completion:*:hosts' hosts ${hosts}
        # highlight the original input.
        zstyle ':completion:*:original' list-colors "=*=$color[blue];$color[bold]"
        # colorize username completion
        zstyle ':completion:*:*:*:*:users' list-colors "=*=$color[blue];$color[bg-black]"

Быстрый и красивый, хотя страшно выглядещий, способ автокомплита ssh хостов.

    zstyle ':completion:*:wine:*'             file-patterns '*.(exe|EXE):exe'

wine автодополняет только exe файлы.

    # highlight parameters with uncommon names
    zstyle ':completion:*:parameters'         list-colors "=[^a-zA-Z]*=$color[cyan]"

Раскраска параметров в меню автодополнения циановым цветом

    # highlight aliases                      
    zstyle ':completion:*:aliases'            list-colors "=*=$color[green]"

А алиасов зеленым.

    ### highlight the original input.
    zstyle ':completion:*:original'           list-colors "=*=$color[blue];$color[bold]"

Комплит того, что было введено, без исправления ошибок, голубым цветом. Почти невероятная ситуация, на самом деле. будет в самом конце списка.

    ### highlight words like 'esac' or 'end'
    zstyle ':completion:*:reserved-words'     list-colors "=*=$color[blue]"

Зарезервированные слова подсвечиваются голубым цветом.

    ### colorize processlist for 'kill'
    zstyle ':completion:*:*:kill:*:processes' list-colors "=(#b) #([0-9]#) #([^ ]#)*=$color[cyan]=$color[yellow]=$color[green]"
    zstyle ':completion:*:kill:*' command 'ps -u $USER -o pid,%cpu,tty,cputime,cmd'

Умная и красивая автодополнялка для kill. Дополняет вывод по имени процесса и подсвечивает это дело голубеньким :D

    zstyle ':completion:*:*:zathura:*'        tag-order files
    zstyle ':completion:*:*:zathura:*'        file-patterns '*(/)|*.{pdf,djvu}'

Zathura это минималистичная читалка для pdf/djvu и всякого. Дополнять только по файлам, типа pdf,djvu и директории(для навигации).

    # make them a little less short, after all (mostly adds -l option to the whatis calll)
    zstyle ':completion:*:command-descriptions' command '_call_whatis -l -s 1 -r .\*; _call_whatis -l -s 6 -r .\* 2>/dev/null'

Задает то, что будет показано в описании команд

    zstyle ':completion:*:*:task:*'                verbose yes         # taskwarrior
    zstyle ':completion:*:*:task:*:descriptions'   format '%U%B%d%b%u' # taskwarrior
    zstyle ':completion:*:*:task:*'                group-name ''       # taskwarrior

Украшательства автокомплита для taskwarrior. Я его использую в качестве легкого псевдо-аналога emacs org-mode для управления своими тасками.

    # command completion: highlight matching part of command, and 
    zstyle -e ':completion:*:-command-:*:commands' list-colors 'reply=( '\''=(#b)('\''$words[CURRENT]'\''|)*-- #(*)=0=38;5;45=38;5;136'\'' '\''=(#b)('\''$words[CURRENT]'\''|)*=0=38;5;248'\'' )'

Подсвечивает белым цветом ту часть команды, которая уже была введена. Практического смысла большого нету, но мне нравится как это выглядит.

    # This is needed to workaround a bug in _setup:12, causing almost 2 seconds delay for bigger LS_COLORS
    # UPDATE: not sure if this is required anymore, with the -command- style above.. keeping it here just to be sure
    zstyle ':completion:*:*:-command-:*' list-colors ''
    # run rehash on completion so new installed program are found automatically:
    _force_rehash() {
        (( CURRENT == 1 )) && rehash
        return 1
    }
    ## correction
    setopt correct
    zstyle -e ':completion:*' completer '
        if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
            _last_try="$HISTNO$BUFFER$CURSOR"
            reply=(_complete _match _ignored _prefix _files)
        else
            if [[ $words[1] == (rm|mv) ]] ; then
                reply=(_complete _files)
            else
                reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
            fi
        fi'

    [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
                              zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
    # use generic completion system for programs not yet defined; (_gnu_generic works
    # with commands that provide a --help option with "standard" gnu-like output.)
    for compcom in cp deborphan df feh fetchipac head hnb ipacsum mv \
                   pal stow tail uname ; do
        [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
    done; unset compcom
    # see upgrade function in this file
    # compdef _hosts upgrade

() {
    local -a coreutils
    coreutils=(
        # /bin
        cat chgrp chmod chown cp date dd df dir ln ls mkdir mknod mv readlink
        rm rmdir vdir sleep stty sync touch uname mktemp
        # /usr/bin
        install hostid nice who users pinky stdbuf base64 basename chcon cksum
        comm csplit cut dircolors dirname du env expand factor fmt fold groups
        head id join link logname md5sum mkfifo nl nproc nohup od paste pathchk
        pr printenv ptx runcon seq sha1sum sha224sum sha256sum sha384sum
        sha512sum shred shuf sort split stat sum tac tail tee timeout tr
        truncate tsort tty unexpand uniq unlink wc whoami yes arch touch
    )

    for i in $coreutils; do
        # all which don't already have one
        # at time of this writing, those are:
        # /bin
        #   chgrp chmod chown cp date dd df ln ls mkdir rm rmdir stty sync
        #   touch uname
        # /usr/bin
        #   nice comm cut du env groups id join logname md5sum nohup printenv
        #   sort stat unexpand uniq whoami
        (( $+_comps[$i] )) || compdef _gnu_generic $i 
    done

}

Какие-то опции, связанные с кешированием, rehash и тп, смысла которых я не помню. Также задается автоматическое выдирание автокомплита опций для команд gnu по списку cp deborphan df feh …

# Load completion from bash, which isn't available in zsh yet.
bash_completions=()
if [ -n "$commands[vzctl]" ] ; then
  bash_completions+=(/etc/bash_completion.d/vzctl.sh)
fi
if (( $#bash_completions )); then
  if ! which complete &>/dev/null; then
    autoload -Uz bashcompinit
    if which bashcompinit &>/dev/null; then
      bashcompinit
    fi
  fi
  bash_source /etc/bash_completion.d/vzctl.sh
fi

Загрузка автокомплита из bash-completions.

expand-or-complete-with-dots() {
    echo -n "\e[31m......\e[0m"
    zle expand-or-complete
    zle redisplay
}
zle -N expand-or-complete-with-dots

function expand-or-complete-with-dots() {
    echo -n "\e[36m-=--...--=-\e[0m"
    zle expand-or-complete
    zle redisplay
}
zle -N expand-or-complete-with-dots
bindkey "^I" expand-or-complete-with-dots

При нажатии на tab показывает три точки. Это просто украшательство, которое будет работать в случае долгого ответа системы автокомплита, например это возможно при обращении к удаленному ресурсу. Почему-то работает лично у меня только в linux-консоли, я особо не заморачивался почему, возможно из-за высокой скорости st/urxvt.

comments powered by Disqus