impl.vim 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. function! go#impl#Impl(...) abort
  2. let recv = ""
  3. let iface = ""
  4. let interactive = 0
  5. let pos = getpos('.')
  6. if a:0 is 0
  7. " Interactive mode if user didn't pass any arguments.
  8. let recv = s:getReceiver()
  9. let iface = input("vim-go: generating method stubs for interface: ")
  10. redraw!
  11. if empty(iface)
  12. call go#util#EchoError('usage: interface type is not provided')
  13. return
  14. endif
  15. elseif a:0 is 1
  16. " we assume the user only passed the interface type,
  17. " i.e: ':GoImpl io.Writer'
  18. let recv = s:getReceiver()
  19. let iface = a:1
  20. elseif a:0 > 2
  21. " user passed receiver and interface type both,
  22. " i.e: 'GoImpl f *Foo io.Writer'
  23. let recv = join(a:000[:-2], ' ')
  24. let iface = a:000[-1]
  25. else
  26. call go#util#EchoError('usage: GoImpl {receiver} {interface}')
  27. return
  28. endif
  29. " Make sure we put the generated code *after* the struct.
  30. if getline(".") =~ "struct "
  31. normal! $%
  32. endif
  33. try
  34. let dirname = fnameescape(expand('%:p:h'))
  35. let [result, err] = go#util#Exec(['impl', '-dir', dirname, recv, iface])
  36. let result = substitute(result, "\n*$", "", "")
  37. if err
  38. call go#util#EchoError(result)
  39. return
  40. endif
  41. if result is# ''
  42. return
  43. end
  44. put =''
  45. silent put =result
  46. finally
  47. call setpos('.', pos)
  48. endtry
  49. endfunction
  50. function! s:getReceiver()
  51. let receiveType = expand("<cword>")
  52. if receiveType == "type"
  53. normal! w
  54. let receiveType = expand("<cword>")
  55. elseif receiveType == "struct"
  56. normal! ge
  57. let receiveType = expand("<cword>")
  58. endif
  59. return printf("%s *%s", tolower(receiveType)[0], receiveType)
  60. endfunction
  61. if exists('*uniq')
  62. function! s:uniq(list)
  63. return uniq(a:list)
  64. endfunction
  65. else
  66. " Note: Believe that the list is sorted
  67. function! s:uniq(list)
  68. let i = len(a:list) - 1
  69. while 0 < i
  70. if a:list[i-1] ==# a:list[i]
  71. call remove(a:list, i)
  72. let i -= 2
  73. else
  74. let i -= 1
  75. endif
  76. endwhile
  77. return a:list
  78. endfunction
  79. endif
  80. function! s:root_dirs() abort
  81. let dirs = []
  82. let root = go#util#env("goroot")
  83. if root !=# '' && isdirectory(root)
  84. call add(dirs, root)
  85. endif
  86. let paths = map(split(go#util#env("gopath"), go#util#PathListSep()), "substitute(v:val, '\\\\', '/', 'g')")
  87. if !empty(filter(paths, 'isdirectory(v:val)'))
  88. call extend(dirs, paths)
  89. endif
  90. return dirs
  91. endfunction
  92. function! s:go_packages(dirs) abort
  93. let pkgs = []
  94. for d in a:dirs
  95. let pkg_root = expand(d . '/pkg/' . go#util#osarch())
  96. call extend(pkgs, split(globpath(pkg_root, '**/*.a', 1), "\n"))
  97. endfor
  98. return map(pkgs, "fnamemodify(v:val, ':t:r')")
  99. endfunction
  100. function! s:interface_list(pkg) abort
  101. let [contents, err] = go#util#Exec(['go', 'doc', a:pkg])
  102. if err
  103. return []
  104. endif
  105. let contents = split(contents, "\n")
  106. call filter(contents, 'v:val =~# ''^type\s\+\h\w*\s\+interface''')
  107. return map(contents, 'a:pkg . "." . matchstr(v:val, ''^type\s\+\zs\h\w*\ze\s\+interface'')')
  108. endfunction
  109. " Complete package and interface for {interface}
  110. function! go#impl#Complete(arglead, cmdline, cursorpos) abort
  111. let words = split(a:cmdline, '\s\+', 1)
  112. if words[-1] ==# ''
  113. return s:uniq(sort(s:go_packages(s:root_dirs())))
  114. elseif words[-1] =~# '^\h\w*$'
  115. return s:uniq(sort(filter(s:go_packages(s:root_dirs()), 'stridx(v:val, words[-1]) == 0')))
  116. elseif words[-1] =~# '^\h\w*\.\%(\h\w*\)\=$'
  117. let [pkg, interface] = split(words[-1], '\.', 1)
  118. echomsg pkg
  119. return s:uniq(sort(filter(s:interface_list(pkg), 'v:val =~? words[-1]')))
  120. else
  121. return []
  122. endif
  123. endfunction
  124. " vim: sw=2 ts=2 et