├── README.md ├── autoload └── goimpl.vim └── ftplugin └── go.vim /README.md: -------------------------------------------------------------------------------- 1 | Use [impl](https://github.com/josharian/impl) in Your Vim 2 | ========================================================= 3 | 4 | [impl](https://github.com/josharian/impl) is a very handy tool to generate method stubs for implementing an interface. 5 | This plugin is created to use [impl](https://github.com/josharian/impl) in your Vim. 6 | 7 | **NOTE:** This plugin is already integrated to [vim-go](https://github.com/fatih/vim-go). If you're using it, you don't need to install any additional plugins. 8 | 9 | ## Usage 10 | 11 | Simply do: 12 | 13 | ``` 14 | :GoImpl {receiver} {interface} 15 | ``` 16 | 17 | You can use completion for package name and interface name in `{interface}` 18 | 19 | For example: 20 | 21 | ``` 22 | :GoImpl f *File io.Reader 23 | ``` 24 | 25 | ``` 26 | :GoImpl f *Foo hash.Hash 27 | ``` 28 | 29 | You need not add single quotes around the receiver. 30 | 31 | Note that `:Impl` is also available. It is equivalent to `:GoImpl`. 32 | 33 | ## Requirements 34 | 35 | - `go` command 36 | - [impl](https://github.com/josharian/impl) command 37 | 38 | ## License 39 | 40 | The MIT License (MIT) 41 | 42 | Copyright (c) 2014-2015 rhysd 43 | 44 | Permission is hereby granted, free of charge, to any person obtaining a copy 45 | of this software and associated documentation files (the "Software"), to deal 46 | in the Software without restriction, including without limitation the rights 47 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 48 | copies of the Software, and to permit persons to whom the Software is 49 | furnished to do so, subject to the following conditions: 50 | 51 | The above copyright notice and this permission notice shall be included in 52 | all copies or substantial portions of the Software. 53 | 54 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 55 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 56 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 57 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 58 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 59 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 60 | THE SOFTWARE. 61 | -------------------------------------------------------------------------------- /autoload/goimpl.vim: -------------------------------------------------------------------------------- 1 | let s:save_cpo = &cpo 2 | set cpo&vim 3 | 4 | let g:goimpl#gocmd = get(g:, 'goimpl#gocmd', 'go') 5 | let g:goimpl#cmd = get(g:, 'goimpl#cmd', 'impl') 6 | let g:goimpl#godoccmd = get(g:, 'goimpl#godoccmd', 'godoc') 7 | 8 | function! s:bin_path() 9 | " check if our global custom path is set, if not check if $GOBIN is set so 10 | " we can use it, otherwise use $GOPATH + '/bin' 11 | if exists("g:go_bin_path") 12 | return g:go_bin_path 13 | elseif !empty($GOBIN) 14 | return $GOBIN 15 | elseif !empty($GOPATH) 16 | return $GOPATH . '/bin' 17 | endif 18 | 19 | return '' 20 | endfunction 21 | 22 | function! s:check_bin_path(binpath) 23 | let binpath = a:binpath 24 | if executable(binpath) 25 | return binpath 26 | endif 27 | 28 | " just get the basename 29 | let basename = fnamemodify(binpath, ":t") 30 | 31 | " check if we have an appropriate bin_path 32 | let go_bin_path = s:bin_path() 33 | if empty(go_bin_path) 34 | return '' 35 | endif 36 | 37 | let new_binpath = go_bin_path . '/' . basename 38 | if !executable(new_binpath) 39 | return '' 40 | endif 41 | 42 | return new_binpath 43 | endfunction 44 | 45 | 46 | function! s:error(msg) 47 | echohl ErrorMsg | echomsg a:msg | echohl None 48 | endfunction 49 | 50 | function! s:has_vimproc() 51 | if !exists('s:exists_vimproc') 52 | try 53 | silent call vimproc#version() 54 | let s:exists_vimproc = 1 55 | catch 56 | let s:exists_vimproc = 0 57 | endtry 58 | endif 59 | return s:exists_vimproc 60 | endfunction 61 | 62 | function! s:system(str, ...) 63 | let command = a:str 64 | let input = a:0 >= 1 ? a:1 : '' 65 | 66 | if a:0 == 0 67 | let output = s:has_vimproc() ? 68 | \ vimproc#system(command) : system(command) 69 | elseif a:0 == 1 70 | let output = s:has_vimproc() ? 71 | \ vimproc#system(command, input) : system(command, input) 72 | else 73 | " ignores 3rd argument unless you have vimproc. 74 | let output = s:has_vimproc() ? 75 | \ vimproc#system(command, input, a:2) : system(command, input) 76 | endif 77 | 78 | return output 79 | endfunction 80 | 81 | function! s:shell_error() 82 | return s:has_vimproc() ? vimproc#get_last_status() : v:shell_error 83 | endfunction 84 | 85 | function! s:chomp(str) 86 | return a:str[len(a:str)-1] ==# "\n" ? a:str[:len(a:str)-2] : a:str 87 | endfunction 88 | 89 | function! s:os_arch() 90 | let os = s:chomp(s:system(g:goimpl#gocmd . ' env GOOS')) 91 | if s:shell_error() 92 | return '' 93 | endif 94 | 95 | let arch = s:chomp(s:system(g:goimpl#gocmd . ' env GOARCH')) 96 | if s:shell_error() 97 | return '' 98 | endif 99 | 100 | return os . '_' . arch 101 | endfunction 102 | 103 | let g:goimpl#os_arch = get(g:, 'goimpl#os_arch', s:os_arch()) 104 | 105 | function! goimpl#impl(recv, iface) 106 | let binpath = s:check_bin_path(g:goimpl#cmd) 107 | if empty(binpath) 108 | call s:error(g:goimpl#cmd . ' command is not found. Please check g:goimpl#cmd') 109 | return '' 110 | endif 111 | 112 | let result = s:system(printf("%s '%s' '%s'", binpath, a:recv, a:iface)) 113 | 114 | if s:shell_error() 115 | call s:error(binpath . ' command failed: ' . result) 116 | return '' 117 | endif 118 | 119 | return result 120 | endfunction 121 | 122 | function! goimpl#do(...) 123 | if a:0 < 2 124 | call s:error('GoImpl {receiver} {interface}') 125 | return 126 | endif 127 | 128 | let recv = join(a:000[:-2], ' ') 129 | let iface = a:000[-1] 130 | let result = goimpl#impl(recv, iface) 131 | 132 | if result ==# '' 133 | return 134 | end 135 | 136 | let pos = getpos('.') 137 | put =result 138 | call setpos('.', pos) 139 | endfunction 140 | 141 | if exists('*uniq') 142 | function! s:uniq(list) 143 | return uniq(a:list) 144 | endfunction 145 | else 146 | " Note: Believe that the list is sorted 147 | function! s:uniq(list) 148 | let i = len(a:list) - 1 149 | while 0 < i 150 | if a:list[i-1] ==# a:list[i] 151 | call remove(a:list, i) 152 | let i -= 2 153 | else 154 | let i -= 1 155 | endif 156 | endwhile 157 | return a:list 158 | endfunction 159 | endif 160 | 161 | function! s:root_dirs() 162 | let dirs = [] 163 | 164 | let root = substitute(s:chomp(s:system(g:goimpl#gocmd . ' env GOROOT')), '\\', '/', 'g') 165 | if s:shell_error() 166 | return [] 167 | endif 168 | 169 | if root !=# '' && isdirectory(root) 170 | call add(dirs, root) 171 | endif 172 | 173 | let path_sep = has('win32') || has('win64') ? ';' : ':' 174 | let paths = map(split(s:chomp(s:system(g:goimpl#gocmd . ' env GOPATH')), path_sep), "substitute(v:val, '\\\\', '/', 'g')") 175 | if s:shell_error() 176 | return [] 177 | endif 178 | 179 | if !empty(filter(paths, 'isdirectory(v:val)')) 180 | call extend(dirs, paths) 181 | endif 182 | 183 | return dirs 184 | endfunction 185 | 186 | function! s:go_packages(dirs) 187 | let pkgs = [] 188 | for d in a:dirs 189 | let pkg_root = expand(d . '/pkg/' . s:os_arch()) 190 | call extend(pkgs, split(globpath(pkg_root, '**/*.a', 1), "\n")) 191 | endfor 192 | return map(pkgs, "fnamemodify(v:val, ':t:r')") 193 | endfunction 194 | 195 | function! s:interface_list(pkg) 196 | let contents = split(s:system(g:goimpl#godoccmd . ' ' . a:pkg), "\n") 197 | if s:shell_error() 198 | return [] 199 | endif 200 | 201 | call filter(contents, 'v:val =~# ''^type\s\+\h\w*\s\+interface''') 202 | return map(contents, 'a:pkg . "." . matchstr(v:val, ''^type\s\+\zs\h\w*\ze\s\+interface'')') 203 | endfunction 204 | 205 | " Complete package and interface for {interface} 206 | function! goimpl#complete(arglead, cmdline, cursorpos) 207 | if !executable(g:goimpl#godoccmd) 208 | return [] 209 | endif 210 | 211 | let words = split(a:cmdline, '\s\+', 1) 212 | if len(words) <= 3 213 | " TODO 214 | return [] 215 | endif 216 | 217 | if words[-1] ==# '' 218 | return s:uniq(sort(s:go_packages(s:root_dirs()))) 219 | elseif words[-1] =~# '^\h\w*$' 220 | return s:uniq(sort(filter(s:go_packages(s:root_dirs()), 'stridx(v:val, words[-1]) == 0'))) 221 | elseif words[-1] =~# '^\h\w*\.\%(\h\w*\)\=$' 222 | let [pkg, interface] = split(words[-1], '\.', 1) 223 | echomsg pkg 224 | return s:uniq(sort(filter(s:interface_list(pkg), 'v:val =~? words[-1]'))) 225 | else 226 | return [] 227 | endif 228 | endfunction 229 | 230 | let &cpo = s:save_cpo 231 | unlet s:save_cpo 232 | -------------------------------------------------------------------------------- /ftplugin/go.vim: -------------------------------------------------------------------------------- 1 | command! -nargs=+ -buffer -complete=customlist,goimpl#complete GoImpl call goimpl#do() 2 | command! -nargs=+ -buffer -complete=customlist,goimpl#complete Impl GoImpl 3 | --------------------------------------------------------------------------------