1
0

signature_help.test.vim 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. let s:timer_interval = 2000
  2. function! s:_ClearSigHelp()
  3. pythonx _sh_state = sh.UpdateSignatureHelp( _sh_state, {} )
  4. call assert_true( pyxeval( '_sh_state.popup_win_id is None' ),
  5. \ 'win id none with emtpy' )
  6. unlet! s:popup_win_id
  7. endfunction
  8. function s:_GetSigHelpWinID()
  9. call WaitForAssert( {->
  10. \ assert_true(
  11. \ pyxeval(
  12. \ 'ycm_state.SignatureHelpRequestReady()'
  13. \ ),
  14. \ 'sig help request reqdy'
  15. \ )
  16. \ } )
  17. call WaitForAssert( {->
  18. \ assert_true(
  19. \ pyxeval(
  20. \ 'ycm_state._signature_help_state.popup_win_id is not None'
  21. \ ),
  22. \ 'popup_win_id'
  23. \ )
  24. \ } )
  25. let s:popup_win_id = pyxeval( 'ycm_state._signature_help_state.popup_win_id' )
  26. return s:popup_win_id
  27. endfunction
  28. function! s:_CheckPopupPosition( winid, pos )
  29. redraw
  30. let actual_pos = popup_getpos( a:winid )
  31. let ret = 0
  32. if a:pos->empty()
  33. return assert_true( actual_pos->empty(), 'popup pos empty' )
  34. endif
  35. for c in keys( a:pos )
  36. if !has_key( actual_pos, c )
  37. let ret += 1
  38. call assert_report( 'popup with ID '
  39. \ . string( a:winid )
  40. \ . ' has no '
  41. \ . c
  42. \ . ' in: '
  43. \ . string( actual_pos ) )
  44. else
  45. let ret += assert_equal( a:pos[ c ],
  46. \ actual_pos[ c ],
  47. \ c . ' in: ' . string( actual_pos ) )
  48. endif
  49. endfor
  50. return ret
  51. endfunction
  52. function! s:_CheckSigHelpAtPos( sh, cursor, pos )
  53. call setpos( '.', [ 0 ] + a:cursor )
  54. redraw
  55. pythonx _sh_state = sh.UpdateSignatureHelp( _sh_state,
  56. \ vim.eval( 'a:sh' ) )
  57. redraw
  58. let winid = pyxeval( '_sh_state.popup_win_id' )
  59. call s:_CheckPopupPosition( winid, a:pos )
  60. endfunction
  61. function! SetUp()
  62. let g:ycm_use_clangd = 1
  63. let g:ycm_confirm_extra_conf = 0
  64. let g:ycm_auto_trigger = 1
  65. let g:ycm_keep_logfiles = 1
  66. let g:ycm_log_level = 'DEBUG'
  67. call youcompleteme#test#setup#SetUp()
  68. pythonx from ycm import signature_help as sh
  69. pythonx _sh_state = sh.SignatureHelpState()
  70. endfunction
  71. function! TearDown()
  72. call s:_ClearSigHelp()
  73. call youcompleteme#test#setup#CleanUp()
  74. endfunction
  75. " This is how we might do screen dump tests
  76. " function! Test_Compl()
  77. " let setup =<< trim END
  78. " edit ../third_party/ycmd/ycmd/tests/clangd/testdata/general_fallback/make_drink.cc
  79. " call setpos( '.', [ 0, 7, 27 ] )
  80. " END
  81. " call writefile( setup, 'Xtest_Compl' )
  82. " let vim = RunVimInTerminal( '-Nu vimrc -S Xtest_Compl', {} )
  83. "
  84. " function! Test() closure
  85. " " Wait for Vim to be ready
  86. " call term_sendkeys( vim, "cl:" )
  87. " call term_wait( vim )
  88. " call VerifyScreenDump( vim, "signature_help_Test_Compl_01", {} )
  89. " endfunction
  90. "
  91. " call WaitForAssert( {-> Test()} )
  92. "
  93. " " clean up
  94. " call StopVimInTerminal(vim)
  95. " call delete('XtestPopup')
  96. " %bwipeout!
  97. " endfunction
  98. function! Test_Enough_Screen_Space()
  99. call assert_true( &lines >= 25,
  100. \ &lines . " is not enough rows. need 25." )
  101. call assert_true( &columns >= 80,
  102. \ &columns . " is not enough columns. need 80." )
  103. endfunction
  104. function! Test_Signatures_After_Trigger()
  105. call youcompleteme#test#setup#OpenFile(
  106. \ '/test/testdata/vim/mixed_filetype.vim',
  107. \ { 'native_ft': 0 } )
  108. setf vim.python
  109. call setpos( '.', [ 0, 3, 17 ] )
  110. " Required to trigger TextChangedI
  111. " https://github.com/vim/vim/issues/4665#event-2480928194
  112. call test_override( 'char_avail', 1 )
  113. " Must do the checks in a timer callback because we need to stay in insert
  114. " mode until done. Use a func because it's big enough (a lambda is a little
  115. " neater in many contexts).
  116. function! Check( id ) closure
  117. call WaitForAssert( {->
  118. \ assert_true(
  119. \ pyxeval(
  120. \ 'ycm_state.SignatureHelpRequestReady()'
  121. \ ),
  122. \ 'sig help request ready'
  123. \ )
  124. \ } )
  125. call WaitForAssert( {->
  126. \ assert_true(
  127. \ pyxeval(
  128. \ "bool( ycm_state.GetSignatureHelpResponse()[ 'signatures' ] )"
  129. \ ),
  130. \ 'sig help request has signatures'
  131. \ )
  132. \ } )
  133. call WaitForAssert( {->
  134. \ assert_true(
  135. \ pyxeval(
  136. \ 'ycm_state._signature_help_state.popup_win_id is not None'
  137. \ ),
  138. \ 'popup_win_id'
  139. \ )
  140. \ } )
  141. let popup_win_id = pyxeval( 'ycm_state._signature_help_state.popup_win_id' )
  142. let pos = win_screenpos( popup_win_id )
  143. call assert_false( pos == [ 0, 0 ] )
  144. " Exit insert mode to ensure the test continues
  145. call test_override( 'ALL', 0 )
  146. call feedkeys( "\<ESC>" )
  147. endfunction
  148. call assert_false( pyxeval( 'ycm_state.SignatureHelpRequestReady()' ) )
  149. call timer_start( s:timer_interval, funcref( 'Check' ) )
  150. call feedkeys( 'cl(', 'ntx!' )
  151. call assert_false( pumvisible(), 'pumvisible()' )
  152. call WaitForAssert( {->
  153. \ assert_true(
  154. \ pyxeval(
  155. \ 'ycm_state._signature_help_state.popup_win_id is None'
  156. \ ),
  157. \ 'popup_win_id'
  158. \ )
  159. \ } )
  160. call test_override( 'ALL', 0 )
  161. %bwipeout!
  162. delfunc! Check
  163. endfunction
  164. function! Test_Signatures_With_PUM_NoSigns()
  165. call youcompleteme#test#setup#OpenFile(
  166. \ '/third_party/ycmd/ycmd/tests/clangd/testdata/general_fallback'
  167. \ . '/make_drink.cc', {} )
  168. " Make sure that error signs don't shift the window
  169. setlocal signcolumn=no
  170. call setpos( '.', [ 0, 7, 13 ] )
  171. " Required to trigger TextChangedI
  172. " https://github.com/vim/vim/issues/4665#event-2480928194
  173. call test_override( 'char_avail', 1 )
  174. function Check2( id ) closure
  175. call WaitForAssert( {-> assert_true( pumvisible() ) } )
  176. call WaitForAssert( {-> assert_notequal( [], complete_info().items ) } )
  177. call assert_equal( 7, pum_getpos().row )
  178. redraw
  179. " NOTE: anchor is 0-based
  180. call assert_equal( 6,
  181. \ pyxeval( 'ycm_state._signature_help_state.anchor[0]' ) )
  182. call assert_equal( 13,
  183. \ pyxeval( 'ycm_state._signature_help_state.anchor[1]' ) )
  184. " Popup is shifted due to 80 column screen
  185. call s:_CheckPopupPosition( s:_GetSigHelpWinID(),
  186. \ { 'line': 5, 'col': 5 } )
  187. call test_override( 'ALL', 0 )
  188. call feedkeys( "\<ESC>", 't' )
  189. endfunction
  190. " Must do the checks in a timer callback because we need to stay in insert
  191. " mode until done.
  192. function! Check( id ) closure
  193. call WaitForAssert( {->
  194. \ assert_true(
  195. \ pyxeval(
  196. \ 'ycm_state._signature_help_state.popup_win_id is not None'
  197. \ ),
  198. \ 'popup_win_id'
  199. \ )
  200. \ } )
  201. " Popup is shifted left due to 80 char screen
  202. call s:_CheckPopupPosition( s:_GetSigHelpWinID(),
  203. \ { 'line': 5, 'col': 5 } )
  204. call timer_start( s:timer_interval, funcref( 'Check2' ) )
  205. call feedkeys( ' TypeOfD', 't' )
  206. endfunction
  207. call assert_false( pyxeval( 'ycm_state.SignatureHelpRequestReady()' ) )
  208. call timer_start( s:timer_interval, funcref( 'Check' ) )
  209. call feedkeys( 'C(', 'ntx!' )
  210. call WaitForAssert( {->
  211. \ assert_true(
  212. \ pyxeval(
  213. \ 'ycm_state._signature_help_state.popup_win_id is None'
  214. \ ),
  215. \ 'popup_win_id'
  216. \ )
  217. \ } )
  218. call test_override( 'ALL', 0 )
  219. %bwipeout!
  220. delfunc! Check
  221. delfunc! Check2
  222. endfunction
  223. function! Test_Signatures_With_PUM_Signs()
  224. call youcompleteme#test#setup#OpenFile(
  225. \ '/third_party/ycmd/ycmd/tests/clangd/testdata/general_fallback'
  226. \ . '/make_drink.cc', {} )
  227. " Make sure that sign causes the popup to shift
  228. setlocal signcolumn=auto
  229. call setpos( '.', [ 0, 7, 13 ] )
  230. " Required to trigger TextChangedI
  231. " https://github.com/vim/vim/issues/4665#event-2480928194
  232. call test_override( 'char_avail', 1 )
  233. function Check2( id ) closure
  234. call WaitForAssert( {-> assert_true( pumvisible() ) } )
  235. call WaitForAssert( {-> assert_notequal( [], complete_info().items ) } )
  236. call assert_equal( 7, pum_getpos().row )
  237. redraw
  238. " NOTE: anchor is 0-based
  239. call assert_equal( 6,
  240. \ pyxeval( 'ycm_state._signature_help_state.anchor[0]' ) )
  241. call assert_equal( 13,
  242. \ pyxeval( 'ycm_state._signature_help_state.anchor[1]' ) )
  243. " Sign column is shown, popup shifts to the right 2 screen columns
  244. " Then shifts back due to 80 character screen width
  245. " FIXME: This test was supposed to show the shifting right. Write another
  246. " one which uses a much smaller popup to do that.
  247. call s:_CheckPopupPosition( s:_GetSigHelpWinID(),
  248. \ { 'line': 5, 'col': 5 } )
  249. call test_override( 'ALL', 0 )
  250. call feedkeys( "\<ESC>", 't' )
  251. endfunction
  252. " Must do the checks in a timer callback because we need to stay in insert
  253. " mode until done.
  254. function! Check( id ) closure
  255. call WaitForAssert( {->
  256. \ assert_true(
  257. \ pyxeval(
  258. \ 'ycm_state._signature_help_state.popup_win_id is not None'
  259. \ ),
  260. \ 'popup_win_id'
  261. \ )
  262. \ } )
  263. " Popup is shifted left due to 80 char screen
  264. call s:_CheckPopupPosition( s:_GetSigHelpWinID(),
  265. \ { 'line': 5, 'col': 5 } )
  266. call timer_start( s:timer_interval, funcref( 'Check2' ) )
  267. call feedkeys( ' TypeOfD', 't' )
  268. endfunction
  269. call assert_false( pyxeval( 'ycm_state.SignatureHelpRequestReady()' ) )
  270. call timer_start( s:timer_interval, funcref( 'Check' ) )
  271. call feedkeys( 'C(', 'ntx!' )
  272. call WaitForAssert( {->
  273. \ assert_true(
  274. \ pyxeval(
  275. \ 'ycm_state._signature_help_state.popup_win_id is None'
  276. \ ),
  277. \ 'popup_win_id'
  278. \ )
  279. \ } )
  280. call test_override( 'ALL', 0 )
  281. %bwipeout!
  282. delfunc! Check
  283. delfunc! Check2
  284. endfunction
  285. function! Test_Placement_Simple()
  286. call assert_true( &lines >= 25, "Enough rows" )
  287. call assert_true( &columns >= 25, "Enough columns" )
  288. let X = join( map( range( 0, &columns - 1 ), {->'X'} ), '' )
  289. for i in range( 0, &lines )
  290. call append( line('$'), X )
  291. endfor
  292. " Delete the blank line that is always added to a buffer
  293. 0delete
  294. call s:_ClearSigHelp()
  295. let v_sh = {
  296. \ 'activeSignature': 0,
  297. \ 'activeParameter': 0,
  298. \ 'signatures': [
  299. \ { 'label': 'test function', 'parameters': [] }
  300. \ ]
  301. \ }
  302. " When displayed in the middle with plenty of space
  303. call s:_CheckSigHelpAtPos( v_sh, [ 10, 3 ], {
  304. \ 'line': 9,
  305. \ 'col': 1
  306. \ } )
  307. " Confirm that anchoring works (i.e. it doesn't move!)
  308. call s:_CheckSigHelpAtPos( v_sh, [ 20, 10 ], {
  309. \ 'line': 9,
  310. \ 'col': 1
  311. \ } )
  312. call s:_ClearSigHelp()
  313. " Window slides from left of screen
  314. call s:_CheckSigHelpAtPos( v_sh, [ 10, 2 ], {
  315. \ 'line': 9,
  316. \ 'col': 1,
  317. \ } )
  318. call s:_ClearSigHelp()
  319. " Window slides from left of screen
  320. call s:_CheckSigHelpAtPos( v_sh, [ 10, 1 ], {
  321. \ 'line': 9,
  322. \ 'col': 1,
  323. \ } )
  324. call s:_ClearSigHelp()
  325. " Cursor at top-left of window
  326. call s:_CheckSigHelpAtPos( v_sh, [ 1, 1 ], {
  327. \ 'line': 2,
  328. \ 'col': 1,
  329. \ } )
  330. call s:_ClearSigHelp()
  331. " Cursor at top-right of window
  332. call s:_CheckSigHelpAtPos( v_sh, [ 1, &columns ], {
  333. \ 'line': 2,
  334. \ 'col': &columns - len( "test function" ) - 1,
  335. \ } )
  336. call s:_ClearSigHelp()
  337. " Bottom-left of window
  338. call s:_CheckSigHelpAtPos( v_sh, [ &lines + 1, 1 ], {
  339. \ 'line': &lines - 2,
  340. \ 'col': 1,
  341. \ } )
  342. call s:_ClearSigHelp()
  343. " Bottom-right of window
  344. call s:_CheckSigHelpAtPos( v_sh, [ &lines + 1, &columns ], {
  345. \ 'line': &lines - 2,
  346. \ 'col': &columns - len( "test function" ) - 1,
  347. \ } )
  348. call s:_ClearSigHelp()
  349. call popup_clear()
  350. %bwipeout!
  351. endfunction
  352. function! Test_Placement_MultiLine()
  353. call assert_true( &lines >= 25, "Enough rows" )
  354. call assert_true( &columns >= 25, "Enough columns" )
  355. let X = join( map( range( 0, &columns - 1 ), {->'X'} ), '' )
  356. for i in range( 0, &lines )
  357. call append( line('$'), X )
  358. endfor
  359. " Delete the blank line that is always added to a buffer
  360. 0delete
  361. call s:_ClearSigHelp()
  362. let v_sh = {
  363. \ 'activeSignature': 0,
  364. \ 'activeParameter': 0,
  365. \ 'signatures': [
  366. \ { 'label': 'test function', 'parameters': [] },
  367. \ { 'label': 'toast function', 'parameters': [
  368. \ { 'label': [ 0, 5 ] }
  369. \ ] },
  370. \ ]
  371. \ }
  372. " When displayed in the middle with plenty of space
  373. call s:_CheckSigHelpAtPos( v_sh, [ 10, 3 ], {
  374. \ 'line': 8,
  375. \ 'col': 1
  376. \ } )
  377. " Confirm that anchoring works (i.e. it doesn't move!)
  378. call s:_CheckSigHelpAtPos( v_sh, [ 20, 10 ], {
  379. \ 'line': 8,
  380. \ 'col': 1
  381. \ } )
  382. call s:_ClearSigHelp()
  383. " Window slides from left of screen
  384. call s:_CheckSigHelpAtPos( v_sh, [ 10, 2 ], {
  385. \ 'line': 8,
  386. \ 'col': 1,
  387. \ } )
  388. call s:_ClearSigHelp()
  389. " Window slides from left of screen
  390. call s:_CheckSigHelpAtPos( v_sh, [ 10, 1 ], {
  391. \ 'line': 8,
  392. \ 'col': 1,
  393. \ } )
  394. call s:_ClearSigHelp()
  395. " Cursor at top-left of window
  396. call s:_CheckSigHelpAtPos( v_sh, [ 1, 1 ], {
  397. \ 'line': 2,
  398. \ 'col': 1,
  399. \ } )
  400. call s:_ClearSigHelp()
  401. " Cursor at top-right of window
  402. call s:_CheckSigHelpAtPos( v_sh, [ 1, &columns ], {
  403. \ 'line': 2,
  404. \ 'col': &columns - len( "toast function" ) - 1,
  405. \ } )
  406. call s:_ClearSigHelp()
  407. " Bottom-left of window
  408. call s:_CheckSigHelpAtPos( v_sh, [ &lines + 1, 1 ], {
  409. \ 'line': &lines - 3,
  410. \ 'col': 1,
  411. \ } )
  412. call s:_ClearSigHelp()
  413. " Bottom-right of window
  414. call s:_CheckSigHelpAtPos( v_sh, [ &lines + 1, &columns ], {
  415. \ 'line': &lines - 3,
  416. \ 'col': &columns - len( "toast function" ) - 1,
  417. \ } )
  418. call s:_ClearSigHelp()
  419. call popup_clear()
  420. %bwipeout!
  421. endfunction
  422. function! Test_Signatures_TopLine()
  423. call youcompleteme#test#setup#OpenFile( 'test/testdata/python/test.py', {} )
  424. call setpos( '.', [ 0, 1, 24 ] )
  425. call test_override( 'char_avail', 1 )
  426. function! Check( id ) closure
  427. call s:_CheckPopupPosition( s:_GetSigHelpWinID(), { 'line': 2, 'col': 23 } )
  428. call test_override( 'ALL', 0 )
  429. call feedkeys( "\<ESC>" )
  430. endfunction
  431. call timer_start( s:timer_interval, funcref( 'Check' ) )
  432. call feedkeys( 'cl(', 'ntx!' )
  433. call test_override( 'ALL', 0 )
  434. %bwipeout!
  435. delfun! Check
  436. endfunction
  437. function! Test_Signatures_TopLineWithPUM()
  438. call youcompleteme#test#setup#OpenFile( 'test/testdata/python/test.py', {} )
  439. call setpos( '.', [ 0, 1, 24 ] )
  440. call test_override( 'char_avail', 1 )
  441. function! CheckSigHelpAndTriggerCompletion( id ) closure
  442. " Popup placed below the cursor
  443. call s:_CheckPopupPosition( s:_GetSigHelpWinID(), { 'line': 2, 'col': 23 } )
  444. " Push more characters into the typeahead buffer to trigger insert mode
  445. " completion.
  446. "
  447. " Nte for some reason the first semantic response can take quite some time,
  448. " and if our timer fires before then, the test just fails. so we take 2
  449. " seconds here.
  450. call timer_start( s:timer_interval,
  451. \ funcref( 'CheckCompletionVisibleAndSigHelpHidden' ) )
  452. call feedkeys( " os.", 't' )
  453. endfunction
  454. function! CheckCompletionVisibleAndSigHelpHidden( id ) closure
  455. " Completion popup now visible, overlapping where the sig help popup was
  456. redraw
  457. call WaitForAssert( {-> assert_true( pumvisible() ) } )
  458. call assert_equal( 1, get( pum_getpos(), 'row', -1 ) )
  459. call assert_equal( 28, get( pum_getpos(), 'col', -1 ) )
  460. " so we hide the sig help popup.
  461. call WaitForAssert( {->
  462. \ assert_true(
  463. \ pyxeval(
  464. \ 'ycm_state._signature_help_state.popup_win_id is None'
  465. \ ),
  466. \ 'popup_win_id'
  467. \ )
  468. \ } )
  469. call s:_CheckPopupPosition( s:popup_win_id, {} )
  470. " We're done in insert mode now.
  471. call test_override( 'ALL', 0 )
  472. call feedkeys( "\<ESC>", 't' )
  473. endfunction
  474. " Edit the line and trigger signature help
  475. call timer_start( s:timer_interval,
  476. \ funcref( 'CheckSigHelpAndTriggerCompletion' ) )
  477. call feedkeys( 'C(', 'ntx!' )
  478. call test_override( 'ALL', 0 )
  479. %bwipeout!
  480. delfunc! CheckSigHelpAndTriggerCompletion
  481. delfunc! CheckCompletionVisibleAndSigHelpHidden
  482. endfunction