All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
2 let g:notified_changes = []
4 runtime autoload/ale/lsp.vim
6 function! ale#lsp#NotifyForChanges(conn_id, buffer) abort
7 call add(g:notified_changes, {
8 \ 'conn_id': a:conn_id,
16 let g:file1 = tempname()
17 let g:file2 = tempname()
20 let g:test.create_change = {line, offset, end_line, end_offset, value ->
23 \ 'fileName': g:file1,
31 \ 'offset': end_offset,
38 function! WriteFileAndEdit() abort
44 call writefile(g:test.text, g:file1, 'S')
45 execute 'edit ' . g:file1
49 " Close the extra buffers if we opened it.
50 if bufnr(g:file1) != -1 && buflisted(bufnr(g:file1))
51 execute ':bp! | :bd! ' . bufnr(g:file1)
53 if bufnr(g:file2) != -1 && buflisted(bufnr(g:file2))
54 execute ':bp! | :bd! ' . bufnr(g:file2)
57 if filereadable(g:file1)
60 if filereadable(g:file2)
64 unlet! g:notified_changes
65 " unlet! g:expected_notified_changes
70 delfunction WriteFileAndEdit
72 runtime autoload/ale/lsp.vim
77 Execute(It should modify and save multiple files):
84 \ ' constructor(readonly a: Name) {}',
88 \ 'import A from "A"',
93 \ 'import D from "D"',
96 call ale#code_action#HandleCodeAction(
99 \ 'fileName': g:file1,
109 \ 'newText': 'Value',
119 \ 'newText': 'Value',
122 \ 'fileName': g:file2,
132 \ 'newText': "import {A, B} from 'module'\n\n",
136 \ {'should_save': 1, 'conn_id': 'test_conn'},
145 \ ' constructor(readonly a: Value) {}',
148 \], readfile(g:file1, 'b')
151 \ 'import A from "A"',
152 \ 'import {A, B} from ''module''',
154 \ 'import D from "D"',
156 \], readfile(g:file2, 'b')
159 \ 'conn_id': 'test_conn',
160 \ 'buffer': bufnr(g:file1),
162 \ 'conn_id': 'test_conn',
163 \ 'buffer': bufnr(g:file2),
164 \}], g:notified_changes
166 Execute(Beginning of file can be modified):
172 call writefile(g:test.text, g:file1, 'S')
174 call ale#code_action#HandleCodeAction(
177 \ 'fileName': g:file1,
187 \ 'newText': "type A: string\ntype B: number\n",
191 \ {'should_save': 1, 'conn_id': 'test_conn'},
197 \] + g:test.text + [''], readfile(g:file1, 'b')
200 \ 'conn_id': 'test_conn',
201 \ 'buffer': bufnr(g:file1),
202 \}], g:notified_changes
205 Execute(End of file can be modified):
211 call writefile(g:test.text, g:file1, 'S')
213 call ale#code_action#HandleCodeAction(
216 \ 'fileName': g:file1,
226 \ 'newText': "type A: string\ntype B: number\n",
230 \ {'should_save': 1, 'conn_id': 'test_conn'},
233 AssertEqual g:test.text + [
237 \], readfile(g:file1, 'b')
240 \ 'conn_id': 'test_conn',
241 \ 'buffer': bufnr(g:file1),
242 \}], g:notified_changes
245 Execute(Current buffer contents will be reloaded):
251 call writefile(g:test.text, g:file1, 'S')
253 execute 'edit ' . g:file1
254 let g:test.buffer = bufnr(g:file1)
256 call ale#code_action#HandleCodeAction(
259 \ 'fileName': g:file1,
269 \ 'newText': "type A: string\ntype B: number\n",
273 \ {'should_save': 1, 'conn_id': 'test_conn'},
279 \] + g:test.text + [''], readfile(g:file1, 'b')
284 \] + g:test.text, getbufline(g:test.buffer, 1, '$')
287 \ 'conn_id': 'test_conn',
288 \ 'buffer': bufnr(g:file1),
289 \}], g:notified_changes
292 Execute(Unlisted buffer contents will be modified correctly):
298 call writefile(g:test.text, g:file1, 'S')
300 execute 'edit ' . g:file1
301 let g:test.buffer = bufnr(g:file1)
304 AssertEqual bufnr(g:file1), g:test.buffer
306 call ale#code_action#HandleCodeAction(
309 \ 'fileName': g:file1,
319 \ 'newText': "type A: string\ntype B: number\n",
323 \ {'should_save': 1, 'conn_id': 'test_conn'},
329 \] + g:test.text + [''], readfile(g:file1, 'b')
332 \ 'conn_id': 'test_conn',
333 \ 'buffer': bufnr(g:file1),
334 \}], g:notified_changes
336 # Tests for cursor repositioning. In comments `=` designates change range, and
337 # `C` cursor position
340 Execute(Cursor will not move when it is before text change):
341 call WriteFileAndEdit()
342 let g:test.changes = g:test.create_change(2, 3, 2, 8, 'value2')
344 call setpos('.', [0, 1, 1, 0])
345 call ale#code_action#HandleCodeAction(g:test.changes, {
347 \ 'conn_id': 'test_conn',
349 AssertEqual [1, 1], getpos('.')[1:2]
352 \ 'conn_id': 'test_conn',
353 \ 'buffer': bufnr(''),
354 \}], g:notified_changes
356 call setpos('.', [0, 2, 2, 0])
357 call ale#code_action#HandleCodeAction(g:test.changes, {
359 \ 'conn_id': 'test_conn',
361 AssertEqual [2, 2], getpos('.')[1:2]
364 \ 'conn_id': 'test_conn',
365 \ 'buffer': bufnr(''),
367 \ 'conn_id': 'test_conn',
368 \ 'buffer': bufnr(''),
369 \}], g:notified_changes
372 Execute(Cursor column will move to the change end when cursor between start/end):
373 let g:test.changes = g:test.create_change(2, 3, 2, 8, 'value2')
376 call WriteFileAndEdit()
377 call setpos('.', [0, 2, r, 0])
378 AssertEqual ' value: string', getline('.')
379 call ale#code_action#HandleCodeAction(g:test.changes, {
381 \ 'conn_id': 'test_conn',
383 AssertEqual ' value2: string', getline('.')
384 AssertEqual [2, 9], getpos('.')[1:2]
388 \ 'conn_id': 'test_conn',
389 \ 'buffer': bufnr(''),
391 \ 'conn_id': 'test_conn',
392 \ 'buffer': bufnr(''),
394 \ 'conn_id': 'test_conn',
395 \ 'buffer': bufnr(''),
397 \ 'conn_id': 'test_conn',
398 \ 'buffer': bufnr(''),
400 \ 'conn_id': 'test_conn',
401 \ 'buffer': bufnr(''),
403 \ 'conn_id': 'test_conn',
404 \ 'buffer': bufnr(''),
405 \}], g:notified_changes
409 Execute(Cursor column will move back when new text is shorter):
410 call WriteFileAndEdit()
411 call setpos('.', [0, 2, 8, 0])
412 AssertEqual ' value: string', getline('.')
413 call ale#code_action#HandleCodeAction(
414 \ g:test.create_change(2, 3, 2, 8, 'val'),
417 \ 'conn_id': 'test_conn',
419 AssertEqual ' val: string', getline('.')
420 AssertEqual [2, 6], getpos('.')[1:2]
423 \ 'conn_id': 'test_conn',
424 \ 'buffer': bufnr(''),
425 \}], g:notified_changes
429 Execute(Cursor column will move forward when new text is longer):
430 call WriteFileAndEdit()
432 call setpos('.', [0, 2, 8, 0])
433 AssertEqual ' value: string', getline('.')
434 call ale#code_action#HandleCodeAction(
435 \ g:test.create_change(2, 3, 2, 8, 'longValue'),
438 \ 'conn_id': 'test_conn',
440 AssertEqual ' longValue: string', getline('.')
441 AssertEqual [2, 12], getpos('.')[1:2]
444 \ 'conn_id': 'test_conn',
445 \ 'buffer': bufnr(''),
446 \}], g:notified_changes
451 Execute(Cursor line will move when updates are happening on lines above):
452 call WriteFileAndEdit()
453 call setpos('.', [0, 3, 1, 0])
454 AssertEqual '}', getline('.')
455 call ale#code_action#HandleCodeAction(
456 \ g:test.create_change(1, 1, 2, 1, "test\ntest\n"),
459 \ 'conn_id': 'test_conn',
461 AssertEqual '}', getline('.')
462 AssertEqual [4, 1], getpos('.')[1:2]
465 \ 'conn_id': 'test_conn',
466 \ 'buffer': bufnr(''),
467 \}], g:notified_changes
472 Execute(Cursor line and column will move when change on lines above and just before cursor column):
473 call WriteFileAndEdit()
474 call setpos('.', [0, 2, 2, 0])
475 AssertEqual ' value: string', getline('.')
476 call ale#code_action#HandleCodeAction(
477 \ g:test.create_change(1, 1, 2, 1, "test\ntest\n123"),
480 \ 'conn_id': 'test_conn',
482 AssertEqual '123 value: string', getline('.')
483 AssertEqual [3, 5], getpos('.')[1:2]
486 \ 'conn_id': 'test_conn',
487 \ 'buffer': bufnr(''),
488 \}], g:notified_changes
493 Execute(Cursor line and column will move at the end of changes):
494 call WriteFileAndEdit()
495 call setpos('.', [0, 2, 10, 0])
496 AssertEqual ' value: string', getline('.')
497 call ale#code_action#HandleCodeAction(
498 \ g:test.create_change(1, 1, 3, 1, "test\n"),
501 \ 'conn_id': 'test_conn',
503 AssertEqual '}', getline('.')
504 AssertEqual [2, 1], getpos('.')[1:2]
507 \ 'conn_id': 'test_conn',
508 \ 'buffer': bufnr(''),
509 \}], g:notified_changes
513 Execute(Cursor will not move when changes happening on lines >= cursor, but after cursor):
514 call WriteFileAndEdit()
515 call setpos('.', [0, 2, 3, 0])
516 AssertEqual ' value: string', getline('.')
517 call ale#code_action#HandleCodeAction(
518 \ g:test.create_change(2, 10, 3, 1, "number\n"),
521 \ 'conn_id': 'test_conn',
523 AssertEqual ' value: number', getline('.')
524 AssertEqual [2, 3], getpos('.')[1:2]
527 \ 'conn_id': 'test_conn',
528 \ 'buffer': bufnr(''),
529 \}], g:notified_changes
531 Execute(Cursor will not move when change covers entire file):
532 call WriteFileAndEdit()
533 call setpos('.', [0, 2, 3, 0])
534 call ale#code_action#HandleCodeAction(
535 \ g:test.create_change(1, 1, len(g:test.text) + 1, 1,
536 \ join(g:test.text + ['x'], "\n")),
539 \ 'conn_id': 'test_conn',
541 AssertEqual [2, 3], getpos('.')[1:2]
544 \ 'conn_id': 'test_conn',
545 \ 'buffer': bufnr(''),
546 \}], g:notified_changes
548 Execute(It should just modify file when should_save is set to v:false):
549 call WriteFileAndEdit()
550 let g:test.change = g:test.create_change(1, 1, 1, 1, "import { writeFile } from 'fs';\n")
551 call ale#code_action#HandleCodeAction(g:test.change, {
552 \ 'conn_id': 'test_conn',
554 AssertEqual 1, getbufvar(bufnr(''), '&modified')
556 \ 'import { writeFile } from ''fs'';',
563 \ 'conn_id': 'test_conn',
564 \ 'buffer': bufnr(''),
565 \}], g:notified_changes
567 Given typescript(An example TypeScript file):
570 export interface ISomething {
571 fooLongName: Foo | null
574 export class SomethingElse implements ISomething {
576 fooLongName!: ISomething['fooLongName']
581 \ {'end': {'offset': 14, 'line': 4}, 'newText': 'foo', 'start': {'offset': 3, 'line': 4}},
582 \ {'end': {'offset': 40, 'line': 9}, 'newText': 'foo', 'start': {'offset': 29, 'line': 9}},
583 \ {'end': {'offset': 14, 'line': 9}, 'newText': 'foo', 'start': {'offset': 3, 'line': 9}},
586 call ale#code_action#ApplyChanges(expand('%:p'), g:changes, {
587 \ 'conn_id': 'test_conn',
591 \ 'conn_id': 'test_conn',
592 \ 'buffer': bufnr(''),
593 \}], g:notified_changes
595 Expect(The changes should be applied correctly):
598 export interface ISomething {
602 export class SomethingElse implements ISomething {
604 foo!: ISomething['foo']