12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625 |
- local t = require('test.testutil')
- local n = require('test.functional.testnvim')()
- local Screen = require('test.functional.ui.screen')
- local fn = n.fn
- local api = n.api
- local command = n.command
- local eq = t.eq
- local exec_lua = n.exec_lua
- local exec_capture = n.exec_capture
- local matches = t.matches
- local pcall_err = t.pcall_err
- describe('vim._with', function()
- before_each(function()
- n.clear()
- exec_lua([[
- _G.fn = vim.fn
- _G.api = vim.api
- _G.setup_buffers = function()
- return api.nvim_create_buf(false, true), api.nvim_get_current_buf()
- end
- _G.setup_windows = function()
- local other_win = api.nvim_get_current_win()
- vim.cmd.new()
- return other_win, api.nvim_get_current_win()
- end
- ]])
- end)
- local assert_events_trigger = function()
- local out = exec_lua [[
- -- Needs three global values defined:
- -- - `test_events` - array of events which are tested.
- -- - `test_context` - context to be tested.
- -- - `test_trig_event` - callable triggering at least one tested event.
- _G.n_events = 0
- local opts = { callback = function() _G.n_events = _G.n_events + 1 end }
- api.nvim_create_autocmd(_G.test_events, opts)
- local context = { bo = { commentstring = '-- %s' } }
- -- Should not trigger events on its own
- vim._with(_G.test_context, function() end)
- local is_no_events = _G.n_events == 0
- -- Should trigger events if specifically asked inside callback
- local is_events = vim._with(_G.test_context, function()
- _G.test_trig_event()
- return _G.n_events > 0
- end)
- return { is_no_events, is_events }
- ]]
- eq({ true, true }, out)
- end
- describe('`bo` context', function()
- before_each(function()
- exec_lua [[
- _G.other_buf, _G.cur_buf = setup_buffers()
- -- 'commentstring' is local to buffer and string
- vim.bo[other_buf].commentstring = '## %s'
- vim.bo[cur_buf].commentstring = '// %s'
- vim.go.commentstring = '$$ %s'
- -- 'undolevels' is global or local to buffer (global-local) and number
- vim.bo[other_buf].undolevels = 100
- vim.bo[cur_buf].undolevels = 250
- vim.go.undolevels = 500
- _G.get_state = function()
- return {
- bo = {
- cms_cur = vim.bo[cur_buf].commentstring,
- cms_other = vim.bo[other_buf].commentstring,
- ul_cur = vim.bo[cur_buf].undolevels,
- ul_other = vim.bo[other_buf].undolevels,
- },
- go = {
- cms = vim.go.commentstring,
- ul = vim.go.undolevels,
- },
- }
- end
- ]]
- end)
- it('works', function()
- local out = exec_lua [[
- local context = { bo = { commentstring = '-- %s', undolevels = 0 } }
- local before = get_state()
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_buf() == cur_buf)
- return get_state()
- end)
- return { before = before, inner = inner, after = get_state() }
- ]]
- eq({
- bo = { cms_cur = '-- %s', cms_other = '## %s', ul_cur = 0, ul_other = 100 },
- go = { cms = '$$ %s', ul = 500 },
- }, out.inner)
- eq(out.before, out.after)
- end)
- it('sets options in `buf` context', function()
- local out = exec_lua [[
- local context = { buf = other_buf, bo = { commentstring = '-- %s', undolevels = 0 } }
- local before = get_state()
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_buf() == other_buf)
- return get_state()
- end)
- return { before = before, inner = inner, after = get_state() }
- ]]
- eq({
- bo = { cms_cur = '// %s', cms_other = '-- %s', ul_cur = 250, ul_other = 0 },
- go = { cms = '$$ %s', ul = 500 },
- }, out.inner)
- eq(out.before, out.after)
- end)
- it('restores only options from context', function()
- local out = exec_lua [[
- local context = { bo = { commentstring = '-- %s' } }
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_buf() == cur_buf)
- vim.bo[cur_buf].undolevels = 750
- vim.bo[cur_buf].commentstring = '!! %s'
- return get_state()
- end)
- return { inner = inner, after = get_state() }
- ]]
- eq({
- bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = 750, ul_other = 100 },
- go = { cms = '$$ %s', ul = 500 },
- }, out.inner)
- eq({
- bo = { cms_cur = '// %s', cms_other = '## %s', ul_cur = 750, ul_other = 100 },
- go = { cms = '$$ %s', ul = 500 },
- }, out.after)
- end)
- it('does not trigger events', function()
- exec_lua [[
- _G.test_events = { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }
- _G.test_context = { bo = { commentstring = '-- %s' } }
- _G.test_trig_event = function() vim.cmd.new() end
- ]]
- assert_events_trigger()
- end)
- it('can be nested', function()
- local out = exec_lua [[
- local before, before_inner, after_inner = get_state(), nil, nil
- vim._with({ bo = { commentstring = '-- %s', undolevels = 0 } }, function()
- before_inner = get_state()
- inner = vim._with({ bo = { commentstring = '!! %s' } }, get_state)
- after_inner = get_state()
- end)
- return {
- before = before, before_inner = before_inner,
- inner = inner,
- after_inner = after_inner, after = get_state(),
- }
- ]]
- eq('!! %s', out.inner.bo.cms_cur)
- eq(0, out.inner.bo.ul_cur)
- eq(out.before_inner, out.after_inner)
- eq(out.before, out.after)
- end)
- end)
- describe('`buf` context', function()
- it('works', function()
- local out = exec_lua [[
- local other_buf, cur_buf = setup_buffers()
- local inner = vim._with({ buf = other_buf }, function()
- return api.nvim_get_current_buf()
- end)
- return { inner == other_buf, api.nvim_get_current_buf() == cur_buf }
- ]]
- eq({ true, true }, out)
- end)
- it('does not trigger events', function()
- exec_lua [[
- _G.test_events = { 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave' }
- _G.test_context = { buf = other_buf }
- _G.test_trig_event = function() vim.cmd.new() end
- ]]
- assert_events_trigger()
- end)
- it('can access buffer options', function()
- local out = exec_lua [[
- other_buf, cur_buf = setup_buffers()
- vim.bo[other_buf].commentstring = '## %s'
- vim.bo[cur_buf].commentstring = '// %s'
- vim._with({ buf = other_buf }, function()
- vim.cmd.set('commentstring=--\\ %s')
- end)
- return vim.bo[other_buf].commentstring == '-- %s' and
- vim.bo[cur_buf].commentstring == '// %s'
- ]]
- eq(true, out)
- end)
- it('works with different kinds of buffers', function()
- exec_lua [[
- local assert_buf = function(buf)
- vim._with({ buf = buf }, function()
- assert(api.nvim_get_current_buf() == buf)
- end)
- end
- -- Current
- assert_buf(api.nvim_get_current_buf())
- -- Hidden listed
- local listed = api.nvim_create_buf(true, true)
- assert_buf(listed)
- -- Visible
- local other_win, cur_win = setup_windows()
- api.nvim_win_set_buf(other_win, listed)
- assert_buf(listed)
- -- Shown but not visible
- vim.cmd.tabnew()
- assert_buf(listed)
- -- Shown in several windows
- api.nvim_win_set_buf(0, listed)
- assert_buf(listed)
- -- Shown in floating window
- local float_buf = api.nvim_create_buf(false, true)
- local config = { relative = 'editor', row = 1, col = 1, width = 5, height = 5 }
- api.nvim_open_win(float_buf, false, config)
- assert_buf(float_buf)
- ]]
- end)
- it('does not cause ml_get errors with invalid visual selection', function()
- exec_lua [[
- api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' })
- api.nvim_feedkeys(vim.keycode('G<C-V>'), 'txn', false)
- local other_buf, _ = setup_buffers()
- vim._with({ buf = buf }, function() vim.cmd.redraw() end)
- ]]
- end)
- it('can be nested', function()
- exec_lua [[
- local other_buf, cur_buf = setup_buffers()
- vim._with({ buf = other_buf }, function()
- assert(api.nvim_get_current_buf() == other_buf)
- inner = vim._with({ buf = cur_buf }, function()
- assert(api.nvim_get_current_buf() == cur_buf)
- end)
- assert(api.nvim_get_current_buf() == other_buf)
- end)
- assert(api.nvim_get_current_buf() == cur_buf)
- ]]
- end)
- it('can be nested crazily with hidden buffers', function()
- local out = exec_lua([[
- local n = 0
- local function with_recursive_nested_bufs()
- n = n + 1
- if n > 20 then return true end
- local other_buf, _ = setup_buffers()
- vim.bo[other_buf].commentstring = '## %s'
- local callback = function()
- return api.nvim_get_current_buf() == other_buf
- and vim.bo[other_buf].commentstring == '## %s'
- and with_recursive_nested_bufs()
- end
- return vim._with({ buf = other_buf }, callback) and
- api.nvim_buf_delete(other_buf, {}) == nil
- end
- return with_recursive_nested_bufs()
- ]])
- eq(true, out)
- end)
- end)
- describe('`emsg_silent` context', function()
- pending('works', function()
- local ok = pcall(
- exec_lua,
- [[
- _G.f = function()
- error('This error should not interfer with execution', 0)
- end
- -- Should not produce error same as `vim.cmd('silent! lua _G.f()')`
- vim._with({ emsg_silent = true }, f)
- ]]
- )
- eq(true, ok)
- -- Should properly report errors afterwards
- ok = pcall(exec_lua, 'lua _G.f()')
- eq(false, ok)
- end)
- it('can be nested', function()
- local ok = pcall(
- exec_lua,
- [[
- _G.f = function()
- error('This error should not interfer with execution', 0)
- end
- -- Should produce error same as `_G.f()`
- vim._with({ emsg_silent = true }, function()
- vim._with( { emsg_silent = false }, f)
- end)
- ]]
- )
- eq(false, ok)
- end)
- end)
- describe('`env` context', function()
- before_each(function()
- exec_lua [[
- vim.fn.setenv('aaa', 'hello')
- _G.get_state = function()
- return { aaa = vim.fn.getenv('aaa'), bbb = vim.fn.getenv('bbb') }
- end
- ]]
- end)
- it('works', function()
- local out = exec_lua [[
- local context = { env = { aaa = 'inside', bbb = 'wow' } }
- local before = get_state()
- local inner = vim._with(context, get_state)
- return { before = before, inner = inner, after = get_state() }
- ]]
- eq({ aaa = 'inside', bbb = 'wow' }, out.inner)
- eq(out.before, out.after)
- end)
- it('restores only variables from context', function()
- local out = exec_lua [[
- local context = { env = { bbb = 'wow' } }
- local before = get_state()
- local inner = vim._with(context, function()
- vim.env.aaa = 'inside'
- return get_state()
- end)
- return { before = before, inner = inner, after = get_state() }
- ]]
- eq({ aaa = 'inside', bbb = 'wow' }, out.inner)
- eq({ aaa = 'inside', bbb = vim.NIL }, out.after)
- end)
- it('can be nested', function()
- local out = exec_lua [[
- local before, before_inner, after_inner = get_state(), nil, nil
- vim._with({ env = { aaa = 'inside', bbb = 'wow' } }, function()
- before_inner = get_state()
- inner = vim._with({ env = { aaa = 'more inside' } }, get_state)
- after_inner = get_state()
- end)
- return {
- before = before, before_inner = before_inner,
- inner = inner,
- after_inner = after_inner, after = get_state(),
- }
- ]]
- eq('more inside', out.inner.aaa)
- eq('wow', out.inner.bbb)
- eq(out.before_inner, out.after_inner)
- eq(out.before, out.after)
- end)
- end)
- describe('`go` context', function()
- before_each(function()
- exec_lua [[
- vim.bo.commentstring = '## %s'
- vim.go.commentstring = '$$ %s'
- vim.wo.winblend = 25
- vim.go.winblend = 50
- vim.go.langmap = 'xy,yx'
- _G.get_state = function()
- return {
- bo = { cms = vim.bo.commentstring },
- wo = { winbl = vim.wo.winblend },
- go = {
- cms = vim.go.commentstring,
- winbl = vim.go.winblend,
- lmap = vim.go.langmap,
- },
- }
- end
- ]]
- end)
- it('works', function()
- local out = exec_lua [[
- local context = {
- go = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba' },
- }
- local before = get_state()
- local inner = vim._with(context, get_state)
- return { before = before, inner = inner, after = get_state() }
- ]]
- eq({
- bo = { cms = '## %s' },
- wo = { winbl = 25 },
- go = { cms = '-- %s', winbl = 75, lmap = 'ab,ba' },
- }, out.inner)
- eq(out.before, out.after)
- end)
- it('works with `eventignore`', function()
- -- This might be an issue if saving and restoring option context is done
- -- to account for triggering `OptionSet`, but in not a good way
- local out = exec_lua [[
- vim.go.eventignore = 'ModeChanged'
- local inner = vim._with({ go = { eventignore = 'CursorMoved' } }, function()
- return vim.go.eventignore
- end)
- return { inner = inner, after = vim.go.eventignore }
- ]]
- eq({ inner = 'CursorMoved', after = 'ModeChanged' }, out)
- end)
- it('restores only options from context', function()
- local out = exec_lua [[
- local context = { go = { langmap = 'ab,ba' } }
- local inner = vim._with(context, function()
- vim.go.commentstring = '!! %s'
- vim.go.winblend = 75
- vim.go.langmap = 'uv,vu'
- return get_state()
- end)
- return { inner = inner, after = get_state() }
- ]]
- eq({
- bo = { cms = '## %s' },
- wo = { winbl = 25 },
- go = { cms = '!! %s', winbl = 75, lmap = 'uv,vu' },
- }, out.inner)
- eq({
- bo = { cms = '## %s' },
- wo = { winbl = 25 },
- go = { cms = '!! %s', winbl = 75, lmap = 'xy,yx' },
- }, out.after)
- end)
- it('does not trigger events', function()
- exec_lua [[
- _G.test_events = {
- 'BufEnter', 'BufLeave', 'BufWinEnter', 'BufWinLeave', 'WinEnter', 'WinLeave'
- }
- _G.test_context = { go = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba' } }
- _G.test_trig_event = function() vim.cmd.new() end
- ]]
- assert_events_trigger()
- end)
- it('can be nested', function()
- local out = exec_lua [[
- local before, before_inner, after_inner = get_state(), nil, nil
- vim._with({ go = { langmap = 'ab,ba', commentstring = '-- %s' } }, function()
- before_inner = get_state()
- inner = vim._with({ go = { langmap = 'uv,vu' } }, get_state)
- after_inner = get_state()
- end)
- return {
- before = before, before_inner = before_inner,
- inner = inner,
- after_inner = after_inner, after = get_state(),
- }
- ]]
- eq('uv,vu', out.inner.go.lmap)
- eq('-- %s', out.inner.go.cms)
- eq(out.before_inner, out.after_inner)
- eq(out.before, out.after)
- end)
- end)
- describe('`hide` context', function()
- pending('works', function()
- local ok = pcall(
- exec_lua,
- [[
- vim.o.hidden = false
- vim.bo.modified = true
- local init_buf = api.nvim_get_current_buf()
- -- Should not produce error same as `vim.cmd('hide enew')`
- vim._with({ hide = true }, function()
- vim.cmd.enew()
- end)
- assert(api.nvim_get_current_buf() ~= init_buf)
- ]]
- )
- eq(true, ok)
- end)
- it('can be nested', function()
- local ok = pcall(
- exec_lua,
- [[
- vim.o.hidden = false
- vim.bo.modified = true
- -- Should produce error same as `vim.cmd.enew()`
- vim._with({ hide = true }, function()
- vim._with({ hide = false }, function()
- vim.cmd.enew()
- end)
- end)
- ]]
- )
- eq(false, ok)
- end)
- end)
- describe('`horizontal` context', function()
- local is_approx_eq = function(dim, id_1, id_2)
- local f = dim == 'height' and api.nvim_win_get_height or api.nvim_win_get_width
- return math.abs(f(id_1) - f(id_2)) <= 1
- end
- local win_id_1, win_id_2, win_id_3
- before_each(function()
- win_id_1 = api.nvim_get_current_win()
- command('wincmd v | wincmd 5>')
- win_id_2 = api.nvim_get_current_win()
- command('wincmd s | wincmd 5+')
- win_id_3 = api.nvim_get_current_win()
- eq(is_approx_eq('width', win_id_1, win_id_2), false)
- eq(is_approx_eq('height', win_id_3, win_id_2), false)
- end)
- pending('works', function()
- exec_lua [[
- -- Should be same as `vim.cmd('horizontal wincmd =')`
- vim._with({ horizontal = true }, function()
- vim.cmd.wincmd('=')
- end)
- ]]
- eq(is_approx_eq('width', win_id_1, win_id_2), true)
- eq(is_approx_eq('height', win_id_3, win_id_2), false)
- end)
- pending('can be nested', function()
- exec_lua [[
- -- Should be same as `vim.cmd.wincmd('=')`
- vim._with({ horizontal = true }, function()
- vim._with({ horizontal = false }, function()
- vim.cmd.wincmd('=')
- end)
- end)
- ]]
- eq(is_approx_eq('width', win_id_1, win_id_2), true)
- eq(is_approx_eq('height', win_id_3, win_id_2), true)
- end)
- end)
- describe('`keepalt` context', function()
- pending('works', function()
- local out = exec_lua [[
- vim.cmd('edit alt')
- vim.cmd('edit new')
- assert(fn.bufname('#') == 'alt')
- -- Should work as `vim.cmd('keepalt edit very-new')`
- vim._with({ keepalt = true }, function()
- vim.cmd.edit('very-new')
- end)
- return fn.bufname('#') == 'alt'
- ]]
- eq(true, out)
- end)
- it('can be nested', function()
- local out = exec_lua [[
- vim.cmd('edit alt')
- vim.cmd('edit new')
- assert(fn.bufname('#') == 'alt')
- -- Should work as `vim.cmd.edit('very-new')`
- vim._with({ keepalt = true }, function()
- vim._with({ keepalt = false }, function()
- vim.cmd.edit('very-new')
- end)
- end)
- return fn.bufname('#') == 'alt'
- ]]
- eq(false, out)
- end)
- end)
- describe('`keepjumps` context', function()
- pending('works', function()
- local out = exec_lua [[
- api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' })
- local jumplist_before = fn.getjumplist()
- -- Should work as `vim.cmd('keepjumps normal! Ggg')`
- vim._with({ keepjumps = true }, function()
- vim.cmd('normal! Ggg')
- end)
- return vim.deep_equal(jumplist_before, fn.getjumplist())
- ]]
- eq(true, out)
- end)
- it('can be nested', function()
- local out = exec_lua [[
- api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb', 'ccc' })
- local jumplist_before = fn.getjumplist()
- vim._with({ keepjumps = true }, function()
- vim._with({ keepjumps = false }, function()
- vim.cmd('normal! Ggg')
- end)
- end)
- return vim.deep_equal(jumplist_before, fn.getjumplist())
- ]]
- eq(false, out)
- end)
- end)
- describe('`keepmarks` context', function()
- pending('works', function()
- local out = exec_lua [[
- vim.cmd('set cpoptions+=R')
- api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' })
- api.nvim_buf_set_mark(0, 'm', 2, 2, {})
- -- Should be the same as `vim.cmd('keepmarks %!sort')`
- vim._with({ keepmarks = true }, function()
- vim.cmd('%!sort')
- end)
- return api.nvim_buf_get_mark(0, 'm')
- ]]
- eq({ 2, 2 }, out)
- end)
- it('can be nested', function()
- local out = exec_lua [[
- vim.cmd('set cpoptions+=R')
- api.nvim_buf_set_lines(0, 0, -1, false, { 'bbb', 'ccc', 'aaa' })
- api.nvim_buf_set_mark(0, 'm', 2, 2, {})
- vim._with({ keepmarks = true }, function()
- vim._with({ keepmarks = false }, function()
- vim.cmd('%!sort')
- end)
- end)
- return api.nvim_buf_get_mark(0, 'm')
- ]]
- eq({ 0, 2 }, out)
- end)
- end)
- describe('`keepatterns` context', function()
- pending('works', function()
- local out = exec_lua [[
- api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' })
- vim.cmd('/aaa')
- -- Should be the same as `vim.cmd('keeppatterns /bbb')`
- vim._with({ keeppatterns = true }, function()
- vim.cmd('/bbb')
- end)
- return fn.getreg('/')
- ]]
- eq('aaa', out)
- end)
- it('can be nested', function()
- local out = exec_lua [[
- api.nvim_buf_set_lines(0, 0, -1, false, { 'aaa', 'bbb' })
- vim.cmd('/aaa')
- vim._with({ keeppatterns = true }, function()
- vim._with({ keeppatterns = false }, function()
- vim.cmd('/bbb')
- end)
- end)
- return fn.getreg('/')
- ]]
- eq('bbb', out)
- end)
- end)
- describe('`lockmarks` context', function()
- it('works', function()
- local mark = exec_lua [[
- api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' })
- api.nvim_buf_set_mark(0, 'm', 2, 2, {})
- -- Should be same as `:lockmarks lua api.nvim_buf_set_lines(...)`
- vim._with({ lockmarks = true }, function()
- api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' })
- end)
- return api.nvim_buf_get_mark(0, 'm')
- ]]
- eq({ 2, 2 }, mark)
- end)
- it('can be nested', function()
- local mark = exec_lua [[
- api.nvim_buf_set_lines(0, 0, 0, false, { 'aaa', 'bbb', 'ccc' })
- api.nvim_buf_set_mark(0, 'm', 2, 2, {})
- vim._with({ lockmarks = true }, function()
- vim._with({ lockmarks = false }, function()
- api.nvim_buf_set_lines(0, 0, 2, false, { 'uuu', 'vvv', 'www' })
- end)
- end)
- return api.nvim_buf_get_mark(0, 'm')
- ]]
- eq({ 0, 2 }, mark)
- end)
- end)
- describe('`noautocmd` context', function()
- it('works', function()
- local out = exec_lua [[
- _G.n_events = 0
- vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1')
- -- Should be the same as `vim.cmd('noautocmd normal! vv')`
- vim._with({ noautocmd = true }, function()
- vim.cmd('normal! vv')
- end)
- return _G.n_events
- ]]
- eq(0, out)
- end)
- it('works with User events', function()
- local out = exec_lua [[
- _G.n_events = 0
- vim.cmd('au User MyEvent lua _G.n_events = _G.n_events + 1')
- -- Should be the same as `vim.cmd('noautocmd doautocmd User MyEvent')`
- vim._with({ noautocmd = true }, function()
- api.nvim_exec_autocmds('User', { pattern = 'MyEvent' })
- end)
- return _G.n_events
- ]]
- eq(0, out)
- end)
- pending('can be nested', function()
- local out = exec_lua [[
- _G.n_events = 0
- vim.cmd('au ModeChanged * lua _G.n_events = _G.n_events + 1')
- vim._with({ noautocmd = true }, function()
- vim._with({ noautocmd = false }, function()
- vim.cmd('normal! vv')
- end)
- end)
- return _G.n_events
- ]]
- eq(2, out)
- end)
- end)
- describe('`o` context', function()
- before_each(function()
- exec_lua [[
- _G.other_win, _G.cur_win = setup_windows()
- _G.other_buf, _G.cur_buf = setup_buffers()
- vim.bo[other_buf].commentstring = '## %s'
- vim.bo[cur_buf].commentstring = '// %s'
- vim.go.commentstring = '$$ %s'
- vim.bo[other_buf].undolevels = 100
- vim.bo[cur_buf].undolevels = 250
- vim.go.undolevels = 500
- vim.wo[other_win].virtualedit = 'block'
- vim.wo[cur_win].virtualedit = 'insert'
- vim.go.virtualedit = 'none'
- vim.wo[other_win].winblend = 10
- vim.wo[cur_win].winblend = 25
- vim.go.winblend = 50
- vim.go.langmap = 'xy,yx'
- _G.get_state = function()
- return {
- bo = {
- cms_cur = vim.bo[cur_buf].commentstring,
- cms_other = vim.bo[other_buf].commentstring,
- ul_cur = vim.bo[cur_buf].undolevels,
- ul_other = vim.bo[other_buf].undolevels,
- },
- wo = {
- ve_cur = vim.wo[cur_win].virtualedit,
- ve_other = vim.wo[other_win].virtualedit,
- winbl_cur = vim.wo[cur_win].winblend,
- winbl_other = vim.wo[other_win].winblend,
- },
- go = {
- cms = vim.go.commentstring,
- ul = vim.go.undolevels,
- ve = vim.go.virtualedit,
- winbl = vim.go.winblend,
- lmap = vim.go.langmap,
- },
- }
- end
- ]]
- end)
- it('works', function()
- local out = exec_lua [[
- local context = {
- o = {
- commentstring = '-- %s',
- undolevels = 0,
- virtualedit = 'all',
- winblend = 75,
- langmap = 'ab,ba',
- },
- }
- local before = get_state()
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_buf() == cur_buf)
- assert(api.nvim_get_current_win() == cur_win)
- return get_state()
- end)
- return { before = before, inner = inner, after = get_state() }
- ]]
- -- Options in context are set with `vim.o`, so usually both local
- -- and global values are affected. Yet all of them should be later
- -- restored to pre-context values.
- eq({
- bo = { cms_cur = '-- %s', cms_other = '## %s', ul_cur = -123456, ul_other = 100 },
- wo = { ve_cur = 'all', ve_other = 'block', winbl_cur = 75, winbl_other = 10 },
- go = { cms = '-- %s', ul = 0, ve = 'all', winbl = 75, lmap = 'ab,ba' },
- }, out.inner)
- eq(out.before, out.after)
- end)
- it('sets options in `buf` context', function()
- local out = exec_lua [[
- local context = { buf = other_buf, o = { commentstring = '-- %s', undolevels = 0 } }
- local before = get_state()
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_buf() == other_buf)
- return get_state()
- end)
- return { before = before, inner = inner, after = get_state() }
- ]]
- eq({
- bo = { cms_cur = '// %s', cms_other = '-- %s', ul_cur = 250, ul_other = -123456 },
- wo = { ve_cur = 'insert', ve_other = 'block', winbl_cur = 25, winbl_other = 10 },
- -- Global `winbl` inside context ideally should be untouched and equal
- -- to 50. It seems to be equal to 0 because `context.buf` uses
- -- `aucmd_prepbuf` C approach which has no guarantees about window or
- -- window option values inside context.
- go = { cms = '-- %s', ul = 0, ve = 'none', winbl = 0, lmap = 'xy,yx' },
- }, out.inner)
- eq(out.before, out.after)
- end)
- it('sets options in `win` context', function()
- local out = exec_lua [[
- local context = { win = other_win, o = { winblend = 75, virtualedit = 'all' } }
- local before = get_state()
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_win() == other_win)
- return get_state()
- end)
- return { before = before, inner = inner, after = get_state() }
- ]]
- eq({
- bo = { cms_cur = '// %s', cms_other = '## %s', ul_cur = 250, ul_other = 100 },
- wo = { winbl_cur = 25, winbl_other = 75, ve_cur = 'insert', ve_other = 'all' },
- go = { cms = '$$ %s', ul = 500, winbl = 75, ve = 'all', lmap = 'xy,yx' },
- }, out.inner)
- eq(out.before, out.after)
- end)
- it('restores only options from context', function()
- local out = exec_lua [[
- local context = { o = { undolevels = 0, winblend = 75, langmap = 'ab,ba' } }
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_buf() == cur_buf)
- assert(api.nvim_get_current_win() == cur_win)
- vim.o.commentstring = '!! %s'
- vim.o.undolevels = 750
- vim.o.virtualedit = 'onemore'
- vim.o.winblend = 99
- vim.o.langmap = 'uv,vu'
- return get_state()
- end)
- return { inner = inner, after = get_state() }
- ]]
- eq({
- bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = -123456, ul_other = 100 },
- wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 99, winbl_other = 10 },
- go = { cms = '!! %s', ul = 750, ve = 'onemore', winbl = 99, lmap = 'uv,vu' },
- }, out.inner)
- eq({
- bo = { cms_cur = '!! %s', cms_other = '## %s', ul_cur = 250, ul_other = 100 },
- wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 25, winbl_other = 10 },
- go = { cms = '!! %s', ul = 500, ve = 'onemore', winbl = 50, lmap = 'xy,yx' },
- }, out.after)
- end)
- it('does not trigger events', function()
- exec_lua [[
- _G.test_events = {
- 'BufEnter', 'BufLeave', 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave'
- }
- _G.test_context = { o = { undolevels = 0, winblend = 75, langmap = 'ab,ba' } }
- _G.test_trig_event = function() vim.cmd.new() end
- ]]
- assert_events_trigger()
- end)
- it('can be nested', function()
- local out = exec_lua [[
- local before, before_inner, after_inner = get_state(), nil, nil
- local cxt_o = { commentstring = '-- %s', winblend = 75, langmap = 'ab,ba', undolevels = 0 }
- vim._with({ o = cxt_o }, function()
- before_inner = get_state()
- local inner_cxt_o = { commentstring = '!! %s', winblend = 99, langmap = 'uv,vu' }
- inner = vim._with({ o = inner_cxt_o }, get_state)
- after_inner = get_state()
- end)
- return {
- before = before, before_inner = before_inner,
- inner = inner,
- after_inner = after_inner, after = get_state(),
- }
- ]]
- eq('!! %s', out.inner.bo.cms_cur)
- eq(99, out.inner.wo.winbl_cur)
- eq('uv,vu', out.inner.go.lmap)
- eq(0, out.inner.go.ul)
- eq(out.before_inner, out.after_inner)
- eq(out.before, out.after)
- end)
- end)
- describe('`sandbox` context', function()
- it('works', function()
- local ok, err = pcall(
- exec_lua,
- [[
- -- Should work as `vim.cmd('sandbox call append(0, "aaa")')`
- vim._with({ sandbox = true }, function()
- fn.append(0, 'aaa')
- end)
- ]]
- )
- eq(false, ok)
- matches('Not allowed in sandbox', err)
- end)
- it('can NOT be nested', function()
- -- This behavior is intentionally different from other flags as allowing
- -- disabling `sandbox` from nested function seems to be against the point
- -- of using `sandbox` context in the first place
- local ok, err = pcall(
- exec_lua,
- [[
- vim._with({ sandbox = true }, function()
- vim._with({ sandbox = false }, function()
- fn.append(0, 'aaa')
- end)
- end)
- ]]
- )
- eq(false, ok)
- matches('Not allowed in sandbox', err)
- end)
- end)
- describe('`silent` context', function()
- it('works', function()
- exec_lua [[
- -- Should be same as `vim.cmd('silent lua print("aaa")')`
- vim._with({ silent = true }, function() print('aaa') end)
- ]]
- eq('', exec_capture('messages'))
- exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echomsg('"bbb"') end) ]]
- eq('', exec_capture('messages'))
- local screen = Screen.new(20, 5)
- screen:set_default_attr_ids {
- [1] = { bold = true, reverse = true },
- [2] = { bold = true, foreground = Screen.colors.Blue },
- }
- exec_lua [[ vim._with({ silent = true }, function() vim.cmd.echo('"ccc"') end) ]]
- screen:expect [[
- ^ |
- {2:~ }|*3
- |
- ]]
- end)
- pending('can be nested', function()
- exec_lua [[ vim._with({ silent = true }, function()
- vim._with({ silent = false }, function()
- print('aaa')
- end)
- end)]]
- eq('aaa', exec_capture('messages'))
- end)
- end)
- describe('`unsilent` context', function()
- it('works', function()
- exec_lua [[
- _G.f = function()
- -- Should be same as `vim.cmd('unsilent lua print("aaa")')`
- vim._with({ unsilent = true }, function() print('aaa') end)
- end
- ]]
- command('silent lua f()')
- eq('aaa', exec_capture('messages'))
- end)
- pending('can be nested', function()
- exec_lua [[
- _G.f = function()
- vim._with({ unsilent = true }, function()
- vim._with({ unsilent = false }, function() print('aaa') end)
- end)
- end
- ]]
- command('silent lua f()')
- eq('', exec_capture('messages'))
- end)
- end)
- describe('`win` context', function()
- it('works', function()
- local out = exec_lua [[
- local other_win, cur_win = setup_windows()
- local inner = vim._with({ win = other_win }, function()
- return api.nvim_get_current_win()
- end)
- return { inner == other_win, api.nvim_get_current_win() == cur_win }
- ]]
- eq({ true, true }, out)
- end)
- it('does not trigger events', function()
- exec_lua [[
- _G.test_events = { 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' }
- _G.test_context = { win = other_win }
- _G.test_trig_event = function() vim.cmd.new() end
- ]]
- assert_events_trigger()
- end)
- it('can access window options', function()
- local out = exec_lua [[
- local other_win, cur_win = setup_windows()
- vim.wo[other_win].winblend = 10
- vim.wo[cur_win].winblend = 25
- vim._with({ win = other_win }, function()
- vim.cmd.setlocal('winblend=0')
- end)
- return vim.wo[other_win].winblend == 0 and vim.wo[cur_win].winblend == 25
- ]]
- eq(true, out)
- end)
- it('works with different kinds of windows', function()
- exec_lua [[
- local assert_win = function(win)
- vim._with({ win = win }, function()
- assert(api.nvim_get_current_win() == win)
- end)
- end
- -- Current
- assert_win(api.nvim_get_current_win())
- -- Not visible
- local other_win, cur_win = setup_windows()
- vim.cmd.tabnew()
- assert_win(other_win)
- -- Floating
- local float_win = api.nvim_open_win(
- api.nvim_create_buf(false, true),
- false,
- { relative = 'editor', row = 1, col = 1, height = 5, width = 5}
- )
- assert_win(float_win)
- ]]
- end)
- it('does not cause ml_get errors with invalid visual selection', function()
- exec_lua [[
- local feedkeys = function(keys) api.nvim_feedkeys(vim.keycode(keys), 'txn', false) end
- -- Add lines to the current buffer and make another window looking into an empty buffer.
- local win_empty, win_lines = setup_windows()
- api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b', 'c' })
- -- Start Visual in current window, redraw in other window with fewer lines.
- -- Should be fixed by vim-patch:8.2.4018.
- feedkeys('G<C-V>')
- vim._with({ win = win_empty }, function() vim.cmd.redraw() end)
- -- Start Visual in current window, extend it in other window with more lines.
- -- Fixed for win_execute by vim-patch:8.2.4026, but nvim_win_call should also not be affected.
- feedkeys('<Esc>gg')
- api.nvim_set_current_win(win_empty)
- feedkeys('gg<C-V>')
- vim._with({ win = win_lines }, function() feedkeys('G<C-V>') end)
- vim.cmd.redraw()
- ]]
- end)
- it('can be nested', function()
- exec_lua [[
- local other_win, cur_win = setup_windows()
- vim._with({ win = other_win }, function()
- assert(api.nvim_get_current_win() == other_win)
- inner = vim._with({ win = cur_win }, function()
- assert(api.nvim_get_current_win() == cur_win)
- end)
- assert(api.nvim_get_current_win() == other_win)
- end)
- assert(api.nvim_get_current_win() == cur_win)
- ]]
- end)
- it('updates ruler if cursor moved', function()
- local screen = Screen.new(30, 5)
- screen:set_default_attr_ids {
- [1] = { reverse = true },
- [2] = { bold = true, reverse = true },
- }
- exec_lua [[
- vim.opt.ruler = true
- local lines = {}
- for i = 0, 499 do lines[#lines + 1] = tostring(i) end
- api.nvim_buf_set_lines(0, 0, -1, true, lines)
- api.nvim_win_set_cursor(0, { 20, 0 })
- vim.cmd 'split'
- _G.win = api.nvim_get_current_win()
- vim.cmd "wincmd w | redraw"
- ]]
- screen:expect [[
- 19 |
- {1:[No Name] [+] 20,1 3%}|
- ^19 |
- {2:[No Name] [+] 20,1 3%}|
- |
- ]]
- exec_lua [[
- vim._with({ win = win }, function() api.nvim_win_set_cursor(0, { 100, 0 }) end)
- vim.cmd "redraw"
- ]]
- screen:expect [[
- 99 |
- {1:[No Name] [+] 100,1 19%}|
- ^19 |
- {2:[No Name] [+] 20,1 3%}|
- |
- ]]
- end)
- it('layout in current tabpage does not affect windows in others', function()
- command('tab split')
- local t2_move_win = api.nvim_get_current_win()
- command('vsplit')
- local t2_other_win = api.nvim_get_current_win()
- command('tabprevious')
- matches('E36: Not enough room$', pcall_err(command, 'execute "split|"->repeat(&lines)'))
- command('vsplit')
- exec_lua('vim._with({ win = ... }, function() vim.cmd.wincmd "J" end)', t2_move_win)
- eq({ 'col', { { 'leaf', t2_other_win }, { 'leaf', t2_move_win } } }, fn.winlayout(2))
- end)
- end)
- describe('`wo` context', function()
- before_each(function()
- exec_lua [[
- _G.other_win, _G.cur_win = setup_windows()
- -- 'virtualedit' is global or local to window (global-local) and string
- vim.wo[other_win].virtualedit = 'block'
- vim.wo[cur_win].virtualedit = 'insert'
- vim.go.virtualedit = 'none'
- -- 'winblend' is local to window and number
- vim.wo[other_win].winblend = 10
- vim.wo[cur_win].winblend = 25
- vim.go.winblend = 50
- _G.get_state = function()
- return {
- wo = {
- ve_cur = vim.wo[cur_win].virtualedit,
- ve_other = vim.wo[other_win].virtualedit,
- winbl_cur = vim.wo[cur_win].winblend,
- winbl_other = vim.wo[other_win].winblend,
- },
- go = {
- ve = vim.go.virtualedit,
- winbl = vim.go.winblend,
- },
- }
- end
- ]]
- end)
- it('works', function()
- local out = exec_lua [[
- local context = { wo = { virtualedit = 'all', winblend = 75 } }
- local before = get_state()
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_win() == cur_win)
- return get_state()
- end)
- return { before = before, inner = inner, after = get_state() }
- ]]
- eq({
- wo = { ve_cur = 'all', ve_other = 'block', winbl_cur = 75, winbl_other = 10 },
- go = { ve = 'none', winbl = 75 },
- }, out.inner)
- eq(out.before, out.after)
- end)
- it('sets options in `win` context', function()
- local out = exec_lua [[
- local context = { win = other_win, wo = { virtualedit = 'all', winblend = 75 } }
- local before = get_state()
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_win() == other_win)
- return get_state()
- end)
- return { before = before, inner = inner, after = get_state() }
- ]]
- eq({
- wo = { ve_cur = 'insert', ve_other = 'all', winbl_cur = 25, winbl_other = 75 },
- go = { ve = 'none', winbl = 75 },
- }, out.inner)
- eq(out.before, out.after)
- end)
- it('restores only options from context', function()
- local out = exec_lua [[
- local context = { wo = { winblend = 75 } }
- local inner = vim._with(context, function()
- assert(api.nvim_get_current_win() == cur_win)
- vim.wo[cur_win].virtualedit = 'onemore'
- vim.wo[cur_win].winblend = 99
- return get_state()
- end)
- return { inner = inner, after = get_state() }
- ]]
- eq({
- wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 99, winbl_other = 10 },
- go = { ve = 'none', winbl = 99 },
- }, out.inner)
- eq({
- wo = { ve_cur = 'onemore', ve_other = 'block', winbl_cur = 25, winbl_other = 10 },
- go = { ve = 'none', winbl = 50 },
- }, out.after)
- end)
- it('does not trigger events', function()
- exec_lua [[
- _G.test_events = { 'WinEnter', 'WinLeave', 'BufWinEnter', 'BufWinLeave' }
- _G.test_context = { wo = { winblend = 75 } }
- _G.test_trig_event = function() vim.cmd.new() end
- ]]
- assert_events_trigger()
- end)
- it('can be nested', function()
- local out = exec_lua [[
- local before, before_inner, after_inner = get_state(), nil, nil
- vim._with({ wo = { winblend = 75, virtualedit = 'all' } }, function()
- before_inner = get_state()
- inner = vim._with({ wo = { winblend = 99 } }, get_state)
- after_inner = get_state()
- end)
- return {
- before = before, before_inner = before_inner,
- inner = inner,
- after_inner = after_inner, after = get_state(),
- }
- ]]
- eq(99, out.inner.wo.winbl_cur)
- eq('all', out.inner.wo.ve_cur)
- eq(out.before_inner, out.after_inner)
- eq(out.before, out.after)
- end)
- end)
- it('returns what callback returns', function()
- local out_verify = exec_lua [[
- out = { vim._with({}, function()
- return 'a', 2, nil, { 4 }, function() end
- end) }
- return {
- out[1] == 'a', out[2] == 2, out[3] == nil,
- vim.deep_equal(out[4], { 4 }),
- type(out[5]) == 'function',
- vim.tbl_count(out),
- }
- ]]
- eq({ true, true, true, true, true, 4 }, out_verify)
- end)
- it('can return values by reference', function()
- local out = exec_lua [[
- local val = { 4, 10 }
- local ref = vim._with({}, function() return val end)
- ref[1] = 7
- return val
- ]]
- eq({ 7, 10 }, out)
- end)
- it('can not work with conflicting `buf` and `win`', function()
- local out = exec_lua [[
- local other_buf, cur_buf = setup_buffers()
- local other_win, cur_win = setup_windows()
- assert(api.nvim_win_get_buf(other_win) ~= other_buf)
- local _, err = pcall(vim._with, { buf = other_buf, win = other_win }, function() end)
- return err
- ]]
- matches('Can not set both `buf` and `win`', out)
- end)
- it('works with several contexts at once', function()
- local out = exec_lua [[
- local other_buf, cur_buf = setup_buffers()
- vim.bo[other_buf].commentstring = '## %s'
- api.nvim_buf_set_lines(other_buf, 0, -1, false, { 'aaa', 'bbb', 'ccc' })
- api.nvim_buf_set_mark(other_buf, 'm', 2, 2, {})
- vim.go.commentstring = '// %s'
- vim.go.langmap = 'xy,yx'
- local context = {
- buf = other_buf,
- bo = { commentstring = '-- %s' },
- go = { langmap = 'ab,ba' },
- lockmarks = true,
- }
- local inner = vim._with(context, function()
- api.nvim_buf_set_lines(0, 0, -1, false, { 'uuu', 'vvv', 'www' })
- return {
- buf = api.nvim_get_current_buf(),
- bo = { cms = vim.bo.commentstring },
- go = { cms = vim.go.commentstring, lmap = vim.go.langmap },
- mark = api.nvim_buf_get_mark(0, 'm')
- }
- end)
- local after = {
- buf = api.nvim_get_current_buf(),
- bo = { cms = vim.bo[other_buf].commentstring },
- go = { cms = vim.go.commentstring, lmap = vim.go.langmap },
- mark = api.nvim_buf_get_mark(other_buf, 'm')
- }
- return {
- context_buf = other_buf, cur_buf = cur_buf,
- inner = inner, after = after
- }
- ]]
- eq({
- buf = out.context_buf,
- bo = { cms = '-- %s' },
- go = { cms = '// %s', lmap = 'ab,ba' },
- mark = { 2, 2 },
- }, out.inner)
- eq({
- buf = out.cur_buf,
- bo = { cms = '## %s' },
- go = { cms = '// %s', lmap = 'xy,yx' },
- mark = { 2, 2 },
- }, out.after)
- end)
- it('works with same option set in different contexts', function()
- local out = exec_lua [[
- local get_state = function()
- return {
- bo = { cms = vim.bo.commentstring },
- wo = { ve = vim.wo.virtualedit },
- go = { cms = vim.go.commentstring, ve = vim.go.virtualedit },
- }
- end
- vim.bo.commentstring = '// %s'
- vim.go.commentstring = '$$ %s'
- vim.wo.virtualedit = 'insert'
- vim.go.virtualedit = 'none'
- local before = get_state()
- local context_no_go = {
- o = { commentstring = '-- %s', virtualedit = 'all' },
- bo = { commentstring = '!! %s' },
- wo = { virtualedit = 'onemore' },
- }
- local inner_no_go = vim._with(context_no_go, get_state)
- local middle = get_state()
- local context_with_go = {
- o = { commentstring = '-- %s', virtualedit = 'all' },
- bo = { commentstring = '!! %s' },
- wo = { virtualedit = 'onemore' },
- go = { commentstring = '@@ %s', virtualedit = 'block' },
- }
- local inner_with_go = vim._with(context_with_go, get_state)
- return {
- before = before,
- inner_no_go = inner_no_go,
- middle = middle,
- inner_with_go = inner_with_go,
- after = get_state(),
- }
- ]]
- -- Should prefer explicit local scopes instead of `o`
- eq({
- bo = { cms = '!! %s' },
- wo = { ve = 'onemore' },
- go = { cms = '-- %s', ve = 'all' },
- }, out.inner_no_go)
- eq(out.before, out.middle)
- -- Should prefer explicit global scopes instead of `o`
- eq({
- bo = { cms = '!! %s' },
- wo = { ve = 'onemore' },
- go = { cms = '@@ %s', ve = 'block' },
- }, out.inner_with_go)
- eq(out.middle, out.after)
- end)
- pending('can forward command modifiers to user command', function()
- local out = exec_lua [[
- local test_flags = {
- 'emsg_silent',
- 'hide',
- 'keepalt',
- 'keepjumps',
- 'keepmarks',
- 'keeppatterns',
- 'lockmarks',
- 'noautocmd',
- 'silent',
- 'unsilent',
- }
- local used_smods
- local command = function(data)
- used_smods = data.smods
- end
- api.nvim_create_user_command('DummyLog', command, {})
- local res = {}
- for _, flag in ipairs(test_flags) do
- used_smods = nil
- vim._with({ [flag] = true }, function() vim.cmd('DummyLog') end)
- res[flag] = used_smods[flag]
- end
- return res
- ]]
- for k, v in pairs(out) do
- eq({ k, true }, { k, v })
- end
- end)
- it('handles error in callback', function()
- -- Should still restore initial context
- local out_buf = exec_lua [[
- local other_buf, cur_buf = setup_buffers()
- vim.bo[other_buf].commentstring = '## %s'
- local context = { buf = other_buf, bo = { commentstring = '-- %s' } }
- local ok, err = pcall(vim._with, context, function() error('Oops buf', 0) end)
- return {
- ok,
- err,
- api.nvim_get_current_buf() == cur_buf,
- vim.bo[other_buf].commentstring,
- }
- ]]
- eq({ false, 'Oops buf', true, '## %s' }, out_buf)
- local out_win = exec_lua [[
- local other_win, cur_win = setup_windows()
- vim.wo[other_win].winblend = 25
- local context = { win = other_win, wo = { winblend = 50 } }
- local ok, err = pcall(vim._with, context, function() error('Oops win', 0) end)
- return {
- ok,
- err,
- api.nvim_get_current_win() == cur_win,
- vim.wo[other_win].winblend,
- }
- ]]
- eq({ false, 'Oops win', true, 25 }, out_win)
- end)
- it('handles not supported option', function()
- local out = exec_lua [[
- -- Should still restore initial state
- vim.bo.commentstring = '## %s'
- local context = { o = { commentstring = '-- %s' }, bo = { winblend = 10 } }
- local ok, err = pcall(vim._with, context, function() end)
- return { ok = ok, err = err, cms = vim.bo.commentstring }
- ]]
- eq(false, out.ok)
- matches('window.*option.*winblend', out.err)
- eq('## %s', out.cms)
- end)
- it('validates arguments', function()
- exec_lua [[
- _G.get_error = function(...)
- local _, err = pcall(vim._with, ...)
- return err or ''
- end
- ]]
- local get_error = function(string_args)
- return exec_lua('return get_error(' .. string_args .. ')')
- end
- matches('context.*table', get_error("'a', function() end"))
- matches('f.*function', get_error('{}, 1'))
- local assert_context = function(bad_context, expected_type)
- local bad_field = vim.tbl_keys(bad_context)[1]
- matches(
- 'context%.' .. bad_field .. '.*' .. expected_type,
- get_error(vim.inspect(bad_context) .. ', function() end')
- )
- end
- assert_context({ bo = 1 }, 'table')
- assert_context({ buf = 'a' }, 'number')
- assert_context({ emsg_silent = 1 }, 'boolean')
- assert_context({ env = 1 }, 'table')
- assert_context({ go = 1 }, 'table')
- assert_context({ hide = 1 }, 'boolean')
- assert_context({ keepalt = 1 }, 'boolean')
- assert_context({ keepjumps = 1 }, 'boolean')
- assert_context({ keepmarks = 1 }, 'boolean')
- assert_context({ keeppatterns = 1 }, 'boolean')
- assert_context({ lockmarks = 1 }, 'boolean')
- assert_context({ noautocmd = 1 }, 'boolean')
- assert_context({ o = 1 }, 'table')
- assert_context({ sandbox = 1 }, 'boolean')
- assert_context({ silent = 1 }, 'boolean')
- assert_context({ unsilent = 1 }, 'boolean')
- assert_context({ win = 'a' }, 'number')
- assert_context({ wo = 1 }, 'table')
- matches('Invalid buffer', get_error('{ buf = -1 }, function() end'))
- matches('Invalid window', get_error('{ win = -1 }, function() end'))
- end)
- end)
|