rename.vim 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. if !exists("g:go_gorename_bin")
  2. let g:go_gorename_bin = "gorename"
  3. endif
  4. " Set the default value. A value of "1" is a shortcut for this, for
  5. " compatibility reasons.
  6. function! s:default() abort
  7. if !exists("g:go_gorename_prefill") || g:go_gorename_prefill == 1
  8. let g:go_gorename_prefill = 'expand("<cword>") =~# "^[A-Z]"' .
  9. \ '? go#util#pascalcase(expand("<cword>"))' .
  10. \ ': go#util#camelcase(expand("<cword>"))'
  11. endif
  12. endfunction
  13. call s:default()
  14. function! go#rename#Rename(bang, ...) abort
  15. call s:default()
  16. let to_identifier = ""
  17. if a:0 == 0
  18. let ask = printf("vim-go: rename '%s' to: ", expand("<cword>"))
  19. if g:go_gorename_prefill != ''
  20. let to_identifier = input(ask, eval(g:go_gorename_prefill))
  21. else
  22. let to_identifier = input(ask)
  23. endif
  24. redraw!
  25. if empty(to_identifier)
  26. return
  27. endif
  28. else
  29. let to_identifier = a:1
  30. endif
  31. " return with a warning if the bin doesn't exist
  32. let bin_path = go#path#CheckBinPath(g:go_gorename_bin)
  33. if empty(bin_path)
  34. return
  35. endif
  36. let fname = expand('%:p')
  37. let pos = go#util#OffsetCursor()
  38. let offset = printf('%s:#%d', fname, pos)
  39. " no need to escape for job call
  40. let bin_path = go#util#has_job() ? bin_path : shellescape(bin_path)
  41. let offset = go#util#has_job() ? offset : shellescape(offset)
  42. let to_identifier = go#util#has_job() ? to_identifier : shellescape(to_identifier)
  43. let cmd = [bin_path, "-offset", offset, "-to", to_identifier]
  44. " check for any tags
  45. if exists('g:go_build_tags')
  46. let tags = get(g:, 'go_build_tags')
  47. call extend(cmd, ["-tags", tags])
  48. endif
  49. if go#util#has_job()
  50. call go#util#EchoProgress(printf("renaming to '%s' ...", to_identifier))
  51. call s:rename_job({
  52. \ 'cmd': cmd,
  53. \ 'bang': a:bang,
  54. \})
  55. return
  56. endif
  57. let command = join(cmd, " ")
  58. let out = go#tool#ExecuteInDir(command)
  59. let splitted = split(out, '\n')
  60. call s:parse_errors(go#util#ShellError(), a:bang, splitted)
  61. endfunction
  62. function s:rename_job(args)
  63. let state = {
  64. \ 'exited': 0,
  65. \ 'closed': 0,
  66. \ 'exitval': 0,
  67. \ 'messages': [],
  68. \ 'status_dir': expand('%:p:h'),
  69. \ 'bang': a:args.bang
  70. \ }
  71. function! s:callback(chan, msg) dict
  72. call add(self.messages, a:msg)
  73. endfunction
  74. function! s:exit_cb(job, exitval) dict
  75. let self.exited = 1
  76. let self.exitval = a:exitval
  77. let status = {
  78. \ 'desc': 'last status',
  79. \ 'type': "gorename",
  80. \ 'state': "finished",
  81. \ }
  82. if a:exitval
  83. let status.state = "failed"
  84. endif
  85. call go#statusline#Update(self.status_dir, status)
  86. if self.closed
  87. call s:parse_errors(self.exitval, self.bang, self.messages)
  88. endif
  89. endfunction
  90. function! s:close_cb(ch) dict
  91. let self.closed = 1
  92. if self.exited
  93. call s:parse_errors(self.exitval, self.bang, self.messages)
  94. endif
  95. endfunction
  96. " explicitly bind the callbacks to state so that self within them always
  97. " refers to state. See :help Partial for more information.
  98. let start_options = {
  99. \ 'callback': funcref("s:callback", [], state),
  100. \ 'exit_cb': funcref("s:exit_cb", [], state),
  101. \ 'close_cb': funcref("s:close_cb", [], state),
  102. \ }
  103. call go#statusline#Update(state.status_dir, {
  104. \ 'desc': "current status",
  105. \ 'type': "gorename",
  106. \ 'state': "started",
  107. \})
  108. call job_start(a:args.cmd, start_options)
  109. endfunction
  110. function s:parse_errors(exit_val, bang, out)
  111. " reload all files to reflect the new changes. We explicitly call
  112. " checktime to trigger a reload of all files. See
  113. " http://www.mail-archive.com/vim@vim.org/msg05900.html for more info
  114. " about the autoread bug
  115. let current_autoread = &autoread
  116. set autoread
  117. silent! checktime
  118. let &autoread = current_autoread
  119. let l:listtype = go#list#Type("GoRename")
  120. if a:exit_val != 0
  121. call go#util#EchoError("FAILED")
  122. let errors = go#tool#ParseErrors(a:out)
  123. call go#list#Populate(l:listtype, errors, 'Rename')
  124. call go#list#Window(l:listtype, len(errors))
  125. if !empty(errors) && !a:bang
  126. call go#list#JumpToFirst(l:listtype)
  127. elseif empty(errors)
  128. " failed to parse errors, output the original content
  129. call go#util#EchoError(a:out)
  130. endif
  131. return
  132. endif
  133. " strip out newline on the end that gorename puts. If we don't remove, it
  134. " will trigger the 'Hit ENTER to continue' prompt
  135. call go#list#Clean(l:listtype)
  136. call go#util#EchoSuccess(a:out[0])
  137. " refresh the buffer so we can see the new content
  138. " TODO(arslan): also find all other buffers and refresh them too. For this
  139. " we need a way to get the list of changes from gorename upon an success
  140. " change.
  141. silent execute ":e"
  142. endfunction
  143. " Commandline completion: original, unexported camelCase, and exported
  144. " CamelCase.
  145. function! go#rename#Complete(lead, cmdline, cursor)
  146. let l:word = expand('<cword>')
  147. return filter(uniq(sort(
  148. \ [l:word, go#util#camelcase(l:word), go#util#pascalcase(l:word)])),
  149. \ 'strpart(v:val, 0, len(a:lead)) == a:lead')
  150. endfunction
  151. " vim: sw=2 ts=2 et