import.vim 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. " Copyright 2011 The Go Authors. All rights reserved.
  2. " Use of this source code is governed by a BSD-style
  3. " license that can be found in the LICENSE file.
  4. "
  5. " Check out the docs for more information at /doc/vim-go.txt
  6. "
  7. function! go#import#SwitchImport(enabled, localname, path, bang) abort
  8. let view = winsaveview()
  9. let path = substitute(a:path, '^\s*\(.\{-}\)\s*$', '\1', '')
  10. " Quotes are not necessary, so remove them if provided.
  11. if path[0] == '"'
  12. let path = strpart(path, 1)
  13. endif
  14. if path[len(path)-1] == '"'
  15. let path = strpart(path, 0, len(path) - 1)
  16. endif
  17. " if given a trailing slash, eg. `github.com/user/pkg/`, remove it
  18. if path[len(path)-1] == '/'
  19. let path = strpart(path, 0, len(path) - 1)
  20. endif
  21. if path == ''
  22. call s:Error('Import path not provided')
  23. return
  24. endif
  25. if a:bang == "!"
  26. let out = go#util#System("go get -u -v ".shellescape(path))
  27. if go#util#ShellError() != 0
  28. call s:Error("Can't find import: " . path . ":" . out)
  29. endif
  30. endif
  31. let exists = go#tool#Exists(path)
  32. if exists == -1
  33. call s:Error("Can't find import: " . path)
  34. return
  35. endif
  36. " Extract any site prefix (e.g. github.com/).
  37. " If other imports with the same prefix are grouped separately,
  38. " we will add this new import with them.
  39. " Only up to and including the first slash is used.
  40. let siteprefix = matchstr(path, "^[^/]*/")
  41. let qpath = '"' . path . '"'
  42. if a:localname != ''
  43. let qlocalpath = a:localname . ' ' . qpath
  44. else
  45. let qlocalpath = qpath
  46. endif
  47. let indentstr = 0
  48. let packageline = -1 " Position of package name statement
  49. let appendline = -1 " Position to introduce new import
  50. let deleteline = -1 " Position of line with existing import
  51. let linesdelta = 0 " Lines added/removed
  52. " Find proper place to add/remove import.
  53. let line = 0
  54. while line <= line('$')
  55. let linestr = getline(line)
  56. if linestr =~# '^package\s'
  57. let packageline = line
  58. let appendline = line
  59. elseif linestr =~# '^import\s\+('
  60. let appendstr = qlocalpath
  61. let indentstr = 1
  62. let appendline = line
  63. let firstblank = -1
  64. let lastprefix = ""
  65. while line <= line("$")
  66. let line = line + 1
  67. let linestr = getline(line)
  68. let m = matchlist(getline(line), '^\()\|\(\s\+\)\(\S*\s*\)"\(.\+\)"\)')
  69. if empty(m)
  70. if siteprefix == "" && a:enabled
  71. " must be in the first group
  72. break
  73. endif
  74. " record this position, but keep looking
  75. if firstblank < 0
  76. let firstblank = line
  77. endif
  78. continue
  79. endif
  80. if m[1] == ')'
  81. " if there's no match, add it to the first group
  82. if appendline < 0 && firstblank >= 0
  83. let appendline = firstblank
  84. endif
  85. break
  86. endif
  87. let lastprefix = matchstr(m[4], "^[^/]*/")
  88. if a:localname != '' && m[3] != ''
  89. let qlocalpath = printf('%-' . (len(m[3])-1) . 's %s', a:localname, qpath)
  90. endif
  91. let appendstr = m[2] . qlocalpath
  92. let indentstr = 0
  93. if m[4] == path
  94. let appendline = -1
  95. let deleteline = line
  96. break
  97. elseif m[4] < path
  98. " don't set candidate position if we have a site prefix,
  99. " we've passed a blank line, and this doesn't share the same
  100. " site prefix.
  101. if siteprefix == "" || firstblank < 0 || match(m[4], "^" . siteprefix) >= 0
  102. let appendline = line
  103. endif
  104. elseif siteprefix != "" && match(m[4], "^" . siteprefix) >= 0
  105. " first entry of site group
  106. let appendline = line - 1
  107. break
  108. endif
  109. endwhile
  110. break
  111. elseif linestr =~# '^import '
  112. if appendline == packageline
  113. let appendstr = 'import ' . qlocalpath
  114. let appendline = line - 1
  115. endif
  116. let m = matchlist(linestr, '^import\(\s\+\)\(\S*\s*\)"\(.\+\)"')
  117. if !empty(m)
  118. if m[3] == path
  119. let appendline = -1
  120. let deleteline = line
  121. break
  122. endif
  123. if m[3] < path
  124. let appendline = line
  125. endif
  126. if a:localname != '' && m[2] != ''
  127. let qlocalpath = printf("%s %" . len(m[2])-1 . "s", a:localname, qpath)
  128. endif
  129. let appendstr = 'import' . m[1] . qlocalpath
  130. endif
  131. elseif linestr =~# '^\(var\|const\|type\|func\)\>'
  132. break
  133. endif
  134. let line = line + 1
  135. endwhile
  136. " Append or remove the package import, as requested.
  137. if a:enabled
  138. if deleteline != -1
  139. call s:Error(qpath . ' already being imported')
  140. elseif appendline == -1
  141. call s:Error('No package line found')
  142. else
  143. if appendline == packageline
  144. call append(appendline + 0, '')
  145. call append(appendline + 1, 'import (')
  146. call append(appendline + 2, ')')
  147. let appendline += 2
  148. let linesdelta += 3
  149. let appendstr = qlocalpath
  150. let indentstr = 1
  151. endif
  152. call append(appendline, appendstr)
  153. execute appendline + 1
  154. if indentstr
  155. execute 'normal! >>'
  156. endif
  157. let linesdelta += 1
  158. endif
  159. else
  160. if deleteline == -1
  161. call s:Error(qpath . ' not being imported')
  162. else
  163. execute deleteline . 'd'
  164. let linesdelta -= 1
  165. if getline(deleteline-1) =~# '^import\s\+(' && getline(deleteline) =~# '^)'
  166. " Delete empty import block
  167. let deleteline -= 1
  168. execute deleteline . "d"
  169. execute deleteline . "d"
  170. let linesdelta -= 2
  171. endif
  172. if getline(deleteline) == '' && getline(deleteline - 1) == ''
  173. " Delete spacing for removed line too.
  174. execute deleteline . "d"
  175. let linesdelta -= 1
  176. endif
  177. endif
  178. endif
  179. " Adjust view for any changes.
  180. let view.lnum += linesdelta
  181. let view.topline += linesdelta
  182. if view.topline < 0
  183. let view.topline = 0
  184. endif
  185. " Put buffer back where it was.
  186. call winrestview(view)
  187. endfunction
  188. function! s:Error(s) abort
  189. echohl Error | echo a:s | echohl None
  190. endfunction
  191. " vim: sw=2 ts=2 et