doc.vim 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. let s:buf_nr = -1
  5. if !exists("g:go_doc_command")
  6. let g:go_doc_command = ["godoc"]
  7. endif
  8. function! go#doc#OpenBrowser(...) abort
  9. " check if we have gogetdoc as it gives us more and accurate information.
  10. " Only supported if we have json_decode as it's not worth to parse the plain
  11. " non-json output of gogetdoc
  12. let bin_path = go#path#CheckBinPath('gogetdoc')
  13. if !empty(bin_path) && exists('*json_decode')
  14. let json_out = s:gogetdoc(1)
  15. if go#util#ShellError() != 0
  16. call go#util#EchoError(json_out)
  17. return
  18. endif
  19. let out = json_decode(json_out)
  20. if type(out) != type({})
  21. call go#util#EchoError("gogetdoc output is malformed")
  22. endif
  23. let import = out["import"]
  24. let name = out["name"]
  25. let decl = out["decl"]
  26. let godoc_url = s:custom_godoc_url()
  27. let godoc_url .= "/" . import
  28. if decl !~ "^package"
  29. let godoc_url .= "#" . name
  30. endif
  31. echo godoc_url
  32. call go#tool#OpenBrowser(godoc_url)
  33. return
  34. endif
  35. let pkgs = s:godocWord(a:000)
  36. if empty(pkgs)
  37. return
  38. endif
  39. let pkg = pkgs[0]
  40. let exported_name = pkgs[1]
  41. " example url: https://godoc.org/github.com/fatih/set#Set
  42. let godoc_url = s:custom_godoc_url() . "/" . pkg . "#" . exported_name
  43. call go#tool#OpenBrowser(godoc_url)
  44. endfunction
  45. function! go#doc#Open(newmode, mode, ...) abort
  46. " With argument: run "godoc [arg]".
  47. if len(a:000)
  48. if empty(go#path#CheckBinPath(g:go_doc_command[0]))
  49. return
  50. endif
  51. let command = printf("%s %s", go#util#Shelljoin(g:go_doc_command), join(a:000, ' '))
  52. let out = go#util#System(command)
  53. " Without argument: run gogetdoc on cursor position.
  54. else
  55. let out = s:gogetdoc(0)
  56. if out == -1
  57. return
  58. endif
  59. endif
  60. if go#util#ShellError() != 0
  61. call go#util#EchoError(out)
  62. return
  63. endif
  64. call s:GodocView(a:newmode, a:mode, out)
  65. endfunction
  66. function! s:GodocView(newposition, position, content) abort
  67. " reuse existing buffer window if it exists otherwise create a new one
  68. let is_visible = bufexists(s:buf_nr) && bufwinnr(s:buf_nr) != -1
  69. if !bufexists(s:buf_nr)
  70. execute a:newposition
  71. sil file `="[Godoc]"`
  72. let s:buf_nr = bufnr('%')
  73. elseif bufwinnr(s:buf_nr) == -1
  74. execute a:position
  75. execute s:buf_nr . 'buffer'
  76. elseif bufwinnr(s:buf_nr) != bufwinnr('%')
  77. execute bufwinnr(s:buf_nr) . 'wincmd w'
  78. endif
  79. " if window was not visible then resize it
  80. if !is_visible
  81. if a:position == "split"
  82. " cap window height to 20, but resize it for smaller contents
  83. let max_height = get(g:, "go_doc_max_height", 20)
  84. let content_height = len(split(a:content, "\n"))
  85. if content_height > max_height
  86. exe 'resize ' . max_height
  87. else
  88. exe 'resize ' . content_height
  89. endif
  90. else
  91. " set a sane maximum width for vertical splits. In this case the minimum
  92. " that fits the godoc for package http without extra linebreaks and line
  93. " numbers on
  94. exe 'vertical resize 84'
  95. endif
  96. endif
  97. setlocal filetype=godoc
  98. setlocal bufhidden=delete
  99. setlocal buftype=nofile
  100. setlocal noswapfile
  101. setlocal nobuflisted
  102. setlocal nocursorline
  103. setlocal nocursorcolumn
  104. setlocal iskeyword+=:
  105. setlocal iskeyword-=-
  106. setlocal modifiable
  107. %delete _
  108. call append(0, split(a:content, "\n"))
  109. sil $delete _
  110. setlocal nomodifiable
  111. sil normal! gg
  112. " close easily with <esc> or enter
  113. noremap <buffer> <silent> <CR> :<C-U>close<CR>
  114. noremap <buffer> <silent> <Esc> :<C-U>close<CR>
  115. endfunction
  116. function! s:gogetdoc(json) abort
  117. " check if we have 'gogetdoc' and use it automatically
  118. let bin_path = go#path#CheckBinPath('gogetdoc')
  119. if empty(bin_path)
  120. return -1
  121. endif
  122. let cmd = [go#util#Shellescape(bin_path)]
  123. let offset = go#util#OffsetCursor()
  124. let fname = expand("%:p:gs!\\!/!")
  125. let pos = shellescape(fname.':#'.offset)
  126. let cmd += ["-pos", pos]
  127. if a:json
  128. let cmd += ["-json"]
  129. endif
  130. let command = join(cmd, " ")
  131. if &modified
  132. let command .= " -modified"
  133. let out = go#util#System(command, go#util#archive())
  134. else
  135. let out = go#util#System(command)
  136. endif
  137. return out
  138. endfunction
  139. " returns the package and exported name. exported name might be empty.
  140. " ie: fmt and Println
  141. " ie: github.com/fatih/set and New
  142. function! s:godocWord(args) abort
  143. if !executable('godoc')
  144. let msg = "godoc command not found."
  145. let msg .= " install with: go get golang.org/x/tools/cmd/godoc"
  146. call go#util#EchoWarning(msg)
  147. return []
  148. endif
  149. if !len(a:args)
  150. let oldiskeyword = &iskeyword
  151. setlocal iskeyword+=.
  152. let word = expand('<cword>')
  153. let &iskeyword = oldiskeyword
  154. let word = substitute(word, '[^a-zA-Z0-9\\/._~-]', '', 'g')
  155. let words = split(word, '\.\ze[^./]\+$')
  156. else
  157. let words = a:args
  158. endif
  159. if !len(words)
  160. return []
  161. endif
  162. let pkg = words[0]
  163. if len(words) == 1
  164. let exported_name = ""
  165. else
  166. let exported_name = words[1]
  167. endif
  168. let packages = go#tool#Imports()
  169. if has_key(packages, pkg)
  170. let pkg = packages[pkg]
  171. endif
  172. return [pkg, exported_name]
  173. endfunction
  174. function! s:custom_godoc_url() abort
  175. let godoc_url = get(g:, 'go_doc_url', 'https://godoc.org')
  176. if godoc_url isnot 'https://godoc.org'
  177. " strip last '/' character if available
  178. let last_char = strlen(godoc_url) - 1
  179. if godoc_url[last_char] == '/'
  180. let godoc_url = strpart(godoc_url, 0, last_char)
  181. endif
  182. " custom godoc installations expect /pkg before package names
  183. let godoc_url .= "/pkg"
  184. endif
  185. return godoc_url
  186. endfunction
  187. " vim: sw=2 ts=2 et