map_functions_spec.lua 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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 eval = n.eval
  6. local exec = n.exec
  7. local exec_lua = n.exec_lua
  8. local expect = n.expect
  9. local feed = n.feed
  10. local fn = n.fn
  11. local api = n.api
  12. local source = n.source
  13. local command = n.command
  14. local exec_capture = n.exec_capture
  15. local pcall_err = t.pcall_err
  16. describe('maparg()', function()
  17. before_each(clear)
  18. local foo_bar_map_table = {
  19. lhs = 'foo',
  20. lhsraw = 'foo',
  21. script = 0,
  22. silent = 0,
  23. rhs = 'bar',
  24. expr = 0,
  25. sid = 0,
  26. scriptversion = 1,
  27. buffer = 0,
  28. nowait = 0,
  29. mode = 'n',
  30. mode_bits = 0x01,
  31. abbr = 0,
  32. noremap = 1,
  33. lnum = 0,
  34. }
  35. it('returns a dict', function()
  36. command('nnoremap foo bar')
  37. eq('bar', fn.maparg('foo'))
  38. eq(foo_bar_map_table, fn.maparg('foo', 'n', false, true))
  39. end)
  40. it('returns 1 for silent when <silent> is used', function()
  41. command('nnoremap <silent> foo bar')
  42. eq(1, fn.maparg('foo', 'n', false, true)['silent'])
  43. command('nnoremap baz bat')
  44. eq(0, fn.maparg('baz', 'n', false, true)['silent'])
  45. end)
  46. it('returns an empty string when no map is present', function()
  47. eq('', fn.maparg('not a mapping'))
  48. end)
  49. it('returns an empty dict when no map is present and dict is requested', function()
  50. eq({}, fn.maparg('not a mapping', 'n', false, true))
  51. end)
  52. it('returns the same value for noremap and <script>', function()
  53. command('inoremap <script> hello world')
  54. command('inoremap this that')
  55. eq(
  56. fn.maparg('hello', 'i', false, true)['noremap'],
  57. fn.maparg('this', 'i', false, true)['noremap']
  58. )
  59. end)
  60. it('returns a boolean for buffer', function()
  61. -- Open enough windows to know we aren't on buffer number 1
  62. command('new')
  63. command('new')
  64. command('new')
  65. command('cnoremap <buffer> this that')
  66. eq(1, fn.maparg('this', 'c', false, true)['buffer'])
  67. -- Global will return 0 always
  68. command('nnoremap other another')
  69. eq(0, fn.maparg('other', 'n', false, true)['buffer'])
  70. end)
  71. it('returns script numbers', function()
  72. source([[
  73. function! s:maparg_test_function() abort
  74. return 'testing'
  75. endfunction
  76. nnoremap fizz :call <SID>maparg_test_function()<CR>
  77. ]])
  78. eq(1, fn.maparg('fizz', 'n', false, true)['sid'])
  79. eq('testing', api.nvim_call_function('<SNR>1_maparg_test_function', {}))
  80. end)
  81. it('works with <F12> and others', function()
  82. source([[
  83. let g:maparg_test_var = 0
  84. nnoremap <F12> :let g:maparg_test_var = 1<CR>
  85. ]])
  86. eq(0, eval('g:maparg_test_var'))
  87. source([[
  88. call feedkeys("\<F12>")
  89. ]])
  90. eq(1, eval('g:maparg_test_var'))
  91. eq(':let g:maparg_test_var = 1<CR>', fn.maparg('<F12>', 'n', false, true)['rhs'])
  92. end)
  93. it('works with <expr>', function()
  94. source([[
  95. let counter = 0
  96. inoremap <expr> <C-L> ListItem()
  97. inoremap <expr> <C-R> ListReset()
  98. func ListItem()
  99. let g:counter += 1
  100. return g:counter . '. '
  101. endfunc
  102. func ListReset()
  103. let g:counter = 0
  104. return ''
  105. endfunc
  106. call feedkeys("i\<C-L>")
  107. ]])
  108. eq(1, eval('g:counter'))
  109. local map_dict = fn.maparg('<C-L>', 'i', false, true)
  110. eq(1, map_dict['expr'])
  111. eq('i', map_dict['mode'])
  112. end)
  113. it('works with combining characters', function()
  114. -- Using addacutes to make combining character better visible
  115. local function ac(s)
  116. local acute = '\204\129' -- U+0301 COMBINING ACUTE ACCENT
  117. local ret = s:gsub('`', acute)
  118. return ret
  119. end
  120. command(ac([[
  121. nnoremap a b`
  122. nnoremap c` d
  123. nnoremap e` f`
  124. ]]))
  125. eq(ac('b`'), fn.maparg(ac('a')))
  126. eq(ac(''), fn.maparg(ac('c')))
  127. eq(ac('d'), fn.maparg(ac('c`')))
  128. eq(ac('f`'), fn.maparg(ac('e`')))
  129. local function acmap(lhs, rhs)
  130. return {
  131. lhs = ac(lhs),
  132. lhsraw = ac(lhs),
  133. rhs = ac(rhs),
  134. buffer = 0,
  135. expr = 0,
  136. mode = 'n',
  137. mode_bits = 0x01,
  138. abbr = 0,
  139. noremap = 1,
  140. nowait = 0,
  141. script = 0,
  142. sid = 0,
  143. scriptversion = 1,
  144. silent = 0,
  145. lnum = 0,
  146. }
  147. end
  148. eq({}, fn.maparg(ac('c'), 'n', 0, 1))
  149. eq(acmap('a', 'b`'), fn.maparg(ac('a'), 'n', 0, 1))
  150. eq(acmap('c`', 'd'), fn.maparg(ac('c`'), 'n', 0, 1))
  151. eq(acmap('e`', 'f`'), fn.maparg(ac('e`'), 'n', 0, 1))
  152. end)
  153. end)
  154. describe('mapset()', function()
  155. before_each(clear)
  156. it('can restore mapping with backslash in lhs', function()
  157. api.nvim_set_keymap('n', '\\ab', 'a', {})
  158. eq('\nn \\ab a', exec_capture('nmap \\ab'))
  159. local mapargs = fn.maparg('\\ab', 'n', false, true)
  160. api.nvim_set_keymap('n', '\\ab', 'b', {})
  161. eq('\nn \\ab b', exec_capture('nmap \\ab'))
  162. fn.mapset('n', false, mapargs)
  163. eq('\nn \\ab a', exec_capture('nmap \\ab'))
  164. end)
  165. it('can restore mapping description from the dict returned by maparg()', function()
  166. api.nvim_set_keymap('n', 'lhs', 'rhs', { desc = 'map description' })
  167. eq('\nn lhs rhs\n map description', exec_capture('nmap lhs'))
  168. local mapargs = fn.maparg('lhs', 'n', false, true)
  169. api.nvim_set_keymap('n', 'lhs', 'rhs', { desc = 'MAP DESCRIPTION' })
  170. eq('\nn lhs rhs\n MAP DESCRIPTION', exec_capture('nmap lhs'))
  171. fn.mapset('n', false, mapargs)
  172. eq('\nn lhs rhs\n map description', exec_capture('nmap lhs'))
  173. end)
  174. it('can restore "replace_keycodes" from the dict returned by maparg()', function()
  175. api.nvim_set_keymap('i', 'foo', [['<l' .. 't>']], { expr = true, replace_keycodes = true })
  176. feed('Afoo')
  177. expect('<')
  178. local mapargs = fn.maparg('foo', 'i', false, true)
  179. api.nvim_set_keymap('i', 'foo', [['<l' .. 't>']], { expr = true })
  180. feed('foo')
  181. expect('<<lt>')
  182. fn.mapset('i', false, mapargs)
  183. feed('foo')
  184. expect('<<lt><')
  185. end)
  186. it('replaces an abbreviation of the same lhs #20320', function()
  187. command('inoreabbr foo bar')
  188. eq('\ni foo * bar', exec_capture('iabbr foo'))
  189. feed('ifoo ')
  190. expect('bar ')
  191. local mapargs = fn.maparg('foo', 'i', true, true)
  192. command('inoreabbr foo BAR')
  193. eq('\ni foo * BAR', exec_capture('iabbr foo'))
  194. feed('foo ')
  195. expect('bar BAR ')
  196. fn.mapset('i', true, mapargs)
  197. eq('\ni foo * bar', exec_capture('iabbr foo'))
  198. feed('foo<Esc>')
  199. expect('bar BAR bar')
  200. end)
  201. it('can restore Lua callback from the dict returned by maparg()', function()
  202. eq(
  203. 0,
  204. exec_lua([[
  205. GlobalCount = 0
  206. vim.api.nvim_set_keymap('n', 'asdf', '', {
  207. callback = function() GlobalCount = GlobalCount + 1 end,
  208. })
  209. return GlobalCount
  210. ]])
  211. )
  212. feed('asdf')
  213. eq(1, exec_lua([[return GlobalCount]]))
  214. exec_lua([[
  215. _G.saved_asdf_map = vim.fn.maparg('asdf', 'n', false, true)
  216. vim.api.nvim_set_keymap('n', 'asdf', '', {
  217. callback = function() GlobalCount = GlobalCount + 10 end,
  218. })
  219. ]])
  220. feed('asdf')
  221. eq(11, exec_lua([[return GlobalCount]]))
  222. exec_lua([[vim.fn.mapset('n', false, _G.saved_asdf_map)]])
  223. feed('asdf')
  224. eq(12, exec_lua([[return GlobalCount]]))
  225. exec([[
  226. let g:saved_asdf_map = maparg('asdf', 'n', v:false, v:true)
  227. lua <<
  228. vim.api.nvim_set_keymap('n', 'asdf', '', {
  229. callback = function() GlobalCount = GlobalCount + 10 end,
  230. })
  231. ]])
  232. feed('asdf')
  233. eq(22, exec_lua([[return GlobalCount]]))
  234. command([[call mapset('n', v:false, g:saved_asdf_map)]])
  235. feed('asdf')
  236. eq(23, exec_lua([[return GlobalCount]]))
  237. end)
  238. it('does not leak memory if lhs is missing', function()
  239. eq(
  240. 'Vim:E460: Entries missing in mapset() dict argument',
  241. pcall_err(exec_lua, [[vim.fn.mapset('n', false, {rhs = 'foo'})]])
  242. )
  243. eq(
  244. 'Vim:E460: Entries missing in mapset() dict argument',
  245. pcall_err(exec_lua, [[vim.fn.mapset('n', false, {callback = function() end})]])
  246. )
  247. end)
  248. end)