12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028 |
- local helpers = require('test.functional.helpers')(after_each)
- local Screen = require('test.functional.ui.screen')
- local lfs = require('lfs')
- local luv = require('luv')
- local fmt = string.format
- local assert_alive = helpers.assert_alive
- local NIL = helpers.NIL
- local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq
- local command = helpers.command
- local exec = helpers.exec
- local eval = helpers.eval
- local expect = helpers.expect
- local funcs = helpers.funcs
- local iswin = helpers.iswin
- local meths = helpers.meths
- local matches = helpers.matches
- local pesc = helpers.pesc
- local mkdir_p = helpers.mkdir_p
- local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed
- local is_os = helpers.is_os
- local parse_context = helpers.parse_context
- local request = helpers.request
- local rmdir = helpers.rmdir
- local source = helpers.source
- local next_msg = helpers.next_msg
- local tmpname = helpers.tmpname
- local write_file = helpers.write_file
- local exec_lua = helpers.exec_lua
- local exc_exec = helpers.exc_exec
- local insert = helpers.insert
- local expect_exit = helpers.expect_exit
- local pcall_err = helpers.pcall_err
- local format_string = helpers.format_string
- local intchar2lua = helpers.intchar2lua
- local mergedicts_copy = helpers.mergedicts_copy
- local endswith = helpers.endswith
- describe('API', function()
- before_each(clear)
- it('validates requests', function()
- -- RPC
- matches('Invalid method: bogus$',
- pcall_err(request, 'bogus'))
- matches('Invalid method: … の り 。…$',
- pcall_err(request, '… の り 。…'))
- matches('Invalid method: <empty>$',
- pcall_err(request, ''))
- -- Non-RPC: rpcrequest(v:servername) uses internal channel.
- matches('Invalid method: … の り 。…$',
- pcall_err(request, 'nvim_eval',
- [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), '… の り 。…')]=]))
- matches('Invalid method: bogus$',
- pcall_err(request, 'nvim_eval',
- [=[rpcrequest(sockconnect('pipe', v:servername, {'rpc':1}), 'bogus')]=]))
- -- XXX: This must be the last one, else next one will fail:
- -- "Packer instance already working. Use another Packer ..."
- matches("can't serialize object$",
- pcall_err(request, nil))
- end)
- it('handles errors in async requests', function()
- local error_types = meths.get_api_info()[2].error_types
- nvim_async('bogus')
- eq({'notification', 'nvim_error_event',
- {error_types.Exception.id, 'Invalid method: nvim_bogus'}}, next_msg())
- -- error didn't close channel.
- assert_alive()
- end)
- it('failed async request emits nvim_error_event', function()
- local error_types = meths.get_api_info()[2].error_types
- nvim_async('command', 'bogus')
- eq({'notification', 'nvim_error_event',
- {error_types.Exception.id, 'Vim:E492: Not an editor command: bogus'}},
- next_msg())
- -- error didn't close channel.
- assert_alive()
- end)
- it('does not set CA_COMMAND_BUSY #7254', function()
- nvim('command', 'split')
- nvim('command', 'autocmd WinEnter * startinsert')
- nvim('command', 'wincmd w')
- eq({mode='i', blocking=false}, nvim("get_mode"))
- end)
- describe('nvim_exec', function()
- it('one-line input', function()
- nvim('exec', "let x1 = 'a'", false)
- eq('a', nvim('get_var', 'x1'))
- end)
- it(':verbose set {option}?', function()
- nvim('exec', 'set nowrap', false)
- eq('nowrap\n\tLast set from anonymous :source',
- nvim('exec', 'verbose set wrap?', true))
- -- Using script var to force creation of a script item
- nvim('exec', [[
- let s:a = 1
- set nowrap
- ]], false)
- eq('nowrap\n\tLast set from anonymous :source (script id 1)',
- nvim('exec', 'verbose set wrap?', true))
- end)
- it('multiline input', function()
- -- Heredoc + empty lines.
- nvim('exec', "let x2 = 'a'\n", false)
- eq('a', nvim('get_var', 'x2'))
- nvim('exec','lua <<EOF\n\n\n\ny=3\n\n\nEOF', false)
- eq(3, nvim('eval', "luaeval('y')"))
- eq('', nvim('exec', 'lua <<EOF\ny=3\nEOF', false))
- eq(3, nvim('eval', "luaeval('y')"))
- -- Multiple statements
- nvim('exec', 'let x1=1\nlet x2=2\nlet x3=3\n', false)
- eq(1, nvim('eval', 'x1'))
- eq(2, nvim('eval', 'x2'))
- eq(3, nvim('eval', 'x3'))
- -- Functions
- nvim('exec', 'function Foo()\ncall setline(1,["xxx"])\nendfunction', false)
- eq('', nvim('get_current_line'))
- nvim('exec', 'call Foo()', false)
- eq('xxx', nvim('get_current_line'))
- -- Autocmds
- nvim('exec','autocmd BufAdd * :let x1 = "Hello"', false)
- nvim('command', 'new foo')
- eq('Hello', request('nvim_eval', 'g:x1'))
- -- Line continuations
- nvim('exec', [[
- let abc = #{
- \ a: 1,
- "\ b: 2,
- \ c: 3
- \ }]], false)
- eq({a = 1, c = 3}, request('nvim_eval', 'g:abc'))
- -- try no spaces before continuations to catch off-by-one error
- nvim('exec', 'let ab = #{\n\\a: 98,\n"\\ b: 2\n\\}', false)
- eq({a = 98}, request('nvim_eval', 'g:ab'))
- -- Script scope (s:)
- eq('ahoy! script-scoped varrrrr', nvim('exec', [[
- let s:pirate = 'script-scoped varrrrr'
- function! s:avast_ye_hades(s) abort
- return a:s .. ' ' .. s:pirate
- endfunction
- echo <sid>avast_ye_hades('ahoy!')
- ]], true))
- eq('ahoy! script-scoped varrrrr', nvim('exec', [[
- let s:pirate = 'script-scoped varrrrr'
- function! Avast_ye_hades(s) abort
- return a:s .. ' ' .. s:pirate
- endfunction
- echo nvim_exec('echo Avast_ye_hades(''ahoy!'')', 1)
- ]], true))
- eq('Vim(call):E5555: API call: Vim(echo):E121: Undefined variable: s:pirate',
- pcall_err(request, 'nvim_exec', [[
- let s:pirate = 'script-scoped varrrrr'
- call nvim_exec('echo s:pirate', 1)
- ]], false))
- -- Script items are created only on script var access
- eq('1\n0', nvim('exec', [[
- echo expand("<SID>")->empty()
- let s:a = 123
- echo expand("<SID>")->empty()
- ]], true))
- eq('1\n0', nvim('exec', [[
- echo expand("<SID>")->empty()
- function s:a() abort
- endfunction
- echo expand("<SID>")->empty()
- ]], true))
- end)
- it('non-ASCII input', function()
- nvim('exec', [=[
- new
- exe "normal! i ax \n Ax "
- :%s/ax/--a1234--/g | :%s/Ax/--A1234--/g
- ]=], false)
- nvim('command', '1')
- eq(' --a1234-- ', nvim('get_current_line'))
- nvim('command', '2')
- eq(' --A1234-- ', nvim('get_current_line'))
- nvim('exec', [[
- new
- call setline(1,['xxx'])
- call feedkeys('r')
- call feedkeys('ñ', 'xt')
- ]], false)
- eq('ñxx', nvim('get_current_line'))
- end)
- it('execution error', function()
- eq('Vim:E492: Not an editor command: bogus_command',
- pcall_err(request, 'nvim_exec', 'bogus_command', false))
- eq('', nvim('eval', 'v:errmsg')) -- v:errmsg was not updated.
- eq('', eval('v:exception'))
- eq('Vim(buffer):E86: Buffer 23487 does not exist',
- pcall_err(request, 'nvim_exec', 'buffer 23487', false))
- eq('', eval('v:errmsg')) -- v:errmsg was not updated.
- eq('', eval('v:exception'))
- end)
- it('recursion', function()
- local fname = tmpname()
- write_file(fname, 'let x1 = "set from :source file"\n')
- -- nvim_exec
- -- :source
- -- nvim_exec
- request('nvim_exec', [[
- let x2 = substitute('foo','o','X','g')
- let x4 = 'should be overwritten'
- call nvim_exec("source ]]..fname..[[\nlet x3 = substitute('foo','foo','set by recursive nvim_exec','g')\nlet x5='overwritten'\nlet x4=x5\n", v:false)
- ]], false)
- eq('set from :source file', request('nvim_get_var', 'x1'))
- eq('fXX', request('nvim_get_var', 'x2'))
- eq('set by recursive nvim_exec', request('nvim_get_var', 'x3'))
- eq('overwritten', request('nvim_get_var', 'x4'))
- eq('overwritten', request('nvim_get_var', 'x5'))
- os.remove(fname)
- end)
- it('traceback', function()
- local fname = tmpname()
- write_file(fname, 'echo "hello"\n')
- local sourcing_fname = tmpname()
- write_file(sourcing_fname, 'call nvim_exec("source '..fname..'", v:false)\n')
- meths.exec('set verbose=2', false)
- local traceback_output = 'line 0: sourcing "'..sourcing_fname..'"\n'..
- 'line 0: sourcing "'..fname..'"\n'..
- 'hello\n'..
- 'finished sourcing '..fname..'\n'..
- 'continuing in nvim_exec() called at '..sourcing_fname..':1\n'..
- 'finished sourcing '..sourcing_fname..'\n'..
- 'continuing in nvim_exec() called at nvim_exec():0'
- eq(traceback_output,
- meths.exec('call nvim_exec("source '..sourcing_fname..'", v:false)', true))
- os.remove(fname)
- os.remove(sourcing_fname)
- end)
- it('returns output', function()
- eq('this is spinal tap',
- nvim('exec', 'lua <<EOF\n\n\nprint("this is spinal tap")\n\n\nEOF', true))
- eq('', nvim('exec', 'echo', true))
- eq('foo 42', nvim('exec', 'echo "foo" 42', true))
- end)
- it('displays messages when output=false', function()
- local screen = Screen.new(40, 8)
- screen:attach()
- screen:set_default_attr_ids({
- [0] = {bold=true, foreground=Screen.colors.Blue},
- })
- meths.exec("echo 'hello'", false)
- screen:expect{grid=[[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- hello |
- ]]}
- end)
- it('doesn\'t display messages when output=true', function()
- local screen = Screen.new(40, 6)
- screen:attach()
- screen:set_default_attr_ids({
- [0] = {bold=true, foreground=Screen.colors.Blue},
- })
- meths.exec("echo 'hello'", true)
- screen:expect{grid=[[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]]}
- exec([[
- func Print()
- call nvim_exec('echo "hello"', v:true)
- endfunc
- ]])
- feed([[:echon 1 | call Print() | echon 5<CR>]])
- screen:expect{grid=[[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- 15 |
- ]]}
- end)
- end)
- describe('nvim_command', function()
- it('works', function()
- local fname = tmpname()
- nvim('command', 'new')
- nvim('command', 'edit '..fname)
- nvim('command', 'normal itesting\napi')
- nvim('command', 'w')
- local f = io.open(fname)
- ok(f ~= nil)
- if is_os('win') then
- eq('testing\r\napi\r\n', f:read('*a'))
- else
- eq('testing\napi\n', f:read('*a'))
- end
- f:close()
- os.remove(fname)
- end)
- it('VimL validation error: fails with specific error', function()
- local status, rv = pcall(nvim, "command", "bogus_command")
- eq(false, status) -- nvim_command() failed.
- eq("E492:", string.match(rv, "E%d*:")) -- VimL error was returned.
- eq('', nvim('eval', 'v:errmsg')) -- v:errmsg was not updated.
- eq('', eval('v:exception'))
- end)
- it('VimL execution error: fails with specific error', function()
- local status, rv = pcall(nvim, "command", "buffer 23487")
- eq(false, status) -- nvim_command() failed.
- eq("E86: Buffer 23487 does not exist", string.match(rv, "E%d*:.*"))
- eq('', eval('v:errmsg')) -- v:errmsg was not updated.
- eq('', eval('v:exception'))
- end)
- end)
- describe('nvim_command_output', function()
- it('does not induce hit-enter prompt', function()
- nvim("ui_attach", 80, 20, {})
- -- Induce a hit-enter prompt use nvim_input (non-blocking).
- nvim('command', 'set cmdheight=1')
- nvim('input', [[:echo "hi\nhi2"<CR>]])
- -- Verify hit-enter prompt.
- eq({mode='r', blocking=true}, nvim("get_mode"))
- nvim('input', [[<C-c>]])
- -- Verify NO hit-enter prompt.
- nvim('command_output', [[echo "hi\nhi2"]])
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end)
- it('captures command output', function()
- eq('this is\nspinal tap',
- nvim('command_output', [[echo "this is\nspinal tap"]]))
- eq('no line ending!',
- nvim('command_output', [[echon "no line ending!"]]))
- end)
- it('captures empty command output', function()
- eq('', nvim('command_output', 'echo'))
- end)
- it('captures single-char command output', function()
- eq('x', nvim('command_output', 'echo "x"'))
- end)
- it('captures multiple commands', function()
- eq('foo\n 1 %a "[No Name]" line 1',
- nvim('command_output', 'echo "foo" | ls'))
- end)
- it('captures nested execute()', function()
- eq('\nnested1\nnested2\n 1 %a "[No Name]" line 1',
- nvim('command_output',
- [[echo execute('echo "nested1\nnested2"') | ls]]))
- end)
- it('captures nested nvim_command_output()', function()
- eq('nested1\nnested2\n 1 %a "[No Name]" line 1',
- nvim('command_output',
- [[echo nvim_command_output('echo "nested1\nnested2"') | ls]]))
- end)
- it('returns shell |:!| output', function()
- local win_lf = iswin() and '\r' or ''
- eq(':!echo foo\r\n\nfoo'..win_lf..'\n', nvim('command_output', [[!echo foo]]))
- end)
- it('VimL validation error: fails with specific error', function()
- local status, rv = pcall(nvim, "command_output", "bogus commannnd")
- eq(false, status) -- nvim_command_output() failed.
- eq("E492: Not an editor command: bogus commannnd",
- string.match(rv, "E%d*:.*"))
- eq('', eval('v:errmsg')) -- v:errmsg was not updated.
- -- Verify NO hit-enter prompt.
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end)
- it('VimL execution error: fails with specific error', function()
- local status, rv = pcall(nvim, "command_output", "buffer 42")
- eq(false, status) -- nvim_command_output() failed.
- eq("E86: Buffer 42 does not exist", string.match(rv, "E%d*:.*"))
- eq('', eval('v:errmsg')) -- v:errmsg was not updated.
- -- Verify NO hit-enter prompt.
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end)
- it('Does not cause heap buffer overflow with large output', function()
- eq(eval('string(range(1000000))'),
- nvim('command_output', 'echo range(1000000)'))
- end)
- end)
- describe('nvim_eval', function()
- it('works', function()
- nvim('command', 'let g:v1 = "a"')
- nvim('command', 'let g:v2 = [1, 2, {"v3": 3}]')
- eq({v1 = 'a', v2 = { 1, 2, { v3 = 3 } } }, nvim('eval', 'g:'))
- end)
- it('handles NULL-initialized strings correctly', function()
- eq(1, nvim('eval',"matcharg(1) == ['', '']"))
- eq({'', ''}, nvim('eval','matcharg(1)'))
- end)
- it('works under deprecated name', function()
- eq(2, request("vim_eval", "1+1"))
- end)
- it("VimL error: returns error details, does NOT update v:errmsg", function()
- eq('Vim:E121: Undefined variable: bogus',
- pcall_err(request, 'nvim_eval', 'bogus expression'))
- eq('', eval('v:errmsg')) -- v:errmsg was not updated.
- end)
- end)
- describe('nvim_call_function', function()
- it('works', function()
- nvim('call_function', 'setqflist', { { { filename = 'something', lnum = 17 } }, 'r' })
- eq(17, nvim('call_function', 'getqflist', {})[1].lnum)
- eq(17, nvim('call_function', 'eval', {17}))
- eq('foo', nvim('call_function', 'simplify', {'this/./is//redundant/../../../foo'}))
- end)
- it("VimL validation error: returns specific error, does NOT update v:errmsg", function()
- eq('Vim:E117: Unknown function: bogus function',
- pcall_err(request, 'nvim_call_function', 'bogus function', {'arg1'}))
- eq('Vim:E119: Not enough arguments for function: atan',
- pcall_err(request, 'nvim_call_function', 'atan', {}))
- eq('', eval('v:exception'))
- eq('', eval('v:errmsg')) -- v:errmsg was not updated.
- end)
- it("VimL error: returns error details, does NOT update v:errmsg", function()
- eq('Vim:E808: Number or Float required',
- pcall_err(request, 'nvim_call_function', 'atan', {'foo'}))
- eq('Vim:Invalid channel stream "xxx"',
- pcall_err(request, 'nvim_call_function', 'chanclose', {999, 'xxx'}))
- eq('Vim:E900: Invalid channel id',
- pcall_err(request, 'nvim_call_function', 'chansend', {999, 'foo'}))
- eq('', eval('v:exception'))
- eq('', eval('v:errmsg')) -- v:errmsg was not updated.
- end)
- it("VimL exception: returns exception details, does NOT update v:errmsg", function()
- source([[
- function! Foo() abort
- throw 'wtf'
- endfunction
- ]])
- eq('wtf', pcall_err(request, 'nvim_call_function', 'Foo', {}))
- eq('', eval('v:exception'))
- eq('', eval('v:errmsg')) -- v:errmsg was not updated.
- end)
- it('validates args', function()
- local too_many_args = { 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x' }
- source([[
- function! Foo(...) abort
- echo a:000
- endfunction
- ]])
- -- E740
- eq('Function called with too many arguments',
- pcall_err(request, 'nvim_call_function', 'Foo', too_many_args))
- end)
- end)
- describe('nvim_call_dict_function', function()
- it('invokes VimL dict function', function()
- source([[
- function! F(name) dict
- return self.greeting.', '.a:name.'!'
- endfunction
- let g:test_dict_fn = { 'greeting':'Hello', 'F':function('F') }
- let g:test_dict_fn2 = { 'greeting':'Hi' }
- function g:test_dict_fn2.F2(name)
- return self.greeting.', '.a:name.' ...'
- endfunction
- ]])
- -- :help Dictionary-function
- eq('Hello, World!', nvim('call_dict_function', 'g:test_dict_fn', 'F', {'World'}))
- -- Funcref is sent as NIL over RPC.
- eq({ greeting = 'Hello', F = NIL }, nvim('get_var', 'test_dict_fn'))
- -- :help numbered-function
- eq('Hi, Moon ...', nvim('call_dict_function', 'g:test_dict_fn2', 'F2', {'Moon'}))
- -- Funcref is sent as NIL over RPC.
- eq({ greeting = 'Hi', F2 = NIL }, nvim('get_var', 'test_dict_fn2'))
- -- Function specified via RPC dict.
- source('function! G() dict\n return "@".(self.result)."@"\nendfunction')
- eq('@it works@', nvim('call_dict_function', { result = 'it works', G = 'G'}, 'G', {}))
- end)
- it('validates args', function()
- command('let g:d={"baz":"zub","meep":[]}')
- eq('Not found: bogus',
- pcall_err(request, 'nvim_call_dict_function', 'g:d', 'bogus', {1,2}))
- eq('Not a function: baz',
- pcall_err(request, 'nvim_call_dict_function', 'g:d', 'baz', {1,2}))
- eq('Not a function: meep',
- pcall_err(request, 'nvim_call_dict_function', 'g:d', 'meep', {1,2}))
- eq('Vim:E117: Unknown function: f',
- pcall_err(request, 'nvim_call_dict_function', { f = '' }, 'f', {1,2}))
- eq('Not a function: f',
- pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", 'f', {1,2}))
- eq('dict argument type must be String or Dictionary',
- pcall_err(request, 'nvim_call_dict_function', 42, 'f', {1,2}))
- eq('Failed to evaluate dict expression',
- pcall_err(request, 'nvim_call_dict_function', 'foo', 'f', {1,2}))
- eq('dict not found',
- pcall_err(request, 'nvim_call_dict_function', '42', 'f', {1,2}))
- eq('Invalid (empty) function name',
- pcall_err(request, 'nvim_call_dict_function', "{ 'f': '' }", '', {1,2}))
- end)
- end)
- describe('nvim_set_current_dir', function()
- local start_dir
- before_each(function()
- clear()
- funcs.mkdir("Xtestdir")
- start_dir = funcs.getcwd()
- end)
- after_each(function()
- helpers.rmdir("Xtestdir")
- end)
- it('works', function()
- meths.set_current_dir("Xtestdir")
- eq(funcs.getcwd(), start_dir .. helpers.get_pathsep() .. "Xtestdir")
- end)
- it('sets previous directory', function()
- meths.set_current_dir("Xtestdir")
- meths.exec('cd -', false)
- eq(funcs.getcwd(), start_dir)
- end)
- end)
- describe('nvim_exec_lua', function()
- it('works', function()
- meths.exec_lua('vim.api.nvim_set_var("test", 3)', {})
- eq(3, meths.get_var('test'))
- eq(17, meths.exec_lua('a, b = ...\nreturn a + b', {10,7}))
- eq(NIL, meths.exec_lua('function xx(a,b)\nreturn a..b\nend',{}))
- eq("xy", meths.exec_lua('return xx(...)', {'x','y'}))
- -- Deprecated name: nvim_execute_lua.
- eq("xy", meths.execute_lua('return xx(...)', {'x','y'}))
- end)
- it('reports errors', function()
- eq([[Error loading lua: [string "<nvim>"]:0: '=' expected near '+']],
- pcall_err(meths.exec_lua, 'a+*b', {}))
- eq([[Error loading lua: [string "<nvim>"]:0: unexpected symbol near '1']],
- pcall_err(meths.exec_lua, '1+2', {}))
- eq([[Error loading lua: [string "<nvim>"]:0: unexpected symbol]],
- pcall_err(meths.exec_lua, 'aa=bb\0', {}))
- eq([[Error executing lua: [string "<nvim>"]:0: attempt to call global 'bork' (a nil value)]],
- pcall_err(meths.exec_lua, 'bork()', {}))
- eq('Error executing lua: [string "<nvim>"]:0: did\nthe\nfail',
- pcall_err(meths.exec_lua, 'error("did\\nthe\\nfail")', {}))
- end)
- it('uses native float values', function()
- eq(2.5, meths.exec_lua("return select(1, ...)", {2.5}))
- eq("2.5", meths.exec_lua("return vim.inspect(...)", {2.5}))
- -- "special" float values are still accepted as return values.
- eq(2.5, meths.exec_lua("return vim.api.nvim_eval('2.5')", {}))
- eq("{\n [false] = 2.5,\n [true] = 3\n}", meths.exec_lua("return vim.inspect(vim.api.nvim_eval('2.5'))", {}))
- end)
- end)
- describe('nvim_notify', function()
- it('can notify a info message', function()
- nvim("notify", "hello world", 2, {})
- end)
- it('can be overridden', function()
- command("lua vim.notify = function(...) return 42 end")
- eq(42, meths.exec_lua("return vim.notify('Hello world')", {}))
- nvim("notify", "hello world", 4, {})
- end)
- end)
- describe('nvim_input', function()
- it("VimL error: does NOT fail, updates v:errmsg", function()
- local status, _ = pcall(nvim, "input", ":call bogus_fn()<CR>")
- local v_errnum = string.match(nvim("eval", "v:errmsg"), "E%d*:")
- eq(true, status) -- nvim_input() did not fail.
- eq("E117:", v_errnum) -- v:errmsg was updated.
- end)
- it('does not crash even if trans_special result is largest #11788, #12287', function()
- command("call nvim_input('<M-'.nr2char(0x40000000).'>')")
- eq(1, eval('1'))
- end)
- end)
- describe('nvim_paste', function()
- it('validates args', function()
- eq('Invalid phase: -2',
- pcall_err(request, 'nvim_paste', 'foo', true, -2))
- eq('Invalid phase: 4',
- pcall_err(request, 'nvim_paste', 'foo', true, 4))
- end)
- local function run_streamed_paste_tests()
- it('stream: multiple chunks form one undo-block', function()
- nvim('paste', '1/chunk 1 (start)\n', true, 1)
- nvim('paste', '1/chunk 2 (end)\n', true, 3)
- local expected1 = [[
- 1/chunk 1 (start)
- 1/chunk 2 (end)
- ]]
- expect(expected1)
- nvim('paste', '2/chunk 1 (start)\n', true, 1)
- nvim('paste', '2/chunk 2\n', true, 2)
- expect([[
- 1/chunk 1 (start)
- 1/chunk 2 (end)
- 2/chunk 1 (start)
- 2/chunk 2
- ]])
- nvim('paste', '2/chunk 3\n', true, 2)
- nvim('paste', '2/chunk 4 (end)\n', true, 3)
- expect([[
- 1/chunk 1 (start)
- 1/chunk 2 (end)
- 2/chunk 1 (start)
- 2/chunk 2
- 2/chunk 3
- 2/chunk 4 (end)
- ]])
- feed('u') -- Undo.
- expect(expected1)
- end)
- it('stream: Insert mode', function()
- -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
- feed('afoo<Esc>u')
- feed('i')
- nvim('paste', 'aaaaaa', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('aaaaaabbbbbbccccccdddddd')
- feed('<Esc>u')
- expect('')
- end)
- describe('stream: Normal mode', function()
- describe('on empty line', function()
- before_each(function()
- -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
- feed('afoo<Esc>u')
- end)
- after_each(function()
- feed('u')
- expect('')
- end)
- it('pasting one line', function()
- nvim('paste', 'aaaaaa', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('aaaaaabbbbbbccccccdddddd')
- end)
- it('pasting multiple lines', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect([[
- aaaaaa
- bbbbbb
- cccccc
- dddddd]])
- end)
- end)
- describe('not at the end of a line', function()
- before_each(function()
- feed('i||<Esc>')
- -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
- feed('afoo<Esc>u')
- feed('0')
- end)
- after_each(function()
- feed('u')
- expect('||')
- end)
- it('pasting one line', function()
- nvim('paste', 'aaaaaa', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('|aaaaaabbbbbbccccccdddddd|')
- end)
- it('pasting multiple lines', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect([[
- |aaaaaa
- bbbbbb
- cccccc
- dddddd|]])
- end)
- end)
- describe('at the end of a line', function()
- before_each(function()
- feed('i||<Esc>')
- -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
- feed('afoo<Esc>u')
- feed('2|')
- end)
- after_each(function()
- feed('u')
- expect('||')
- end)
- it('pasting one line', function()
- nvim('paste', 'aaaaaa', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('||aaaaaabbbbbbccccccdddddd')
- end)
- it('pasting multiple lines', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect([[
- ||aaaaaa
- bbbbbb
- cccccc
- dddddd]])
- end)
- end)
- end)
- describe('stream: Visual mode', function()
- describe('neither end at the end of a line', function()
- before_each(function()
- feed('i|xxx<CR>xxx|<Esc>')
- -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
- feed('afoo<Esc>u')
- feed('3|vhk')
- end)
- after_each(function()
- feed('u')
- expect([[
- |xxx
- xxx|]])
- end)
- it('with non-empty chunks', function()
- nvim('paste', 'aaaaaa', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('|aaaaaabbbbbbccccccdddddd|')
- end)
- it('with empty first chunk', function()
- nvim('paste', '', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('|bbbbbbccccccdddddd|')
- end)
- it('with all chunks empty', function()
- nvim('paste', '', false, 1)
- nvim('paste', '', false, 2)
- nvim('paste', '', false, 2)
- nvim('paste', '', false, 3)
- expect('||')
- end)
- end)
- describe('cursor at the end of a line', function()
- before_each(function()
- feed('i||xxx<CR>xxx<Esc>')
- -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
- feed('afoo<Esc>u')
- feed('3|vko')
- end)
- after_each(function()
- feed('u')
- expect([[
- ||xxx
- xxx]])
- end)
- it('with non-empty chunks', function()
- nvim('paste', 'aaaaaa', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('||aaaaaabbbbbbccccccdddddd')
- end)
- it('with empty first chunk', function()
- nvim('paste', '', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('||bbbbbbccccccdddddd')
- end)
- end)
- describe('other end at the end of a line', function()
- before_each(function()
- feed('i||xxx<CR>xxx<Esc>')
- -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
- feed('afoo<Esc>u')
- feed('3|vk')
- end)
- after_each(function()
- feed('u')
- expect([[
- ||xxx
- xxx]])
- end)
- it('with non-empty chunks', function()
- nvim('paste', 'aaaaaa', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('||aaaaaabbbbbbccccccdddddd')
- end)
- it('with empty first chunk', function()
- nvim('paste', '', false, 1)
- nvim('paste', 'bbbbbb', false, 2)
- nvim('paste', 'cccccc', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect('||bbbbbbccccccdddddd')
- end)
- end)
- end)
- describe('stream: linewise Visual mode', function()
- before_each(function()
- feed('i123456789<CR>987654321<CR>123456789<Esc>')
- -- If nvim_paste() calls :undojoin without making any changes, this makes it an error.
- feed('afoo<Esc>u')
- end)
- after_each(function()
- feed('u')
- expect([[
- 123456789
- 987654321
- 123456789]])
- end)
- describe('selecting the start of a file', function()
- before_each(function()
- feed('ggV')
- end)
- it('pasting text without final new line', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect([[
- aaaaaa
- bbbbbb
- cccccc
- dddddd987654321
- 123456789]])
- end)
- it('pasting text with final new line', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd\n', false, 3)
- expect([[
- aaaaaa
- bbbbbb
- cccccc
- dddddd
- 987654321
- 123456789]])
- end)
- end)
- describe('selecting the middle of a file', function()
- before_each(function()
- feed('2ggV')
- end)
- it('pasting text without final new line', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect([[
- 123456789
- aaaaaa
- bbbbbb
- cccccc
- dddddd123456789]])
- end)
- it('pasting text with final new line', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd\n', false, 3)
- expect([[
- 123456789
- aaaaaa
- bbbbbb
- cccccc
- dddddd
- 123456789]])
- end)
- end)
- describe('selecting the end of a file', function()
- before_each(function()
- feed('3ggV')
- end)
- it('pasting text without final new line', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect([[
- 123456789
- 987654321
- aaaaaa
- bbbbbb
- cccccc
- dddddd]])
- end)
- it('pasting text with final new line', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd\n', false, 3)
- expect([[
- 123456789
- 987654321
- aaaaaa
- bbbbbb
- cccccc
- dddddd
- ]])
- end)
- end)
- describe('selecting the whole file', function()
- before_each(function()
- feed('ggVG')
- end)
- it('pasting text without final new line', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd', false, 3)
- expect([[
- aaaaaa
- bbbbbb
- cccccc
- dddddd]])
- end)
- it('pasting text with final new line', function()
- nvim('paste', 'aaaaaa\n', false, 1)
- nvim('paste', 'bbbbbb\n', false, 2)
- nvim('paste', 'cccccc\n', false, 2)
- nvim('paste', 'dddddd\n', false, 3)
- expect([[
- aaaaaa
- bbbbbb
- cccccc
- dddddd
- ]])
- end)
- end)
- end)
- end
- describe('without virtualedit,', function()
- run_streamed_paste_tests()
- end)
- describe('with virtualedit=onemore,', function()
- before_each(function()
- command('set virtualedit=onemore')
- end)
- run_streamed_paste_tests()
- end)
- it('non-streaming', function()
- -- With final "\n".
- nvim('paste', 'line 1\nline 2\nline 3\n', true, -1)
- expect([[
- line 1
- line 2
- line 3
- ]])
- eq({0,4,1,0}, funcs.getpos('.')) -- Cursor follows the paste.
- eq(false, nvim('get_option', 'paste'))
- command('%delete _')
- -- Without final "\n".
- nvim('paste', 'line 1\nline 2\nline 3', true, -1)
- expect([[
- line 1
- line 2
- line 3]])
- eq({0,3,6,0}, funcs.getpos('.'))
- command('%delete _')
- -- CRLF #10872
- nvim('paste', 'line 1\r\nline 2\r\nline 3\r\n', true, -1)
- expect([[
- line 1
- line 2
- line 3
- ]])
- eq({0,4,1,0}, funcs.getpos('.'))
- command('%delete _')
- -- CRLF without final "\n".
- nvim('paste', 'line 1\r\nline 2\r\nline 3\r', true, -1)
- expect([[
- line 1
- line 2
- line 3
- ]])
- eq({0,4,1,0}, funcs.getpos('.'))
- command('%delete _')
- -- CRLF without final "\r\n".
- nvim('paste', 'line 1\r\nline 2\r\nline 3', true, -1)
- expect([[
- line 1
- line 2
- line 3]])
- eq({0,3,6,0}, funcs.getpos('.'))
- command('%delete _')
- -- Various other junk.
- nvim('paste', 'line 1\r\n\r\rline 2\nline 3\rline 4\r', true, -1)
- expect('line 1\n\n\nline 2\nline 3\nline 4\n')
- eq({0,7,1,0}, funcs.getpos('.'))
- eq(false, nvim('get_option', 'paste'))
- end)
- it('Replace-mode', function()
- -- Within single line
- nvim('put', {'aabbccdd', 'eeffgghh', 'iijjkkll'}, "c", true, false)
- command('normal l')
- command('startreplace')
- nvim('paste', '123456', true, -1)
- expect([[
- a123456d
- eeffgghh
- iijjkkll]])
- command('%delete _')
- -- Across lines
- nvim('put', {'aabbccdd', 'eeffgghh', 'iijjkkll'}, "c", true, false)
- command('normal l')
- command('startreplace')
- nvim('paste', '123\n456', true, -1)
- expect([[
- a123
- 456d
- eeffgghh
- iijjkkll]])
- end)
- it('when searching in Visual mode', function()
- feed('v/')
- nvim('paste', 'aabbccdd', true, -1)
- eq('aabbccdd', funcs.getcmdline())
- expect('')
- end)
- it('mappings are disabled in Cmdline mode', function()
- command('cnoremap a b')
- feed(':')
- nvim('paste', 'a', true, -1)
- eq('a', funcs.getcmdline())
- end)
- it('pasted text is saved in cmdline history when <CR> comes from mapping #20957', function()
- command('cnoremap <CR> <CR>')
- feed(':')
- nvim('paste', 'echo', true, -1)
- eq('', funcs.histget(':'))
- feed('<CR>')
- eq('echo', funcs.histget(':'))
- end)
- it('pasting with empty last chunk in Cmdline mode', function()
- local screen = Screen.new(20, 4)
- screen:attach()
- feed(':')
- nvim('paste', 'Foo', true, 1)
- nvim('paste', '', true, 3)
- screen:expect([[
- |
- ~ |
- ~ |
- :Foo^ |
- ]])
- end)
- it('pasting text with control characters in Cmdline mode', function()
- local screen = Screen.new(20, 4)
- screen:attach()
- feed(':')
- nvim('paste', 'normal! \023\022\006\027', true, -1)
- screen:expect([[
- |
- ~ |
- ~ |
- :normal! ^W^V^F^[^ |
- ]])
- end)
- it('crlf=false does not break lines at CR, CRLF', function()
- nvim('paste', 'line 1\r\n\r\rline 2\nline 3\rline 4\r', false, -1)
- expect('line 1\r\n\r\rline 2\nline 3\rline 4\r')
- eq({0,3,14,0}, funcs.getpos('.'))
- end)
- it('vim.paste() failure', function()
- nvim('exec_lua', 'vim.paste = (function(lines, phase) error("fake fail") end)', {})
- eq([[Error executing lua: [string "<nvim>"]:0: fake fail]],
- pcall_err(request, 'nvim_paste', 'line 1\nline 2\nline 3', false, 1))
- end)
- end)
- describe('nvim_put', function()
- it('validates args', function()
- eq('Invalid lines (expected array of strings)',
- pcall_err(request, 'nvim_put', {42}, 'l', false, false))
- eq("Invalid type: 'x'",
- pcall_err(request, 'nvim_put', {'foo'}, 'x', false, false))
- end)
- it("fails if 'nomodifiable'", function()
- command('set nomodifiable')
- eq([[Vim:E21: Cannot make changes, 'modifiable' is off]],
- pcall_err(request, 'nvim_put', {'a','b'}, 'l', true, true))
- end)
- it('inserts text', function()
- -- linewise
- nvim('put', {'line 1','line 2','line 3'}, 'l', true, true)
- expect([[
- line 1
- line 2
- line 3]])
- eq({0,4,1,0}, funcs.getpos('.'))
- command('%delete _')
- -- charwise
- nvim('put', {'line 1','line 2','line 3'}, 'c', true, false)
- expect([[
- line 1
- line 2
- line 3]])
- eq({0,1,1,0}, funcs.getpos('.')) -- follow=false
- -- blockwise
- nvim('put', {'AA','BB'}, 'b', true, true)
- expect([[
- lAAine 1
- lBBine 2
- line 3]])
- eq({0,2,4,0}, funcs.getpos('.'))
- command('%delete _')
- -- Empty lines list.
- nvim('put', {}, 'c', true, true)
- eq({0,1,1,0}, funcs.getpos('.'))
- expect([[]])
- -- Single empty line.
- nvim('put', {''}, 'c', true, true)
- eq({0,1,1,0}, funcs.getpos('.'))
- expect([[
- ]])
- nvim('put', {'AB'}, 'c', true, true)
- -- after=false, follow=true
- nvim('put', {'line 1','line 2'}, 'c', false, true)
- expect([[
- Aline 1
- line 2B]])
- eq({0,2,7,0}, funcs.getpos('.'))
- command('%delete _')
- nvim('put', {'AB'}, 'c', true, true)
- -- after=false, follow=false
- nvim('put', {'line 1','line 2'}, 'c', false, false)
- expect([[
- Aline 1
- line 2B]])
- eq({0,1,2,0}, funcs.getpos('.'))
- eq('', nvim('eval', 'v:errmsg'))
- end)
- it('detects charwise/linewise text (empty {type})', function()
- -- linewise (final item is empty string)
- nvim('put', {'line 1','line 2','line 3',''}, '', true, true)
- expect([[
- line 1
- line 2
- line 3]])
- eq({0,4,1,0}, funcs.getpos('.'))
- command('%delete _')
- -- charwise (final item is non-empty)
- nvim('put', {'line 1','line 2','line 3'}, '', true, true)
- expect([[
- line 1
- line 2
- line 3]])
- eq({0,3,6,0}, funcs.getpos('.'))
- end)
- it('allows block width', function()
- -- behave consistently with setreg(); support "\022{NUM}" return by getregtype()
- meths.put({'line 1','line 2','line 3'}, 'l', false, false)
- expect([[
- line 1
- line 2
- line 3
- ]])
- -- larger width create spaces
- meths.put({'a', 'bc'}, 'b3', false, false)
- expect([[
- a line 1
- bc line 2
- line 3
- ]])
- -- smaller width is ignored
- meths.put({'xxx', 'yyy'}, '\0221', false, true)
- expect([[
- xxxa line 1
- yyybc line 2
- line 3
- ]])
- eq("Invalid type: 'bx'",
- pcall_err(meths.put, {'xxx', 'yyy'}, 'bx', false, true))
- eq("Invalid type: 'b3x'",
- pcall_err(meths.put, {'xxx', 'yyy'}, 'b3x', false, true))
- end)
- end)
- describe('nvim_strwidth', function()
- it('works', function()
- eq(3, nvim('strwidth', 'abc'))
- -- 6 + (neovim)
- -- 19 * 2 (each japanese character occupies two cells)
- eq(44, nvim('strwidth', 'neovimのデザインかなりまともなのになってる。'))
- end)
- it('cannot handle NULs', function()
- eq(0, nvim('strwidth', '\0abc'))
- end)
- end)
- describe('nvim_get_current_line, nvim_set_current_line', function()
- it('works', function()
- eq('', nvim('get_current_line'))
- nvim('set_current_line', 'abc')
- eq('abc', nvim('get_current_line'))
- end)
- end)
- describe('set/get/del variables', function()
- it('nvim_get_var, nvim_set_var, nvim_del_var', function()
- nvim('set_var', 'lua', {1, 2, {['3'] = 1}})
- eq({1, 2, {['3'] = 1}}, nvim('get_var', 'lua'))
- eq({1, 2, {['3'] = 1}}, nvim('eval', 'g:lua'))
- eq(1, funcs.exists('g:lua'))
- meths.del_var('lua')
- eq(0, funcs.exists('g:lua'))
- eq("Key not found: lua", pcall_err(meths.del_var, 'lua'))
- meths.set_var('lua', 1)
- -- Set locked g: var.
- command('lockvar lua')
- eq('Key is locked: lua', pcall_err(meths.del_var, 'lua'))
- eq('Key is locked: lua', pcall_err(meths.set_var, 'lua', 1))
- exec([[
- function Test()
- endfunction
- function s:Test()
- endfunction
- let g:Unknown_func = function('Test')
- let g:Unknown_script_func = function('s:Test')
- ]])
- eq(NIL, meths.get_var('Unknown_func'))
- eq(NIL, meths.get_var('Unknown_script_func'))
- -- Check if autoload works properly
- local pathsep = helpers.get_pathsep()
- local xconfig = 'Xhome' .. pathsep .. 'Xconfig'
- local xdata = 'Xhome' .. pathsep .. 'Xdata'
- local autoload_folder = table.concat({xconfig, 'nvim', 'autoload'}, pathsep)
- local autoload_file = table.concat({autoload_folder , 'testload.vim'}, pathsep)
- mkdir_p(autoload_folder)
- write_file(autoload_file , [[let testload#value = 2]])
- clear{ args_rm={'-u'}, env={ XDG_CONFIG_HOME=xconfig, XDG_DATA_HOME=xdata } }
- eq(2, meths.get_var('testload#value'))
- rmdir('Xhome')
- end)
- it('nvim_get_vvar, nvim_set_vvar', function()
- -- Set readonly v: var.
- eq('Key is read-only: count',
- pcall_err(request, 'nvim_set_vvar', 'count', 42))
- -- Set writable v: var.
- meths.set_vvar('errmsg', 'set by API')
- eq('set by API', meths.get_vvar('errmsg'))
- end)
- it('vim_set_var returns the old value', function()
- local val1 = {1, 2, {['3'] = 1}}
- local val2 = {4, 7}
- eq(NIL, request('vim_set_var', 'lua', val1))
- eq(val1, request('vim_set_var', 'lua', val2))
- end)
- it('vim_del_var returns the old value', function()
- local val1 = {1, 2, {['3'] = 1}}
- local val2 = {4, 7}
- eq(NIL, request('vim_set_var', 'lua', val1))
- eq(val1, request('vim_set_var', 'lua', val2))
- eq(val2, request('vim_del_var', 'lua'))
- end)
- it('truncates values with NULs in them', function()
- nvim('set_var', 'xxx', 'ab\0cd')
- eq('ab', nvim('get_var', 'xxx'))
- end)
- end)
- describe('nvim_get_option, nvim_set_option', function()
- it('works', function()
- ok(nvim('get_option', 'equalalways'))
- nvim('set_option', 'equalalways', false)
- ok(not nvim('get_option', 'equalalways'))
- end)
- it('works to get global value of local options', function()
- eq(false, nvim('get_option', 'lisp'))
- eq(8, nvim('get_option', 'shiftwidth'))
- end)
- it('works to set global value of local options', function()
- nvim('set_option', 'lisp', true)
- eq(true, nvim('get_option', 'lisp'))
- eq(false, helpers.curbuf('get_option', 'lisp'))
- eq(nil, nvim('command_output', 'setglobal lisp?'):match('nolisp'))
- eq('nolisp', nvim('command_output', 'setlocal lisp?'):match('nolisp'))
- nvim('set_option', 'shiftwidth', 20)
- eq('20', nvim('command_output', 'setglobal shiftwidth?'):match('%d+'))
- eq('8', nvim('command_output', 'setlocal shiftwidth?'):match('%d+'))
- end)
- it('most window-local options have no global value', function()
- local status, err = pcall(nvim, 'get_option', 'foldcolumn')
- eq(false, status)
- ok(err:match('Invalid option name') ~= nil)
- end)
- it('updates where the option was last set from', function()
- nvim('set_option', 'equalalways', false)
- local status, rv = pcall(nvim, 'command_output',
- 'verbose set equalalways?')
- eq(true, status)
- ok(nil ~= string.find(rv, 'noequalalways\n'..
- '\tLast set from API client %(channel id %d+%)'))
- nvim('exec_lua', 'vim.api.nvim_set_option("equalalways", true)', {})
- status, rv = pcall(nvim, 'command_output',
- 'verbose set equalalways?')
- eq(true, status)
- eq(' equalalways\n\tLast set from Lua', rv)
- end)
- end)
- describe('nvim_get_option_value, nvim_set_option_value', function()
- it('works', function()
- ok(nvim('get_option_value', 'equalalways', {}))
- nvim('set_option_value', 'equalalways', false, {})
- ok(not nvim('get_option_value', 'equalalways', {}))
- end)
- it('can get local values when global value is set', function()
- eq(0, nvim('get_option_value', 'scrolloff', {}))
- eq(-1, nvim('get_option_value', 'scrolloff', {scope = 'local'}))
- end)
- it('can set global and local values', function()
- nvim('set_option_value', 'makeprg', 'hello', {})
- eq('hello', nvim('get_option_value', 'makeprg', {}))
- eq('', nvim('get_option_value', 'makeprg', {scope = 'local'}))
- nvim('set_option_value', 'makeprg', 'world', {scope = 'local'})
- eq('world', nvim('get_option_value', 'makeprg', {scope = 'local'}))
- nvim('set_option_value', 'makeprg', 'goodbye', {scope = 'global'})
- eq('goodbye', nvim('get_option_value', 'makeprg', {scope = 'global'}))
- nvim('set_option_value', 'makeprg', 'hello', {})
- eq('hello', nvim('get_option_value', 'makeprg', {scope = 'global'}))
- eq('hello', nvim('get_option_value', 'makeprg', {}))
- eq('', nvim('get_option_value', 'makeprg', {scope = 'local'}))
- end)
- it('clears the local value of an option with nil', function()
- -- Set global value
- nvim('set_option_value', 'shiftwidth', 42, {})
- eq(42, nvim('get_option_value', 'shiftwidth', {}))
- -- Set local value
- nvim('set_option_value', 'shiftwidth', 8, {scope = 'local'})
- eq(8, nvim('get_option_value', 'shiftwidth', {}))
- eq(8, nvim('get_option_value', 'shiftwidth', {scope = 'local'}))
- eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'global'}))
- -- Clear value without scope
- nvim('set_option_value', 'shiftwidth', NIL, {})
- eq(42, nvim('get_option_value', 'shiftwidth', {}))
- eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'local'}))
- -- Clear value with explicit scope
- nvim('set_option_value', 'shiftwidth', 8, {scope = 'local'})
- nvim('set_option_value', 'shiftwidth', NIL, {scope = 'local'})
- eq(42, nvim('get_option_value', 'shiftwidth', {}))
- eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'local'}))
- -- Now try with options with a special "local is unset" value (e.g. 'undolevels')
- nvim('set_option_value', 'undolevels', 1000, {})
- eq(1000, nvim('get_option_value', 'undolevels', {scope = 'local'}))
- nvim('set_option_value', 'undolevels', NIL, {scope = 'local'})
- eq(-123456, nvim('get_option_value', 'undolevels', {scope = 'local'}))
- nvim('set_option_value', 'autoread', true, {})
- eq(true, nvim('get_option_value', 'autoread', {scope = 'local'}))
- nvim('set_option_value', 'autoread', NIL, {scope = 'local'})
- eq(NIL, nvim('get_option_value', 'autoread', {scope = 'local'}))
- end)
- it('set window options', function()
- -- Same as to nvim_win_set_option
- nvim('set_option_value', 'colorcolumn', '4,3', {win=0})
- eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'}))
- command("set modified hidden")
- command("enew") -- edit new buffer, window option is preserved
- eq('4,3', nvim('get_option_value', 'colorcolumn', {scope = 'local'}))
- end)
- it('set local window options', function()
- -- Different to nvim_win_set_option
- nvim('set_option_value', 'colorcolumn', '4,3', {win=0, scope='local'})
- eq('4,3', nvim('get_option_value', 'colorcolumn', {win = 0, scope = 'local'}))
- command("set modified hidden")
- command("enew") -- edit new buffer, window option is reset
- eq('', nvim('get_option_value', 'colorcolumn', {win = 0, scope = 'local'}))
- end)
- it('get buffer or window-local options', function()
- nvim('command', 'new')
- local buf = nvim('get_current_buf').id
- nvim('buf_set_option', buf, 'tagfunc', 'foobar')
- eq('foobar', nvim('get_option_value', 'tagfunc', {buf = buf}))
- local win = nvim('get_current_win').id
- nvim('win_set_option', win, 'number', true)
- eq(true, nvim('get_option_value', 'number', {win = win}))
- end)
- it('getting current buffer option does not adjust cursor #19381', function()
- nvim('command', 'new')
- local buf = nvim('get_current_buf').id
- local win = nvim('get_current_win').id
- insert('some text')
- feed('0v$')
- eq({1, 9}, nvim('win_get_cursor', win))
- nvim('get_option_value', 'filetype', {buf = buf})
- eq({1, 9}, nvim('win_get_cursor', win))
- end)
- end)
- describe('nvim_{get,set}_current_buf, nvim_list_bufs', function()
- it('works', function()
- eq(1, #nvim('list_bufs'))
- eq(nvim('list_bufs')[1], nvim('get_current_buf'))
- nvim('command', 'new')
- eq(2, #nvim('list_bufs'))
- eq(nvim('list_bufs')[2], nvim('get_current_buf'))
- nvim('set_current_buf', nvim('list_bufs')[1])
- eq(nvim('list_bufs')[1], nvim('get_current_buf'))
- end)
- end)
- describe('nvim_{get,set}_current_win, nvim_list_wins', function()
- it('works', function()
- eq(1, #nvim('list_wins'))
- eq(nvim('list_wins')[1], nvim('get_current_win'))
- nvim('command', 'vsplit')
- nvim('command', 'split')
- eq(3, #nvim('list_wins'))
- eq(nvim('list_wins')[1], nvim('get_current_win'))
- nvim('set_current_win', nvim('list_wins')[2])
- eq(nvim('list_wins')[2], nvim('get_current_win'))
- end)
- end)
- describe('nvim_{get,set}_current_tabpage, nvim_list_tabpages', function()
- it('works', function()
- eq(1, #nvim('list_tabpages'))
- eq(nvim('list_tabpages')[1], nvim('get_current_tabpage'))
- nvim('command', 'tabnew')
- eq(2, #nvim('list_tabpages'))
- eq(2, #nvim('list_wins'))
- eq(nvim('list_wins')[2], nvim('get_current_win'))
- eq(nvim('list_tabpages')[2], nvim('get_current_tabpage'))
- nvim('set_current_win', nvim('list_wins')[1])
- -- Switching window also switches tabpages if necessary
- eq(nvim('list_tabpages')[1], nvim('get_current_tabpage'))
- eq(nvim('list_wins')[1], nvim('get_current_win'))
- nvim('set_current_tabpage', nvim('list_tabpages')[2])
- eq(nvim('list_tabpages')[2], nvim('get_current_tabpage'))
- eq(nvim('list_wins')[2], nvim('get_current_win'))
- end)
- end)
- describe('nvim_get_mode', function()
- it("during normal-mode `g` returns blocking=true", function()
- nvim("input", "o") -- add a line
- eq({mode='i', blocking=false}, nvim("get_mode"))
- nvim("input", [[<C-\><C-N>]])
- eq(2, nvim("eval", "line('.')"))
- eq({mode='n', blocking=false}, nvim("get_mode"))
- nvim("input", "g")
- eq({mode='n', blocking=true}, nvim("get_mode"))
- nvim("input", "k") -- complete the operator
- eq(1, nvim("eval", "line('.')")) -- verify the completed operator
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end)
- it("returns the correct result multiple consecutive times", function()
- for _ = 1,5 do
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end
- nvim("input", "g")
- for _ = 1,4 do
- eq({mode='n', blocking=true}, nvim("get_mode"))
- end
- nvim("input", "g")
- for _ = 1,7 do
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end
- end)
- it("during normal-mode CTRL-W, returns blocking=true", function()
- nvim("input", "<C-W>")
- eq({mode='n', blocking=true}, nvim("get_mode"))
- nvim("input", "s") -- complete the operator
- eq(2, nvim("eval", "winnr('$')")) -- verify the completed operator
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end)
- it("during press-enter prompt without UI returns blocking=false", function()
- eq({mode='n', blocking=false}, nvim("get_mode"))
- command("echom 'msg1'")
- command("echom 'msg2'")
- command("echom 'msg3'")
- command("echom 'msg4'")
- command("echom 'msg5'")
- eq({mode='n', blocking=false}, nvim("get_mode"))
- nvim("input", ":messages<CR>")
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end)
- it("during press-enter prompt returns blocking=true", function()
- nvim("ui_attach", 80, 20, {})
- eq({mode='n', blocking=false}, nvim("get_mode"))
- command("echom 'msg1'")
- command("echom 'msg2'")
- command("echom 'msg3'")
- command("echom 'msg4'")
- command("echom 'msg5'")
- eq({mode='n', blocking=false}, nvim("get_mode"))
- nvim("input", ":messages<CR>")
- eq({mode='r', blocking=true}, nvim("get_mode"))
- end)
- it("during getchar() returns blocking=false", function()
- nvim("input", ":let g:test_input = nr2char(getchar())<CR>")
- -- Events are enabled during getchar(), RPC calls are *not* blocked. #5384
- eq({mode='n', blocking=false}, nvim("get_mode"))
- eq(0, nvim("eval", "exists('g:test_input')"))
- nvim("input", "J")
- eq("J", nvim("eval", "g:test_input"))
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end)
- -- TODO: bug #6247#issuecomment-286403810
- it("batched with input", function()
- nvim("ui_attach", 80, 20, {})
- eq({mode='n', blocking=false}, nvim("get_mode"))
- command("echom 'msg1'")
- command("echom 'msg2'")
- command("echom 'msg3'")
- command("echom 'msg4'")
- command("echom 'msg5'")
- local req = {
- {'nvim_get_mode', {}},
- {'nvim_input', {':messages<CR>'}},
- {'nvim_get_mode', {}},
- {'nvim_eval', {'1'}},
- }
- eq({ { {mode='n', blocking=false},
- 13,
- {mode='n', blocking=false}, -- TODO: should be blocked=true ?
- 1 },
- NIL}, meths.call_atomic(req))
- eq({mode='r', blocking=true}, nvim("get_mode"))
- end)
- it("during insert-mode map-pending, returns blocking=true #6166", function()
- command("inoremap xx foo")
- nvim("input", "ix")
- eq({mode='i', blocking=true}, nvim("get_mode"))
- end)
- it("during normal-mode gU, returns blocking=false #6166", function()
- nvim("input", "gu")
- eq({mode='no', blocking=false}, nvim("get_mode"))
- end)
- it("at '-- More --' prompt returns blocking=true #11899", function()
- command('set more')
- feed(':digraphs<cr>')
- eq({mode='rm', blocking=true}, nvim("get_mode"))
- end)
- it('after <Nop> mapping returns blocking=false #17257', function()
- command('nnoremap <F2> <Nop>')
- feed('<F2>')
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end)
- it('after empty string <expr> mapping returns blocking=false #17257', function()
- command('nnoremap <expr> <F2> ""')
- feed('<F2>')
- eq({mode='n', blocking=false}, nvim("get_mode"))
- end)
- end)
- describe('RPC (K_EVENT)', function()
- it('does not complete ("interrupt") normal-mode operator-pending #6166', function()
- helpers.insert([[
- FIRST LINE
- SECOND LINE]])
- nvim('input', 'gg')
- nvim('input', 'gu')
- -- Make any RPC request (can be non-async: op-pending does not block).
- nvim('get_current_buf')
- -- Buffer should not change.
- expect([[
- FIRST LINE
- SECOND LINE]])
- -- Now send input to complete the operator.
- nvim('input', 'j')
- expect([[
- first line
- second line]])
- end)
- it('does not complete ("interrupt") `d` #3732', function()
- local screen = Screen.new(20, 4)
- screen:attach()
- command('set listchars=eol:$')
- command('set list')
- feed('ia<cr>b<cr>c<cr><Esc>kkk')
- feed('d')
- -- Make any RPC request (can be non-async: op-pending does not block).
- nvim('get_current_buf')
- screen:expect([[
- ^a$ |
- b$ |
- c$ |
- |
- ]])
- end)
- it('does not complete ("interrupt") normal-mode map-pending #6166', function()
- command("nnoremap dd :let g:foo='it worked...'<CR>")
- helpers.insert([[
- FIRST LINE
- SECOND LINE]])
- nvim('input', 'gg')
- nvim('input', 'd')
- -- Make any RPC request (must be async, because map-pending blocks).
- nvim('get_api_info')
- -- Send input to complete the mapping.
- nvim('input', 'd')
- expect([[
- FIRST LINE
- SECOND LINE]])
- eq('it worked...', helpers.eval('g:foo'))
- end)
- it('does not complete ("interrupt") insert-mode map-pending #6166', function()
- command('inoremap xx foo')
- command('set timeoutlen=9999')
- helpers.insert([[
- FIRST LINE
- SECOND LINE]])
- nvim('input', 'ix')
- -- Make any RPC request (must be async, because map-pending blocks).
- nvim('get_api_info')
- -- Send input to complete the mapping.
- nvim('input', 'x')
- expect([[
- FIRST LINE
- SECOND LINfooE]])
- end)
- it('does not interrupt Insert mode i_CTRL-O #10035', function()
- feed('iHello World<c-o>')
- eq({mode='niI', blocking=false}, meths.get_mode()) -- fast event
- eq(2, eval('1+1')) -- causes K_EVENT key
- eq({mode='niI', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
- feed('dd')
- eq({mode='i', blocking=false}, meths.get_mode()) -- left ctrl-o mode
- expect('') -- executed the command
- end)
- it('does not interrupt Select mode v_CTRL-O #15688', function()
- feed('iHello World<esc>gh<c-o>')
- eq({mode='vs', blocking=false}, meths.get_mode()) -- fast event
- eq({mode='vs', blocking=false}, meths.get_mode()) -- again #15288
- eq(2, eval('1+1')) -- causes K_EVENT key
- eq({mode='vs', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
- feed('^')
- eq({mode='s', blocking=false}, meths.get_mode()) -- left ctrl-o mode
- feed('h')
- eq({mode='i', blocking=false}, meths.get_mode()) -- entered insert mode
- expect('h') -- selection is the whole line and is replaced
- end)
- it('does not interrupt Insert mode i_0_CTRL-D #13997', function()
- command('set timeoutlen=9999')
- feed('i<Tab><Tab>a0')
- eq(2, eval('1+1')) -- causes K_EVENT key
- feed('<C-D>')
- expect('a') -- recognized i_0_CTRL-D
- end)
- end)
- describe('nvim_get_context', function()
- it('validates args', function()
- eq("Invalid key: 'blah'",
- pcall_err(nvim, 'get_context', {blah={}}))
- eq('invalid value for key: types',
- pcall_err(nvim, 'get_context', {types=42}))
- eq('unexpected type: zub',
- pcall_err(nvim, 'get_context', {types={'jumps', 'zub', 'zam',}}))
- end)
- it('returns map of current editor state', function()
- local opts = {types={'regs', 'jumps', 'bufs', 'gvars'}}
- eq({}, parse_context(nvim('get_context', {})))
- feed('i1<cr>2<cr>3<c-[>ddddddqahjklquuu')
- feed('gg')
- feed('G')
- command('edit! BUF1')
- command('edit BUF2')
- nvim('set_var', 'one', 1)
- nvim('set_var', 'Two', 2)
- nvim('set_var', 'THREE', 3)
- local expected_ctx = {
- ['regs'] = {
- {['rt'] = 1, ['rc'] = {'1'}, ['n'] = 49, ['ru'] = true},
- {['rt'] = 1, ['rc'] = {'2'}, ['n'] = 50},
- {['rt'] = 1, ['rc'] = {'3'}, ['n'] = 51},
- {['rc'] = {'hjkl'}, ['n'] = 97},
- },
- ['jumps'] = eval(([[
- filter(map(add(
- getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }),
- 'filter(
- { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
- { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
- ]]):gsub('\n', '')),
- ['bufs'] = eval([[
- filter(map(getbufinfo(), '{ "f": v:val.name }'), '!empty(v:val.f)')
- ]]),
- ['gvars'] = {{'one', 1}, {'Two', 2}, {'THREE', 3}},
- }
- eq(expected_ctx, parse_context(nvim('get_context', opts)))
- eq(expected_ctx, parse_context(nvim('get_context', {})))
- eq(expected_ctx, parse_context(nvim('get_context', {types={}})))
- end)
- end)
- describe('nvim_load_context', function()
- it('sets current editor state to given context dictionary', function()
- local opts = {types={'regs', 'jumps', 'bufs', 'gvars'}}
- eq({}, parse_context(nvim('get_context', opts)))
- nvim('set_var', 'one', 1)
- nvim('set_var', 'Two', 2)
- nvim('set_var', 'THREE', 3)
- local ctx = nvim('get_context', opts)
- nvim('set_var', 'one', 'a')
- nvim('set_var', 'Two', 'b')
- nvim('set_var', 'THREE', 'c')
- eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
- nvim('load_context', ctx)
- eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
- end)
- end)
- describe('nvim_replace_termcodes', function()
- it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function()
- eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true))
- end)
- it('leaves non-K_SPECIAL string unchanged', function()
- eq('abc', helpers.nvim('replace_termcodes', 'abc', true, true, true))
- end)
- it('converts <expressions>', function()
- eq('\\', helpers.nvim('replace_termcodes', '<Leader>', true, true, true))
- end)
- it('converts <LeftMouse> to K_SPECIAL KS_EXTRA KE_LEFTMOUSE', function()
- -- K_SPECIAL KS_EXTRA KE_LEFTMOUSE
- -- 0x80 0xfd 0x2c
- -- 128 253 44
- eq('\128\253\44', helpers.nvim('replace_termcodes',
- '<LeftMouse>', true, true, true))
- end)
- it('converts keycodes', function()
- eq('\nx\27x\rx<x', helpers.nvim('replace_termcodes',
- '<NL>x<Esc>x<CR>x<lt>x', true, true, true))
- end)
- it('does not convert keycodes if special=false', function()
- eq('<NL>x<Esc>x<CR>x<lt>x', helpers.nvim('replace_termcodes',
- '<NL>x<Esc>x<CR>x<lt>x', true, true, false))
- end)
- it('does not crash when transforming an empty string', function()
- -- Actually does not test anything, because current code will use NULL for
- -- an empty string.
- --
- -- Problem here is that if String argument has .data in allocated memory
- -- then `return str` in vim_replace_termcodes body will make Neovim free
- -- `str.data` twice: once when freeing arguments, then when freeing return
- -- value.
- eq('', meths.replace_termcodes('', true, true, true))
- end)
- end)
- describe('nvim_feedkeys', function()
- it('K_SPECIAL escaping', function()
- local function on_setup()
- -- notice the special char(…) \xe2\80\xa6
- nvim('feedkeys', ':let x1="…"\n', '', true)
- -- Both nvim_replace_termcodes and nvim_feedkeys escape \x80
- local inp = helpers.nvim('replace_termcodes', ':let x2="…"<CR>', true, true, true)
- nvim('feedkeys', inp, '', true) -- escape_ks=true
- -- nvim_feedkeys with K_SPECIAL escaping disabled
- inp = helpers.nvim('replace_termcodes', ':let x3="…"<CR>', true, true, true)
- nvim('feedkeys', inp, '', false) -- escape_ks=false
- helpers.stop()
- end
- -- spin the loop a bit
- helpers.run(nil, nil, on_setup)
- eq('…', nvim('get_var', 'x1'))
- -- Because of the double escaping this is neq
- neq('…', nvim('get_var', 'x2'))
- eq('…', nvim('get_var', 'x3'))
- end)
- end)
- describe('nvim_err_write', function()
- local screen
- before_each(function()
- clear()
- screen = Screen.new(40, 8)
- screen:attach()
- screen:set_default_attr_ids({
- [0] = {bold=true, foreground=Screen.colors.Blue},
- [1] = {foreground = Screen.colors.White, background = Screen.colors.Red},
- [2] = {bold = true, foreground = Screen.colors.SeaGreen},
- [3] = {bold = true, reverse = true},
- })
- end)
- it('can show one line', function()
- nvim_async('err_write', 'has bork\n')
- screen:expect([[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {1:has bork} |
- ]])
- end)
- it('shows return prompt when more than &cmdheight lines', function()
- nvim_async('err_write', 'something happened\nvery bad\n')
- screen:expect([[
- |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {3: }|
- {1:something happened} |
- {1:very bad} |
- {2:Press ENTER or type command to continue}^ |
- ]])
- end)
- it('shows return prompt after all lines are shown', function()
- nvim_async('err_write', 'FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n')
- screen:expect([[
- |
- {0:~ }|
- {3: }|
- {1:FAILURE} |
- {1:ERROR} |
- {1:EXCEPTION} |
- {1:TRACEBACK} |
- {2:Press ENTER or type command to continue}^ |
- ]])
- end)
- it('handles multiple calls', function()
- -- without linebreak text is joined to one line
- nvim_async('err_write', 'very ')
- nvim_async('err_write', 'fail\n')
- screen:expect([[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {1:very fail} |
- ]])
- helpers.poke_eventloop()
- -- shows up to &cmdheight lines
- nvim_async('err_write', 'more fail\ntoo fail\n')
- screen:expect([[
- |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {3: }|
- {1:more fail} |
- {1:too fail} |
- {2:Press ENTER or type command to continue}^ |
- ]])
- feed('<cr>') -- exit the press ENTER screen
- end)
- end)
- describe('nvim_list_chans, nvim_get_chan_info', function()
- before_each(function()
- command('autocmd ChanOpen * let g:opened_event = deepcopy(v:event)')
- command('autocmd ChanInfo * let g:info_event = deepcopy(v:event)')
- end)
- local testinfo = {
- stream = 'stdio',
- id = 1,
- mode = 'rpc',
- client = {},
- }
- local stderr = {
- stream = 'stderr',
- id = 2,
- mode = 'bytes',
- }
- it('returns {} for invalid channel', function()
- eq({}, meths.get_chan_info(0))
- eq({}, meths.get_chan_info(-1))
- -- more preallocated numbers might be added, try something high
- eq({}, meths.get_chan_info(10))
- end)
- it('stream=stdio channel', function()
- eq({[1]=testinfo,[2]=stderr}, meths.list_chans())
- eq(testinfo, meths.get_chan_info(1))
- eq(stderr, meths.get_chan_info(2))
- meths.set_client_info("functionaltests",
- {major=0, minor=3, patch=17},
- 'ui',
- {do_stuff={n_args={2,3}}},
- {license= 'Apache2'})
- local info = {
- stream = 'stdio',
- id = 1,
- mode = 'rpc',
- client = {
- name='functionaltests',
- version={major=0, minor=3, patch=17},
- type='ui',
- methods={do_stuff={n_args={2,3}}},
- attributes={license='Apache2'},
- },
- }
- eq({info=info}, meths.get_var("info_event"))
- eq({[1]=info, [2]=stderr}, meths.list_chans())
- eq(info, meths.get_chan_info(1))
- end)
- it('stream=job channel', function()
- eq(3, eval("jobstart(['cat'], {'rpc': v:true})"))
- local catpath = eval('exepath("cat")')
- local info = {
- stream='job',
- id=3,
- argv={ catpath },
- mode='rpc',
- client={},
- }
- eq({info=info}, meths.get_var("opened_event"))
- eq({[1]=testinfo,[2]=stderr,[3]=info}, meths.list_chans())
- eq(info, meths.get_chan_info(3))
- eval('rpcrequest(3, "nvim_set_client_info", "amazing-cat", {}, "remote",'..
- '{"nvim_command":{"n_args":1}},'.. -- and so on
- '{"description":"The Amazing Cat"})')
- info = {
- stream='job',
- id=3,
- argv={ catpath },
- mode='rpc',
- client = {
- name='amazing-cat',
- version={major=0},
- type='remote',
- methods={nvim_command={n_args=1}},
- attributes={description="The Amazing Cat"},
- },
- }
- eq({info=info}, meths.get_var("info_event"))
- eq({[1]=testinfo,[2]=stderr,[3]=info}, meths.list_chans())
- eq("Vim:Error invoking 'nvim_set_current_buf' on channel 3 (amazing-cat):\nWrong type for argument 1 when calling nvim_set_current_buf, expecting Buffer",
- pcall_err(eval, 'rpcrequest(3, "nvim_set_current_buf", -1)'))
- end)
- it('stream=job :terminal channel', function()
- command(':terminal')
- eq({id=1}, meths.get_current_buf())
- eq(3, meths.buf_get_option(1, 'channel'))
- local info = {
- stream='job',
- id=3,
- argv={ eval('exepath(&shell)') },
- mode='terminal',
- buffer = 1,
- pty='?',
- }
- local event = meths.get_var("opened_event")
- if not iswin() then
- info.pty = event.info.pty
- neq(nil, string.match(info.pty, "^/dev/"))
- end
- eq({info=info}, event)
- info.buffer = {id=1}
- eq({[1]=testinfo,[2]=stderr,[3]=info}, meths.list_chans())
- eq(info, meths.get_chan_info(3))
- -- :terminal with args + running process.
- command(':exe "terminal" shellescape(v:progpath) "-u NONE -i NONE"')
- eq(-1, eval('jobwait([&channel], 0)[0]')) -- Running?
- local expected2 = {
- stream = 'job',
- id = 4,
- argv = (
- iswin() and {
- eval('&shell'),
- '/s',
- '/c',
- fmt('"%s -u NONE -i NONE"', eval('shellescape(v:progpath)')),
- } or {
- eval('&shell'),
- eval('&shellcmdflag'),
- fmt('%s -u NONE -i NONE', eval('shellescape(v:progpath)')),
- }
- ),
- mode = 'terminal',
- buffer = 2,
- pty = '?',
- }
- local actual2 = eval('nvim_get_chan_info(&channel)')
- expected2.pty = actual2.pty
- eq(expected2, actual2)
- -- :terminal with args + stopped process.
- eq(1, eval('jobstop(&channel)'))
- eval('jobwait([&channel], 1000)') -- Wait.
- expected2.pty = (iswin() and '?' or '') -- pty stream was closed.
- eq(expected2, eval('nvim_get_chan_info(&channel)'))
- end)
- end)
- describe('nvim_call_atomic', function()
- it('works', function()
- meths.buf_set_lines(0, 0, -1, true, {'first'})
- local req = {
- {'nvim_get_current_line', {}},
- {'nvim_set_current_line', {'second'}},
- }
- eq({{'first', NIL}, NIL}, meths.call_atomic(req))
- eq({'second'}, meths.buf_get_lines(0, 0, -1, true))
- end)
- it('allows multiple return values', function()
- local req = {
- {'nvim_set_var', {'avar', true}},
- {'nvim_set_var', {'bvar', 'string'}},
- {'nvim_get_var', {'avar'}},
- {'nvim_get_var', {'bvar'}},
- }
- eq({{NIL, NIL, true, 'string'}, NIL}, meths.call_atomic(req))
- end)
- it('is aborted by errors in call', function()
- local error_types = meths.get_api_info()[2].error_types
- local req = {
- {'nvim_set_var', {'one', 1}},
- {'nvim_buf_set_lines', {}},
- {'nvim_set_var', {'two', 2}},
- }
- eq({{NIL}, {1, error_types.Exception.id,
- 'Wrong number of arguments: expecting 5 but got 0'}},
- meths.call_atomic(req))
- eq(1, meths.get_var('one'))
- eq(false, pcall(meths.get_var, 'two'))
- -- still returns all previous successful calls
- req = {
- {'nvim_set_var', {'avar', 5}},
- {'nvim_set_var', {'bvar', 'string'}},
- {'nvim_get_var', {'avar'}},
- {'nvim_buf_get_lines', {0, 10, 20, true}},
- {'nvim_get_var', {'bvar'}},
- }
- eq({{NIL, NIL, 5}, {3, error_types.Validation.id, 'Index out of bounds'}},
- meths.call_atomic(req))
- req = {
- {'i_am_not_a_method', {'xx'}},
- {'nvim_set_var', {'avar', 10}},
- }
- eq({{}, {0, error_types.Exception.id, 'Invalid method: i_am_not_a_method'}},
- meths.call_atomic(req))
- eq(5, meths.get_var('avar'))
- end)
- it('throws error on malformed arguments', function()
- local req = {
- {'nvim_set_var', {'avar', 1}},
- {'nvim_set_var'},
- {'nvim_set_var', {'avar', 2}},
- }
- local status, err = pcall(meths.call_atomic, req)
- eq(false, status)
- ok(err:match('Items in calls array must be arrays of size 2') ~= nil)
- -- call before was done, but not after
- eq(1, meths.get_var('avar'))
- req = {
- { 'nvim_set_var', { 'bvar', { 2, 3 } } },
- 12,
- }
- status, err = pcall(meths.call_atomic, req)
- eq(false, status)
- ok(err:match('Items in calls array must be arrays') ~= nil)
- eq({2,3}, meths.get_var('bvar'))
- req = {
- {'nvim_set_current_line', 'little line'},
- {'nvim_set_var', {'avar', 3}},
- }
- status, err = pcall(meths.call_atomic, req)
- eq(false, status)
- ok(err:match('Args must be Array') ~= nil)
- -- call before was done, but not after
- eq(1, meths.get_var('avar'))
- eq({''}, meths.buf_get_lines(0, 0, -1, true))
- end)
- end)
- describe('nvim_list_runtime_paths', function()
- setup(function()
- local pathsep = helpers.get_pathsep()
- mkdir_p('Xtest'..pathsep..'a')
- mkdir_p('Xtest'..pathsep..'b')
- end)
- teardown(function()
- rmdir 'Xtest'
- end)
- before_each(function()
- meths.set_current_dir 'Xtest'
- end)
- it('returns nothing with empty &runtimepath', function()
- meths.set_option('runtimepath', '')
- eq({}, meths.list_runtime_paths())
- end)
- it('returns single runtimepath', function()
- meths.set_option('runtimepath', 'a')
- eq({'a'}, meths.list_runtime_paths())
- end)
- it('returns two runtimepaths', function()
- meths.set_option('runtimepath', 'a,b')
- eq({'a', 'b'}, meths.list_runtime_paths())
- end)
- it('returns empty strings when appropriate', function()
- meths.set_option('runtimepath', 'a,,b')
- eq({'a', '', 'b'}, meths.list_runtime_paths())
- meths.set_option('runtimepath', ',a,b')
- eq({'', 'a', 'b'}, meths.list_runtime_paths())
- -- Trailing "," is ignored. Use ",," if you really really want CWD.
- meths.set_option('runtimepath', 'a,b,')
- eq({'a', 'b'}, meths.list_runtime_paths())
- meths.set_option('runtimepath', 'a,b,,')
- eq({'a', 'b', ''}, meths.list_runtime_paths())
- end)
- it('truncates too long paths', function()
- local long_path = ('/a'):rep(8192)
- meths.set_option('runtimepath', long_path)
- local paths_list = meths.list_runtime_paths()
- eq({}, paths_list)
- end)
- end)
- it('can throw exceptions', function()
- local status, err = pcall(nvim, 'get_option', 'invalid-option')
- eq(false, status)
- ok(err:match('Invalid option name') ~= nil)
- end)
- it('does not truncate error message <1 MB #5984', function()
- local very_long_name = 'A'..('x'):rep(10000)..'Z'
- local status, err = pcall(nvim, 'get_option', very_long_name)
- eq(false, status)
- eq(very_long_name, err:match('Ax+Z?'))
- end)
- it("does not leak memory on incorrect argument types", function()
- local status, err = pcall(nvim, 'set_current_dir',{'not', 'a', 'dir'})
- eq(false, status)
- ok(err:match(': Wrong type for argument 1 when calling nvim_set_current_dir, expecting String') ~= nil)
- end)
- describe('nvim_parse_expression', function()
- before_each(function()
- meths.set_option('isident', '')
- end)
- local it_maybe_pending = it
- if helpers.isCI() and os.getenv('CONFIGURATION') == 'MSVC_32' then
- -- For "works with &opt" (flaky on MSVC_32), but not easy to skip alone. #10241
- it_maybe_pending = pending
- end
- local function simplify_east_api_node(line, east_api_node)
- if east_api_node == NIL then
- return nil
- end
- if east_api_node.children then
- for k, v in pairs(east_api_node.children) do
- east_api_node.children[k] = simplify_east_api_node(line, v)
- end
- end
- local typ = east_api_node.type
- if typ == 'Register' then
- typ = typ .. ('(name=%s)'):format(
- tostring(intchar2lua(east_api_node.name)))
- east_api_node.name = nil
- elseif typ == 'PlainIdentifier' then
- typ = typ .. ('(scope=%s,ident=%s)'):format(
- tostring(intchar2lua(east_api_node.scope)), east_api_node.ident)
- east_api_node.scope = nil
- east_api_node.ident = nil
- elseif typ == 'PlainKey' then
- typ = typ .. ('(key=%s)'):format(east_api_node.ident)
- east_api_node.ident = nil
- elseif typ == 'Comparison' then
- typ = typ .. ('(type=%s,inv=%u,ccs=%s)'):format(
- east_api_node.cmp_type, east_api_node.invert and 1 or 0,
- east_api_node.ccs_strategy)
- east_api_node.ccs_strategy = nil
- east_api_node.cmp_type = nil
- east_api_node.invert = nil
- elseif typ == 'Integer' then
- typ = typ .. ('(val=%u)'):format(east_api_node.ivalue)
- east_api_node.ivalue = nil
- elseif typ == 'Float' then
- typ = typ .. format_string('(val=%e)', east_api_node.fvalue)
- east_api_node.fvalue = nil
- elseif typ == 'SingleQuotedString' or typ == 'DoubleQuotedString' then
- typ = format_string('%s(val=%q)', typ, east_api_node.svalue)
- east_api_node.svalue = nil
- elseif typ == 'Option' then
- typ = ('%s(scope=%s,ident=%s)'):format(
- typ,
- tostring(intchar2lua(east_api_node.scope)),
- east_api_node.ident)
- east_api_node.ident = nil
- east_api_node.scope = nil
- elseif typ == 'Environment' then
- typ = ('%s(ident=%s)'):format(typ, east_api_node.ident)
- east_api_node.ident = nil
- elseif typ == 'Assignment' then
- local aug = east_api_node.augmentation
- if aug == '' then aug = 'Plain' end
- typ = ('%s(%s)'):format(typ, aug)
- east_api_node.augmentation = nil
- end
- typ = ('%s:%u:%u:%s'):format(
- typ, east_api_node.start[1], east_api_node.start[2],
- line:sub(east_api_node.start[2] + 1,
- east_api_node.start[2] + 1 + east_api_node.len - 1))
- assert(east_api_node.start[2] + east_api_node.len - 1 <= #line)
- for k, _ in pairs(east_api_node.start) do
- assert(({true, true})[k])
- end
- east_api_node.start = nil
- east_api_node.type = nil
- east_api_node.len = nil
- local can_simplify = true
- for _, _ in pairs(east_api_node) do
- if can_simplify then can_simplify = false end
- end
- if can_simplify then
- return typ
- else
- east_api_node[1] = typ
- return east_api_node
- end
- end
- local function simplify_east_api(line, east_api)
- if east_api.error then
- east_api.err = east_api.error
- east_api.error = nil
- east_api.err.msg = east_api.err.message
- east_api.err.message = nil
- end
- if east_api.ast then
- east_api.ast = {simplify_east_api_node(line, east_api.ast)}
- if #east_api.ast == 0 then
- east_api.ast = nil
- end
- end
- if east_api.len == #line then
- east_api.len = nil
- end
- return east_api
- end
- local function simplify_east_hl(line, east_hl)
- for i, v in ipairs(east_hl) do
- east_hl[i] = ('%s:%u:%u:%s'):format(
- v[4],
- v[1],
- v[2],
- line:sub(v[2] + 1, v[3]))
- end
- return east_hl
- end
- local FLAGS_TO_STR = {
- [0] = "",
- [1] = "m",
- [2] = "E",
- [3] = "mE",
- [4] = "l",
- [5] = "lm",
- [6] = "lE",
- [7] = "lmE",
- }
- local function _check_parsing(opts, str, exp_ast, exp_highlighting_fs,
- nz_flags_exps)
- if type(str) ~= 'string' then
- return
- end
- local zflags = opts.flags[1]
- nz_flags_exps = nz_flags_exps or {}
- for _, flags in ipairs(opts.flags) do
- local err, msg = pcall(function()
- local east_api = meths.parse_expression(str, FLAGS_TO_STR[flags], true)
- local east_hl = east_api.highlight
- east_api.highlight = nil
- local ast = simplify_east_api(str, east_api)
- local hls = simplify_east_hl(str, east_hl)
- local exps = {
- ast = exp_ast,
- hl_fs = exp_highlighting_fs,
- }
- local add_exps = nz_flags_exps[flags]
- if not add_exps and flags == 3 + zflags then
- add_exps = nz_flags_exps[1 + zflags] or nz_flags_exps[2 + zflags]
- end
- if add_exps then
- if add_exps.ast then
- exps.ast = mergedicts_copy(exps.ast, add_exps.ast)
- end
- if add_exps.hl_fs then
- exps.hl_fs = mergedicts_copy(exps.hl_fs, add_exps.hl_fs)
- end
- end
- eq(exps.ast, ast)
- if exp_highlighting_fs then
- local exp_highlighting = {}
- local next_col = 0
- for i, h in ipairs(exps.hl_fs) do
- exp_highlighting[i], next_col = h(next_col)
- end
- eq(exp_highlighting, hls)
- end
- end)
- if not err then
- if type(msg) == 'table' then
- local merr, new_msg = pcall(
- format_string, 'table error:\n%s\n\n(%r)', msg.message, msg)
- if merr then
- msg = new_msg
- else
- msg = format_string('table error without .message:\n(%r)',
- msg)
- end
- elseif type(msg) ~= 'string' then
- msg = format_string('non-string non-table error:\n%r', msg)
- end
- error(format_string('Error while processing test (%r, %s):\n%s',
- str, FLAGS_TO_STR[flags], msg))
- end
- end
- end
- local function hl(group, str, shift)
- return function(next_col)
- local col = next_col + (shift or 0)
- return (('%s:%u:%u:%s'):format(
- 'Nvim' .. group,
- 0,
- col,
- str)), (col + #str)
- end
- end
- local function fmtn(typ, args, rest)
- if (typ == 'UnknownFigure'
- or typ == 'DictLiteral'
- or typ == 'CurlyBracesIdentifier'
- or typ == 'Lambda') then
- return ('%s%s'):format(typ, rest)
- elseif typ == 'DoubleQuotedString' or typ == 'SingleQuotedString' then
- if args:sub(-4) == 'NULL' then
- args = args:sub(1, -5) .. '""'
- end
- return ('%s(%s)%s'):format(typ, args, rest)
- end
- end
- require('test.unit.viml.expressions.parser_tests')(
- it_maybe_pending, _check_parsing, hl, fmtn)
- end)
- describe('nvim_list_uis', function()
- it('returns empty if --headless', function()
- -- Test runner defaults to --headless.
- eq({}, nvim("list_uis"))
- end)
- it('returns attached UIs', function()
- local screen = Screen.new(20, 4)
- screen:attach({override=true})
- local expected = {
- {
- chan = 1,
- ext_cmdline = false,
- ext_popupmenu = false,
- ext_tabline = false,
- ext_wildmenu = false,
- ext_linegrid = screen._options.ext_linegrid or false,
- ext_multigrid = false,
- ext_hlstate = false,
- ext_termcolors = false,
- ext_messages = false,
- height = 4,
- rgb = true,
- override = true,
- width = 20,
- }
- }
- eq(expected, nvim("list_uis"))
- screen:detach()
- screen = Screen.new(44, 99)
- screen:attach({ rgb = false })
- expected[1].rgb = false
- expected[1].override = false
- expected[1].width = 44
- expected[1].height = 99
- eq(expected, nvim("list_uis"))
- end)
- end)
- describe('nvim_create_namespace', function()
- it('works', function()
- eq({}, meths.get_namespaces())
- eq(1, meths.create_namespace("ns-1"))
- eq(2, meths.create_namespace("ns-2"))
- eq(1, meths.create_namespace("ns-1"))
- eq({["ns-1"]=1, ["ns-2"]=2}, meths.get_namespaces())
- eq(3, meths.create_namespace(""))
- eq(4, meths.create_namespace(""))
- eq({["ns-1"]=1, ["ns-2"]=2}, meths.get_namespaces())
- end)
- end)
- describe('nvim_create_buf', function()
- it('works', function()
- eq({id=2}, meths.create_buf(true, false))
- eq({id=3}, meths.create_buf(false, false))
- eq(' 1 %a "[No Name]" line 1\n'..
- ' 2 h "[No Name]" line 0',
- meths.command_output("ls"))
- -- current buffer didn't change
- eq({id=1}, meths.get_current_buf())
- local screen = Screen.new(20, 4)
- screen:attach()
- meths.buf_set_lines(2, 0, -1, true, {"some text"})
- meths.set_current_buf(2)
- screen:expect([[
- ^some text |
- {1:~ }|
- {1:~ }|
- |
- ]], {
- [1] = {bold = true, foreground = Screen.colors.Blue1},
- })
- end)
- it('can change buftype before visiting', function()
- meths.set_option("hidden", false)
- eq({id=2}, meths.create_buf(true, false))
- meths.buf_set_option(2, "buftype", "nofile")
- meths.buf_set_lines(2, 0, -1, true, {"test text"})
- command("split | buffer 2")
- eq({id=2}, meths.get_current_buf())
- -- if the buf_set_option("buftype") didn't work, this would error out.
- command("close")
- eq({id=1}, meths.get_current_buf())
- end)
- it("does not trigger BufEnter, BufWinEnter", function()
- command("let g:fired = v:false")
- command("au BufEnter,BufWinEnter * let g:fired = v:true")
- eq({id=2}, meths.create_buf(true, false))
- meths.buf_set_lines(2, 0, -1, true, {"test", "text"})
- eq(false, eval('g:fired'))
- end)
- it('scratch-buffer', function()
- eq({id=2}, meths.create_buf(false, true))
- eq({id=3}, meths.create_buf(true, true))
- eq({id=4}, meths.create_buf(true, true))
- local scratch_bufs = { 2, 3, 4 }
- eq(' 1 %a "[No Name]" line 1\n'..
- ' 3 h "[Scratch]" line 0\n'..
- ' 4 h "[Scratch]" line 0',
- meths.exec('ls', true))
- -- current buffer didn't change
- eq({id=1}, meths.get_current_buf())
- local screen = Screen.new(20, 4)
- screen:set_default_attr_ids({
- [1] = {bold = true, foreground = Screen.colors.Blue1},
- })
- screen:attach()
- --
- -- Editing a scratch-buffer does NOT change its properties.
- --
- local edited_buf = 2
- meths.buf_set_lines(edited_buf, 0, -1, true, {"some text"})
- for _,b in ipairs(scratch_bufs) do
- eq('nofile', meths.buf_get_option(b, 'buftype'))
- eq('hide', meths.buf_get_option(b, 'bufhidden'))
- eq(false, meths.buf_get_option(b, 'swapfile'))
- eq(false, meths.buf_get_option(b, 'modeline'))
- end
- --
- -- Visiting a scratch-buffer DOES NOT change its properties.
- --
- meths.set_current_buf(edited_buf)
- screen:expect([[
- ^some text |
- {1:~ }|
- {1:~ }|
- |
- ]])
- eq('nofile', meths.buf_get_option(edited_buf, 'buftype'))
- eq('hide', meths.buf_get_option(edited_buf, 'bufhidden'))
- eq(false, meths.buf_get_option(edited_buf, 'swapfile'))
- eq(false, meths.buf_get_option(edited_buf, 'modeline'))
- -- Scratch buffer can be wiped without error.
- command('bwipe')
- screen:expect([[
- ^ |
- {1:~ }|
- {1:~ }|
- |
- ]])
- end)
- it('does not cause heap-use-after-free on exit while setting options', function()
- command('au OptionSet * q')
- expect_exit(command, 'silent! call nvim_create_buf(0, 1)')
- end)
- end)
- describe('nvim_get_runtime_file', function()
- local p = helpers.alter_slashes
- it('can find files', function()
- eq({}, meths.get_runtime_file("bork.borkbork", false))
- eq({}, meths.get_runtime_file("bork.borkbork", true))
- eq(1, #meths.get_runtime_file("autoload/msgpack.vim", false))
- eq(1, #meths.get_runtime_file("autoload/msgpack.vim", true))
- local val = meths.get_runtime_file("autoload/remote/*.vim", true)
- eq(2, #val)
- if endswith(val[1], "define.vim") then
- ok(endswith(val[1], p"autoload/remote/define.vim"))
- ok(endswith(val[2], p"autoload/remote/host.vim"))
- else
- ok(endswith(val[1], p"autoload/remote/host.vim"))
- ok(endswith(val[2], p"autoload/remote/define.vim"))
- end
- val = meths.get_runtime_file("autoload/remote/*.vim", false)
- eq(1, #val)
- ok(endswith(val[1], p"autoload/remote/define.vim")
- or endswith(val[1], p"autoload/remote/host.vim"))
- val = meths.get_runtime_file("lua", true)
- eq(1, #val)
- ok(endswith(val[1], p"lua"))
- val = meths.get_runtime_file("lua/vim", true)
- eq(1, #val)
- ok(endswith(val[1], p"lua/vim"))
- end)
- it('can find directories', function()
- local val = meths.get_runtime_file("lua/", true)
- eq(1, #val)
- ok(endswith(val[1], p"lua/"))
- val = meths.get_runtime_file("lua/vim/", true)
- eq(1, #val)
- ok(endswith(val[1], p"lua/vim/"))
- eq({}, meths.get_runtime_file("foobarlang/", true))
- end)
- it('can handle bad patterns', function()
- if helpers.pending_win32(pending) then return end
- eq("Vim:E220: Missing }.", pcall_err(meths.get_runtime_file, "{", false))
- eq('Vim(echo):E5555: API call: Vim:E220: Missing }.',
- exc_exec("echo nvim_get_runtime_file('{', v:false)"))
- end)
- end)
- describe('nvim_get_all_options_info', function()
- it('should have key value pairs of option names', function()
- local options_info = meths.get_all_options_info()
- neq(nil, options_info.listchars)
- neq(nil, options_info.tabstop)
- eq(meths.get_option_info'winhighlight', options_info.winhighlight)
- end)
- it('should not crash when echoed', function()
- meths.exec("echo nvim_get_all_options_info()", true)
- end)
- end)
- describe('nvim_get_option_info', function()
- it('should error for unknown options', function()
- eq("no such option: 'bogus'", pcall_err(meths.get_option_info, 'bogus'))
- end)
- it('should return the same options for short and long name', function()
- eq(meths.get_option_info'winhl', meths.get_option_info'winhighlight')
- end)
- it('should have information about window options', function()
- eq({
- allows_duplicates = false,
- commalist = true;
- default = "";
- flaglist = false;
- global_local = false;
- last_set_chan = 0;
- last_set_linenr = 0;
- last_set_sid = 0;
- name = "winhighlight";
- scope = "win";
- shortname = "winhl";
- type = "string";
- was_set = false;
- }, meths.get_option_info'winhl')
- end)
- it('should have information about buffer options', function()
- eq({
- allows_duplicates = true,
- commalist = false,
- default = "",
- flaglist = false,
- global_local = false,
- last_set_chan = 0,
- last_set_linenr = 0,
- last_set_sid = 0,
- name = "filetype",
- scope = "buf",
- shortname = "ft",
- type = "string",
- was_set = false
- }, meths.get_option_info'filetype')
- end)
- it('should have information about global options', function()
- -- precondition: the option was changed from its default
- -- in test setup.
- eq(false, meths.get_option'showcmd')
- eq({
- allows_duplicates = true,
- commalist = false,
- default = true,
- flaglist = false,
- global_local = false,
- last_set_chan = 0,
- last_set_linenr = 0,
- last_set_sid = -2,
- name = "showcmd",
- scope = "global",
- shortname = "sc",
- type = "boolean",
- was_set = true
- }, meths.get_option_info'showcmd')
- end)
- end)
- describe('nvim_echo', function()
- local screen
- before_each(function()
- clear()
- screen = Screen.new(40, 8)
- screen:attach()
- screen:set_default_attr_ids({
- [0] = {bold=true, foreground=Screen.colors.Blue},
- [1] = {bold = true, foreground = Screen.colors.SeaGreen},
- [2] = {bold = true, reverse = true},
- [3] = {foreground = Screen.colors.Brown, bold = true}, -- Statement
- [4] = {foreground = Screen.colors.SlateBlue}, -- Special
- })
- command('highlight Statement gui=bold guifg=Brown')
- command('highlight Special guifg=SlateBlue')
- end)
- it('should clear cmdline message before echo', function()
- feed(':call nvim_echo([["msg"]], v:false, {})<CR>')
- screen:expect{grid=[[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- msg |
- ]]}
- end)
- it('can show highlighted line', function()
- nvim_async("echo", {{"msg_a"}, {"msg_b", "Statement"}, {"msg_c", "Special"}}, true, {})
- screen:expect{grid=[[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- msg_a{3:msg_b}{4:msg_c} |
- ]]}
- end)
- it('can show highlighted multiline', function()
- nvim_async("echo", {{"msg_a\nmsg_a", "Statement"}, {"msg_b", "Special"}}, true, {})
- screen:expect{grid=[[
- |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {2: }|
- {3:msg_a} |
- {3:msg_a}{4:msg_b} |
- {1:Press ENTER or type command to continue}^ |
- ]]}
- end)
- it('can save message history', function()
- nvim('command', 'set cmdheight=2') -- suppress Press ENTER
- nvim("echo", {{"msg\nmsg"}, {"msg"}}, true, {})
- eq("msg\nmsgmsg", meths.exec('messages', true))
- end)
- it('can disable saving message history', function()
- nvim('command', 'set cmdheight=2') -- suppress Press ENTER
- nvim_async("echo", {{"msg\nmsg"}, {"msg"}}, false, {})
- eq("", meths.exec("messages", true))
- end)
- end)
- describe('nvim_open_term', function()
- local screen
- before_each(function()
- clear()
- screen = Screen.new(100, 35)
- screen:attach()
- screen:set_default_attr_ids({
- [0] = {bold=true, foreground=Screen.colors.Blue},
- [1] = {background = Screen.colors.Plum1};
- [2] = {background = tonumber('0xffff40'), bg_indexed = true};
- [3] = {background = Screen.colors.Plum1, fg_indexed = true, foreground = tonumber('0x00e000')};
- [4] = {bold = true, reverse = true, background = Screen.colors.Plum1};
- [5] = {foreground = Screen.colors.Blue, background = Screen.colors.LightMagenta, bold = true};
- [6] = {bold = true};
- [7] = {reverse = true, background = Screen.colors.LightMagenta};
- })
- end)
- it('can batch process sequences', function()
- local b = meths.create_buf(true,true)
- meths.open_win(b, false, {width=79, height=31, row=1, col=1, relative='editor'})
- local t = meths.open_term(b, {})
- meths.chan_send(t, io.open("test/functional/fixtures/smile2.cat", "r"):read("*a"))
- screen:expect{grid=[[
- ^ |
- {0:~}{1::smile }{0: }|
- {0:~}{1: }{2:oooo$$$$$$$$$$$$oooo}{1: }{0: }|
- {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{0: }|
- {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:o$}{1: }{2:$$}{1: }{2:o$}{1: }{0: }|
- {0:~}{1: }{2:o}{1: }{2:$}{1: }{2:oo}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:$$}{1: }{2:$$}{1: }{2:$$o$}{1: }{0: }|
- {0:~}{1: }{2:oo}{1: }{2:$}{1: }{2:$}{1: "}{2:$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$o}{1: }{2:$$$o$$o$}{1: }{0: }|
- {0:~}{1: "}{2:$$$$$$o$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$o}{1: }{2:$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$}{1: """}{2:$$$}{1: }{0: }|
- {0:~}{1: "}{2:$$$}{1:""""}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$o}{1: }{0: }|
- {0:~}{1: }{2:o$$}{1:" }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$o}{1: }{0: }|
- {0:~}{1: }{2:$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" "}{2:$$$$$$ooooo$$$$o}{1: }{0: }|
- {0:~}{1: }{2:o$$$oooo$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:o$$$$$$$$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$$}{1:"}{2:$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$}{1:"""""""" }{0: }|
- {0:~}{1: """" }{2:$$$$}{1: "}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" }{2:o$$$}{1: }{0: }|
- {0:~}{1: "}{2:$$$o}{1: """}{2:$$$$$$$$$$$$$$$$$$}{1:"}{2:$$}{1:" }{2:$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$o}{1: "}{2:$$}{1:""}{2:$$$$$$}{1:"""" }{2:o$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$o}{1: }{2:o$$$}{1:" }{0: }|
- {0:~}{1: "}{2:$$$$o}{1: }{2:o$$$$$$o}{1:"}{2:$$$$o}{1: }{2:o$$$$}{1: }{0: }|
- {0:~}{1: "}{2:$$$$$oo}{1: ""}{2:$$$$o$$$$$o}{1: }{2:o$$$$}{1:"" }{0: }|
- {0:~}{1: ""}{2:$$$$$oooo}{1: "}{2:$$$o$$$$$$$$$}{1:""" }{0: }|
- {0:~}{1: ""}{2:$$$$$$$oo}{1: }{2:$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: """"}{2:$$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$$$$$$}{1: }{0: }|
- {0:~}{1: }{2:$$$$$$$$$$}{1:" }{0: }|
- {0:~}{1: "}{2:$$$}{1:"""" }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{3:Press ENTER or type command to continue}{1: }{0: }|
- {0:~}{4:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{0: }|
- {0:~}{1::call nvim__screenshot("smile2.cat") }{0: }|
- {0:~ }|
- {0:~ }|
- |
- ]]}
- end)
- it('can handle input', function()
- screen:try_resize(50, 10)
- eq({3, 2}, exec_lua [[
- buf = vim.api.nvim_create_buf(1,1)
- stream = ''
- do_the_echo = false
- function input(_,t1,b1,data)
- stream = stream .. data
- _G.vals = {t1, b1}
- if do_the_echo then
- vim.api.nvim_chan_send(t1, data)
- end
- end
- term = vim.api.nvim_open_term(buf, {on_input=input})
- vim.api.nvim_open_win(buf, true, {width=40, height=5, row=1, col=1, relative='editor'})
- return {term, buf}
- ]])
- screen:expect{grid=[[
- |
- {0:~}{1:^ }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]]}
- feed 'iba<c-x>bla'
- screen:expect{grid=[[
- |
- {0:~}{7: }{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {6:-- TERMINAL --} |
- ]]}
- eq('ba\024bla', exec_lua [[ return stream ]])
- eq({3,2}, exec_lua [[ return vals ]])
- exec_lua [[ do_the_echo = true ]]
- feed 'herrejösses!'
- screen:expect{grid=[[
- |
- {0:~}{1:herrejösses!}{7: }{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~}{1: }{0: }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {6:-- TERMINAL --} |
- ]]}
- eq('ba\024blaherrejösses!', exec_lua [[ return stream ]])
- end)
- end)
- describe('nvim_del_mark', function()
- it('works', function()
- local buf = meths.create_buf(false,true)
- meths.buf_set_lines(buf, -1, -1, true, {'a', 'bit of', 'text'})
- eq(true, meths.buf_set_mark(buf, 'F', 2, 2, {}))
- eq(true, meths.del_mark('F'))
- eq({0, 0}, meths.buf_get_mark(buf, 'F'))
- end)
- it('fails when invalid marks are used', function()
- eq(false, pcall(meths.del_mark, 'f'))
- eq(false, pcall(meths.del_mark, '!'))
- eq(false, pcall(meths.del_mark, 'fail'))
- end)
- end)
- describe('nvim_get_mark', function()
- it('works', function()
- local buf = meths.create_buf(false,true)
- meths.buf_set_lines(buf, -1, -1, true, {'a', 'bit of', 'text'})
- meths.buf_set_mark(buf, 'F', 2, 2, {})
- meths.buf_set_name(buf, "mybuf")
- local mark = meths.get_mark('F', {})
- -- Compare the path tail ony
- assert(string.find(mark[4], "mybuf$"))
- eq({2, 2, buf.id, mark[4]}, mark)
- end)
- it('fails when invalid marks are used', function()
- eq(false, pcall(meths.del_mark, 'f'))
- eq(false, pcall(meths.del_mark, '!'))
- eq(false, pcall(meths.del_mark, 'fail'))
- end)
- it('returns the expected when mark is not set', function()
- eq(true, meths.del_mark('A'))
- eq({0, 0, 0, ''}, meths.get_mark('A', {}))
- end)
- it('works with deleted buffers', function()
- local fname = tmpname()
- write_file(fname, 'a\nbit of\text')
- nvim("command", "edit " .. fname)
- local buf = meths.get_current_buf()
- meths.buf_set_mark(buf, 'F', 2, 2, {})
- nvim("command", "new") -- Create new buf to avoid :bd failing
- nvim("command", "bd! " .. buf.id)
- os.remove(fname)
- local mark = meths.get_mark('F', {})
- -- To avoid comparing relative vs absolute path
- local mfname = mark[4]
- local tail_patt = [[[\/][^\/]*$]]
- -- tail of paths should be equals
- eq(fname:match(tail_patt), mfname:match(tail_patt))
- eq({2, 2, buf.id, mark[4]}, mark)
- end)
- end)
- describe('nvim_eval_statusline', function()
- it('works', function()
- eq({
- str = '%StatusLineStringWithHighlights',
- width = 31
- },
- meths.eval_statusline(
- '%%StatusLineString%#WarningMsg#WithHighlights',
- {}))
- end)
- it('doesn\'t exceed maxwidth', function()
- eq({
- str = 'Should be trun>',
- width = 15
- },
- meths.eval_statusline(
- 'Should be truncated%<',
- { maxwidth = 15 }))
- end)
- it('supports ASCII fillchar', function()
- eq({ str = 'a~~~b', width = 5 },
- meths.eval_statusline('a%=b', { fillchar = '~', maxwidth = 5 }))
- end)
- it('supports single-width multibyte fillchar', function()
- eq({ str = 'a━━━b', width = 5 },
- meths.eval_statusline('a%=b', { fillchar = '━', maxwidth = 5 }))
- end)
- it('treats double-width fillchar as single-width', function()
- eq({ str = 'a哦哦哦b', width = 5 },
- meths.eval_statusline('a%=b', { fillchar = '哦', maxwidth = 5 }))
- end)
- it('treats control character fillchar as single-width', function()
- eq({ str = 'a\031\031\031b', width = 5 },
- meths.eval_statusline('a%=b', { fillchar = '\031', maxwidth = 5 }))
- end)
- it('rejects multiple-character fillchar', function()
- eq('fillchar must be a single character',
- pcall_err(meths.eval_statusline, '', { fillchar = 'aa' }))
- end)
- it('rejects empty string fillchar', function()
- eq('fillchar must be a single character',
- pcall_err(meths.eval_statusline, '', { fillchar = '' }))
- end)
- it('rejects non-string fillchar', function()
- eq('fillchar must be a single character',
- pcall_err(meths.eval_statusline, '', { fillchar = 1 }))
- end)
- it('rejects invalid string', function()
- eq('E539: Illegal character <}>',
- pcall_err(meths.eval_statusline, '%{%}', {}))
- end)
- describe('highlight parsing', function()
- it('works', function()
- eq({
- str = "TextWithWarningHighlightTextWithUserHighlight",
- width = 45,
- highlights = {
- { start = 0, group = 'WarningMsg' },
- { start = 24, group = 'User1' }
- },
- },
- meths.eval_statusline(
- '%#WarningMsg#TextWithWarningHighlight%1*TextWithUserHighlight',
- { highlights = true }))
- end)
- it('works with no highlight', function()
- eq({
- str = "TextWithNoHighlight",
- width = 19,
- highlights = {
- { start = 0, group = 'StatusLine' },
- },
- },
- meths.eval_statusline(
- 'TextWithNoHighlight',
- { highlights = true }))
- end)
- it('works with inactive statusline', function()
- command('split')
- eq({
- str = 'TextWithNoHighlightTextWithWarningHighlight',
- width = 43,
- highlights = {
- { start = 0, group = 'StatusLineNC' },
- { start = 19, group = 'WarningMsg' }
- }
- },
- meths.eval_statusline(
- 'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
- { winid = meths.list_wins()[2].id, highlights = true }))
- end)
- it('works with tabline', function()
- eq({
- str = 'TextWithNoHighlightTextWithWarningHighlight',
- width = 43,
- highlights = {
- { start = 0, group = 'TabLineFill' },
- { start = 19, group = 'WarningMsg' }
- }
- },
- meths.eval_statusline(
- 'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
- { use_tabline = true, highlights = true }))
- end)
- it('works with winbar', function()
- eq({
- str = 'TextWithNoHighlightTextWithWarningHighlight',
- width = 43,
- highlights = {
- { start = 0, group = 'WinBar' },
- { start = 19, group = 'WarningMsg' }
- }
- },
- meths.eval_statusline(
- 'TextWithNoHighlight%#WarningMsg#TextWithWarningHighlight',
- { use_winbar = true, highlights = true }))
- end)
- end)
- end)
- describe('nvim_parse_cmd', function()
- it('works', function()
- eq({
- cmd = 'echo',
- args = { 'foo' },
- bang = false,
- addr = 'none',
- magic = {
- file = false,
- bar = false
- },
- nargs = '*',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('echo foo', {}))
- end)
- it('works with ranges', function()
- eq({
- cmd = 'substitute',
- args = { '/math.random/math.max/' },
- bang = false,
- range = { 4, 6 },
- addr = 'line',
- magic = {
- file = false,
- bar = false
- },
- nargs = '*',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('4,6s/math.random/math.max/', {}))
- end)
- it('works with count', function()
- eq({
- cmd = 'buffer',
- args = {},
- bang = false,
- range = { 1 },
- count = 1,
- addr = 'buf',
- magic = {
- file = false,
- bar = true
- },
- nargs = '*',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('buffer 1', {}))
- end)
- it('works with register', function()
- eq({
- cmd = 'put',
- args = {},
- bang = false,
- range = {},
- reg = '+',
- addr = 'line',
- magic = {
- file = false,
- bar = true
- },
- nargs = '0',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('put +', {}))
- eq({
- cmd = 'put',
- args = {},
- bang = false,
- range = {},
- reg = '',
- addr = 'line',
- magic = {
- file = false,
- bar = true
- },
- nargs = '0',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('put', {}))
- end)
- it('works with range, count and register', function()
- eq({
- cmd = 'delete',
- args = {},
- bang = false,
- range = { 3, 7 },
- count = 7,
- reg = '*',
- addr = 'line',
- magic = {
- file = false,
- bar = true
- },
- nargs = '0',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('1,3delete * 5', {}))
- end)
- it('works with bang', function()
- eq({
- cmd = 'write',
- args = {},
- bang = true,
- range = {},
- addr = 'line',
- magic = {
- file = true,
- bar = true
- },
- nargs = '?',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- },
- }, meths.parse_cmd('w!', {}))
- end)
- it('works with modifiers', function()
- eq({
- cmd = 'split',
- args = { 'foo.txt' },
- bang = false,
- range = {},
- addr = '?',
- magic = {
- file = true,
- bar = true
- },
- nargs = '?',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = true,
- filter = {
- pattern = "foo",
- force = false
- },
- hide = false,
- horizontal = true,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = true,
- split = "topleft",
- tab = 1,
- unsilent = false,
- verbose = 15,
- vertical = false,
- },
- }, meths.parse_cmd('15verbose silent! horizontal topleft tab filter /foo/ split foo.txt', {}))
- eq({
- cmd = 'split',
- args = { 'foo.txt' },
- bang = false,
- range = {},
- addr = '?',
- magic = {
- file = true,
- bar = true
- },
- nargs = '?',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = true,
- emsg_silent = false,
- filter = {
- pattern = "foo",
- force = true
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "botright",
- tab = 0,
- unsilent = true,
- verbose = 0,
- vertical = false,
- },
- }, meths.parse_cmd('0verbose unsilent botright 0tab confirm filter! /foo/ split foo.txt', {}))
- end)
- it('works with user commands', function()
- command('command -bang -nargs=+ -range -addr=lines MyCommand echo foo')
- eq({
- cmd = 'MyCommand',
- args = { 'test', 'it' },
- bang = true,
- range = { 4, 6 },
- addr = 'line',
- magic = {
- file = false,
- bar = false
- },
- nargs = '+',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('4,6MyCommand! test it', {}))
- end)
- it('works for commands separated by bar', function()
- eq({
- cmd = 'argadd',
- args = { 'a.txt' },
- bang = false,
- range = {},
- addr = 'arg',
- magic = {
- file = true,
- bar = true
- },
- nargs = '*',
- nextcmd = 'argadd b.txt',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('argadd a.txt | argadd b.txt', {}))
- end)
- it('works for nargs=1', function()
- command('command -nargs=1 MyCommand echo <q-args>')
- eq({
- cmd = 'MyCommand',
- args = { 'test it' },
- bang = false,
- addr = 'none',
- magic = {
- file = false,
- bar = false
- },
- nargs = '1',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('MyCommand test it', {}))
- end)
- it('errors for invalid command', function()
- eq('Error while parsing command line', pcall_err(meths.parse_cmd, '', {}))
- eq('Error while parsing command line', pcall_err(meths.parse_cmd, '" foo', {}))
- eq('Error while parsing command line: E492: Not an editor command: Fubar',
- pcall_err(meths.parse_cmd, 'Fubar', {}))
- command('command! Fubar echo foo')
- eq('Error while parsing command line: E477: No ! allowed',
- pcall_err(meths.parse_cmd, 'Fubar!', {}))
- eq('Error while parsing command line: E481: No range allowed',
- pcall_err(meths.parse_cmd, '4,6Fubar', {}))
- command('command! Foobar echo foo')
- eq('Error while parsing command line: E464: Ambiguous use of user-defined command',
- pcall_err(meths.parse_cmd, 'F', {}))
- end)
- it('does not interfere with printing line in Ex mode #19400', function()
- local screen = Screen.new(60, 7)
- screen:set_default_attr_ids({
- [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
- [1] = {bold = true, reverse = true}, -- MsgSeparator
- })
- screen:attach()
- insert([[
- foo
- bar]])
- feed('gQ1')
- screen:expect([[
- foo |
- bar |
- {0:~ }|
- {0:~ }|
- {1: }|
- Entering Ex mode. Type "visual" to go to Normal mode. |
- :1^ |
- ]])
- eq('Error while parsing command line', pcall_err(meths.parse_cmd, '', {}))
- feed('<CR>')
- screen:expect([[
- foo |
- bar |
- {1: }|
- Entering Ex mode. Type "visual" to go to Normal mode. |
- :1 |
- foo |
- :^ |
- ]])
- end)
- it('does not move cursor or change search history/pattern #19878 #19890', function()
- meths.buf_set_lines(0, 0, -1, true, {'foo', 'bar', 'foo', 'bar'})
- eq({1, 0}, meths.win_get_cursor(0))
- eq('', funcs.getreg('/'))
- eq('', funcs.histget('search'))
- feed(':') -- call the API in cmdline mode to test whether it changes search history
- eq({
- cmd = 'normal',
- args = {'x'},
- bang = true,
- range = {3, 4},
- addr = 'line',
- magic = {
- file = false,
- bar = false,
- },
- nargs = '+',
- nextcmd = '',
- mods = {
- browse = false,
- confirm = false,
- emsg_silent = false,
- filter = {
- pattern = "",
- force = false,
- },
- hide = false,
- horizontal = false,
- keepalt = false,
- keepjumps = false,
- keepmarks = false,
- keeppatterns = false,
- lockmarks = false,
- noautocmd = false,
- noswapfile = false,
- sandbox = false,
- silent = false,
- split = "",
- tab = -1,
- unsilent = false,
- verbose = -1,
- vertical = false,
- }
- }, meths.parse_cmd('+2;/bar/normal! x', {}))
- eq({1, 0}, meths.win_get_cursor(0))
- eq('', funcs.getreg('/'))
- eq('', funcs.histget('search'))
- end)
- it('result can be used directly by nvim_cmd #20051', function()
- eq("foo", meths.cmd(meths.parse_cmd('echo "foo"', {}), { output = true }))
- meths.cmd(meths.parse_cmd("set cursorline", {}), {})
- eq(true, meths.get_option_value("cursorline", {}))
- end)
- end)
- describe('nvim_cmd', function()
- it('works', function ()
- meths.cmd({ cmd = "set", args = { "cursorline" } }, {})
- eq(true, meths.get_option_value("cursorline", {}))
- end)
- it('captures output', function()
- eq("foo", meths.cmd({ cmd = "echo", args = { '"foo"' } }, { output = true }))
- end)
- it('sets correct script context', function()
- meths.cmd({ cmd = "set", args = { "cursorline" } }, {})
- local str = meths.exec([[verbose set cursorline?]], true)
- neq(nil, str:find("cursorline\n\tLast set from API client %(channel id %d+%)"))
- end)
- it('works with range', function()
- insert [[
- line1
- line2
- line3
- line4
- you didn't expect this
- line5
- line6
- ]]
- meths.cmd({ cmd = "del", range = {2, 4} }, {})
- expect [[
- line1
- you didn't expect this
- line5
- line6
- ]]
- end)
- it('works with count', function()
- insert [[
- line1
- line2
- line3
- line4
- you didn't expect this
- line5
- line6
- ]]
- meths.cmd({ cmd = "del", range = { 2 }, count = 4 }, {})
- expect [[
- line1
- line5
- line6
- ]]
- end)
- it('works with register', function()
- insert [[
- line1
- line2
- line3
- line4
- you didn't expect this
- line5
- line6
- ]]
- meths.cmd({ cmd = "del", range = { 2, 4 }, reg = 'a' }, {})
- meths.exec("1put a", false)
- expect [[
- line1
- line2
- line3
- line4
- you didn't expect this
- line5
- line6
- ]]
- end)
- it('works with bang', function ()
- meths.create_user_command("Foo", 'echo "<bang>"', { bang = true })
- eq("!", meths.cmd({ cmd = "Foo", bang = true }, { output = true }))
- eq("", meths.cmd({ cmd = "Foo", bang = false }, { output = true }))
- end)
- it('works with modifiers', function()
- -- with silent = true output is still captured
- eq('1',
- meths.cmd({ cmd = 'echomsg', args = { '1' }, mods = { silent = true } },
- { output = true }))
- -- but message isn't added to message history
- eq('', meths.cmd({ cmd = 'messages' }, { output = true }))
- meths.create_user_command("Foo", 'set verbose', {})
- eq(" verbose=1", meths.cmd({ cmd = "Foo", mods = { verbose = 1 } }, { output = true }))
- meths.create_user_command("Mods", "echo '<mods>'", {})
- eq('keepmarks keeppatterns silent 3verbose aboveleft horizontal',
- meths.cmd({ cmd = "Mods", mods = {
- horizontal = true,
- keepmarks = true,
- keeppatterns = true,
- silent = true,
- split = 'aboveleft',
- verbose = 3,
- } }, { output = true }))
- eq(0, meths.get_option_value("verbose", {}))
- command('edit foo.txt | edit bar.txt')
- eq(' 1 #h "foo.txt" line 1',
- meths.cmd({ cmd = "buffers", mods = { filter = { pattern = "foo", force = false } } },
- { output = true }))
- eq(' 2 %a "bar.txt" line 1',
- meths.cmd({ cmd = "buffers", mods = { filter = { pattern = "foo", force = true } } },
- { output = true }))
- -- with emsg_silent = true error is suppresed
- feed([[:lua vim.api.nvim_cmd({ cmd = 'call', mods = { emsg_silent = true } }, {})<CR>]])
- eq('', meths.cmd({ cmd = 'messages' }, { output = true }))
- -- error from the next command typed is not suppressed #21420
- feed(':call<CR><CR>')
- eq('E471: Argument required', meths.cmd({ cmd = 'messages' }, { output = true }))
- end)
- it('works with magic.file', function()
- exec_lua([[
- vim.api.nvim_create_user_command("Foo", function(opts)
- vim.api.nvim_echo({{ opts.fargs[1] }}, false, {})
- end, { nargs = 1 })
- ]])
- eq(lfs.currentdir(),
- meths.cmd({ cmd = "Foo", args = { '%:p:h' }, magic = { file = true } },
- { output = true }))
- end)
- it('splits arguments correctly', function()
- meths.exec([[
- function! FooFunc(...)
- echo a:000
- endfunction
- ]], false)
- meths.create_user_command("Foo", "call FooFunc(<f-args>)", { nargs = '+' })
- eq([=[['a quick', 'brown fox', 'jumps over the', 'lazy dog']]=],
- meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}},
- { output = true }))
- eq([=[['test \ \\ \"""\', 'more\ tests\" ']]=],
- meths.cmd({ cmd = "Foo", args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } },
- { output = true }))
- end)
- it('splits arguments correctly for Lua callback', function()
- meths.exec_lua([[
- local function FooFunc(opts)
- vim.pretty_print(opts.fargs)
- end
- vim.api.nvim_create_user_command("Foo", FooFunc, { nargs = '+' })
- ]], {})
- eq([[{ "a quick", "brown fox", "jumps over the", "lazy dog" }]],
- meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}},
- { output = true }))
- eq([[{ 'test \\ \\\\ \\"""\\', 'more\\ tests\\" ' }]],
- meths.cmd({ cmd = "Foo", args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } },
- { output = true }))
- end)
- it('works with buffer names', function()
- command("edit foo.txt | edit bar.txt")
- meths.cmd({ cmd = "buffer", args = { "foo.txt" } }, {})
- eq("foo.txt", funcs.fnamemodify(meths.buf_get_name(0), ":t"))
- meths.cmd({ cmd = "buffer", args = { "bar.txt" } }, {})
- eq("bar.txt", funcs.fnamemodify(meths.buf_get_name(0), ":t"))
- end)
- it('triggers CmdUndefined event if command is not found', function()
- meths.exec_lua([[
- vim.api.nvim_create_autocmd("CmdUndefined",
- { pattern = "Foo",
- callback = function()
- vim.api.nvim_create_user_command("Foo", "echo 'foo'", {})
- end
- })
- ]], {})
- eq("foo", meths.cmd({ cmd = "Foo" }, { output = true }))
- end)
- it('errors if command is not implemented', function()
- eq("Command not implemented: winpos", pcall_err(meths.cmd, { cmd = "winpos" }, {}))
- end)
- it('works with empty arguments list', function()
- meths.cmd({ cmd = "update" }, {})
- meths.cmd({ cmd = "buffer", count = 0 }, {})
- end)
- it('doesn\'t suppress errors when used in keymapping', function()
- meths.exec_lua([[
- vim.keymap.set("n", "[l",
- function() vim.api.nvim_cmd({ cmd = "echo", args = {"foo"} }, {}) end)
- ]], {})
- feed("[l")
- neq(nil, string.find(eval("v:errmsg"), "E5108:"))
- end)
- it('handles 0 range #19608', function()
- meths.buf_set_lines(0, 0, -1, false, { "aa" })
- meths.cmd({ cmd = 'delete', range = { 0 } }, {})
- command('undo')
- eq({'aa'}, meths.buf_get_lines(0, 0, 1, false))
- assert_alive()
- end)
- it('supports filename expansion', function()
- meths.cmd({ cmd = 'argadd', args = { '%:p:h:t', '%:p:h:t' } }, {})
- local arg = funcs.expand('%:p:h:t')
- eq({ arg, arg }, funcs.argv())
- end)
- it("'make' command works when argument count isn't 1 #19696", function()
- command('set makeprg=echo')
- command('set shellquote=')
- matches('^:!echo ',
- meths.cmd({ cmd = 'make' }, { output = true }))
- assert_alive()
- matches('^:!echo foo bar',
- meths.cmd({ cmd = 'make', args = { 'foo', 'bar' } }, { output = true }))
- assert_alive()
- local arg_pesc = pesc(funcs.expand('%:p:h:t'))
- matches(('^:!echo %s %s'):format(arg_pesc, arg_pesc),
- meths.cmd({ cmd = 'make', args = { '%:p:h:t', '%:p:h:t' } }, { output = true }))
- assert_alive()
- end)
- it('doesn\'t display messages when output=true', function()
- local screen = Screen.new(40, 6)
- screen:attach()
- screen:set_default_attr_ids({
- [0] = {bold=true, foreground=Screen.colors.Blue},
- })
- meths.cmd({cmd = 'echo', args = {[['hello']]}}, {output = true})
- screen:expect{grid=[[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- |
- ]]}
- exec([[
- func Print()
- call nvim_cmd(#{cmd: 'echo', args: ['"hello"']}, #{output: v:true})
- endfunc
- ]])
- feed([[:echon 1 | call Print() | echon 5<CR>]])
- screen:expect{grid=[[
- ^ |
- {0:~ }|
- {0:~ }|
- {0:~ }|
- {0:~ }|
- 15 |
- ]]}
- end)
- it('works with non-String args', function()
- eq('2', meths.cmd({cmd = 'echo', args = {2}}, {output = true}))
- eq('1', meths.cmd({cmd = 'echo', args = {true}}, {output = true}))
- end)
- describe('first argument as count', function()
- before_each(clear)
- it('works', function()
- command('vsplit | enew')
- meths.cmd({cmd = 'bdelete', args = {meths.get_current_buf()}}, {})
- eq(1, meths.get_current_buf().id)
- end)
- it('works with :sleep using milliseconds', function()
- local start = luv.now()
- meths.cmd({cmd = 'sleep', args = {'100m'}}, {})
- ok(luv.now() - start <= 300)
- end)
- end)
- end)
- end)
|