marks_spec.lua (13110B)
1 -- ShaDa marks saving/reading support 2 local t = require('test.testutil') 3 local n = require('test.functional.testnvim')() 4 local t_shada = require('test.functional.shada.testutil') 5 6 local api, nvim_command, fn, eq = n.api, n.command, n.fn, t.eq 7 local feed = n.feed 8 local exc_exec, exec_capture = n.exc_exec, n.exec_capture 9 local expect_exit = n.expect_exit 10 11 local reset, clear = t_shada.reset, t_shada.clear 12 13 local nvim_current_line = function() 14 return api.nvim_win_get_cursor(0)[1] 15 end 16 17 describe('ShaDa support code', function() 18 local testfilename = 'Xtestfile-functional-shada-marks' 19 local testfilename_2 = 'Xtestfile-functional-shada-marks-2' 20 local non_existent_testfilename = testfilename .. '.nonexistent' 21 before_each(function() 22 reset() 23 os.remove(non_existent_testfilename) 24 local fd = io.open(testfilename, 'w') 25 fd:write('test\n') 26 fd:write('test2\n') 27 fd:close() 28 fd = io.open(testfilename_2, 'w') 29 fd:write('test3\n') 30 fd:write('test4\n') 31 fd:close() 32 end) 33 after_each(function() 34 clear() 35 os.remove(testfilename) 36 os.remove(testfilename_2) 37 end) 38 39 it('is able to dump and read back global mark', function() 40 nvim_command('edit ' .. testfilename) 41 nvim_command('mark A') 42 nvim_command('2') 43 nvim_command('kB') 44 nvim_command('wshada') 45 reset() 46 nvim_command('rshada') 47 nvim_command('normal! `A') 48 eq(testfilename, fn.fnamemodify(api.nvim_buf_get_name(0), ':t')) 49 eq(1, nvim_current_line()) 50 nvim_command('normal! `B') 51 eq(2, nvim_current_line()) 52 end) 53 54 it('can dump and read back numbered marks', function() 55 local function move(cmd) 56 feed(cmd) 57 nvim_command('wshada') 58 end 59 nvim_command('edit ' .. testfilename) 60 move('l') 61 move('l') 62 move('j') 63 move('l') 64 move('l') 65 nvim_command('edit ' .. testfilename_2) 66 move('l') 67 move('l') 68 move('j') 69 move('l') 70 move('l') 71 -- we have now populated marks 0 through 9 72 nvim_command('edit ' .. testfilename) 73 feed('gg0') 74 -- during shada save on exit, mark 0 will become the current position, 75 -- 9 will be removed, and all other marks shifted 76 expect_exit(nvim_command, 'qall') 77 reset() 78 nvim_command('edit ' .. testfilename) 79 nvim_command('edit ' .. testfilename_2) 80 local marklist = fn.getmarklist() 81 for _, mark in ipairs(marklist) do 82 mark.file = fn.fnamemodify(mark.file, ':t') 83 end 84 eq({ 85 { 86 file = testfilename, 87 mark = "'0", 88 pos = { 1, 1, 1, 0 }, 89 }, 90 { 91 file = testfilename_2, 92 mark = "'1", 93 pos = { 2, 2, 5, 0 }, 94 }, 95 { 96 file = testfilename_2, 97 mark = "'2", 98 pos = { 2, 2, 4, 0 }, 99 }, 100 { 101 file = testfilename_2, 102 mark = "'3", 103 pos = { 2, 2, 3, 0 }, 104 }, 105 { 106 file = testfilename_2, 107 mark = "'4", 108 pos = { 2, 1, 3, 0 }, 109 }, 110 { 111 file = testfilename_2, 112 mark = "'5", 113 pos = { 2, 1, 2, 0 }, 114 }, 115 { 116 file = testfilename, 117 mark = "'6", 118 pos = { 1, 2, 5, 0 }, 119 }, 120 { 121 file = testfilename, 122 mark = "'7", 123 pos = { 1, 2, 4, 0 }, 124 }, 125 { 126 file = testfilename, 127 mark = "'8", 128 pos = { 1, 2, 3, 0 }, 129 }, 130 { 131 file = testfilename, 132 mark = "'9", 133 pos = { 1, 1, 3, 0 }, 134 }, 135 }, marklist) 136 end) 137 138 it('does not dump global or numbered marks with `f0` in shada', function() 139 nvim_command('set shada+=f0') 140 nvim_command('edit ' .. testfilename) 141 nvim_command('mark A') 142 nvim_command('2') 143 nvim_command('wshada') 144 reset() 145 nvim_command('language C') 146 eq('Vim(normal):E20: Mark not set', exc_exec('normal! `A')) 147 eq('Vim(normal):E20: Mark not set', exc_exec('normal! `0')) 148 end) 149 150 it("restores global and numbered marks even with `'0` and `f0` in shada", function() 151 nvim_command('edit ' .. testfilename) 152 nvim_command('mark A') 153 nvim_command('2') 154 nvim_command('wshada') 155 reset("set shada='0,f0") 156 nvim_command('language C') 157 nvim_command('normal! `A') 158 eq(testfilename, fn.fnamemodify(api.nvim_buf_get_name(0), ':t')) 159 eq(1, nvim_current_line()) 160 nvim_command('normal! `0') 161 eq(testfilename, fn.fnamemodify(api.nvim_buf_get_name(0), ':t')) 162 eq(2, nvim_current_line()) 163 end) 164 165 it('is able to dump and read back local mark', function() 166 nvim_command('edit ' .. testfilename) 167 nvim_command('mark a') 168 nvim_command('2') 169 nvim_command('kb') 170 expect_exit(nvim_command, 'qall') 171 reset() 172 nvim_command('edit ' .. testfilename) 173 nvim_command('normal! `a') 174 eq(testfilename, fn.fnamemodify(api.nvim_buf_get_name(0), ':t')) 175 eq(1, nvim_current_line()) 176 nvim_command('normal! `b') 177 eq(2, nvim_current_line()) 178 end) 179 180 it('is able to dump and read back mark "', function() 181 nvim_command('edit ' .. testfilename) 182 nvim_command('2') 183 expect_exit(nvim_command, 'qall') 184 reset() 185 nvim_command('edit ' .. testfilename) 186 nvim_command('normal! `"') 187 eq(2, nvim_current_line()) 188 end) 189 190 it('is able to dump and read back mark " from a closed tab', function() 191 nvim_command('edit ' .. testfilename) 192 nvim_command('tabedit ' .. testfilename_2) 193 nvim_command('2') 194 nvim_command('q!') 195 expect_exit(nvim_command, 'qall') 196 reset() 197 nvim_command('edit ' .. testfilename_2) 198 nvim_command('normal! `"') 199 eq(2, nvim_current_line()) 200 end) 201 202 it('is able to populate v:oldfiles', function() 203 nvim_command('edit ' .. testfilename) 204 local tf_full = api.nvim_buf_get_name(0) 205 nvim_command('edit ' .. testfilename_2) 206 local tf_full_2 = api.nvim_buf_get_name(0) 207 expect_exit(nvim_command, 'qall') 208 reset() 209 local oldfiles = api.nvim_get_vvar('oldfiles') 210 table.sort(oldfiles) 211 eq(2, #oldfiles) 212 eq(testfilename, oldfiles[1]:sub(-#testfilename)) 213 eq(testfilename_2, oldfiles[2]:sub(-#testfilename_2)) 214 eq(tf_full, oldfiles[1]) 215 eq(tf_full_2, oldfiles[2]) 216 nvim_command('rshada!') 217 oldfiles = api.nvim_get_vvar('oldfiles') 218 table.sort(oldfiles) 219 eq(2, #oldfiles) 220 eq(testfilename, oldfiles[1]:sub(-#testfilename)) 221 eq(testfilename_2, oldfiles[2]:sub(-#testfilename_2)) 222 eq(tf_full, oldfiles[1]) 223 eq(tf_full_2, oldfiles[2]) 224 end) 225 226 it('is able to dump and restore jump list', function() 227 nvim_command('edit ' .. testfilename_2) 228 nvim_command('normal! G') 229 nvim_command('normal! gg') 230 nvim_command('edit ' .. testfilename) 231 nvim_command('normal! G') 232 nvim_command('normal! gg') 233 nvim_command('enew') 234 nvim_command('normal! gg') 235 local saved = exec_capture('jumps') 236 expect_exit(nvim_command, 'qall') 237 reset() 238 eq(saved, exec_capture('jumps')) 239 end) 240 241 it("does not dump jumplist if `'0` in shada", function() 242 local empty_jumps = exec_capture('jumps') 243 nvim_command("set shada='0") 244 nvim_command('edit ' .. testfilename_2) 245 nvim_command('normal! G') 246 nvim_command('normal! gg') 247 nvim_command('edit ' .. testfilename) 248 nvim_command('normal! G') 249 nvim_command('normal! gg') 250 nvim_command('enew') 251 nvim_command('normal! gg') 252 expect_exit(nvim_command, 'qall') 253 reset() 254 eq(empty_jumps, exec_capture('jumps')) 255 end) 256 257 it("does read back jumplist even with `'0` in shada", function() 258 nvim_command('edit ' .. testfilename_2) 259 nvim_command('normal! G') 260 nvim_command('normal! gg') 261 nvim_command('edit ' .. testfilename) 262 nvim_command('normal! G') 263 nvim_command('normal! gg') 264 nvim_command('enew') 265 nvim_command('normal! gg') 266 local saved = exec_capture('jumps') 267 expect_exit(nvim_command, 'qall') 268 reset("set shada='0") 269 eq(saved, exec_capture('jumps')) 270 end) 271 272 it('when dumping jump list also dumps current position', function() 273 nvim_command('edit ' .. testfilename) 274 nvim_command('normal! G') 275 nvim_command('split ' .. testfilename_2) 276 nvim_command('normal! G') 277 nvim_command('wshada') 278 nvim_command('quit') 279 nvim_command('rshada') 280 nvim_command('normal! \15') -- <C-o> 281 eq(testfilename_2, fn.bufname('%')) 282 eq({ 2, 0 }, api.nvim_win_get_cursor(0)) 283 end) 284 285 it('is able to dump and restore jump list with different times', function() 286 nvim_command('edit ' .. testfilename_2) 287 nvim_command('sleep 10m') 288 nvim_command('normal! G') 289 nvim_command('sleep 10m') 290 nvim_command('normal! gg') 291 nvim_command('sleep 10m') 292 nvim_command('edit ' .. testfilename) 293 nvim_command('sleep 10m') 294 nvim_command('normal! G') 295 nvim_command('sleep 10m') 296 nvim_command('normal! gg') 297 expect_exit(nvim_command, 'qall') 298 reset() 299 nvim_command('redraw') 300 nvim_command('edit ' .. testfilename) 301 eq(testfilename, fn.bufname('%')) 302 eq(1, nvim_current_line()) 303 nvim_command('execute "normal! \\<C-o>"') 304 eq(testfilename, fn.bufname('%')) 305 eq(2, nvim_current_line()) 306 nvim_command('execute "normal! \\<C-o>"') 307 eq(testfilename_2, fn.bufname('%')) 308 eq(1, nvim_current_line()) 309 nvim_command('execute "normal! \\<C-o>"') 310 eq(testfilename_2, fn.bufname('%')) 311 eq(2, nvim_current_line()) 312 nvim_command('execute "normal! \\<C-o>"') 313 eq(testfilename_2, fn.bufname('%')) 314 eq(2, nvim_current_line()) 315 end) 316 317 it('is able to dump and restore change list', function() 318 nvim_command('edit ' .. testfilename) 319 nvim_command('normal! Gra') 320 nvim_command('normal! ggrb') 321 expect_exit(nvim_command, 'qall!') 322 reset() 323 nvim_command('edit ' .. testfilename) 324 nvim_command('normal! Gg;') 325 -- Note: without “sync” “commands” test has good changes to fail for unknown 326 -- reason (in first eq expected 1 is compared with 2). Any command inserted 327 -- causes this to work properly. 328 nvim_command('" sync') 329 eq(1, nvim_current_line()) 330 nvim_command('normal! g;') 331 nvim_command('" sync 2') 332 eq(2, nvim_current_line()) 333 end) 334 335 -- -c temporary sets lnum to zero to make `+/pat` work, so calling setpcmark() 336 -- during -c used to add item with zero lnum to jump list. 337 it('does not create incorrect file for non-existent buffers when writing from -c', function() 338 local p = n.spawn_wait { 339 args_rm = { 340 '-i', 341 '--embed', -- no --embed 342 }, 343 args = { 344 '-i', 345 api.nvim_get_var('tmpname'), -- Use same shada file as parent. 346 '--cmd', 347 'silent edit ' .. non_existent_testfilename, 348 '-c', 349 'qall', 350 }, 351 } 352 eq('', p:output()) 353 eq(0, p.status) 354 eq(0, exc_exec('rshada')) 355 end) 356 357 it('does not create incorrect file for non-existent buffers opened from -c', function() 358 local p = n.spawn_wait { 359 args_rm = { 360 '-i', 361 '--embed', -- no --embed 362 }, 363 args = { 364 '-i', 365 api.nvim_get_var('tmpname'), -- Use same shada file as parent. 366 '-c', 367 'silent edit ' .. non_existent_testfilename, 368 '-c', 369 'autocmd VimEnter * qall', 370 }, 371 } 372 eq('', p:output()) 373 eq(0, p.status) 374 eq(0, exc_exec('rshada')) 375 end) 376 377 it('updates deleted marks with :delmarks', function() 378 nvim_command('edit ' .. testfilename) 379 380 nvim_command('mark A') 381 nvim_command('mark a') 382 -- create a change to set the '.' mark, 383 -- since it can't be set via :mark 384 feed('ggifoobar<esc>') 385 nvim_command('wshada') 386 387 reset() 388 nvim_command('edit ' .. testfilename) 389 nvim_command('normal! `A`a`.') 390 nvim_command('delmarks A a .') 391 nvim_command('wshada') 392 393 reset() 394 nvim_command('edit ' .. testfilename) 395 eq('Vim(normal):E20: Mark not set', exc_exec('normal! `A')) 396 eq('Vim(normal):E20: Mark not set', exc_exec('normal! `a')) 397 eq('Vim(normal):E20: Mark not set', exc_exec('normal! `.')) 398 end) 399 400 it('updates deleted marks with :delmarks!', function() 401 nvim_command('edit ' .. testfilename) 402 403 nvim_command('mark A') 404 nvim_command('mark a') 405 feed('ggifoobar<esc>') 406 nvim_command('wshada') 407 408 reset() 409 nvim_command('edit ' .. testfilename) 410 nvim_command('normal! `A`a`.') 411 nvim_command('delmarks!') 412 nvim_command('wshada') 413 414 reset() 415 nvim_command('edit ' .. testfilename) 416 eq('Vim(normal):E20: Mark not set', exc_exec('normal! `a')) 417 eq('Vim(normal):E20: Mark not set', exc_exec('normal! `.')) 418 -- Make sure that uppercase marks aren't deleted. 419 nvim_command('normal! `A') 420 end) 421 422 it('preserves marks after :bdelete #35770', function() 423 nvim_command('edit foo') 424 nvim_command('mark X') 425 nvim_command('bdelete') 426 nvim_command('wshada') 427 428 reset() 429 local mX = api.nvim_get_mark('X', {}) 430 t.matches(vim.pesc('foo'), mX[4]) 431 432 nvim_command('delmarks X') 433 nvim_command('edit foo') 434 nvim_command('mark X') 435 nvim_command('edit bar') 436 nvim_command('mark Y') 437 nvim_command('bufdo bdelete') 438 nvim_command('edit foo') 439 nvim_command('wshada') 440 441 reset() 442 mX = api.nvim_get_mark('X', {}) 443 local mY = api.nvim_get_mark('Y', {}) 444 t.matches(vim.pesc('foo'), mX[4]) 445 t.matches(vim.pesc('bar'), mY[4]) 446 end) 447 end)