api_functions_spec.lua 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. local t = require('test.testutil')
  2. local n = require('test.functional.testnvim')()
  3. local Screen = require('test.functional.ui.screen')
  4. local neq, eq, command = t.neq, t.eq, n.command
  5. local clear = n.clear
  6. local exc_exec, expect, eval = n.exc_exec, n.expect, n.eval
  7. local exec_lua = n.exec_lua
  8. local insert, pcall_err = n.insert, t.pcall_err
  9. local matches = t.matches
  10. local api = n.api
  11. local feed = n.feed
  12. describe('eval-API', function()
  13. before_each(clear)
  14. it('work', function()
  15. command("call nvim_command('let g:test = 1')")
  16. eq(1, eval("nvim_get_var('test')"))
  17. local buf = eval('nvim_get_current_buf()')
  18. command('call nvim_buf_set_lines(' .. buf .. ", 0, -1, v:true, ['aa', 'bb'])")
  19. expect([[
  20. aa
  21. bb]])
  22. command('call nvim_win_set_cursor(0, [1, 1])')
  23. command("call nvim_input('ax<esc>')")
  24. expect([[
  25. aax
  26. bb]])
  27. end)
  28. it('throw errors for invalid arguments', function()
  29. local err = exc_exec('call nvim_get_current_buf("foo")')
  30. eq('Vim(call):E118: Too many arguments for function: nvim_get_current_buf', err)
  31. err = exc_exec('call nvim_set_option_value("hlsearch")')
  32. eq('Vim(call):E119: Not enough arguments for function: nvim_set_option_value', err)
  33. err = exc_exec('call nvim_buf_set_lines(1, 0, -1, [], ["list"])')
  34. eq(
  35. 'Vim(call):E5555: API call: Wrong type for argument 4 when calling nvim_buf_set_lines, expecting Boolean',
  36. err
  37. )
  38. err = exc_exec('call nvim_buf_set_lines(0, 0, -1, v:true, "string")')
  39. eq(
  40. 'Vim(call):E5555: API call: Wrong type for argument 5 when calling nvim_buf_set_lines, expecting ArrayOf(String)',
  41. err
  42. )
  43. err = exc_exec('call nvim_buf_get_number("0")')
  44. eq(
  45. 'Vim(call):E5555: API call: Wrong type for argument 1 when calling nvim_buf_get_number, expecting Buffer',
  46. err
  47. )
  48. err = exc_exec('call nvim_buf_line_count(17)')
  49. eq('Vim(call):E5555: API call: Invalid buffer id: 17', err)
  50. end)
  51. it('cannot change text or window if textlocked', function()
  52. command('autocmd TextYankPost <buffer> ++once call nvim_buf_set_lines(0, 0, -1, v:false, [])')
  53. matches(
  54. 'Vim%(call%):E5555: API call: E565: Not allowed to change text or change window$',
  55. pcall_err(command, 'normal! yy')
  56. )
  57. command('autocmd TextYankPost <buffer> ++once call nvim_open_term(0, {})')
  58. matches(
  59. 'Vim%(call%):E5555: API call: E565: Not allowed to change text or change window$',
  60. pcall_err(command, 'normal! yy')
  61. )
  62. -- Functions checking textlock should also not be usable from <expr> mappings.
  63. command('inoremap <expr> <f2> nvim_win_close(0, 1)')
  64. eq(
  65. 'Vim(normal):E5555: API call: E565: Not allowed to change text or change window',
  66. pcall_err(command, [[execute "normal i\<f2>"]])
  67. )
  68. -- Text-changing functions gave a "Failed to save undo information" error when called from an
  69. -- <expr> mapping outside do_cmdline() (msg_list == NULL), so use feed() to test this.
  70. command("inoremap <expr> <f2> nvim_buf_set_text(0, 0, 0, 0, 0, ['hi'])")
  71. api.nvim_set_vvar('errmsg', '')
  72. feed('i<f2><esc>')
  73. eq(
  74. 'E5555: API call: E565: Not allowed to change text or change window',
  75. api.nvim_get_vvar('errmsg')
  76. )
  77. -- Some functions checking textlock (usually those that may change the current window or buffer)
  78. -- also ought to not be usable in the cmdwin.
  79. local old_win = api.nvim_get_current_win()
  80. feed('q:')
  81. eq(
  82. 'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
  83. pcall_err(api.nvim_set_current_win, old_win)
  84. )
  85. -- But others, like nvim_buf_set_lines(), which just changes text, is OK.
  86. api.nvim_buf_set_lines(0, 0, -1, 1, { 'wow!' })
  87. eq({ 'wow!' }, api.nvim_buf_get_lines(0, 0, -1, 1))
  88. -- Turning the cmdwin buffer into a terminal buffer would be pretty weird.
  89. eq(
  90. 'E11: Invalid in command-line window; <CR> executes, CTRL-C quits',
  91. pcall_err(api.nvim_open_term, 0, {})
  92. )
  93. matches(
  94. 'E11: Invalid in command%-line window; <CR> executes, CTRL%-C quits$',
  95. pcall_err(
  96. exec_lua,
  97. [[
  98. local cmdwin_buf = vim.api.nvim_get_current_buf()
  99. vim.api.nvim_buf_call(vim.api.nvim_create_buf(false, true), function()
  100. vim.api.nvim_open_term(cmdwin_buf, {})
  101. end)
  102. ]]
  103. )
  104. )
  105. -- But turning a different buffer into a terminal from the cmdwin is OK.
  106. local term_buf = api.nvim_create_buf(false, true)
  107. api.nvim_open_term(term_buf, {})
  108. eq('terminal', api.nvim_get_option_value('buftype', { buf = term_buf }))
  109. end)
  110. it('use buffer numbers and windows ids as handles', function()
  111. local screen = Screen.new(40, 8)
  112. screen:attach()
  113. local bnr = eval("bufnr('')")
  114. local bhnd = eval('nvim_get_current_buf()')
  115. local wid = eval('win_getid()')
  116. local whnd = eval('nvim_get_current_win()')
  117. eq(bnr, bhnd)
  118. eq(wid, whnd)
  119. command('new') -- creates new buffer and new window
  120. local bnr2 = eval("bufnr('')")
  121. local bhnd2 = eval('nvim_get_current_buf()')
  122. local wid2 = eval('win_getid()')
  123. local whnd2 = eval('nvim_get_current_win()')
  124. eq(bnr2, bhnd2)
  125. eq(wid2, whnd2)
  126. neq(bnr, bnr2)
  127. neq(wid, wid2)
  128. -- 0 is synonymous to the current buffer
  129. eq(bnr2, eval('nvim_buf_get_number(0)'))
  130. command('bn') -- show old buffer in new window
  131. eq(bnr, eval('nvim_get_current_buf()'))
  132. eq(bnr, eval("bufnr('')"))
  133. eq(bnr, eval('nvim_buf_get_number(0)'))
  134. eq(wid2, eval('win_getid()'))
  135. eq(whnd2, eval('nvim_get_current_win()'))
  136. end)
  137. it('get_lines and set_lines use NL to represent NUL', function()
  138. api.nvim_buf_set_lines(0, 0, -1, true, { 'aa\0', 'b\0b' })
  139. eq({ 'aa\n', 'b\nb' }, eval('nvim_buf_get_lines(0, 0, -1, 1)'))
  140. command('call nvim_buf_set_lines(0, 1, 2, v:true, ["xx", "\\nyy"])')
  141. eq({ 'aa\0', 'xx', '\0yy' }, api.nvim_buf_get_lines(0, 0, -1, 1))
  142. end)
  143. it('that are FUNC_ATTR_NOEVAL cannot be called', function()
  144. -- Deprecated vim_ prefix is not exported.
  145. local err = exc_exec('call vim_get_current_buffer("foo")')
  146. eq('Vim(call):E117: Unknown function: vim_get_current_buffer', err)
  147. -- Deprecated buffer_ prefix is not exported.
  148. err = exc_exec('call buffer_line_count(0)')
  149. eq('Vim(call):E117: Unknown function: buffer_line_count', err)
  150. -- Functions deprecated before the api functions became available
  151. -- in vimscript are not exported.
  152. err = exc_exec('call buffer_get_line(0, 1)')
  153. eq('Vim(call):E117: Unknown function: buffer_get_line', err)
  154. -- some api functions are only useful from a msgpack-rpc channel
  155. err = exc_exec('call nvim_subscribe("fancyevent")')
  156. eq('Vim(call):E117: Unknown function: nvim_subscribe', err)
  157. end)
  158. it('have metadata accessible with api_info()', function()
  159. local api_keys = eval('sort(keys(api_info()))')
  160. eq({ 'error_types', 'functions', 'types', 'ui_events', 'ui_options', 'version' }, api_keys)
  161. end)
  162. it('are highlighted by vim.vim syntax file', function()
  163. local screen = Screen.new(40, 8)
  164. screen:attach()
  165. screen:set_default_attr_ids({
  166. [1] = { bold = true, foreground = Screen.colors.Brown },
  167. [2] = { foreground = Screen.colors.DarkCyan },
  168. [3] = { foreground = Screen.colors.SlateBlue },
  169. [4] = { foreground = Screen.colors.Fuchsia },
  170. [5] = { bold = true, foreground = Screen.colors.Blue },
  171. })
  172. command('set ft=vim')
  173. command('set rtp^=build/runtime/')
  174. command('syntax on')
  175. insert([[
  176. call bufnr('%')
  177. call nvim_input('typing...')
  178. call not_a_function(42)]])
  179. screen:expect([[
  180. {1:call} {2:bufnr}{3:(}{4:'%'}{3:)} |
  181. {1:call} {2:nvim_input}{3:(}{4:'typing...'}{3:)} |
  182. {1:call} not_a_function{3:(}{4:42}{3:^)} |
  183. {5:~ }|*4
  184. |
  185. ]])
  186. end)
  187. it('cannot be called from sandbox', function()
  188. eq(
  189. 'Vim(call):E48: Not allowed in sandbox',
  190. pcall_err(command, "sandbox call nvim_input('ievil')")
  191. )
  192. eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, true))
  193. end)
  194. it('converts blobs to API strings', function()
  195. command('let g:v1 = nvim__id(0z68656c6c6f)')
  196. command('let g:v2 = nvim__id(v:_null_blob)')
  197. eq(1, eval('type(g:v1)'))
  198. eq(1, eval('type(g:v2)'))
  199. eq('hello', eval('g:v1'))
  200. eq('', eval('g:v2'))
  201. end)
  202. end)