vim_spec.lua 129 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503
  1. -- Test suite for testing interactions with API bindings
  2. local t = require('test.testutil')
  3. local n = require('test.functional.testnvim')()
  4. local Screen = require('test.functional.ui.screen')
  5. local nvim_prog = n.nvim_prog
  6. local fn = n.fn
  7. local api = n.api
  8. local command = n.command
  9. local dedent = t.dedent
  10. local insert = n.insert
  11. local clear = n.clear
  12. local eq = t.eq
  13. local ok = t.ok
  14. local pesc = vim.pesc
  15. local eval = n.eval
  16. local feed = n.feed
  17. local pcall_err = t.pcall_err
  18. local exec_lua = n.exec_lua
  19. local matches = t.matches
  20. local exec = n.exec
  21. local NIL = vim.NIL
  22. local retry = t.retry
  23. local next_msg = n.next_msg
  24. local remove_trace = t.remove_trace
  25. local mkdir_p = n.mkdir_p
  26. local rmdir = n.rmdir
  27. local write_file = t.write_file
  28. local poke_eventloop = n.poke_eventloop
  29. local assert_alive = n.assert_alive
  30. local expect = n.expect
  31. describe('lua stdlib', function()
  32. before_each(clear)
  33. -- İ: `tolower("İ")` is `i` which has length 1 while `İ` itself has
  34. -- length 2 (in bytes).
  35. -- Ⱥ: `tolower("Ⱥ")` is `ⱥ` which has length 2 while `Ⱥ` itself has
  36. -- length 3 (in bytes).
  37. --
  38. -- Note: 'i' !=? 'İ' and 'ⱥ' !=? 'Ⱥ' on some systems.
  39. -- Note: Built-in Nvim comparison (on systems lacking `strcasecmp`) works
  40. -- only on ASCII characters.
  41. it('vim.stricmp', function()
  42. eq(0, fn.luaeval('vim.stricmp("a", "A")'))
  43. eq(0, fn.luaeval('vim.stricmp("A", "a")'))
  44. eq(0, fn.luaeval('vim.stricmp("a", "a")'))
  45. eq(0, fn.luaeval('vim.stricmp("A", "A")'))
  46. eq(0, fn.luaeval('vim.stricmp("", "")'))
  47. eq(0, fn.luaeval('vim.stricmp("\\0", "\\0")'))
  48. eq(0, fn.luaeval('vim.stricmp("\\0\\0", "\\0\\0")'))
  49. eq(0, fn.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0\\0")'))
  50. eq(0, fn.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0a")'))
  51. eq(0, fn.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0A")'))
  52. eq(0, fn.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0a")'))
  53. eq(0, fn.luaeval('vim.stricmp("a\\0", "A\\0")'))
  54. eq(0, fn.luaeval('vim.stricmp("A\\0", "a\\0")'))
  55. eq(0, fn.luaeval('vim.stricmp("a\\0", "a\\0")'))
  56. eq(0, fn.luaeval('vim.stricmp("A\\0", "A\\0")'))
  57. eq(0, fn.luaeval('vim.stricmp("\\0a", "\\0A")'))
  58. eq(0, fn.luaeval('vim.stricmp("\\0A", "\\0a")'))
  59. eq(0, fn.luaeval('vim.stricmp("\\0a", "\\0a")'))
  60. eq(0, fn.luaeval('vim.stricmp("\\0A", "\\0A")'))
  61. eq(0, fn.luaeval('vim.stricmp("\\0a\\0", "\\0A\\0")'))
  62. eq(0, fn.luaeval('vim.stricmp("\\0A\\0", "\\0a\\0")'))
  63. eq(0, fn.luaeval('vim.stricmp("\\0a\\0", "\\0a\\0")'))
  64. eq(0, fn.luaeval('vim.stricmp("\\0A\\0", "\\0A\\0")'))
  65. eq(-1, fn.luaeval('vim.stricmp("a", "B")'))
  66. eq(-1, fn.luaeval('vim.stricmp("A", "b")'))
  67. eq(-1, fn.luaeval('vim.stricmp("a", "b")'))
  68. eq(-1, fn.luaeval('vim.stricmp("A", "B")'))
  69. eq(-1, fn.luaeval('vim.stricmp("", "\\0")'))
  70. eq(-1, fn.luaeval('vim.stricmp("\\0", "\\0\\0")'))
  71. eq(-1, fn.luaeval('vim.stricmp("\\0\\0", "\\0\\0\\0")'))
  72. eq(-1, fn.luaeval('vim.stricmp("\\0\\0\\0A", "\\0\\0\\0b")'))
  73. eq(-1, fn.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0B")'))
  74. eq(-1, fn.luaeval('vim.stricmp("\\0\\0\\0a", "\\0\\0\\0b")'))
  75. eq(-1, fn.luaeval('vim.stricmp("a\\0", "B\\0")'))
  76. eq(-1, fn.luaeval('vim.stricmp("A\\0", "b\\0")'))
  77. eq(-1, fn.luaeval('vim.stricmp("a\\0", "b\\0")'))
  78. eq(-1, fn.luaeval('vim.stricmp("A\\0", "B\\0")'))
  79. eq(-1, fn.luaeval('vim.stricmp("\\0a", "\\0B")'))
  80. eq(-1, fn.luaeval('vim.stricmp("\\0A", "\\0b")'))
  81. eq(-1, fn.luaeval('vim.stricmp("\\0a", "\\0b")'))
  82. eq(-1, fn.luaeval('vim.stricmp("\\0A", "\\0B")'))
  83. eq(-1, fn.luaeval('vim.stricmp("\\0a\\0", "\\0B\\0")'))
  84. eq(-1, fn.luaeval('vim.stricmp("\\0A\\0", "\\0b\\0")'))
  85. eq(-1, fn.luaeval('vim.stricmp("\\0a\\0", "\\0b\\0")'))
  86. eq(-1, fn.luaeval('vim.stricmp("\\0A\\0", "\\0B\\0")'))
  87. eq(1, fn.luaeval('vim.stricmp("c", "B")'))
  88. eq(1, fn.luaeval('vim.stricmp("C", "b")'))
  89. eq(1, fn.luaeval('vim.stricmp("c", "b")'))
  90. eq(1, fn.luaeval('vim.stricmp("C", "B")'))
  91. eq(1, fn.luaeval('vim.stricmp("\\0", "")'))
  92. eq(1, fn.luaeval('vim.stricmp("\\0\\0", "\\0")'))
  93. eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0", "\\0\\0")'))
  94. eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0\\0", "\\0\\0\\0")'))
  95. eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0C", "\\0\\0\\0b")'))
  96. eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0B")'))
  97. eq(1, fn.luaeval('vim.stricmp("\\0\\0\\0c", "\\0\\0\\0b")'))
  98. eq(1, fn.luaeval('vim.stricmp("c\\0", "B\\0")'))
  99. eq(1, fn.luaeval('vim.stricmp("C\\0", "b\\0")'))
  100. eq(1, fn.luaeval('vim.stricmp("c\\0", "b\\0")'))
  101. eq(1, fn.luaeval('vim.stricmp("C\\0", "B\\0")'))
  102. eq(1, fn.luaeval('vim.stricmp("c\\0", "B")'))
  103. eq(1, fn.luaeval('vim.stricmp("C\\0", "b")'))
  104. eq(1, fn.luaeval('vim.stricmp("c\\0", "b")'))
  105. eq(1, fn.luaeval('vim.stricmp("C\\0", "B")'))
  106. eq(1, fn.luaeval('vim.stricmp("\\0c", "\\0B")'))
  107. eq(1, fn.luaeval('vim.stricmp("\\0C", "\\0b")'))
  108. eq(1, fn.luaeval('vim.stricmp("\\0c", "\\0b")'))
  109. eq(1, fn.luaeval('vim.stricmp("\\0C", "\\0B")'))
  110. eq(1, fn.luaeval('vim.stricmp("\\0c\\0", "\\0B\\0")'))
  111. eq(1, fn.luaeval('vim.stricmp("\\0C\\0", "\\0b\\0")'))
  112. eq(1, fn.luaeval('vim.stricmp("\\0c\\0", "\\0b\\0")'))
  113. eq(1, fn.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")'))
  114. end)
  115. --- @param prerel string | nil
  116. local function test_vim_deprecate(prerel)
  117. -- vim.deprecate(name, alternative, version, plugin, backtrace)
  118. -- See MAINTAIN.md for the soft/hard deprecation policy
  119. describe(('vim.deprecate prerel=%s,'):format(prerel or 'nil'), function()
  120. local curver --- @type {major:number, minor:number}
  121. before_each(function()
  122. curver = exec_lua('return vim.version()')
  123. end)
  124. it('plugin=nil, same message skipped', function()
  125. -- "0.10" or "0.10-dev+xxx"
  126. local curstr = ('%s.%s%s'):format(curver.major, curver.minor, prerel or '')
  127. eq(
  128. ([[foo.bar() is deprecated. Run ":checkhealth vim.deprecated" for more information]]):format(
  129. curstr
  130. ),
  131. exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', curstr)
  132. )
  133. -- Same message as above; skipped this time.
  134. eq(vim.NIL, exec_lua('return vim.deprecate(...)', 'foo.bar()', 'zub.wooo{ok=yay}', curstr))
  135. end)
  136. it('plugin=nil, no error if soft-deprecated', function()
  137. eq(vim.NIL, exec_lua [[return vim.deprecate('old1', 'new1', '0.99.0')]])
  138. -- Major version > current Nvim major is always "soft-deprecated".
  139. -- XXX: This is also a reminder to update the hardcoded `nvim_major`, when Nvim reaches 1.0.
  140. eq(vim.NIL, exec_lua [[return vim.deprecate('old2', 'new2', '1.0.0')]])
  141. end)
  142. it('plugin=nil, show error if hard-deprecated', function()
  143. -- "0.10" or "0.11"
  144. local nextver = ('%s.%s'):format(curver.major, curver.minor + (prerel and 0 or 1))
  145. local was_removed = prerel and 'was removed' or 'will be removed'
  146. eq(
  147. dedent(
  148. [[
  149. foo.hard_dep() is deprecated. Run ":checkhealth vim.deprecated" for more information]]
  150. ):format(was_removed, nextver),
  151. exec_lua('return vim.deprecate(...)', 'foo.hard_dep()', 'vim.new_api()', nextver)
  152. )
  153. end)
  154. it('plugin specified', function()
  155. -- When `plugin` is specified, don't show ":help deprecated". #22235
  156. eq(
  157. dedent [[
  158. foo.bar() is deprecated, use zub.wooo{ok=yay} instead.
  159. Feature will be removed in my-plugin.nvim 0.3.0]],
  160. exec_lua(
  161. 'return vim.deprecate(...)',
  162. 'foo.bar()',
  163. 'zub.wooo{ok=yay}',
  164. '0.3.0',
  165. 'my-plugin.nvim',
  166. false
  167. )
  168. )
  169. -- plugins: no soft deprecation period
  170. eq(
  171. dedent [[
  172. foo.bar() is deprecated, use zub.wooo{ok=yay} instead.
  173. Feature will be removed in my-plugin.nvim 0.11.0]],
  174. exec_lua(
  175. 'return vim.deprecate(...)',
  176. 'foo.bar()',
  177. 'zub.wooo{ok=yay}',
  178. '0.11.0',
  179. 'my-plugin.nvim',
  180. false
  181. )
  182. )
  183. end)
  184. end)
  185. end
  186. test_vim_deprecate()
  187. test_vim_deprecate('-dev+g0000000')
  188. it('vim.startswith', function()
  189. eq(true, fn.luaeval('vim.startswith("123", "1")'))
  190. eq(true, fn.luaeval('vim.startswith("123", "")'))
  191. eq(true, fn.luaeval('vim.startswith("123", "123")'))
  192. eq(true, fn.luaeval('vim.startswith("", "")'))
  193. eq(false, fn.luaeval('vim.startswith("123", " ")'))
  194. eq(false, fn.luaeval('vim.startswith("123", "2")'))
  195. eq(false, fn.luaeval('vim.startswith("123", "1234")'))
  196. matches(
  197. 'prefix: expected string, got nil',
  198. pcall_err(exec_lua, 'return vim.startswith("123", nil)')
  199. )
  200. matches('s: expected string, got nil', pcall_err(exec_lua, 'return vim.startswith(nil, "123")'))
  201. end)
  202. it('vim.endswith', function()
  203. eq(true, fn.luaeval('vim.endswith("123", "3")'))
  204. eq(true, fn.luaeval('vim.endswith("123", "")'))
  205. eq(true, fn.luaeval('vim.endswith("123", "123")'))
  206. eq(true, fn.luaeval('vim.endswith("", "")'))
  207. eq(false, fn.luaeval('vim.endswith("123", " ")'))
  208. eq(false, fn.luaeval('vim.endswith("123", "2")'))
  209. eq(false, fn.luaeval('vim.endswith("123", "1234")'))
  210. matches(
  211. 'suffix: expected string, got nil',
  212. pcall_err(exec_lua, 'return vim.endswith("123", nil)')
  213. )
  214. matches('s: expected string, got nil', pcall_err(exec_lua, 'return vim.endswith(nil, "123")'))
  215. end)
  216. it('vim.str_utfindex/str_byteindex', function()
  217. exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ\000ъ"]])
  218. local indices32 = {
  219. [0] = 0,
  220. 1,
  221. 2,
  222. 3,
  223. 5,
  224. 7,
  225. 9,
  226. 10,
  227. 12,
  228. 13,
  229. 16,
  230. 19,
  231. 20,
  232. 23,
  233. 24,
  234. 28,
  235. 29,
  236. 33,
  237. 34,
  238. 35,
  239. 37,
  240. 38,
  241. 40,
  242. 42,
  243. 44,
  244. 46,
  245. 48,
  246. 49,
  247. 51,
  248. }
  249. local indices16 = {
  250. [0] = 0,
  251. 1,
  252. 2,
  253. 3,
  254. 5,
  255. 7,
  256. 9,
  257. 10,
  258. 12,
  259. 13,
  260. 16,
  261. 19,
  262. 20,
  263. 23,
  264. 24,
  265. 28,
  266. 28,
  267. 29,
  268. 33,
  269. 33,
  270. 34,
  271. 35,
  272. 37,
  273. 38,
  274. 40,
  275. 42,
  276. 44,
  277. 46,
  278. 48,
  279. 49,
  280. 51,
  281. }
  282. local indices8 = {
  283. [0] = 0,
  284. 1,
  285. 2,
  286. 3,
  287. 4,
  288. 5,
  289. 6,
  290. 7,
  291. 8,
  292. 9,
  293. 10,
  294. 11,
  295. 12,
  296. 13,
  297. 14,
  298. 15,
  299. 16,
  300. 17,
  301. 18,
  302. 19,
  303. 20,
  304. 21,
  305. 22,
  306. 23,
  307. 24,
  308. 25,
  309. 26,
  310. 27,
  311. 28,
  312. 29,
  313. 30,
  314. 31,
  315. 32,
  316. 33,
  317. 34,
  318. 35,
  319. 36,
  320. 37,
  321. 38,
  322. 39,
  323. 40,
  324. 41,
  325. 42,
  326. 43,
  327. 44,
  328. 45,
  329. 46,
  330. 47,
  331. 48,
  332. 49,
  333. 50,
  334. 51,
  335. }
  336. for i, k in pairs(indices32) do
  337. eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ...)', i), i)
  338. eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., false)', i), i)
  339. eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", ...)', i), i)
  340. end
  341. for i, k in pairs(indices16) do
  342. eq(k, exec_lua('return vim.str_byteindex(_G.test_text, ..., true)', i), i)
  343. eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", ...)', i), i)
  344. end
  345. for i, k in pairs(indices8) do
  346. eq(k, exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", ...)', i), i)
  347. end
  348. matches(
  349. 'index out of range',
  350. pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ...)', #indices32 + 1)
  351. )
  352. matches(
  353. 'index out of range',
  354. pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, ..., true)', #indices16 + 1)
  355. )
  356. matches(
  357. 'index out of range',
  358. pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-16", ...)', #indices16 + 1)
  359. )
  360. matches(
  361. 'index out of range',
  362. pcall_err(exec_lua, 'return vim.str_byteindex(_G.test_text, "utf-32", ...)', #indices32 + 1)
  363. )
  364. matches(
  365. 'invalid encoding',
  366. pcall_err(exec_lua, 'return vim.str_byteindex("hello", "madeupencoding", 1)')
  367. )
  368. eq(
  369. indices32[#indices32],
  370. exec_lua('return vim.str_byteindex(_G.test_text, "utf-32", 99999, false)')
  371. )
  372. eq(
  373. indices16[#indices16],
  374. exec_lua('return vim.str_byteindex(_G.test_text, "utf-16", 99999, false)')
  375. )
  376. eq(
  377. indices8[#indices8],
  378. exec_lua('return vim.str_byteindex(_G.test_text, "utf-8", 99999, false)')
  379. )
  380. eq(2, exec_lua('return vim.str_byteindex("é", "utf-16", 2, false)'))
  381. local i32, i16, i8 = 0, 0, 0
  382. local len = 51
  383. for k = 0, len do
  384. if indices32[i32] < k then
  385. i32 = i32 + 1
  386. end
  387. if indices16[i16] < k then
  388. i16 = i16 + 1
  389. if indices16[i16 + 1] == indices16[i16] then
  390. i16 = i16 + 1
  391. end
  392. end
  393. if indices8[i8] < k then
  394. i8 = i8 + 1
  395. end
  396. eq({ i32, i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, ...)}', k), k)
  397. eq({ i32 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-32", ...)}', k), k)
  398. eq({ i16 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-16", ...)}', k), k)
  399. eq({ i8 }, exec_lua('return {vim.str_utfindex(_G.test_text, "utf-8", ...)}', k), k)
  400. end
  401. eq({ #indices32, #indices16 }, exec_lua('return {vim.str_utfindex(_G.test_text)}'))
  402. eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32", math.huge, false)'))
  403. eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16", math.huge, false)'))
  404. eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8", math.huge, false)'))
  405. eq(#indices32, exec_lua('return vim.str_utfindex(_G.test_text, "utf-32")'))
  406. eq(#indices16, exec_lua('return vim.str_utfindex(_G.test_text, "utf-16")'))
  407. eq(#indices8, exec_lua('return vim.str_utfindex(_G.test_text, "utf-8")'))
  408. matches(
  409. 'invalid encoding',
  410. pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, "madeupencoding", ...)', 1)
  411. )
  412. matches(
  413. 'index out of range',
  414. pcall_err(exec_lua, 'return vim.str_utfindex(_G.test_text, ...)', len + 1)
  415. )
  416. end)
  417. it('vim.str_utf_start', function()
  418. exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]])
  419. local expected_positions = {
  420. 0,
  421. 0,
  422. 0,
  423. 0,
  424. -1,
  425. 0,
  426. -1,
  427. 0,
  428. -1,
  429. 0,
  430. 0,
  431. -1,
  432. 0,
  433. 0,
  434. -1,
  435. -2,
  436. 0,
  437. -1,
  438. -2,
  439. 0,
  440. 0,
  441. -1,
  442. -2,
  443. 0,
  444. 0,
  445. -1,
  446. -2,
  447. -3,
  448. 0,
  449. 0,
  450. -1,
  451. -2,
  452. -3,
  453. 0,
  454. 0,
  455. 0,
  456. -1,
  457. 0,
  458. 0,
  459. -1,
  460. 0,
  461. -1,
  462. 0,
  463. -1,
  464. 0,
  465. -1,
  466. 0,
  467. -1,
  468. }
  469. eq(
  470. expected_positions,
  471. exec_lua([[
  472. local start_codepoint_positions = {}
  473. for idx = 1, #_G.test_text do
  474. table.insert(start_codepoint_positions, vim.str_utf_start(_G.test_text, idx))
  475. end
  476. return start_codepoint_positions
  477. ]])
  478. )
  479. end)
  480. it('vim.str_utf_end', function()
  481. exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]])
  482. local expected_positions = {
  483. 0,
  484. 0,
  485. 0,
  486. 1,
  487. 0,
  488. 1,
  489. 0,
  490. 1,
  491. 0,
  492. 0,
  493. 1,
  494. 0,
  495. 0,
  496. 2,
  497. 1,
  498. 0,
  499. 2,
  500. 1,
  501. 0,
  502. 0,
  503. 2,
  504. 1,
  505. 0,
  506. 0,
  507. 3,
  508. 2,
  509. 1,
  510. 0,
  511. 0,
  512. 3,
  513. 2,
  514. 1,
  515. 0,
  516. 0,
  517. 0,
  518. 1,
  519. 0,
  520. 0,
  521. 1,
  522. 0,
  523. 1,
  524. 0,
  525. 1,
  526. 0,
  527. 1,
  528. 0,
  529. 1,
  530. 0,
  531. }
  532. eq(
  533. expected_positions,
  534. exec_lua([[
  535. local end_codepoint_positions = {}
  536. for idx = 1, #_G.test_text do
  537. table.insert(end_codepoint_positions, vim.str_utf_end(_G.test_text, idx))
  538. end
  539. return end_codepoint_positions
  540. ]])
  541. )
  542. end)
  543. it('vim.str_utf_pos', function()
  544. exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 å بِيَّ"]])
  545. local expected_positions = {
  546. 1,
  547. 2,
  548. 3,
  549. 4,
  550. 6,
  551. 8,
  552. 10,
  553. 11,
  554. 13,
  555. 14,
  556. 17,
  557. 20,
  558. 21,
  559. 24,
  560. 25,
  561. 29,
  562. 30,
  563. 34,
  564. 35,
  565. 36,
  566. 38,
  567. 39,
  568. 41,
  569. 43,
  570. 45,
  571. 47,
  572. }
  573. eq(expected_positions, exec_lua('return vim.str_utf_pos(_G.test_text)'))
  574. end)
  575. it('vim.schedule', function()
  576. exec_lua([[
  577. test_table = {}
  578. vim.schedule(function()
  579. table.insert(test_table, "xx")
  580. end)
  581. table.insert(test_table, "yy")
  582. ]])
  583. eq({ 'yy', 'xx' }, exec_lua('return test_table'))
  584. -- Validates args.
  585. matches('vim.schedule: expected function', pcall_err(exec_lua, "vim.schedule('stringly')"))
  586. matches('vim.schedule: expected function', pcall_err(exec_lua, 'vim.schedule()'))
  587. exec_lua([[
  588. vim.schedule(function()
  589. error("big failure\nvery async")
  590. end)
  591. ]])
  592. feed('<cr>')
  593. matches('big failure\nvery async', remove_trace(eval('v:errmsg')))
  594. local screen = Screen.new(60, 5)
  595. screen:expect {
  596. grid = [[
  597. ^ |
  598. {1:~ }|*3
  599. |
  600. ]],
  601. }
  602. -- nvim_command causes a Vimscript exception, check that it is properly caught
  603. -- and propagated as an error message in async contexts.. #10809
  604. exec_lua([[
  605. vim.schedule(function()
  606. vim.api.nvim_command(":echo 'err")
  607. end)
  608. ]])
  609. screen:expect {
  610. grid = [[
  611. {9:stack traceback:} |
  612. {9: [C]: in function 'nvim_command'} |
  613. {9: [string "<nvim>"]:2: in function <[string "<nvim>"]:}|
  614. {9:1>} |
  615. {6:Press ENTER or type command to continue}^ |
  616. ]],
  617. }
  618. end)
  619. it('vim.gsplit, vim.split', function()
  620. local tests = {
  621. -- plain trimempty
  622. { 'a,b', ',', false, false, { 'a', 'b' } },
  623. { ':aa::::bb:', ':', false, false, { '', 'aa', '', '', '', 'bb', '' } },
  624. { ':aa::::bb:', ':', false, true, { 'aa', '', '', '', 'bb' } },
  625. { 'aa::::bb:', ':', false, true, { 'aa', '', '', '', 'bb' } },
  626. { ':aa::bb:', ':', false, true, { 'aa', '', 'bb' } },
  627. { '/a/b:/b/\n', '[:\n]', false, true, { '/a/b', '/b/' } },
  628. { '::ee::ff:', ':', false, false, { '', '', 'ee', '', 'ff', '' } },
  629. { '::ee::ff::', ':', false, true, { 'ee', '', 'ff' } },
  630. { 'ab', '.', false, false, { '', '', '' } },
  631. { 'a1b2c', '[0-9]', false, false, { 'a', 'b', 'c' } },
  632. { 'xy', '', false, false, { 'x', 'y' } },
  633. { 'here be dragons', ' ', false, false, { 'here', 'be', 'dragons' } },
  634. { 'axaby', 'ab?', false, false, { '', 'x', 'y' } },
  635. { 'f v2v v3v w2w ', '([vw])2%1', false, false, { 'f ', ' v3v ', ' ' } },
  636. { '', '', false, false, {} },
  637. { '', '', false, true, {} },
  638. { '\n', '[:\n]', false, true, {} },
  639. { '', 'a', false, false, { '' } },
  640. { 'x*yz*oo*l', '*', true, false, { 'x', 'yz', 'oo', 'l' } },
  641. }
  642. for _, q in ipairs(tests) do
  643. eq(q[5], vim.split(q[1], q[2], { plain = q[3], trimempty = q[4] }), q[1])
  644. end
  645. -- Test old signature
  646. eq({ 'x', 'yz', 'oo', 'l' }, vim.split('x*yz*oo*l', '*', true))
  647. local loops = {
  648. { 'abc', '.-' },
  649. }
  650. for _, q in ipairs(loops) do
  651. matches('Infinite loop detected', pcall_err(vim.split, q[1], q[2]))
  652. end
  653. -- Validates args.
  654. eq(true, pcall(vim.split, 'string', 'string'))
  655. matches('s: expected string, got number', pcall_err(vim.split, 1, 'string'))
  656. matches('sep: expected string, got number', pcall_err(vim.split, 'string', 1))
  657. matches('opts: expected table, got number', pcall_err(vim.split, 'string', 'string', 1))
  658. end)
  659. it('vim.trim', function()
  660. local trim = function(s)
  661. return exec_lua('return vim.trim(...)', s)
  662. end
  663. local trims = {
  664. { ' a', 'a' },
  665. { ' b ', 'b' },
  666. { '\tc', 'c' },
  667. { 'r\n', 'r' },
  668. }
  669. for _, q in ipairs(trims) do
  670. assert(q[2], trim(q[1]))
  671. end
  672. -- Validates args.
  673. matches('s: expected string, got number', pcall_err(trim, 2))
  674. end)
  675. it('vim.inspect', function()
  676. -- just make sure it basically works, it has its own test suite
  677. local inspect = function(q, opts)
  678. return exec_lua('return vim.inspect(...)', q, opts)
  679. end
  680. eq('2', inspect(2))
  681. eq('{+a = {+b = 1+}+}', inspect({ a = { b = 1 } }, { newline = '+', indent = '' }))
  682. -- special value vim.inspect.KEY works
  683. eq(
  684. '{ KEY_a = "x", KEY_b = "y"}',
  685. exec_lua([[
  686. return vim.inspect({a="x", b="y"}, {newline = '', process = function(item, path)
  687. if path[#path] == vim.inspect.KEY then
  688. return 'KEY_'..item
  689. end
  690. return item
  691. end})
  692. ]])
  693. )
  694. end)
  695. it('vim.deepcopy', function()
  696. ok(exec_lua([[
  697. local a = { x = { 1, 2 }, y = 5}
  698. local b = vim.deepcopy(a)
  699. return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and vim.tbl_count(b) == 2
  700. and tostring(a) ~= tostring(b)
  701. ]]))
  702. ok(exec_lua([[
  703. local a = {}
  704. local b = vim.deepcopy(a)
  705. return vim.islist(b) and vim.tbl_count(b) == 0 and tostring(a) ~= tostring(b)
  706. ]]))
  707. ok(exec_lua([[
  708. local a = vim.empty_dict()
  709. local b = vim.deepcopy(a)
  710. return not vim.islist(b) and vim.tbl_count(b) == 0
  711. ]]))
  712. ok(exec_lua([[
  713. local a = {x = vim.empty_dict(), y = {}}
  714. local b = vim.deepcopy(a)
  715. return not vim.islist(b.x) and vim.islist(b.y)
  716. and vim.tbl_count(b) == 2
  717. and tostring(a) ~= tostring(b)
  718. ]]))
  719. ok(exec_lua([[
  720. local f1 = function() return 1 end
  721. local f2 = function() return 2 end
  722. local t1 = {f = f1}
  723. local t2 = vim.deepcopy(t1)
  724. t1.f = f2
  725. return t1.f() ~= t2.f()
  726. ]]))
  727. ok(exec_lua([[
  728. local t1 = {a = 5}
  729. t1.self = t1
  730. local t2 = vim.deepcopy(t1)
  731. return t2.self == t2 and t2.self ~= t1
  732. ]]))
  733. ok(exec_lua([[
  734. local mt = {mt=true}
  735. local t1 = setmetatable({a = 5}, mt)
  736. local t2 = vim.deepcopy(t1)
  737. return getmetatable(t2) == mt
  738. ]]))
  739. ok(exec_lua([[
  740. local t1 = {a = vim.NIL}
  741. local t2 = vim.deepcopy(t1)
  742. return t2.a == vim.NIL
  743. ]]))
  744. matches(
  745. 'Cannot deepcopy object of type thread',
  746. pcall_err(
  747. exec_lua,
  748. [[
  749. local thread = coroutine.create(function () return 0 end)
  750. local t = {thr = thread}
  751. vim.deepcopy(t)
  752. ]]
  753. )
  754. )
  755. end)
  756. it('vim.pesc', function()
  757. eq('foo%-bar', exec_lua([[return vim.pesc('foo-bar')]]))
  758. eq('foo%%%-bar', exec_lua([[return vim.pesc(vim.pesc('foo-bar'))]]))
  759. -- pesc() returns one result. #20751
  760. eq({ 'x' }, exec_lua([[return {vim.pesc('x')}]]))
  761. -- Validates args.
  762. matches('s: expected string, got number', pcall_err(exec_lua, [[return vim.pesc(2)]]))
  763. end)
  764. it('vim.list_contains', function()
  765. eq(true, exec_lua("return vim.list_contains({'a','b','c'}, 'c')"))
  766. eq(false, exec_lua("return vim.list_contains({'a','b','c'}, 'd')"))
  767. end)
  768. it('vim.tbl_contains', function()
  769. eq(true, exec_lua("return vim.tbl_contains({'a','b','c'}, 'c')"))
  770. eq(false, exec_lua("return vim.tbl_contains({'a','b','c'}, 'd')"))
  771. eq(true, exec_lua("return vim.tbl_contains({[2]='a',foo='b',[5] = 'c'}, 'c')"))
  772. eq(
  773. true,
  774. exec_lua([[
  775. return vim.tbl_contains({ 'a', { 'b', 'c' } }, function(v)
  776. return vim.deep_equal(v, { 'b', 'c' })
  777. end, { predicate = true })
  778. ]])
  779. )
  780. end)
  781. it('vim.tbl_keys', function()
  782. eq({}, exec_lua('return vim.tbl_keys({})'))
  783. for _, v in pairs(exec_lua("return vim.tbl_keys({'a', 'b', 'c'})")) do
  784. eq(true, exec_lua('return vim.tbl_contains({ 1, 2, 3 }, ...)', v))
  785. end
  786. for _, v in pairs(exec_lua('return vim.tbl_keys({a=1, b=2, c=3})')) do
  787. eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v))
  788. end
  789. end)
  790. it('vim.tbl_values', function()
  791. eq({}, exec_lua('return vim.tbl_values({})'))
  792. for _, v in pairs(exec_lua("return vim.tbl_values({'a', 'b', 'c'})")) do
  793. eq(true, exec_lua("return vim.tbl_contains({ 'a', 'b', 'c' }, ...)", v))
  794. end
  795. for _, v in pairs(exec_lua('return vim.tbl_values({a=1, b=2, c=3})')) do
  796. eq(true, exec_lua('return vim.tbl_contains({ 1, 2, 3 }, ...)', v))
  797. end
  798. end)
  799. it('vim.tbl_map', function()
  800. eq(
  801. {},
  802. exec_lua([[
  803. return vim.tbl_map(function(v) return v * 2 end, {})
  804. ]])
  805. )
  806. eq(
  807. { 2, 4, 6 },
  808. exec_lua([[
  809. return vim.tbl_map(function(v) return v * 2 end, {1, 2, 3})
  810. ]])
  811. )
  812. eq(
  813. { { i = 2 }, { i = 4 }, { i = 6 } },
  814. exec_lua([[
  815. return vim.tbl_map(function(v) return { i = v.i * 2 } end, {{i=1}, {i=2}, {i=3}})
  816. ]])
  817. )
  818. end)
  819. it('vim.tbl_filter', function()
  820. eq(
  821. {},
  822. exec_lua([[
  823. return vim.tbl_filter(function(v) return (v % 2) == 0 end, {})
  824. ]])
  825. )
  826. eq(
  827. { 2 },
  828. exec_lua([[
  829. return vim.tbl_filter(function(v) return (v % 2) == 0 end, {1, 2, 3})
  830. ]])
  831. )
  832. eq(
  833. { { i = 2 } },
  834. exec_lua([[
  835. return vim.tbl_filter(function(v) return (v.i % 2) == 0 end, {{i=1}, {i=2}, {i=3}})
  836. ]])
  837. )
  838. end)
  839. it('vim.isarray', function()
  840. eq(true, exec_lua('return vim.isarray({})'))
  841. eq(false, exec_lua('return vim.isarray(vim.empty_dict())'))
  842. eq(true, exec_lua("return vim.isarray({'a', 'b', 'c'})"))
  843. eq(false, exec_lua("return vim.isarray({'a', '32', a='hello', b='baz'})"))
  844. eq(false, exec_lua("return vim.isarray({1, a='hello', b='baz'})"))
  845. eq(false, exec_lua("return vim.isarray({a='hello', b='baz', 1})"))
  846. eq(false, exec_lua("return vim.isarray({1, 2, nil, a='hello'})"))
  847. eq(true, exec_lua('return vim.isarray({1, 2, nil, 4})'))
  848. eq(true, exec_lua('return vim.isarray({nil, 2, 3, 4})'))
  849. eq(false, exec_lua('return vim.isarray({1, [1.5]=2, [3]=3})'))
  850. end)
  851. it('vim.islist', function()
  852. eq(true, exec_lua('return vim.islist({})'))
  853. eq(false, exec_lua('return vim.islist(vim.empty_dict())'))
  854. eq(true, exec_lua("return vim.islist({'a', 'b', 'c'})"))
  855. eq(false, exec_lua("return vim.islist({'a', '32', a='hello', b='baz'})"))
  856. eq(false, exec_lua("return vim.islist({1, a='hello', b='baz'})"))
  857. eq(false, exec_lua("return vim.islist({a='hello', b='baz', 1})"))
  858. eq(false, exec_lua("return vim.islist({1, 2, nil, a='hello'})"))
  859. eq(false, exec_lua('return vim.islist({1, 2, nil, 4})'))
  860. eq(false, exec_lua('return vim.islist({nil, 2, 3, 4})'))
  861. eq(false, exec_lua('return vim.islist({1, [1.5]=2, [3]=3})'))
  862. end)
  863. it('vim.tbl_isempty', function()
  864. eq(true, exec_lua('return vim.tbl_isempty({})'))
  865. eq(false, exec_lua('return vim.tbl_isempty({ 1, 2, 3 })'))
  866. eq(false, exec_lua('return vim.tbl_isempty({a=1, b=2, c=3})'))
  867. end)
  868. it('vim.tbl_get', function()
  869. eq(
  870. true,
  871. exec_lua("return vim.tbl_get({ test = { nested_test = true }}, 'test', 'nested_test')")
  872. )
  873. eq(NIL, exec_lua("return vim.tbl_get({ unindexable = true }, 'unindexable', 'missing_key')"))
  874. eq(NIL, exec_lua("return vim.tbl_get({ unindexable = 1 }, 'unindexable', 'missing_key')"))
  875. eq(
  876. NIL,
  877. exec_lua(
  878. "return vim.tbl_get({ unindexable = coroutine.create(function () end) }, 'unindexable', 'missing_key')"
  879. )
  880. )
  881. eq(
  882. NIL,
  883. exec_lua(
  884. "return vim.tbl_get({ unindexable = function () end }, 'unindexable', 'missing_key')"
  885. )
  886. )
  887. eq(NIL, exec_lua("return vim.tbl_get({}, 'missing_key')"))
  888. eq(NIL, exec_lua('return vim.tbl_get({})'))
  889. eq(1, exec_lua("return select('#', vim.tbl_get({}))"))
  890. eq(1, exec_lua("return select('#', vim.tbl_get({ nested = {} }, 'nested', 'missing_key'))"))
  891. end)
  892. it('vim.tbl_extend', function()
  893. ok(exec_lua([[
  894. local a = {x = 1}
  895. local b = {y = 2}
  896. local c = vim.tbl_extend("keep", a, b)
  897. return c.x == 1 and b.y == 2 and vim.tbl_count(c) == 2
  898. ]]))
  899. ok(exec_lua([[
  900. local a = {x = 1}
  901. local b = {y = 2}
  902. local c = {z = 3}
  903. local d = vim.tbl_extend("keep", a, b, c)
  904. return d.x == 1 and d.y == 2 and d.z == 3 and vim.tbl_count(d) == 3
  905. ]]))
  906. ok(exec_lua([[
  907. local a = {x = 1}
  908. local b = {x = 3}
  909. local c = vim.tbl_extend("keep", a, b)
  910. return c.x == 1 and vim.tbl_count(c) == 1
  911. ]]))
  912. ok(exec_lua([[
  913. local a = {x = 1}
  914. local b = {x = 3}
  915. local c = vim.tbl_extend("force", a, b)
  916. return c.x == 3 and vim.tbl_count(c) == 1
  917. ]]))
  918. ok(exec_lua([[
  919. local a = vim.empty_dict()
  920. local b = {}
  921. local c = vim.tbl_extend("keep", a, b)
  922. return not vim.islist(c) and vim.tbl_count(c) == 0
  923. ]]))
  924. ok(exec_lua([[
  925. local a = {}
  926. local b = vim.empty_dict()
  927. local c = vim.tbl_extend("keep", a, b)
  928. return vim.islist(c) and vim.tbl_count(c) == 0
  929. ]]))
  930. ok(exec_lua([[
  931. local a = {x = {a = 1, b = 2}}
  932. local b = {x = {a = 2, c = {y = 3}}}
  933. local c = vim.tbl_extend("keep", a, b)
  934. local count = 0
  935. for _ in pairs(c) do count = count + 1 end
  936. return c.x.a == 1 and c.x.b == 2 and c.x.c == nil and count == 1
  937. ]]))
  938. matches(
  939. 'invalid "behavior": nil',
  940. pcall_err(
  941. exec_lua,
  942. [[
  943. return vim.tbl_extend()
  944. ]]
  945. )
  946. )
  947. matches(
  948. 'wrong number of arguments %(given 1, expected at least 3%)',
  949. pcall_err(
  950. exec_lua,
  951. [[
  952. return vim.tbl_extend("keep")
  953. ]]
  954. )
  955. )
  956. matches(
  957. 'wrong number of arguments %(given 2, expected at least 3%)',
  958. pcall_err(
  959. exec_lua,
  960. [[
  961. return vim.tbl_extend("keep", {})
  962. ]]
  963. )
  964. )
  965. end)
  966. it('vim.tbl_deep_extend', function()
  967. ok(exec_lua([[
  968. local a = {x = {a = 1, b = 2}}
  969. local b = {x = {a = 2, c = {y = 3}}}
  970. local c = vim.tbl_deep_extend("keep", a, b)
  971. local count = 0
  972. for _ in pairs(c) do count = count + 1 end
  973. return c.x.a == 1 and c.x.b == 2 and c.x.c.y == 3 and count == 1
  974. ]]))
  975. ok(exec_lua([[
  976. local a = {x = {a = 1, b = 2}}
  977. local b = {x = {a = 2, c = {y = 3}}}
  978. local c = vim.tbl_deep_extend("force", a, b)
  979. local count = 0
  980. for _ in pairs(c) do count = count + 1 end
  981. return c.x.a == 2 and c.x.b == 2 and c.x.c.y == 3 and count == 1
  982. ]]))
  983. ok(exec_lua([[
  984. local a = {x = {a = 1, b = 2}}
  985. local b = {x = {a = 2, c = {y = 3}}}
  986. local c = {x = {c = 4, d = {y = 4}}}
  987. local d = vim.tbl_deep_extend("keep", a, b, c)
  988. local count = 0
  989. for _ in pairs(c) do count = count + 1 end
  990. 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
  991. ]]))
  992. ok(exec_lua([[
  993. local a = {x = {a = 1, b = 2}}
  994. local b = {x = {a = 2, c = {y = 3}}}
  995. local c = {x = {c = 4, d = {y = 4}}}
  996. local d = vim.tbl_deep_extend("force", a, b, c)
  997. local count = 0
  998. for _ in pairs(c) do count = count + 1 end
  999. return d.x.a == 2 and d.x.b == 2 and d.x.c == 4 and d.x.d.y == 4 and count == 1
  1000. ]]))
  1001. ok(exec_lua([[
  1002. local a = vim.empty_dict()
  1003. local b = {}
  1004. local c = vim.tbl_deep_extend("keep", a, b)
  1005. local count = 0
  1006. for _ in pairs(c) do count = count + 1 end
  1007. return not vim.islist(c) and count == 0
  1008. ]]))
  1009. ok(exec_lua([[
  1010. local a = {}
  1011. local b = vim.empty_dict()
  1012. local c = vim.tbl_deep_extend("keep", a, b)
  1013. local count = 0
  1014. for _ in pairs(c) do count = count + 1 end
  1015. return vim.islist(c) and count == 0
  1016. ]]))
  1017. eq(
  1018. { a = { b = 1 } },
  1019. exec_lua([[
  1020. local a = { a = { b = 1 } }
  1021. local b = { a = {} }
  1022. return vim.tbl_deep_extend("force", a, b)
  1023. ]])
  1024. )
  1025. eq(
  1026. { a = { b = 1 } },
  1027. exec_lua([[
  1028. local a = { a = 123 }
  1029. local b = { a = { b = 1} }
  1030. return vim.tbl_deep_extend("force", a, b)
  1031. ]])
  1032. )
  1033. ok(exec_lua([[
  1034. local a = { a = {[2] = 3} }
  1035. local b = { a = {[3] = 3} }
  1036. local c = vim.tbl_deep_extend("force", a, b)
  1037. return vim.deep_equal(c, {a = {[2] = 3, [3] = 3}})
  1038. ]]))
  1039. eq(
  1040. { a = 123 },
  1041. exec_lua([[
  1042. local a = { a = { b = 1} }
  1043. local b = { a = 123 }
  1044. return vim.tbl_deep_extend("force", a, b)
  1045. ]])
  1046. )
  1047. ok(exec_lua([[
  1048. local a = { sub = { 'a', 'b' } }
  1049. local b = { sub = { 'b', 'c' } }
  1050. local c = vim.tbl_deep_extend('force', a, b)
  1051. return vim.deep_equal(c, { sub = { 'b', 'c' } })
  1052. ]]))
  1053. matches('invalid "behavior": nil', pcall_err(exec_lua, [[return vim.tbl_deep_extend()]]))
  1054. matches(
  1055. 'wrong number of arguments %(given 1, expected at least 3%)',
  1056. pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep")]])
  1057. )
  1058. matches(
  1059. 'wrong number of arguments %(given 2, expected at least 3%)',
  1060. pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {})]])
  1061. )
  1062. matches(
  1063. 'after the second argument%: expected table, got number',
  1064. pcall_err(exec_lua, [[return vim.tbl_deep_extend("keep", {}, 42)]])
  1065. )
  1066. end)
  1067. it('vim.tbl_count', function()
  1068. eq(0, exec_lua [[ return vim.tbl_count({}) ]])
  1069. eq(0, exec_lua [[ return vim.tbl_count(vim.empty_dict()) ]])
  1070. eq(0, exec_lua [[ return vim.tbl_count({nil}) ]])
  1071. eq(0, exec_lua [[ return vim.tbl_count({a=nil}) ]])
  1072. eq(1, exec_lua [[ return vim.tbl_count({1}) ]])
  1073. eq(2, exec_lua [[ return vim.tbl_count({1, 2}) ]])
  1074. eq(2, exec_lua [[ return vim.tbl_count({1, nil, 3}) ]])
  1075. eq(1, exec_lua [[ return vim.tbl_count({a=1}) ]])
  1076. eq(2, exec_lua [[ return vim.tbl_count({a=1, b=2}) ]])
  1077. eq(2, exec_lua [[ return vim.tbl_count({a=1, b=nil, c=3}) ]])
  1078. end)
  1079. it('vim.deep_equal', function()
  1080. eq(true, exec_lua [[ return vim.deep_equal({a=1}, {a=1}) ]])
  1081. eq(true, exec_lua [[ return vim.deep_equal({a={b=1}}, {a={b=1}}) ]])
  1082. eq(true, exec_lua [[ return vim.deep_equal({a={b={nil}}}, {a={b={}}}) ]])
  1083. eq(true, exec_lua [[ return vim.deep_equal({a=1, [5]=5}, {nil,nil,nil,nil,5,a=1}) ]])
  1084. eq(false, exec_lua [[ return vim.deep_equal(1, {nil,nil,nil,nil,5,a=1}) ]])
  1085. eq(false, exec_lua [[ return vim.deep_equal(1, 3) ]])
  1086. eq(false, exec_lua [[ return vim.deep_equal(nil, 3) ]])
  1087. eq(false, exec_lua [[ return vim.deep_equal({a=1}, {a=2}) ]])
  1088. end)
  1089. it('vim.list_extend', function()
  1090. eq({ 1, 2, 3 }, exec_lua [[ return vim.list_extend({1}, {2,3}) ]])
  1091. matches(
  1092. 'src: expected table, got nil',
  1093. pcall_err(exec_lua, [[ return vim.list_extend({1}, nil) ]])
  1094. )
  1095. eq({ 1, 2 }, exec_lua [[ return vim.list_extend({1}, {2;a=1}) ]])
  1096. eq(true, exec_lua [[ local a = {1} return vim.list_extend(a, {2;a=1}) == a ]])
  1097. eq({ 2 }, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1) ]])
  1098. eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 2) ]])
  1099. eq({}, exec_lua [[ return vim.list_extend({}, {2;a=1}, 1, -1) ]])
  1100. eq({ 2 }, exec_lua [[ return vim.list_extend({}, {2;a=1}, -1, 2) ]])
  1101. end)
  1102. it('vim.tbl_add_reverse_lookup', function()
  1103. eq(
  1104. true,
  1105. exec_lua [[
  1106. local a = { A = 1 }
  1107. vim.tbl_add_reverse_lookup(a)
  1108. return vim.deep_equal(a, { A = 1; [1] = 'A'; })
  1109. ]]
  1110. )
  1111. -- Throw an error for trying to do it twice (run into an existing key)
  1112. local code = [[
  1113. local res = {}
  1114. local a = { A = 1 }
  1115. vim.tbl_add_reverse_lookup(a)
  1116. assert(vim.deep_equal(a, { A = 1; [1] = 'A'; }))
  1117. vim.tbl_add_reverse_lookup(a)
  1118. ]]
  1119. matches(
  1120. 'The reverse lookup found an existing value for "[1A]" while processing key "[1A]"$',
  1121. pcall_err(exec_lua, code)
  1122. )
  1123. end)
  1124. it('vim.spairs', function()
  1125. local res = ''
  1126. local table = {
  1127. ccc = 1,
  1128. bbb = 2,
  1129. ddd = 3,
  1130. aaa = 4,
  1131. }
  1132. for key, _ in vim.spairs(table) do
  1133. res = res .. key
  1134. end
  1135. matches('aaabbbcccddd', res)
  1136. end)
  1137. it('vim.call, vim.fn', function()
  1138. eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]]))
  1139. eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]]))
  1140. -- compat: nvim_call_function uses "special" value for Vimscript float
  1141. eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]]))
  1142. exec([[
  1143. func! FooFunc(test)
  1144. let g:test = a:test
  1145. return {}
  1146. endfunc
  1147. func! VarArg(...)
  1148. return a:000
  1149. endfunc
  1150. func! Nilly()
  1151. return [v:null, v:null]
  1152. endfunc
  1153. ]])
  1154. eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]]))
  1155. eq(3, eval('g:test'))
  1156. eq(true, exec_lua([[return vim.tbl_isempty(vim.api.nvim_call_function("FooFunc", {5}))]]))
  1157. eq(5, eval('g:test'))
  1158. eq({ 2, 'foo', true }, exec_lua([[return vim.fn.VarArg(2, "foo", true)]]))
  1159. eq(
  1160. true,
  1161. exec_lua([[
  1162. local x = vim.fn.Nilly()
  1163. return #x == 2 and x[1] == vim.NIL and x[2] == vim.NIL
  1164. ]])
  1165. )
  1166. eq({ NIL, NIL }, exec_lua([[return vim.fn.Nilly()]]))
  1167. -- error handling
  1168. eq(
  1169. { false, 'Vim:E897: List or Blob required' },
  1170. exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]])
  1171. )
  1172. -- conversion between LuaRef and Vim Funcref
  1173. eq(
  1174. true,
  1175. exec_lua([[
  1176. local x = vim.fn.VarArg(function() return 'foo' end, function() return 'bar' end)
  1177. return #x == 2 and x[1]() == 'foo' and x[2]() == 'bar'
  1178. ]])
  1179. )
  1180. -- Test for #20211
  1181. eq(
  1182. 'a (b) c',
  1183. exec_lua([[
  1184. return vim.fn.substitute('a b c', 'b', function(m) return '(' .. m[1] .. ')' end, 'g')
  1185. ]])
  1186. )
  1187. end)
  1188. it('vim.fn errors when calling API function', function()
  1189. matches(
  1190. 'Tried to call API function with vim.fn: use vim.api.nvim_get_current_line instead',
  1191. pcall_err(exec_lua, 'vim.fn.nvim_get_current_line()')
  1192. )
  1193. end)
  1194. it('vim.fn is allowed in "fast" context by some functions #18306', function()
  1195. exec_lua([[
  1196. local timer = vim.uv.new_timer()
  1197. timer:start(0, 0, function()
  1198. timer:close()
  1199. assert(vim.in_fast_event())
  1200. vim.g.fnres = vim.fn.iconv('hello', 'utf-8', 'utf-8')
  1201. end)
  1202. ]])
  1203. poke_eventloop()
  1204. eq('hello', exec_lua [[return vim.g.fnres]])
  1205. end)
  1206. it('vim.rpcrequest and vim.rpcnotify', function()
  1207. exec_lua([[
  1208. chan = vim.fn.jobstart({'cat'}, {rpc=true})
  1209. vim.rpcrequest(chan, 'nvim_set_current_line', 'meow')
  1210. ]])
  1211. eq('meow', api.nvim_get_current_line())
  1212. command("let x = [3, 'aa', v:true, v:null]")
  1213. eq(
  1214. true,
  1215. exec_lua([[
  1216. ret = vim.rpcrequest(chan, 'nvim_get_var', 'x')
  1217. return #ret == 4 and ret[1] == 3 and ret[2] == 'aa' and ret[3] == true and ret[4] == vim.NIL
  1218. ]])
  1219. )
  1220. eq({ 3, 'aa', true, NIL }, exec_lua([[return ret]]))
  1221. eq(
  1222. { {}, {}, false, true },
  1223. exec_lua([[
  1224. vim.rpcrequest(chan, 'nvim_exec', 'let xx = {}\nlet yy = []', false)
  1225. local dict = vim.rpcrequest(chan, 'nvim_eval', 'xx')
  1226. local list = vim.rpcrequest(chan, 'nvim_eval', 'yy')
  1227. return {dict, list, vim.islist(dict), vim.islist(list)}
  1228. ]])
  1229. )
  1230. exec_lua([[
  1231. vim.rpcrequest(chan, 'nvim_set_var', 'aa', {})
  1232. vim.rpcrequest(chan, 'nvim_set_var', 'bb', vim.empty_dict())
  1233. ]])
  1234. eq({ 1, 1 }, eval('[type(g:aa) == type([]), type(g:bb) == type({})]'))
  1235. -- error handling
  1236. eq({ false, 'Invalid channel: 23' }, exec_lua([[return {pcall(vim.rpcrequest, 23, 'foo')}]]))
  1237. eq({ false, 'Invalid channel: 23' }, exec_lua([[return {pcall(vim.rpcnotify, 23, 'foo')}]]))
  1238. eq(
  1239. { false, 'Vim:E121: Undefined variable: foobar' },
  1240. exec_lua([[return {pcall(vim.rpcrequest, chan, 'nvim_eval', "foobar")}]])
  1241. )
  1242. -- rpcnotify doesn't wait on request
  1243. eq(
  1244. 'meow',
  1245. exec_lua([[
  1246. vim.rpcnotify(chan, 'nvim_set_current_line', 'foo')
  1247. return vim.api.nvim_get_current_line()
  1248. ]])
  1249. )
  1250. retry(10, nil, function()
  1251. eq('foo', api.nvim_get_current_line())
  1252. end)
  1253. local screen = Screen.new(50, 7)
  1254. exec_lua([[
  1255. timer = vim.uv.new_timer()
  1256. timer:start(20, 0, function ()
  1257. -- notify ok (executed later when safe)
  1258. vim.rpcnotify(chan, 'nvim_set_var', 'yy', {3, vim.NIL})
  1259. -- rpcrequest an error
  1260. vim.rpcrequest(chan, 'nvim_set_current_line', 'bork')
  1261. end)
  1262. ]])
  1263. screen:expect {
  1264. grid = [[
  1265. {9:[string "<nvim>"]:6: E5560: rpcrequest must not be}|
  1266. {9: called in a fast event context} |
  1267. {9:stack traceback:} |
  1268. {9: [C]: in function 'rpcrequest'} |
  1269. {9: [string "<nvim>"]:6: in function <[string }|
  1270. {9:"<nvim>"]:2>} |
  1271. {6:Press ENTER or type command to continue}^ |
  1272. ]],
  1273. }
  1274. feed('<cr>')
  1275. retry(10, nil, function()
  1276. eq({ 3, NIL }, api.nvim_get_var('yy'))
  1277. end)
  1278. exec_lua([[timer:close()]])
  1279. end)
  1280. it('vim.empty_dict()', function()
  1281. eq(
  1282. { true, false, true, true },
  1283. exec_lua([[
  1284. vim.api.nvim_set_var('listy', {})
  1285. vim.api.nvim_set_var('dicty', vim.empty_dict())
  1286. local listy = vim.fn.eval("listy")
  1287. local dicty = vim.fn.eval("dicty")
  1288. return {vim.islist(listy), vim.islist(dicty), next(listy) == nil, next(dicty) == nil}
  1289. ]])
  1290. )
  1291. -- vim.empty_dict() gives new value each time
  1292. -- equality is not overridden (still by ref)
  1293. -- non-empty table uses the usual heuristics (ignores the tag)
  1294. eq(
  1295. { false, { 'foo' }, { namey = 'bar' } },
  1296. exec_lua([[
  1297. local aa = vim.empty_dict()
  1298. local bb = vim.empty_dict()
  1299. local equally = (aa == bb)
  1300. aa[1] = "foo"
  1301. bb["namey"] = "bar"
  1302. return {equally, aa, bb}
  1303. ]])
  1304. )
  1305. eq('{ {}, vim.empty_dict() }', exec_lua('return vim.inspect({{}, vim.empty_dict()})'))
  1306. eq('{}', exec_lua([[ return vim.fn.json_encode(vim.empty_dict()) ]]))
  1307. eq('{"a": {}, "b": []}', exec_lua([[ return vim.fn.json_encode({a=vim.empty_dict(), b={}}) ]]))
  1308. end)
  1309. it('vim.validate (fast form)', function()
  1310. exec_lua("vim.validate('arg1', {}, 'table')")
  1311. exec_lua("vim.validate('arg1', nil, 'table', true)")
  1312. exec_lua("vim.validate('arg1', { foo='foo' }, 'table')")
  1313. exec_lua("vim.validate('arg1', { 'foo' }, 'table')")
  1314. exec_lua("vim.validate('arg1', 'foo', 'string')")
  1315. exec_lua("vim.validate('arg1', nil, 'string', true)")
  1316. exec_lua("vim.validate('arg1', 1, 'number')")
  1317. exec_lua("vim.validate('arg1', 0, 'number')")
  1318. exec_lua("vim.validate('arg1', 0.1, 'number')")
  1319. exec_lua("vim.validate('arg1', nil, 'number', true)")
  1320. exec_lua("vim.validate('arg1', true, 'boolean')")
  1321. exec_lua("vim.validate('arg1', false, 'boolean')")
  1322. exec_lua("vim.validate('arg1', nil, 'boolean', true)")
  1323. exec_lua("vim.validate('arg1', function()end, 'function')")
  1324. exec_lua("vim.validate('arg1', nil, 'function', true)")
  1325. exec_lua("vim.validate('arg1', nil, 'nil')")
  1326. exec_lua("vim.validate('arg1', nil, 'nil', true)")
  1327. exec_lua("vim.validate('arg1', coroutine.create(function()end), 'thread')")
  1328. exec_lua("vim.validate('arg1', nil, 'thread', true)")
  1329. exec_lua("vim.validate('arg1', 2, function(a) return (a % 2) == 0 end, 'even number')")
  1330. exec_lua("vim.validate('arg1', 5, {'number', 'string'})")
  1331. exec_lua("vim.validate('arg2', 'foo', {'number', 'string'})")
  1332. matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number'))
  1333. matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string'))
  1334. matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table'))
  1335. matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function'))
  1336. matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string'))
  1337. matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table'))
  1338. matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function'))
  1339. matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number'))
  1340. matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate('arg1', 1, 'x')"))
  1341. matches('invalid validator: 1', pcall_err(exec_lua, "vim.validate('arg1', 1, 1)"))
  1342. matches('invalid arguments', pcall_err(exec_lua, "vim.validate('arg1', { 1 })"))
  1343. -- Validated parameters are required by default.
  1344. matches(
  1345. 'arg1: expected string, got nil',
  1346. pcall_err(exec_lua, "vim.validate('arg1', nil, 'string')")
  1347. )
  1348. -- Explicitly required.
  1349. matches(
  1350. 'arg1: expected string, got nil',
  1351. pcall_err(exec_lua, "vim.validate('arg1', nil, 'string', false)")
  1352. )
  1353. matches(
  1354. 'arg1: expected table, got number',
  1355. pcall_err(exec_lua, "vim.validate('arg1', 1, 'table')")
  1356. )
  1357. matches(
  1358. 'arg1: expected even number, got 3',
  1359. pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end, 'even number')")
  1360. )
  1361. matches(
  1362. 'arg1: expected %?, got 3',
  1363. pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1 end)")
  1364. )
  1365. matches(
  1366. 'arg1: expected number|string, got nil',
  1367. pcall_err(exec_lua, "vim.validate('arg1', nil, {'number', 'string'})")
  1368. )
  1369. -- Pass an additional message back.
  1370. matches(
  1371. 'arg1: expected %?, got 3. Info: TEST_MSG',
  1372. pcall_err(exec_lua, "vim.validate('arg1', 3, function(a) return a == 1, 'TEST_MSG' end)")
  1373. )
  1374. end)
  1375. it('vim.validate (spec form)', function()
  1376. exec_lua("vim.validate{arg1={{}, 'table' }}")
  1377. exec_lua("vim.validate{arg1={{}, 't' }}")
  1378. exec_lua("vim.validate{arg1={nil, 't', true }}")
  1379. exec_lua("vim.validate{arg1={{ foo='foo' }, 't' }}")
  1380. exec_lua("vim.validate{arg1={{ 'foo' }, 't' }}")
  1381. exec_lua("vim.validate{arg1={'foo', 'string' }}")
  1382. exec_lua("vim.validate{arg1={'foo', 's' }}")
  1383. exec_lua("vim.validate{arg1={'', 's' }}")
  1384. exec_lua("vim.validate{arg1={nil, 's', true }}")
  1385. exec_lua("vim.validate{arg1={1, 'number' }}")
  1386. exec_lua("vim.validate{arg1={1, 'n' }}")
  1387. exec_lua("vim.validate{arg1={0, 'n' }}")
  1388. exec_lua("vim.validate{arg1={0.1, 'n' }}")
  1389. exec_lua("vim.validate{arg1={nil, 'n', true }}")
  1390. exec_lua("vim.validate{arg1={true, 'boolean' }}")
  1391. exec_lua("vim.validate{arg1={true, 'b' }}")
  1392. exec_lua("vim.validate{arg1={false, 'b' }}")
  1393. exec_lua("vim.validate{arg1={nil, 'b', true }}")
  1394. exec_lua("vim.validate{arg1={function()end, 'function' }}")
  1395. exec_lua("vim.validate{arg1={function()end, 'f' }}")
  1396. exec_lua("vim.validate{arg1={nil, 'f', true }}")
  1397. exec_lua("vim.validate{arg1={nil, 'nil' }}")
  1398. exec_lua("vim.validate{arg1={nil, 'nil', true }}")
  1399. exec_lua("vim.validate{arg1={coroutine.create(function()end), 'thread' }}")
  1400. exec_lua("vim.validate{arg1={nil, 'thread', true }}")
  1401. exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}")
  1402. exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}")
  1403. exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}")
  1404. matches('expected table, got number', pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
  1405. matches('arg1: expected x, got number', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}"))
  1406. matches('invalid validator: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}'))
  1407. matches('invalid validator: nil', pcall_err(exec_lua, 'vim.validate{ arg1={ 1 }}'))
  1408. -- Validated parameters are required by default.
  1409. matches(
  1410. 'arg1: expected string, got nil',
  1411. pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's' }}")
  1412. )
  1413. -- Explicitly required.
  1414. matches(
  1415. 'arg1: expected string, got nil',
  1416. pcall_err(exec_lua, "vim.validate{ arg1={ nil, 's', false }}")
  1417. )
  1418. matches('arg1: expected table, got number', pcall_err(exec_lua, "vim.validate{arg1={1, 't'}}"))
  1419. matches(
  1420. 'arg2: expected string, got number',
  1421. pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={1, 's'}}")
  1422. )
  1423. matches(
  1424. 'arg2: expected string, got nil',
  1425. pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")
  1426. )
  1427. matches(
  1428. 'arg2: expected string, got nil',
  1429. pcall_err(exec_lua, "vim.validate{arg1={{}, 't'}, arg2={nil, 's'}}")
  1430. )
  1431. matches(
  1432. 'arg1: expected even number, got 3',
  1433. pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}")
  1434. )
  1435. matches(
  1436. 'arg1: expected %?, got 3',
  1437. pcall_err(exec_lua, 'vim.validate{arg1={3, function(a) return a == 1 end}}')
  1438. )
  1439. matches(
  1440. 'arg1: expected number|string, got nil',
  1441. pcall_err(exec_lua, "vim.validate{ arg1={ nil, {'n', 's'} }}")
  1442. )
  1443. -- Pass an additional message back.
  1444. matches(
  1445. 'arg1: expected %?, got 3. Info: TEST_MSG',
  1446. pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1, 'TEST_MSG' end}}")
  1447. )
  1448. end)
  1449. it('vim.is_callable', function()
  1450. eq(true, exec_lua('return vim.is_callable(function()end)'))
  1451. eq(
  1452. true,
  1453. exec_lua([[
  1454. local meta = { __call = function()end }
  1455. local function new_callable()
  1456. return setmetatable({}, meta)
  1457. end
  1458. local callable = new_callable()
  1459. return vim.is_callable(callable)
  1460. ]])
  1461. )
  1462. eq(
  1463. { false, false },
  1464. exec_lua([[
  1465. local meta = { __call = {} }
  1466. assert(meta.__call)
  1467. local function new()
  1468. return setmetatable({}, meta)
  1469. end
  1470. local not_callable = new()
  1471. return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
  1472. ]])
  1473. )
  1474. eq(
  1475. { false, false },
  1476. exec_lua([[
  1477. local function new()
  1478. return { __call = function()end }
  1479. end
  1480. local not_callable = new()
  1481. assert(not_callable.__call)
  1482. return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
  1483. ]])
  1484. )
  1485. eq(
  1486. { false, false },
  1487. exec_lua([[
  1488. local meta = setmetatable(
  1489. { __index = { __call = function() end } },
  1490. { __index = { __call = function() end } }
  1491. )
  1492. assert(meta.__call)
  1493. local not_callable = setmetatable({}, meta)
  1494. assert(not_callable.__call)
  1495. return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
  1496. ]])
  1497. )
  1498. eq(
  1499. { false, false },
  1500. exec_lua([[
  1501. local meta = setmetatable({
  1502. __index = function()
  1503. return function() end
  1504. end,
  1505. }, {
  1506. __index = function()
  1507. return function() end
  1508. end,
  1509. })
  1510. assert(meta.__call)
  1511. local not_callable = setmetatable({}, meta)
  1512. assert(not_callable.__call)
  1513. return { pcall(function() not_callable() end), vim.is_callable(not_callable) }
  1514. ]])
  1515. )
  1516. eq(false, exec_lua('return vim.is_callable(1)'))
  1517. eq(false, exec_lua("return vim.is_callable('foo')"))
  1518. eq(false, exec_lua('return vim.is_callable({})'))
  1519. end)
  1520. it('vim.g', function()
  1521. exec_lua [[
  1522. vim.api.nvim_set_var("testing", "hi")
  1523. vim.api.nvim_set_var("other", 123)
  1524. vim.api.nvim_set_var("floaty", 5120.1)
  1525. vim.api.nvim_set_var("nullvar", vim.NIL)
  1526. vim.api.nvim_set_var("to_delete", {hello="world"})
  1527. ]]
  1528. eq('hi', fn.luaeval 'vim.g.testing')
  1529. eq(123, fn.luaeval 'vim.g.other')
  1530. eq(5120.1, fn.luaeval 'vim.g.floaty')
  1531. eq(NIL, fn.luaeval 'vim.g.nonexistent')
  1532. eq(NIL, fn.luaeval 'vim.g.nullvar')
  1533. -- lost over RPC, so test locally:
  1534. eq(
  1535. { false, true },
  1536. exec_lua [[
  1537. return {vim.g.nonexistent == vim.NIL, vim.g.nullvar == vim.NIL}
  1538. ]]
  1539. )
  1540. eq({ hello = 'world' }, fn.luaeval 'vim.g.to_delete')
  1541. exec_lua [[
  1542. vim.g.to_delete = nil
  1543. ]]
  1544. eq(NIL, fn.luaeval 'vim.g.to_delete')
  1545. matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.g[0].testing'))
  1546. exec_lua [[
  1547. local counter = 0
  1548. local function add_counter() counter = counter + 1 end
  1549. local function get_counter() return counter end
  1550. vim.g.AddCounter = add_counter
  1551. vim.g.GetCounter = get_counter
  1552. vim.g.fn = {add = add_counter, get = get_counter}
  1553. vim.g.AddParens = function(s) return '(' .. s .. ')' end
  1554. ]]
  1555. eq(0, eval('g:GetCounter()'))
  1556. eval('g:AddCounter()')
  1557. eq(1, eval('g:GetCounter()'))
  1558. eval('g:AddCounter()')
  1559. eq(2, eval('g:GetCounter()'))
  1560. exec_lua([[vim.g.AddCounter()]])
  1561. eq(3, exec_lua([[return vim.g.GetCounter()]]))
  1562. exec_lua([[vim.api.nvim_get_var('AddCounter')()]])
  1563. eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]]))
  1564. exec_lua([[vim.g.fn.add()]])
  1565. eq(5, exec_lua([[return vim.g.fn.get()]]))
  1566. exec_lua([[vim.api.nvim_get_var('fn').add()]])
  1567. eq(6, exec_lua([[return vim.api.nvim_get_var('fn').get()]]))
  1568. eq('((foo))', eval([['foo'->AddParens()->AddParens()]]))
  1569. exec_lua [[
  1570. local counter = 0
  1571. local function add_counter() counter = counter + 1 end
  1572. local function get_counter() return counter end
  1573. vim.api.nvim_set_var('AddCounter', add_counter)
  1574. vim.api.nvim_set_var('GetCounter', get_counter)
  1575. vim.api.nvim_set_var('fn', {add = add_counter, get = get_counter})
  1576. vim.api.nvim_set_var('AddParens', function(s) return '(' .. s .. ')' end)
  1577. ]]
  1578. eq(0, eval('g:GetCounter()'))
  1579. eval('g:AddCounter()')
  1580. eq(1, eval('g:GetCounter()'))
  1581. eval('g:AddCounter()')
  1582. eq(2, eval('g:GetCounter()'))
  1583. exec_lua([[vim.g.AddCounter()]])
  1584. eq(3, exec_lua([[return vim.g.GetCounter()]]))
  1585. exec_lua([[vim.api.nvim_get_var('AddCounter')()]])
  1586. eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]]))
  1587. exec_lua([[vim.g.fn.add()]])
  1588. eq(5, exec_lua([[return vim.g.fn.get()]]))
  1589. exec_lua([[vim.api.nvim_get_var('fn').add()]])
  1590. eq(6, exec_lua([[return vim.api.nvim_get_var('fn').get()]]))
  1591. eq('((foo))', eval([['foo'->AddParens()->AddParens()]]))
  1592. exec([[
  1593. function Test()
  1594. endfunction
  1595. function s:Test()
  1596. endfunction
  1597. let g:Unknown_func = function('Test')
  1598. let g:Unknown_script_func = function('s:Test')
  1599. ]])
  1600. eq(NIL, exec_lua([[return vim.g.Unknown_func]]))
  1601. eq(NIL, exec_lua([[return vim.g.Unknown_script_func]]))
  1602. -- Check if autoload works properly
  1603. local pathsep = n.get_pathsep()
  1604. local xconfig = 'Xhome' .. pathsep .. 'Xconfig'
  1605. local xdata = 'Xhome' .. pathsep .. 'Xdata'
  1606. local autoload_folder = table.concat({ xconfig, 'nvim', 'autoload' }, pathsep)
  1607. local autoload_file = table.concat({ autoload_folder, 'testload.vim' }, pathsep)
  1608. mkdir_p(autoload_folder)
  1609. write_file(autoload_file, [[let testload#value = 2]])
  1610. clear { args_rm = { '-u' }, env = { XDG_CONFIG_HOME = xconfig, XDG_DATA_HOME = xdata } }
  1611. eq(2, exec_lua("return vim.g['testload#value']"))
  1612. rmdir('Xhome')
  1613. end)
  1614. it('vim.b', function()
  1615. exec_lua [[
  1616. vim.api.nvim_buf_set_var(0, "testing", "hi")
  1617. vim.api.nvim_buf_set_var(0, "other", 123)
  1618. vim.api.nvim_buf_set_var(0, "floaty", 5120.1)
  1619. vim.api.nvim_buf_set_var(0, "nullvar", vim.NIL)
  1620. vim.api.nvim_buf_set_var(0, "to_delete", {hello="world"})
  1621. BUF = vim.api.nvim_create_buf(false, true)
  1622. vim.api.nvim_buf_set_var(BUF, "testing", "bye")
  1623. ]]
  1624. eq('hi', fn.luaeval 'vim.b.testing')
  1625. eq('bye', fn.luaeval 'vim.b[BUF].testing')
  1626. eq(123, fn.luaeval 'vim.b.other')
  1627. eq(5120.1, fn.luaeval 'vim.b.floaty')
  1628. eq(NIL, fn.luaeval 'vim.b.nonexistent')
  1629. eq(NIL, fn.luaeval 'vim.b[BUF].nonexistent')
  1630. eq(NIL, fn.luaeval 'vim.b.nullvar')
  1631. -- lost over RPC, so test locally:
  1632. eq(
  1633. { false, true },
  1634. exec_lua [[
  1635. return {vim.b.nonexistent == vim.NIL, vim.b.nullvar == vim.NIL}
  1636. ]]
  1637. )
  1638. matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.b[BUF][0].testing'))
  1639. eq({ hello = 'world' }, fn.luaeval 'vim.b.to_delete')
  1640. exec_lua [[
  1641. vim.b.to_delete = nil
  1642. ]]
  1643. eq(NIL, fn.luaeval 'vim.b.to_delete')
  1644. exec_lua [[
  1645. local counter = 0
  1646. local function add_counter() counter = counter + 1 end
  1647. local function get_counter() return counter end
  1648. vim.b.AddCounter = add_counter
  1649. vim.b.GetCounter = get_counter
  1650. vim.b.fn = {add = add_counter, get = get_counter}
  1651. vim.b.AddParens = function(s) return '(' .. s .. ')' end
  1652. ]]
  1653. eq(0, eval('b:GetCounter()'))
  1654. eval('b:AddCounter()')
  1655. eq(1, eval('b:GetCounter()'))
  1656. eval('b:AddCounter()')
  1657. eq(2, eval('b:GetCounter()'))
  1658. exec_lua([[vim.b.AddCounter()]])
  1659. eq(3, exec_lua([[return vim.b.GetCounter()]]))
  1660. exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]])
  1661. eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]]))
  1662. exec_lua([[vim.b.fn.add()]])
  1663. eq(5, exec_lua([[return vim.b.fn.get()]]))
  1664. exec_lua([[vim.api.nvim_buf_get_var(0, 'fn').add()]])
  1665. eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'fn').get()]]))
  1666. eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]]))
  1667. exec_lua [[
  1668. local counter = 0
  1669. local function add_counter() counter = counter + 1 end
  1670. local function get_counter() return counter end
  1671. vim.api.nvim_buf_set_var(0, 'AddCounter', add_counter)
  1672. vim.api.nvim_buf_set_var(0, 'GetCounter', get_counter)
  1673. vim.api.nvim_buf_set_var(0, 'fn', {add = add_counter, get = get_counter})
  1674. vim.api.nvim_buf_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end)
  1675. ]]
  1676. eq(0, eval('b:GetCounter()'))
  1677. eval('b:AddCounter()')
  1678. eq(1, eval('b:GetCounter()'))
  1679. eval('b:AddCounter()')
  1680. eq(2, eval('b:GetCounter()'))
  1681. exec_lua([[vim.b.AddCounter()]])
  1682. eq(3, exec_lua([[return vim.b.GetCounter()]]))
  1683. exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]])
  1684. eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]]))
  1685. exec_lua([[vim.b.fn.add()]])
  1686. eq(5, exec_lua([[return vim.b.fn.get()]]))
  1687. exec_lua([[vim.api.nvim_buf_get_var(0, 'fn').add()]])
  1688. eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'fn').get()]]))
  1689. eq('((foo))', eval([['foo'->b:AddParens()->b:AddParens()]]))
  1690. exec([[
  1691. function Test()
  1692. endfunction
  1693. function s:Test()
  1694. endfunction
  1695. let b:Unknown_func = function('Test')
  1696. let b:Unknown_script_func = function('s:Test')
  1697. ]])
  1698. eq(NIL, exec_lua([[return vim.b.Unknown_func]]))
  1699. eq(NIL, exec_lua([[return vim.b.Unknown_script_func]]))
  1700. exec_lua [[
  1701. vim.cmd "vnew"
  1702. ]]
  1703. eq(NIL, fn.luaeval 'vim.b.testing')
  1704. eq(NIL, fn.luaeval 'vim.b.other')
  1705. eq(NIL, fn.luaeval 'vim.b.nonexistent')
  1706. end)
  1707. it('vim.w', function()
  1708. exec_lua [[
  1709. vim.api.nvim_win_set_var(0, "testing", "hi")
  1710. vim.api.nvim_win_set_var(0, "other", 123)
  1711. vim.api.nvim_win_set_var(0, "to_delete", {hello="world"})
  1712. BUF = vim.api.nvim_create_buf(false, true)
  1713. WIN = vim.api.nvim_open_win(BUF, false, {
  1714. width=10, height=10,
  1715. relative='win', row=0, col=0
  1716. })
  1717. vim.api.nvim_win_set_var(WIN, "testing", "bye")
  1718. ]]
  1719. eq('hi', fn.luaeval 'vim.w.testing')
  1720. eq('bye', fn.luaeval 'vim.w[WIN].testing')
  1721. eq(123, fn.luaeval 'vim.w.other')
  1722. eq(NIL, fn.luaeval 'vim.w.nonexistent')
  1723. eq(NIL, fn.luaeval 'vim.w[WIN].nonexistent')
  1724. matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.w[WIN][0].testing'))
  1725. eq({ hello = 'world' }, fn.luaeval 'vim.w.to_delete')
  1726. exec_lua [[
  1727. vim.w.to_delete = nil
  1728. ]]
  1729. eq(NIL, fn.luaeval 'vim.w.to_delete')
  1730. exec_lua [[
  1731. local counter = 0
  1732. local function add_counter() counter = counter + 1 end
  1733. local function get_counter() return counter end
  1734. vim.w.AddCounter = add_counter
  1735. vim.w.GetCounter = get_counter
  1736. vim.w.fn = {add = add_counter, get = get_counter}
  1737. vim.w.AddParens = function(s) return '(' .. s .. ')' end
  1738. ]]
  1739. eq(0, eval('w:GetCounter()'))
  1740. eval('w:AddCounter()')
  1741. eq(1, eval('w:GetCounter()'))
  1742. eval('w:AddCounter()')
  1743. eq(2, eval('w:GetCounter()'))
  1744. exec_lua([[vim.w.AddCounter()]])
  1745. eq(3, exec_lua([[return vim.w.GetCounter()]]))
  1746. exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]])
  1747. eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]]))
  1748. exec_lua([[vim.w.fn.add()]])
  1749. eq(5, exec_lua([[return vim.w.fn.get()]]))
  1750. exec_lua([[vim.api.nvim_win_get_var(0, 'fn').add()]])
  1751. eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'fn').get()]]))
  1752. eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]]))
  1753. exec_lua [[
  1754. local counter = 0
  1755. local function add_counter() counter = counter + 1 end
  1756. local function get_counter() return counter end
  1757. vim.api.nvim_win_set_var(0, 'AddCounter', add_counter)
  1758. vim.api.nvim_win_set_var(0, 'GetCounter', get_counter)
  1759. vim.api.nvim_win_set_var(0, 'fn', {add = add_counter, get = get_counter})
  1760. vim.api.nvim_win_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end)
  1761. ]]
  1762. eq(0, eval('w:GetCounter()'))
  1763. eval('w:AddCounter()')
  1764. eq(1, eval('w:GetCounter()'))
  1765. eval('w:AddCounter()')
  1766. eq(2, eval('w:GetCounter()'))
  1767. exec_lua([[vim.w.AddCounter()]])
  1768. eq(3, exec_lua([[return vim.w.GetCounter()]]))
  1769. exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]])
  1770. eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]]))
  1771. exec_lua([[vim.w.fn.add()]])
  1772. eq(5, exec_lua([[return vim.w.fn.get()]]))
  1773. exec_lua([[vim.api.nvim_win_get_var(0, 'fn').add()]])
  1774. eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'fn').get()]]))
  1775. eq('((foo))', eval([['foo'->w:AddParens()->w:AddParens()]]))
  1776. exec([[
  1777. function Test()
  1778. endfunction
  1779. function s:Test()
  1780. endfunction
  1781. let w:Unknown_func = function('Test')
  1782. let w:Unknown_script_func = function('s:Test')
  1783. ]])
  1784. eq(NIL, exec_lua([[return vim.w.Unknown_func]]))
  1785. eq(NIL, exec_lua([[return vim.w.Unknown_script_func]]))
  1786. exec_lua [[
  1787. vim.cmd "vnew"
  1788. ]]
  1789. eq(NIL, fn.luaeval 'vim.w.testing')
  1790. eq(NIL, fn.luaeval 'vim.w.other')
  1791. eq(NIL, fn.luaeval 'vim.w.nonexistent')
  1792. end)
  1793. it('vim.t', function()
  1794. exec_lua [[
  1795. vim.api.nvim_tabpage_set_var(0, "testing", "hi")
  1796. vim.api.nvim_tabpage_set_var(0, "other", 123)
  1797. vim.api.nvim_tabpage_set_var(0, "to_delete", {hello="world"})
  1798. ]]
  1799. eq('hi', fn.luaeval 'vim.t.testing')
  1800. eq(123, fn.luaeval 'vim.t.other')
  1801. eq(NIL, fn.luaeval 'vim.t.nonexistent')
  1802. eq('hi', fn.luaeval 'vim.t[0].testing')
  1803. eq(123, fn.luaeval 'vim.t[0].other')
  1804. eq(NIL, fn.luaeval 'vim.t[0].nonexistent')
  1805. matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.t[0][0].testing'))
  1806. eq({ hello = 'world' }, fn.luaeval 'vim.t.to_delete')
  1807. exec_lua [[
  1808. vim.t.to_delete = nil
  1809. ]]
  1810. eq(NIL, fn.luaeval 'vim.t.to_delete')
  1811. exec_lua [[
  1812. local counter = 0
  1813. local function add_counter() counter = counter + 1 end
  1814. local function get_counter() return counter end
  1815. vim.t.AddCounter = add_counter
  1816. vim.t.GetCounter = get_counter
  1817. vim.t.fn = {add = add_counter, get = get_counter}
  1818. vim.t.AddParens = function(s) return '(' .. s .. ')' end
  1819. ]]
  1820. eq(0, eval('t:GetCounter()'))
  1821. eval('t:AddCounter()')
  1822. eq(1, eval('t:GetCounter()'))
  1823. eval('t:AddCounter()')
  1824. eq(2, eval('t:GetCounter()'))
  1825. exec_lua([[vim.t.AddCounter()]])
  1826. eq(3, exec_lua([[return vim.t.GetCounter()]]))
  1827. exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]])
  1828. eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]]))
  1829. exec_lua([[vim.t.fn.add()]])
  1830. eq(5, exec_lua([[return vim.t.fn.get()]]))
  1831. exec_lua([[vim.api.nvim_tabpage_get_var(0, 'fn').add()]])
  1832. eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'fn').get()]]))
  1833. eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]]))
  1834. exec_lua [[
  1835. local counter = 0
  1836. local function add_counter() counter = counter + 1 end
  1837. local function get_counter() return counter end
  1838. vim.api.nvim_tabpage_set_var(0, 'AddCounter', add_counter)
  1839. vim.api.nvim_tabpage_set_var(0, 'GetCounter', get_counter)
  1840. vim.api.nvim_tabpage_set_var(0, 'fn', {add = add_counter, get = get_counter})
  1841. vim.api.nvim_tabpage_set_var(0, 'AddParens', function(s) return '(' .. s .. ')' end)
  1842. ]]
  1843. eq(0, eval('t:GetCounter()'))
  1844. eval('t:AddCounter()')
  1845. eq(1, eval('t:GetCounter()'))
  1846. eval('t:AddCounter()')
  1847. eq(2, eval('t:GetCounter()'))
  1848. exec_lua([[vim.t.AddCounter()]])
  1849. eq(3, exec_lua([[return vim.t.GetCounter()]]))
  1850. exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]])
  1851. eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]]))
  1852. exec_lua([[vim.t.fn.add()]])
  1853. eq(5, exec_lua([[return vim.t.fn.get()]]))
  1854. exec_lua([[vim.api.nvim_tabpage_get_var(0, 'fn').add()]])
  1855. eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'fn').get()]]))
  1856. eq('((foo))', eval([['foo'->t:AddParens()->t:AddParens()]]))
  1857. exec_lua [[
  1858. vim.cmd "tabnew"
  1859. ]]
  1860. eq(NIL, fn.luaeval 'vim.t.testing')
  1861. eq(NIL, fn.luaeval 'vim.t.other')
  1862. eq(NIL, fn.luaeval 'vim.t.nonexistent')
  1863. end)
  1864. it('vim.env', function()
  1865. exec_lua([[vim.fn.setenv('A', 123)]])
  1866. eq('123', fn.luaeval('vim.env.A'))
  1867. exec_lua([[vim.env.A = 456]])
  1868. eq('456', fn.luaeval('vim.env.A'))
  1869. exec_lua([[vim.env.A = nil]])
  1870. eq(NIL, fn.luaeval('vim.env.A'))
  1871. eq(true, fn.luaeval('vim.env.B == nil'))
  1872. command([[let $HOME = 'foo']])
  1873. eq('foo', fn.expand('~'))
  1874. eq('foo', fn.luaeval('vim.env.HOME'))
  1875. exec_lua([[vim.env.HOME = nil]])
  1876. eq('foo', fn.expand('~'))
  1877. exec_lua([[vim.env.HOME = 'bar']])
  1878. eq('bar', fn.expand('~'))
  1879. eq('bar', fn.luaeval('vim.env.HOME'))
  1880. end)
  1881. it('vim.v', function()
  1882. eq(fn.luaeval "vim.api.nvim_get_vvar('progpath')", fn.luaeval 'vim.v.progpath')
  1883. eq(false, fn.luaeval "vim.v['false']")
  1884. eq(NIL, fn.luaeval 'vim.v.null')
  1885. matches([[attempt to index .* nil value]], pcall_err(exec_lua, 'return vim.v[0].progpath'))
  1886. eq('Key is read-only: count', pcall_err(exec_lua, [[vim.v.count = 42]]))
  1887. eq('Dict is locked', pcall_err(exec_lua, [[vim.v.nosuchvar = 42]]))
  1888. eq('Key is fixed: errmsg', pcall_err(exec_lua, [[vim.v.errmsg = nil]]))
  1889. exec_lua([[vim.v.errmsg = 'set by Lua']])
  1890. eq('set by Lua', eval('v:errmsg'))
  1891. exec_lua([[vim.v.errmsg = 42]])
  1892. eq('42', eval('v:errmsg'))
  1893. exec_lua([[vim.v.oldfiles = { 'one', 'two' }]])
  1894. eq({ 'one', 'two' }, eval('v:oldfiles'))
  1895. exec_lua([[vim.v.oldfiles = {}]])
  1896. eq({}, eval('v:oldfiles'))
  1897. eq('Setting v:oldfiles to value with wrong type', pcall_err(exec_lua, [[vim.v.oldfiles = 'a']]))
  1898. eq({}, eval('v:oldfiles'))
  1899. feed('i foo foo foo<Esc>0/foo<CR>')
  1900. eq({ 1, 1 }, api.nvim_win_get_cursor(0))
  1901. eq(1, eval('v:searchforward'))
  1902. feed('n')
  1903. eq({ 1, 5 }, api.nvim_win_get_cursor(0))
  1904. exec_lua([[vim.v.searchforward = 0]])
  1905. eq(0, eval('v:searchforward'))
  1906. feed('n')
  1907. eq({ 1, 1 }, api.nvim_win_get_cursor(0))
  1908. exec_lua([[vim.v.searchforward = 1]])
  1909. eq(1, eval('v:searchforward'))
  1910. feed('n')
  1911. eq({ 1, 5 }, api.nvim_win_get_cursor(0))
  1912. local screen = Screen.new(60, 3)
  1913. eq(1, eval('v:hlsearch'))
  1914. screen:expect {
  1915. grid = [[
  1916. {10:foo} {10:^foo} {10:foo} |
  1917. {1:~ }|
  1918. |
  1919. ]],
  1920. }
  1921. exec_lua([[vim.v.hlsearch = 0]])
  1922. eq(0, eval('v:hlsearch'))
  1923. screen:expect {
  1924. grid = [[
  1925. foo ^foo foo |
  1926. {1:~ }|
  1927. |
  1928. ]],
  1929. }
  1930. exec_lua([[vim.v.hlsearch = 1]])
  1931. eq(1, eval('v:hlsearch'))
  1932. screen:expect {
  1933. grid = [[
  1934. {10:foo} {10:^foo} {10:foo} |
  1935. {1:~ }|
  1936. |
  1937. ]],
  1938. }
  1939. end)
  1940. it('vim.bo', function()
  1941. eq('', fn.luaeval 'vim.bo.filetype')
  1942. exec_lua [[
  1943. vim.api.nvim_set_option_value("filetype", "markdown", {})
  1944. BUF = vim.api.nvim_create_buf(false, true)
  1945. vim.api.nvim_set_option_value("modifiable", false, {buf = BUF})
  1946. ]]
  1947. eq(false, fn.luaeval 'vim.bo.modified')
  1948. eq('markdown', fn.luaeval 'vim.bo.filetype')
  1949. eq(false, fn.luaeval 'vim.bo[BUF].modifiable')
  1950. exec_lua [[
  1951. vim.bo.filetype = ''
  1952. vim.bo[BUF].modifiable = true
  1953. ]]
  1954. eq('', fn.luaeval 'vim.bo.filetype')
  1955. eq(true, fn.luaeval 'vim.bo[BUF].modifiable')
  1956. matches("Unknown option 'nosuchopt'$", pcall_err(exec_lua, 'return vim.bo.nosuchopt'))
  1957. matches('Expected Lua string$', pcall_err(exec_lua, 'return vim.bo[0][0].autoread'))
  1958. matches('Invalid buffer id: %-1$', pcall_err(exec_lua, 'return vim.bo[-1].filetype'))
  1959. end)
  1960. it('vim.wo', function()
  1961. exec_lua [[
  1962. vim.api.nvim_set_option_value("cole", 2, {})
  1963. vim.cmd "split"
  1964. vim.api.nvim_set_option_value("cole", 2, {})
  1965. ]]
  1966. eq(2, fn.luaeval 'vim.wo.cole')
  1967. exec_lua [[
  1968. vim.wo.conceallevel = 0
  1969. ]]
  1970. eq(0, fn.luaeval 'vim.wo.cole')
  1971. eq(0, fn.luaeval 'vim.wo[0].cole')
  1972. eq(0, fn.luaeval 'vim.wo[1001].cole')
  1973. matches("Unknown option 'notanopt'$", pcall_err(exec_lua, 'return vim.wo.notanopt'))
  1974. matches('Invalid window id: %-1$', pcall_err(exec_lua, 'return vim.wo[-1].list'))
  1975. eq(2, fn.luaeval 'vim.wo[1000].cole')
  1976. exec_lua [[
  1977. vim.wo[1000].cole = 0
  1978. ]]
  1979. eq(0, fn.luaeval 'vim.wo[1000].cole')
  1980. -- Can handle global-local values
  1981. exec_lua [[vim.o.scrolloff = 100]]
  1982. exec_lua [[vim.wo.scrolloff = 200]]
  1983. eq(200, fn.luaeval 'vim.wo.scrolloff')
  1984. exec_lua [[vim.wo.scrolloff = -1]]
  1985. eq(100, fn.luaeval 'vim.wo.scrolloff')
  1986. exec_lua [[
  1987. vim.wo[0][0].scrolloff = 200
  1988. vim.cmd "enew"
  1989. ]]
  1990. eq(100, fn.luaeval 'vim.wo.scrolloff')
  1991. matches('only bufnr=0 is supported', pcall_err(exec_lua, 'vim.wo[0][10].signcolumn = "no"'))
  1992. matches('only bufnr=0 is supported', pcall_err(exec_lua, 'local a = vim.wo[0][10].signcolumn'))
  1993. end)
  1994. describe('vim.opt', function()
  1995. -- TODO: We still need to write some tests for optlocal, opt and then getting the options
  1996. -- Probably could also do some stuff with getting things from viml side as well to confirm behavior is the same.
  1997. it('allows setting number values', function()
  1998. local scrolloff = exec_lua [[
  1999. vim.opt.scrolloff = 10
  2000. return vim.o.scrolloff
  2001. ]]
  2002. eq(10, scrolloff)
  2003. end)
  2004. pending('handles STUPID window things', function()
  2005. local result = exec_lua [[
  2006. local result = {}
  2007. table.insert(result, vim.api.nvim_get_option_value('scrolloff', {scope='global'}))
  2008. table.insert(result, vim.api.nvim_get_option_value('scrolloff', {win=0}))
  2009. return result
  2010. ]]
  2011. eq({}, result)
  2012. end)
  2013. it('allows setting tables', function()
  2014. local wildignore = exec_lua [[
  2015. vim.opt.wildignore = { 'hello', 'world' }
  2016. return vim.o.wildignore
  2017. ]]
  2018. eq('hello,world', wildignore)
  2019. end)
  2020. it('allows setting tables with shortnames', function()
  2021. local wildignore = exec_lua [[
  2022. vim.opt.wig = { 'hello', 'world' }
  2023. return vim.o.wildignore
  2024. ]]
  2025. eq('hello,world', wildignore)
  2026. end)
  2027. it('errors when you attempt to set string values to numeric options', function()
  2028. local result = exec_lua [[
  2029. return {
  2030. pcall(function() vim.opt.textwidth = 'hello world' end)
  2031. }
  2032. ]]
  2033. eq(false, result[1])
  2034. end)
  2035. it('errors when you attempt to setlocal a global value', function()
  2036. local result = exec_lua [[
  2037. return pcall(function() vim.opt_local.clipboard = "hello" end)
  2038. ]]
  2039. eq(false, result)
  2040. end)
  2041. it('allows you to set boolean values', function()
  2042. eq(
  2043. { true, false, true },
  2044. exec_lua [[
  2045. local results = {}
  2046. vim.opt.autoindent = true
  2047. table.insert(results, vim.bo.autoindent)
  2048. vim.opt.autoindent = false
  2049. table.insert(results, vim.bo.autoindent)
  2050. vim.opt.autoindent = not vim.opt.autoindent:get()
  2051. table.insert(results, vim.bo.autoindent)
  2052. return results
  2053. ]]
  2054. )
  2055. end)
  2056. it('changes current buffer values and defaults for global local values', function()
  2057. local result = exec_lua [[
  2058. local result = {}
  2059. vim.opt.makeprg = "global-local"
  2060. table.insert(result, vim.go.makeprg)
  2061. table.insert(result, vim.api.nvim_get_option_value('makeprg', {buf=0}))
  2062. vim.opt_local.mp = "only-local"
  2063. table.insert(result, vim.go.makeprg)
  2064. table.insert(result, vim.api.nvim_get_option_value('makeprg', {buf=0}))
  2065. vim.opt_global.makeprg = "only-global"
  2066. table.insert(result, vim.go.makeprg)
  2067. table.insert(result, vim.api.nvim_get_option_value('makeprg', {buf=0}))
  2068. vim.opt.makeprg = "global-local"
  2069. table.insert(result, vim.go.makeprg)
  2070. table.insert(result, vim.api.nvim_get_option_value('makeprg', {buf=0}))
  2071. return result
  2072. ]]
  2073. -- Set -> global & local
  2074. eq('global-local', result[1])
  2075. eq('', result[2])
  2076. -- Setlocal -> only local
  2077. eq('global-local', result[3])
  2078. eq('only-local', result[4])
  2079. -- Setglobal -> only global
  2080. eq('only-global', result[5])
  2081. eq('only-local', result[6])
  2082. -- Set -> sets global value and resets local value
  2083. eq('global-local', result[7])
  2084. eq('', result[8])
  2085. end)
  2086. it('allows you to retrieve window opts even if they have not been set', function()
  2087. local result = exec_lua [[
  2088. local result = {}
  2089. table.insert(result, vim.opt.number:get())
  2090. table.insert(result, vim.opt_local.number:get())
  2091. vim.opt_local.number = true
  2092. table.insert(result, vim.opt.number:get())
  2093. table.insert(result, vim.opt_local.number:get())
  2094. return result
  2095. ]]
  2096. eq({ false, false, true, true }, result)
  2097. end)
  2098. it('allows all sorts of string manipulation', function()
  2099. eq(
  2100. { 'hello', 'hello world', 'start hello world' },
  2101. exec_lua [[
  2102. local results = {}
  2103. vim.opt.makeprg = "hello"
  2104. table.insert(results, vim.o.makeprg)
  2105. vim.opt.makeprg = vim.opt.makeprg + " world"
  2106. table.insert(results, vim.o.makeprg)
  2107. vim.opt.makeprg = vim.opt.makeprg ^ "start "
  2108. table.insert(results, vim.o.makeprg)
  2109. return results
  2110. ]]
  2111. )
  2112. end)
  2113. describe('option:get()', function()
  2114. it('works for boolean values', function()
  2115. eq(
  2116. false,
  2117. exec_lua [[
  2118. vim.opt.number = false
  2119. return vim.opt.number:get()
  2120. ]]
  2121. )
  2122. end)
  2123. it('works for number values', function()
  2124. local tabstop = exec_lua [[
  2125. vim.opt.tabstop = 10
  2126. return vim.opt.tabstop:get()
  2127. ]]
  2128. eq(10, tabstop)
  2129. end)
  2130. it('works for string values', function()
  2131. eq(
  2132. 'hello world',
  2133. exec_lua [[
  2134. vim.opt.makeprg = "hello world"
  2135. return vim.opt.makeprg:get()
  2136. ]]
  2137. )
  2138. end)
  2139. it('works for set type flaglists', function()
  2140. local formatoptions = exec_lua [[
  2141. vim.opt.formatoptions = 'tcro'
  2142. return vim.opt.formatoptions:get()
  2143. ]]
  2144. eq(true, formatoptions.t)
  2145. eq(true, not formatoptions.q)
  2146. end)
  2147. it('works for set type flaglists', function()
  2148. local formatoptions = exec_lua [[
  2149. vim.opt.formatoptions = { t = true, c = true, r = true, o = true }
  2150. return vim.opt.formatoptions:get()
  2151. ]]
  2152. eq(true, formatoptions.t)
  2153. eq(true, not formatoptions.q)
  2154. end)
  2155. it('works for array list type options', function()
  2156. local wildignore = exec_lua [[
  2157. vim.opt.wildignore = "*.c,*.o,__pycache__"
  2158. return vim.opt.wildignore:get()
  2159. ]]
  2160. eq(3, #wildignore)
  2161. eq('*.c', wildignore[1])
  2162. end)
  2163. it('works for options that are both commalist and flaglist', function()
  2164. local result = exec_lua [[
  2165. vim.opt.whichwrap = "b,s"
  2166. return vim.opt.whichwrap:get()
  2167. ]]
  2168. eq({ b = true, s = true }, result)
  2169. result = exec_lua [[
  2170. vim.opt.whichwrap = { b = true, s = false, h = true }
  2171. return vim.opt.whichwrap:get()
  2172. ]]
  2173. eq({ b = true, h = true }, result)
  2174. end)
  2175. it('works for key-value pair options', function()
  2176. local listchars = exec_lua [[
  2177. vim.opt.listchars = "tab:> ,space:_"
  2178. return vim.opt.listchars:get()
  2179. ]]
  2180. eq({
  2181. tab = '> ',
  2182. space = '_',
  2183. }, listchars)
  2184. end)
  2185. it('allows you to add numeric options', function()
  2186. eq(
  2187. 16,
  2188. exec_lua [[
  2189. vim.opt.tabstop = 12
  2190. vim.opt.tabstop = vim.opt.tabstop + 4
  2191. return vim.bo.tabstop
  2192. ]]
  2193. )
  2194. end)
  2195. it('allows you to subtract numeric options', function()
  2196. eq(
  2197. 2,
  2198. exec_lua [[
  2199. vim.opt.tabstop = 4
  2200. vim.opt.tabstop = vim.opt.tabstop - 2
  2201. return vim.bo.tabstop
  2202. ]]
  2203. )
  2204. end)
  2205. end)
  2206. describe('key:value style options', function()
  2207. it('handles dict style', function()
  2208. local listchars = exec_lua [[
  2209. vim.opt.listchars = {
  2210. eol = "~",
  2211. space = ".",
  2212. }
  2213. return vim.o.listchars
  2214. ]]
  2215. eq('eol:~,space:.', listchars)
  2216. end)
  2217. it('allows adding dict style', function()
  2218. local listchars = exec_lua [[
  2219. vim.opt.listchars = {
  2220. eol = "~",
  2221. space = ".",
  2222. }
  2223. vim.opt.listchars = vim.opt.listchars + { space = "-" }
  2224. return vim.o.listchars
  2225. ]]
  2226. eq('eol:~,space:-', listchars)
  2227. end)
  2228. it('allows adding dict style', function()
  2229. local listchars = exec_lua [[
  2230. vim.opt.listchars = {
  2231. eol = "~",
  2232. space = ".",
  2233. }
  2234. vim.opt.listchars = vim.opt.listchars + { space = "-" } + { space = "_" }
  2235. return vim.o.listchars
  2236. ]]
  2237. eq('eol:~,space:_', listchars)
  2238. end)
  2239. it('allows completely new keys', function()
  2240. local listchars = exec_lua [[
  2241. vim.opt.listchars = {
  2242. eol = "~",
  2243. space = ".",
  2244. }
  2245. vim.opt.listchars = vim.opt.listchars + { tab = ">>>" }
  2246. return vim.o.listchars
  2247. ]]
  2248. eq('eol:~,space:.,tab:>>>', listchars)
  2249. end)
  2250. it('allows subtracting dict style', function()
  2251. local listchars = exec_lua [[
  2252. vim.opt.listchars = {
  2253. eol = "~",
  2254. space = ".",
  2255. }
  2256. vim.opt.listchars = vim.opt.listchars - "space"
  2257. return vim.o.listchars
  2258. ]]
  2259. eq('eol:~', listchars)
  2260. end)
  2261. it('allows subtracting dict style', function()
  2262. local listchars = exec_lua [[
  2263. vim.opt.listchars = {
  2264. eol = "~",
  2265. space = ".",
  2266. }
  2267. vim.opt.listchars = vim.opt.listchars - "space" - "eol"
  2268. return vim.o.listchars
  2269. ]]
  2270. eq('', listchars)
  2271. end)
  2272. it('allows subtracting dict style multiple times', function()
  2273. local listchars = exec_lua [[
  2274. vim.opt.listchars = {
  2275. eol = "~",
  2276. space = ".",
  2277. }
  2278. vim.opt.listchars = vim.opt.listchars - "space" - "space"
  2279. return vim.o.listchars
  2280. ]]
  2281. eq('eol:~', listchars)
  2282. end)
  2283. it('allows adding a key:value string to a listchars', function()
  2284. local listchars = exec_lua [[
  2285. vim.opt.listchars = {
  2286. eol = "~",
  2287. space = ".",
  2288. }
  2289. vim.opt.listchars = vim.opt.listchars + "tab:>~"
  2290. return vim.o.listchars
  2291. ]]
  2292. eq('eol:~,space:.,tab:>~', listchars)
  2293. end)
  2294. it('allows prepending a key:value string to a listchars', function()
  2295. local listchars = exec_lua [[
  2296. vim.opt.listchars = {
  2297. eol = "~",
  2298. space = ".",
  2299. }
  2300. vim.opt.listchars = vim.opt.listchars ^ "tab:>~"
  2301. return vim.o.listchars
  2302. ]]
  2303. eq('eol:~,space:.,tab:>~', listchars)
  2304. end)
  2305. end)
  2306. it('automatically sets when calling remove', function()
  2307. eq(
  2308. 'foo,baz',
  2309. exec_lua [[
  2310. vim.opt.wildignore = "foo,bar,baz"
  2311. vim.opt.wildignore:remove("bar")
  2312. return vim.o.wildignore
  2313. ]]
  2314. )
  2315. end)
  2316. it('automatically sets when calling remove with a table', function()
  2317. eq(
  2318. 'foo',
  2319. exec_lua [[
  2320. vim.opt.wildignore = "foo,bar,baz"
  2321. vim.opt.wildignore:remove { "bar", "baz" }
  2322. return vim.o.wildignore
  2323. ]]
  2324. )
  2325. end)
  2326. it('automatically sets when calling append', function()
  2327. eq(
  2328. 'foo,bar,baz,bing',
  2329. exec_lua [[
  2330. vim.opt.wildignore = "foo,bar,baz"
  2331. vim.opt.wildignore:append("bing")
  2332. return vim.o.wildignore
  2333. ]]
  2334. )
  2335. end)
  2336. it('automatically sets when calling append with a table', function()
  2337. eq(
  2338. 'foo,bar,baz,bing,zap',
  2339. exec_lua [[
  2340. vim.opt.wildignore = "foo,bar,baz"
  2341. vim.opt.wildignore:append { "bing", "zap" }
  2342. return vim.o.wildignore
  2343. ]]
  2344. )
  2345. end)
  2346. it('allows adding tables', function()
  2347. local wildignore = exec_lua [[
  2348. vim.opt.wildignore = 'foo'
  2349. return vim.o.wildignore
  2350. ]]
  2351. eq('foo', wildignore)
  2352. wildignore = exec_lua [[
  2353. vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
  2354. return vim.o.wildignore
  2355. ]]
  2356. eq('foo,bar,baz', wildignore)
  2357. end)
  2358. it('handles adding duplicates', function()
  2359. local wildignore = exec_lua [[
  2360. vim.opt.wildignore = 'foo'
  2361. return vim.o.wildignore
  2362. ]]
  2363. eq('foo', wildignore)
  2364. wildignore = exec_lua [[
  2365. vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
  2366. return vim.o.wildignore
  2367. ]]
  2368. eq('foo,bar,baz', wildignore)
  2369. wildignore = exec_lua [[
  2370. vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
  2371. return vim.o.wildignore
  2372. ]]
  2373. eq('foo,bar,baz', wildignore)
  2374. end)
  2375. it('allows adding multiple times', function()
  2376. local wildignore = exec_lua [[
  2377. vim.opt.wildignore = 'foo'
  2378. vim.opt.wildignore = vim.opt.wildignore + 'bar' + 'baz'
  2379. return vim.o.wildignore
  2380. ]]
  2381. eq('foo,bar,baz', wildignore)
  2382. end)
  2383. it('removes values when you use minus', function()
  2384. local wildignore = exec_lua [[
  2385. vim.opt.wildignore = 'foo'
  2386. return vim.o.wildignore
  2387. ]]
  2388. eq('foo', wildignore)
  2389. wildignore = exec_lua [[
  2390. vim.opt.wildignore = vim.opt.wildignore + { 'bar', 'baz' }
  2391. return vim.o.wildignore
  2392. ]]
  2393. eq('foo,bar,baz', wildignore)
  2394. wildignore = exec_lua [[
  2395. vim.opt.wildignore = vim.opt.wildignore - 'bar'
  2396. return vim.o.wildignore
  2397. ]]
  2398. eq('foo,baz', wildignore)
  2399. end)
  2400. it('prepends values when using ^', function()
  2401. local wildignore = exec_lua [[
  2402. vim.opt.wildignore = 'foo'
  2403. vim.opt.wildignore = vim.opt.wildignore ^ 'first'
  2404. return vim.o.wildignore
  2405. ]]
  2406. eq('first,foo', wildignore)
  2407. wildignore = exec_lua [[
  2408. vim.opt.wildignore = vim.opt.wildignore ^ 'super_first'
  2409. return vim.o.wildignore
  2410. ]]
  2411. eq('super_first,first,foo', wildignore)
  2412. end)
  2413. it('does not remove duplicates from wildmode: #14708', function()
  2414. local wildmode = exec_lua [[
  2415. vim.opt.wildmode = {"full", "list", "full"}
  2416. return vim.o.wildmode
  2417. ]]
  2418. eq('full,list,full', wildmode)
  2419. end)
  2420. describe('option types', function()
  2421. it('allows to set option with numeric value', function()
  2422. eq(
  2423. 4,
  2424. exec_lua [[
  2425. vim.opt.tabstop = 4
  2426. return vim.bo.tabstop
  2427. ]]
  2428. )
  2429. matches(
  2430. "Invalid option type 'string' for 'tabstop'",
  2431. pcall_err(
  2432. exec_lua,
  2433. [[
  2434. vim.opt.tabstop = '4'
  2435. ]]
  2436. )
  2437. )
  2438. matches(
  2439. "Invalid option type 'boolean' for 'tabstop'",
  2440. pcall_err(
  2441. exec_lua,
  2442. [[
  2443. vim.opt.tabstop = true
  2444. ]]
  2445. )
  2446. )
  2447. matches(
  2448. "Invalid option type 'table' for 'tabstop'",
  2449. pcall_err(
  2450. exec_lua,
  2451. [[
  2452. vim.opt.tabstop = {4, 2}
  2453. ]]
  2454. )
  2455. )
  2456. matches(
  2457. "Invalid option type 'function' for 'tabstop'",
  2458. pcall_err(
  2459. exec_lua,
  2460. [[
  2461. vim.opt.tabstop = function()
  2462. return 4
  2463. end
  2464. ]]
  2465. )
  2466. )
  2467. end)
  2468. it('allows to set option with boolean value', function()
  2469. eq(
  2470. true,
  2471. exec_lua [[
  2472. vim.opt.undofile = true
  2473. return vim.bo.undofile
  2474. ]]
  2475. )
  2476. matches(
  2477. "Invalid option type 'number' for 'undofile'",
  2478. pcall_err(
  2479. exec_lua,
  2480. [[
  2481. vim.opt.undofile = 0
  2482. ]]
  2483. )
  2484. )
  2485. matches(
  2486. "Invalid option type 'table' for 'undofile'",
  2487. pcall_err(
  2488. exec_lua,
  2489. [[
  2490. vim.opt.undofile = {true}
  2491. ]]
  2492. )
  2493. )
  2494. matches(
  2495. "Invalid option type 'string' for 'undofile'",
  2496. pcall_err(
  2497. exec_lua,
  2498. [[
  2499. vim.opt.undofile = 'true'
  2500. ]]
  2501. )
  2502. )
  2503. matches(
  2504. "Invalid option type 'function' for 'undofile'",
  2505. pcall_err(
  2506. exec_lua,
  2507. [[
  2508. vim.opt.undofile = function()
  2509. return true
  2510. end
  2511. ]]
  2512. )
  2513. )
  2514. end)
  2515. it('allows to set option with array or string value', function()
  2516. eq(
  2517. 'indent,eol,start',
  2518. exec_lua [[
  2519. vim.opt.backspace = {'indent','eol','start'}
  2520. return vim.go.backspace
  2521. ]]
  2522. )
  2523. eq(
  2524. 'indent,eol,start',
  2525. exec_lua [[
  2526. vim.opt.backspace = 'indent,eol,start'
  2527. return vim.go.backspace
  2528. ]]
  2529. )
  2530. matches(
  2531. "Invalid option type 'boolean' for 'backspace'",
  2532. pcall_err(
  2533. exec_lua,
  2534. [[
  2535. vim.opt.backspace = true
  2536. ]]
  2537. )
  2538. )
  2539. matches(
  2540. "Invalid option type 'number' for 'backspace'",
  2541. pcall_err(
  2542. exec_lua,
  2543. [[
  2544. vim.opt.backspace = 2
  2545. ]]
  2546. )
  2547. )
  2548. matches(
  2549. "Invalid option type 'function' for 'backspace'",
  2550. pcall_err(
  2551. exec_lua,
  2552. [[
  2553. vim.opt.backspace = function()
  2554. return 'indent,eol,start'
  2555. end
  2556. ]]
  2557. )
  2558. )
  2559. end)
  2560. it('allows set option with map or string value', function()
  2561. eq(
  2562. 'eol:~,space:.',
  2563. exec_lua [[
  2564. vim.opt.listchars = {
  2565. eol = "~",
  2566. space = ".",
  2567. }
  2568. return vim.o.listchars
  2569. ]]
  2570. )
  2571. eq(
  2572. 'eol:~,space:.,tab:>~',
  2573. exec_lua [[
  2574. vim.opt.listchars = "eol:~,space:.,tab:>~"
  2575. return vim.o.listchars
  2576. ]]
  2577. )
  2578. matches(
  2579. "Invalid option type 'boolean' for 'listchars'",
  2580. pcall_err(
  2581. exec_lua,
  2582. [[
  2583. vim.opt.listchars = true
  2584. ]]
  2585. )
  2586. )
  2587. matches(
  2588. "Invalid option type 'number' for 'listchars'",
  2589. pcall_err(
  2590. exec_lua,
  2591. [[
  2592. vim.opt.listchars = 2
  2593. ]]
  2594. )
  2595. )
  2596. matches(
  2597. "Invalid option type 'function' for 'listchars'",
  2598. pcall_err(
  2599. exec_lua,
  2600. [[
  2601. vim.opt.listchars = function()
  2602. return "eol:~,space:.,tab:>~"
  2603. end
  2604. ]]
  2605. )
  2606. )
  2607. end)
  2608. it('allows set option with set or string value', function()
  2609. local ww = exec_lua [[
  2610. vim.opt.whichwrap = {
  2611. b = true,
  2612. s = 1,
  2613. }
  2614. return vim.go.whichwrap
  2615. ]]
  2616. eq('b,s', ww)
  2617. eq(
  2618. 'b,s,<,>,[,]',
  2619. exec_lua [[
  2620. vim.opt.whichwrap = "b,s,<,>,[,]"
  2621. return vim.go.whichwrap
  2622. ]]
  2623. )
  2624. matches(
  2625. "Invalid option type 'boolean' for 'whichwrap'",
  2626. pcall_err(
  2627. exec_lua,
  2628. [[
  2629. vim.opt.whichwrap = true
  2630. ]]
  2631. )
  2632. )
  2633. matches(
  2634. "Invalid option type 'number' for 'whichwrap'",
  2635. pcall_err(
  2636. exec_lua,
  2637. [[
  2638. vim.opt.whichwrap = 2
  2639. ]]
  2640. )
  2641. )
  2642. matches(
  2643. "Invalid option type 'function' for 'whichwrap'",
  2644. pcall_err(
  2645. exec_lua,
  2646. [[
  2647. vim.opt.whichwrap = function()
  2648. return "b,s,<,>,[,]"
  2649. end
  2650. ]]
  2651. )
  2652. )
  2653. end)
  2654. end)
  2655. -- isfname=a,b,c,,,d,e,f
  2656. it('can handle isfname ,,,', function()
  2657. local result = exec_lua [[
  2658. vim.opt.isfname = "a,b,,,c"
  2659. return { vim.opt.isfname:get(), vim.go.isfname }
  2660. ]]
  2661. eq({ { ',', 'a', 'b', 'c' }, 'a,b,,,c' }, result)
  2662. end)
  2663. -- isfname=a,b,c,^,,def
  2664. it('can handle isfname ,^,,', function()
  2665. local result = exec_lua [[
  2666. vim.opt.isfname = "a,b,^,,c"
  2667. return { vim.opt.isfname:get(), vim.go.isfname }
  2668. ]]
  2669. eq({ { '^,', 'a', 'b', 'c' }, 'a,b,^,,c' }, result)
  2670. end)
  2671. describe('https://github.com/neovim/neovim/issues/14828', function()
  2672. it('gives empty list when item is empty:array', function()
  2673. eq(
  2674. {},
  2675. exec_lua [[
  2676. vim.cmd("set wildignore=")
  2677. return vim.opt.wildignore:get()
  2678. ]]
  2679. )
  2680. eq(
  2681. {},
  2682. exec_lua [[
  2683. vim.opt.wildignore = {}
  2684. return vim.opt.wildignore:get()
  2685. ]]
  2686. )
  2687. end)
  2688. it('gives empty list when item is empty:set', function()
  2689. eq(
  2690. {},
  2691. exec_lua [[
  2692. vim.cmd("set formatoptions=")
  2693. return vim.opt.formatoptions:get()
  2694. ]]
  2695. )
  2696. eq(
  2697. {},
  2698. exec_lua [[
  2699. vim.opt.formatoptions = {}
  2700. return vim.opt.formatoptions:get()
  2701. ]]
  2702. )
  2703. end)
  2704. it('does not append to empty item', function()
  2705. eq(
  2706. { '*.foo', '*.bar' },
  2707. exec_lua [[
  2708. vim.opt.wildignore = {}
  2709. vim.opt.wildignore:append { "*.foo", "*.bar" }
  2710. return vim.opt.wildignore:get()
  2711. ]]
  2712. )
  2713. end)
  2714. it('does not prepend to empty item', function()
  2715. eq(
  2716. { '*.foo', '*.bar' },
  2717. exec_lua [[
  2718. vim.opt.wildignore = {}
  2719. vim.opt.wildignore:prepend { "*.foo", "*.bar" }
  2720. return vim.opt.wildignore:get()
  2721. ]]
  2722. )
  2723. end)
  2724. it('append to empty set', function()
  2725. eq(
  2726. { t = true },
  2727. exec_lua [[
  2728. vim.opt.formatoptions = {}
  2729. vim.opt.formatoptions:append("t")
  2730. return vim.opt.formatoptions:get()
  2731. ]]
  2732. )
  2733. end)
  2734. it('prepend to empty set', function()
  2735. eq(
  2736. { t = true },
  2737. exec_lua [[
  2738. vim.opt.formatoptions = {}
  2739. vim.opt.formatoptions:prepend("t")
  2740. return vim.opt.formatoptions:get()
  2741. ]]
  2742. )
  2743. end)
  2744. end)
  2745. end) -- vim.opt
  2746. describe('vim.opt_local', function()
  2747. it('appends into global value when changing local option value', function()
  2748. eq(
  2749. { 'foo,bar,baz,qux' },
  2750. exec_lua [[
  2751. local result = {}
  2752. vim.opt.tags = "foo,bar"
  2753. vim.opt_local.tags:append("baz")
  2754. vim.opt_local.tags:append("qux")
  2755. table.insert(result, vim.bo.tags)
  2756. return result
  2757. ]]
  2758. )
  2759. end)
  2760. end)
  2761. describe('vim.opt_global', function()
  2762. it('gets current global option value', function()
  2763. eq(
  2764. { 'yes' },
  2765. exec_lua [[
  2766. local result = {}
  2767. vim.cmd "setglobal signcolumn=yes"
  2768. table.insert(result, vim.opt_global.signcolumn:get())
  2769. return result
  2770. ]]
  2771. )
  2772. end)
  2773. end)
  2774. it('vim.cmd', function()
  2775. exec_lua [[
  2776. vim.cmd "autocmd BufNew * ++once lua BUF = vim.fn.expand('<abuf>')"
  2777. vim.cmd "new"
  2778. ]]
  2779. eq('2', fn.luaeval 'BUF')
  2780. eq(2, fn.luaeval '#vim.api.nvim_list_bufs()')
  2781. -- vim.cmd can be indexed with a command name
  2782. exec_lua [[
  2783. vim.cmd.let 'g:var = 2'
  2784. ]]
  2785. eq(2, fn.luaeval 'vim.g.var')
  2786. end)
  2787. it('vim.regex', function()
  2788. exec_lua [[
  2789. re1 = vim.regex"ab\\+c"
  2790. vim.cmd "set nomagic ignorecase"
  2791. re2 = vim.regex"xYz"
  2792. ]]
  2793. eq({}, exec_lua [[return {re1:match_str("x ac")}]])
  2794. eq({ 3, 7 }, exec_lua [[return {re1:match_str("ac abbc")}]])
  2795. api.nvim_buf_set_lines(0, 0, -1, true, { 'yy', 'abc abbc' })
  2796. eq({}, exec_lua [[return {re1:match_line(0, 0)}]])
  2797. eq({ 0, 3 }, exec_lua [[return {re1:match_line(0, 1)}]])
  2798. eq({ 3, 7 }, exec_lua [[return {re1:match_line(0, 1, 1)}]])
  2799. eq({ 3, 7 }, exec_lua [[return {re1:match_line(0, 1, 1, 8)}]])
  2800. eq({}, exec_lua [[return {re1:match_line(0, 1, 1, 7)}]])
  2801. eq({ 0, 3 }, exec_lua [[return {re1:match_line(0, 1, 0, 7)}]])
  2802. -- vim.regex() error inside :silent! should not crash. #20546
  2803. command([[silent! lua vim.regex('\\z')]])
  2804. assert_alive()
  2805. end)
  2806. it('vim.defer_fn', function()
  2807. eq(
  2808. false,
  2809. exec_lua [[
  2810. vim.g.test = false
  2811. vim.defer_fn(function() vim.g.test = true end, 150)
  2812. return vim.g.test
  2813. ]]
  2814. )
  2815. exec_lua [[vim.wait(1000, function() return vim.g.test end)]]
  2816. eq(true, exec_lua [[return vim.g.test]])
  2817. end)
  2818. describe('vim.region', function()
  2819. it('charwise', function()
  2820. insert(dedent([[
  2821. text tααt tααt text
  2822. text tαxt txtα tex
  2823. text tαxt tαxt
  2824. ]]))
  2825. eq({ 5, 13 }, exec_lua [[ return vim.region(0,{0,5},{0,13},'v',false)[0] ]])
  2826. eq({ 5, 15 }, exec_lua [[ return vim.region(0,{0,5},{0,13},'v',true)[0] ]])
  2827. eq({ 5, 15 }, exec_lua [[ return vim.region(0,{0,5},{0,14},'v',true)[0] ]])
  2828. eq({ 5, 15 }, exec_lua [[ return vim.region(0,{0,5},{0,15},'v',false)[0] ]])
  2829. eq({ 5, 17 }, exec_lua [[ return vim.region(0,{0,5},{0,15},'v',true)[0] ]])
  2830. eq({ 5, 17 }, exec_lua [[ return vim.region(0,{0,5},{0,16},'v',true)[0] ]])
  2831. eq({ 5, 17 }, exec_lua [[ return vim.region(0,{0,5},{0,17},'v',false)[0] ]])
  2832. eq({ 5, 18 }, exec_lua [[ return vim.region(0,{0,5},{0,17},'v',true)[0] ]])
  2833. end)
  2834. it('blockwise', function()
  2835. insert([[αα]])
  2836. eq({ 0, 5 }, exec_lua [[ return vim.region(0,{0,0},{0,4},'3',true)[0] ]])
  2837. end)
  2838. it('linewise', function()
  2839. insert(dedent([[
  2840. text tααt tααt text
  2841. text tαxt txtα tex
  2842. text tαxt tαxt
  2843. ]]))
  2844. eq({ 0, -1 }, exec_lua [[ return vim.region(0,{1,5},{1,14},'V',true)[1] ]])
  2845. end)
  2846. it('getpos() input', function()
  2847. insert('getpos')
  2848. eq({ 0, 6 }, exec_lua [[ return vim.region(0,{0,0},'.','v',true)[0] ]])
  2849. end)
  2850. end)
  2851. describe('vim.on_key', function()
  2852. it('tracks Unicode input', function()
  2853. insert([[hello world ]])
  2854. exec_lua [[
  2855. keys = {}
  2856. typed = {}
  2857. vim.on_key(function(buf, typed_buf)
  2858. if buf:byte() == 27 then
  2859. buf = "<ESC>"
  2860. end
  2861. if typed_buf:byte() == 27 then
  2862. typed_buf = "<ESC>"
  2863. end
  2864. table.insert(keys, buf)
  2865. table.insert(typed, typed_buf)
  2866. end)
  2867. ]]
  2868. insert([[next 🤦 lines å …]])
  2869. -- It has escape in the keys pressed
  2870. eq('inext 🤦 lines å …<ESC>', exec_lua [[return table.concat(keys, '')]])
  2871. eq('inext 🤦 lines å …<ESC>', exec_lua [[return table.concat(typed, '')]])
  2872. end)
  2873. it('tracks input with modifiers', function()
  2874. exec_lua [[
  2875. keys = {}
  2876. typed = {}
  2877. vim.on_key(function(buf, typed_buf)
  2878. table.insert(keys, vim.fn.keytrans(buf))
  2879. table.insert(typed, vim.fn.keytrans(typed_buf))
  2880. end)
  2881. ]]
  2882. feed([[i<C-V><C-;><C-V><C-…><Esc>]])
  2883. eq('i<C-V><C-;><C-V><C-…><Esc>', exec_lua [[return table.concat(keys, '')]])
  2884. eq('i<C-V><C-;><C-V><C-…><Esc>', exec_lua [[return table.concat(typed, '')]])
  2885. end)
  2886. it('works with character find and Select mode', function()
  2887. insert('12345')
  2888. exec_lua [[
  2889. typed = {}
  2890. vim.cmd('snoremap # @')
  2891. vim.on_key(function(buf, typed_buf)
  2892. table.insert(typed, vim.fn.keytrans(typed_buf))
  2893. end)
  2894. ]]
  2895. feed('F3gHβγδεζ<Esc>gH…<Esc>gH#$%^')
  2896. eq('F3gHβγδεζ<Esc>gH…<Esc>gH#$%^', exec_lua [[return table.concat(typed, '')]])
  2897. end)
  2898. it('allows removing on_key listeners', function()
  2899. -- Create some unused namespaces
  2900. api.nvim_create_namespace('unused1')
  2901. api.nvim_create_namespace('unused2')
  2902. api.nvim_create_namespace('unused3')
  2903. api.nvim_create_namespace('unused4')
  2904. insert([[hello world]])
  2905. exec_lua [[
  2906. keys = {}
  2907. return vim.on_key(function(buf)
  2908. if buf:byte() == 27 then
  2909. buf = "<ESC>"
  2910. end
  2911. table.insert(keys, buf)
  2912. end, vim.api.nvim_create_namespace("logger"))
  2913. ]]
  2914. insert([[next lines]])
  2915. eq(1, exec_lua('return vim.on_key()'))
  2916. exec_lua("vim.on_key(nil, vim.api.nvim_create_namespace('logger'))")
  2917. eq(0, exec_lua('return vim.on_key()'))
  2918. insert([[more lines]])
  2919. -- It has escape in the keys pressed
  2920. eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]])
  2921. end)
  2922. it('skips any function that caused an error and shows stacktrace', function()
  2923. insert([[hello world]])
  2924. exec_lua [[
  2925. local function ErrF2()
  2926. error("Dumb Error")
  2927. end
  2928. local function ErrF1()
  2929. ErrF2()
  2930. end
  2931. keys = {}
  2932. return vim.on_key(function(buf)
  2933. if buf:byte() == 27 then
  2934. buf = "<ESC>"
  2935. end
  2936. table.insert(keys, buf)
  2937. if buf == 'l' then
  2938. ErrF1()
  2939. end
  2940. end)
  2941. ]]
  2942. insert([[next lines]])
  2943. insert([[more lines]])
  2944. -- Only the first letter gets added. After that we remove the callback
  2945. eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
  2946. local errmsg = api.nvim_get_vvar('errmsg')
  2947. matches(
  2948. [[
  2949. ^Error executing vim%.on%_key%(%) callbacks:.*
  2950. With ns%_id %d+: .*: Dumb Error
  2951. stack traceback:
  2952. .*: in function 'error'
  2953. .*: in function 'ErrF2'
  2954. .*: in function 'ErrF1'
  2955. .*]],
  2956. errmsg
  2957. )
  2958. end)
  2959. it('argument 1 is keys after mapping, argument 2 is typed keys', function()
  2960. exec_lua [[
  2961. keys = {}
  2962. typed = {}
  2963. vim.cmd("inoremap hello world")
  2964. vim.on_key(function(buf, typed_buf)
  2965. if buf:byte() == 27 then
  2966. buf = "<ESC>"
  2967. end
  2968. if typed_buf:byte() == 27 then
  2969. typed_buf = "<ESC>"
  2970. end
  2971. table.insert(keys, buf)
  2972. table.insert(typed, typed_buf)
  2973. end)
  2974. ]]
  2975. insert('hello')
  2976. eq('iworld<ESC>', exec_lua [[return table.concat(keys, '')]])
  2977. eq('ihello<ESC>', exec_lua [[return table.concat(typed, '')]])
  2978. end)
  2979. it('can call vim.fn functions on Ctrl-C #17273', function()
  2980. exec_lua([[
  2981. _G.ctrl_c_cmdtype = ''
  2982. vim.on_key(function(c)
  2983. if c == '\3' then
  2984. _G.ctrl_c_cmdtype = vim.fn.getcmdtype()
  2985. end
  2986. end)
  2987. ]])
  2988. feed('/')
  2989. poke_eventloop() -- This is needed because Ctrl-C flushes input
  2990. feed('<C-C>')
  2991. eq('/', exec_lua([[return _G.ctrl_c_cmdtype]]))
  2992. end)
  2993. it('callback is not invoked recursively #30752', function()
  2994. local screen = Screen.new(60, 10)
  2995. exec_lua([[
  2996. vim.on_key(function(key, typed)
  2997. vim.api.nvim_echo({
  2998. { 'key_cb\n' },
  2999. { ("KEYCB: key '%s', typed '%s'\n"):format(key, typed) },
  3000. }, false, {})
  3001. end)
  3002. ]])
  3003. feed('^')
  3004. screen:expect([[
  3005. |
  3006. {1:~ }|*5
  3007. {3: }|
  3008. key_cb |
  3009. KEYCB: key '^', typed '^' |
  3010. {6:Press ENTER or type command to continue}^ |
  3011. ]])
  3012. feed('<C-C>')
  3013. screen:expect([[
  3014. |
  3015. {1:~ }|*3
  3016. {3: }|
  3017. key_cb |
  3018. KEYCB: key '^', typed '^' |
  3019. key_cb |
  3020. KEYCB: key '{18:^C}', typed '{18:^C}' |
  3021. {6:Press ENTER or type command to continue}^ |
  3022. ]])
  3023. feed('<C-C>')
  3024. screen:expect([[
  3025. ^ |
  3026. {1:~ }|*8
  3027. |
  3028. ]])
  3029. end)
  3030. it('can discard input', function()
  3031. clear()
  3032. -- discard every other normal 'x' command
  3033. exec_lua [[
  3034. n_key = 0
  3035. vim.on_key(function(buf, typed_buf)
  3036. if typed_buf == 'x' then
  3037. n_key = n_key + 1
  3038. end
  3039. return (n_key % 2 == 0) and "" or nil
  3040. end)
  3041. ]]
  3042. api.nvim_buf_set_lines(0, 0, -1, true, { '54321' })
  3043. feed('x')
  3044. expect('4321')
  3045. feed('x')
  3046. expect('4321')
  3047. feed('x')
  3048. expect('321')
  3049. feed('x')
  3050. expect('321')
  3051. end)
  3052. it('callback invalid return', function()
  3053. clear()
  3054. -- second key produces an error which removes the callback
  3055. exec_lua [[
  3056. n_call = 0
  3057. vim.on_key(function(buf, typed_buf)
  3058. if typed_buf == 'x' then
  3059. n_call = n_call + 1
  3060. end
  3061. return n_call >= 2 and '!' or nil
  3062. end)
  3063. ]]
  3064. api.nvim_buf_set_lines(0, 0, -1, true, { '54321' })
  3065. local function cleanup_msg(msg)
  3066. return msg:gsub('^Error .*\nWith ns%_id %d+: ', '')
  3067. end
  3068. feed('x')
  3069. eq(1, exec_lua [[ return n_call ]])
  3070. eq(1, exec_lua [[ return vim.on_key(nil, nil) ]])
  3071. eq('', cleanup_msg(eval('v:errmsg')))
  3072. feed('x')
  3073. eq(2, exec_lua [[ return n_call ]])
  3074. eq('return string must be empty', cleanup_msg(eval('v:errmsg')))
  3075. command('let v:errmsg = ""')
  3076. eq(0, exec_lua [[ return vim.on_key(nil, nil) ]])
  3077. feed('x')
  3078. eq(2, exec_lua [[ return n_call ]])
  3079. expect('21')
  3080. eq('', cleanup_msg(eval('v:errmsg')))
  3081. end)
  3082. end)
  3083. describe('vim.wait', function()
  3084. before_each(function()
  3085. exec_lua [[
  3086. -- high precision timer
  3087. get_time = function()
  3088. return vim.fn.reltimefloat(vim.fn.reltime())
  3089. end
  3090. ]]
  3091. end)
  3092. it('runs from lua', function()
  3093. exec_lua [[vim.wait(100, function() return true end)]]
  3094. end)
  3095. it('waits the expected time if false', function()
  3096. eq(
  3097. { time = true, wait_result = { false, -1 } },
  3098. exec_lua [[
  3099. start_time = get_time()
  3100. wait_succeed, wait_fail_val = vim.wait(200, function() return false end)
  3101. return {
  3102. -- 150ms waiting or more results in true. Flaky tests are bad.
  3103. time = (start_time + 0.15) < get_time(),
  3104. wait_result = {wait_succeed, wait_fail_val}
  3105. }
  3106. ]]
  3107. )
  3108. end)
  3109. it('does not block other events', function()
  3110. eq(
  3111. { time = true, wait_result = true },
  3112. exec_lua [[
  3113. start_time = get_time()
  3114. vim.g.timer_result = false
  3115. timer = vim.uv.new_timer()
  3116. timer:start(100, 0, vim.schedule_wrap(function()
  3117. vim.g.timer_result = true
  3118. end))
  3119. -- Would wait ten seconds if results blocked.
  3120. wait_result = vim.wait(10000, function() return vim.g.timer_result end)
  3121. timer:close()
  3122. return {
  3123. time = (start_time + 5) > get_time(),
  3124. wait_result = wait_result,
  3125. }
  3126. ]]
  3127. )
  3128. end)
  3129. it('does not process non-fast events when commanded', function()
  3130. eq(
  3131. { wait_result = false },
  3132. exec_lua [[
  3133. start_time = get_time()
  3134. vim.g.timer_result = false
  3135. timer = vim.uv.new_timer()
  3136. timer:start(100, 0, vim.schedule_wrap(function()
  3137. vim.g.timer_result = true
  3138. end))
  3139. wait_result = vim.wait(300, function() return vim.g.timer_result end, nil, true)
  3140. timer:close()
  3141. return {
  3142. wait_result = wait_result,
  3143. }
  3144. ]]
  3145. )
  3146. end)
  3147. it('works with vim.defer_fn', function()
  3148. eq(
  3149. { time = true, wait_result = true },
  3150. exec_lua [[
  3151. start_time = get_time()
  3152. vim.defer_fn(function() vim.g.timer_result = true end, 100)
  3153. wait_result = vim.wait(10000, function() return vim.g.timer_result end)
  3154. return {
  3155. time = (start_time + 5) > get_time(),
  3156. wait_result = wait_result,
  3157. }
  3158. ]]
  3159. )
  3160. end)
  3161. it('does not crash when callback errors', function()
  3162. local result = exec_lua [[
  3163. return {pcall(function() vim.wait(1000, function() error("As Expected") end) end)}
  3164. ]]
  3165. eq({ false, '[string "<nvim>"]:1: As Expected' }, { result[1], remove_trace(result[2]) })
  3166. end)
  3167. it('if callback is passed, it must be a function', function()
  3168. eq(
  3169. { false, 'vim.wait: if passed, condition must be a function' },
  3170. exec_lua [[
  3171. return {pcall(function() vim.wait(1000, 13) end)}
  3172. ]]
  3173. )
  3174. end)
  3175. it('allows waiting with no callback, explicit', function()
  3176. eq(
  3177. true,
  3178. exec_lua [[
  3179. local start_time = vim.uv.hrtime()
  3180. vim.wait(50, nil)
  3181. return vim.uv.hrtime() - start_time > 25000
  3182. ]]
  3183. )
  3184. end)
  3185. it('allows waiting with no callback, implicit', function()
  3186. eq(
  3187. true,
  3188. exec_lua [[
  3189. local start_time = vim.uv.hrtime()
  3190. vim.wait(50)
  3191. return vim.uv.hrtime() - start_time > 25000
  3192. ]]
  3193. )
  3194. end)
  3195. it('calls callbacks exactly once if they return true immediately', function()
  3196. eq(
  3197. true,
  3198. exec_lua [[
  3199. vim.g.wait_count = 0
  3200. vim.wait(1000, function()
  3201. vim.g.wait_count = vim.g.wait_count + 1
  3202. return true
  3203. end, 20)
  3204. return vim.g.wait_count == 1
  3205. ]]
  3206. )
  3207. end)
  3208. it('calls callbacks few times with large `interval`', function()
  3209. eq(
  3210. true,
  3211. exec_lua [[
  3212. vim.g.wait_count = 0
  3213. vim.wait(50, function() vim.g.wait_count = vim.g.wait_count + 1 end, 200)
  3214. return vim.g.wait_count < 5
  3215. ]]
  3216. )
  3217. end)
  3218. it('plays nice with `not` when fails', function()
  3219. eq(
  3220. true,
  3221. exec_lua [[
  3222. if not vim.wait(50, function() end) then
  3223. return true
  3224. end
  3225. return false
  3226. ]]
  3227. )
  3228. end)
  3229. it('plays nice with `if` when success', function()
  3230. eq(
  3231. true,
  3232. exec_lua [[
  3233. if vim.wait(50, function() return true end) then
  3234. return true
  3235. end
  3236. return false
  3237. ]]
  3238. )
  3239. end)
  3240. it('returns immediately with false if timeout is 0', function()
  3241. eq(
  3242. { false, -1 },
  3243. exec_lua [[
  3244. return {
  3245. vim.wait(0, function() return false end)
  3246. }
  3247. ]]
  3248. )
  3249. end)
  3250. it('works with tables with __call', function()
  3251. eq(
  3252. true,
  3253. exec_lua [[
  3254. local t = setmetatable({}, {__call = function(...) return true end})
  3255. return vim.wait(100, t, 10)
  3256. ]]
  3257. )
  3258. end)
  3259. it('works with tables with __call that change', function()
  3260. eq(
  3261. true,
  3262. exec_lua [[
  3263. local t = {count = 0}
  3264. setmetatable(t, {
  3265. __call = function()
  3266. t.count = t.count + 1
  3267. return t.count > 3
  3268. end
  3269. })
  3270. return vim.wait(1000, t, 10)
  3271. ]]
  3272. )
  3273. end)
  3274. it('fails with negative intervals', function()
  3275. local pcall_result = exec_lua [[
  3276. return pcall(function() vim.wait(1000, function() return false end, -1) end)
  3277. ]]
  3278. eq(false, pcall_result)
  3279. end)
  3280. it('fails with weird intervals', function()
  3281. local pcall_result = exec_lua [[
  3282. return pcall(function() vim.wait(1000, function() return false end, 'a string value') end)
  3283. ]]
  3284. eq(false, pcall_result)
  3285. end)
  3286. describe('returns -2 when interrupted', function()
  3287. before_each(function()
  3288. local channel = api.nvim_get_chan_info(0).id
  3289. api.nvim_set_var('channel', channel)
  3290. end)
  3291. it('without callback', function()
  3292. exec_lua([[
  3293. function _G.Wait()
  3294. vim.rpcnotify(vim.g.channel, 'ready')
  3295. local _, interrupted = vim.wait(4000)
  3296. vim.rpcnotify(vim.g.channel, 'wait', interrupted)
  3297. end
  3298. ]])
  3299. feed(':lua _G.Wait()<CR>')
  3300. eq({ 'notification', 'ready', {} }, next_msg(500))
  3301. feed('<C-C>')
  3302. eq({ 'notification', 'wait', { -2 } }, next_msg(500))
  3303. end)
  3304. it('with callback', function()
  3305. exec_lua([[
  3306. function _G.Wait()
  3307. vim.rpcnotify(vim.g.channel, 'ready')
  3308. local _, interrupted = vim.wait(4000, function() end)
  3309. vim.rpcnotify(vim.g.channel, 'wait', interrupted)
  3310. end
  3311. ]])
  3312. feed(':lua _G.Wait()<CR>')
  3313. eq({ 'notification', 'ready', {} }, next_msg(500))
  3314. feed('<C-C>')
  3315. eq({ 'notification', 'wait', { -2 } }, next_msg(500))
  3316. end)
  3317. end)
  3318. it('fails in fast callbacks #26122', function()
  3319. local screen = Screen.new(80, 10)
  3320. exec_lua([[
  3321. local timer = vim.uv.new_timer()
  3322. timer:start(0, 0, function()
  3323. timer:close()
  3324. vim.wait(100, function() end)
  3325. end)
  3326. ]])
  3327. screen:expect({
  3328. any = pesc('E5560: vim.wait must not be called in a fast event context'),
  3329. })
  3330. feed('<CR>')
  3331. assert_alive()
  3332. end)
  3333. end)
  3334. it('vim.notify_once', function()
  3335. local screen = Screen.new(60, 5)
  3336. screen:expect {
  3337. grid = [[
  3338. ^ |
  3339. {1:~ }|*3
  3340. |
  3341. ]],
  3342. }
  3343. exec_lua [[vim.notify_once("I'll only tell you this once...", vim.log.levels.WARN)]]
  3344. screen:expect {
  3345. grid = [[
  3346. ^ |
  3347. {1:~ }|*3
  3348. {19:I'll only tell you this once...} |
  3349. ]],
  3350. }
  3351. feed('<C-l>')
  3352. screen:expect {
  3353. grid = [[
  3354. ^ |
  3355. {1:~ }|*3
  3356. |
  3357. ]],
  3358. }
  3359. exec_lua [[vim.notify_once("I'll only tell you this once...")]]
  3360. screen:expect_unchanged()
  3361. end)
  3362. describe('vim.schedule_wrap', function()
  3363. it('preserves argument lists', function()
  3364. exec_lua [[
  3365. local fun = vim.schedule_wrap(function(kling, klang, klonk)
  3366. vim.rpcnotify(1, 'mayday_mayday', {a=kling, b=klang, c=klonk})
  3367. end)
  3368. fun("BOB", nil, "MIKE")
  3369. ]]
  3370. eq({ 'notification', 'mayday_mayday', { { a = 'BOB', c = 'MIKE' } } }, next_msg())
  3371. -- let's gooooo
  3372. exec_lua [[
  3373. vim.schedule_wrap(function(...) vim.rpcnotify(1, 'boogalo', select('#', ...)) end)(nil,nil,nil,nil)
  3374. ]]
  3375. eq({ 'notification', 'boogalo', { 4 } }, next_msg())
  3376. end)
  3377. end)
  3378. describe('vim.api.nvim_buf_call', function()
  3379. it('can access buf options', function()
  3380. local buf1 = api.nvim_get_current_buf()
  3381. local buf2 = exec_lua [[
  3382. buf2 = vim.api.nvim_create_buf(false, true)
  3383. return buf2
  3384. ]]
  3385. eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 }))
  3386. eq(false, api.nvim_get_option_value('autoindent', { buf = buf2 }))
  3387. local val = exec_lua [[
  3388. return vim.api.nvim_buf_call(buf2, function()
  3389. vim.cmd "set autoindent"
  3390. return vim.api.nvim_get_current_buf()
  3391. end)
  3392. ]]
  3393. eq(false, api.nvim_get_option_value('autoindent', { buf = buf1 }))
  3394. eq(true, api.nvim_get_option_value('autoindent', { buf = buf2 }))
  3395. eq(buf1, api.nvim_get_current_buf())
  3396. eq(buf2, val)
  3397. end)
  3398. it('does not cause ml_get errors with invalid visual selection', function()
  3399. -- Should be fixed by vim-patch:8.2.4028.
  3400. exec_lua [[
  3401. local api = vim.api
  3402. local t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end
  3403. api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"})
  3404. api.nvim_feedkeys(t "G<C-V>", "txn", false)
  3405. api.nvim_buf_call(api.nvim_create_buf(false, true), function() vim.cmd "redraw" end)
  3406. ]]
  3407. end)
  3408. it('can be nested crazily with hidden buffers', function()
  3409. eq(
  3410. true,
  3411. exec_lua([[
  3412. local function scratch_buf_call(fn)
  3413. local buf = vim.api.nvim_create_buf(false, true)
  3414. vim.api.nvim_set_option_value('cindent', true, {buf = buf})
  3415. return vim.api.nvim_buf_call(buf, function()
  3416. return vim.api.nvim_get_current_buf() == buf
  3417. and vim.api.nvim_get_option_value('cindent', {buf = buf})
  3418. and fn()
  3419. end) and vim.api.nvim_buf_delete(buf, {}) == nil
  3420. end
  3421. return scratch_buf_call(function()
  3422. return scratch_buf_call(function()
  3423. return scratch_buf_call(function()
  3424. return scratch_buf_call(function()
  3425. return scratch_buf_call(function()
  3426. return scratch_buf_call(function()
  3427. return scratch_buf_call(function()
  3428. return scratch_buf_call(function()
  3429. return scratch_buf_call(function()
  3430. return scratch_buf_call(function()
  3431. return scratch_buf_call(function()
  3432. return scratch_buf_call(function()
  3433. return true
  3434. end)
  3435. end)
  3436. end)
  3437. end)
  3438. end)
  3439. end)
  3440. end)
  3441. end)
  3442. end)
  3443. end)
  3444. end)
  3445. end)
  3446. ]])
  3447. )
  3448. end)
  3449. it('can return values by reference', function()
  3450. eq(
  3451. { 4, 7 },
  3452. exec_lua [[
  3453. local val = {4, 10}
  3454. local ref = vim.api.nvim_buf_call(0, function() return val end)
  3455. ref[2] = 7
  3456. return val
  3457. ]]
  3458. )
  3459. end)
  3460. end)
  3461. describe('vim.api.nvim_win_call', function()
  3462. it('can access window options', function()
  3463. command('vsplit')
  3464. local win1 = api.nvim_get_current_win()
  3465. command('wincmd w')
  3466. local win2 = exec_lua [[
  3467. win2 = vim.api.nvim_get_current_win()
  3468. return win2
  3469. ]]
  3470. command('wincmd p')
  3471. eq('', api.nvim_get_option_value('winhighlight', { win = win1 }))
  3472. eq('', api.nvim_get_option_value('winhighlight', { win = win2 }))
  3473. local val = exec_lua [[
  3474. return vim.api.nvim_win_call(win2, function()
  3475. vim.cmd "setlocal winhighlight=Normal:Normal"
  3476. return vim.api.nvim_get_current_win()
  3477. end)
  3478. ]]
  3479. eq('', api.nvim_get_option_value('winhighlight', { win = win1 }))
  3480. eq('Normal:Normal', api.nvim_get_option_value('winhighlight', { win = win2 }))
  3481. eq(win1, api.nvim_get_current_win())
  3482. eq(win2, val)
  3483. end)
  3484. it('does not cause ml_get errors with invalid visual selection', function()
  3485. -- Add lines to the current buffer and make another window looking into an empty buffer.
  3486. exec_lua [[
  3487. _G.api = vim.api
  3488. _G.t = function(s) return api.nvim_replace_termcodes(s, true, true, true) end
  3489. _G.win_lines = api.nvim_get_current_win()
  3490. vim.cmd "new"
  3491. _G.win_empty = api.nvim_get_current_win()
  3492. api.nvim_set_current_win(win_lines)
  3493. api.nvim_buf_set_lines(0, 0, -1, true, {"a", "b", "c"})
  3494. ]]
  3495. -- Start Visual in current window, redraw in other window with fewer lines.
  3496. -- Should be fixed by vim-patch:8.2.4018.
  3497. exec_lua [[
  3498. api.nvim_feedkeys(t "G<C-V>", "txn", false)
  3499. api.nvim_win_call(win_empty, function() vim.cmd "redraw" end)
  3500. ]]
  3501. -- Start Visual in current window, extend it in other window with more lines.
  3502. -- Fixed for win_execute by vim-patch:8.2.4026, but nvim_win_call should also not be affected.
  3503. exec_lua [[
  3504. api.nvim_feedkeys(t "<Esc>gg", "txn", false)
  3505. api.nvim_set_current_win(win_empty)
  3506. api.nvim_feedkeys(t "gg<C-V>", "txn", false)
  3507. api.nvim_win_call(win_lines, function() api.nvim_feedkeys(t "G<C-V>", "txn", false) end)
  3508. vim.cmd "redraw"
  3509. ]]
  3510. end)
  3511. it('updates ruler if cursor moved', function()
  3512. -- Fixed for win_execute in vim-patch:8.1.2124, but should've applied to nvim_win_call too!
  3513. local screen = Screen.new(30, 5)
  3514. exec_lua [[
  3515. _G.api = vim.api
  3516. vim.opt.ruler = true
  3517. local lines = {}
  3518. for i = 0, 499 do lines[#lines + 1] = tostring(i) end
  3519. api.nvim_buf_set_lines(0, 0, -1, true, lines)
  3520. api.nvim_win_set_cursor(0, {20, 0})
  3521. vim.cmd "split"
  3522. _G.win = api.nvim_get_current_win()
  3523. vim.cmd "wincmd w | redraw"
  3524. ]]
  3525. screen:expect [[
  3526. 19 |
  3527. {2:[No Name] [+] 20,1 3%}|
  3528. ^19 |
  3529. {3:[No Name] [+] 20,1 3%}|
  3530. |
  3531. ]]
  3532. exec_lua [[
  3533. api.nvim_win_call(win, function() api.nvim_win_set_cursor(0, {100, 0}) end)
  3534. vim.cmd "redraw"
  3535. ]]
  3536. screen:expect [[
  3537. 99 |
  3538. {2:[No Name] [+] 100,1 19%}|
  3539. ^19 |
  3540. {3:[No Name] [+] 20,1 3%}|
  3541. |
  3542. ]]
  3543. end)
  3544. it('can return values by reference', function()
  3545. eq(
  3546. { 7, 10 },
  3547. exec_lua [[
  3548. local val = {4, 10}
  3549. local ref = vim.api.nvim_win_call(0, function() return val end)
  3550. ref[1] = 7
  3551. return val
  3552. ]]
  3553. )
  3554. end)
  3555. it('layout in current tabpage does not affect windows in others', function()
  3556. command('tab split')
  3557. local t2_move_win = api.nvim_get_current_win()
  3558. command('vsplit')
  3559. local t2_other_win = api.nvim_get_current_win()
  3560. command('tabprevious')
  3561. matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)'))
  3562. command('vsplit')
  3563. -- Without vim-patch:8.2.3862, this gives E36, despite just the 1st tabpage being full.
  3564. exec_lua('vim.api.nvim_win_call(..., function() vim.cmd.wincmd "J" end)', t2_move_win)
  3565. eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2))
  3566. end)
  3567. end)
  3568. describe('vim.iconv', function()
  3569. it('can convert strings', function()
  3570. eq(
  3571. 'hello',
  3572. exec_lua [[
  3573. return vim.iconv('hello', 'latin1', 'utf-8')
  3574. ]]
  3575. )
  3576. end)
  3577. it('can validate arguments', function()
  3578. eq(
  3579. { false, 'Expected at least 3 arguments' },
  3580. exec_lua [[
  3581. return {pcall(vim.iconv, 'hello')}
  3582. ]]
  3583. )
  3584. eq(
  3585. { false, "bad argument #3 to '?' (expected string)" },
  3586. exec_lua [[
  3587. return {pcall(vim.iconv, 'hello', 'utf-8', true)}
  3588. ]]
  3589. )
  3590. end)
  3591. it('can handle bad encodings', function()
  3592. eq(
  3593. NIL,
  3594. exec_lua [[
  3595. return vim.iconv('hello', 'foo', 'bar')
  3596. ]]
  3597. )
  3598. end)
  3599. it('can handle strings with NUL bytes', function()
  3600. eq(
  3601. 7,
  3602. exec_lua [[
  3603. local a = string.char(97, 98, 99, 0, 100, 101, 102) -- abc\0def
  3604. return string.len(vim.iconv(a, 'latin1', 'utf-8'))
  3605. ]]
  3606. )
  3607. end)
  3608. end)
  3609. describe('vim.defaulttable', function()
  3610. it('creates nested table by default', function()
  3611. eq(
  3612. { b = { c = 1 } },
  3613. exec_lua [[
  3614. local a = vim.defaulttable()
  3615. a.b.c = 1
  3616. return a
  3617. ]]
  3618. )
  3619. end)
  3620. it('allows to create default objects', function()
  3621. eq(
  3622. { b = 1 },
  3623. exec_lua [[
  3624. local a = vim.defaulttable(function() return 0 end)
  3625. a.b = a.b + 1
  3626. return a
  3627. ]]
  3628. )
  3629. end)
  3630. it('accepts the key name', function()
  3631. eq(
  3632. { b = 'b', c = 'c' },
  3633. exec_lua [[
  3634. local a = vim.defaulttable(function(k) return k end)
  3635. local _ = a.b
  3636. local _ = a.c
  3637. return a
  3638. ]]
  3639. )
  3640. end)
  3641. end)
  3642. it('vim.lua_omnifunc', function()
  3643. local screen = Screen.new(60, 5)
  3644. command [[ set omnifunc=v:lua.vim.lua_omnifunc ]]
  3645. -- Note: the implementation is shared with lua command line completion.
  3646. -- More tests for completion in lua/command_line_completion_spec.lua
  3647. feed [[ivim.insp<c-x><c-o>]]
  3648. screen:expect {
  3649. grid = [[
  3650. vim.inspect^ |
  3651. {1:~ }{12: inspect }{1: }|
  3652. {1:~ }{4: inspect_pos }{1: }|
  3653. {1:~ }|
  3654. {5:-- Omni completion (^O^N^P) }{6:match 1 of 2} |
  3655. ]],
  3656. }
  3657. end)
  3658. it('vim.print', function()
  3659. -- vim.print() returns its args.
  3660. eq(
  3661. { 42, 'abc', { a = { b = 77 } } },
  3662. exec_lua [[return {vim.print(42, 'abc', { a = { b = 77 }})}]]
  3663. )
  3664. -- vim.print() pretty-prints the args.
  3665. eq(
  3666. dedent [[
  3667. 42
  3668. abc
  3669. {
  3670. a = {
  3671. b = 77
  3672. }
  3673. }]],
  3674. eval [[execute('lua vim.print(42, "abc", { a = { b = 77 }})')]]
  3675. )
  3676. end)
  3677. it('vim.F.if_nil', function()
  3678. local function if_nil(...)
  3679. return exec_lua(
  3680. [[
  3681. local args = {...}
  3682. local nargs = select('#', ...)
  3683. for i = 1, nargs do
  3684. if args[i] == vim.NIL then
  3685. args[i] = nil
  3686. end
  3687. end
  3688. return vim.F.if_nil(unpack(args, 1, nargs))
  3689. ]],
  3690. ...
  3691. )
  3692. end
  3693. local a = NIL
  3694. local b = NIL
  3695. local c = 42
  3696. local d = false
  3697. eq(42, if_nil(a, c))
  3698. eq(false, if_nil(d, b))
  3699. eq(42, if_nil(a, b, c, d))
  3700. eq(false, if_nil(d))
  3701. eq(false, if_nil(d, c))
  3702. eq(NIL, if_nil(a))
  3703. end)
  3704. it('lpeg', function()
  3705. eq(
  3706. 5,
  3707. exec_lua [[
  3708. local m = vim.lpeg
  3709. return m.match(m.R'09'^1, '4504ab')
  3710. ]]
  3711. )
  3712. eq(4, exec_lua [[ return vim.re.match("abcde", '[a-c]+') ]])
  3713. end)
  3714. it('vim.ringbuf', function()
  3715. local results = exec_lua([[
  3716. local ringbuf = vim.ringbuf(3)
  3717. ringbuf:push("a") -- idx: 0
  3718. local peeka1 = ringbuf:peek()
  3719. local peeka2 = ringbuf:peek()
  3720. local popa = ringbuf:pop()
  3721. local popnil = ringbuf:pop()
  3722. ringbuf:push("a") -- idx: 1
  3723. ringbuf:push("b") -- idx: 2
  3724. -- doesn't read last added item, but uses separate read index
  3725. local pop_after_add_b = ringbuf:pop()
  3726. ringbuf:push("c") -- idx: 3 wraps around, overrides idx: 0 "a"
  3727. ringbuf:push("d") -- idx: 4 wraps around, overrides idx: 1 "a"
  3728. return {
  3729. peeka1 = peeka1,
  3730. peeka2 = peeka2,
  3731. pop1 = popa,
  3732. pop2 = popnil,
  3733. pop3 = ringbuf:pop(),
  3734. pop4 = ringbuf:pop(),
  3735. pop5 = ringbuf:pop(),
  3736. pop_after_add_b = pop_after_add_b,
  3737. }
  3738. ]])
  3739. local expected = {
  3740. peeka1 = 'a',
  3741. peeka2 = 'a',
  3742. pop1 = 'a',
  3743. pop2 = nil,
  3744. pop3 = 'b',
  3745. pop4 = 'c',
  3746. pop5 = 'd',
  3747. pop_after_add_b = 'a',
  3748. }
  3749. eq(expected, results)
  3750. end)
  3751. end)
  3752. describe('lua: builtin modules', function()
  3753. local function do_tests()
  3754. eq(2, exec_lua [[return vim.tbl_count {x=1,y=2}]])
  3755. eq('{ 10, "spam" }', exec_lua [[return vim.inspect {10, 'spam'}]])
  3756. end
  3757. it('works', function()
  3758. clear()
  3759. do_tests()
  3760. end)
  3761. it('works when disabled', function()
  3762. clear('--luamod-dev')
  3763. do_tests()
  3764. end)
  3765. it('works without runtime', function()
  3766. clear { env = { VIMRUNTIME = 'fixtures/a' } }
  3767. do_tests()
  3768. end)
  3769. it('fails when disabled without runtime', function()
  3770. clear()
  3771. command("let $VIMRUNTIME='fixtures/a'")
  3772. -- Use system([nvim,…]) instead of clear() to avoid stderr noise. #21844
  3773. local out = fn.system({
  3774. nvim_prog,
  3775. '--clean',
  3776. '--luamod-dev',
  3777. [[+call nvim_exec_lua('return vim.tbl_count {x=1,y=2}')]],
  3778. '+qa!',
  3779. }):gsub('\r\n', '\n')
  3780. eq(1, eval('v:shell_error'))
  3781. matches("'vim%.shared' not found", out)
  3782. end)
  3783. end)
  3784. describe('lua: require("mod") from packages', function()
  3785. before_each(function()
  3786. clear('--cmd', 'set rtp+=test/functional/fixtures pp+=test/functional/fixtures')
  3787. end)
  3788. it('propagates syntax error', function()
  3789. local syntax_error_msg = exec_lua [[
  3790. local _, err = pcall(require, "syntax_error")
  3791. return err
  3792. ]]
  3793. matches('unexpected symbol', syntax_error_msg)
  3794. end)
  3795. it('uses the right order of mod.lua vs mod/init.lua', function()
  3796. -- lua/fancy_x.lua takes precedence over lua/fancy_x/init.lua
  3797. eq('I am fancy_x.lua', exec_lua [[ return require'fancy_x' ]])
  3798. -- but lua/fancy_y/init.lua takes precedence over after/lua/fancy_y.lua
  3799. eq('I am init.lua of fancy_y!', exec_lua [[ return require'fancy_y' ]])
  3800. -- safety check: after/lua/fancy_z.lua is still loaded
  3801. eq('I am fancy_z.lua', exec_lua [[ return require'fancy_z' ]])
  3802. end)
  3803. end)
  3804. describe('vim.keymap', function()
  3805. before_each(clear)
  3806. it('validates', function()
  3807. matches(
  3808. 'mode: expected string|table, got number',
  3809. pcall_err(exec_lua, [[vim.keymap.set(42, 'x', print)]])
  3810. )
  3811. matches(
  3812. 'rhs: expected string|function, got nil',
  3813. pcall_err(exec_lua, [[vim.keymap.set('n', 'x')]])
  3814. )
  3815. matches(
  3816. 'lhs: expected string, got table',
  3817. pcall_err(exec_lua, [[vim.keymap.set('n', {}, print)]])
  3818. )
  3819. matches(
  3820. 'rhs: expected string|function, got number',
  3821. pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 42, function() end)]])
  3822. )
  3823. matches(
  3824. 'opts: expected table, got function',
  3825. pcall_err(exec_lua, [[vim.keymap.set({}, 'x', 'x', function() end)]])
  3826. )
  3827. matches(
  3828. 'rhs: expected string|function, got number',
  3829. pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 42)]])
  3830. )
  3831. matches('Invalid mode shortname: "z"', pcall_err(exec_lua, [[vim.keymap.set('z', 'x', 'y')]]))
  3832. end)
  3833. it('mapping', function()
  3834. eq(
  3835. 0,
  3836. exec_lua [[
  3837. GlobalCount = 0
  3838. vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end)
  3839. return GlobalCount
  3840. ]]
  3841. )
  3842. feed('asdf\n')
  3843. eq(1, exec_lua [[return GlobalCount]])
  3844. end)
  3845. it('expr mapping', function()
  3846. exec_lua [[
  3847. vim.keymap.set('n', 'aa', function() return '<Insert>π<C-V><M-π>foo<lt><Esc>' end, {expr = true})
  3848. ]]
  3849. feed('aa')
  3850. eq({ 'π<M-π>foo<' }, api.nvim_buf_get_lines(0, 0, -1, false))
  3851. end)
  3852. it('overwrite a mapping', function()
  3853. eq(
  3854. 0,
  3855. exec_lua [[
  3856. GlobalCount = 0
  3857. vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end)
  3858. return GlobalCount
  3859. ]]
  3860. )
  3861. feed('asdf\n')
  3862. eq(1, exec_lua [[return GlobalCount]])
  3863. exec_lua [[
  3864. vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount - 1 end)
  3865. ]]
  3866. feed('asdf\n')
  3867. eq(0, exec_lua [[return GlobalCount]])
  3868. end)
  3869. it('unmap', function()
  3870. eq(
  3871. 0,
  3872. exec_lua [[
  3873. GlobalCount = 0
  3874. vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end)
  3875. return GlobalCount
  3876. ]]
  3877. )
  3878. feed('asdf\n')
  3879. eq(1, exec_lua [[return GlobalCount]])
  3880. exec_lua [[
  3881. vim.keymap.del('n', 'asdf')
  3882. ]]
  3883. feed('asdf\n')
  3884. eq(1, exec_lua [[return GlobalCount]])
  3885. eq('\nNo mapping found', n.exec_capture('nmap asdf'))
  3886. end)
  3887. it('buffer-local mappings', function()
  3888. eq(
  3889. 0,
  3890. exec_lua [[
  3891. GlobalCount = 0
  3892. vim.keymap.set('n', 'asdf', function() GlobalCount = GlobalCount + 1 end, {buffer=true})
  3893. return GlobalCount
  3894. ]]
  3895. )
  3896. feed('asdf\n')
  3897. eq(1, exec_lua [[return GlobalCount]])
  3898. exec_lua [[
  3899. vim.keymap.del('n', 'asdf', {buffer=true})
  3900. ]]
  3901. feed('asdf\n')
  3902. eq(1, exec_lua [[return GlobalCount]])
  3903. eq('\nNo mapping found', n.exec_capture('nmap asdf'))
  3904. end)
  3905. it('does not mutate the opts parameter', function()
  3906. eq(
  3907. true,
  3908. exec_lua [[
  3909. opts = {buffer=true}
  3910. vim.keymap.set('n', 'asdf', function() end, opts)
  3911. return opts.buffer
  3912. ]]
  3913. )
  3914. eq(
  3915. true,
  3916. exec_lua [[
  3917. vim.keymap.del('n', 'asdf', opts)
  3918. return opts.buffer
  3919. ]]
  3920. )
  3921. end)
  3922. it('<Plug> mappings', function()
  3923. eq(
  3924. 0,
  3925. exec_lua [[
  3926. GlobalCount = 0
  3927. vim.keymap.set('n', '<plug>(asdf)', function() GlobalCount = GlobalCount + 1 end)
  3928. vim.keymap.set('n', 'ww', '<plug>(asdf)')
  3929. return GlobalCount
  3930. ]]
  3931. )
  3932. feed('ww\n')
  3933. eq(1, exec_lua [[return GlobalCount]])
  3934. end)
  3935. end)
  3936. describe('Vimscript function exists()', function()
  3937. it('can check a lua function', function()
  3938. eq(
  3939. 1,
  3940. exec_lua [[
  3941. _G.test = function() print("hello") end
  3942. return vim.fn.exists('*v:lua.test')
  3943. ]]
  3944. )
  3945. eq(1, fn.exists('*v:lua.require("mpack").decode'))
  3946. eq(1, fn.exists("*v:lua.require('mpack').decode"))
  3947. eq(1, fn.exists('*v:lua.require"mpack".decode'))
  3948. eq(1, fn.exists("*v:lua.require'mpack'.decode"))
  3949. eq(1, fn.exists("*v:lua.require('vim.lsp').start"))
  3950. eq(1, fn.exists('*v:lua.require"vim.lsp".start'))
  3951. eq(1, fn.exists("*v:lua.require'vim.lsp'.start"))
  3952. eq(0, fn.exists("*v:lua.require'vim.lsp'.unknown"))
  3953. eq(0, fn.exists('*v:lua.?'))
  3954. end)
  3955. end)