vim_spec.lua 70 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222
  1. -- Test suite for testing interactions with API bindings
  2. local helpers = require('test.functional.helpers')(after_each)
  3. local Screen = require('test.functional.ui.screen')
  4. local funcs = helpers.funcs
  5. local meths = helpers.meths
  6. local dedent = helpers.dedent
  7. local command = helpers.command
  8. local insert = helpers.insert
  9. local clear = helpers.clear
  10. local eq = helpers.eq
  11. local ok = helpers.ok
  12. local eval = helpers.eval
  13. local feed = helpers.feed
  14. local pcall_err = helpers.pcall_err
  15. local exec_lua = helpers.exec_lua
  16. local matches = helpers.matches
  17. local source = helpers.source
  18. local NIL = helpers.NIL
  19. local retry = helpers.retry
  20. before_each(clear)
  21. describe('lua stdlib', function()
  22. -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has
  23. -- length 2 (in bytes).
  24. -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has
  25. -- length 3 (in bytes).
  26. --
  27. -- Note: 'i' !=? 'İ' and 'ⱥ' !=? 'Ⱥ' on some systems.
  28. -- Note: Built-in Nvim comparison (on systems lacking `strcasecmp`) works
  29. -- only on ASCII characters.
  30. it('vim.stricmp', function()
  31. eq(0, funcs.luaeval('vim.stricmp("a", "A")'))
  32. eq(0, funcs.luaeval('vim.stricmp("A", "a")'))
  33. eq(0, funcs.luaeval('vim.stricmp("a", "a")'))
  34. eq(0, funcs.luaeval('vim.stricmp("A", "A")'))
  35. eq(0, funcs.luaeval('vim.stricmp("", "")'))
  36. eq(0, funcs.luaeval('vim.stricmp("\\0", "\\0")'))
  37. eq(0, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0")'))
  38. eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0\\0")'))
  39. eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0a")'))
  40. eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0A")'))
  41. eq(0, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0a")'))
  42. eq(0, funcs.luaeval('vim.stricmp("a\\0", "A\\0")'))
  43. eq(0, funcs.luaeval('vim.stricmp("A\\0", "a\\0")'))
  44. eq(0, funcs.luaeval('vim.stricmp("a\\0", "a\\0")'))
  45. eq(0, funcs.luaeval('vim.stricmp("A\\0", "A\\0")'))
  46. eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0A")'))
  47. eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0a")'))
  48. eq(0, funcs.luaeval('vim.stricmp("\\0a", "\\0a")'))
  49. eq(0, funcs.luaeval('vim.stricmp("\\0A", "\\0A")'))
  50. eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0A\\0")'))
  51. eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0a\\0")'))
  52. eq(0, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0a\\0")'))
  53. eq(0, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0A\\0")'))
  54. eq(-1, funcs.luaeval('vim.stricmp("a", "B")'))
  55. eq(-1, funcs.luaeval('vim.stricmp("A", "b")'))
  56. eq(-1, funcs.luaeval('vim.stricmp("a", "b")'))
  57. eq(-1, funcs.luaeval('vim.stricmp("A", "B")'))
  58. eq(-1, funcs.luaeval('vim.stricmp("", "\\0")'))
  59. eq(-1, funcs.luaeval('vim.stricmp("\\0", "\\0\\0")'))
  60. eq(-1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0\\0\\0")'))
  61. eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0b")'))
  62. eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0B")'))
  63. eq(-1, funcs.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0b")'))
  64. eq(-1, funcs.luaeval('vim.stricmp("a\\0", "B\\0")'))
  65. eq(-1, funcs.luaeval('vim.stricmp("A\\0", "b\\0")'))
  66. eq(-1, funcs.luaeval('vim.stricmp("a\\0", "b\\0")'))
  67. eq(-1, funcs.luaeval('vim.stricmp("A\\0", "B\\0")'))
  68. eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0B")'))
  69. eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0b")'))
  70. eq(-1, funcs.luaeval('vim.stricmp("\\0a", "\\0b")'))
  71. eq(-1, funcs.luaeval('vim.stricmp("\\0A", "\\0B")'))
  72. eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0B\\0")'))
  73. eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0b\\0")'))
  74. eq(-1, funcs.luaeval('vim.stricmp("\\0a\\0", "\\0b\\0")'))
  75. eq(-1, funcs.luaeval('vim.stricmp("\\0A\\0", "\\0B\\0")'))
  76. eq(1, funcs.luaeval('vim.stricmp("c", "B")'))
  77. eq(1, funcs.luaeval('vim.stricmp("C", "b")'))
  78. eq(1, funcs.luaeval('vim.stricmp("c", "b")'))
  79. eq(1, funcs.luaeval('vim.stricmp("C", "B")'))
  80. eq(1, funcs.luaeval('vim.stricmp("\\0", "")'))
  81. eq(1, funcs.luaeval('vim.stricmp("\\0\\0", "\\0")'))
  82. eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0")'))
  83. eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0\\0", "\\0\\0\\0")'))
  84. eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0C", "\\0\\0\\0b")'))
  85. eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0B")'))
  86. eq(1, funcs.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0b")'))
  87. eq(1, funcs.luaeval('vim.stricmp("c\\0", "B\\0")'))
  88. eq(1, funcs.luaeval('vim.stricmp("C\\0", "b\\0")'))
  89. eq(1, funcs.luaeval('vim.stricmp("c\\0", "b\\0")'))
  90. eq(1, funcs.luaeval('vim.stricmp("C\\0", "B\\0")'))
  91. eq(1, funcs.luaeval('vim.stricmp("c\\0", "B")'))
  92. eq(1, funcs.luaeval('vim.stricmp("C\\0", "b")'))
  93. eq(1, funcs.luaeval('vim.stricmp("c\\0", "b")'))
  94. eq(1, funcs.luaeval('vim.stricmp("C\\0", "B")'))
  95. eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0B")'))
  96. eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0b")'))
  97. eq(1, funcs.luaeval('vim.stricmp("\\0c", "\\0b")'))
  98. eq(1, funcs.luaeval('vim.stricmp("\\0C", "\\0B")'))
  99. eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0B\\0")'))
  100. eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0b\\0")'))
  101. eq(1, funcs.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")'))
  102. eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")'))
  103. end)
  104. -- for brevity, match only the error header (not the traceback)
  105. local function pcall_header(...)
  106. return string.gsub(string.gsub(pcall_err(exec_lua, ...), '[\r\n].*', ''), '^Error executing lua: ', '')
  107. end
  108. it('vim.startswith', function()
  109. eq(true, funcs.luaeval('vim.startswith("123", "1")'))
  110. eq(true, funcs.luaeval('vim.startswith("123", "")'))
  111. eq(true, funcs.luaeval('vim.startswith("123", "123")'))
  112. eq(true, funcs.luaeval('vim.startswith("", "")'))
  113. eq(false, funcs.luaeval('vim.startswith("123", " ")'))
  114. eq(false, funcs.luaeval('vim.startswith("123", "2")'))
  115. eq(false, funcs.luaeval('vim.startswith("123", "1234")'))
  116. eq("vim/shared.lua:0: prefix: expected string, got nil", pcall_header 'return vim.startswith("123", nil)')
  117. eq("vim/shared.lua:0: s: expected string, got nil", pcall_header 'return vim.startswith(nil, "123")')
  118. end)
  119. it('vim.endswith', function()
  120. eq(true, funcs.luaeval('vim.endswith("123", "3")'))
  121. eq(true, funcs.luaeval('vim.endswith("123", "")'))
  122. eq(true, funcs.luaeval('vim.endswith("123", "123")'))
  123. eq(true, funcs.luaeval('vim.endswith("", "")'))
  124. eq(false, funcs.luaeval('vim.endswith("123", " ")'))
  125. eq(false, funcs.luaeval('vim.endswith("123", "2")'))
  126. eq(false, funcs.luaeval('vim.endswith("123", "1234")'))
  127. eq("vim/shared.lua:0: suffix: expected string, got nil", pcall_header 'return vim.endswith("123", nil)')
  128. eq("vim/shared.lua:0: s: expected string, got nil", pcall_header 'return vim.endswith(nil, "123")')
  129. end)
  130. it("vim.str_utfindex/str_byteindex", function()
  131. exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]])
  132. local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48}
  133. local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48}
  134. for i,k in pairs(indicies32) do
  135. eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i)
  136. end
  137. for i,k in pairs(indicies16) do
  138. eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i)
  139. end
  140. local i32, i16 = 0, 0
  141. for k = 0,48 do
  142. if indicies32[i32] < k then
  143. i32 = i32 + 1
  144. end
  145. if indicies16[i16] < k then
  146. i16 = i16 + 1
  147. if indicies16[i16+1] == indicies16[i16] then
  148. i16 = i16 + 1
  149. end
  150. end
  151. eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k)
  152. end
  153. end)
  154. it("vim.schedule", function()
  155. exec_lua([[
  156. test_table = {}
  157. vim.schedule(function()
  158. table.insert(test_table, "xx")
  159. end)
  160. table.insert(test_table, "yy")
  161. ]])
  162. eq({"yy","xx"}, exec_lua("return test_table"))
  163. -- Validates args.
  164. eq('Error executing lua: vim.schedule: expected function',
  165. pcall_err(exec_lua, "vim.schedule('stringly')"))
  166. eq('Error executing lua: vim.schedule: expected function',
  167. pcall_err(exec_lua, "vim.schedule()"))
  168. exec_lua([[
  169. vim.schedule(function()
  170. error("big failure\nvery async")
  171. end)
  172. ]])
  173. feed("<cr>")
  174. eq('Error executing vim.schedule lua callback: [string "<nvim>"]:2: big failure\nvery async', eval("v:errmsg"))
  175. local screen = Screen.new(60,5)
  176. screen:set_default_attr_ids({
  177. [1] = {bold = true, foreground = Screen.colors.Blue1},
  178. [2] = {bold = true, reverse = true},
  179. [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
  180. [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
  181. })
  182. screen:attach()
  183. screen:expect{grid=[[
  184. ^ |
  185. {1:~ }|
  186. {1:~ }|
  187. {1:~ }|
  188. |
  189. ]]}
  190. -- nvim_command causes a vimL exception, check that it is properly caught
  191. -- and propagated as an error message in async contexts.. #10809
  192. exec_lua([[
  193. vim.schedule(function()
  194. vim.api.nvim_command(":echo 'err")
  195. end)
  196. ]])
  197. screen:expect{grid=[[
  198. |
  199. {2: }|
  200. {3:Error executing vim.schedule lua callback: [string "<nvim>"]}|
  201. {3::2: Vim(echo):E115: Missing quote: 'err} |
  202. {4:Press ENTER or type command to continue}^ |
  203. ]]}
  204. end)
  205. it("vim.split", function()
  206. local split = function(str, sep, plain)
  207. return exec_lua('return vim.split(...)', str, sep, plain)
  208. end
  209. local tests = {
  210. { "a,b", ",", false, { 'a', 'b' } },
  211. { ":aa::bb:", ":", false, { '', 'aa', '', 'bb', '' } },
  212. { "::ee::ff:", ":", false, { '', '', 'ee', '', 'ff', '' } },
  213. { "ab", ".", false, { '', '', '' } },
  214. { "a1b2c", "[0-9]", false, { 'a', 'b', 'c' } },
  215. { "xy", "", false, { 'x', 'y' } },
  216. { "here be dragons", " ", false, { "here", "be", "dragons"} },
  217. { "axaby", "ab?", false, { '', 'x', 'y' } },
  218. { "f v2v v3v w2w ", "([vw])2%1", false, { 'f ', ' v3v ', ' ' } },
  219. { "", "", false, {} },
  220. { "", "a", false, { '' } },
  221. { "x*yz*oo*l", "*", true, { 'x', 'yz', 'oo', 'l' } },
  222. }
  223. for _, t in ipairs(tests) do
  224. eq(t[4], split(t[1], t[2], t[3]))
  225. end
  226. local loops = {
  227. { "abc", ".-" },
  228. }
  229. for _, t in ipairs(loops) do
  230. eq("Error executing lua: vim/shared.lua:0: Infinite loop detected", pcall_err(split, t[1], t[2]))
  231. end
  232. -- Validates args.
  233. eq(true, pcall(split, 'string', 'string'))
  234. eq(dedent([[
  235. Error executing lua: vim/shared.lua:0: s: expected string, got number
  236. stack traceback:
  237. vim/shared.lua:0: in function 'gsplit'
  238. vim/shared.lua:0: in function <vim/shared.lua:0>]]),
  239. pcall_err(split, 1, 'string'))
  240. eq(dedent([[
  241. Error executing lua: vim/shared.lua:0: sep: expected string, got number
  242. stack traceback:
  243. vim/shared.lua:0: in function 'gsplit'
  244. vim/shared.lua:0: in function <vim/shared.lua:0>]]),
  245. pcall_err(split, 'string', 1))
  246. eq(dedent([[
  247. Error executing lua: vim/shared.lua:0: plain: expected boolean, got number
  248. stack traceback:
  249. vim/shared.lua:0: in function 'gsplit'
  250. vim/shared.lua:0: in function <vim/shared.lua:0>]]),
  251. pcall_err(split, 'string', 'string', 1))
  252. end)
  253. it('vim.trim', function()
  254. local trim = function(s)
  255. return exec_lua('return vim.trim(...)', s)
  256. end
  257. local trims = {
  258. { " a", "a" },
  259. { " b ", "b" },
  260. { "\tc" , "c" },
  261. { "r\n", "r" },
  262. }
  263. for _, t in ipairs(trims) do
  264. assert(t[2], trim(t[1]))
  265. end
  266. -- Validates args.
  267. eq(dedent([[
  268. Error executing lua: vim/shared.lua:0: s: expected string, got number
  269. stack traceback:
  270. vim/shared.lua:0: in function <vim/shared.lua:0>]]),
  271. pcall_err(trim, 2))
  272. end)
  273. it('vim.inspect', function()
  274. -- just make sure it basically works, it has its own test suite
  275. local inspect = function(t, opts)
  276. return exec_lua('return vim.inspect(...)', t, opts)
  277. end
  278. eq('2', inspect(2))
  279. eq('{+a = {+b = 1+}+}',
  280. inspect({ a = { b = 1 } }, { newline = '+', indent = '' }))
  281. -- special value vim.inspect.KEY works
  282. eq('{ KEY_a = "x", KEY_b = "y"}', exec_lua([[
  283. return vim.inspect({a="x", b="y"}, {newline = '', process = function(item, path)
  284. if path[#path] == vim.inspect.KEY then
  285. return 'KEY_'..item
  286. end
  287. return item
  288. end})
  289. ]]))
  290. end)
  291. it("vim.deepcopy", function()
  292. ok(exec_lua([[
  293. local a = { x = { 1, 2 }, y = 5}
  294. local b = vim.deepcopy(a)
  295. return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and vim.tbl_count(b) == 2
  296. and tostring(a) ~= tostring(b)
  297. ]]))
  298. ok(exec_lua([[
  299. local a = {}
  300. local b = vim.deepcopy(a)
  301. return vim.tbl_islist(b) and vim.tbl_count(b) == 0 and tostring(a) ~= tostring(b)
  302. ]]))
  303. ok(exec_lua([[
  304. local a = vim.empty_dict()
  305. local b = vim.deepcopy(a)
  306. return not vim.tbl_islist(b) and vim.tbl_count(b) == 0
  307. ]]))
  308. ok(exec_lua([[
  309. local a = {x = vim.empty_dict(), y = {}}
  310. local b = vim.deepcopy(a)
  311. return not vim.tbl_islist(b.x) and vim.tbl_islist(b.y)
  312. and vim.tbl_count(b) == 2
  313. and tostring(a) ~= tostring(b)
  314. ]]))
  315. ok(exec_lua([[
  316. local f1 = function() return 1 end
  317. local f2 = function() return 2 end
  318. local t1 = {f = f1}
  319. local t2 = vim.deepcopy(t1)
  320. t1.f = f2
  321. return t1.f() ~= t2.f()
  322. ]]))
  323. eq('Error executing lua: vim/shared.lua:0: Cannot deepcopy object of type thread',
  324. pcall_err(exec_lua, [[
  325. local thread = coroutine.create(function () return 0 end)
  326. local t = {thr = thread}
  327. vim.deepcopy(t)
  328. ]]))
  329. end)
  330. it('vim.pesc', function()
  331. eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]]))
  332. eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]]))
  333. -- Validates args.
  334. eq(dedent([[
  335. Error executing lua: vim/shared.lua:0: s: expected string, got number
  336. stack traceback:
  337. vim/shared.lua:0: in function <vim/shared.lua:0>]]),
  338. pcall_err(exec_lua, [[return vim.pesc(2)]]))
  339. end)
  340. it('vim.tbl_keys', function()
  341. eq({}, exec_lua("return vim.tbl_keys({})"))
  342. for _, v in pairs(exec_lua("return vim.tbl_keys({'a', 'b', 'c'})")) do
  343. eq(true, exec_lua("return vim.tbl_contains({ 1, 2, 3 }, ...)", v))
  344. end
  345. for _, v in pairs(exec_lua("return vim.tbl_keys({a=1, b=2, c=3})")) do
  346. eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v))
  347. end
  348. end)
  349. it('vim.tbl_values', function()
  350. eq({}, exec_lua("return vim.tbl_values({})"))
  351. for _, v in pairs(exec_lua("return vim.tbl_values({'a', 'b', 'c'})")) do
  352. eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v))
  353. end
  354. for _, v in pairs(exec_lua("return vim.tbl_values({a=1, b=2, c=3})")) do
  355. eq(true, exec_lua("return vim.tbl_contains({ 1, 2, 3 }, ...)", v))
  356. end
  357. end)
  358. it('vim.tbl_map', function()
  359. eq({}, exec_lua([[
  360. return vim.tbl_map(function(v) return v * 2 end, {})
  361. ]]))
  362. eq({2, 4, 6}, exec_lua([[
  363. return vim.tbl_map(function(v) return v * 2 end, {1, 2, 3})
  364. ]]))
  365. eq({{i=2}, {i=4}, {i=6}}, exec_lua([[
  366. return vim.tbl_map(function(v) return { i = v.i * 2 } end, {{i=1}, {i=2}, {i=3}})
  367. ]]))
  368. end)
  369. it('vim.tbl_filter', function()
  370. eq({}, exec_lua([[
  371. return vim.tbl_filter(function(v) return (v % 2) == 0 end, {})
  372. ]]))
  373. eq({2}, exec_lua([[
  374. return vim.tbl_filter(function(v) return (v % 2) == 0 end, {1, 2, 3})
  375. ]]))
  376. eq({{i=2}}, exec_lua([[
  377. return vim.tbl_filter(function(v) return (v.i % 2) == 0 end, {{i=1}, {i=2}, {i=3}})
  378. ]]))
  379. end)
  380. it('vim.tbl_islist', function()
  381. eq(true, exec_lua("return vim.tbl_islist({})"))
  382. eq(false, exec_lua("return vim.tbl_islist(vim.empty_dict())"))
  383. eq(true, exec_lua("return vim.tbl_islist({'a', 'b', 'c'})"))
  384. eq(false, exec_lua("return vim.tbl_islist({'a', '32', a='hello', b='baz'})"))
  385. eq(false, exec_lua("return vim.tbl_islist({1, a='hello', b='baz'})"))
  386. eq(false, exec_lua("return vim.tbl_islist({a='hello', b='baz', 1})"))
  387. eq(false, exec_lua("return vim.tbl_islist({1, 2, nil, a='hello'})"))
  388. end)
  389. it('vim.tbl_isempty', function()
  390. eq(true, exec_lua("return vim.tbl_isempty({})"))
  391. eq(false, exec_lua("return vim.tbl_isempty({ 1, 2, 3 })"))
  392. eq(false, exec_lua("return vim.tbl_isempty({a=1, b=2, c=3})"))
  393. end)
  394. it('vim.tbl_extend', function()
  395. ok(exec_lua([[
  396. local a = {x = 1}
  397. local b = {y = 2}
  398. local c = vim.tbl_extend("keep", a, b)
  399. return c.x == 1 and b.y == 2 and vim.tbl_count(c) == 2
  400. ]]))
  401. ok(exec_lua([[
  402. local a = {x = 1}
  403. local b = {y = 2}
  404. local c = {z = 3}
  405. local d = vim.tbl_extend("keep", a, b, c)
  406. return d.x == 1 and d.y == 2 and d.z == 3 and vim.tbl_count(d) == 3
  407. ]]))
  408. ok(exec_lua([[
  409. local a = {x = 1}
  410. local b = {x = 3}
  411. local c = vim.tbl_extend("keep", a, b)
  412. return c.x == 1 and vim.tbl_count(c) == 1
  413. ]]))
  414. ok(exec_lua([[
  415. local a = {x = 1}
  416. local b = {x = 3}
  417. local c = vim.tbl_extend("force", a, b)
  418. return c.x == 3 and vim.tbl_count(c) == 1
  419. ]]))
  420. ok(exec_lua([[
  421. local a = vim.empty_dict()
  422. local b = {}
  423. local c = vim.tbl_extend("keep", a, b)
  424. return not vim.tbl_islist(c) and vim.tbl_count(c) == 0
  425. ]]))
  426. ok(exec_lua([[
  427. local a = {}
  428. local b = vim.empty_dict()
  429. local c = vim.tbl_extend("keep", a, b)
  430. return vim.tbl_islist(c) and vim.tbl_count(c) == 0
  431. ]]))
  432. ok(exec_lua([[
  433. local a = {x = {a = 1, b = 2}}
  434. local b = {x = {a = 2, c = {y = 3}}}
  435. local c = vim.tbl_extend("keep", a, b)
  436. local count = 0
  437. for _ in pairs(c) do count = count + 1 end
  438. return c.x.a == 1 and c.x.b == 2 and c.x.c == nil and count == 1
  439. ]]))
  440. eq('Error executing lua: vim/shared.lua:0: invalid "behavior": nil',
  441. pcall_err(exec_lua, [[
  442. return vim.tbl_extend()
  443. ]])
  444. )
  445. eq('Error executing lua: vim/shared.lua:0: wrong number of arguments (given 1, expected at least 3)',
  446. pcall_err(exec_lua, [[
  447. return vim.tbl_extend("keep")
  448. ]])
  449. )
  450. eq('Error executing lua: vim/shared.lua:0: wrong number of arguments (given 2, expected at least 3)',
  451. pcall_err(exec_lua, [[
  452. return vim.tbl_extend("keep", {})
  453. ]])
  454. )
  455. end)
  456. it('vim.tbl_deep_extend', function()
  457. ok(exec_lua([[
  458. local a = {x = {a = 1, b = 2}}
  459. local b = {x = {a = 2, c = {y = 3}}}
  460. local c = vim.tbl_deep_extend("keep", a, b)
  461. local count = 0
  462. for _ in pairs(c) do count = count + 1 end
  463. return c.x.a == 1 and c.x.b == 2 and c.x.c.y == 3 and count == 1
  464. ]]))
  465. ok(exec_lua([[
  466. local a = {x = {a = 1, b = 2}}
  467. local b = {x = {a = 2, c = {y = 3}}}
  468. local c = vim.tbl_deep_extend("force", a, b)
  469. local count = 0
  470. for _ in pairs(c) do count = count + 1 end
  471. return c.x.a == 2 and c.x.b == 2 and c.x.c.y == 3 and count == 1
  472. ]]))
  473. ok(exec_lua([[
  474. local a = {x = {a = 1, b = 2}}
  475. local b = {x = {a = 2, c = {y = 3}}}
  476. local c = {x = {c = 4, d = {y = 4}}}
  477. local d = vim.tbl_deep_extend("keep", a, b, c)
  478. local count = 0
  479. for _ in pairs(c) do count = count + 1 end
  480. return d.x.a == 1 and d.x.b == 2 and d.x.c.y == 3 and d.x.d.y == 4 and count == 1
  481. ]]))
  482. ok(exec_lua([[
  483. local a = {x = {a = 1, b = 2}}
  484. local b = {x = {a = 2, c = {y = 3}}}
  485. local c = {x = {c = 4, d = {y = 4}}}
  486. local d = vim.tbl_deep_extend("force", a, b, c)
  487. local count = 0
  488. for _ in pairs(c) do count = count + 1 end
  489. return d.x.a == 2 and d.x.b == 2 and d.x.c == 4 and d.x.d.y == 4 and count == 1
  490. ]]))
  491. ok(exec_lua([[
  492. local a = vim.empty_dict()
  493. local b = {}
  494. local c = vim.tbl_deep_extend("keep", a, b)
  495. local count = 0
  496. for _ in pairs(c) do count = count + 1 end
  497. return not vim.tbl_islist(c) and count == 0
  498. ]]))
  499. ok(exec_lua([[
  500. local a = {}
  501. local b = vim.empty_dict()
  502. local c = vim.tbl_deep_extend("keep", a, b)
  503. local count = 0
  504. for _ in pairs(c) do count = count + 1 end
  505. return vim.tbl_islist(c) and count == 0
  506. ]]))
  507. eq('Error executing lua: vim/shared.lua:0: invalid "behavior": nil',
  508. pcall_err(exec_lua, [[
  509. return vim.tbl_deep_extend()
  510. ]])
  511. )
  512. eq('Error executing lua: vim/shared.lua:0: wrong number of arguments (given 1, expected at least 3)',
  513. pcall_err(exec_lua, [[
  514. return vim.tbl_deep_extend("keep")
  515. ]])
  516. )
  517. eq('Error executing lua: vim/shared.lua:0: wrong number of arguments (given 2, expected at least 3)',
  518. pcall_err(exec_lua, [[
  519. return vim.tbl_deep_extend("keep", {})
  520. ]])
  521. )
  522. end)
  523. it('vim.tbl_count', function()
  524. eq(0, exec_lua [[ return vim.tbl_count({}) ]])
  525. eq(0, exec_lua [[ return vim.tbl_count(vim.empty_dict()) ]])
  526. eq(0, exec_lua [[ return vim.tbl_count({nil}) ]])
  527. eq(0, exec_lua [[ return vim.tbl_count({a=nil}) ]])
  528. eq(1, exec_lua [[ return vim.tbl_count({1}) ]])
  529. eq(2, exec_lua [[ return vim.tbl_count({1, 2}) ]])
  530. eq(2, exec_lua [[ return vim.tbl_count({1, nil, 3}) ]])
  531. eq(1, exec_lua [[ return vim.tbl_count({a=1}) ]])
  532. eq(2, exec_lua [[ return vim.tbl_count({a=1, b=2}) ]])
  533. eq(2, exec_lua [[ return vim.tbl_count({a=1, b=nil, c=3}) ]])
  534. end)
  535. it('vim.deep_equal', function()
  536. eq(true, exec_lua [[ return vim.deep_equal({a=1}, {a=1}) ]])
  537. eq(true, exec_lua [[ return vim.deep_equal({a={b=1}}, {a={b=1}}) ]])
  538. eq(true, exec_lua [[ return vim.deep_equal({a={b={nil}}}, {a={b={}}}) ]])
  539. eq(true, exec_lua [[ return vim.deep_equal({a=1, [5]=5}, {nil,nil,nil,nil,5,a=1}) ]])
  540. eq(false, exec_lua [[ return vim.deep_equal(1, {nil,nil,nil,nil,5,a=1}) ]])
  541. eq(false, exec_lua [[ return vim.deep_equal(1, 3) ]])
  542. eq(false, exec_lua [[ return vim.deep_equal(nil, 3) ]])
  543. eq(false, exec_lua [[ return vim.deep_equal({a=1}, {a=2}) ]])
  544. end)
  545. it('vim.list_extend', function()
  546. eq({1,2,3}, exec_lua [[ return vim.list_extend({1}, {2,3}) ]])
  547. eq(dedent([[
  548. Error executing lua: vim/shared.lua:0: src: expected table, got nil
  549. stack traceback:
  550. vim/shared.lua:0: in function <vim/shared.lua:0>]]),
  551. pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]]))
  552. eq({1,2}, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]])
  553. eq(true, exec_lua [[ local a = {1} return vim.list_extend(a, {2;a=1}) == a ]])
  554. eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1) ]])
  555. eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 2) ]])
  556. eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1, -1) ]])
  557. eq({2}, exec_lua [[ return vim.list_extend({}, {2;a=1}, -1, 2) ]])
  558. end)
  559. it('vim.tbl_add_reverse_lookup', function()
  560. eq(true, exec_lua [[
  561. local a = { A = 1 }
  562. vim.tbl_add_reverse_lookup(a)
  563. return vim.deep_equal(a, { A = 1; [1] = 'A'; })
  564. ]])
  565. -- Throw an error for trying to do it twice (run into an existing key)
  566. local code = [[
  567. local res = {}
  568. local a = { A = 1 }
  569. vim.tbl_add_reverse_lookup(a)
  570. assert(vim.deep_equal(a, { A = 1; [1] = 'A'; }))
  571. vim.tbl_add_reverse_lookup(a)
  572. ]]
  573. matches('^Error executing lua: vim/shared%.lua:0: The reverse lookup found an existing value for "[1A]" while processing key "[1A]"$',
  574. pcall_err(exec_lua, code))
  575. end)
  576. it('vim.call, vim.fn', function()
  577. eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]]))
  578. eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]]))
  579. -- compat: nvim_call_function uses "special" value for vimL float
  580. eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]]))
  581. source([[
  582. func! FooFunc(test)
  583. let g:test = a:test
  584. return {}
  585. endfunc
  586. func! VarArg(...)
  587. return a:000
  588. endfunc
  589. func! Nilly()
  590. return [v:null, v:null]
  591. endfunc
  592. ]])
  593. eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]]))
  594. eq(3, eval("g:test"))
  595. -- compat: nvim_call_function uses "special" value for empty dict
  596. eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]]))
  597. eq(5, eval("g:test"))
  598. eq({2, "foo", true}, exec_lua([[return vim.fn.VarArg(2, "foo", true)]]))
  599. eq(true, exec_lua([[
  600. local x = vim.fn.Nilly()
  601. return #x == 2 and x[1] == vim.NIL and x[2] == vim.NIL
  602. ]]))
  603. eq({NIL, NIL}, exec_lua([[return vim.fn.Nilly()]]))
  604. -- error handling
  605. eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]]))
  606. end)
  607. it('vim.fn should error when calling API function', function()
  608. eq('Error executing lua: vim.lua:0: Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead',
  609. pcall_err(exec_lua, "vim.fn.nvim_get_current_line()"))
  610. end)
  611. it('vim.rpcrequest and vim.rpcnotify', function()
  612. exec_lua([[
  613. chan = vim.fn.jobstart({'cat'}, {rpc=true})
  614. vim.rpcrequest(chan, 'nvim_set_current_line', 'meow')
  615. ]])
  616. eq('meow', meths.get_current_line())
  617. command("let x = [3, 'aa', v:true, v:null]")
  618. eq(true, exec_lua([[
  619. ret = vim.rpcrequest(chan, 'nvim_get_var', 'x')
  620. return #ret == 4 and ret[1] == 3 and ret[2] == 'aa' and ret[3] == true and ret[4] == vim.NIL
  621. ]]))
  622. eq({3, 'aa', true, NIL}, exec_lua([[return ret]]))
  623. eq({{}, {}, false, true}, exec_lua([[
  624. vim.rpcrequest(chan, 'nvim_exec', 'let xx = {}\nlet yy = []', false)
  625. local dict = vim.rpcrequest(chan, 'nvim_eval', 'xx')
  626. local list = vim.rpcrequest(chan, 'nvim_eval', 'yy')
  627. return {dict, list, vim.tbl_islist(dict), vim.tbl_islist(list)}
  628. ]]))
  629. exec_lua([[
  630. vim.rpcrequest(chan, 'nvim_set_var', 'aa', {})
  631. vim.rpcrequest(chan, 'nvim_set_var', 'bb', vim.empty_dict())
  632. ]])
  633. eq({1, 1}, eval('[type(g:aa) == type([]), type(g:bb) == type({})]'))
  634. -- error handling
  635. eq({false, 'Invalid channel: 23'},
  636. exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]]))
  637. eq({false, 'Invalid channel: 23'},
  638. exec_lua([[return {pcall(vim.rpcnotify, 23, 'foo')}]]))
  639. eq({false, 'Vim:E121: Undefined variable: foobar'},
  640. exec_lua([[return {pcall(vim.rpcrequest, chan, 'nvim_eval', "foobar")}]]))
  641. -- rpcnotify doesn't wait on request
  642. eq('meow', exec_lua([[
  643. vim.rpcnotify(chan, 'nvim_set_current_line', 'foo')
  644. return vim.api.nvim_get_current_line()
  645. ]]))
  646. retry(10, nil, function()
  647. eq('foo', meths.get_current_line())
  648. end)
  649. local screen = Screen.new(50,7)
  650. screen:set_default_attr_ids({
  651. [1] = {bold = true, foreground = Screen.colors.Blue1},
  652. [2] = {bold = true, reverse = true},
  653. [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
  654. [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
  655. })
  656. screen:attach()
  657. exec_lua([[
  658. timer = vim.loop.new_timer()
  659. timer:start(20, 0, function ()
  660. -- notify ok (executed later when safe)
  661. vim.rpcnotify(chan, 'nvim_set_var', 'yy', {3, vim.NIL})
  662. -- rpcrequest an error
  663. vim.rpcrequest(chan, 'nvim_set_current_line', 'bork')
  664. end)
  665. ]])
  666. screen:expect{grid=[[
  667. foo |
  668. {1:~ }|
  669. {2: }|
  670. {3:Error executing luv callback:} |
  671. {3:[string "<nvim>"]:6: E5560: rpcrequest must not be}|
  672. {3: called in a lua loop callback} |
  673. {4:Press ENTER or type command to continue}^ |
  674. ]]}
  675. feed('<cr>')
  676. eq({3, NIL}, meths.get_var('yy'))
  677. exec_lua([[timer:close()]])
  678. end)
  679. it('vim.empty_dict()', function()
  680. eq({true, false, true, true}, exec_lua([[
  681. vim.api.nvim_set_var('listy', {})
  682. vim.api.nvim_set_var('dicty', vim.empty_dict())
  683. local listy = vim.fn.eval("listy")
  684. local dicty = vim.fn.eval("dicty")
  685. return {vim.tbl_islist(listy), vim.tbl_islist(dicty), next(listy) == nil, next(dicty) == nil}
  686. ]]))
  687. -- vim.empty_dict() gives new value each time
  688. -- equality is not overriden (still by ref)
  689. -- non-empty table uses the usual heuristics (ignores the tag)
  690. eq({false, {"foo"}, {namey="bar"}}, exec_lua([[
  691. local aa = vim.empty_dict()
  692. local bb = vim.empty_dict()
  693. local equally = (aa == bb)
  694. aa[1] = "foo"
  695. bb["namey"] = "bar"
  696. return {equally, aa, bb}
  697. ]]))
  698. eq("{ {}, vim.empty_dict() }", exec_lua("return vim.inspect({{}, vim.empty_dict()})"))
  699. eq('{}', exec_lua([[ return vim.fn.json_encode(vim.empty_dict()) ]]))
  700. eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]]))
  701. end)
  702. it('vim.validate', function()
  703. exec_lua("vim.validate{arg1={{}, 'table' }}")
  704. exec_lua("vim.validate{arg1={{}, 't' }}")
  705. exec_lua("vim.validate{arg1={nil, 't', true }}")
  706. exec_lua("vim.validate{arg1={{ foo='foo' }, 't' }}")
  707. exec_lua("vim.validate{arg1={{ 'foo' }, 't' }}")
  708. exec_lua("vim.validate{arg1={'foo', 'string' }}")
  709. exec_lua("vim.validate{arg1={'foo', 's' }}")
  710. exec_lua("vim.validate{arg1={'', 's' }}")
  711. exec_lua("vim.validate{arg1={nil, 's', true }}")
  712. exec_lua("vim.validate{arg1={1, 'number' }}")
  713. exec_lua("vim.validate{arg1={1, 'n' }}")
  714. exec_lua("vim.validate{arg1={0, 'n' }}")
  715. exec_lua("vim.validate{arg1={0.1, 'n' }}")
  716. exec_lua("vim.validate{arg1={nil, 'n', true }}")
  717. exec_lua("vim.validate{arg1={true, 'boolean' }}")
  718. exec_lua("vim.validate{arg1={true, 'b' }}")
  719. exec_lua("vim.validate{arg1={false, 'b' }}")
  720. exec_lua("vim.validate{arg1={nil, 'b', true }}")
  721. exec_lua("vim.validate{arg1={function()end, 'function' }}")
  722. exec_lua("vim.validate{arg1={function()end, 'f' }}")
  723. exec_lua("vim.validate{arg1={nil, 'f', true }}")
  724. exec_lua("vim.validate{arg1={nil, 'nil' }}")
  725. exec_lua("vim.validate{arg1={nil, 'nil', true }}")
  726. exec_lua("vim.validate{arg1={coroutine.create(function()end), 'thread' }}")
  727. exec_lua("vim.validate{arg1={nil, 'thread', true }}")
  728. exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}")
  729. exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}")
  730. eq(dedent([[
  731. Error executing lua: [string "<nvim>"]:0: opt[1]: expected table, got number
  732. stack traceback:
  733. [string "<nvim>"]:0: in main chunk]]),
  734. pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
  735. eq(dedent([[
  736. Error executing lua: [string "<nvim>"]:0: invalid type name: x
  737. stack traceback:
  738. [string "<nvim>"]:0: in main chunk]]),
  739. pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
  740. eq(dedent([[
  741. Error executing lua: [string "<nvim>"]:0: invalid type name: 1
  742. stack traceback:
  743. [string "<nvim>"]:0: in main chunk]]),
  744. pcall_err(exec_lua, "vim.validate{ arg1={ 1, 1 }}"))
  745. eq(dedent([[
  746. Error executing lua: [string "<nvim>"]:0: invalid type name: nil
  747. stack traceback:
  748. [string "<nvim>"]:0: in main chunk]]),
  749. pcall_err(exec_lua, "vim.validate{ arg1={ 1 }}"))
  750. -- Validated parameters are required by default.
  751. eq(dedent([[
  752. Error executing lua: [string "<nvim>"]:0: arg1: expected string, got nil
  753. stack traceback:
  754. [string "<nvim>"]:0: in main chunk]]),
  755. pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's' }}"))
  756. -- Explicitly required.
  757. eq(dedent([[
  758. Error executing lua: [string "<nvim>"]:0: arg1: expected string, got nil
  759. stack traceback:
  760. [string "<nvim>"]:0: in main chunk]]),
  761. pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's', false }}"))
  762. eq(dedent([[
  763. Error executing lua: [string "<nvim>"]:0: arg1: expected table, got number
  764. stack traceback:
  765. [string "<nvim>"]:0: in main chunk]]),
  766. pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}"))
  767. eq(dedent([[
  768. Error executing lua: [string "<nvim>"]:0: arg2: expected string, got number
  769. stack traceback:
  770. [string "<nvim>"]:0: in main chunk]]),
  771. pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}"))
  772. eq(dedent([[
  773. Error executing lua: [string "<nvim>"]:0: arg2: expected string, got nil
  774. stack traceback:
  775. [string "<nvim>"]:0: in main chunk]]),
  776. pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
  777. eq(dedent([[
  778. Error executing lua: [string "<nvim>"]:0: arg2: expected string, got nil
  779. stack traceback:
  780. [string "<nvim>"]:0: in main chunk]]),
  781. pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}"))
  782. eq(dedent([[
  783. Error executing lua: [string "<nvim>"]:0: arg1: expected even number, got 3
  784. stack traceback:
  785. [string "<nvim>"]:0: in main chunk]]),
  786. pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}"))
  787. eq(dedent([[
  788. Error executing lua: [string "<nvim>"]:0: arg1: expected ?, got 3
  789. stack traceback:
  790. [string "<nvim>"]:0: in main chunk]]),
  791. pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}"))
  792. -- Pass an additional message back.
  793. eq(dedent([[
  794. Error executing lua: [string "<nvim>"]:0: arg1: expected ?, got 3. Info: TEST_MSG
  795. stack traceback:
  796. [string "<nvim>"]:0: in main chunk]]),
  797. pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1, 'TEST_MSG' end}}"))
  798. end)
  799. it('vim.is_callable', function()
  800. eq(true, exec_lua("return vim.is_callable(function()end)"))
  801. eq(true, exec_lua([[
  802. local meta = { __call = function()end }
  803. local function new_callable()
  804. return setmetatable({}, meta)
  805. end
  806. local callable = new_callable()
  807. return vim.is_callable(callable)
  808. ]]))
  809. eq(false, exec_lua("return vim.is_callable(1)"))
  810. eq(false, exec_lua("return vim.is_callable('foo')"))
  811. eq(false, exec_lua("return vim.is_callable({})"))
  812. end)
  813. it('vim.g', function()
  814. exec_lua [[
  815. vim.api.nvim_set_var("testing", "hi")
  816. vim.api.nvim_set_var("other", 123)
  817. vim.api.nvim_set_var("floaty", 5120.1)
  818. vim.api.nvim_set_var("nullvar", vim.NIL)
  819. vim.api.nvim_set_var("to_delete", {hello="world"})
  820. ]]
  821. eq('hi', funcs.luaeval "vim.g.testing")
  822. eq(123, funcs.luaeval "vim.g.other")
  823. eq(5120.1, funcs.luaeval "vim.g.floaty")
  824. eq(NIL, funcs.luaeval "vim.g.nonexistant")
  825. eq(NIL, funcs.luaeval "vim.g.nullvar")
  826. -- lost over RPC, so test locally:
  827. eq({false, true}, exec_lua [[
  828. return {vim.g.nonexistant == vim.NIL, vim.g.nullvar == vim.NIL}
  829. ]])
  830. eq({hello="world"}, funcs.luaeval "vim.g.to_delete")
  831. exec_lua [[
  832. vim.g.to_delete = nil
  833. ]]
  834. eq(NIL, funcs.luaeval "vim.g.to_delete")
  835. end)
  836. it('vim.b', function()
  837. exec_lua [[
  838. vim.api.nvim_buf_set_var(0, "testing", "hi")
  839. vim.api.nvim_buf_set_var(0, "other", 123)
  840. vim.api.nvim_buf_set_var(0, "floaty", 5120.1)
  841. vim.api.nvim_buf_set_var(0, "nullvar", vim.NIL)
  842. vim.api.nvim_buf_set_var(0, "to_delete", {hello="world"})
  843. ]]
  844. eq('hi', funcs.luaeval "vim.b.testing")
  845. eq(123, funcs.luaeval "vim.b.other")
  846. eq(5120.1, funcs.luaeval "vim.b.floaty")
  847. eq(NIL, funcs.luaeval "vim.b.nonexistant")
  848. eq(NIL, funcs.luaeval "vim.b.nullvar")
  849. -- lost over RPC, so test locally:
  850. eq({false, true}, exec_lua [[
  851. return {vim.b.nonexistant == vim.NIL, vim.b.nullvar == vim.NIL}
  852. ]])
  853. eq({hello="world"}, funcs.luaeval "vim.b.to_delete")
  854. exec_lua [[
  855. vim.b.to_delete = nil
  856. ]]
  857. eq(NIL, funcs.luaeval "vim.b.to_delete")
  858. exec_lua [[
  859. vim.cmd "vnew"
  860. ]]
  861. eq(NIL, funcs.luaeval "vim.b.testing")
  862. eq(NIL, funcs.luaeval "vim.b.other")
  863. eq(NIL, funcs.luaeval "vim.b.nonexistant")
  864. end)
  865. it('vim.w', function()
  866. exec_lua [[
  867. vim.api.nvim_win_set_var(0, "testing", "hi")
  868. vim.api.nvim_win_set_var(0, "other", 123)
  869. vim.api.nvim_win_set_var(0, "to_delete", {hello="world"})
  870. ]]
  871. eq('hi', funcs.luaeval "vim.w.testing")
  872. eq(123, funcs.luaeval "vim.w.other")
  873. eq(NIL, funcs.luaeval "vim.w.nonexistant")
  874. eq({hello="world"}, funcs.luaeval "vim.w.to_delete")
  875. exec_lua [[
  876. vim.w.to_delete = nil
  877. ]]
  878. eq(NIL, funcs.luaeval "vim.w.to_delete")
  879. exec_lua [[
  880. vim.cmd "vnew"
  881. ]]
  882. eq(NIL, funcs.luaeval "vim.w.testing")
  883. eq(NIL, funcs.luaeval "vim.w.other")
  884. eq(NIL, funcs.luaeval "vim.w.nonexistant")
  885. end)
  886. it('vim.t', function()
  887. exec_lua [[
  888. vim.api.nvim_tabpage_set_var(0, "testing", "hi")
  889. vim.api.nvim_tabpage_set_var(0, "other", 123)
  890. vim.api.nvim_tabpage_set_var(0, "to_delete", {hello="world"})
  891. ]]
  892. eq('hi', funcs.luaeval "vim.t.testing")
  893. eq(123, funcs.luaeval "vim.t.other")
  894. eq(NIL, funcs.luaeval "vim.t.nonexistant")
  895. eq({hello="world"}, funcs.luaeval "vim.t.to_delete")
  896. exec_lua [[
  897. vim.t.to_delete = nil
  898. ]]
  899. eq(NIL, funcs.luaeval "vim.t.to_delete")
  900. exec_lua [[
  901. vim.cmd "tabnew"
  902. ]]
  903. eq(NIL, funcs.luaeval "vim.t.testing")
  904. eq(NIL, funcs.luaeval "vim.t.other")
  905. eq(NIL, funcs.luaeval "vim.t.nonexistant")
  906. end)
  907. it('vim.env', function()
  908. exec_lua [[
  909. vim.fn.setenv("A", 123)
  910. ]]
  911. eq('123', funcs.luaeval "vim.env.A")
  912. eq(true, funcs.luaeval "vim.env.B == nil")
  913. end)
  914. it('vim.v', function()
  915. eq(funcs.luaeval "vim.api.nvim_get_vvar('progpath')", funcs.luaeval "vim.v.progpath")
  916. eq(false, funcs.luaeval "vim.v['false']")
  917. eq(NIL, funcs.luaeval "vim.v.null")
  918. end)
  919. it('vim.bo', function()
  920. eq('', funcs.luaeval "vim.bo.filetype")
  921. exec_lua [[
  922. vim.api.nvim_buf_set_option(0, "filetype", "markdown")
  923. BUF = vim.api.nvim_create_buf(false, true)
  924. vim.api.nvim_buf_set_option(BUF, "modifiable", false)
  925. ]]
  926. eq(false, funcs.luaeval "vim.bo.modified")
  927. eq('markdown', funcs.luaeval "vim.bo.filetype")
  928. eq(false, funcs.luaeval "vim.bo[BUF].modifiable")
  929. exec_lua [[
  930. vim.bo.filetype = ''
  931. vim.bo[BUF].modifiable = true
  932. ]]
  933. eq('', funcs.luaeval "vim.bo.filetype")
  934. eq(true, funcs.luaeval "vim.bo[BUF].modifiable")
  935. matches("^Error executing lua: .*: Invalid option name: 'nosuchopt'$",
  936. pcall_err(exec_lua, 'return vim.bo.nosuchopt'))
  937. matches("^Error executing lua: .*: Expected lua string$",
  938. pcall_err(exec_lua, 'return vim.bo[0][0].autoread'))
  939. end)
  940. it('vim.wo', function()
  941. exec_lua [[
  942. vim.api.nvim_win_set_option(0, "cole", 2)
  943. vim.cmd "split"
  944. vim.api.nvim_win_set_option(0, "cole", 2)
  945. ]]
  946. eq(2, funcs.luaeval "vim.wo.cole")
  947. exec_lua [[
  948. vim.wo.conceallevel = 0
  949. ]]
  950. eq(0, funcs.luaeval "vim.wo.cole")
  951. eq(0, funcs.luaeval "vim.wo[0].cole")
  952. eq(0, funcs.luaeval "vim.wo[1001].cole")
  953. matches("^Error executing lua: .*: Invalid option name: 'notanopt'$",
  954. pcall_err(exec_lua, 'return vim.wo.notanopt'))
  955. matches("^Error executing lua: .*: Expected lua string$",
  956. pcall_err(exec_lua, 'return vim.wo[0][0].list'))
  957. eq(2, funcs.luaeval "vim.wo[1000].cole")
  958. exec_lua [[
  959. vim.wo[1000].cole = 0
  960. ]]
  961. eq(0, funcs.luaeval "vim.wo[1000].cole")
  962. end)
  963. describe('vim.opt', function()
  964. -- TODO: We still need to write some tests for optlocal, opt and then getting the options
  965. -- Probably could also do some stuff with getting things from viml side as well to confirm behavior is the same.
  966. it('should allow setting number values', function()
  967. local scrolloff = exec_lua [[
  968. vim.opt.scrolloff = 10
  969. return vim.o.scrolloff
  970. ]]
  971. eq(scrolloff, 10)
  972. end)
  973. pending('should handle STUPID window things', function()
  974. local result = exec_lua [[
  975. local result = {}
  976. table.insert(result, vim.api.nvim_get_option('scrolloff'))
  977. table.insert(result, vim.api.nvim_win_get_option(0, 'scrolloff'))
  978. return result
  979. ]]
  980. eq({}, result)
  981. end)
  982. it('should allow setting tables', function()
  983. local wildignore = exec_lua [[
  984. vim.opt.wildignore = { 'hello', 'world' }
  985. return vim.o.wildignore
  986. ]]
  987. eq(wildignore, "hello,world")
  988. end)
  989. it('should allow setting tables with shortnames', function()
  990. local wildignore = exec_lua [[
  991. vim.opt.wig = { 'hello', 'world' }
  992. return vim.o.wildignore
  993. ]]
  994. eq(wildignore, "hello,world")
  995. end)
  996. it('should error when you attempt to set string values to numeric options', function()
  997. local result = exec_lua [[
  998. return {
  999. pcall(function() vim.opt.textwidth = 'hello world' end)
  1000. }
  1001. ]]
  1002. eq(false, result[1])
  1003. end)
  1004. it('should error when you attempt to setlocal a global value', function()
  1005. local result = exec_lua [[
  1006. return pcall(function() vim.opt_local.clipboard = "hello" end)
  1007. ]]
  1008. eq(false, result)
  1009. end)
  1010. it('should allow you to set boolean values', function()
  1011. eq({true, false, true}, exec_lua [[
  1012. local results = {}
  1013. vim.opt.autoindent = true
  1014. table.insert(results, vim.bo.autoindent)
  1015. vim.opt.autoindent = false
  1016. table.insert(results, vim.bo.autoindent)
  1017. vim.opt.autoindent = not vim.opt.autoindent:get()
  1018. table.insert(results, vim.bo.autoindent)
  1019. return results
  1020. ]])
  1021. end)
  1022. it('should change current buffer values and defaults for global local values', function()
  1023. local result = exec_lua [[
  1024. local result = {}
  1025. vim.opt.makeprg = "global-local"
  1026. table.insert(result, vim.api.nvim_get_option('makeprg'))
  1027. table.insert(result, (pcall(vim.api.nvim_buf_get_option, 0, 'makeprg')))
  1028. vim.opt_local.mp = "only-local"
  1029. table.insert(result, vim.api.nvim_get_option('makeprg'))
  1030. table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg'))
  1031. vim.opt_global.makeprg = "only-global"
  1032. table.insert(result, vim.api.nvim_get_option('makeprg'))
  1033. table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg'))
  1034. vim.opt.makeprg = "global-local"
  1035. table.insert(result, vim.api.nvim_get_option('makeprg'))
  1036. table.insert(result, vim.api.nvim_buf_get_option(0, 'makeprg'))
  1037. return result
  1038. ]]
  1039. -- Set -> global & local
  1040. eq("global-local", result[1])
  1041. eq(false, result[2])
  1042. -- Setlocal -> only local
  1043. eq("global-local", result[3])
  1044. eq("only-local", result[4])
  1045. -- Setglobal -> only global
  1046. eq("only-global", result[5])
  1047. eq("only-local", result[6])
  1048. -- set -> doesn't override previously set value
  1049. eq("global-local", result[7])
  1050. eq("only-local", result[8])
  1051. end)
  1052. it('should allow you to retrieve window opts even if they have not been set', function()
  1053. local result = exec_lua [[
  1054. local result = {}
  1055. table.insert(result, vim.opt.number:get())
  1056. table.insert(result, vim.opt_local.number:get())
  1057. vim.opt_local.number = true
  1058. table.insert(result, vim.opt.number:get())
  1059. table.insert(result, vim.opt_local.number:get())
  1060. return result
  1061. ]]
  1062. eq({false, false, true, true}, result)
  1063. end)
  1064. it('should allow all sorts of string manipulation', function()
  1065. eq({'hello', 'hello world', 'start hello world'}, exec_lua [[
  1066. local results = {}
  1067. vim.opt.makeprg = "hello"
  1068. table.insert(results, vim.o.makeprg)
  1069. vim.opt.makeprg = vim.opt.makeprg + " world"
  1070. table.insert(results, vim.o.makeprg)
  1071. vim.opt.makeprg = vim.opt.makeprg ^ "start "
  1072. table.insert(results, vim.o.makeprg)
  1073. return results
  1074. ]])
  1075. end)
  1076. describe('option:get()', function()
  1077. it('should work for boolean values', function()
  1078. eq(false, exec_lua [[
  1079. vim.opt.number = false
  1080. return vim.opt.number:get()
  1081. ]])
  1082. end)
  1083. it('should work for number values', function()
  1084. local tabstop = exec_lua[[
  1085. vim.opt.tabstop = 10
  1086. return vim.opt.tabstop:get()
  1087. ]]
  1088. eq(10, tabstop)
  1089. end)
  1090. it('should work for string values', function()
  1091. eq("hello world", exec_lua [[
  1092. vim.opt.makeprg = "hello world"
  1093. return vim.opt.makeprg:get()
  1094. ]])
  1095. end)
  1096. it('should work for set type flaglists', function()
  1097. local formatoptions = exec_lua [[
  1098. vim.opt.formatoptions = 'tcro'
  1099. return vim.opt.formatoptions:get()
  1100. ]]
  1101. eq(true, formatoptions.t)
  1102. eq(true, not formatoptions.q)
  1103. end)
  1104. it('should work for set type flaglists', function()
  1105. local formatoptions = exec_lua [[
  1106. vim.opt.formatoptions = { t = true, c = true, r = true, o = true }
  1107. return vim.opt.formatoptions:get()
  1108. ]]
  1109. eq(true, formatoptions.t)
  1110. eq(true, not formatoptions.q)
  1111. end)
  1112. it('should work for array list type options', function()
  1113. local wildignore = exec_lua [[
  1114. vim.opt.wildignore = "*.c,*.o,__pycache__"
  1115. return vim.opt.wildignore:get()
  1116. ]]
  1117. eq(3, #wildignore)
  1118. eq("*.c", wildignore[1])
  1119. end)
  1120. it('should work for options that are both commalist and flaglist', function()
  1121. local result = exec_lua [[
  1122. vim.opt.whichwrap = "b,s"
  1123. return vim.opt.whichwrap:get()
  1124. ]]
  1125. eq({b = true, s = true}, result)
  1126. result = exec_lua [[
  1127. vim.opt.whichwrap = { b = true, s = false, h = true }
  1128. return vim.opt.whichwrap:get()
  1129. ]]
  1130. eq({b = true, h = true}, result)
  1131. end)
  1132. it('should work for key-value pair options', function()
  1133. local listchars = exec_lua [[
  1134. vim.opt.listchars = "tab:> ,space:_"
  1135. return vim.opt.listchars:get()
  1136. ]]
  1137. eq({
  1138. tab = "> ",
  1139. space = "_",
  1140. }, listchars)
  1141. end)
  1142. it('should allow you to add numeric options', function()
  1143. eq(16, exec_lua [[
  1144. vim.opt.tabstop = 12
  1145. vim.opt.tabstop = vim.opt.tabstop + 4
  1146. return vim.bo.tabstop
  1147. ]])
  1148. end)
  1149. it('should allow you to subtract numeric options', function()
  1150. eq(2, exec_lua [[
  1151. vim.opt.tabstop = 4
  1152. vim.opt.tabstop = vim.opt.tabstop - 2
  1153. return vim.bo.tabstop
  1154. ]])
  1155. end)
  1156. end)
  1157. describe('key:value style options', function()
  1158. it('should handle dictionary style', function()
  1159. local listchars = exec_lua [[
  1160. vim.opt.listchars = {
  1161. eol = "~",
  1162. space = ".",
  1163. }
  1164. return vim.o.listchars
  1165. ]]
  1166. eq("eol:~,space:.", listchars)
  1167. end)
  1168. it('should allow adding dictionary style', function()
  1169. local listchars = exec_lua [[
  1170. vim.opt.listchars = {
  1171. eol = "~",
  1172. space = ".",
  1173. }
  1174. vim.opt.listchars = vim.opt.listchars + { space = "-" }
  1175. return vim.o.listchars
  1176. ]]
  1177. eq("eol:~,space:-", listchars)
  1178. end)
  1179. it('should allow adding dictionary style', function()
  1180. local listchars = exec_lua [[
  1181. vim.opt.listchars = {
  1182. eol = "~",
  1183. space = ".",
  1184. }
  1185. vim.opt.listchars = vim.opt.listchars + { space = "-" } + { space = "_" }
  1186. return vim.o.listchars
  1187. ]]
  1188. eq("eol:~,space:_", listchars)
  1189. end)
  1190. it('should allow completely new keys', function()
  1191. local listchars = exec_lua [[
  1192. vim.opt.listchars = {
  1193. eol = "~",
  1194. space = ".",
  1195. }
  1196. vim.opt.listchars = vim.opt.listchars + { tab = ">>>" }
  1197. return vim.o.listchars
  1198. ]]
  1199. eq("eol:~,space:.,tab:>>>", listchars)
  1200. end)
  1201. it('should allow subtracting dictionary style', function()
  1202. local listchars = exec_lua [[
  1203. vim.opt.listchars = {
  1204. eol = "~",
  1205. space = ".",
  1206. }
  1207. vim.opt.listchars = vim.opt.listchars - "space"
  1208. return vim.o.listchars
  1209. ]]
  1210. eq("eol:~", listchars)
  1211. end)
  1212. it('should allow subtracting dictionary style', function()
  1213. local listchars = exec_lua [[
  1214. vim.opt.listchars = {
  1215. eol = "~",
  1216. space = ".",
  1217. }
  1218. vim.opt.listchars = vim.opt.listchars - "space" - "eol"
  1219. return vim.o.listchars
  1220. ]]
  1221. eq("", listchars)
  1222. end)
  1223. it('should allow subtracting dictionary style multiple times', function()
  1224. local listchars = exec_lua [[
  1225. vim.opt.listchars = {
  1226. eol = "~",
  1227. space = ".",
  1228. }
  1229. vim.opt.listchars = vim.opt.listchars - "space" - "space"
  1230. return vim.o.listchars
  1231. ]]
  1232. eq("eol:~", listchars)
  1233. end)
  1234. it('should allow adding a key:value string to a listchars', function()
  1235. local listchars = exec_lua [[
  1236. vim.opt.listchars = {
  1237. eol = "~",
  1238. space = ".",
  1239. }
  1240. vim.opt.listchars = vim.opt.listchars + "tab:>~"
  1241. return vim.o.listchars
  1242. ]]
  1243. eq("eol:~,space:.,tab:>~", listchars)
  1244. end)
  1245. it('should allow prepending a key:value string to a listchars', function()
  1246. local listchars = exec_lua [[
  1247. vim.opt.listchars = {
  1248. eol = "~",
  1249. space = ".",
  1250. }
  1251. vim.opt.listchars = vim.opt.listchars ^ "tab:>~"
  1252. return vim.o.listchars
  1253. ]]
  1254. eq("eol:~,space:.,tab:>~", listchars)
  1255. end)
  1256. end)
  1257. it('should automatically set when calling remove', function()
  1258. eq("foo,baz", exec_lua [[
  1259. vim.opt.wildignore = "foo,bar,baz"
  1260. vim.opt.wildignore:remove("bar")
  1261. return vim.o.wildignore
  1262. ]])
  1263. end)
  1264. it('should automatically set when calling remove with a table', function()
  1265. eq("foo", exec_lua [[
  1266. vim.opt.wildignore = "foo,bar,baz"
  1267. vim.opt.wildignore:remove { "bar", "baz" }
  1268. return vim.o.wildignore
  1269. ]])
  1270. end)
  1271. it('should automatically set when calling append', function()
  1272. eq("foo,bar,baz,bing", exec_lua [[
  1273. vim.opt.wildignore = "foo,bar,baz"
  1274. vim.opt.wildignore:append("bing")
  1275. return vim.o.wildignore
  1276. ]])
  1277. end)
  1278. it('should automatically set when calling append with a table', function()
  1279. eq("foo,bar,baz,bing,zap", exec_lua [[
  1280. vim.opt.wildignore = "foo,bar,baz"
  1281. vim.opt.wildignore:append { "bing", "zap" }
  1282. return vim.o.wildignore
  1283. ]])
  1284. end)
  1285. it('should allow adding tables', function()
  1286. local wildignore = exec_lua [[
  1287. vim.opt.wildignore = 'foo'
  1288. return vim.o.wildignore
  1289. ]]
  1290. eq(wildignore, 'foo')
  1291. wildignore = exec_lua [[
  1292. vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
  1293. return vim.o.wildignore
  1294. ]]
  1295. eq(wildignore, 'foo,bar,baz')
  1296. end)
  1297. it('should handle adding duplicates', function()
  1298. local wildignore = exec_lua [[
  1299. vim.opt.wildignore = 'foo'
  1300. return vim.o.wildignore
  1301. ]]
  1302. eq(wildignore, 'foo')
  1303. wildignore = exec_lua [[
  1304. vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
  1305. return vim.o.wildignore
  1306. ]]
  1307. eq(wildignore, 'foo,bar,baz')
  1308. wildignore = exec_lua [[
  1309. vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
  1310. return vim.o.wildignore
  1311. ]]
  1312. eq(wildignore, 'foo,bar,baz')
  1313. end)
  1314. it('should allow adding multiple times', function()
  1315. local wildignore = exec_lua [[
  1316. vim.opt.wildignore = 'foo'
  1317. vim.opt.wildignore = vim.opt.wildignore + 'bar' + 'baz'
  1318. return vim.o.wildignore
  1319. ]]
  1320. eq(wildignore, 'foo,bar,baz')
  1321. end)
  1322. it('should remove values when you use minus', function()
  1323. local wildignore = exec_lua [[
  1324. vim.opt.wildignore = 'foo'
  1325. return vim.o.wildignore
  1326. ]]
  1327. eq(wildignore, 'foo')
  1328. wildignore = exec_lua [[
  1329. vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
  1330. return vim.o.wildignore
  1331. ]]
  1332. eq(wildignore, 'foo,bar,baz')
  1333. wildignore = exec_lua [[
  1334. vim.opt.wildignore = vim.opt.wildignore - 'bar'
  1335. return vim.o.wildignore
  1336. ]]
  1337. eq(wildignore, 'foo,baz')
  1338. end)
  1339. it('should prepend values when using ^', function()
  1340. local wildignore = exec_lua [[
  1341. vim.opt.wildignore = 'foo'
  1342. vim.opt.wildignore = vim.opt.wildignore ^ 'first'
  1343. return vim.o.wildignore
  1344. ]]
  1345. eq('first,foo', wildignore)
  1346. wildignore = exec_lua [[
  1347. vim.opt.wildignore = vim.opt.wildignore ^ 'super_first'
  1348. return vim.o.wildignore
  1349. ]]
  1350. eq(wildignore, 'super_first,first,foo')
  1351. end)
  1352. it('should not remove duplicates from wildmode: #14708', function()
  1353. local wildmode = exec_lua [[
  1354. vim.opt.wildmode = {"full", "list", "full"}
  1355. return vim.o.wildmode
  1356. ]]
  1357. eq(wildmode, 'full,list,full')
  1358. end)
  1359. describe('option types', function()
  1360. it('should allow to set option with numeric value', function()
  1361. eq(4, exec_lua [[
  1362. vim.opt.tabstop = 4
  1363. return vim.bo.tabstop
  1364. ]])
  1365. matches("Invalid option type 'string' for 'tabstop'", pcall_err(exec_lua, [[
  1366. vim.opt.tabstop = '4'
  1367. ]]))
  1368. matches("Invalid option type 'boolean' for 'tabstop'", pcall_err(exec_lua, [[
  1369. vim.opt.tabstop = true
  1370. ]]))
  1371. matches("Invalid option type 'table' for 'tabstop'", pcall_err(exec_lua, [[
  1372. vim.opt.tabstop = {4, 2}
  1373. ]]))
  1374. matches("Invalid option type 'function' for 'tabstop'", pcall_err(exec_lua, [[
  1375. vim.opt.tabstop = function()
  1376. return 4
  1377. end
  1378. ]]))
  1379. end)
  1380. it('should allow to set option with boolean value', function()
  1381. eq(true, exec_lua [[
  1382. vim.opt.undofile = true
  1383. return vim.bo.undofile
  1384. ]])
  1385. matches("Invalid option type 'number' for 'undofile'", pcall_err(exec_lua, [[
  1386. vim.opt.undofile = 0
  1387. ]]))
  1388. matches("Invalid option type 'table' for 'undofile'", pcall_err(exec_lua, [[
  1389. vim.opt.undofile = {true}
  1390. ]]))
  1391. matches("Invalid option type 'string' for 'undofile'", pcall_err(exec_lua, [[
  1392. vim.opt.undofile = 'true'
  1393. ]]))
  1394. matches("Invalid option type 'function' for 'undofile'", pcall_err(exec_lua, [[
  1395. vim.opt.undofile = function()
  1396. return true
  1397. end
  1398. ]]))
  1399. end)
  1400. it('should allow to set option with array or string value', function()
  1401. eq('indent,eol,start', exec_lua [[
  1402. vim.opt.backspace = {'indent','eol','start'}
  1403. return vim.go.backspace
  1404. ]])
  1405. eq('indent,eol,start', exec_lua [[
  1406. vim.opt.backspace = 'indent,eol,start'
  1407. return vim.go.backspace
  1408. ]])
  1409. matches("Invalid option type 'boolean' for 'backspace'", pcall_err(exec_lua, [[
  1410. vim.opt.backspace = true
  1411. ]]))
  1412. matches("Invalid option type 'number' for 'backspace'", pcall_err(exec_lua, [[
  1413. vim.opt.backspace = 2
  1414. ]]))
  1415. matches("Invalid option type 'function' for 'backspace'", pcall_err(exec_lua, [[
  1416. vim.opt.backspace = function()
  1417. return 'indent,eol,start'
  1418. end
  1419. ]]))
  1420. end)
  1421. it('should allow set option with map or string value', function()
  1422. eq("eol:~,space:.", exec_lua [[
  1423. vim.opt.listchars = {
  1424. eol = "~",
  1425. space = ".",
  1426. }
  1427. return vim.o.listchars
  1428. ]])
  1429. eq("eol:~,space:.,tab:>~", exec_lua [[
  1430. vim.opt.listchars = "eol:~,space:.,tab:>~"
  1431. return vim.o.listchars
  1432. ]])
  1433. matches("Invalid option type 'boolean' for 'listchars'", pcall_err(exec_lua, [[
  1434. vim.opt.listchars = true
  1435. ]]))
  1436. matches("Invalid option type 'number' for 'listchars'", pcall_err(exec_lua, [[
  1437. vim.opt.listchars = 2
  1438. ]]))
  1439. matches("Invalid option type 'function' for 'listchars'", pcall_err(exec_lua, [[
  1440. vim.opt.listchars = function()
  1441. return "eol:~,space:.,tab:>~"
  1442. end
  1443. ]]))
  1444. end)
  1445. it('should allow set option with set or string value', function()
  1446. local ww = exec_lua [[
  1447. vim.opt.whichwrap = {
  1448. b = true,
  1449. s = 1,
  1450. }
  1451. return vim.go.whichwrap
  1452. ]]
  1453. eq(ww, "b,s")
  1454. eq("b,s,<,>,[,]", exec_lua [[
  1455. vim.opt.whichwrap = "b,s,<,>,[,]"
  1456. return vim.go.whichwrap
  1457. ]])
  1458. matches("Invalid option type 'boolean' for 'whichwrap'", pcall_err(exec_lua, [[
  1459. vim.opt.whichwrap = true
  1460. ]]))
  1461. matches("Invalid option type 'number' for 'whichwrap'", pcall_err(exec_lua, [[
  1462. vim.opt.whichwrap = 2
  1463. ]]))
  1464. matches("Invalid option type 'function' for 'whichwrap'", pcall_err(exec_lua, [[
  1465. vim.opt.whichwrap = function()
  1466. return "b,s,<,>,[,]"
  1467. end
  1468. ]]))
  1469. end)
  1470. end)
  1471. -- isfname=a,b,c,,,d,e,f
  1472. it('can handle isfname ,,,', function()
  1473. local result = exec_lua [[
  1474. vim.opt.isfname = "a,b,,,c"
  1475. return { vim.opt.isfname:get(), vim.api.nvim_get_option('isfname') }
  1476. ]]
  1477. eq({{",", "a", "b", "c"}, "a,b,,,c"}, result)
  1478. end)
  1479. -- isfname=a,b,c,^,,def
  1480. it('can handle isfname ,^,,', function()
  1481. local result = exec_lua [[
  1482. vim.opt.isfname = "a,b,^,,c"
  1483. return { vim.opt.isfname:get(), vim.api.nvim_get_option('isfname') }
  1484. ]]
  1485. eq({{"^,", "a", "b", "c"}, "a,b,^,,c"}, result)
  1486. end)
  1487. describe('https://github.com/neovim/neovim/issues/14828', function()
  1488. it('gives empty list when item is empty:array', function()
  1489. eq({}, exec_lua [[
  1490. vim.cmd("set wildignore=")
  1491. return vim.opt.wildignore:get()
  1492. ]])
  1493. eq({}, exec_lua [[
  1494. vim.opt.wildignore = {}
  1495. return vim.opt.wildignore:get()
  1496. ]])
  1497. end)
  1498. it('gives empty list when item is empty:set', function()
  1499. eq({}, exec_lua [[
  1500. vim.cmd("set formatoptions=")
  1501. return vim.opt.formatoptions:get()
  1502. ]])
  1503. eq({}, exec_lua [[
  1504. vim.opt.formatoptions = {}
  1505. return vim.opt.formatoptions:get()
  1506. ]])
  1507. end)
  1508. it('does not append to empty item', function()
  1509. eq({"*.foo", "*.bar"}, exec_lua [[
  1510. vim.opt.wildignore = {}
  1511. vim.opt.wildignore:append { "*.foo", "*.bar" }
  1512. return vim.opt.wildignore:get()
  1513. ]])
  1514. end)
  1515. it('does not prepend to empty item', function()
  1516. eq({"*.foo", "*.bar"}, exec_lua [[
  1517. vim.opt.wildignore = {}
  1518. vim.opt.wildignore:prepend { "*.foo", "*.bar" }
  1519. return vim.opt.wildignore:get()
  1520. ]])
  1521. end)
  1522. it('append to empty set', function()
  1523. eq({ t = true }, exec_lua [[
  1524. vim.opt.formatoptions = {}
  1525. vim.opt.formatoptions:append("t")
  1526. return vim.opt.formatoptions:get()
  1527. ]])
  1528. end)
  1529. it('prepend to empty set', function()
  1530. eq({ t = true }, exec_lua [[
  1531. vim.opt.formatoptions = {}
  1532. vim.opt.formatoptions:prepend("t")
  1533. return vim.opt.formatoptions:get()
  1534. ]])
  1535. end)
  1536. end)
  1537. end) -- vim.opt
  1538. it('vim.cmd', function()
  1539. exec_lua [[
  1540. vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('<abuf>')"
  1541. vim.cmd "new"
  1542. ]]
  1543. eq('2', funcs.luaeval "BUF")
  1544. eq(2, funcs.luaeval "#vim.api.nvim_list_bufs()")
  1545. end)
  1546. it('vim.regex', function()
  1547. exec_lua [[
  1548. re1 = vim.regex"ab\\+c"
  1549. vim.cmd "set nomagic ignorecase"
  1550. re2 = vim.regex"xYz"
  1551. ]]
  1552. eq({}, exec_lua[[return {re1:match_str("x ac")}]])
  1553. eq({3,7}, exec_lua[[return {re1:match_str("ac abbc")}]])
  1554. meths.buf_set_lines(0, 0, -1, true, {"yy", "abc abbc"})
  1555. eq({}, exec_lua[[return {re1:match_line(0, 0)}]])
  1556. eq({0,3}, exec_lua[[return {re1:match_line(0, 1)}]])
  1557. eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1)}]])
  1558. eq({3,7}, exec_lua[[return {re1:match_line(0, 1, 1, 8)}]])
  1559. eq({}, exec_lua[[return {re1:match_line(0, 1, 1, 7)}]])
  1560. eq({0,3}, exec_lua[[return {re1:match_line(0, 1, 0, 7)}]])
  1561. end)
  1562. it('vim.defer_fn', function()
  1563. eq(false, exec_lua [[
  1564. vim.g.test = false
  1565. vim.defer_fn(function() vim.g.test = true end, 150)
  1566. return vim.g.test
  1567. ]])
  1568. exec_lua [[vim.wait(1000, function() return vim.g.test end)]]
  1569. eq(true, exec_lua[[return vim.g.test]])
  1570. end)
  1571. it('vim.region', function()
  1572. insert(helpers.dedent( [[
  1573. text tααt tααt text
  1574. text tαxt txtα tex
  1575. text tαxt tαxt
  1576. ]]))
  1577. eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]])
  1578. end)
  1579. describe('vim.on_key', function()
  1580. it('tracks keystrokes', function()
  1581. insert([[hello world ]])
  1582. exec_lua [[
  1583. keys = {}
  1584. vim.on_key(function(buf)
  1585. if buf:byte() == 27 then
  1586. buf = "<ESC>"
  1587. end
  1588. table.insert(keys, buf)
  1589. end)
  1590. ]]
  1591. insert([[next 🤦 lines å ]])
  1592. -- It has escape in the keys pressed
  1593. eq('inext 🤦 lines å <ESC>', exec_lua [[return table.concat(keys, '')]])
  1594. end)
  1595. it('allows removing on_key listeners', function()
  1596. insert([[hello world]])
  1597. exec_lua [[
  1598. keys = {}
  1599. return vim.on_key(function(buf)
  1600. if buf:byte() == 27 then
  1601. buf = "<ESC>"
  1602. end
  1603. table.insert(keys, buf)
  1604. end, vim.api.nvim_create_namespace("logger"))
  1605. ]]
  1606. insert([[next lines]])
  1607. eq(1, exec_lua('return vim.on_key()'))
  1608. exec_lua("vim.on_key(nil, vim.api.nvim_create_namespace('logger'))")
  1609. eq(0, exec_lua('return vim.on_key()'))
  1610. insert([[more lines]])
  1611. -- It has escape in the keys pressed
  1612. eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]])
  1613. end)
  1614. it('skips any function that caused an error', function()
  1615. insert([[hello world]])
  1616. exec_lua [[
  1617. keys = {}
  1618. return vim.on_key(function(buf)
  1619. if buf:byte() == 27 then
  1620. buf = "<ESC>"
  1621. end
  1622. table.insert(keys, buf)
  1623. if buf == 'l' then
  1624. error("Dumb Error")
  1625. end
  1626. end)
  1627. ]]
  1628. insert([[next lines]])
  1629. insert([[more lines]])
  1630. -- Only the first letter gets added. After that we remove the callback
  1631. eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
  1632. end)
  1633. it('processes mapped keys, not unmapped keys', function()
  1634. exec_lua [[
  1635. keys = {}
  1636. vim.cmd("inoremap hello world")
  1637. vim.on_key(function(buf)
  1638. if buf:byte() == 27 then
  1639. buf = "<ESC>"
  1640. end
  1641. table.insert(keys, buf)
  1642. end)
  1643. ]]
  1644. insert("hello")
  1645. eq('iworld<ESC>', exec_lua[[return table.concat(keys, '')]])
  1646. end)
  1647. end)
  1648. describe('vim.wait', function()
  1649. before_each(function()
  1650. exec_lua[[
  1651. -- high precision timer
  1652. get_time = function()
  1653. return vim.fn.reltimefloat(vim.fn.reltime())
  1654. end
  1655. ]]
  1656. end)
  1657. it('should run from lua', function()
  1658. exec_lua[[vim.wait(100, function() return true end)]]
  1659. end)
  1660. it('should wait the expected time if false', function()
  1661. eq({time = true, wait_result = {false, -1}}, exec_lua[[
  1662. start_time = get_time()
  1663. wait_succeed, wait_fail_val = vim.wait(200, function() return false end)
  1664. return {
  1665. -- 150ms waiting or more results in true. Flaky tests are bad.
  1666. time = (start_time + 0.15) < get_time(),
  1667. wait_result = {wait_succeed, wait_fail_val}
  1668. }
  1669. ]])
  1670. end)
  1671. it('should not block other events', function()
  1672. eq({time = true, wait_result = true}, exec_lua[[
  1673. start_time = get_time()
  1674. vim.g.timer_result = false
  1675. timer = vim.loop.new_timer()
  1676. timer:start(100, 0, vim.schedule_wrap(function()
  1677. vim.g.timer_result = true
  1678. end))
  1679. -- Would wait ten seconds if results blocked.
  1680. wait_result = vim.wait(10000, function() return vim.g.timer_result end)
  1681. return {
  1682. time = (start_time + 5) > get_time(),
  1683. wait_result = wait_result,
  1684. }
  1685. ]])
  1686. end)
  1687. it('should not process non-fast events when commanded', function()
  1688. eq({wait_result = false}, exec_lua[[
  1689. start_time = get_time()
  1690. vim.g.timer_result = false
  1691. timer = vim.loop.new_timer()
  1692. timer:start(100, 0, vim.schedule_wrap(function()
  1693. vim.g.timer_result = true
  1694. end))
  1695. wait_result = vim.wait(300, function() return vim.g.timer_result end, nil, true)
  1696. return {
  1697. wait_result = wait_result,
  1698. }
  1699. ]])
  1700. end)
  1701. it('should work with vim.defer_fn', function()
  1702. eq({time = true, wait_result = true}, exec_lua[[
  1703. start_time = get_time()
  1704. vim.defer_fn(function() vim.g.timer_result = true end, 100)
  1705. wait_result = vim.wait(10000, function() return vim.g.timer_result end)
  1706. return {
  1707. time = (start_time + 5) > get_time(),
  1708. wait_result = wait_result,
  1709. }
  1710. ]])
  1711. end)
  1712. it('should not crash when callback errors', function()
  1713. eq({false, '[string "<nvim>"]:1: As Expected'}, exec_lua [[
  1714. return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)}
  1715. ]])
  1716. end)
  1717. it('if callback is passed, it must be a function', function()
  1718. eq({false, 'vim.wait: if passed, condition must be a function'}, exec_lua [[
  1719. return {pcall(function() vim.wait(1000, 13) end)}
  1720. ]])
  1721. end)
  1722. it('should allow waiting with no callback, explicit', function()
  1723. eq(true, exec_lua [[
  1724. local start_time = vim.loop.hrtime()
  1725. vim.wait(50, nil)
  1726. return vim.loop.hrtime() - start_time > 25000
  1727. ]])
  1728. end)
  1729. it('should allow waiting with no callback, implicit', function()
  1730. eq(true, exec_lua [[
  1731. local start_time = vim.loop.hrtime()
  1732. vim.wait(50)
  1733. return vim.loop.hrtime() - start_time > 25000
  1734. ]])
  1735. end)
  1736. it('should call callbacks exactly once if they return true immediately', function()
  1737. eq(true, exec_lua [[
  1738. vim.g.wait_count = 0
  1739. vim.wait(1000, function()
  1740. vim.g.wait_count = vim.g.wait_count + 1
  1741. return true
  1742. end, 20)
  1743. return vim.g.wait_count == 1
  1744. ]])
  1745. end)
  1746. it('should call callbacks few times with large `interval`', function()
  1747. eq(true, exec_lua [[
  1748. vim.g.wait_count = 0
  1749. vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 200)
  1750. return vim.g.wait_count < 5
  1751. ]])
  1752. end)
  1753. it('should play nice with `not` when fails', function()
  1754. eq(true, exec_lua [[
  1755. if not vim.wait(50, function() end) then
  1756. return true
  1757. end
  1758. return false
  1759. ]])
  1760. end)
  1761. it('should play nice with `if` when success', function()
  1762. eq(true, exec_lua [[
  1763. if vim.wait(50, function() return true end) then
  1764. return true
  1765. end
  1766. return false
  1767. ]])
  1768. end)
  1769. it('should return immediately with false if timeout is 0', function()
  1770. eq({false, -1}, exec_lua [[
  1771. return {
  1772. vim.wait(0, function() return false end)
  1773. }
  1774. ]])
  1775. end)
  1776. it('should work with tables with __call', function()
  1777. eq(true, exec_lua [[
  1778. local t = setmetatable({}, {__call = function(...) return true end})
  1779. return vim.wait(100, t, 10)
  1780. ]])
  1781. end)
  1782. it('should work with tables with __call that change', function()
  1783. eq(true, exec_lua [[
  1784. local t = {count = 0}
  1785. setmetatable(t, {
  1786. __call = function()
  1787. t.count = t.count + 1
  1788. return t.count > 3
  1789. end
  1790. })
  1791. return vim.wait(1000, t, 10)
  1792. ]])
  1793. end)
  1794. it('should not work with negative intervals', function()
  1795. local pcall_result = exec_lua [[
  1796. return pcall(function() vim.wait(1000, function() return false end, -1) end)
  1797. ]]
  1798. eq(false, pcall_result)
  1799. end)
  1800. it('should not work with weird intervals', function()
  1801. local pcall_result = exec_lua [[
  1802. return pcall(function() vim.wait(1000, function() return false end, 'a string value') end)
  1803. ]]
  1804. eq(false, pcall_result)
  1805. end)
  1806. end)
  1807. describe('vim.api.nvim_buf_call', function()
  1808. it('can access buf options', function()
  1809. local buf1 = meths.get_current_buf()
  1810. local buf2 = exec_lua [[
  1811. buf2 = vim.api.nvim_create_buf(false, true)
  1812. return buf2
  1813. ]]
  1814. eq(false, meths.buf_get_option(buf1, 'autoindent'))
  1815. eq(false, meths.buf_get_option(buf2, 'autoindent'))
  1816. local val = exec_lua [[
  1817. return vim.api.nvim_buf_call(buf2, function()
  1818. vim.cmd "set autoindent"
  1819. return vim.api.nvim_get_current_buf()
  1820. end)
  1821. ]]
  1822. eq(false, meths.buf_get_option(buf1, 'autoindent'))
  1823. eq(true, meths.buf_get_option(buf2, 'autoindent'))
  1824. eq(buf1, meths.get_current_buf())
  1825. eq(buf2, val)
  1826. end)
  1827. end)
  1828. describe('vim.api.nvim_win_call', function()
  1829. it('can access window options', function()
  1830. command('vsplit')
  1831. local win1 = meths.get_current_win()
  1832. command('wincmd w')
  1833. local win2 = exec_lua [[
  1834. win2 = vim.api.nvim_get_current_win()
  1835. return win2
  1836. ]]
  1837. command('wincmd p')
  1838. eq('', meths.win_get_option(win1, 'winhighlight'))
  1839. eq('', meths.win_get_option(win2, 'winhighlight'))
  1840. local val = exec_lua [[
  1841. return vim.api.nvim_win_call(win2, function()
  1842. vim.cmd "setlocal winhighlight=Normal:Normal"
  1843. return vim.api.nvim_get_current_win()
  1844. end)
  1845. ]]
  1846. eq('', meths.win_get_option(win1, 'winhighlight'))
  1847. eq('Normal:Normal', meths.win_get_option(win2, 'winhighlight'))
  1848. eq(win1, meths.get_current_win())
  1849. eq(win2, val)
  1850. end)
  1851. end)
  1852. end)
  1853. describe('lua: require("mod") from packages', function()
  1854. before_each(function()
  1855. command('set rtp+=test/functional/fixtures')
  1856. end)
  1857. it('propagates syntax error', function()
  1858. local syntax_error_msg = exec_lua [[
  1859. local _, err = pcall(require, "syntax_error")
  1860. return err
  1861. ]]
  1862. matches("unexpected symbol", syntax_error_msg)
  1863. end)
  1864. end)