textobj.vim 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. if !exists("g:go_textobj_enabled")
  2. let g:go_textobj_enabled = 1
  3. endif
  4. if !exists("g:go_textobj_include_function_doc")
  5. let g:go_textobj_include_function_doc = 1
  6. endif
  7. if !exists("g:go_textobj_include_variable")
  8. let g:go_textobj_include_variable = 1
  9. endif
  10. " ( ) motions
  11. " { } motions
  12. " s for sentence
  13. " p for parapgrah
  14. " < >
  15. " t for tag
  16. function! go#textobj#Function(mode) abort
  17. let offset = go#util#OffsetCursor()
  18. let fname = shellescape(expand("%:p"))
  19. if &modified
  20. " Write current unsaved buffer to a temp file and use the modified content
  21. let l:tmpname = tempname()
  22. call writefile(go#util#GetLines(), l:tmpname)
  23. let fname = l:tmpname
  24. endif
  25. let bin_path = go#path#CheckBinPath('motion')
  26. if empty(bin_path)
  27. return
  28. endif
  29. let command = printf("%s -format vim -file %s -offset %s", bin_path, fname, offset)
  30. let command .= " -mode enclosing"
  31. if g:go_textobj_include_function_doc
  32. let command .= " -parse-comments"
  33. endif
  34. let out = go#util#System(command)
  35. if go#util#ShellError() != 0
  36. call go#util#EchoError(out)
  37. return
  38. endif
  39. " if exists, delete it as we don't need it anymore
  40. if exists("l:tmpname")
  41. call delete(l:tmpname)
  42. endif
  43. " convert our string dict representation into native Vim dictionary type
  44. let result = eval(out)
  45. if type(result) != 4 || !has_key(result, 'fn')
  46. return
  47. endif
  48. let info = result.fn
  49. if a:mode == 'a'
  50. " anonymous functions doesn't have associated doc. Also check if the user
  51. " want's to include doc comments for function declarations
  52. if has_key(info, 'doc') && g:go_textobj_include_function_doc
  53. call cursor(info.doc.line, info.doc.col)
  54. elseif info['sig']['name'] == '' && g:go_textobj_include_variable
  55. " one liner anonymous functions
  56. if info.lbrace.line == info.rbrace.line
  57. " jump to first nonblack char, to get the correct column
  58. call cursor(info.lbrace.line, 0 )
  59. normal! ^
  60. call cursor(info.func.line, col("."))
  61. else
  62. call cursor(info.func.line, info.rbrace.col)
  63. endif
  64. else
  65. call cursor(info.func.line, info.func.col)
  66. endif
  67. normal! v
  68. call cursor(info.rbrace.line, info.rbrace.col)
  69. return
  70. endif
  71. " rest is inner mode, a:mode == 'i'
  72. " if the function is a one liner we need to select only that portion
  73. if info.lbrace.line == info.rbrace.line
  74. call cursor(info.lbrace.line, info.lbrace.col+1)
  75. normal! v
  76. call cursor(info.rbrace.line, info.rbrace.col-1)
  77. return
  78. endif
  79. call cursor(info.lbrace.line+1, 1)
  80. normal! V
  81. call cursor(info.rbrace.line-1, 1)
  82. endfunction
  83. function! go#textobj#FunctionJump(mode, direction) abort
  84. " get count of the motion. This should be done before all the normal
  85. " expressions below as those reset this value(because they have zero
  86. " count!). We abstract -1 because the index starts from 0 in motion.
  87. let l:cnt = v:count1 - 1
  88. " set context mark so we can jump back with '' or ``
  89. normal! m'
  90. " select already previously selected visual content and continue from there.
  91. " If it's the first time starts with the visual mode. This is needed so
  92. " after selecting something in visual mode, every consecutive motion
  93. " continues.
  94. if a:mode == 'v'
  95. normal! gv
  96. endif
  97. let offset = go#util#OffsetCursor()
  98. let fname = shellescape(expand("%:p"))
  99. if &modified
  100. " Write current unsaved buffer to a temp file and use the modified content
  101. let l:tmpname = tempname()
  102. call writefile(go#util#GetLines(), l:tmpname)
  103. let fname = l:tmpname
  104. endif
  105. let bin_path = go#path#CheckBinPath('motion')
  106. if empty(bin_path)
  107. return
  108. endif
  109. let command = printf("%s -format vim -file %s -offset %s", bin_path, fname, offset)
  110. let command .= ' -shift ' . l:cnt
  111. if a:direction == 'next'
  112. let command .= ' -mode next'
  113. else " 'prev'
  114. let command .= ' -mode prev'
  115. endif
  116. if g:go_textobj_include_function_doc
  117. let command .= " -parse-comments"
  118. endif
  119. let out = go#util#System(command)
  120. if go#util#ShellError() != 0
  121. call go#util#EchoError(out)
  122. return
  123. endif
  124. " if exists, delete it as we don't need it anymore
  125. if exists("l:tmpname")
  126. call delete(l:tmpname)
  127. endif
  128. " convert our string dict representation into native Vim dictionary type
  129. let result = eval(out)
  130. if type(result) != 4 || !has_key(result, 'fn')
  131. return
  132. endif
  133. " we reached the end and there are no functions. The usual [[ or ]] jumps to
  134. " the top or bottom, we'll do the same.
  135. if type(result) == 4 && has_key(result, 'err') && result.err == "no functions found"
  136. if a:direction == 'next'
  137. keepjumps normal! G
  138. else " 'prev'
  139. keepjumps normal! gg
  140. endif
  141. return
  142. endif
  143. let info = result.fn
  144. " if we select something ,select all function
  145. if a:mode == 'v' && a:direction == 'next'
  146. keepjumps call cursor(info.rbrace.line, 1)
  147. return
  148. endif
  149. if a:mode == 'v' && a:direction == 'prev'
  150. if has_key(info, 'doc') && g:go_textobj_include_function_doc
  151. keepjumps call cursor(info.doc.line, 1)
  152. else
  153. keepjumps call cursor(info.func.line, 1)
  154. endif
  155. return
  156. endif
  157. keepjumps call cursor(info.func.line, 1)
  158. endfunction
  159. " vim: sw=2 ts=2 et