├── ftplugin └── zsh_complete.vim ├── plugin ├── capture.zsh └── zsh_completion.vim └── readme.md /ftplugin/zsh_complete.vim: -------------------------------------------------------------------------------- 1 | " zsh_complete.vim - Omni Completion for zsh 2 | " Maintainer: Valodim Skywalker 3 | " Last Updated: 03 Oct 2013 4 | 5 | set omnifunc=zsh_completion#Complete 6 | 7 | " vim: set et ts=4: 8 | -------------------------------------------------------------------------------- /plugin/capture.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | zmodload zsh/zpty || { echo 'error: missing module zsh/zpty' >&2; exit 1 } 4 | 5 | # spawn shell 6 | zpty z zsh -f -i 7 | 8 | # line buffer for pty output 9 | local line 10 | 11 | setopt rcquotes 12 | () { 13 | zpty -w z source $1 14 | repeat 4; do 15 | zpty -r z line 16 | [[ $line == ok* ]] && return 17 | done 18 | echo 'error initializing.' >&2 19 | exit 2 20 | } =( <<< ' 21 | # no prompt! 22 | PROMPT= 23 | 24 | # load completion system 25 | autoload compinit 26 | compinit -d ~/.zcompdump_capture 27 | 28 | # never run a command 29 | bindkey ''^M'' undefined 30 | bindkey ''^J'' undefined 31 | bindkey ''^I'' complete-word 32 | 33 | # send a line with null-byte at the end before and after completions are output 34 | null-line () { 35 | echo -E - $''\0'' 36 | } 37 | compprefuncs=( null-line ) 38 | comppostfuncs=( null-line exit ) 39 | 40 | # never group stuff! 41 | zstyle '':completion:*'' list-grouped false 42 | # don''t insert tab when attempting completion on empty line 43 | zstyle '':completion:*'' insert-tab false 44 | # no list separator, this saves some stripping later on 45 | zstyle '':completion:*'' list-separator '''' 46 | 47 | # we use zparseopts 48 | zmodload zsh/zutil 49 | 50 | # override compadd (this our hook) 51 | compadd () { 52 | 53 | # check if any of -O, -A or -D are given 54 | if [[ ${@[1,(i)(-|--)]} == *-(O|A|D)\ * ]]; then 55 | # if that is the case, just delegate and leave 56 | builtin compadd "$@" 57 | return $? 58 | fi 59 | 60 | # ok, this concerns us! 61 | # echo -E - got this: "$@" 62 | 63 | # be careful with namespacing here, we don''t want to mess with stuff that 64 | # should be passed to compadd! 65 | typeset -a __hits __dscr __tmp 66 | 67 | # do we have a description parameter? 68 | # note we don''t use zparseopts here because of combined option parameters 69 | # with arguments like -default- confuse it. 70 | if (( $@[(I)-d] )); then # kind of a hack, $+@[(r)-d] doesn''t work because of line noise overload 71 | # next param after -d 72 | __tmp=${@[$[${@[(i)-d]}+1]]} 73 | # description can be given as an array parameter name, or inline () array 74 | if [[ $__tmp == \(* ]]; then 75 | eval "__dscr=$__tmp" 76 | else 77 | __dscr=( "${(@P)__tmp}" ) 78 | fi 79 | fi 80 | 81 | # capture completions by injecting -A parameter into the compadd call. 82 | # this takes care of matching for us. 83 | builtin compadd -A __hits -D __dscr "$@" 84 | 85 | # JESUS CHRIST IT TOOK ME FOREVER TO FIGURE OUT THIS OPTION WAS SET AND WAS MESSING WITH MY SHIT HERE 86 | setopt localoptions norcexpandparam extendedglob 87 | 88 | # extract prefixes and suffixes from compadd call. we can''t do zsh''s cool 89 | # -r remove-func magic, but it''s better than nothing. 90 | typeset -A apre hpre hsuf asuf 91 | zparseopts -E P:=apre p:=hpre S:=asuf s:=hsuf 92 | 93 | # append / to directories? we are only emulating -f in a half-assed way 94 | # here, but it''s better than nothing. 95 | integer dirsuf=0 96 | # don''t be fooled by -default- >.> 97 | if [[ -z $hsuf && "${${@//-default-/}% -# *}" == *-[[:alnum:]]#f* ]]; then 98 | dirsuf=1 99 | fi 100 | 101 | # just drop 102 | [[ -n $__hits ]] || return 103 | 104 | # this is the point where we have all matches in $__hits and all 105 | # descriptions in $__dscr! 106 | 107 | # display all matches 108 | local dsuf dscr 109 | for i in {1..$#__hits}; do 110 | 111 | # add a dir suffix? 112 | (( dirsuf )) && [[ -d $__hits[$i] ]] && dsuf=/ || dsuf= 113 | # description to be displayed afterwards 114 | (( $#__dscr >= $i )) && dscr=" -- ${${__dscr[$i]}##$__hits[$i] #}" || dscr= 115 | 116 | echo -E - $IPREFIX$apre$hpre$__hits[$i]$dsuf$hsuf$asuf$dscr 117 | 118 | done 119 | 120 | } 121 | 122 | # signal success! 123 | echo ok') 124 | 125 | zpty -w z "$1"$'\t' 126 | 127 | integer tog=0 128 | # read from the pty, and parse linewise 129 | while zpty -r z; do :; done | while IFS= read -r line; do 130 | if [[ $line == *$'\0\r' ]]; then 131 | (( tog++ )) && return 0 || continue 132 | fi 133 | # display between toggles 134 | (( tog )) && echo -E - $line 135 | done 136 | 137 | return 2 138 | -------------------------------------------------------------------------------- /plugin/zsh_completion.vim: -------------------------------------------------------------------------------- 1 | " zsh_completion.vim - Omni Completion for zsh 2 | " Maintainer: Valodim Skywalker 3 | " Last Updated: 03 Oct 2013 4 | 5 | fun! zsh_completion#Complete(findstart, base) 6 | 7 | if a:findstart 8 | " locate the start of the word 9 | let l:line = getline('.') 10 | let l:pos = col('.') - 1 11 | while l:pos > 0 && l:line[l:pos - 1] =~ '\S' 12 | let l:pos -= 1 13 | endwhile 14 | 15 | " SAVE THE BASE OURSELVES 16 | " For some weird reason, if the base for completion is just '-', which 17 | " is the case fairly often in shell completion, the a:base argument we 18 | " get below is just '0'. I don't know why, it just does. So I'm saving 19 | " it here myself as a workaround. If anyone knows how to fix this or 20 | " what I'm doing wrong, I'd be happy to hear it. 21 | let s:base = l:line[l:pos :] 22 | 23 | return l:pos 24 | else 25 | 26 | let l:srcfile = globpath(&rtp, 'plugin/capture.zsh') 27 | if len(l:srcfile) == 0 28 | return -1 29 | endif 30 | 31 | let s:out = system(l:srcfile . ' ' . shellescape(getline(".") . s:base) . ' ' . (col('.')+strlen(s:base)-1)) 32 | let l:result = [] 33 | for item in split(s:out, '\r\n') 34 | let l:pieces = split(item, ' -- ') 35 | if len(l:pieces) > 1 36 | call add(l:result, { 'word': l:pieces[0], 'menu': l:pieces[1] }) 37 | else 38 | call add(l:result, { 'word': l:pieces[0] }) 39 | endif 40 | endfor 41 | return {'words': l:result, 'refresh': 'always'} 42 | 43 | endif 44 | endfun 45 | 46 | " vim: set et ts=4: 47 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # vim-zsh-completion 2 | 3 | This is a vim omnicompletion which captures completions from zsh's completion 4 | engine. This is an application of 5 | [this](https://github.com/Valodim/zsh-capture-completion) zsh completion 6 | capturing method. 7 | 8 | ## Demo 9 | 10 | ![demo](http://mugenguild.com/~valodim/vim-zsh-completion.gif) 11 | 12 | ## Status 13 | 14 | The script works reasonably well for most cases I tested. 15 | 16 | While it does work reasonably well, the way completion results are gathered 17 | from zsh is a HUGE HACK, so don't be too surprised with inexplicable behavior. 18 | 19 | ## Installation 20 | 21 | Install using [vundle](https://github.com/gmarik/vundle): 22 | 23 | Bundle 'Valodim/vim-zsh-completion' 24 | BundleInstall 25 | 26 | The script is set as omnicompletion (^X^O) for zsh files automatically. It 27 | plays well with YouCompleteMe from what I have seen, although it needs to be 28 | manually triggered like most semantic completions. 29 | 30 | You can also bind it to user completion (^X^U) for use outside of zsh script 31 | files using: 32 | 33 | :set completefunc=zsh_completion#Complete 34 | --------------------------------------------------------------------------------