1" tests for listener_add() and listener_remove() 2 3func s:StoreList(s, e, a, l) 4 let s:start = a:s 5 let s:end = a:e 6 let s:added = a:a 7 let s:text = getline(a:s) 8 let s:list = a:l 9endfunc 10 11func s:AnotherStoreList(l) 12 let s:list2 = a:l 13endfunc 14 15func s:EvilStoreList(l) 16 let s:list3 = a:l 17 call assert_fails("call add(a:l, 'myitem')", "E742:") 18endfunc 19 20func Test_listening() 21 new 22 call setline(1, ['one', 'two']) 23 let s:list = [] 24 let id = listener_add({b, s, e, a, l -> s:StoreList(s, e, a, l)}) 25 call setline(1, 'one one') 26 call listener_flush() 27 call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], s:list) 28 29 " Undo is also a change 30 set undolevels& " start new undo block 31 call append(2, 'two two') 32 undo 33 call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1}], s:list) 34 redraw 35 " the two changes are not merged 36 call assert_equal([{'lnum': 3, 'end': 4, 'col': 1, 'added': -1}], s:list) 37 1 38 39 " Two listeners, both get called. Also check column. 40 call setline(1, ['one one', 'two']) 41 call listener_flush() 42 let id2 = listener_add({b, s, e, a, l -> s:AnotherStoreList(l)}) 43 let s:list = [] 44 let s:list2 = [] 45 exe "normal $asome\<Esc>" 46 redraw 47 call assert_equal([{'lnum': 1, 'end': 2, 'col': 8, 'added': 0}], s:list) 48 call assert_equal([{'lnum': 1, 'end': 2, 'col': 8, 'added': 0}], s:list2) 49 50 " removing listener works 51 call listener_remove(id2) 52 call setline(1, ['one one', 'two']) 53 call listener_flush() 54 let s:list = [] 55 let s:list2 = [] 56 call setline(3, 'three') 57 redraw 58 call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1}], s:list) 59 call assert_equal([], s:list2) 60 61 " a change above a previous change without a line number change is reported 62 " together 63 call setline(1, ['one one', 'two']) 64 call listener_flush(bufnr()) 65 call append(2, 'two two') 66 call setline(1, 'something') 67 call bufnr()->listener_flush() 68 call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1}, 69 \ {'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], s:list) 70 call assert_equal(1, s:start) 71 call assert_equal(3, s:end) 72 call assert_equal(1, s:added) 73 74 " an insert just above a previous change that was the last one does not get 75 " merged 76 call setline(1, ['one one', 'two']) 77 call listener_flush() 78 let s:list = [] 79 call setline(2, 'something') 80 call append(1, 'two two') 81 call assert_equal([{'lnum': 2, 'end': 3, 'col': 1, 'added': 0}], s:list) 82 call listener_flush() 83 call assert_equal([{'lnum': 2, 'end': 2, 'col': 1, 'added': 1}], s:list) 84 85 " an insert above a previous change causes a flush 86 call setline(1, ['one one', 'two']) 87 call listener_flush() 88 call setline(2, 'something') 89 call append(0, 'two two') 90 call assert_equal([{'lnum': 2, 'end': 3, 'col': 1, 'added': 0}], s:list) 91 call assert_equal('something', s:text) 92 call listener_flush() 93 call assert_equal([{'lnum': 1, 'end': 1, 'col': 1, 'added': 1}], s:list) 94 call assert_equal('two two', s:text) 95 96 " a delete at a previous change that was the last one does not get merged 97 call setline(1, ['one one', 'two']) 98 call listener_flush() 99 let s:list = [] 100 call setline(2, 'something') 101 2del 102 call assert_equal([{'lnum': 2, 'end': 3, 'col': 1, 'added': 0}], s:list) 103 call listener_flush() 104 call assert_equal([{'lnum': 2, 'end': 3, 'col': 1, 'added': -1}], s:list) 105 106 " a delete above a previous change causes a flush 107 call setline(1, ['one one', 'two']) 108 call listener_flush() 109 call setline(2, 'another') 110 1del 111 call assert_equal([{'lnum': 2, 'end': 3, 'col': 1, 'added': 0}], s:list) 112 call assert_equal(2, s:start) 113 call assert_equal('another', s:text) 114 call listener_flush() 115 call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': -1}], s:list) 116 call assert_equal('another', s:text) 117 118 " the "o" command first adds an empty line and then changes it 119 %del 120 call setline(1, ['one one', 'two']) 121 call listener_flush() 122 let s:list = [] 123 exe "normal Gofour\<Esc>" 124 redraw 125 call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1}, 126 \ {'lnum': 3, 'end': 4, 'col': 1, 'added': 0}], s:list) 127 128 " Remove last listener 129 let s:list = [] 130 call listener_remove(id) 131 call setline(1, 'asdfasdf') 132 redraw 133 call assert_equal([], s:list) 134 135 " Trying to change the list fails 136 let id = listener_add({b, s, e, a, l -> s:EvilStoreList(l)}) 137 let s:list3 = [] 138 call setline(1, 'asdfasdf') 139 redraw 140 call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], s:list3) 141 142 eval id->listener_remove() 143 bwipe! 144endfunc 145 146func s:StoreListArgs(buf, start, end, added, list) 147 let s:buf = a:buf 148 let s:start = a:start 149 let s:end = a:end 150 let s:added = a:added 151 let s:list = a:list 152endfunc 153 154func Test_listener_args() 155 new 156 call setline(1, ['one', 'two']) 157 let s:list = [] 158 let id = listener_add('s:StoreListArgs') 159 160 " just one change 161 call setline(1, 'one one') 162 call listener_flush() 163 call assert_equal(bufnr(''), s:buf) 164 call assert_equal(1, s:start) 165 call assert_equal(2, s:end) 166 call assert_equal(0, s:added) 167 call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], s:list) 168 169 " two disconnected changes 170 call setline(1, ['one', 'two', 'three', 'four']) 171 call listener_flush() 172 call setline(1, 'one one') 173 call setline(3, 'three three') 174 call listener_flush() 175 call assert_equal(bufnr(''), s:buf) 176 call assert_equal(1, s:start) 177 call assert_equal(4, s:end) 178 call assert_equal(0, s:added) 179 call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}, 180 \ {'lnum': 3, 'end': 4, 'col': 1, 'added': 0}], s:list) 181 182 " add and remove lines 183 call setline(1, ['one', 'two', 'three', 'four', 'five', 'six']) 184 call listener_flush() 185 call append(2, 'two two') 186 4del 187 call append(5, 'five five') 188 call listener_flush() 189 call assert_equal(bufnr(''), s:buf) 190 call assert_equal(3, s:start) 191 call assert_equal(6, s:end) 192 call assert_equal(1, s:added) 193 call assert_equal([{'lnum': 3, 'end': 3, 'col': 1, 'added': 1}, 194 \ {'lnum': 4, 'end': 5, 'col': 1, 'added': -1}, 195 \ {'lnum': 6, 'end': 6, 'col': 1, 'added': 1}], s:list) 196 197 " split a line then insert one, should get two disconnected change lists 198 call setline(1, 'split here') 199 call listener_flush() 200 let s:list = [] 201 exe "normal 1ggwi\<CR>\<Esc>" 202 1 203 normal o 204 call assert_equal([{'lnum': 1, 'end': 2, 'col': 7, 'added': 1}], s:list) 205 call listener_flush() 206 call assert_equal([{'lnum': 2, 'end': 2, 'col': 1, 'added': 1}], s:list) 207 208 call listener_remove(id) 209 bwipe! 210 211 " Invalid arguments 212 call assert_fails('call listener_add([])', 'E921:') 213 call assert_fails('call listener_add("s:StoreListArgs", [])', 'E730:') 214 call assert_fails('call listener_flush([])', 'E730:') 215endfunc 216 217func s:StoreBufList(buf, start, end, added, list) 218 let s:bufnr = a:buf 219 let s:list = a:list 220endfunc 221 222func Test_listening_other_buf() 223 new 224 call setline(1, ['one', 'two']) 225 let bufnr = bufnr('') 226 normal ww 227 let id = bufnr->listener_add(function('s:StoreBufList')) 228 let s:list = [] 229 call setbufline(bufnr, 1, 'hello') 230 redraw 231 call assert_equal(bufnr, s:bufnr) 232 call assert_equal([{'lnum': 1, 'end': 2, 'col': 1, 'added': 0}], s:list) 233 234 call listener_remove(id) 235 exe "buf " .. bufnr 236 bwipe! 237endfunc 238 239func Test_listener_garbage_collect() 240 func MyListener(x, bufnr, start, end, added, changes) 241 " NOP 242 endfunc 243 244 new 245 let id = listener_add(function('MyListener', [{}]), bufnr('')) 246 call test_garbagecollect_now() 247 " must not crash caused by invalid memory access 248 normal ia 249 call assert_true(v:true) 250 251 call listener_remove(id) 252 delfunc MyListener 253 bwipe! 254endfunc 255 256" This verifies the fix for issue #4455 257func Test_listener_caches_buffer_line() 258 new 259 inoremap <silent> <CR> <CR><Esc>O 260 261 function EchoChanges(bufnr, start, end, added, changes) 262 for l:change in a:changes 263 let text = getbufline(a:bufnr, l:change.lnum, l:change.end-1+l:change.added) 264 endfor 265 endfunction 266 let lid = listener_add("EchoChanges") 267 set autoindent 268 set cindent 269 270 call setline(1, ["{", "\tif true {}", "}"]) 271 exe "normal /{}\nl" 272 call feedkeys("i\r\e", 'xt') 273 call assert_equal(["{", "\tif true {", "", "\t}", "}"], getline(1, 5)) 274 275 bwipe! 276 delfunc EchoChanges 277 call listener_remove(lid) 278 iunmap <CR> 279 set nocindent 280endfunc 281 282" Verify the fix for issue #4908 283func Test_listener_undo_line_number() 284 function DoIt() 285 " NOP 286 endfunction 287 function EchoChanges(bufnr, start, end, added, changes) 288 call DoIt() 289 endfunction 290 291 new 292 let lid = listener_add("EchoChanges") 293 call setline(1, ['a', 'b', 'c']) 294 set undolevels& " start new undo block 295 call feedkeys("ggcG\<Esc>", 'xt') 296 undo 297 298 bwipe! 299 delfunc DoIt 300 delfunc EchoChanges 301 call listener_remove(lid) 302endfunc 303 304func Test_listener_undo_delete_all() 305 new 306 call setline(1, [1, 2, 3, 4]) 307 let s:changes = [] 308 func s:ExtendList(bufnr, start, end, added, changes) 309 call extend(s:changes, a:changes) 310 endfunc 311 let id = listener_add('s:ExtendList') 312 313 set undolevels& " start new undo block 314 normal! ggdG 315 undo 316 call listener_flush() 317 call assert_equal(2, s:changes->len()) 318 " delete removes four lines, empty line remains 319 call assert_equal({'lnum': 1, 'end': 5, 'col': 1, 'added': -4}, s:changes[0]) 320 " undo replaces empty line and adds 3 lines 321 call assert_equal({'lnum': 1, 'end': 2, 'col': 1, 'added': 3}, s:changes[1]) 322 323 call listener_remove(id) 324 delfunc s:ExtendList 325 unlet s:changes 326 bwipe! 327endfunc 328 329func Test_listener_cleared_newbuf() 330 func Listener(bufnr, start, end, added, changes) 331 let g:gotCalled += 1 332 endfunc 333 new 334 " check that listening works 335 let g:gotCalled = 0 336 let lid = listener_add("Listener") 337 call feedkeys("axxx\<Esc>", 'xt') 338 call listener_flush(bufnr()) 339 call assert_equal(1, g:gotCalled) 340 %bwipe! 341 let bufnr = bufnr() 342 let b:testing = 123 343 let lid = listener_add("Listener") 344 enew! 345 " check buffer is reused 346 call assert_equal(bufnr, bufnr()) 347 call assert_false(exists('b:testing')) 348 349 " check that listening stops when reusing the buffer 350 let g:gotCalled = 0 351 call feedkeys("axxx\<Esc>", 'xt') 352 call listener_flush(bufnr()) 353 call assert_equal(0, g:gotCalled) 354 unlet g:gotCalled 355 356 bwipe! 357 delfunc Listener 358endfunc 359 360func Test_col_after_deletion_moved_cur() 361 func Listener(bufnr, start, end, added, changes) 362 call assert_equal([#{lnum: 1, end: 2, added: 0, col: 2}], a:changes) 363 endfunc 364 new 365 call setline(1, ['foo']) 366 let lid = listener_add('Listener') 367 call feedkeys("lD", 'xt') 368 call listener_flush() 369 bwipe! 370 delfunc Listener 371endfunc 372 373func Test_remove_listener_in_callback() 374 new 375 let s:ID = listener_add('Listener') 376 func Listener(...) 377 call listener_remove(s:ID) 378 let g:listener_called = 'yes' 379 endfunc 380 call setline(1, ['foo']) 381 call feedkeys("lD", 'xt') 382 call listener_flush() 383 call assert_equal('yes', g:listener_called) 384 385 bwipe! 386 delfunc Listener 387 unlet g:listener_called 388endfunc 389 390 391" vim: shiftwidth=2 sts=2 expandtab 392