tool.vim 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. " From "go list -h".
  2. function! go#tool#ValidFiles(...)
  3. let l:list = ["GoFiles", "CgoFiles", "IgnoredGoFiles", "CFiles", "CXXFiles",
  4. \ "MFiles", "HFiles", "FFiles", "SFiles", "SwigFiles", "SwigCXXFiles",
  5. \ "SysoFiles", "TestGoFiles", "XTestGoFiles"]
  6. " Used as completion
  7. if len(a:000) > 0
  8. let l:list = filter(l:list, 'strpart(v:val, 0, len(a:1)) == a:1')
  9. endif
  10. return l:list
  11. endfunction
  12. function! go#tool#Files(...) abort
  13. if len(a:000) > 0
  14. let source_files = a:000
  15. else
  16. let source_files = ['GoFiles']
  17. endif
  18. let combined = ''
  19. for sf in source_files
  20. " Strip dot in case people used ":GoFiles .GoFiles".
  21. let sf = substitute(sf, '^\.', '', '')
  22. " Make sure the passed options are valid.
  23. if index(go#tool#ValidFiles(), sf) == -1
  24. echoerr "unknown source file variable: " . sf
  25. endif
  26. if go#util#IsWin()
  27. let combined .= '{{range $f := .' . sf . '}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}\{{$f}}{{printf \"\n\"}}{{end}}'
  28. else
  29. let combined .= "{{range $f := ." . sf . "}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}{{range $f := .CgoFiles}}{{$.Dir}}/{{$f}}{{printf \"\\n\"}}{{end}}"
  30. endif
  31. endfor
  32. let out = go#tool#ExecuteInDir('go list -f ' . shellescape(combined))
  33. return split(out, '\n')
  34. endfunction
  35. function! go#tool#Deps() abort
  36. if go#util#IsWin()
  37. let format = '{{range $f := .Deps}}{{$f}}{{printf \"\n\"}}{{end}}'
  38. else
  39. let format = "{{range $f := .Deps}}{{$f}}\n{{end}}"
  40. endif
  41. let command = 'go list -f '.shellescape(format)
  42. let out = go#tool#ExecuteInDir(command)
  43. return split(out, '\n')
  44. endfunction
  45. function! go#tool#Imports() abort
  46. let imports = {}
  47. if go#util#IsWin()
  48. let format = '{{range $f := .Imports}}{{$f}}{{printf \"\n\"}}{{end}}'
  49. else
  50. let format = "{{range $f := .Imports}}{{$f}}{{printf \"\\n\"}}{{end}}"
  51. endif
  52. let command = 'go list -f '.shellescape(format)
  53. let out = go#tool#ExecuteInDir(command)
  54. if go#util#ShellError() != 0
  55. echo out
  56. return imports
  57. endif
  58. for package_path in split(out, '\n')
  59. let cmd = "go list -f '{{.Name}}' " . shellescape(package_path)
  60. let package_name = substitute(go#tool#ExecuteInDir(cmd), '\n$', '', '')
  61. let imports[package_name] = package_path
  62. endfor
  63. return imports
  64. endfunction
  65. function! go#tool#Info(auto) abort
  66. let l:mode = get(g:, 'go_info_mode', 'gocode')
  67. if l:mode == 'gocode'
  68. call go#complete#Info(a:auto)
  69. elseif l:mode == 'guru'
  70. call go#guru#DescribeInfo()
  71. else
  72. call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [gocode, guru]')
  73. endif
  74. endfunction
  75. function! go#tool#PackageName() abort
  76. let command = "go list -f \"{{.Name}}\""
  77. let out = go#tool#ExecuteInDir(command)
  78. if go#util#ShellError() != 0
  79. return -1
  80. endif
  81. return split(out, '\n')[0]
  82. endfunction
  83. function! go#tool#ParseErrors(lines) abort
  84. let errors = []
  85. for line in a:lines
  86. let fatalerrors = matchlist(line, '^\(fatal error:.*\)$')
  87. let tokens = matchlist(line, '^\s*\(.\{-}\):\(\d\+\):\s*\(.*\)')
  88. if !empty(fatalerrors)
  89. call add(errors, {"text": fatalerrors[1]})
  90. elseif !empty(tokens)
  91. " strip endlines of form ^M
  92. let out = substitute(tokens[3], '\r$', '', '')
  93. call add(errors, {
  94. \ "filename" : fnamemodify(tokens[1], ':p'),
  95. \ "lnum" : tokens[2],
  96. \ "text" : out,
  97. \ })
  98. elseif !empty(errors)
  99. " Preserve indented lines.
  100. " This comes up especially with multi-line test output.
  101. if match(line, '^\s') >= 0
  102. call add(errors, {"text": line})
  103. endif
  104. endif
  105. endfor
  106. return errors
  107. endfunction
  108. "FilterValids filters the given items with only items that have a valid
  109. "filename. Any non valid filename is filtered out.
  110. function! go#tool#FilterValids(items) abort
  111. " Remove any nonvalid filename from the location list to avoid opening an
  112. " empty buffer. See https://github.com/fatih/vim-go/issues/287 for
  113. " details.
  114. let filtered = []
  115. let is_readable = {}
  116. for item in a:items
  117. if has_key(item, 'bufnr')
  118. let filename = bufname(item.bufnr)
  119. elseif has_key(item, 'filename')
  120. let filename = item.filename
  121. else
  122. " nothing to do, add item back to the list
  123. call add(filtered, item)
  124. continue
  125. endif
  126. if !has_key(is_readable, filename)
  127. let is_readable[filename] = filereadable(filename)
  128. endif
  129. if is_readable[filename]
  130. call add(filtered, item)
  131. endif
  132. endfor
  133. for k in keys(filter(is_readable, '!v:val'))
  134. echo "vim-go: " | echohl Identifier | echon "[run] Dropped " | echohl Constant | echon '"' . k . '"'
  135. echohl Identifier | echon " from location list (nonvalid filename)" | echohl None
  136. endfor
  137. return filtered
  138. endfunction
  139. function! go#tool#ExecuteInDir(cmd) abort
  140. " Verify that the directory actually exists. If the directory does not
  141. " exist, then assume that the a:cmd should not be executed. Callers expect
  142. " to check v:shell_error (via go#util#ShellError()), so execute a command
  143. " that will return an error as if a:cmd was run and exited with an error.
  144. " This helps avoid errors when working with plugins that use virtual files
  145. " that don't actually exist on the file system (e.g. vim-fugitive's
  146. " GitDiff).
  147. if !isdirectory(expand("%:p:h"))
  148. let [out, err] = go#util#Exec(["false"])
  149. return ''
  150. endif
  151. let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
  152. let dir = getcwd()
  153. try
  154. execute cd . fnameescape(expand("%:p:h"))
  155. let out = go#util#System(a:cmd)
  156. finally
  157. execute cd . fnameescape(dir)
  158. endtry
  159. return out
  160. endfunction
  161. " Exists checks whether the given importpath exists or not. It returns 0 if
  162. " the importpath exists under GOPATH.
  163. function! go#tool#Exists(importpath) abort
  164. let command = "go list ". a:importpath
  165. let out = go#tool#ExecuteInDir(command)
  166. if go#util#ShellError() != 0
  167. return -1
  168. endif
  169. return 0
  170. endfunction
  171. " following two functions are from: https://github.com/mattn/gist-vim
  172. " thanks @mattn
  173. function! s:get_browser_command() abort
  174. let go_play_browser_command = get(g:, 'go_play_browser_command', '')
  175. if go_play_browser_command == ''
  176. if go#util#IsWin()
  177. let go_play_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%'
  178. elseif go#util#IsMac()
  179. let go_play_browser_command = 'open %URL%'
  180. elseif executable('xdg-open')
  181. let go_play_browser_command = 'xdg-open %URL%'
  182. elseif executable('firefox')
  183. let go_play_browser_command = 'firefox %URL% &'
  184. elseif executable('chromium')
  185. let go_play_browser_command = 'chromium %URL% &'
  186. else
  187. let go_play_browser_command = ''
  188. endif
  189. endif
  190. return go_play_browser_command
  191. endfunction
  192. function! go#tool#OpenBrowser(url) abort
  193. let cmd = s:get_browser_command()
  194. if len(cmd) == 0
  195. redraw
  196. echohl WarningMsg
  197. echo "It seems that you don't have general web browser. Open URL below."
  198. echohl None
  199. echo a:url
  200. return
  201. endif
  202. if cmd =~ '^!'
  203. let cmd = substitute(cmd, '%URL%', '\=escape(shellescape(a:url),"#")', 'g')
  204. silent! exec cmd
  205. elseif cmd =~ '^:[A-Z]'
  206. let cmd = substitute(cmd, '%URL%', '\=escape(a:url,"#")', 'g')
  207. exec cmd
  208. else
  209. let cmd = substitute(cmd, '%URL%', '\=shellescape(a:url)', 'g')
  210. call go#util#System(cmd)
  211. endif
  212. endfunction
  213. " vim: sw=2 ts=2 et