command_line_completion_spec.lua 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local clear = n.clear
  4. local eq = t.eq
  5. local exec_lua = n.exec_lua
  6. --- @return { [1]: string[], [2]: integer }
  7. local get_completions = function(input, env)
  8. return exec_lua('return { vim._expand_pat(...) }', input, env)
  9. end
  10. --- @return { [1]: string[], [2]: integer }
  11. local get_compl_parts = function(parts)
  12. return exec_lua('return { vim._expand_pat_get_parts(...) }', parts)
  13. end
  14. before_each(clear)
  15. describe('nlua_expand_pat', function()
  16. it('should complete exact matches', function()
  17. eq({ { 'exact' }, 0 }, get_completions('exact', { exact = true }))
  18. end)
  19. it('should return empty table when nothing matches', function()
  20. eq({ {}, 0 }, get_completions('foo', { bar = true }))
  21. end)
  22. it('should return nice completions with function call prefix', function()
  23. eq({ { 'FOO' }, 6 }, get_completions('print(F', { FOO = true, bawr = true }))
  24. end)
  25. it('should return keys for nested dictionaries', function()
  26. eq(
  27. { {
  28. 'nvim_buf_set_lines',
  29. }, 8 },
  30. get_completions('vim.api.nvim_buf_', {
  31. vim = {
  32. api = {
  33. nvim_buf_set_lines = true,
  34. nvim_win_doesnt_match = true,
  35. },
  36. other_key = true,
  37. },
  38. })
  39. )
  40. end)
  41. it('it should work with colons', function()
  42. eq(
  43. { {
  44. 'bawr',
  45. 'baz',
  46. }, 8 },
  47. get_completions('MyClass:b', {
  48. MyClass = {
  49. baz = true,
  50. bawr = true,
  51. foo = false,
  52. },
  53. })
  54. )
  55. end)
  56. it('should return keys for string reffed dictionaries', function()
  57. eq(
  58. { {
  59. 'nvim_buf_set_lines',
  60. }, 11 },
  61. get_completions('vim["api"].nvim_buf_', {
  62. vim = {
  63. api = {
  64. nvim_buf_set_lines = true,
  65. nvim_win_doesnt_match = true,
  66. },
  67. other_key = true,
  68. },
  69. })
  70. )
  71. end)
  72. it('should return keys for string reffed dictionaries', function()
  73. eq(
  74. { {
  75. 'nvim_buf_set_lines',
  76. }, 21 },
  77. get_completions('vim["nested"]["api"].nvim_buf_', {
  78. vim = {
  79. nested = {
  80. api = {
  81. nvim_buf_set_lines = true,
  82. nvim_win_doesnt_match = true,
  83. },
  84. },
  85. other_key = true,
  86. },
  87. })
  88. )
  89. end)
  90. it('should work with lazy submodules of "vim" global', function()
  91. eq({ { 'inspect', 'inspect_pos' }, 4 }, get_completions('vim.inspec'))
  92. eq({ { 'treesitter' }, 4 }, get_completions('vim.treesi'))
  93. eq({ { 'set' }, 11 }, get_completions('vim.keymap.se'))
  94. end)
  95. it('should be able to interpolate globals', function()
  96. eq(
  97. { {
  98. 'nvim_buf_set_lines',
  99. }, 12 },
  100. get_completions('vim[MY_VAR].nvim_buf_', {
  101. MY_VAR = 'api',
  102. vim = {
  103. api = {
  104. nvim_buf_set_lines = true,
  105. nvim_win_doesnt_match = true,
  106. },
  107. other_key = true,
  108. },
  109. })
  110. )
  111. end)
  112. describe('should complete vim.fn', function()
  113. it('correctly works for simple completion', function()
  114. local actual = get_completions('vim.fn.did')
  115. local expected = {
  116. { 'did_filetype' },
  117. #'vim.fn.',
  118. }
  119. eq(expected, actual)
  120. end)
  121. it('should not suggest items with #', function()
  122. exec_lua [[
  123. -- ensure remote#host#... functions exist
  124. vim.cmd [=[
  125. runtime! autoload/remote/host.vim
  126. ]=]
  127. -- make a dummy call to ensure vim.fn contains an entry: remote#host#...
  128. vim.fn['remote#host#IsRunning']('python3')
  129. ]]
  130. local actual = get_completions('vim.fn.remo')
  131. local expected = {
  132. { 'remove' }, -- there should be no completion "remote#host#..."
  133. #'vim.fn.',
  134. }
  135. eq(expected, actual)
  136. end)
  137. end)
  138. describe('should complete for variable accessors for', function()
  139. it('vim.v', function()
  140. local actual = get_completions('vim.v.t_')
  141. local expected = {
  142. { 't_blob', 't_bool', 't_dict', 't_float', 't_func', 't_list', 't_number', 't_string' },
  143. #'vim.v.',
  144. }
  145. eq(expected, actual)
  146. end)
  147. it('vim.g', function()
  148. exec_lua [[
  149. vim.cmd [=[
  150. let g:nlua_foo = 'completion'
  151. let g:nlua_foo_bar = 'completion'
  152. let g:nlua_foo#bar = 'nocompletion' " should be excluded from lua completion
  153. ]=]
  154. ]]
  155. local actual = get_completions('vim.g.nlua')
  156. local expected = {
  157. { 'nlua_foo', 'nlua_foo_bar' },
  158. #'vim.g.',
  159. }
  160. eq(expected, actual)
  161. end)
  162. it('vim.b', function()
  163. exec_lua [[
  164. vim.b.nlua_foo_buf = 'bar'
  165. vim.b.some_other_vars = 'bar'
  166. ]]
  167. local actual = get_completions('vim.b.nlua')
  168. local expected = {
  169. { 'nlua_foo_buf' },
  170. #'vim.b.',
  171. }
  172. eq(expected, actual)
  173. end)
  174. it('vim.w', function()
  175. exec_lua [[
  176. vim.w.nlua_win_var = 42
  177. ]]
  178. local actual = get_completions('vim.w.nlua')
  179. local expected = {
  180. { 'nlua_win_var' },
  181. #'vim.w.',
  182. }
  183. eq(expected, actual)
  184. end)
  185. it('vim.t', function()
  186. exec_lua [[
  187. vim.t.nlua_tab_var = 42
  188. ]]
  189. local actual = get_completions('vim.t.')
  190. local expected = {
  191. { 'nlua_tab_var' },
  192. #'vim.t.',
  193. }
  194. eq(expected, actual)
  195. end)
  196. end)
  197. describe('should complete for option accessors for', function()
  198. -- for { vim.o, vim.go, vim.opt, vim.opt_local, vim.opt_global }
  199. local test_opt = function(accessor)
  200. do
  201. local actual = get_completions(accessor .. '.file')
  202. local expected = {
  203. 'fileencoding',
  204. 'fileencodings',
  205. 'fileformat',
  206. 'fileformats',
  207. 'fileignorecase',
  208. 'filetype',
  209. }
  210. eq({ expected, #accessor + 1 }, actual, accessor .. '.file')
  211. end
  212. do
  213. local actual = get_completions(accessor .. '.winh')
  214. local expected = {
  215. 'winheight',
  216. 'winhighlight',
  217. }
  218. eq({ expected, #accessor + 1 }, actual, accessor .. '.winh')
  219. end
  220. end
  221. test_opt('vim.o')
  222. test_opt('vim.go')
  223. test_opt('vim.opt')
  224. test_opt('vim.opt_local')
  225. test_opt('vim.opt_global')
  226. it('vim.o, suggesting all the known options', function()
  227. local completions = get_completions('vim.o.')[1] ---@type string[]
  228. eq(
  229. exec_lua [[
  230. return vim.tbl_count(vim.api.nvim_get_all_options_info())
  231. ]],
  232. #completions
  233. )
  234. end)
  235. it('vim.bo', function()
  236. do
  237. local actual = get_completions('vim.bo.file')
  238. local compls = {
  239. -- should contain buffer options only
  240. 'fileencoding',
  241. 'fileformat',
  242. 'filetype',
  243. }
  244. eq({ compls, #'vim.bo.' }, actual)
  245. end
  246. do
  247. local actual = get_completions('vim.bo.winh')
  248. local compls = {}
  249. eq({ compls, #'vim.bo.' }, actual)
  250. end
  251. end)
  252. it('vim.wo', function()
  253. do
  254. local actual = get_completions('vim.wo.file')
  255. local compls = {}
  256. eq({ compls, #'vim.wo.' }, actual)
  257. end
  258. do
  259. local actual = get_completions('vim.wo.winh')
  260. -- should contain window options only
  261. local compls = { 'winhighlight' }
  262. eq({ compls, #'vim.wo.' }, actual)
  263. end
  264. end)
  265. end)
  266. it('should return everything if the input is of length 0', function()
  267. eq({ { 'other', 'vim' }, 0 }, get_completions('', { vim = true, other = true }))
  268. end)
  269. describe('get_parts', function()
  270. it('should return an empty list for no separators', function()
  271. eq({ {}, 1 }, get_compl_parts('vim'))
  272. end)
  273. it('just the first item before a period', function()
  274. eq({ { 'vim' }, 5 }, get_compl_parts('vim.ap'))
  275. end)
  276. it('should return multiple parts just for period', function()
  277. eq({ { 'vim', 'api' }, 9 }, get_compl_parts('vim.api.nvim_buf'))
  278. end)
  279. it('should be OK with colons', function()
  280. eq({ { 'vim', 'api' }, 9 }, get_compl_parts('vim:api.nvim_buf'))
  281. end)
  282. it('should work for just one string ref', function()
  283. eq({ { 'vim', 'api' }, 12 }, get_compl_parts("vim['api'].nvim_buf"))
  284. end)
  285. it('should work for just one string ref, with double quote', function()
  286. eq({ { 'vim', 'api' }, 12 }, get_compl_parts('vim["api"].nvim_buf'))
  287. end)
  288. it('should allows back-to-back string ref', function()
  289. eq({ { 'vim', 'nested', 'api' }, 22 }, get_compl_parts('vim["nested"]["api"].nvim_buf'))
  290. end)
  291. it('should allows back-to-back string ref with spaces before and after', function()
  292. eq({ { 'vim', 'nested', 'api' }, 25 }, get_compl_parts('vim[ "nested" ]["api"].nvim_buf'))
  293. end)
  294. it('should allow VAR style loolup', function()
  295. eq({ { 'vim', { 'NESTED' }, 'api' }, 20 }, get_compl_parts('vim[NESTED]["api"].nvim_buf'))
  296. end)
  297. end)
  298. end)