From 9ef371fd545034519e4259da001a52e9f7838ffe Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 13 Dec 2016 14:15:10 -0500 Subject: [PATCH 01/26] test: quickfix: Move upstream vim quickfix test to src/nvim/testdir Massaging the upstream patches for this test into the lua tests are too cumbersome and slow down patching. --- src/nvim/testdir/Makefile | 5 +- src/nvim/testdir/test_quickfix.vim | 681 ++++++++++++++++++++++ test/functional/legacy/quickfix_spec.lua | 683 ----------------------- 3 files changed, 684 insertions(+), 685 deletions(-) create mode 100644 src/nvim/testdir/test_quickfix.vim delete mode 100644 test/functional/legacy/quickfix_spec.lua diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 0118597eb8..7cd1921ce1 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -30,15 +30,16 @@ SCRIPTS := \ # Tests using runtest.vim.vim. # Keep test_alot*.res as the last one, sort the others. NEW_TESTS = \ + test_cmdline.res \ test_cscope.res \ - test_cmdline.res \ test_diffmode.res \ test_hardcopy.res \ test_help_tagjump.res \ test_history.res \ test_langmap.res \ - test_match.res \ + test_match.res \ test_matchadd_conceal.res \ + test_quickfix.res \ test_syntax.res \ test_usercommands.res \ test_timers.res \ diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim new file mode 100644 index 0000000000..9dbd00b001 --- /dev/null +++ b/src/nvim/testdir/test_quickfix.vim @@ -0,0 +1,681 @@ +" Test for the quickfix commands. + +if !has('quickfix') + finish +endif + +set encoding=utf-8 + +" Tests for the :clist and :llist commands +function XlistTests(cchar) + let Xlist = a:cchar . 'list' + let Xgetexpr = a:cchar . 'getexpr' + + " With an empty list, command should return error + exe Xgetexpr . ' []' + exe 'silent! ' . Xlist + call assert_true(v:errmsg ==# 'E42: No Errors') + + " Populate the list and then try + exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', + \ 'non-error 2', 'Xtestfile2:2:2:Line2', + \ 'non-error 3', 'Xtestfile3:3:1:Line3']" + + " List only valid entries + redir => result + exe Xlist + redir END + let l = split(result, "\n") + call assert_equal([' 2 Xtestfile1:1 col 3: Line1', + \ ' 4 Xtestfile2:2 col 2: Line2', + \ ' 6 Xtestfile3:3 col 1: Line3'], l) + + " List all the entries + redir => result + exe Xlist . "!" + redir END + let l = split(result, "\n") + call assert_equal([' 1: non-error 1', ' 2 Xtestfile1:1 col 3: Line1', + \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2', + \ ' 5: non-error 3', ' 6 Xtestfile3:3 col 1: Line3'], l) + + " List a range of errors + redir => result + exe Xlist . " 3,6" + redir END + let l = split(result, "\n") + call assert_equal([' 4 Xtestfile2:2 col 2: Line2', + \ ' 6 Xtestfile3:3 col 1: Line3'], l) + + redir => result + exe Xlist . "! 3,4" + redir END + let l = split(result, "\n") + call assert_equal([' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l) + + redir => result + exe Xlist . " -6,-4" + redir END + let l = split(result, "\n") + call assert_equal([' 2 Xtestfile1:1 col 3: Line1'], l) + + redir => result + exe Xlist . "! -5,-3" + redir END + let l = split(result, "\n") + call assert_equal([' 2 Xtestfile1:1 col 3: Line1', + \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l) +endfunction + +function Test_clist() + call XlistTests('c') + call XlistTests('l') +endfunction + +" Tests for the :colder, :cnewer, :lolder and :lnewer commands +" Note that this test assumes that a quickfix/location list is +" already set by the caller. +function XageTests(cchar) + let Xolder = a:cchar . 'older' + let Xnewer = a:cchar . 'newer' + let Xgetexpr = a:cchar . 'getexpr' + if a:cchar == 'c' + let Xgetlist = 'getqflist()' + else + let Xgetlist = 'getloclist(0)' + endif + + " Jumping to a non existent list should return error + exe 'silent! ' . Xolder . ' 99' + call assert_true(v:errmsg ==# 'E380: At bottom of quickfix stack') + + exe 'silent! ' . Xnewer . ' 99' + call assert_true(v:errmsg ==# 'E381: At top of quickfix stack') + + " Add three quickfix/location lists + exe Xgetexpr . " ['Xtestfile1:1:3:Line1']" + exe Xgetexpr . " ['Xtestfile2:2:2:Line2']" + exe Xgetexpr . " ['Xtestfile3:3:1:Line3']" + + " Go back two lists + exe Xolder + exe 'let l = ' . Xgetlist + call assert_equal('Line2', l[0].text) + + " Go forward two lists + exe Xnewer + exe 'let l = ' . Xgetlist + call assert_equal('Line3', l[0].text) + + " Test for the optional count argument + exe Xolder . ' 2' + exe 'let l = ' . Xgetlist + call assert_equal('Line1', l[0].text) + + exe Xnewer . ' 2' + exe 'let l = ' . Xgetlist + call assert_equal('Line3', l[0].text) +endfunction + +function Test_cage() + let list = [{'bufnr': 1, 'lnum': 1}] + call setqflist(list) + call XageTests('c') + + call setloclist(0, list) + call XageTests('l') +endfunction + +" Tests for the :cwindow, :lwindow :cclose, :lclose, :copen and :lopen +" commands +function XwindowTests(cchar) + let Xwindow = a:cchar . 'window' + let Xclose = a:cchar . 'close' + let Xopen = a:cchar . 'open' + let Xgetexpr = a:cchar . 'getexpr' + + " Create a list with no valid entries + exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" + + " Quickfix/Location window should not open with no valid errors + exe Xwindow + call assert_true(winnr('$') == 1) + + " Create a list with valid entries + exe Xgetexpr . " ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2', + \ 'Xtestfile3:3:1:Line3']" + + " Open the window + exe Xwindow + call assert_true(winnr('$') == 2 && winnr() == 2 && + \ getline('.') ==# 'Xtestfile1|1 col 3| Line1') + + " Close the window + exe Xclose + call assert_true(winnr('$') == 1) + + " Create a list with no valid entries + exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" + + " Open the window + exe Xopen . ' 5' + call assert_true(winnr('$') == 2 && getline('.') ==# '|| non-error 1' + \ && winheight('.') == 5) + + " Opening the window again, should move the cursor to that window + wincmd t + exe Xopen . ' 7' + call assert_true(winnr('$') == 2 && winnr() == 2 && + \ winheight('.') == 7 && + \ getline('.') ==# '|| non-error 1') + + + " Calling cwindow should close the quickfix window with no valid errors + exe Xwindow + call assert_true(winnr('$') == 1) +endfunction + +function Test_cwindow() + call XwindowTests('c') + call XwindowTests('l') +endfunction + +" Tests for the :cfile, :lfile, :caddfile, :laddfile, :cgetfile and :lgetfile +" commands. +function XfileTests(cchar) + let Xfile = a:cchar . 'file' + let Xgetfile = a:cchar . 'getfile' + let Xaddfile = a:cchar . 'addfile' + if a:cchar == 'c' + let Xgetlist = 'getqflist()' + else + let Xgetlist = 'getloclist(0)' + endif + + call writefile(['Xtestfile1:700:10:Line 700', + \ 'Xtestfile2:800:15:Line 800'], 'Xqftestfile1') + + enew! + exe Xfile . ' Xqftestfile1' + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 2 && + \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && + \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') + + " Run cfile/lfile from a modified buffer + enew! + silent! put ='Quickfix' + exe 'silent! ' . Xfile . ' Xqftestfile1' + call assert_true(v:errmsg ==# 'E37: No write since last change (add ! to override)') + + call writefile(['Xtestfile3:900:30:Line 900'], 'Xqftestfile1') + exe Xaddfile . ' Xqftestfile1' + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 3 && + \ l[2].lnum == 900 && l[2].col == 30 && l[2].text ==# 'Line 900') + + call writefile(['Xtestfile1:222:77:Line 222', + \ 'Xtestfile2:333:88:Line 333'], 'Xqftestfile1') + + enew! + exe Xgetfile . ' Xqftestfile1' + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 2 && + \ l[0].lnum == 222 && l[0].col == 77 && l[0].text ==# 'Line 222' && + \ l[1].lnum == 333 && l[1].col == 88 && l[1].text ==# 'Line 333') + + call delete('Xqftestfile1') +endfunction + +function Test_cfile() + call XfileTests('c') + call XfileTests('l') +endfunction + +" Tests for the :cbuffer, :lbuffer, :caddbuffer, :laddbuffer, :cgetbuffer and +" :lgetbuffer commands. +function XbufferTests(cchar) + let Xbuffer = a:cchar . 'buffer' + let Xgetbuffer = a:cchar . 'getbuffer' + let Xaddbuffer = a:cchar . 'addbuffer' + if a:cchar == 'c' + let Xgetlist = 'getqflist()' + else + let Xgetlist = 'getloclist(0)' + endif + + enew! + silent! call setline(1, ['Xtestfile7:700:10:Line 700', + \ 'Xtestfile8:800:15:Line 800']) + exe Xbuffer . "!" + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 2 && + \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && + \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') + + enew! + silent! call setline(1, ['Xtestfile9:900:55:Line 900', + \ 'Xtestfile10:950:66:Line 950']) + exe Xgetbuffer + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 2 && + \ l[0].lnum == 900 && l[0].col == 55 && l[0].text ==# 'Line 900' && + \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950') + + enew! + silent! call setline(1, ['Xtestfile11:700:20:Line 700', + \ 'Xtestfile12:750:25:Line 750']) + exe Xaddbuffer + exe 'let l = ' . Xgetlist + call assert_true(len(l) == 4 && + \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950' && + \ l[2].lnum == 700 && l[2].col == 20 && l[2].text ==# 'Line 700' && + \ l[3].lnum == 750 && l[3].col == 25 && l[3].text ==# 'Line 750') + +endfunction + +function Test_cbuffer() + call XbufferTests('c') + call XbufferTests('l') +endfunction + +function Test_helpgrep() + helpgrep quickfix + copen + " This wipes out the buffer, make sure that doesn't cause trouble. + cclose +endfunc + +func Test_errortitle() + augroup QfBufWinEnter + au! + au BufWinEnter * :let g:a=get(w:, 'quickfix_title', 'NONE') + augroup END + copen + let a=[{'lnum': 308, 'bufnr': bufnr(''), 'col': 58, 'valid': 1, 'vcol': 0, 'nr': 0, 'type': '', 'pattern': '', 'text': ' au BufWinEnter * :let g:a=get(w:, ''quickfix_title'', ''NONE'')'}] + call setqflist(a) + call assert_equal(':setqflist()', g:a) + augroup QfBufWinEnter + au! + augroup END + augroup! QfBufWinEnter +endfunc + +func Test_vimgreptitle() + augroup QfBufWinEnter + au! + au BufWinEnter * :let g:a=get(w:, 'quickfix_title', 'NONE') + augroup END + try + vimgrep /pattern/j file + catch /E480/ + endtry + copen + call assert_equal(': vimgrep /pattern/j file', g:a) + augroup QfBufWinEnter + au! + augroup END + augroup! QfBufWinEnter +endfunc + +function XqfTitleTests(cchar) + let Xgetexpr = a:cchar . 'getexpr' + if a:cchar == 'c' + let Xgetlist = 'getqflist()' + else + let Xgetlist = 'getloclist(0)' + endif + let Xopen = a:cchar . 'open' + let Xclose = a:cchar . 'close' + + exe Xgetexpr . " ['file:1:1:message']" + exe 'let l = ' . Xgetlist + if a:cchar == 'c' + call setqflist(l, 'r') + else + call setloclist(0, l, 'r') + endif + + exe Xopen + if a:cchar == 'c' + let title = ':setqflist()' + else + let title = ':setloclist()' + endif + call assert_equal(title, w:quickfix_title) + exe Xclose +endfunction + +" Tests for quickfix window's title +function Test_qf_title() + call XqfTitleTests('c') + call XqfTitleTests('l') +endfunction + +" Tests for 'errorformat' +function Test_efm() + let save_efm = &efm + set efm=%EEEE%m,%WWWW%m,%+CCCC%.%#,%-GGGG%.%# + cgetexpr ['WWWW', 'EEEE', 'CCCC'] + let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]'))) + call assert_equal("[['W', 1], ['E^@CCCC', 1]]", l) + cgetexpr ['WWWW', 'GGGG', 'EEEE', 'CCCC'] + let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]'))) + call assert_equal("[['W', 1], ['E^@CCCC', 1]]", l) + cgetexpr ['WWWW', 'GGGG', 'ZZZZ', 'EEEE', 'CCCC', 'YYYY'] + let l = strtrans(string(map(getqflist(), '[v:val.text, v:val.valid]'))) + call assert_equal("[['W', 1], ['ZZZZ', 0], ['E^@CCCC', 1], ['YYYY', 0]]", l) + let &efm = save_efm +endfunction + +" This will test for problems in quickfix: +" A. incorrectly copying location lists which caused the location list to show +" a different name than the file that was actually being displayed. +" B. not reusing the window for which the location list window is opened but +" instead creating new windows. +" C. make sure that the location list window is not reused instead of the +" window it belongs to. +" +" Set up the test environment: +function! ReadTestProtocol(name) + let base = substitute(a:name, '\v^test://(.*)%(\.[^.]+)?', '\1', '') + let word = substitute(base, '\v(.*)\..*', '\1', '') + + setl modifiable + setl noreadonly + setl noswapfile + setl bufhidden=delete + %del _ + " For problem 2: + " 'buftype' has to be set to reproduce the constant opening of new windows + setl buftype=nofile + + call setline(1, word) + + setl nomodified + setl nomodifiable + setl readonly + exe 'doautocmd BufRead ' . substitute(a:name, '\v^test://(.*)', '\1', '') +endfunction + +function Test_locationlist() + enew + + augroup testgroup + au! + autocmd BufReadCmd test://* call ReadTestProtocol(expand("")) + augroup END + + let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ] + + let qflist = [] + for word in words + call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', }) + " NOTE: problem 1: + " intentionally not setting 'lnum' so that the quickfix entries are not + " valid + call setloclist(0, qflist, ' ') + endfor + + " Test A + lrewind + enew + lopen + lnext + lnext + lnext + lnext + vert split + wincmd L + lopen + wincmd p + lnext + let fileName = expand("%") + wincmd p + let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '') + let fileName = substitute(fileName, '\\', '/', 'g') + let locationListFileName = substitute(locationListFileName, '\\', '/', 'g') + call assert_equal("test://bar.txt", fileName) + call assert_equal("test://bar.txt", locationListFileName) + + wincmd n | only + + " Test B: + lrewind + lopen + 2 + exe "normal \" + wincmd p + 3 + exe "normal \" + wincmd p + 4 + exe "normal \" + call assert_equal(2, winnr('$')) + wincmd n | only + + " Test C: + lrewind + lopen + " Let's move the location list window to the top to check whether it (the + " first window found) will be reused when we try to open new windows: + wincmd K + 2 + exe "normal \" + wincmd p + 3 + exe "normal \" + wincmd p + 4 + exe "normal \" + 1wincmd w + call assert_equal('quickfix', &buftype) + 2wincmd w + let bufferName = expand("%") + let bufferName = substitute(bufferName, '\\', '/', 'g') + call assert_equal('test://quux.txt', bufferName) + + wincmd n | only + + augroup! testgroup +endfunction + +function Test_locationlist_curwin_was_closed() + augroup testgroup + au! + autocmd BufReadCmd t call R(expand("")) + augroup END + + function! R(n) + quit + endfunc + + new + let q = [] + call add(q, {'filename': 't' }) + call setloclist(0, q) + call assert_fails('lrewind', 'E924:') + + augroup! testgroup +endfunction + +" More tests for 'errorformat' +function! Test_efm1() + if !has('unix') + " The 'errorformat' setting is different on non-Unix systems. + " This test works only on Unix-like systems. + return + endif + + let l = [ + \ '"Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set.', + \ '"Xtestfile", line 6 col 19; this is an error', + \ 'gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include version.c', + \ 'Xtestfile:9: parse error before `asd''', + \ 'make: *** [vim] Error 1', + \ 'in file "Xtestfile" linenr 10: there is an error', + \ '', + \ '2 returned', + \ '"Xtestfile", line 11 col 1; this is an error', + \ '"Xtestfile", line 12 col 2; this is another error', + \ '"Xtestfile", line 14:10; this is an error in column 10', + \ '=Xtestfile=, line 15:10; this is another error, but in vcol 10 this time', + \ '"Xtestfile", linenr 16: yet another problem', + \ 'Error in "Xtestfile" at line 17:', + \ 'x should be a dot', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17', + \ ' ^', + \ 'Error in "Xtestfile" at line 18:', + \ 'x should be a dot', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18', + \ '.............^', + \ 'Error in "Xtestfile" at line 19:', + \ 'x should be a dot', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19', + \ '--------------^', + \ 'Error in "Xtestfile" at line 20:', + \ 'x should be a dot', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20', + \ ' ^', + \ '', + \ 'Does anyone know what is the problem and how to correction it?', + \ '"Xtestfile", line 21 col 9: What is the title of the quickfix window?', + \ '"Xtestfile", line 22 col 9: What is the title of the quickfix window?' + \ ] + + call writefile(l, 'Xerrorfile1') + call writefile(l[:-2], 'Xerrorfile2') + + let m = [ + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 4', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 5', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 6', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 7', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 8', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 9', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 10', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 11', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 12', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 13', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 14', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 15', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 16', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 21', + \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 22' + \ ] + call writefile(m, 'Xtestfile') + + let save_efm = &efm + set efm+==%f=\\,\ line\ %l%*\\D%v%*[^\ ]\ %m + set efm^=%AError\ in\ \"%f\"\ at\ line\ %l:,%Z%p^,%C%m + + exe 'cf Xerrorfile2' + clast + copen + call assert_equal(':cf Xerrorfile2', w:quickfix_title) + wincmd p + + exe 'cf Xerrorfile1' + call assert_equal([4, 12], [line('.'), col('.')]) + cn + call assert_equal([6, 19], [line('.'), col('.')]) + cn + call assert_equal([9, 2], [line('.'), col('.')]) + cn + call assert_equal([10, 2], [line('.'), col('.')]) + cn + call assert_equal([11, 1], [line('.'), col('.')]) + cn + call assert_equal([12, 2], [line('.'), col('.')]) + cn + call assert_equal([14, 10], [line('.'), col('.')]) + cn + call assert_equal([15, 3, 10], [line('.'), col('.'), virtcol('.')]) + cn + call assert_equal([16, 2], [line('.'), col('.')]) + cn + call assert_equal([17, 6], [line('.'), col('.')]) + cn + call assert_equal([18, 7], [line('.'), col('.')]) + cn + call assert_equal([19, 8], [line('.'), col('.')]) + cn + call assert_equal([20, 9], [line('.'), col('.')]) + clast + cprev + cprev + wincmd w + call assert_equal(':cf Xerrorfile1', w:quickfix_title) + wincmd p + + let &efm = save_efm + call delete('Xerrorfile1') + call delete('Xerrorfile2') + call delete('Xtestfile') +endfunction + +function XquickfixChangedByAutocmd(cchar) + let Xolder = a:cchar . 'older' + let Xgetexpr = a:cchar . 'getexpr' + let Xrewind = a:cchar . 'rewind' + if a:cchar == 'c' + let Xsetlist = 'setqflist(' + let ErrorNr = 'E925' + function! ReadFunc() + colder + cgetexpr [] + endfunc + else + let Xsetlist = 'setloclist(0,' + let ErrorNr = 'E926' + function! ReadFunc() + lolder + lgetexpr [] + endfunc + endif + + augroup testgroup + au! + autocmd BufReadCmd t call ReadFunc() + augroup END + + bwipe! + let words = [ "a", "b" ] + let qflist = [] + for word in words + call add(qflist, {'filename': 't'}) + exec "call " . Xsetlist . "qflist, '')" + endfor + exec "call assert_fails('" . Xrewind . "', '" . ErrorNr . ":')" + + augroup! testgroup +endfunc + +function Test_quickfix_was_changed_by_autocmd() + call XquickfixChangedByAutocmd('c') + call XquickfixChangedByAutocmd('l') +endfunction + +func Test_caddbuffer_to_empty() + helpgr quickfix + call setqflist([], 'r') + cad + try + cn + catch + " number of matches is unknown + call assert_true(v:exception =~ 'E553:') + endtry + quit! +endfunc + +func Test_cgetexpr_works() + " this must not crash Vim + cgetexpr [$x] +endfunc diff --git a/test/functional/legacy/quickfix_spec.lua b/test/functional/legacy/quickfix_spec.lua deleted file mode 100644 index 5787ff8ff3..0000000000 --- a/test/functional/legacy/quickfix_spec.lua +++ /dev/null @@ -1,683 +0,0 @@ --- Test for the quickfix commands. - -local helpers = require('test.functional.helpers')(after_each) -local source, clear = helpers.source, helpers.clear -local eq, nvim, call = helpers.eq, helpers.meths, helpers.call -local eval = helpers.eval -local execute = helpers.execute - -local function expected_empty() - eq({}, nvim.get_vvar('errors')) -end - -describe('helpgrep', function() - before_each(function() - clear() - - source([[ - " Tests for the :clist and :llist commands - function XlistTests(cchar) - let Xlist = a:cchar . 'list' - let Xgetexpr = a:cchar . 'getexpr' - - " With an empty list, command should return error - exe Xgetexpr . ' []' - exe 'silent! ' . Xlist - call assert_true(v:errmsg ==# 'E42: No Errors') - - " Populate the list and then try - exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', - \ 'non-error 2', 'Xtestfile2:2:2:Line2', - \ 'non-error 3', 'Xtestfile3:3:1:Line3']" - - " List only valid entries - redir => result - exe 'silent ' . Xlist - redir END - let l = split(result, "\n") - call assert_equal([' 2 Xtestfile1:1 col 3: Line1', - \ ' 4 Xtestfile2:2 col 2: Line2', - \ ' 6 Xtestfile3:3 col 1: Line3'], l) - - " List all the entries - redir => result - exe 'silent ' . Xlist . "!" - redir END - let l = split(result, "\n") - call assert_equal([' 1: non-error 1', ' 2 Xtestfile1:1 col 3: Line1', - \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2', - \ ' 5: non-error 3', ' 6 Xtestfile3:3 col 1: Line3'], l) - - " List a range of errors - redir => result - exe 'silent '. Xlist . " 3,6" - redir END - let l = split(result, "\n") - call assert_equal([' 4 Xtestfile2:2 col 2: Line2', - \ ' 6 Xtestfile3:3 col 1: Line3'], l) - - redir => result - exe 'silent ' . Xlist . "! 3,4" - redir END - let l = split(result, "\n") - call assert_equal([' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l) - - redir => result - exe 'silent ' . Xlist . " -6,-4" - redir END - let l = split(result, "\n") - call assert_equal([' 2 Xtestfile1:1 col 3: Line1'], l) - - redir => result - exe 'silent ' . Xlist . "! -5,-3" - redir END - let l = split(result, "\n") - call assert_equal([' 2 Xtestfile1:1 col 3: Line1', - \ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l) - endfunction - - " Tests for the :colder, :cnewer, :lolder and :lnewer commands - " Note that this test assumes that a quickfix/location list is - " already set by the caller - function XageTests(cchar) - let Xolder = a:cchar . 'older' - let Xnewer = a:cchar . 'newer' - let Xgetexpr = a:cchar . 'getexpr' - if a:cchar == 'c' - let Xgetlist = 'getqflist()' - else - let Xgetlist = 'getloclist(0)' - endif - - " Jumping to a non existent list should return error - exe 'silent! ' . Xolder . ' 99' - call assert_true(v:errmsg ==# 'E380: At bottom of quickfix stack') - - exe 'silent! ' . Xnewer . ' 99' - call assert_true(v:errmsg ==# 'E381: At top of quickfix stack') - - " Add three quickfix/location lists - exe Xgetexpr . " ['Xtestfile1:1:3:Line1']" - exe Xgetexpr . " ['Xtestfile2:2:2:Line2']" - exe Xgetexpr . " ['Xtestfile3:3:1:Line3']" - - " Go back two lists - exe Xolder - exe 'let l = ' . Xgetlist - call assert_equal('Line2', l[0].text) - - " Go forward two lists - exe Xnewer - exe 'let l = ' . Xgetlist - call assert_equal('Line3', l[0].text) - - " Test for the optional count argument - exe Xolder . ' 2' - exe 'let l = ' . Xgetlist - call assert_equal('Line1', l[0].text) - - exe Xnewer . ' 2' - exe 'let l = ' . Xgetlist - call assert_equal('Line3', l[0].text) - endfunction - - " Tests for the :cwindow, :lwindow :cclose, :lclose, :copen and :lopen - " commands - function XwindowTests(cchar) - let Xwindow = a:cchar . 'window' - let Xclose = a:cchar . 'close' - let Xopen = a:cchar . 'open' - let Xgetexpr = a:cchar . 'getexpr' - - " Create a list with no valid entries - exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" - - " Quickfix/Location window should not open with no valid errors - exe Xwindow - call assert_true(winnr('$') == 1) - - " Create a list with valid entries - exe Xgetexpr . " ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2', - \ 'Xtestfile3:3:1:Line3']" - - " Open the window - exe Xwindow - call assert_true(winnr('$') == 2 && winnr() == 2 && - \ getline('.') ==# 'Xtestfile1|1 col 3| Line1') - - " Close the window - exe Xclose - call assert_true(winnr('$') == 1) - - " Create a list with no valid entries - exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" - - " Open the window - exe Xopen . ' 5' - call assert_true(winnr('$') == 2 && getline('.') ==# '|| non-error 1' - \ && winheight('.') == 5) - - " Opening the window again, should move the cursor to that window - wincmd t - exe Xopen . ' 7' - call assert_true(winnr('$') == 2 && winnr() == 2 && - \ winheight('.') == 7 && - \ getline('.') ==# '|| non-error 1') - - - " Calling cwindow should close the quickfix window with no valid errors - exe Xwindow - call assert_true(winnr('$') == 1) - endfunction - - " Tests for the :cfile, :lfile, :caddfile, :laddfile, :cgetfile and :lgetfile - " commands. - function XfileTests(cchar) - let Xfile = a:cchar . 'file' - let Xgetfile = a:cchar . 'getfile' - let Xaddfile = a:cchar . 'addfile' - if a:cchar == 'c' - let Xgetlist = 'getqflist()' - else - let Xgetlist = 'getloclist(0)' - endif - - call writefile(['Xtestfile1:700:10:Line 700', - \ 'Xtestfile2:800:15:Line 800'], 'Xqftestfile1') - - enew! - exe Xfile . ' Xqftestfile1' - exe 'let l = ' . Xgetlist - call assert_true(len(l) == 2 && - \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && - \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') - - " Run cfile/lfile from a modified buffer - enew! - silent! put ='Quickfix' - exe 'silent! ' . Xfile . ' Xqftestfile1' - call assert_true(v:errmsg ==# 'E37: No write since last change (add ! to override)') - - call writefile(['Xtestfile3:900:30:Line 900'], 'Xqftestfile1') - exe Xaddfile . ' Xqftestfile1' - exe 'let l = ' . Xgetlist - call assert_true(len(l) == 3 && - \ l[2].lnum == 900 && l[2].col == 30 && l[2].text ==# 'Line 900') - - call writefile(['Xtestfile1:222:77:Line 222', - \ 'Xtestfile2:333:88:Line 333'], 'Xqftestfile1') - - enew! - exe Xgetfile . ' Xqftestfile1' - exe 'let l = ' . Xgetlist - call assert_true(len(l) == 2 && - \ l[0].lnum == 222 && l[0].col == 77 && l[0].text ==# 'Line 222' && - \ l[1].lnum == 333 && l[1].col == 88 && l[1].text ==# 'Line 333') - - call delete('Xqftestfile1') - endfunction - - " Tests for the :cbuffer, :lbuffer, :caddbuffer, :laddbuffer, :cgetbuffer and - " :lgetbuffer commands. - function XbufferTests(cchar) - let Xbuffer = a:cchar . 'buffer' - let Xgetbuffer = a:cchar . 'getbuffer' - let Xaddbuffer = a:cchar . 'addbuffer' - if a:cchar == 'c' - let Xgetlist = 'getqflist()' - else - let Xgetlist = 'getloclist(0)' - endif - - enew! - silent! call setline(1, ['Xtestfile7:700:10:Line 700', - \ 'Xtestfile8:800:15:Line 800']) - exe Xbuffer . "!" - exe 'let l = ' . Xgetlist - call assert_true(len(l) == 2 && - \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && - \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') - - enew! - silent! call setline(1, ['Xtestfile9:900:55:Line 900', - \ 'Xtestfile10:950:66:Line 950']) - exe Xgetbuffer - exe 'let l = ' . Xgetlist - call assert_true(len(l) == 2 && - \ l[0].lnum == 900 && l[0].col == 55 && l[0].text ==# 'Line 900' && - \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950') - - enew! - silent! call setline(1, ['Xtestfile11:700:20:Line 700', - \ 'Xtestfile12:750:25:Line 750']) - exe Xaddbuffer - exe 'let l = ' . Xgetlist - call assert_true(len(l) == 4 && - \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950' && - \ l[2].lnum == 700 && l[2].col == 20 && l[2].text ==# 'Line 700' && - \ l[3].lnum == 750 && l[3].col == 25 && l[3].text ==# 'Line 750') - - endfunction - - function Test_locationlist_curwin_was_closed() - augroup testgroup - au! - autocmd BufReadCmd t call R(expand("")) - augroup END - - function! R(n) - quit - endfunc - - new - let q = [] - call add(q, {'filename': 't' }) - call setloclist(0, q) - call assert_fails('lrewind', 'E924:') - - augroup! testgroup - endfunction - - " This will test for problems in quickfix: - " A. incorrectly copying location lists which caused the location list to show - " a different name than the file that was actually being displayed. - " B. not reusing the window for which the location list window is opened but - " instead creating new windows. - " C. make sure that the location list window is not reused instead of the - " window it belongs to. - " - " Set up the test environment: - function! ReadTestProtocol(name) - let base = substitute(a:name, '\v^test://(.*)%(\.[^.]+)?', '\1', '') - let word = substitute(base, '\v(.*)\..*', '\1', '') - - setl modifiable - setl noreadonly - setl noswapfile - setl bufhidden=delete - %del _ - " For problem 2: - " 'buftype' has to be set to reproduce the constant opening of new windows - setl buftype=nofile - - call setline(1, word) - - setl nomodified - setl nomodifiable - setl readonly - exe 'doautocmd BufRead ' . substitute(a:name, '\v^test://(.*)', '\1', '') - endfunction - - function Test_locationlist() - enew - - augroup testgroup - au! - autocmd BufReadCmd test://* call ReadTestProtocol(expand("")) - augroup END - - let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ] - - let qflist = [] - for word in words - call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', }) - " NOTE: problem 1: - " intentionally not setting 'lnum' so that the quickfix entries are not - " valid - call setloclist(0, qflist, ' ') - endfor - - " Test A - lrewind - enew - lopen - lnext - lnext - lnext - lnext - vert split - wincmd L - lopen - wincmd p - lnext - let fileName = expand("%") - wincmd p - let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '') - let fileName = substitute(fileName, '\\', '/', 'g') - let locationListFileName = substitute(locationListFileName, '\\', '/', 'g') - call assert_equal("test://bar.txt", fileName) - call assert_equal("test://bar.txt", locationListFileName) - - wincmd n | only - - " Test B: - lrewind - lopen - 2 - exe "normal \" - wincmd p - 3 - exe "normal \" - wincmd p - 4 - exe "normal \" - call assert_equal(2, winnr('$')) - wincmd n | only - - " Test C: - lrewind - lopen - " Let's move the location list window to the top to check whether it (the - " first window found) will be reused when we try to open new windows: - wincmd K - 2 - exe "normal \" - wincmd p - 3 - exe "normal \" - wincmd p - 4 - exe "normal \" - 1wincmd w - call assert_equal('quickfix', &buftype) - 2wincmd w - let bufferName = expand("%") - let bufferName = substitute(bufferName, '\\', '/', 'g') - call assert_equal('test://quux.txt', bufferName) - - wincmd n | only - - augroup! testgroup - endfunction - - func Test_vimgreptitle() - augroup QfBufWinEnter - au! - au BufWinEnter * :let g:a=get(w:, 'quickfix_title', 'NONE') - augroup END - try - vimgrep /pattern/j file - catch /E480/ - endtry - copen - call assert_equal(': vimgrep /pattern/j file', g:a) - augroup QfBufWinEnter - au! - augroup END - augroup! QfBufWinEnter - endfunc - - function XquickfixChangedByAutocmd(cchar) - let Xolder = a:cchar . 'older' - let Xgetexpr = a:cchar . 'getexpr' - let Xrewind = a:cchar . 'rewind' - if a:cchar == 'c' - let Xsetlist = 'setqflist(' - let ErrorNr = 'E925' - function! ReadFunc() - colder - cgetexpr [] - endfunc - else - let Xsetlist = 'setloclist(0,' - let ErrorNr = 'E926' - function! ReadFunc() - lolder - lgetexpr [] - endfunc - endif - - augroup testgroup - au! - autocmd BufReadCmd t call ReadFunc() - augroup END - - bwipe! - let words = [ "a", "b" ] - let qflist = [] - for word in words - call add(qflist, {'filename': 't'}) - exec "call " . Xsetlist . "qflist, '')" - endfor - exec "call assert_fails('" . Xrewind . "', '" . ErrorNr . ":')" - - augroup! testgroup - endfunc - - func Test_caddbuffer_to_empty() - helpgr quickfix - call setqflist([], 'r') - cad - try - silent cn - catch - " number of matches is unknown - call assert_true(v:exception =~ 'E553:') - endtry - quit! - endfunc - ]]) - end) - - it('copen/cclose work', function() - source([[ - helpgrep quickfix - copen - " This wipes out the buffer, make sure that doesn't cause trouble. - cclose - ]]) - end) - - it('clist/llist work', function() - call('XlistTests', 'c') - expected_empty() - call('XlistTests', 'l') - expected_empty() - end) - - it('colder/cnewer and lolder/lnewer work', function() - local list = {{bufnr = 1, lnum = 1}} - call('setqflist', list) - call('XageTests', 'c') - expected_empty() - - call('setloclist', 0, list) - call('XageTests', 'l') - expected_empty() - end) - - it('quickfix/location list window commands work', function() - call('XwindowTests', 'c') - expected_empty() - call('XwindowTests', 'l') - expected_empty() - end) - - it('quickfix/location list file commands work', function() - call('XfileTests', 'c') - expected_empty() - call('XfileTests', 'l') - expected_empty() - end) - - it('quickfix/location list buffer commands work', function() - call('XbufferTests', 'c') - expected_empty() - call('XbufferTests', 'l') - expected_empty() - end) - - it('autocommands triggered by quickfix can get title', function() - execute('au FileType qf let g:foo = get(w:, "quickfix_title", "NONE")') - execute('call setqflist([])') - execute('copen') - eq(':setqflist()', eval('g:foo')) - end) - - it('does not truncate quickfix title', function() - call('Test_vimgreptitle') - expected_empty() - end) - - it('errors when an autocommand closes the location list\'s window', function() - call('Test_locationlist_curwin_was_closed') - expected_empty() - end) - - it('checks locationlist protocol read', function() - call('Test_locationlist') - expected_empty() - end) - - it('is changed by autocmd', function() - call('XquickfixChangedByAutocmd', 'c') - expected_empty() - call('XquickfixChangedByAutocmd', 'l') - expected_empty() - end) - - it('does not crash after using caddbuffer with an empty qf list', function() - call('Test_caddbuffer_to_empty') - expected_empty() - end) - - it('cgetexpr does not crash with a NULL element in a list', function() - execute('cgetexpr [$x]') - -- Still alive? - eq(2, eval('1+1')) - end) -end) - -describe('errorformat', function() - before_each(function() - clear() - - source([[ - " More tests for 'errorformat' - function! Test_efm1() - if !has('unix') - " The 'errorformat' setting is different on non-Unix systems. - " This test works only on Unix-like systems. - return - endif - - let l = [ - \ '"Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set.', - \ '"Xtestfile", line 6 col 19; this is an error', - \ 'gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include version.c', - \ 'Xtestfile:9: parse error before `asd''', - \ 'make: *** [vim] Error 1', - \ 'in file "Xtestfile" linenr 10: there is an error', - \ '', - \ '2 returned', - \ '"Xtestfile", line 11 col 1; this is an error', - \ '"Xtestfile", line 12 col 2; this is another error', - \ '"Xtestfile", line 14:10; this is an error in column 10', - \ '=Xtestfile=, line 15:10; this is another error, but in vcol 10 this time', - \ '"Xtestfile", linenr 16: yet another problem', - \ 'Error in "Xtestfile" at line 17:', - \ 'x should be a dot', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17', - \ ' ^', - \ 'Error in "Xtestfile" at line 18:', - \ 'x should be a dot', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18', - \ '.............^', - \ 'Error in "Xtestfile" at line 19:', - \ 'x should be a dot', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19', - \ '--------------^', - \ 'Error in "Xtestfile" at line 20:', - \ 'x should be a dot', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20', - \ ' ^', - \ '', - \ 'Does anyone know what is the problem and how to correction it?', - \ '"Xtestfile", line 21 col 9: What is the title of the quickfix window?', - \ '"Xtestfile", line 22 col 9: What is the title of the quickfix window?' - \ ] - - call writefile(l, 'Xerrorfile1') - call writefile(l[:-2], 'Xerrorfile2') - - let m = [ - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 4', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 5', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 6', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 7', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 8', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 9', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 10', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 11', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 12', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 13', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 14', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 15', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 16', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 21', - \ ' xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 22' - \ ] - call writefile(m, 'Xtestfile') - - let save_efm = &efm - set efm+==%f=\\,\ line\ %l%*\\D%v%*[^\ ]\ %m - set efm^=%AError\ in\ \"%f\"\ at\ line\ %l:,%Z%p^,%C%m - - exe 'cf Xerrorfile2' - clast - copen - call assert_equal(':cf Xerrorfile2', w:quickfix_title) - wincmd p - - exe 'cf Xerrorfile1' - call assert_equal([4, 12], [line('.'), col('.')]) - cn - call assert_equal([6, 19], [line('.'), col('.')]) - cn - call assert_equal([9, 2], [line('.'), col('.')]) - cn - call assert_equal([10, 2], [line('.'), col('.')]) - cn - call assert_equal([11, 1], [line('.'), col('.')]) - cn - call assert_equal([12, 2], [line('.'), col('.')]) - cn - call assert_equal([14, 10], [line('.'), col('.')]) - cn - call assert_equal([15, 3, 10], [line('.'), col('.'), virtcol('.')]) - cn - call assert_equal([16, 2], [line('.'), col('.')]) - cn - call assert_equal([17, 6], [line('.'), col('.')]) - cn - call assert_equal([18, 7], [line('.'), col('.')]) - cn - call assert_equal([19, 8], [line('.'), col('.')]) - cn - call assert_equal([20, 9], [line('.'), col('.')]) - clast - cprev - cprev - wincmd w - call assert_equal(':cf Xerrorfile1', w:quickfix_title) - wincmd p - - let &efm = save_efm - call delete('Xerrorfile1') - call delete('Xerrorfile2') - call delete('Xtestfile') - endfunction - ]]) - end) - - it('works', function() - call('Test_efm1') - expected_empty() - end) -end) From e89efe75f9fd872e2c7323ea525b35af90e8afa0 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 10:56:00 -0500 Subject: [PATCH 02/26] vim-patch:7.4.1752 Problem: When adding to the quickfix list the current position is reset. Solution: Do not reset the position when not needed. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/c1808d5822ed9534ef7f0fe509b15bee92a5cc28 --- src/nvim/quickfix.c | 26 +++++++++------- src/nvim/testdir/test_quickfix.vim | 48 ++++++++++++++++++++++++++++++ src/nvim/version.c | 2 +- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index f0d77f9e2b..b97530b700 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -786,7 +786,7 @@ qf_init_end: xfree(pattern); xfree(fmtstr); - qf_update_buffer(qi); + qf_update_buffer(qi, true); return retval; } @@ -1927,7 +1927,7 @@ static void qf_msg(qf_info_T *qi) smsg(_("error list %d of %d; %d errors"), qi->qf_curlist + 1, qi->qf_listcount, qi->qf_lists[qi->qf_curlist].qf_count); - qf_update_buffer(qi); + qf_update_buffer(qi, true); } /* @@ -2314,7 +2314,7 @@ static buf_T *qf_find_buf(qf_info_T *qi) /* * Find the quickfix buffer. If it exists, update the contents. */ -static void qf_update_buffer(qf_info_T *qi) +static void qf_update_buffer(qf_info_T *qi, bool update_cursor) { buf_T *buf; win_T *win; @@ -2337,8 +2337,9 @@ static void qf_update_buffer(qf_info_T *qi) /* restore curwin/curbuf and a few other things */ aucmd_restbuf(&aco); - - (void)qf_win_pos_update(qi, 0); + if (update_cursor) { + (void)qf_win_pos_update(qi, 0); + } } } @@ -3240,7 +3241,7 @@ void ex_vimgrep(exarg_T *eap) qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; qi->qf_lists[qi->qf_curlist].qf_index = 1; - qf_update_buffer(qi); + qf_update_buffer(qi, true); if (au_name != NULL) apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, @@ -3624,12 +3625,15 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE; else qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; - qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; - if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { - qi->qf_lists[qi->qf_curlist].qf_index = 1; + if (action != 'a') { + qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; + if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { + qi->qf_lists[qi->qf_curlist].qf_index = 1; + } } - qf_update_buffer(qi); + // Don't update the cursor in quickfix window when appending entries + qf_update_buffer(qi, (action != 'a')); return retval; } @@ -3885,7 +3889,7 @@ void ex_helpgrep(exarg_T *eap) /* Darn, some plugin changed the value. */ free_string_option(save_cpo); - qf_update_buffer(qi); + qf_update_buffer(qi, true); if (au_name != NULL) { apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 9dbd00b001..9955b4f775 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -679,3 +679,51 @@ func Test_cgetexpr_works() " this must not crash Vim cgetexpr [$x] endfunc + +" Tests for the setqflist() and setloclist() functions +function SetXlistTests(cchar, bnum) + if a:cchar == 'c' + let Xsetlist = function('setqflist') + let Xgetlist = function('getqflist') + let Xnext = 'cnext' + else + let Xsetlist = function('setloclist', [0]) + let Xgetlist = function('getloclist', [0]) + let Xnext = 'lnext' + endif + + call Xsetlist([{'bufnr': a:bnum, 'lnum': 1}, + \ {'bufnr': a:bnum, 'lnum': 2}]) + let l = Xgetlist() + call assert_equal(2, len(l)) + call assert_equal(2, l[1].lnum) + + exe Xnext + call Xsetlist([{'bufnr': a:bnum, 'lnum': 3}], 'a') + let l = Xgetlist() + call assert_equal(3, len(l)) + exe Xnext + call assert_equal(3, line('.')) + + call Xsetlist([{'bufnr': a:bnum, 'lnum': 3}, + \ {'bufnr': a:bnum, 'lnum': 4}, + \ {'bufnr': a:bnum, 'lnum': 5}], 'r') + let l = Xgetlist() + call assert_equal(3, len(l)) + call assert_equal(5, l[2].lnum) + + call Xsetlist([]) + let l = Xgetlist() + call assert_equal(0, len(l)) +endfunction + +function Test_setqflist() + new Xtestfile | only + let bnum = bufnr('%') + call setline(1, range(1,5)) + + call SetXlistTests('c', bnum) + call SetXlistTests('l', bnum) + + call delete('Xtestfile') +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index ed1d7448ea..d10d5cf75b 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -689,7 +689,7 @@ static int included_patches[] = { 1754, 1753, // 1753, - // 1752, + 1752, 1751, // 1750 NA // 1749 NA From 29d7a597115b692a7e2e39d213b87ac566444a5c Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 11:33:51 -0500 Subject: [PATCH 03/26] vim-patch:7.4.1768 Problem: Arguments of setqflist() are not checked properly. Solution: Add better checks, add a test. (Nikolai Pavlov, Hirohito Higashi, closes vim/vim#661) https://github.com/vim/vim/commit/d106e5ba7f10f0d2a14eaefe5d78405044416cb9 --- src/nvim/eval.c | 11 ++- src/nvim/po/uk.po | 4 +- src/nvim/testdir/test_quickfix.vim | 102 ++++++++++++++++++++++-- src/nvim/version.c | 2 +- test/functional/viml/errorlist_spec.lua | 12 +-- 5 files changed, 111 insertions(+), 20 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 39e121eb53..45364a1666 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -158,7 +158,7 @@ static char *e_listdictarg = N_( static char *e_emptykey = N_("E713: Cannot use empty key for Dictionary"); static char *e_listreq = N_("E714: List required"); static char *e_dictreq = N_("E715: Dictionary required"); -static char *e_strreq = N_("E114: String required"); +static char *e_stringreq = N_("E928: String required"); static char *e_toomanyarg = N_("E118: Too many arguments for function: %s"); static char *e_dictkey = N_("E716: Key not present in Dictionary: %s"); static char *e_funcexts = N_( @@ -14996,6 +14996,7 @@ static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv) FUNC_ATTR_NONNULL_ARG(2, 3) { + static char *e_invact = N_("E927: Invalid action: '%s'"); char_u *title = NULL; int action = ' '; rettv->vval.v_number = -1; @@ -15011,13 +15012,17 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv) // Option argument was not given. goto skip_args; } else if (action_arg->v_type != VAR_STRING) { - EMSG(_(e_strreq)); + EMSG(_(e_stringreq)); return; } char_u *act = get_tv_string_chk(action_arg); - if (*act == 'a' || *act == 'r') { + if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL) { action = *act; } + else { + EMSG2(_(e_invact), act); + return; + } typval_T *title_arg = &args[2]; if (title_arg->v_type == VAR_UNKNOWN) { diff --git a/src/nvim/po/uk.po b/src/nvim/po/uk.po index bbbb462292..3145931bfe 100644 --- a/src/nvim/po/uk.po +++ b/src/nvim/po/uk.po @@ -564,8 +564,8 @@ msgstr "E714: Потрібен список" msgid "E715: Dictionary required" msgstr "E715: Потрібен словник" -msgid "E114: String required" -msgstr "E114: Потрібен String" +msgid "E928: String required" +msgstr "E928: Потрібен String" #, c-format msgid "E118: Too many arguments for function: %s" diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 9955b4f775..2c6f3c922a 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -483,7 +483,7 @@ endfunction function Test_locationlist_curwin_was_closed() augroup testgroup au! - autocmd BufReadCmd t call R(expand("")) + autocmd BufReadCmd test_curwin.txt call R(expand("")) augroup END function! R(n) @@ -492,7 +492,7 @@ function Test_locationlist_curwin_was_closed() new let q = [] - call add(q, {'filename': 't' }) + call add(q, {'filename': 'test_curwin.txt' }) call setloclist(0, q) call assert_fails('lrewind', 'E924:') @@ -625,14 +625,14 @@ function XquickfixChangedByAutocmd(cchar) let Xgetexpr = a:cchar . 'getexpr' let Xrewind = a:cchar . 'rewind' if a:cchar == 'c' - let Xsetlist = 'setqflist(' + let Xsetlist = function('setqflist') let ErrorNr = 'E925' function! ReadFunc() colder cgetexpr [] endfunc else - let Xsetlist = 'setloclist(0,' + let Xsetlist = function('setloclist', [0]) let ErrorNr = 'E926' function! ReadFunc() lolder @@ -642,15 +642,15 @@ function XquickfixChangedByAutocmd(cchar) augroup testgroup au! - autocmd BufReadCmd t call ReadFunc() + autocmd BufReadCmd test_changed.txt call ReadFunc() augroup END - bwipe! + new | only let words = [ "a", "b" ] let qflist = [] for word in words - call add(qflist, {'filename': 't'}) - exec "call " . Xsetlist . "qflist, '')" + call add(qflist, {'filename': 'test_changed.txt'}) + call Xsetlist(qflist, ' ') endfor exec "call assert_fails('" . Xrewind . "', '" . ErrorNr . ":')" @@ -727,3 +727,89 @@ function Test_setqflist() call delete('Xtestfile') endfunction + +function! XquickfixSetListWithAct(cchar) + let Xolder = a:cchar . 'older' + let Xnewer = a:cchar . 'newer' + if a:cchar == 'c' + let Xsetlist = function('setqflist') + let Xgetlist = function('getqflist') + else + let Xsetlist = function('setloclist', [0]) + let Xgetlist = function('getloclist', [0]) + endif + let list1 = [{'filename': 'fnameA', 'text': 'A'}, + \ {'filename': 'fnameB', 'text': 'B'}] + let list2 = [{'filename': 'fnameC', 'text': 'C'}, + \ {'filename': 'fnameD', 'text': 'D'}, + \ {'filename': 'fnameE', 'text': 'E'}] + + " {action} is unspecified. Same as specifing ' '. + new | only + exec "silent! " . Xnewer . "99" + call Xsetlist(list1) + call Xsetlist(list2) + let li = Xgetlist() + call assert_equal(3, len(li)) + call assert_equal('C', li[0]['text']) + call assert_equal('D', li[1]['text']) + call assert_equal('E', li[2]['text']) + exec "silent! " . Xolder + let li = Xgetlist() + call assert_equal(2, len(li)) + call assert_equal('A', li[0]['text']) + call assert_equal('B', li[1]['text']) + + " {action} is specified ' '. + new | only + exec "silent! " . Xnewer . "99" + call Xsetlist(list1) + call Xsetlist(list2, ' ') + let li = Xgetlist() + call assert_equal(3, len(li)) + call assert_equal('C', li[0]['text']) + call assert_equal('D', li[1]['text']) + call assert_equal('E', li[2]['text']) + exec "silent! " . Xolder + let li = Xgetlist() + call assert_equal(2, len(li)) + call assert_equal('A', li[0]['text']) + call assert_equal('B', li[1]['text']) + + " {action} is specified 'a'. + new | only + exec "silent! " . Xnewer . "99" + call Xsetlist(list1) + call Xsetlist(list2, 'a') + let li = Xgetlist() + call assert_equal(5, len(li)) + call assert_equal('A', li[0]['text']) + call assert_equal('B', li[1]['text']) + call assert_equal('C', li[2]['text']) + call assert_equal('D', li[3]['text']) + call assert_equal('E', li[4]['text']) + + " {action} is specified 'r'. + new | only + exec "silent! " . Xnewer . "99" + call Xsetlist(list1) + call Xsetlist(list2, 'r') + let li = Xgetlist() + call assert_equal(3, len(li)) + call assert_equal('C', li[0]['text']) + call assert_equal('D', li[1]['text']) + call assert_equal('E', li[2]['text']) + + " Test for wrong value. + new | only + call assert_fails("call Xsetlist(0)", 'E714:') + call assert_fails("call Xsetlist(list1, '')", 'E927:') + call assert_fails("call Xsetlist(list1, 'aa')", 'E927:') + call assert_fails("call Xsetlist(list1, ' a')", 'E927:') + call assert_fails("call Xsetlist(list1, 0)", 'E928:') +endfunc + +function Test_quickfix_set_list_with_act() + call XquickfixSetListWithAct('c') + call XquickfixSetListWithAct('l') +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index d10d5cf75b..a5addaf819 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -672,7 +672,7 @@ static int included_patches[] = { // 1771 NA // 1770 NA // 1769, - // 1768, + 1768, // 1767 NA // 1766 NA 1765, diff --git a/test/functional/viml/errorlist_spec.lua b/test/functional/viml/errorlist_spec.lua index 56d08771b7..f889ca9adc 100644 --- a/test/functional/viml/errorlist_spec.lua +++ b/test/functional/viml/errorlist_spec.lua @@ -18,9 +18,9 @@ describe('setqflist()', function() end) it('requires a string for {action}', function() - eq('Vim(call):E114: String required', exc_exec('call setqflist([], 5)')) - eq('Vim(call):E114: String required', exc_exec('call setqflist([], [])')) - eq('Vim(call):E114: String required', exc_exec('call setqflist([], {})')) + eq('Vim(call):E928: String required', exc_exec('call setqflist([], 5)')) + eq('Vim(call):E928: String required', exc_exec('call setqflist([], [])')) + eq('Vim(call):E928: String required', exc_exec('call setqflist([], {})')) end) it('sets w:quickfix_title', function() @@ -56,9 +56,9 @@ describe('setloclist()', function() end) it('requires a string for {action}', function() - eq('Vim(call):E114: String required', exc_exec('call setloclist(0, [], 5)')) - eq('Vim(call):E114: String required', exc_exec('call setloclist(0, [], [])')) - eq('Vim(call):E114: String required', exc_exec('call setloclist(0, [], {})')) + eq('Vim(call):E928: String required', exc_exec('call setloclist(0, [], 5)')) + eq('Vim(call):E928: String required', exc_exec('call setloclist(0, [], [])')) + eq('Vim(call):E928: String required', exc_exec('call setloclist(0, [], {})')) end) it('sets w:quickfix_title for the correct window', function() From 39faa56bce66796f731ec339301acc3d303c08e9 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:04:44 -0500 Subject: [PATCH 04/26] vim-patch:7.4.1802 Problem: Quickfix doesn't handle long lines well, they are split. Solution: Drop characters after a limit. (Anton Lindqvist) https://github.com/vim/vim/commit/6be8c8e165204b8aa4eeb8a52be87a58d8b41b9e --- src/nvim/quickfix.c | 210 +++++++++++++++++++++----- src/nvim/testdir/samples/quickfix.txt | 3 + src/nvim/testdir/test_quickfix.vim | 37 +++++ src/nvim/version.c | 2 +- 4 files changed, 216 insertions(+), 36 deletions(-) create mode 100644 src/nvim/testdir/samples/quickfix.txt diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index b97530b700..3c59fcef03 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -168,6 +168,9 @@ qf_init ( qf_title); } +// Maximum number of bytes allowed per line while reading an errorfile. +static const size_t LINE_MAXLEN = 4096; + /* * Read the errorfile "efile" into memory, line by line, building the error * list. @@ -192,8 +195,15 @@ qf_init_ext ( { char_u *namebuf; char_u *errmsg; + size_t errmsglen; char_u *pattern; char_u *fmtstr = NULL; + char_u *growbuf = NULL; + size_t growbuflen; + size_t growbufsiz; + char_u *linebuf; + size_t linelen; + bool discard; int col = 0; bool use_viscol = false; char_u type = 0; @@ -210,7 +220,7 @@ qf_init_ext ( char_u *efm; char_u *ptr; char_u *srcptr; - int len; + size_t len; int i; int round; int idx = 0; @@ -221,6 +231,7 @@ qf_init_ext ( char_u *directory = NULL; char_u *currfile = NULL; char_u *tail = NULL; + char_u *p_buf = NULL; char_u *p_str = NULL; listitem_T *p_li = NULL; struct dir_stack_T *file_stack = NULL; @@ -243,7 +254,8 @@ qf_init_ext ( }; namebuf = xmalloc(CMDBUFFSIZE + 1); - errmsg = xmalloc(CMDBUFFSIZE + 1); + errmsglen = CMDBUFFSIZE + 1; + errmsg = xmalloc(errmsglen); pattern = xmalloc(CMDBUFFSIZE + 1); if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL) { @@ -466,36 +478,66 @@ qf_init_ext ( /* Get the next line from the supplied string */ char_u *p; - if (!*p_str) /* Reached the end of the string */ + if (*p_str == NUL) // Reached the end of the string break; p = vim_strchr(p_str, '\n'); - if (p) - len = (int)(p - p_str + 1); + if (p != NULL) + len = (size_t)(p - p_str) + 1; else - len = (int)STRLEN(p_str); + len = STRLEN(p_str); - if (len > CMDBUFFSIZE - 2) - STRLCPY(IObuff, p_str, CMDBUFFSIZE - 1); - else - STRLCPY(IObuff, p_str, len + 1); + if (len > IOSIZE - 2) { + // If the line exceeds LINE_MAXLEN exclude the last byte since it's + // not a NL character. + linelen = len > LINE_MAXLEN ? LINE_MAXLEN - 1 : len; + if (growbuf == NULL) { + growbuf = xmalloc(linelen); + } else if (linelen > growbufsiz) { + growbuf = xrealloc(growbuf, linelen); + } + growbufsiz = linelen; + linebuf = growbuf; + } else { + linebuf = IObuff; + linelen = len; + } + STRLCPY(linebuf, p_str, linelen + 1); + // Increment using len in order to discard the rest of the line if it + // exceeds LINE_MAXLEN. p_str += len; } else if (tv->v_type == VAR_LIST) { // Get the next line from the supplied list - while (p_li && (p_li->li_tv.v_type != VAR_STRING - || p_li->li_tv.vval.v_string == NULL)) { + while (p_li != NULL + && (p_li->li_tv.v_type != VAR_STRING + || p_li->li_tv.vval.v_string == NULL)) { p_li = p_li->li_next; // Skip non-string items } - if (!p_li) /* End of the list */ + if (p_li == NULL) // End of the list break; - len = (int)STRLEN(p_li->li_tv.vval.v_string); - if (len > CMDBUFFSIZE - 2) - len = CMDBUFFSIZE - 2; + len = STRLEN(p_li->li_tv.vval.v_string); + if (len > IOSIZE - 2) { + linelen = len; + if (linelen > LINE_MAXLEN) { + linelen = LINE_MAXLEN - 1; + } + if (growbuf == NULL) { + growbuf = xmalloc(linelen); + growbufsiz = linelen; + } else if (linelen > growbufsiz) { + growbuf = xrealloc(growbuf, linelen); + growbufsiz = linelen; + } + linebuf = growbuf; + } else { + linebuf = IObuff; + linelen = len; + } - STRLCPY(IObuff, p_li->li_tv.vval.v_string, len + 1); + STRLCPY(linebuf, p_li->li_tv.vval.v_string, linelen + 1); p_li = p_li->li_next; /* next item */ } @@ -503,21 +545,103 @@ qf_init_ext ( /* Get the next line from the supplied buffer */ if (buflnum > lnumlast) break; - STRLCPY(IObuff, ml_get_buf(buf, buflnum++, FALSE), - CMDBUFFSIZE - 1); + p_buf = ml_get_buf(buf, buflnum++, false); + linelen = STRLEN(p_buf); + if (linelen > IOSIZE - 2) { + if (growbuf == NULL) { + growbuf = xmalloc(linelen); + growbufsiz = linelen; + } else if (linelen > growbufsiz) { + if (linelen > LINE_MAXLEN) { + linelen = LINE_MAXLEN - 1; + } + growbuf = xrealloc(growbuf, linelen); + growbufsiz = linelen; + } + linebuf = growbuf; + } else { + linebuf = IObuff; + } + STRLCPY(linebuf, p_buf, linelen + 1); + } + } else { + if (fgets((char *)IObuff, IOSIZE, fd) == NULL) { + break; } - } else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL) - break; - IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */ - remove_bom(IObuff); - - if ((efmp = vim_strrchr(IObuff, '\n')) != NULL) - *efmp = NUL; + discard = false; + linelen = STRLEN(IObuff); + if (linelen == IOSIZE - 1 && (IObuff[linelen - 1] != '\n' #ifdef USE_CRNL - if ((efmp = vim_strrchr(IObuff, '\r')) != NULL) - *efmp = NUL; + || IObuff[linelen - 1] != '\r' #endif + )) { + // The current line exceeds IObuff, continue reading using growbuf + // until EOL or LINE_MAXLEN bytes is read. + if (growbuf == NULL) { + growbufsiz = 2 * (IOSIZE - 1); + growbuf = xmalloc(growbufsiz); + } + + // Copy the read part of the line, excluding null-terminator + memcpy(growbuf, IObuff, IOSIZE - 1); + growbuflen = linelen; + + for (;;) { + if (fgets((char*)growbuf + growbuflen, + (int)(growbufsiz - growbuflen), fd) == NULL) { + break; + } + linelen = STRLEN(growbuf + growbuflen); + growbuflen += linelen; + if (growbuf[growbuflen - 1] == '\n' +#ifdef USE_CRNL + || growbuf[growbuflen - 1] == '\r' +#endif + ) { + break; + } + if (growbufsiz == LINE_MAXLEN) { + discard = true; + break; + } + + growbufsiz = (2 * growbufsiz < LINE_MAXLEN) + ? 2 * growbufsiz : LINE_MAXLEN; + growbuf = xrealloc(growbuf, 2 * growbufsiz); + } + + while (discard) { + // The current line is longer than LINE_MAXLEN, continue reading but + // discard everything until EOL or EOF is reached. + if (fgets((char *)IObuff, IOSIZE, fd) == NULL + || STRLEN(IObuff) < IOSIZE - 1 + || IObuff[IOSIZE - 1] == '\n' +#ifdef USE_CRNL + || IObuff[IOSIZE - 1] == '\r' +#endif + ) { + break; + } + } + + linebuf = growbuf; + linelen = growbuflen; + } else { + linebuf = IObuff; + } + } + + if (linelen > 0 && linebuf[linelen - 1] == '\n') { + linebuf[linelen - 1] = NUL; + } +#ifdef USE_CRNL + if (linelen > 0 && linebuf[linelen - 1] == '\r') { + linebuf[linelen - 1] = NUL; + } +#endif + + remove_bom(linebuf); /* If there was no %> item start at the first pattern */ if (fmt_start == NULL) @@ -547,7 +671,7 @@ restofline: tail = NULL; regmatch.regprog = fmt_ptr->prog; - int r = vim_regexec(®match, IObuff, (colnr_T)0); + int r = vim_regexec(®match, linebuf, (colnr_T)0); fmt_ptr->prog = regmatch.regprog; if (r) { if ((idx == 'C' || idx == 'Z') && !multiline) { @@ -596,12 +720,22 @@ restofline: continue; type = *regmatch.startp[i]; } - if (fmt_ptr->flags == '+' && !multiscan) /* %+ */ - STRCPY(errmsg, IObuff); - else if ((i = (int)fmt_ptr->addr[5]) > 0) { /* %m */ + if (fmt_ptr->flags == '+' && !multiscan) { // %+ + if (linelen > errmsglen) { + // linelen + null terminator + errmsg = xrealloc(errmsg, linelen + 1); + errmsglen = linelen + 1; + } + STRLCPY(errmsg, linebuf, linelen + 1); + } else if ((i = (int)fmt_ptr->addr[5]) > 0) { /* %m */ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) continue; - len = (int)(regmatch.endp[i] - regmatch.startp[i]); + len = (size_t)(regmatch.endp[i] - regmatch.startp[i]); + if (len > errmsglen) { + // len + null terminator + errmsg = xrealloc(errmsg, len + 1); + errmsglen = len + 1; + } STRLCPY(errmsg, regmatch.startp[i], len + 1); } if ((i = (int)fmt_ptr->addr[6]) > 0) { /* %r */ @@ -635,7 +769,7 @@ restofline: if ((i = (int)fmt_ptr->addr[9]) > 0) { /* %s */ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) continue; - len = (int)(regmatch.endp[i] - regmatch.startp[i]); + len = (size_t)(regmatch.endp[i] - regmatch.startp[i]); if (len > CMDBUFFSIZE - 5) len = CMDBUFFSIZE - 5; STRCPY(pattern, "^\\V"); @@ -664,7 +798,12 @@ restofline: namebuf[0] = NUL; // no match found, remove file name lnum = 0; // don't jump to this line valid = false; - STRCPY(errmsg, IObuff); // copy whole line to error message + if (linelen > errmsglen) { + // linelen + null terminator + errmsg = xrealloc(errmsg, linelen + 1); + } + // copy whole line to error message + STRLCPY(errmsg, linebuf, linelen + 1); if (fmt_ptr == NULL) { multiline = multiignore = false; } @@ -785,6 +924,7 @@ qf_init_end: xfree(errmsg); xfree(pattern); xfree(fmtstr); + xfree(growbuf); qf_update_buffer(qi, true); diff --git a/src/nvim/testdir/samples/quickfix.txt b/src/nvim/testdir/samples/quickfix.txt new file mode 100644 index 0000000000..38c8f49149 --- /dev/null +++ b/src/nvim/testdir/samples/quickfix.txt @@ -0,0 +1,3 @@ +samples/quickfix.txt:1:1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +samples/quickfix.txt:2:1:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +samples/quickfix.txt:3:1:cccccccccc diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 2c6f3c922a..d43ab1e6db 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -813,3 +813,40 @@ function Test_quickfix_set_list_with_act() call XquickfixSetListWithAct('c') call XquickfixSetListWithAct('l') endfunction + +func XLongLinesTests() + let l = getqflist() + + call assert_equal(3, len(l)) + call assert_equal(1, l[0].lnum) + call assert_equal(1, l[0].col) + call assert_equal(4070, len(l[0].text)) + call assert_equal(2, l[1].lnum) + call assert_equal(1, l[1].col) + call assert_equal(4070, len(l[1].text)) + call assert_equal(3, l[2].lnum) + call assert_equal(1, l[2].col) + call assert_equal(10, len(l[2].text)) + + call setqflist([], 'r') +endfunc + +func Test_long_lines() + let testfile = 'samples/quickfix.txt' + + " file + exe 'cgetfile' testfile + call XLongLinesTests() + + " list + cexpr readfile(testfile) + call XLongLinesTests() + + " string + cexpr join(readfile(testfile), "\n") + call XLongLinesTests() + + " buffer + e testfile + exe 'cbuffer' bufnr('%') +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index a5addaf819..897daf359c 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -637,7 +637,7 @@ static int included_patches[] = { // 1805 NA // 1804 NA // 1803 NA - // 1802, + 1802, // 1801 NA // 1800 NA 1799, From 48b5d0f1ba1ad75411f6510ed79d322116ba6809 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:04:52 -0500 Subject: [PATCH 05/26] vim-patch:7.4.1813 Problem: Memory access error when running test_quickfix. Solution: Allocate one more byte. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/9b4ebc692d77ca8ef90d72517347f74c2474dd3d --- src/nvim/quickfix.c | 12 ++++++------ src/nvim/version.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 3c59fcef03..b4f8750c4c 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -492,9 +492,9 @@ qf_init_ext ( // not a NL character. linelen = len > LINE_MAXLEN ? LINE_MAXLEN - 1 : len; if (growbuf == NULL) { - growbuf = xmalloc(linelen); + growbuf = xmalloc(linelen + 1); } else if (linelen > growbufsiz) { - growbuf = xrealloc(growbuf, linelen); + growbuf = xrealloc(growbuf, linelen + 1); } growbufsiz = linelen; linebuf = growbuf; @@ -525,10 +525,10 @@ qf_init_ext ( linelen = LINE_MAXLEN - 1; } if (growbuf == NULL) { - growbuf = xmalloc(linelen); + growbuf = xmalloc(linelen + 1); growbufsiz = linelen; } else if (linelen > growbufsiz) { - growbuf = xrealloc(growbuf, linelen); + growbuf = xrealloc(growbuf, linelen + 1); growbufsiz = linelen; } linebuf = growbuf; @@ -549,13 +549,13 @@ qf_init_ext ( linelen = STRLEN(p_buf); if (linelen > IOSIZE - 2) { if (growbuf == NULL) { - growbuf = xmalloc(linelen); + growbuf = xmalloc(linelen + 1); growbufsiz = linelen; } else if (linelen > growbufsiz) { if (linelen > LINE_MAXLEN) { linelen = LINE_MAXLEN - 1; } - growbuf = xrealloc(growbuf, linelen); + growbuf = xrealloc(growbuf, linelen + 1); growbufsiz = linelen; } linebuf = growbuf; diff --git a/src/nvim/version.c b/src/nvim/version.c index 897daf359c..5edced3f0d 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -626,7 +626,7 @@ static int included_patches[] = { 1816, // 1815, // 1814 NA - // 1813, + 1813, // 1812, // 1811 NA // 1810 NA From b9c5ca21e6a666dfcd3324720ca59ed52ce34883 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:04:57 -0500 Subject: [PATCH 06/26] vim-patch:7.4.1815 Problem: Compiler warnings for unused variables. (Ajit Thakkar) Solution: Add a dummy initialization. (Yasuhiro Matsumoto) https://github.com/vim/vim/commit/9a3b3311d26c990208150255ad65472bb4eefaa4 --- src/nvim/quickfix.c | 6 +++--- src/nvim/version.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index b4f8750c4c..1188ed7fd4 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -200,9 +200,9 @@ qf_init_ext ( char_u *fmtstr = NULL; char_u *growbuf = NULL; size_t growbuflen; - size_t growbufsiz; - char_u *linebuf; - size_t linelen; + size_t growbufsiz = 0; + char_u *linebuf = NULL; + size_t linelen = 0; bool discard; int col = 0; bool use_viscol = false; diff --git a/src/nvim/version.c b/src/nvim/version.c index 5edced3f0d..e8f639fcd4 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -624,7 +624,7 @@ static int included_patches[] = { 1818, // 1817 NA 1816, - // 1815, + 1815, // 1814 NA 1813, // 1812, From e2b081ed0c9aa43e891e5b33c1f3f077bc579356 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 13 Dec 2016 11:03:28 -0500 Subject: [PATCH 07/26] vim-patch:7.4.1823 Problem: Warning from 64 bit compiler. Solution: Add type cast. (Mike Williams) https://github.com/vim/vim/commit/d9db8b448c214eb583e84c598bca0688b9202ba7 Already silenced in earlier commits by using size_t. --- src/nvim/version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/version.c b/src/nvim/version.c index e8f639fcd4..c8eae8b588 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -616,7 +616,7 @@ static int included_patches[] = { // 1826 NA // 1825 NA // 1824 NA - // 1823, + 1823, // 1822 NA 1821, 1820, From 9df9cf4ecc4143ce23b5ab85b2ad1ef413a249bd Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:01 -0500 Subject: [PATCH 08/26] vim-patch:7.4.1841 Problem: The code to reallocate the buffer used for quickfix is repeated. Solution: Move the code to a function. (Yegappan Lakshmanan, closes vim/vim#831) https://github.com/vim/vim/commit/2b2b8ae5ab37b04584633c469265d85825166905 --- src/nvim/quickfix.c | 52 +++++++++++------------------- src/nvim/testdir/test_quickfix.vim | 13 ++++++-- src/nvim/version.c | 2 +- 3 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 1188ed7fd4..a68c4eca2e 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -171,6 +171,22 @@ qf_init ( // Maximum number of bytes allowed per line while reading an errorfile. static const size_t LINE_MAXLEN = 4096; +static char_u *qf_grow_linebuf(char_u **growbuf, size_t *growbufsiz, + size_t newsz, size_t *allocsz) +{ + // If the line exceeds LINE_MAXLEN exclude the last + // byte since it's not a NL character. + *allocsz = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz; + if (*growbuf == NULL) { + *growbuf = xmalloc(*allocsz + 1); + *growbufsiz = *allocsz; + } else if (*allocsz > *growbufsiz) { + *growbuf = xrealloc(*growbuf, *allocsz + 1); + *growbufsiz = *allocsz; + } + return *growbuf; +} + /* * Read the errorfile "efile" into memory, line by line, building the error * list. @@ -488,16 +504,7 @@ qf_init_ext ( len = STRLEN(p_str); if (len > IOSIZE - 2) { - // If the line exceeds LINE_MAXLEN exclude the last byte since it's - // not a NL character. - linelen = len > LINE_MAXLEN ? LINE_MAXLEN - 1 : len; - if (growbuf == NULL) { - growbuf = xmalloc(linelen + 1); - } else if (linelen > growbufsiz) { - growbuf = xrealloc(growbuf, linelen + 1); - } - growbufsiz = linelen; - linebuf = growbuf; + linebuf = qf_grow_linebuf(&growbuf, &growbufsiz, len, &linelen); } else { linebuf = IObuff; linelen = len; @@ -520,18 +527,7 @@ qf_init_ext ( len = STRLEN(p_li->li_tv.vval.v_string); if (len > IOSIZE - 2) { - linelen = len; - if (linelen > LINE_MAXLEN) { - linelen = LINE_MAXLEN - 1; - } - if (growbuf == NULL) { - growbuf = xmalloc(linelen + 1); - growbufsiz = linelen; - } else if (linelen > growbufsiz) { - growbuf = xrealloc(growbuf, linelen + 1); - growbufsiz = linelen; - } - linebuf = growbuf; + linebuf = qf_grow_linebuf(&growbuf, &growbufsiz, len, &linelen); } else { linebuf = IObuff; linelen = len; @@ -548,17 +544,7 @@ qf_init_ext ( p_buf = ml_get_buf(buf, buflnum++, false); linelen = STRLEN(p_buf); if (linelen > IOSIZE - 2) { - if (growbuf == NULL) { - growbuf = xmalloc(linelen + 1); - growbufsiz = linelen; - } else if (linelen > growbufsiz) { - if (linelen > LINE_MAXLEN) { - linelen = LINE_MAXLEN - 1; - } - growbuf = xrealloc(growbuf, linelen + 1); - growbufsiz = linelen; - } - linebuf = growbuf; + linebuf = qf_grow_linebuf(&growbuf, &growbufsiz, len, &linelen); } else { linebuf = IObuff; } diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index d43ab1e6db..73ee240c77 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -682,14 +682,14 @@ endfunc " Tests for the setqflist() and setloclist() functions function SetXlistTests(cchar, bnum) + let Xwindow = a:cchar . 'window' + let Xnext = a:cchar . 'next' if a:cchar == 'c' let Xsetlist = function('setqflist') let Xgetlist = function('getqflist') - let Xnext = 'cnext' else let Xsetlist = function('setloclist', [0]) let Xgetlist = function('getloclist', [0]) - let Xnext = 'lnext' endif call Xsetlist([{'bufnr': a:bnum, 'lnum': 1}, @@ -705,6 +705,15 @@ function SetXlistTests(cchar, bnum) exe Xnext call assert_equal(3, line('.')) + " Appending entries to the list should not change the cursor position + " in the quickfix window + exe Xwindow + 1 + call Xsetlist([{'bufnr': a:bnum, 'lnum': 4}, + \ {'bufnr': a:bnum, 'lnum': 5}], 'a') + call assert_equal(1, line('.')) + close + call Xsetlist([{'bufnr': a:bnum, 'lnum': 3}, \ {'bufnr': a:bnum, 'lnum': 4}, \ {'bufnr': a:bnum, 'lnum': 5}], 'r') diff --git a/src/nvim/version.c b/src/nvim/version.c index c8eae8b588..8af6579ac4 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -599,7 +599,7 @@ static int included_patches[] = { // 1844, // 1843 NA 1842, - // 1841, + 1841, 1840, // 1839, // 1838, From d244068f4fda821888a08858c8a00722f0326da6 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:06 -0500 Subject: [PATCH 09/26] vim-patch:7.4.1871 Problem: Appending to the quickfix list while the quickfix window is open is very slow. Solution: Do not delete all the lines, only append the new ones. Avoid using a window while updating the list. (closes vim/vim#841) https://github.com/vim/vim/commit/864293abb72d62604d8d6b458addfb43c14230c3 --- src/nvim/quickfix.c | 144 +++++++++++++++++++++++++++----------------- src/nvim/version.c | 2 +- 2 files changed, 90 insertions(+), 56 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index a68c4eca2e..dcc4ebcc1b 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -187,15 +187,14 @@ static char_u *qf_grow_linebuf(char_u **growbuf, size_t *growbufsiz, return *growbuf; } -/* - * Read the errorfile "efile" into memory, line by line, building the error - * list. - * Alternative: when "efile" is null read errors from buffer "buf". - * Always use 'errorformat' from "buf" if there is a local value. - * Then "lnumfirst" and "lnumlast" specify the range of lines to use. - * Set the title of the list to "qf_title". - * Return -1 for error, number of errors for success. - */ +// Read the errorfile "efile" into memory, line by line, building the error +// list. +// Alternative: when "efile" is NULL read errors from buffer "buf". +// Alternative: when "tv" is not NULL get errors from the string or list. +// Always use 'errorformat' from "buf" if there is a local value. +// Then "lnumfirst" and "lnumlast" specify the range of lines to use. +// Set the title of the list to "qf_title". +// Return -1 for error, number of errors for success. static int qf_init_ext ( qf_info_T *qi, @@ -228,6 +227,7 @@ qf_init_ext ( int enr = 0; FILE *fd = NULL; qfline_T *qfprev = NULL; /* init to make SASC shut up */ + qfline_T *old_last = NULL; char_u *efmp; efm_T *fmt_first = NULL; efm_T *fmt_last = NULL; @@ -282,11 +282,13 @@ qf_init_ext ( if (newlist || qi->qf_curlist == qi->qf_listcount) /* make place for a new list */ qf_new_list(qi, qf_title); - else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) + else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { /* Adding to existing list, find last entry. */ for (qfprev = qi->qf_lists[qi->qf_curlist].qf_start; qfprev->qf_next != qfprev; qfprev = qfprev->qf_next) ; + old_last = qfprev; + } /* * Each part of the format string is copied and modified from errorformat to @@ -912,7 +914,7 @@ qf_init_end: xfree(fmtstr); xfree(growbuf); - qf_update_buffer(qi, true); + qf_update_buffer(qi, old_last); return retval; } @@ -2053,7 +2055,7 @@ static void qf_msg(qf_info_T *qi) smsg(_("error list %d of %d; %d errors"), qi->qf_curlist + 1, qi->qf_listcount, qi->qf_lists[qi->qf_curlist].qf_count); - qf_update_buffer(qi, true); + qf_update_buffer(qi, NULL); } /* @@ -2321,7 +2323,7 @@ void ex_copen(exarg_T *eap) qf_set_title_var(qi); // Fill the buffer with the quickfix list. - qf_fill_buffer(qi); + qf_fill_buffer(qi, curbuf, NULL); curwin->w_cursor.lnum = qi->qf_lists[qi->qf_curlist].qf_index; curwin->w_cursor.col = 0; @@ -2440,7 +2442,7 @@ static buf_T *qf_find_buf(qf_info_T *qi) /* * Find the quickfix buffer. If it exists, update the contents. */ -static void qf_update_buffer(qf_info_T *qi, bool update_cursor) +static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last) { buf_T *buf; win_T *win; @@ -2450,8 +2452,12 @@ static void qf_update_buffer(qf_info_T *qi, bool update_cursor) /* Check if a buffer for the quickfix list exists. Update it. */ buf = qf_find_buf(qi); if (buf != NULL) { - /* set curwin/curbuf to buf and save a few things */ - aucmd_prepbuf(&aco, buf); + linenr_T old_line_count = buf->b_ml.ml_line_count; + + if (old_last == NULL) { + // set curwin/curbuf to buf and save a few things + aucmd_prepbuf(&aco, buf); + } if ((win = qf_find_win(qi)) != NULL) { curwin_save = curwin; @@ -2459,12 +2465,20 @@ static void qf_update_buffer(qf_info_T *qi, bool update_cursor) qf_set_title_var(qi); curwin = curwin_save; } - qf_fill_buffer(qi); - /* restore curwin/curbuf and a few other things */ - aucmd_restbuf(&aco); - if (update_cursor) { + qf_fill_buffer(qi, buf, old_last); + + if (old_last == NULL) { (void)qf_win_pos_update(qi, 0); + + // restore curwin/curbuf and a few other things + aucmd_restbuf(&aco); + } + + // Only redraw when added lines are visible. This avoids flickering when + // the added lines are not visible. + if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline) { + redraw_buf_later(buf, NOT_VALID); } } } @@ -2478,11 +2492,12 @@ static void qf_set_title_var(qf_info_T *qi) } } -/* - * Fill current buffer with quickfix errors, replacing any previous contents. - * curbuf must be the quickfix buffer! - */ -static void qf_fill_buffer(qf_info_T *qi) +// Fill current buffer with quickfix errors, replacing any previous contents. +// curbuf must be the quickfix buffer! +// If "old_last" is not NULL append the items after this one. +// When "old_last" is NULL then "buf" must equal "curbuf"! Because ml_delete() +// is used and autocommands will be triggered. +static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) { linenr_T lnum; qfline_T *qfp; @@ -2490,15 +2505,28 @@ static void qf_fill_buffer(qf_info_T *qi) int len; int old_KeyTyped = KeyTyped; - /* delete all existing lines */ - while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) - (void)ml_delete((linenr_T)1, FALSE); + if (old_last == NULL) { + if (buf != curbuf) { + EMSG2(_(e_intern2), "qf_fill_buffer()"); + return; + } + + /* delete all existing lines */ + while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) + (void)ml_delete((linenr_T)1, FALSE); + } /* Check if there is anything to display */ if (qi->qf_curlist < qi->qf_listcount) { /* Add one line for each error */ - qfp = qi->qf_lists[qi->qf_curlist].qf_start; - for (lnum = 0; lnum < qi->qf_lists[qi->qf_curlist].qf_count; ++lnum) { + if (old_last == NULL) { + qfp = qi->qf_lists[qi->qf_curlist].qf_start; + lnum = 0; + } else { + qfp = old_last->qf_next; + lnum = buf->b_ml.ml_line_count; + } + while (lnum < qi->qf_lists[qi->qf_curlist].qf_count) { if (qfp->qf_fnum != 0 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL && errbuf->b_fname != NULL) { @@ -2538,33 +2566,38 @@ static void qf_fill_buffer(qf_info_T *qi) qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text, IObuff + len, IOSIZE - len); - if (ml_append(lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE) + if (ml_append_buf(buf, lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE) == FAIL) break; + lnum++; qfp = qfp->qf_next; } - /* Delete the empty line which is now at the end */ - (void)ml_delete(lnum + 1, FALSE); + if (old_last == NULL) { + /* Delete the empty line which is now at the end */ + (void)ml_delete(lnum + 1, FALSE); + } } /* correct cursor position */ check_lnums(TRUE); - /* Set the 'filetype' to "qf" each time after filling the buffer. This - * resembles reading a file into a buffer, it's more logical when using - * autocommands. */ - set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL); - curbuf->b_p_ma = FALSE; + if (old_last == NULL) { + /* Set the 'filetype' to "qf" each time after filling the buffer. This + * resembles reading a file into a buffer, it's more logical when using + * autocommands. */ + set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL); + curbuf->b_p_ma = FALSE; - keep_filetype = TRUE; /* don't detect 'filetype' */ - apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, - FALSE, curbuf); - apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, - FALSE, curbuf); - keep_filetype = FALSE; + keep_filetype = TRUE; /* don't detect 'filetype' */ + apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, + FALSE, curbuf); + apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, + FALSE, curbuf); + keep_filetype = FALSE; - /* make sure it will be redrawn */ - redraw_curbuf_later(NOT_VALID); + /* make sure it will be redrawn */ + redraw_curbuf_later(NOT_VALID); + } /* Restore KeyTyped, setting 'filetype' may reset it. */ KeyTyped = old_KeyTyped; @@ -3367,7 +3400,7 @@ void ex_vimgrep(exarg_T *eap) qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; qi->qf_lists[qi->qf_curlist].qf_index = 1; - qf_update_buffer(qi, true); + qf_update_buffer(qi, NULL); if (au_name != NULL) apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, @@ -3655,15 +3688,15 @@ int get_errorlist(win_T *wp, list_T *list) return OK; } -/* - * Populate the quickfix list with the items supplied in the list - * of dictionaries. "title" will be copied to w:quickfix_title - */ +// Populate the quickfix list with the items supplied in the list +// of dictionaries. "title" will be copied to w:quickfix_title +// "action" is 'a' for add, 'r' for replace. Otherwise create a new list. int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) { listitem_T *li; dict_T *d; qfline_T *prevp = NULL; + qfline_T *old_last = NULL; int retval = OK; qf_info_T *qi = &ql_info; bool did_bufnr_emsg = false; @@ -3675,12 +3708,13 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) if (action == ' ' || qi->qf_curlist == qi->qf_listcount) /* make place for a new list */ qf_new_list(qi, title); - else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) + else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) { /* Adding to existing list, find last entry. */ for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; prevp->qf_next != prevp; prevp = prevp->qf_next) ; - else if (action == 'r') { + old_last = prevp; + } else if (action == 'r') { qf_free(qi, qi->qf_curlist); qf_store_title(qi, title); } @@ -3759,7 +3793,7 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) } // Don't update the cursor in quickfix window when appending entries - qf_update_buffer(qi, (action != 'a')); + qf_update_buffer(qi, old_last); return retval; } @@ -4015,7 +4049,7 @@ void ex_helpgrep(exarg_T *eap) /* Darn, some plugin changed the value. */ free_string_option(save_cpo); - qf_update_buffer(qi, true); + qf_update_buffer(qi, NULL); if (au_name != NULL) { apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, diff --git a/src/nvim/version.c b/src/nvim/version.c index 8af6579ac4..93ad69d5f0 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -569,7 +569,7 @@ static int included_patches[] = { // 1874 NA // 1873 NA // 1872 NA - // 1871, + 1871, // 1870 NA // 1869 NA // 1868, From 1e49cf6f233f6681a5a269bba84a09d8f8dbac22 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:10 -0500 Subject: [PATCH 10/26] vim-patch:7.4.1881 Problem: Appending to a long quickfix list is slow. Solution: Add qf_last. https://github.com/vim/vim/commit/83e6d7ac6a1c2a0cb5ee6c8420a5dc792f1d5ffa --- src/nvim/quickfix.c | 94 ++++++++++++++++++++++----------------------- src/nvim/version.c | 2 +- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index dcc4ebcc1b..34918e4134 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -77,6 +77,7 @@ struct qfline_S { typedef struct qf_list_S { qfline_T *qf_start; /* pointer to the first error */ + qfline_T *qf_last; // pointer to the last error qfline_T *qf_ptr; /* pointer to the current error */ int qf_count; /* number of errors (0 means no error list) */ int qf_index; /* current index in the error list */ @@ -226,7 +227,6 @@ qf_init_ext ( long lnum = 0L; int enr = 0; FILE *fd = NULL; - qfline_T *qfprev = NULL; /* init to make SASC shut up */ qfline_T *old_last = NULL; char_u *efmp; efm_T *fmt_first = NULL; @@ -283,11 +283,8 @@ qf_init_ext ( /* make place for a new list */ qf_new_list(qi, qf_title); else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { - /* Adding to existing list, find last entry. */ - for (qfprev = qi->qf_lists[qi->qf_curlist].qf_start; - qfprev->qf_next != qfprev; qfprev = qfprev->qf_next) - ; - old_last = qfprev; + /* Adding to existing list, use last entry. */ + old_last = qi->qf_lists[qi->qf_curlist].qf_last; } /* @@ -805,6 +802,7 @@ restofline: multiignore = false; // reset continuation } else if (vim_strchr((char_u *)"CZ", idx) != NULL) { /* continuation of multi-line msg */ + qfline_T *qfprev = qi->qf_lists[qi->qf_curlist].qf_last; if (qfprev == NULL) goto error2; if (*errmsg && !multiignore) { @@ -857,7 +855,7 @@ restofline: } } - if (qf_add_entry(qi, &qfprev, + if (qf_add_entry(qi, directory, (*namebuf || directory) ? namebuf @@ -997,7 +995,6 @@ void qf_free_all(win_T *wp) /// Add an entry to the end of the list of errors. /// /// @param qi quickfix list -/// @param prevp nonnull pointer (to previously added entry or NULL) /// @param dir optional directory name /// @param fname file name or NULL /// @param bufnum buffer number or zero @@ -1011,12 +1008,12 @@ void qf_free_all(win_T *wp) /// @param valid valid entry /// /// @returns OK or FAIL. -static int qf_add_entry(qf_info_T *qi, qfline_T **prevp, char_u *dir, - char_u *fname, int bufnum, char_u *mesg, long lnum, - int col, char_u vis_col, char_u *pattern, int nr, - char_u type, char_u valid) +static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum, + char_u *mesg, long lnum, int col, char_u vis_col, + char_u *pattern, int nr, char_u type, char_u valid) { qfline_T *qfp = xmalloc(sizeof(qfline_T)); + qfline_T **lastp; // pointer to qf_last or NULL if (bufnum != 0) qfp->qf_fnum = bufnum; @@ -1037,20 +1034,21 @@ static int qf_add_entry(qf_info_T *qi, qfline_T **prevp, char_u *dir, qfp->qf_type = type; qfp->qf_valid = valid; + lastp = &qi->qf_lists[qi->qf_curlist].qf_last; if (qi->qf_lists[qi->qf_curlist].qf_count == 0) { /* first element in the list */ qi->qf_lists[qi->qf_curlist].qf_start = qfp; qi->qf_lists[qi->qf_curlist].qf_ptr = qfp; qi->qf_lists[qi->qf_curlist].qf_index = 0; - qfp->qf_prev = qfp; // first element points to itself + qfp->qf_prev = NULL; } else { - assert(*prevp); - qfp->qf_prev = *prevp; - (*prevp)->qf_next = qfp; + assert(*lastp); + qfp->qf_prev = *lastp; + (*lastp)->qf_next = qfp; } - qfp->qf_next = qfp; /* last element points to itself */ + qfp->qf_next = NULL; qfp->qf_cleared = FALSE; - *prevp = qfp; + *lastp = qfp; ++qi->qf_lists[qi->qf_curlist].qf_count; if (qi->qf_lists[qi->qf_curlist].qf_index == 0 && qfp->qf_valid) { /* first valid entry */ @@ -1136,6 +1134,7 @@ void copy_loclist(win_T *from, win_T *to) to_qfl->qf_count = 0; to_qfl->qf_index = 0; to_qfl->qf_start = NULL; + to_qfl->qf_last = NULL; to_qfl->qf_ptr = NULL; if (from_qfl->qf_title != NULL) to_qfl->qf_title = vim_strsave(from_qfl->qf_title); @@ -1144,12 +1143,13 @@ void copy_loclist(win_T *from, win_T *to) if (from_qfl->qf_count) { qfline_T *from_qfp; - qfline_T *prevp = NULL; + qfline_T *prevp; /* copy all the location entries in this list */ - for (i = 0, from_qfp = from_qfl->qf_start; i < from_qfl->qf_count; + for (i = 0, from_qfp = from_qfl->qf_start; + i < from_qfl->qf_count && from_qfp != NULL; ++i, from_qfp = from_qfp->qf_next) { - if (qf_add_entry(to->w_llist, &prevp, + if (qf_add_entry(to->w_llist, NULL, NULL, 0, @@ -1169,6 +1169,7 @@ void copy_loclist(win_T *from, win_T *to) * directory and file names are not supplied. So the qf_fnum * field is copied here. */ + prevp = to->w_llist->qf_lists[to->w_llist->qf_curlist].qf_last; prevp->qf_fnum = from_qfp->qf_fnum; /* file number */ prevp->qf_type = from_qfp->qf_type; /* error type */ if (from_qfl->qf_ptr == from_qfp) @@ -1400,7 +1401,7 @@ static bool is_qf_entry_present(qf_info_T *qi, qfline_T *qf_ptr) // Search for the entry in the current list for (i = 0, qfp = qfl->qf_start; i < qfl->qf_count; i++, qfp = qfp->qf_next) { - if (qfp == qf_ptr) { + if (qfp == NULL || qfp == qf_ptr) { break; } } @@ -1981,6 +1982,9 @@ void qf_list(exarg_T *eap) } qfp = qfp->qf_next; + if (qfp == NULL) { + break; + } ++i; os_breakcheck(); } @@ -2064,22 +2068,24 @@ static void qf_msg(qf_info_T *qi) static void qf_free(qf_info_T *qi, int idx) { qfline_T *qfp; + qfline_T *qfpnext; int stop = FALSE; - while (qi->qf_lists[idx].qf_count) { - qfp = qi->qf_lists[idx].qf_start->qf_next; + while (qi->qf_lists[idx].qf_count && qi->qf_lists[idx].qf_start != NULL) { + qfp = qi->qf_lists[idx].qf_start; + qfpnext = qfp->qf_next; if (qi->qf_lists[idx].qf_title != NULL && !stop) { - xfree(qi->qf_lists[idx].qf_start->qf_text); - stop = (qi->qf_lists[idx].qf_start == qfp); - xfree(qi->qf_lists[idx].qf_start->qf_pattern); - xfree(qi->qf_lists[idx].qf_start); + xfree(qfp->qf_text); + stop = (qfp == qfpnext); + xfree(qfp->qf_pattern); + xfree(qfp); if (stop) /* Somehow qf_count may have an incorrect value, set it to 1 * to avoid crashing when it's wrong. * TODO: Avoid qf_count being incorrect. */ qi->qf_lists[idx].qf_count = 1; } - qi->qf_lists[idx].qf_start = qfp; + qi->qf_lists[idx].qf_start = qfpnext; --qi->qf_lists[idx].qf_count; } xfree(qi->qf_lists[idx].qf_title); @@ -2108,7 +2114,8 @@ void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long for (idx = 0; idx < qi->qf_listcount; ++idx) if (qi->qf_lists[idx].qf_count) for (i = 0, qfp = qi->qf_lists[idx].qf_start; - i < qi->qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next) + i < qi->qf_lists[idx].qf_count && qfp != NULL; + ++i, qfp = qfp->qf_next) if (qfp->qf_fnum == curbuf->b_fnum) { if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) { if (amount == MAXLNUM) @@ -2571,6 +2578,9 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) break; lnum++; qfp = qfp->qf_next; + if (qfp == NULL) { + break; + } } if (old_last == NULL) { /* Delete the empty line which is now at the end */ @@ -3123,7 +3133,6 @@ void ex_vimgrep(exarg_T *eap) int fi; qf_info_T *qi = &ql_info; qfline_T *cur_qf_start; - qfline_T *prevp = NULL; long lnum; buf_T *buf; int duplicate_name = FALSE; @@ -3208,12 +3217,6 @@ void ex_vimgrep(exarg_T *eap) || qi->qf_curlist == qi->qf_listcount) { // make place for a new list qf_new_list(qi, title != NULL ? title : *eap->cmdlinep); - } else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { - // Adding to existing list, find last entry. - for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; - prevp->qf_next != prevp; - prevp = prevp->qf_next) { - } } /* parse the list of arguments */ @@ -3311,7 +3314,7 @@ void ex_vimgrep(exarg_T *eap) while (vim_regexec_multi(®match, curwin, buf, lnum, col, NULL) > 0) { ; - if (qf_add_entry(qi, &prevp, + if (qf_add_entry(qi, NULL, /* dir */ fname, 0, @@ -3684,6 +3687,9 @@ int get_errorlist(win_T *wp, list_T *list) return FAIL; qfp = qfp->qf_next; + if (qfp == NULL) { + break; + } } return OK; } @@ -3695,7 +3701,6 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) { listitem_T *li; dict_T *d; - qfline_T *prevp = NULL; qfline_T *old_last = NULL; int retval = OK; qf_info_T *qi = &ql_info; @@ -3709,11 +3714,8 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) /* make place for a new list */ qf_new_list(qi, title); else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) { - /* Adding to existing list, find last entry. */ - for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; - prevp->qf_next != prevp; prevp = prevp->qf_next) - ; - old_last = prevp; + // Adding to existing list, use last entry. + old_last = qi->qf_lists[qi->qf_curlist].qf_last; } else if (action == 'r') { qf_free(qi, qi->qf_curlist); qf_store_title(qi, title); @@ -3756,7 +3758,6 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) } int status = qf_add_entry(qi, - &prevp, NULL, // dir filename, bufnum, @@ -3898,7 +3899,6 @@ void ex_helpgrep(exarg_T *eap) char_u **fnames; FILE *fd; int fi; - qfline_T *prevp = NULL; long lnum; char_u *lang; qf_info_T *qi = &ql_info; @@ -4001,7 +4001,7 @@ void ex_helpgrep(exarg_T *eap) while (l > 0 && line[l - 1] <= ' ') line[--l] = NUL; - if (qf_add_entry(qi, &prevp, + if (qf_add_entry(qi, NULL, /* dir */ fnames[fi], 0, diff --git a/src/nvim/version.c b/src/nvim/version.c index 93ad69d5f0..692bbb27c8 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -559,7 +559,7 @@ static int included_patches[] = { // 1884, // 1883 NA // 1882, - // 1881, + 1881, // 1880 NA // 1879 NA // 1878 NA From a86d8b4088d21b784c1b72a03db9c22dcae67d00 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:15 -0500 Subject: [PATCH 11/26] vim-patch:7.4.1882 Problem: Check for line break at end of line wrong. (Dominique Pelle) Solution: Correct the logic. https://github.com/vim/vim/commit/b37662a0fbb952838fca87aff4d26b596030b67b --- src/nvim/quickfix.c | 4 ++-- src/nvim/version.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 34918e4134..9703d8763a 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -556,9 +556,9 @@ qf_init_ext ( discard = false; linelen = STRLEN(IObuff); - if (linelen == IOSIZE - 1 && (IObuff[linelen - 1] != '\n' + if (linelen == IOSIZE - 1 && !(IObuff[linelen - 1] == '\n' #ifdef USE_CRNL - || IObuff[linelen - 1] != '\r' + || IObuff[linelen - 1] == '\r' #endif )) { // The current line exceeds IObuff, continue reading using growbuf diff --git a/src/nvim/version.c b/src/nvim/version.c index 692bbb27c8..17c1a85a95 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -558,7 +558,7 @@ static int included_patches[] = { // 1885 NA // 1884, // 1883 NA - // 1882, + 1882, 1881, // 1880 NA // 1879 NA From ab43303df7f09d1789a70e2536552461657f08ac Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:20 -0500 Subject: [PATCH 12/26] vim-patch:7.4.1884 Problem: Updating marks in a quickfix list is very slow when the list is long. Solution: Only update marks if the buffer has a quickfix entry. https://github.com/vim/vim/commit/2f095a4bc4d786e0ac834f48dd18a94fe2d140e3 --- src/nvim/buffer_defs.h | 3 +- src/nvim/quickfix.c | 78 +++++++++++++++++++++++++----------------- src/nvim/version.c | 2 +- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 2f0e8ad974..da08357cb0 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -609,6 +609,7 @@ struct file_buffer { int b_p_bomb; ///< 'bomb' char_u *b_p_bh; ///< 'bufhidden' char_u *b_p_bt; ///< 'buftype' + bool b_has_qf_entry; ///< quickfix exists for buffer int b_p_bl; ///< 'buflisted' int b_p_cin; ///< 'cindent' char_u *b_p_cino; ///< 'cinoptions' @@ -1037,7 +1038,7 @@ struct window_S { int w_wrow, w_wcol; /* cursor position in window */ linenr_T w_botline; /* number of the line below the bottom of - the screen */ + the window */ int w_empty_rows; /* number of ~ rows in window */ int w_filler_rows; /* number of filler rows at the end of the window */ diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 9703d8763a..9b2dbf1bf5 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -1015,9 +1015,14 @@ static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum, qfline_T *qfp = xmalloc(sizeof(qfline_T)); qfline_T **lastp; // pointer to qf_last or NULL - if (bufnum != 0) + if (bufnum != 0) { + buf_T *buf = buflist_findnr(bufnum); + qfp->qf_fnum = bufnum; - else + if (buf != NULL) { + buf->b_has_qf_entry = true; + } + } else qfp->qf_fnum = qf_get_fnum(dir, fname); qfp->qf_text = vim_strsave(mesg); qfp->qf_lnum = lnum; @@ -1190,45 +1195,47 @@ void copy_loclist(win_T *from, win_T *to) to->w_llist->qf_curlist = qi->qf_curlist; /* current list */ } -/* - * get buffer number for file "dir.name" - */ +// Get buffer number for file "dir.name". +// Also sets the b_has_qf_entry flag. static int qf_get_fnum(char_u *directory, char_u *fname) { + char_u *ptr; + buf_T *buf; if (fname == NULL || *fname == NUL) /* no file name */ return 0; - { - char_u *ptr; - int fnum; #ifdef BACKSLASH_IN_FILENAME - if (directory != NULL) - slash_adjust(directory); - slash_adjust(fname); + if (directory != NULL) + slash_adjust(directory); + slash_adjust(fname); #endif - if (directory != NULL && !vim_isAbsName(fname)) { - ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE); - /* - * Here we check if the file really exists. - * This should normally be true, but if make works without - * "leaving directory"-messages we might have missed a - * directory change. - */ - if (!os_path_exists(ptr)) { - xfree(ptr); - directory = qf_guess_filepath(fname); - if (directory) - ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE); - else - ptr = vim_strsave(fname); - } - /* Use concatenated directory name and file name */ - fnum = buflist_add(ptr, 0); + if (directory != NULL && !vim_isAbsName(fname)) { + ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE); + /* + * Here we check if the file really exists. + * This should normally be true, but if make works without + * "leaving directory"-messages we might have missed a + * directory change. + */ + if (!os_path_exists(ptr)) { xfree(ptr); - return fnum; + directory = qf_guess_filepath(fname); + if (directory) + ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE); + else + ptr = vim_strsave(fname); } - return buflist_add(fname, 0); + /* Use concatenated directory name and file name */ + buf = buflist_new(ptr, NULL, (linenr_T)0, 0); + xfree(ptr); + } else { + buf = buflist_new(fname, NULL, (linenr_T)0, 0); } + if (buf == NULL) { + return 0; + } + buf->b_has_qf_entry = true; + return buf->b_fnum; } /* @@ -2104,7 +2111,11 @@ void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long qfline_T *qfp; int idx; qf_info_T *qi = &ql_info; + bool found_one = false; + if (!curbuf->b_has_qf_entry) { + return; + } if (wp != NULL) { if (wp->w_llist == NULL) return; @@ -2117,6 +2128,7 @@ void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long i < qi->qf_lists[idx].qf_count && qfp != NULL; ++i, qfp = qfp->qf_next) if (qfp->qf_fnum == curbuf->b_fnum) { + found_one = true; if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) { if (amount == MAXLNUM) qfp->qf_cleared = TRUE; @@ -2125,6 +2137,10 @@ void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long } else if (amount_after && qfp->qf_lnum > line2) qfp->qf_lnum += amount_after; } + + if (!found_one) { + curbuf->b_has_qf_entry = false; + } } /* diff --git a/src/nvim/version.c b/src/nvim/version.c index 17c1a85a95..bf0baa8dbf 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -556,7 +556,7 @@ static int included_patches[] = { // 1887 NA // 1886 NA // 1885 NA - // 1884, + 1884, // 1883 NA 1882, 1881, From fbcc854d49330aff7e4511eb6321487f7b4fdae4 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:24 -0500 Subject: [PATCH 13/26] vim-patch:7.4.1912 Problem: No test for using setqflist() on an older quickfix list. Solution: Add a couple of tests. https://github.com/vim/vim/commit/1cee693b310e1494115a1677fac064941092e1bb --- src/nvim/testdir/test_quickfix.vim | 43 ++++++++++++++++++++++++++++++ src/nvim/version.c | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 73ee240c77..a7ca42e021 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -734,9 +734,52 @@ function Test_setqflist() call SetXlistTests('c', bnum) call SetXlistTests('l', bnum) + enew! call delete('Xtestfile') endfunction +func Test_setqflist_empty_middle() + " create three quickfix lists + vimgrep Test_ test_quickfix.vim + let testlen = len(getqflist()) + call assert_true(testlen > 0) + vimgrep empty test_quickfix.vim + call assert_true(len(getqflist()) > 0) + vimgrep matches test_quickfix.vim + let matchlen = len(getqflist()) + call assert_true(matchlen > 0) + colder + " make the middle list empty + call setqflist([], 'r') + call assert_true(len(getqflist()) == 0) + colder + call assert_equal(testlen, len(getqflist())) + cnewer + cnewer + call assert_equal(matchlen, len(getqflist())) +endfunc + +func Test_setqflist_empty_older() + " create three quickfix lists + vimgrep one test_quickfix.vim + let onelen = len(getqflist()) + call assert_true(onelen > 0) + vimgrep two test_quickfix.vim + let twolen = len(getqflist()) + call assert_true(twolen > 0) + vimgrep three test_quickfix.vim + let threelen = len(getqflist()) + call assert_true(threelen > 0) + colder 2 + " make the first list empty, check the others didn't change + call setqflist([], 'r') + call assert_true(len(getqflist()) == 0) + cnewer + call assert_equal(twolen, len(getqflist())) + cnewer + call assert_equal(threelen, len(getqflist())) +endfunc + function! XquickfixSetListWithAct(cchar) let Xolder = a:cchar . 'older' let Xnewer = a:cchar . 'newer' diff --git a/src/nvim/version.c b/src/nvim/version.c index bf0baa8dbf..4ecf7b2dd3 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -528,7 +528,7 @@ static int included_patches[] = { // 1915 NA // 1914, 1913, - // 1912, + 1912, // 1911, // 1910, 1909, From 4ac88c4faa1abe449e69263a3e6f8655b7a71d7c Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:29 -0500 Subject: [PATCH 14/26] vim-patch:7.4.1937 Problem: No test for directory stack in quickfix. Solution: Add a test. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/ab47c61f46f0797308217cd3c045472cb0ec3195 --- src/nvim/testdir/test_quickfix.vim | 120 ++++++++++++++++++++++++----- src/nvim/version.c | 2 +- 2 files changed, 102 insertions(+), 20 deletions(-) diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index a7ca42e021..4e9f404528 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -80,9 +80,9 @@ function XageTests(cchar) let Xnewer = a:cchar . 'newer' let Xgetexpr = a:cchar . 'getexpr' if a:cchar == 'c' - let Xgetlist = 'getqflist()' + let Xgetlist = function('getqflist') else - let Xgetlist = 'getloclist(0)' + let Xgetlist = function('getloclist', [0]) endif " Jumping to a non existent list should return error @@ -99,21 +99,21 @@ function XageTests(cchar) " Go back two lists exe Xolder - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_equal('Line2', l[0].text) " Go forward two lists exe Xnewer - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_equal('Line3', l[0].text) " Test for the optional count argument exe Xolder . ' 2' - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_equal('Line1', l[0].text) exe Xnewer . ' 2' - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_equal('Line3', l[0].text) endfunction @@ -187,9 +187,9 @@ function XfileTests(cchar) let Xgetfile = a:cchar . 'getfile' let Xaddfile = a:cchar . 'addfile' if a:cchar == 'c' - let Xgetlist = 'getqflist()' + let Xgetlist = function('getqflist') else - let Xgetlist = 'getloclist(0)' + let Xgetlist = function('getloclist', [0]) endif call writefile(['Xtestfile1:700:10:Line 700', @@ -197,7 +197,7 @@ function XfileTests(cchar) enew! exe Xfile . ' Xqftestfile1' - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_true(len(l) == 2 && \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') @@ -210,7 +210,7 @@ function XfileTests(cchar) call writefile(['Xtestfile3:900:30:Line 900'], 'Xqftestfile1') exe Xaddfile . ' Xqftestfile1' - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_true(len(l) == 3 && \ l[2].lnum == 900 && l[2].col == 30 && l[2].text ==# 'Line 900') @@ -219,7 +219,7 @@ function XfileTests(cchar) enew! exe Xgetfile . ' Xqftestfile1' - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_true(len(l) == 2 && \ l[0].lnum == 222 && l[0].col == 77 && l[0].text ==# 'Line 222' && \ l[1].lnum == 333 && l[1].col == 88 && l[1].text ==# 'Line 333') @@ -239,16 +239,16 @@ function XbufferTests(cchar) let Xgetbuffer = a:cchar . 'getbuffer' let Xaddbuffer = a:cchar . 'addbuffer' if a:cchar == 'c' - let Xgetlist = 'getqflist()' + let Xgetlist = function('getqflist') else - let Xgetlist = 'getloclist(0)' + let Xgetlist = function('getloclist', [0]) endif enew! silent! call setline(1, ['Xtestfile7:700:10:Line 700', \ 'Xtestfile8:800:15:Line 800']) exe Xbuffer . "!" - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_true(len(l) == 2 && \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') @@ -257,7 +257,7 @@ function XbufferTests(cchar) silent! call setline(1, ['Xtestfile9:900:55:Line 900', \ 'Xtestfile10:950:66:Line 950']) exe Xgetbuffer - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_true(len(l) == 2 && \ l[0].lnum == 900 && l[0].col == 55 && l[0].text ==# 'Line 900' && \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950') @@ -266,11 +266,12 @@ function XbufferTests(cchar) silent! call setline(1, ['Xtestfile11:700:20:Line 700', \ 'Xtestfile12:750:25:Line 750']) exe Xaddbuffer - exe 'let l = ' . Xgetlist + let l = Xgetlist() call assert_true(len(l) == 4 && \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950' && \ l[2].lnum == 700 && l[2].col == 20 && l[2].text ==# 'Line 700' && \ l[3].lnum == 750 && l[3].col == 25 && l[3].text ==# 'Line 750') + enew! endfunction @@ -321,15 +322,15 @@ endfunc function XqfTitleTests(cchar) let Xgetexpr = a:cchar . 'getexpr' if a:cchar == 'c' - let Xgetlist = 'getqflist()' + let Xgetlist = function('getqflist') else - let Xgetlist = 'getloclist(0)' + let Xgetlist = function('getloclist', [0]) endif let Xopen = a:cchar . 'open' let Xclose = a:cchar . 'close' exe Xgetexpr . " ['file:1:1:message']" - exe 'let l = ' . Xgetlist + let l = Xgetlist() if a:cchar == 'c' call setqflist(l, 'r') else @@ -620,6 +621,87 @@ function! Test_efm1() call delete('Xtestfile') endfunction +" Test for quickfix directory stack support +function! s:dir_stack_tests(cchar) + let Xgetexpr = a:cchar . 'getexpr' + if a:cchar == 'c' + let Xgetlist = function('getqflist') + else + let Xgetlist = function('getloclist', [0]) + endif + + let save_efm=&efm + set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f' + + let l = "Entering dir 'dir1/a'\n" . + \ 'habits2.txt:1:Nine Healthy Habits' . "\n" . + \ "Entering dir 'b'\n" . + \ 'habits3.txt:2:0 Hours of television' . "\n" . + \ 'habits2.txt:7:5 Small meals' . "\n" . + \ "Entering dir 'dir1/c'\n" . + \ 'habits4.txt:3:1 Hour of exercise' . "\n" . + \ "Leaving dir 'dir1/c'\n" . + \ "Leaving dir 'dir1/a'\n" . + \ 'habits1.txt:4:2 Liters of water' . "\n" . + \ "Entering dir 'dir2'\n" . + \ 'habits5.txt:5:3 Cups of hot green tea' . "\n" . + \ "Leaving dir 'dir2'\n" + + exe Xgetexpr . " l" + + let qf = Xgetlist() + + call assert_equal('dir1/a/habits2.txt', bufname(qf[1].bufnr)) + call assert_equal(1, qf[1].lnum) + call assert_equal('dir1/a/b/habits3.txt', bufname(qf[3].bufnr)) + call assert_equal(2, qf[3].lnum) + call assert_equal('dir1/a/habits2.txt', bufname(qf[4].bufnr)) + call assert_equal(7, qf[4].lnum) + call assert_equal('dir1/c/habits4.txt', bufname(qf[6].bufnr)) + call assert_equal(3, qf[6].lnum) + call assert_equal('habits1.txt', bufname(qf[9].bufnr)) + call assert_equal(4, qf[9].lnum) + call assert_equal('dir2/habits5.txt', bufname(qf[11].bufnr)) + call assert_equal(5, qf[11].lnum) + + let &efm=save_efm +endfunction + +" Tests for %D and %X errorformat options +function! Test_efm_dirstack() + " Create the directory stack and files + call mkdir('dir1') + call mkdir('dir1/a') + call mkdir('dir1/a/b') + call mkdir('dir1/c') + call mkdir('dir2') + + let lines = ["Nine Healthy Habits", + \ "0 Hours of television", + \ "1 Hour of exercise", + \ "2 Liters of water", + \ "3 Cups of hot green tea", + \ "4 Short mental breaks", + \ "5 Small meals", + \ "6 AM wake up time", + \ "7 Minutes of laughter", + \ "8 Hours of sleep (at least)", + \ "9 PM end of the day and off to bed" + \ ] + call writefile(lines, 'habits1.txt') + call writefile(lines, 'dir1/a/habits2.txt') + call writefile(lines, 'dir1/a/b/habits3.txt') + call writefile(lines, 'dir1/c/habits4.txt') + call writefile(lines, 'dir2/habits5.txt') + + call s:dir_stack_tests('c') + call s:dir_stack_tests('l') + + call delete('dir1', 'rf') + call delete('dir2', 'rf') + call delete('habits1.txt') +endfunction + function XquickfixChangedByAutocmd(cchar) let Xolder = a:cchar . 'older' let Xgetexpr = a:cchar . 'getexpr' diff --git a/src/nvim/version.c b/src/nvim/version.c index 4ecf7b2dd3..04f995ee0a 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -503,7 +503,7 @@ static int included_patches[] = { // 1940, // 1939 NA // 1938 NA - // 1937, + 1937, // 1936, // 1935 NA // 1934 NA From 2244253c14193be94dac4b40a24dcea56e1f1b15 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:34 -0500 Subject: [PATCH 15/26] vim-patch:7.4.1941 Problem: Not all quickfix tests are also done with the location lists. Solution: Test more quickfix code. Use user commands instead of "exe". (Yegappan Lakshmanan) https://github.com/vim/vim/commit/3ef5bf7d459d6b8a21aaefc80f65448f5a7aa59f --- src/nvim/testdir/test_quickfix.vim | 420 +++++++++++++++-------------- src/nvim/version.c | 2 +- 2 files changed, 215 insertions(+), 207 deletions(-) diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 4e9f404528..025f26059f 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -6,24 +6,67 @@ endif set encoding=utf-8 +function! s:setup_commands(cchar) + if a:cchar == 'c' + command! -nargs=* -bang Xlist clist + command! -nargs=* Xgetexpr cgetexpr + command! -nargs=* Xolder colder + command! -nargs=* Xnewer cnewer + command! -nargs=* Xopen copen + command! -nargs=* Xwindow cwindow + command! -nargs=* Xclose cclose + command! -nargs=* -bang Xfile cfile + command! -nargs=* Xgetfile cgetfile + command! -nargs=* Xaddfile caddfile + command! -nargs=* -bang Xbuffer cbuffer + command! -nargs=* Xgetbuffer cgetbuffer + command! -nargs=* Xaddbuffer caddbuffer + command! -nargs=* Xrewind crewind + command! -nargs=* -bang Xnext cnext + command! -nargs=* Xexpr cexpr + command! -nargs=* Xvimgrep vimgrep + let g:Xgetlist = function('getqflist') + let g:Xsetlist = function('setqflist') + else + command! -nargs=* -bang Xlist llist + command! -nargs=* Xgetexpr lgetexpr + command! -nargs=* Xolder lolder + command! -nargs=* Xnewer lnewer + command! -nargs=* Xopen lopen + command! -nargs=* Xwindow lwindow + command! -nargs=* Xclose lclose + command! -nargs=* -bang Xfile lfile + command! -nargs=* Xgetfile lgetfile + command! -nargs=* Xaddfile laddfile + command! -nargs=* -bang Xbuffer lbuffer + command! -nargs=* Xgetbuffer lgetbuffer + command! -nargs=* Xaddbuffer laddbuffer + command! -nargs=* Xrewind lrewind + command! -nargs=* -bang Xnext lnext + command! -nargs=* Xexpr lexpr + command! -nargs=* Xvimgrep lvimgrep + let g:Xgetlist = function('getloclist', [0]) + let g:Xsetlist = function('setloclist', [0]) + endif +endfunction + " Tests for the :clist and :llist commands function XlistTests(cchar) - let Xlist = a:cchar . 'list' - let Xgetexpr = a:cchar . 'getexpr' + call s:setup_commands(a:cchar) " With an empty list, command should return error - exe Xgetexpr . ' []' - exe 'silent! ' . Xlist + Xgetexpr [] + silent! Xlist call assert_true(v:errmsg ==# 'E42: No Errors') " Populate the list and then try - exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', + Xgetexpr ['non-error 1', 'Xtestfile1:1:3:Line1', \ 'non-error 2', 'Xtestfile2:2:2:Line2', - \ 'non-error 3', 'Xtestfile3:3:1:Line3']" + \ 'non-error 3', 'Xtestfile3:3:1:Line3'] " List only valid entries redir => result - exe Xlist + Xlist redir END let l = split(result, "\n") call assert_equal([' 2 Xtestfile1:1 col 3: Line1', @@ -32,7 +75,7 @@ function XlistTests(cchar) " List all the entries redir => result - exe Xlist . "!" + Xlist! redir END let l = split(result, "\n") call assert_equal([' 1: non-error 1', ' 2 Xtestfile1:1 col 3: Line1', @@ -41,26 +84,26 @@ function XlistTests(cchar) " List a range of errors redir => result - exe Xlist . " 3,6" + Xlist 3,6 redir END let l = split(result, "\n") call assert_equal([' 4 Xtestfile2:2 col 2: Line2', \ ' 6 Xtestfile3:3 col 1: Line3'], l) redir => result - exe Xlist . "! 3,4" + Xlist! 3,4 redir END let l = split(result, "\n") call assert_equal([' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l) redir => result - exe Xlist . " -6,-4" + Xlist -6,-4 redir END let l = split(result, "\n") call assert_equal([' 2 Xtestfile1:1 col 3: Line1'], l) redir => result - exe Xlist . "! -5,-3" + Xlist! -5,-3 redir END let l = split(result, "\n") call assert_equal([' 2 Xtestfile1:1 col 3: Line1', @@ -76,44 +119,37 @@ endfunction " Note that this test assumes that a quickfix/location list is " already set by the caller. function XageTests(cchar) - let Xolder = a:cchar . 'older' - let Xnewer = a:cchar . 'newer' - let Xgetexpr = a:cchar . 'getexpr' - if a:cchar == 'c' - let Xgetlist = function('getqflist') - else - let Xgetlist = function('getloclist', [0]) - endif + call s:setup_commands(a:cchar) " Jumping to a non existent list should return error - exe 'silent! ' . Xolder . ' 99' + silent! Xolder 99 call assert_true(v:errmsg ==# 'E380: At bottom of quickfix stack') - exe 'silent! ' . Xnewer . ' 99' + silent! Xnewer 99 call assert_true(v:errmsg ==# 'E381: At top of quickfix stack') " Add three quickfix/location lists - exe Xgetexpr . " ['Xtestfile1:1:3:Line1']" - exe Xgetexpr . " ['Xtestfile2:2:2:Line2']" - exe Xgetexpr . " ['Xtestfile3:3:1:Line3']" + Xgetexpr ['Xtestfile1:1:3:Line1'] + Xgetexpr ['Xtestfile2:2:2:Line2'] + Xgetexpr ['Xtestfile3:3:1:Line3'] " Go back two lists - exe Xolder - let l = Xgetlist() + Xolder + let l = g:Xgetlist() call assert_equal('Line2', l[0].text) " Go forward two lists - exe Xnewer - let l = Xgetlist() + Xnewer + let l = g:Xgetlist() call assert_equal('Line3', l[0].text) " Test for the optional count argument - exe Xolder . ' 2' - let l = Xgetlist() + Xolder 2 + let l = g:Xgetlist() call assert_equal('Line1', l[0].text) - exe Xnewer . ' 2' - let l = Xgetlist() + Xnewer 2 + let l = g:Xgetlist() call assert_equal('Line3', l[0].text) endfunction @@ -129,49 +165,46 @@ endfunction " Tests for the :cwindow, :lwindow :cclose, :lclose, :copen and :lopen " commands function XwindowTests(cchar) - let Xwindow = a:cchar . 'window' - let Xclose = a:cchar . 'close' - let Xopen = a:cchar . 'open' - let Xgetexpr = a:cchar . 'getexpr' + call s:setup_commands(a:cchar) " Create a list with no valid entries - exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" + Xgetexpr ['non-error 1', 'non-error 2', 'non-error 3'] " Quickfix/Location window should not open with no valid errors - exe Xwindow + Xwindow call assert_true(winnr('$') == 1) " Create a list with valid entries - exe Xgetexpr . " ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2', - \ 'Xtestfile3:3:1:Line3']" + Xgetexpr ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2', + \ 'Xtestfile3:3:1:Line3'] " Open the window - exe Xwindow + Xwindow call assert_true(winnr('$') == 2 && winnr() == 2 && \ getline('.') ==# 'Xtestfile1|1 col 3| Line1') " Close the window - exe Xclose + Xclose call assert_true(winnr('$') == 1) " Create a list with no valid entries - exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']" + Xgetexpr ['non-error 1', 'non-error 2', 'non-error 3'] " Open the window - exe Xopen . ' 5' + Xopen 5 call assert_true(winnr('$') == 2 && getline('.') ==# '|| non-error 1' \ && winheight('.') == 5) " Opening the window again, should move the cursor to that window wincmd t - exe Xopen . ' 7' + Xopen 7 call assert_true(winnr('$') == 2 && winnr() == 2 && \ winheight('.') == 7 && \ getline('.') ==# '|| non-error 1') " Calling cwindow should close the quickfix window with no valid errors - exe Xwindow + Xwindow call assert_true(winnr('$') == 1) endfunction @@ -183,21 +216,14 @@ endfunction " Tests for the :cfile, :lfile, :caddfile, :laddfile, :cgetfile and :lgetfile " commands. function XfileTests(cchar) - let Xfile = a:cchar . 'file' - let Xgetfile = a:cchar . 'getfile' - let Xaddfile = a:cchar . 'addfile' - if a:cchar == 'c' - let Xgetlist = function('getqflist') - else - let Xgetlist = function('getloclist', [0]) - endif + call s:setup_commands(a:cchar) call writefile(['Xtestfile1:700:10:Line 700', \ 'Xtestfile2:800:15:Line 800'], 'Xqftestfile1') enew! - exe Xfile . ' Xqftestfile1' - let l = Xgetlist() + Xfile Xqftestfile1 + let l = g:Xgetlist() call assert_true(len(l) == 2 && \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') @@ -205,12 +231,12 @@ function XfileTests(cchar) " Run cfile/lfile from a modified buffer enew! silent! put ='Quickfix' - exe 'silent! ' . Xfile . ' Xqftestfile1' + silent! Xfile Xqftestfile1 call assert_true(v:errmsg ==# 'E37: No write since last change (add ! to override)') call writefile(['Xtestfile3:900:30:Line 900'], 'Xqftestfile1') - exe Xaddfile . ' Xqftestfile1' - let l = Xgetlist() + Xaddfile Xqftestfile1 + let l = g:Xgetlist() call assert_true(len(l) == 3 && \ l[2].lnum == 900 && l[2].col == 30 && l[2].text ==# 'Line 900') @@ -218,8 +244,8 @@ function XfileTests(cchar) \ 'Xtestfile2:333:88:Line 333'], 'Xqftestfile1') enew! - exe Xgetfile . ' Xqftestfile1' - let l = Xgetlist() + Xgetfile Xqftestfile1 + let l = g:Xgetlist() call assert_true(len(l) == 2 && \ l[0].lnum == 222 && l[0].col == 77 && l[0].text ==# 'Line 222' && \ l[1].lnum == 333 && l[1].col == 88 && l[1].text ==# 'Line 333') @@ -235,20 +261,13 @@ endfunction " Tests for the :cbuffer, :lbuffer, :caddbuffer, :laddbuffer, :cgetbuffer and " :lgetbuffer commands. function XbufferTests(cchar) - let Xbuffer = a:cchar . 'buffer' - let Xgetbuffer = a:cchar . 'getbuffer' - let Xaddbuffer = a:cchar . 'addbuffer' - if a:cchar == 'c' - let Xgetlist = function('getqflist') - else - let Xgetlist = function('getloclist', [0]) - endif + call s:setup_commands(a:cchar) enew! silent! call setline(1, ['Xtestfile7:700:10:Line 700', \ 'Xtestfile8:800:15:Line 800']) - exe Xbuffer . "!" - let l = Xgetlist() + Xbuffer! + let l = g:Xgetlist() call assert_true(len(l) == 2 && \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') @@ -256,8 +275,8 @@ function XbufferTests(cchar) enew! silent! call setline(1, ['Xtestfile9:900:55:Line 900', \ 'Xtestfile10:950:66:Line 950']) - exe Xgetbuffer - let l = Xgetlist() + Xgetbuffer + let l = g:Xgetlist() call assert_true(len(l) == 2 && \ l[0].lnum == 900 && l[0].col == 55 && l[0].text ==# 'Line 900' && \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950') @@ -265,8 +284,8 @@ function XbufferTests(cchar) enew! silent! call setline(1, ['Xtestfile11:700:20:Line 700', \ 'Xtestfile12:750:25:Line 750']) - exe Xaddbuffer - let l = Xgetlist() + Xaddbuffer + let l = g:Xgetlist() call assert_true(len(l) == 4 && \ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950' && \ l[2].lnum == 700 && l[2].col == 20 && l[2].text ==# 'Line 700' && @@ -320,37 +339,30 @@ func Test_vimgreptitle() endfunc function XqfTitleTests(cchar) - let Xgetexpr = a:cchar . 'getexpr' - if a:cchar == 'c' - let Xgetlist = function('getqflist') - else - let Xgetlist = function('getloclist', [0]) - endif - let Xopen = a:cchar . 'open' - let Xclose = a:cchar . 'close' + call s:setup_commands(a:cchar) - exe Xgetexpr . " ['file:1:1:message']" - let l = Xgetlist() + Xgetexpr ['file:1:1:message'] + let l = g:Xgetlist() if a:cchar == 'c' call setqflist(l, 'r') else call setloclist(0, l, 'r') endif - exe Xopen + Xopen if a:cchar == 'c' let title = ':setqflist()' else let title = ':setloclist()' endif call assert_equal(title, w:quickfix_title) - exe Xclose + Xclose endfunction " Tests for quickfix window's title function Test_qf_title() - call XqfTitleTests('c') - call XqfTitleTests('l') + call XqfTitleTests('c') + call XqfTitleTests('l') endfunction " Tests for 'errorformat' @@ -623,13 +635,6 @@ endfunction " Test for quickfix directory stack support function! s:dir_stack_tests(cchar) - let Xgetexpr = a:cchar . 'getexpr' - if a:cchar == 'c' - let Xgetlist = function('getqflist') - else - let Xgetlist = function('getloclist', [0]) - endif - let save_efm=&efm set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f' @@ -644,12 +649,12 @@ function! s:dir_stack_tests(cchar) \ "Leaving dir 'dir1/a'\n" . \ 'habits1.txt:4:2 Liters of water' . "\n" . \ "Entering dir 'dir2'\n" . - \ 'habits5.txt:5:3 Cups of hot green tea' . "\n" . + \ 'habits5.txt:5:3 Cups of hot green tea' . "\n" \ "Leaving dir 'dir2'\n" - exe Xgetexpr . " l" + Xgetexpr l - let qf = Xgetlist() + let qf = g:Xgetlist() call assert_equal('dir1/a/habits2.txt', bufname(qf[1].bufnr)) call assert_equal(1, qf[1].lnum) @@ -703,18 +708,14 @@ function! Test_efm_dirstack() endfunction function XquickfixChangedByAutocmd(cchar) - let Xolder = a:cchar . 'older' - let Xgetexpr = a:cchar . 'getexpr' - let Xrewind = a:cchar . 'rewind' + call s:setup_commands(a:cchar) if a:cchar == 'c' - let Xsetlist = function('setqflist') let ErrorNr = 'E925' function! ReadFunc() colder cgetexpr [] endfunc else - let Xsetlist = function('setloclist', [0]) let ErrorNr = 'E926' function! ReadFunc() lolder @@ -732,9 +733,9 @@ function XquickfixChangedByAutocmd(cchar) let qflist = [] for word in words call add(qflist, {'filename': 'test_changed.txt'}) - call Xsetlist(qflist, ' ') + call g:Xsetlist(qflist, ' ') endfor - exec "call assert_fails('" . Xrewind . "', '" . ErrorNr . ":')" + call assert_fails('Xrewind', ErrorNr . ':') augroup! testgroup endfunc @@ -760,51 +761,44 @@ endfunc func Test_cgetexpr_works() " this must not crash Vim cgetexpr [$x] + lgetexpr [$x] endfunc " Tests for the setqflist() and setloclist() functions function SetXlistTests(cchar, bnum) - let Xwindow = a:cchar . 'window' - let Xnext = a:cchar . 'next' - if a:cchar == 'c' - let Xsetlist = function('setqflist') - let Xgetlist = function('getqflist') - else - let Xsetlist = function('setloclist', [0]) - let Xgetlist = function('getloclist', [0]) - endif + call s:setup_commands(a:cchar) - call Xsetlist([{'bufnr': a:bnum, 'lnum': 1}, + call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 1}, \ {'bufnr': a:bnum, 'lnum': 2}]) - let l = Xgetlist() + let l = g:Xgetlist() call assert_equal(2, len(l)) call assert_equal(2, l[1].lnum) - exe Xnext - call Xsetlist([{'bufnr': a:bnum, 'lnum': 3}], 'a') - let l = Xgetlist() + Xnext + call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 3}], 'a') + let l = g:Xgetlist() call assert_equal(3, len(l)) - exe Xnext + Xnext call assert_equal(3, line('.')) " Appending entries to the list should not change the cursor position " in the quickfix window - exe Xwindow + Xwindow 1 - call Xsetlist([{'bufnr': a:bnum, 'lnum': 4}, + call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 4}, \ {'bufnr': a:bnum, 'lnum': 5}], 'a') call assert_equal(1, line('.')) close - call Xsetlist([{'bufnr': a:bnum, 'lnum': 3}, + call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 3}, \ {'bufnr': a:bnum, 'lnum': 4}, \ {'bufnr': a:bnum, 'lnum': 5}], 'r') - let l = Xgetlist() + let l = g:Xgetlist() call assert_equal(3, len(l)) call assert_equal(5, l[2].lnum) - call Xsetlist([]) - let l = Xgetlist() + call g:Xsetlist([]) + let l = g:Xgetlist() call assert_equal(0, len(l)) endfunction @@ -820,58 +814,65 @@ function Test_setqflist() call delete('Xtestfile') endfunction -func Test_setqflist_empty_middle() +function Xlist_empty_middle(cchar) + call s:setup_commands(a:cchar) + " create three quickfix lists - vimgrep Test_ test_quickfix.vim - let testlen = len(getqflist()) + Xvimgrep Test_ test_quickfix.vim + let testlen = len(g:Xgetlist()) call assert_true(testlen > 0) - vimgrep empty test_quickfix.vim - call assert_true(len(getqflist()) > 0) - vimgrep matches test_quickfix.vim - let matchlen = len(getqflist()) + Xvimgrep empty test_quickfix.vim + call assert_true(len(g:Xgetlist()) > 0) + Xvimgrep matches test_quickfix.vim + let matchlen = len(g:Xgetlist()) call assert_true(matchlen > 0) - colder + Xolder " make the middle list empty - call setqflist([], 'r') - call assert_true(len(getqflist()) == 0) - colder - call assert_equal(testlen, len(getqflist())) - cnewer - cnewer - call assert_equal(matchlen, len(getqflist())) + call g:Xsetlist([], 'r') + call assert_true(len(g:Xgetlist()) == 0) + Xolder + call assert_equal(testlen, len(g:Xgetlist())) + Xnewer + Xnewer + call assert_equal(matchlen, len(g:Xgetlist())) endfunc -func Test_setqflist_empty_older() +function Test_setqflist_empty_middle() + call Xlist_empty_middle('c') + call Xlist_empty_middle('l') +endfunction + +function Xlist_empty_older(cchar) + call s:setup_commands(a:cchar) + " create three quickfix lists - vimgrep one test_quickfix.vim - let onelen = len(getqflist()) + Xvimgrep one test_quickfix.vim + let onelen = len(g:Xgetlist()) call assert_true(onelen > 0) - vimgrep two test_quickfix.vim - let twolen = len(getqflist()) + Xvimgrep two test_quickfix.vim + let twolen = len(g:Xgetlist()) call assert_true(twolen > 0) - vimgrep three test_quickfix.vim - let threelen = len(getqflist()) + Xvimgrep three test_quickfix.vim + let threelen = len(g:Xgetlist()) call assert_true(threelen > 0) - colder 2 + Xolder 2 " make the first list empty, check the others didn't change - call setqflist([], 'r') - call assert_true(len(getqflist()) == 0) - cnewer - call assert_equal(twolen, len(getqflist())) - cnewer - call assert_equal(threelen, len(getqflist())) -endfunc + call g:Xsetlist([], 'r') + call assert_true(len(g:Xgetlist()) == 0) + Xnewer + call assert_equal(twolen, len(g:Xgetlist())) + Xnewer + call assert_equal(threelen, len(g:Xgetlist())) +endfunction + +function Test_setqflist_empty_older() + call Xlist_empty_older('c') + call Xlist_empty_older('l') +endfunction function! XquickfixSetListWithAct(cchar) - let Xolder = a:cchar . 'older' - let Xnewer = a:cchar . 'newer' - if a:cchar == 'c' - let Xsetlist = function('setqflist') - let Xgetlist = function('getqflist') - else - let Xsetlist = function('setloclist', [0]) - let Xgetlist = function('getloclist', [0]) - endif + call s:setup_commands(a:cchar) + let list1 = [{'filename': 'fnameA', 'text': 'A'}, \ {'filename': 'fnameB', 'text': 'B'}] let list2 = [{'filename': 'fnameC', 'text': 'C'}, @@ -880,42 +881,42 @@ function! XquickfixSetListWithAct(cchar) " {action} is unspecified. Same as specifing ' '. new | only - exec "silent! " . Xnewer . "99" - call Xsetlist(list1) - call Xsetlist(list2) - let li = Xgetlist() + silent! Xnewer 99 + call g:Xsetlist(list1) + call g:Xsetlist(list2) + let li = g:Xgetlist() call assert_equal(3, len(li)) call assert_equal('C', li[0]['text']) call assert_equal('D', li[1]['text']) call assert_equal('E', li[2]['text']) - exec "silent! " . Xolder - let li = Xgetlist() + silent! Xolder + let li = g:Xgetlist() call assert_equal(2, len(li)) call assert_equal('A', li[0]['text']) call assert_equal('B', li[1]['text']) " {action} is specified ' '. new | only - exec "silent! " . Xnewer . "99" - call Xsetlist(list1) - call Xsetlist(list2, ' ') - let li = Xgetlist() + silent! Xnewer 99 + call g:Xsetlist(list1) + call g:Xsetlist(list2, ' ') + let li = g:Xgetlist() call assert_equal(3, len(li)) call assert_equal('C', li[0]['text']) call assert_equal('D', li[1]['text']) call assert_equal('E', li[2]['text']) - exec "silent! " . Xolder - let li = Xgetlist() + silent! Xolder + let li = g:Xgetlist() call assert_equal(2, len(li)) call assert_equal('A', li[0]['text']) call assert_equal('B', li[1]['text']) " {action} is specified 'a'. new | only - exec "silent! " . Xnewer . "99" - call Xsetlist(list1) - call Xsetlist(list2, 'a') - let li = Xgetlist() + silent! Xnewer 99 + call g:Xsetlist(list1) + call g:Xsetlist(list2, 'a') + let li = g:Xgetlist() call assert_equal(5, len(li)) call assert_equal('A', li[0]['text']) call assert_equal('B', li[1]['text']) @@ -925,10 +926,10 @@ function! XquickfixSetListWithAct(cchar) " {action} is specified 'r'. new | only - exec "silent! " . Xnewer . "99" - call Xsetlist(list1) - call Xsetlist(list2, 'r') - let li = Xgetlist() + silent! Xnewer 99 + call g:Xsetlist(list1) + call g:Xsetlist(list2, 'r') + let li = g:Xgetlist() call assert_equal(3, len(li)) call assert_equal('C', li[0]['text']) call assert_equal('D', li[1]['text']) @@ -936,11 +937,11 @@ function! XquickfixSetListWithAct(cchar) " Test for wrong value. new | only - call assert_fails("call Xsetlist(0)", 'E714:') - call assert_fails("call Xsetlist(list1, '')", 'E927:') - call assert_fails("call Xsetlist(list1, 'aa')", 'E927:') - call assert_fails("call Xsetlist(list1, ' a')", 'E927:') - call assert_fails("call Xsetlist(list1, 0)", 'E928:') + call assert_fails("call g:Xsetlist(0)", 'E714:') + call assert_fails("call g:Xsetlist(list1, '')", 'E927:') + call assert_fails("call g:Xsetlist(list1, 'aa')", 'E927:') + call assert_fails("call g:Xsetlist(list1, ' a')", 'E927:') + call assert_fails("call g:Xsetlist(list1, 0)", 'E928:') endfunc function Test_quickfix_set_list_with_act() @@ -948,8 +949,8 @@ function Test_quickfix_set_list_with_act() call XquickfixSetListWithAct('l') endfunction -func XLongLinesTests() - let l = getqflist() +function XLongLinesTests(cchar) + let l = g:Xgetlist() call assert_equal(3, len(l)) call assert_equal(1, l[0].lnum) @@ -962,25 +963,32 @@ func XLongLinesTests() call assert_equal(1, l[2].col) call assert_equal(10, len(l[2].text)) - call setqflist([], 'r') -endfunc + call g:Xsetlist([], 'r') +endfunction + +function s:long_lines_tests(cchar) + call s:setup_commands(a:cchar) -func Test_long_lines() let testfile = 'samples/quickfix.txt' " file - exe 'cgetfile' testfile - call XLongLinesTests() + exe 'Xgetfile' testfile + call XLongLinesTests(a:cchar) " list - cexpr readfile(testfile) - call XLongLinesTests() + Xexpr readfile(testfile) + call XLongLinesTests(a:cchar) " string - cexpr join(readfile(testfile), "\n") - call XLongLinesTests() + Xexpr join(readfile(testfile), "\n") + call XLongLinesTests(a:cchar) " buffer - e testfile - exe 'cbuffer' bufnr('%') -endfunc + exe 'edit' testfile + exe 'Xbuffer' bufnr('%') +endfunction + +function Test_long_lines() + call s:long_lines_tests('c') + call s:long_lines_tests('l') +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index 04f995ee0a..f9385dcc93 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -499,7 +499,7 @@ static int included_patches[] = { // 1944 NA // 1943 NA // 1942 NA - // 1941, + 1941, // 1940, // 1939 NA // 1938 NA From 63d4ac7b2515072bffabe1d69fd6eb62aeb860f4 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:38 -0500 Subject: [PATCH 16/26] vim-patch:7.4.1949 Problem: Minor problems with the quickfix code. Solution: Fix the problems. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/38df43bd13a2498cc96b3ddd9a20dd75126bd171 --- src/nvim/quickfix.c | 11 +++++------ src/nvim/testdir/test_quickfix.vim | 2 ++ src/nvim/version.c | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 9b2dbf1bf5..16d336c41f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -541,11 +541,12 @@ qf_init_ext ( if (buflnum > lnumlast) break; p_buf = ml_get_buf(buf, buflnum++, false); - linelen = STRLEN(p_buf); - if (linelen > IOSIZE - 2) { + len = STRLEN(p_buf); + if (len > IOSIZE - 2) { linebuf = qf_grow_linebuf(&growbuf, &growbufsiz, len, &linelen); } else { linebuf = IObuff; + linelen = len; } STRLCPY(linebuf, p_buf, linelen + 1); } @@ -1238,10 +1239,8 @@ static int qf_get_fnum(char_u *directory, char_u *fname) return buf->b_fnum; } -/* - * push dirbuf onto the directory stack and return pointer to actual dir or - * NULL on error - */ +// Push dirbuf onto the directory stack and return pointer to actual dir or +// NULL on error. static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr) { struct dir_stack_T *ds_ptr; diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 025f26059f..bfdce9cd38 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -635,6 +635,8 @@ endfunction " Test for quickfix directory stack support function! s:dir_stack_tests(cchar) + call s:setup_commands(a:cchar) + let save_efm=&efm set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f' diff --git a/src/nvim/version.c b/src/nvim/version.c index f9385dcc93..480e6723f3 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -491,7 +491,7 @@ static int included_patches[] = { 1952, // 1951 NA // 1950, - // 1949, + 1949, // 1948, // 1947 NA // 1946 NA From d091faf2849dcd4ece60bffaaf8db61ae4f2fe5e Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:43 -0500 Subject: [PATCH 17/26] vim-patch:7.4.1950 Problem: Quickfix long lines test not executed for buffer. Solution: Call the function to test long lines. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/f50df3925b7c909d1cda4c868d8c7ba38189aabe --- src/nvim/testdir/test_quickfix.vim | 1 + src/nvim/version.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index bfdce9cd38..6ae60b1641 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -988,6 +988,7 @@ function s:long_lines_tests(cchar) " buffer exe 'edit' testfile exe 'Xbuffer' bufnr('%') + call XLongLinesTests(a:cchar) endfunction function Test_long_lines() diff --git a/src/nvim/version.c b/src/nvim/version.c index 480e6723f3..b75aae3226 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -490,7 +490,7 @@ static int included_patches[] = { // 1953, 1952, // 1951 NA - // 1950, + 1950, 1949, // 1948, // 1947 NA From 8f0bf810ff9257b55afc2ee95c2e0f81bdec79bd Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:47 -0500 Subject: [PATCH 18/26] vim-patch:7.4.1953 Problem: Not all parts of the quickfix code are tested. Solution: Add more tests. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/049cba9e9760152b5695399a991dc61cea9ba143 --- src/nvim/testdir/samples/quickfix.txt | 5 +- src/nvim/testdir/test_quickfix.vim | 239 +++++++++++++++++++++++++- src/nvim/version.c | 2 +- 3 files changed, 236 insertions(+), 10 deletions(-) diff --git a/src/nvim/testdir/samples/quickfix.txt b/src/nvim/testdir/samples/quickfix.txt index 38c8f49149..2de3835473 100644 --- a/src/nvim/testdir/samples/quickfix.txt +++ b/src/nvim/testdir/samples/quickfix.txt @@ -1,3 +1,4 @@ -samples/quickfix.txt:1:1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +samples/quickfix.txt:1:1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa samples/quickfix.txt:2:1:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -samples/quickfix.txt:3:1:cccccccccc +samples/quickfix.txt:3:1:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc +samples/quickfix.txt:4:1:dddddddddd diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 6ae60b1641..3bd7a8c4fb 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -25,6 +25,9 @@ function! s:setup_commands(cchar) command! -nargs=* -bang Xnext cnext command! -nargs=* Xexpr cexpr command! -nargs=* Xvimgrep vimgrep + command! -nargs=* Xgrep grep + command! -nargs=* Xgrepadd grepadd + command! -nargs=* Xhelpgrep helpgrep let g:Xgetlist = function('getqflist') let g:Xsetlist = function('setqflist') else @@ -45,6 +48,9 @@ function! s:setup_commands(cchar) command! -nargs=* -bang Xnext lnext command! -nargs=* Xexpr lexpr command! -nargs=* Xvimgrep lvimgrep + command! -nargs=* Xgrep lgrep + command! -nargs=* Xgrepadd lgrepadd + command! -nargs=* Xhelpgrep lhelpgrep let g:Xgetlist = function('getloclist', [0]) let g:Xsetlist = function('setloclist', [0]) endif @@ -228,6 +234,9 @@ function XfileTests(cchar) \ l[0].lnum == 700 && l[0].col == 10 && l[0].text ==# 'Line 700' && \ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800') + " Test with a non existent file + call assert_fails('Xfile non_existent_file', 'E40') + " Run cfile/lfile from a modified buffer enew! silent! put ='Quickfix' @@ -299,11 +308,23 @@ function Test_cbuffer() call XbufferTests('l') endfunction -function Test_helpgrep() - helpgrep quickfix - copen +function! s:test_xhelpgrep(cchar) + call s:setup_commands(a:cchar) + Xhelpgrep quickfix + Xopen + if a:cchar == 'c' + let title_text = ':helpgrep quickfix' + else + let title_text = ':lhelpgrep quickfix' + endif + call assert_true(w:quickfix_title =~ title_text, w:quickfix_title) " This wipes out the buffer, make sure that doesn't cause trouble. - cclose + Xclose +endfunction + +function Test_helpgrep() + call s:test_xhelpgrep('c') + call s:test_xhelpgrep('l') endfunc func Test_errortitle() @@ -709,6 +730,47 @@ function! Test_efm_dirstack() call delete('habits1.txt') endfunction +" TODO: +" Add tests for the following formats in 'errorformat' +" %n %t %r %+ %- %O +function! Test_efm2() + let save_efm = &efm + + " Test for invalid efm + set efm=%L%M%N + call assert_fails('cexpr "abc.txt:1:Hello world"', 'E376:') + call assert_fails('lexpr "abc.txt:1:Hello world"', 'E376:') + + " Test for %s format in efm + set efm=%f:%s + cexpr 'Xtestfile:Line search text' + + let l = getqflist() + call assert_equal(l[0].pattern, '^\VLine search text\$') + call assert_equal(l[0].lnum, 0) + + let lines=["[Xtestfile1]", + \ "(1,17) error: ';' missing", + \ "(21,2) warning: variable 'z' not defined", + \ "(67,3) error: end of file found before string ended", + \ "", + \ "[Xtestfile2]", + \ "", + \ "[Xtestfile3]", + \ "NEW compiler v1.1", + \ "(2,2) warning: variable 'x' not defined", + \ "(67,3) warning: 's' already defined" + \] + set efm=%+P[%f],(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%-Q + cgetexpr lines + let l = getqflist() + call assert_equal(9, len(l)) + call assert_equal(21, l[2].lnum) + call assert_equal(2, l[2].col) + + let &efm = save_efm +endfunction + function XquickfixChangedByAutocmd(cchar) call s:setup_commands(a:cchar) if a:cchar == 'c' @@ -954,16 +1016,19 @@ endfunction function XLongLinesTests(cchar) let l = g:Xgetlist() - call assert_equal(3, len(l)) + call assert_equal(4, len(l)) call assert_equal(1, l[0].lnum) call assert_equal(1, l[0].col) - call assert_equal(4070, len(l[0].text)) + call assert_equal(1975, len(l[0].text)) call assert_equal(2, l[1].lnum) call assert_equal(1, l[1].col) call assert_equal(4070, len(l[1].text)) call assert_equal(3, l[2].lnum) call assert_equal(1, l[2].col) - call assert_equal(10, len(l[2].text)) + call assert_equal(4070, len(l[2].text)) + call assert_equal(4, l[3].lnum) + call assert_equal(1, l[3].col) + call assert_equal(10, len(l[3].text)) call g:Xsetlist([], 'r') endfunction @@ -995,3 +1060,163 @@ function Test_long_lines() call s:long_lines_tests('c') call s:long_lines_tests('l') endfunction + +function! s:create_test_file(filename) + let l = [] + for i in range(1, 20) + call add(l, 'Line' . i) + endfor + call writefile(l, a:filename) +endfunction + +function! Test_switchbuf() + call s:create_test_file('Xqftestfile1') + call s:create_test_file('Xqftestfile2') + call s:create_test_file('Xqftestfile3') + + new | only + edit Xqftestfile1 + let file1_winid = win_getid() + new Xqftestfile2 + let file2_winid = win_getid() + cgetexpr ['Xqftestfile1:5:Line5', + \ 'Xqftestfile1:6:Line6', + \ 'Xqftestfile2:10:Line10', + \ 'Xqftestfile2:11:Line11', + \ 'Xqftestfile3:15:Line15', + \ 'Xqftestfile3:16:Line16'] + + new + let winid = win_getid() + cfirst | cnext + call assert_equal(winid, win_getid()) + cnext | cnext + call assert_equal(winid, win_getid()) + cnext | cnext + call assert_equal(winid, win_getid()) + enew + + set switchbuf=useopen + cfirst | cnext + call assert_equal(file1_winid, win_getid()) + cnext | cnext + call assert_equal(file2_winid, win_getid()) + cnext | cnext + call assert_equal(file2_winid, win_getid()) + + enew | only + set switchbuf=usetab + tabedit Xqftestfile1 + tabedit Xqftestfile2 + tabfirst + cfirst | cnext + call assert_equal(2, tabpagenr()) + cnext | cnext + call assert_equal(3, tabpagenr()) + cnext | cnext + call assert_equal(3, tabpagenr()) + tabfirst | tabonly | enew + + set switchbuf=split + cfirst | cnext + call assert_equal(1, winnr('$')) + cnext | cnext + call assert_equal(2, winnr('$')) + cnext | cnext + call assert_equal(3, winnr('$')) + enew | only + + set switchbuf=newtab + cfirst | cnext + call assert_equal(1, tabpagenr('$')) + cnext | cnext + call assert_equal(2, tabpagenr('$')) + cnext | cnext + call assert_equal(3, tabpagenr('$')) + tabfirst | enew | tabonly | only + + set switchbuf= + edit Xqftestfile1 + let file1_winid = win_getid() + new Xqftestfile2 + let file2_winid = win_getid() + copen + exe "normal 1G\" + call assert_equal(file1_winid, win_getid()) + copen + exe "normal 3G\" + call assert_equal(file2_winid, win_getid()) + copen | only + exe "normal 5G\" + call assert_equal(2, winnr('$')) + call assert_equal(1, bufwinnr('Xqftestfile3')) + + enew | only + + call delete('Xqftestfile1') + call delete('Xqftestfile2') + call delete('Xqftestfile3') +endfunction + +function! Xadjust_qflnum(cchar) + call s:setup_commands(a:cchar) + + enew | only + + call s:create_test_file('Xqftestfile') + edit Xqftestfile + + Xgetexpr ['Xqftestfile:5:Line5', + \ 'Xqftestfile:10:Line10', + \ 'Xqftestfile:15:Line15', + \ 'Xqftestfile:20:Line20'] + + 6,14delete + call append(6, ['Buffer', 'Window']) + + let l = g:Xgetlist() + + call assert_equal(5, l[0].lnum) + call assert_equal(6, l[2].lnum) + call assert_equal(13, l[3].lnum) + + enew! + call delete('Xqftestfile') +endfunction + +function! Test_adjust_lnum() + call Xadjust_qflnum('c') + call Xadjust_qflnum('l') +endfunction + +" Tests for the :grep/:lgrep and :grepadd/:lgrepadd commands +function! s:test_xgrep(cchar) + call s:setup_commands(a:cchar) + + " The following lines are used for the grep test. Don't remove. + " Grep_Test_Text: Match 1 + " Grep_Test_Text: Match 2 + " GrepAdd_Test_Text: Match 1 + " GrepAdd_Test_Text: Match 2 + enew! | only + set makeef&vim + silent Xgrep Grep_Test_Text: test_quickfix.vim + call assert_true(len(g:Xgetlist()) == 3) + Xopen + call assert_true(w:quickfix_title =~ '^:grep') + Xclose + enew + set makeef=Temp_File_## + silent Xgrepadd GrepAdd_Test_Text: test_quickfix.vim + call assert_true(len(g:Xgetlist()) == 6) +endfunction + +function! Test_grep() + if !has('unix') + " The grepprg may not be set on non-Unix systems + return + endif + + call s:test_xgrep('c') + call s:test_xgrep('l') +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index b75aae3226..c4fdcd61f9 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -487,7 +487,7 @@ static int included_patches[] = { 1956, // 1955, // 1954, - // 1953, + 1953, 1952, // 1951 NA 1950, From 82f54c0a5eea91dcfd7a509588b4ac37f7e55b57 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:52 -0500 Subject: [PATCH 19/26] vim-patch:7.4.1964 Problem: The quickfix init function is too big. Solution: Factor out parsing 'errorformat' to a separate function. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/688e3d1fd9b9129a5ba0e0d599ccfe6f4443daf3 --- src/nvim/quickfix.c | 430 ++++++++++++++++++++++++-------------------- src/nvim/version.c | 2 +- 2 files changed, 240 insertions(+), 192 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 16d336c41f..1499c3e12f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -188,6 +188,243 @@ static char_u *qf_grow_linebuf(char_u **growbuf, size_t *growbufsiz, return *growbuf; } +static struct fmtpattern +{ + char_u convchar; + char *pattern; +} fmt_pat[FMT_PATTERNS] = +{ + {'f', ".\\+"}, // only used when at end + {'n', "\\d\\+"}, + {'l', "\\d\\+"}, + {'c', "\\d\\+"}, + {'t', "."}, + {'m', ".\\+"}, + {'r', ".*"}, + {'p', "[- .]*"}, + {'v', "\\d\\+"}, + {'s', ".\\+"} +}; + +// Converts a 'errorformat' string to regular expression pattern +static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr, + char_u *regpat, char_u *errmsg) +{ + // Build regexp pattern from current 'errorformat' option + char_u *ptr = regpat; + *ptr++ = '^'; + int round = 0; + for (char_u *efmp = efm; efmp < efm + len; efmp++) { + if (*efmp == '%') { + efmp++; + int idx; + for (idx = 0; idx < FMT_PATTERNS; idx++) { + if (fmt_pat[idx].convchar == *efmp) { + break; + } + } + if (idx < FMT_PATTERNS) { + if (fmt_ptr->addr[idx]) { + sprintf((char *)errmsg, + _("E372: Too many %%%c in format string"), *efmp); + EMSG(errmsg); + return -1; + } + if ((idx + && idx < 6 + && vim_strchr((char_u *)"DXOPQ", fmt_ptr->prefix) != NULL) + || (idx == 6 + && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)) { + sprintf((char *)errmsg, + _("E373: Unexpected %%%c in format string"), *efmp); + EMSG(errmsg); + return -1; + } + round++; + fmt_ptr->addr[idx] = (char_u)round; + *ptr++ = '\\'; + *ptr++ = '('; +#ifdef BACKSLASH_IN_FILENAME + if (*efmp == 'f') { + // Also match "c:" in the file name, even when + // checking for a colon next: "%f:". + // "\%(\a:\)\=" + STRCPY(ptr, "\\%(\\a:\\)\\="); + ptr += 10; + } +#endif + if (*efmp == 'f' && efmp[1] != NUL) { + if (efmp[1] != '\\' && efmp[1] != '%') { + // A file name may contain spaces, but this isn't + // in "\f". For "%f:%l:%m" there may be a ":" in + // the file name. Use ".\{-1,}x" instead (x is + // the next character), the requirement that :999: + // follows should work. + STRCPY(ptr, ".\\{-1,}"); + ptr += 7; + } else { + // File name followed by '\\' or '%': include as + // many file name chars as possible. + STRCPY(ptr, "\\f\\+"); + ptr += 4; + } + } else { + char_u *srcptr = (char_u *)fmt_pat[idx].pattern; + while ((*ptr = *srcptr++) != NUL) { + ptr++; + } + } + *ptr++ = '\\'; + *ptr++ = ')'; + } else if (*efmp == '*') { + if (*++efmp == '[' || *efmp == '\\') { + if ((*ptr++ = *efmp) == '[') { // %*[^a-z0-9] etc. + if (efmp[1] == '^') { + *ptr++ = *++efmp; + } + if (efmp < efm + len) { + efmp++; + *ptr++ = *efmp; // could be ']' + while (efmp < efm + len) { + efmp++; + if ((*ptr++ = *efmp) == ']') { + break; + } + } + if (efmp == efm + len) { + EMSG(_("E374: Missing ] in format string")); + return -1; + } + } + } else if (efmp < efm + len) { // %*\D, %*\s etc. + efmp++; + *ptr++ = *efmp; + } + *ptr++ = '\\'; + *ptr++ = '+'; + } else { + // TODO: scanf()-like: %*ud, %*3c, %*f, ... ? + sprintf((char *)errmsg, + _("E375: Unsupported %%%c in format string"), *efmp); + EMSG(errmsg); + return -1; + } + } else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) { + *ptr++ = *efmp; // regexp magic characters + } else if (*efmp == '#') { + *ptr++ = '*'; + } else if (*efmp == '>') { + fmt_ptr->conthere = true; + } else if (efmp == efm + 1) { // analyse prefix + if (vim_strchr((char_u *)"+-", *efmp) != NULL) { + fmt_ptr->flags = *efmp++; + } + if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) { + fmt_ptr->prefix = *efmp; + } else { + sprintf((char *)errmsg, + _("E376: Invalid %%%c in format string prefix"), *efmp); + EMSG(errmsg); + return -1; + } + } else { + sprintf((char *)errmsg, + _("E377: Invalid %%%c in format string"), *efmp); + EMSG(errmsg); + return -1; + } + } else { // copy normal character + if (*efmp == '\\' && efmp + 1 < efm + len) { + efmp++; + } else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) { + *ptr++ = '\\'; // escape regexp atoms + } + if (*efmp) { + *ptr++ = *efmp; + } + } + } + *ptr++ = '$'; + *ptr = NUL; + + return 0; +} + +static void free_efm_list(efm_T **efm_first) +{ + for (efm_T *efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first) { + *efm_first = efm_ptr->next; + vim_regfree(efm_ptr->prog); + xfree(efm_ptr); + } +} + +// Parse 'errorformat' option +static efm_T * parse_efm_option(char_u *efm) +{ + efm_T *fmt_ptr = NULL; + efm_T *fmt_first = NULL; + efm_T *fmt_last = NULL; + int len; + + size_t errmsglen = CMDBUFFSIZE + 1; + char_u *errmsg = xmalloc(errmsglen); + + // Get some space to modify the format string into. + size_t i = (FMT_PATTERNS * 3) + (STRLEN(efm) << 2); + for (int round = FMT_PATTERNS - 1; round >= 0; ) { + i += STRLEN(fmt_pat[round--].pattern); + } +#ifdef COLON_IN_FILENAME + i += 12; /* "%f" can become twelve chars longer */ +#else + i += 2; /* "%f" can become two chars longer */ +#endif + char_u *fmtstr = xmalloc(i); + + while (efm[0] != NUL) { + // Allocate a new eformat structure and put it at the end of the list + fmt_ptr = (efm_T *)xcalloc(1, sizeof(efm_T)); + if (fmt_first == NULL) { // first one + fmt_first = fmt_ptr; + } else { + fmt_last->next = fmt_ptr; + } + fmt_last = fmt_ptr; + + // Isolate one part in the 'errorformat' option + for (len = 0; efm[len] != NUL && efm[len] != ','; len++) { + if (efm[len] == '\\' && efm[len + 1] != NUL) { + len++; + } + } + + if (efm_to_regpat(efm, len, fmt_ptr, fmtstr, errmsg) == -1) { + goto parse_efm_error; + } + if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) { + goto parse_efm_error; + } + // Advance to next part + efm = skip_to_option_part(efm + len); // skip comma and spaces + } + + if (fmt_first == NULL) { // nothing found + EMSG(_("E378: 'errorformat' contains no pattern")); + } + + goto parse_efm_end; + +parse_efm_error: + free_efm_list(&fmt_first); + +parse_efm_end: + xfree(fmtstr); + xfree(errmsg); + + return fmt_first; +} + // Read the errorfile "efile" into memory, line by line, building the error // list. // Alternative: when "efile" is NULL read errors from buffer "buf". @@ -213,7 +450,6 @@ qf_init_ext ( char_u *errmsg; size_t errmsglen; char_u *pattern; - char_u *fmtstr = NULL; char_u *growbuf = NULL; size_t growbuflen; size_t growbufsiz = 0; @@ -228,17 +464,13 @@ qf_init_ext ( int enr = 0; FILE *fd = NULL; qfline_T *old_last = NULL; - char_u *efmp; efm_T *fmt_first = NULL; - efm_T *fmt_last = NULL; efm_T *fmt_ptr; efm_T *fmt_start = NULL; char_u *efm; char_u *ptr; - char_u *srcptr; size_t len; int i; - int round; int idx = 0; bool multiline = false; bool multiignore = false; @@ -252,22 +484,6 @@ qf_init_ext ( listitem_T *p_li = NULL; struct dir_stack_T *file_stack = NULL; regmatch_T regmatch; - static struct fmtpattern { - char_u convchar; - char *pattern; - } fmt_pat[FMT_PATTERNS] = - { - {'f', ".\\+"}, /* only used when at end */ - {'n', "\\d\\+"}, - {'l', "\\d\\+"}, - {'c', "\\d\\+"}, - {'t', "."}, - {'m', ".\\+"}, - {'r', ".*"}, - {'p', "[- .]*"}, - {'v', "\\d\\+"}, - {'s', ".\\+"} - }; namebuf = xmalloc(CMDBUFFSIZE + 1); errmsglen = CMDBUFFSIZE + 1; @@ -296,172 +512,9 @@ qf_init_ext ( efm = buf->b_p_efm; else efm = errorformat; - /* - * Get some space to modify the format string into. - */ - size_t fmtstr_size = 3 * FMT_PATTERNS + 4 * STRLEN(efm); - for (round = FMT_PATTERNS; round > 0; ) { - fmtstr_size += STRLEN(fmt_pat[--round].pattern); - } -#ifdef COLON_IN_FILENAME - fmtstr_size += 12; // "%f" can become twelve chars longer -#else - fmtstr_size += 2; // "%f" can become two chars longer -#endif - fmtstr = xmalloc(fmtstr_size); - while (efm[0] != NUL) { - /* - * Allocate a new eformat structure and put it at the end of the list - */ - fmt_ptr = xcalloc(1, sizeof(efm_T)); - if (fmt_first == NULL) /* first one */ - fmt_first = fmt_ptr; - else - fmt_last->next = fmt_ptr; - fmt_last = fmt_ptr; - - /* - * Isolate one part in the 'errorformat' option - */ - for (len = 0; efm[len] != NUL && efm[len] != ','; ++len) - if (efm[len] == '\\' && efm[len + 1] != NUL) - ++len; - - /* - * Build regexp pattern from current 'errorformat' option - */ - ptr = fmtstr; - *ptr++ = '^'; - round = 0; - for (efmp = efm; efmp < efm + len; ++efmp) { - if (*efmp == '%') { - ++efmp; - for (idx = 0; idx < FMT_PATTERNS; ++idx) - if (fmt_pat[idx].convchar == *efmp) - break; - if (idx < FMT_PATTERNS) { - if (fmt_ptr->addr[idx]) { - sprintf((char *)errmsg, - _("E372: Too many %%%c in format string"), *efmp); - EMSG(errmsg); - goto error2; - } - if ((idx - && idx < 6 - && vim_strchr((char_u *)"DXOPQ", - fmt_ptr->prefix) != NULL) - || (idx == 6 - && vim_strchr((char_u *)"OPQ", - fmt_ptr->prefix) == NULL)) { - sprintf((char *)errmsg, - _("E373: Unexpected %%%c in format string"), *efmp); - EMSG(errmsg); - goto error2; - } - fmt_ptr->addr[idx] = (char_u)++ round; - *ptr++ = '\\'; - *ptr++ = '('; -#ifdef BACKSLASH_IN_FILENAME - if (*efmp == 'f') { - /* Also match "c:" in the file name, even when - * checking for a colon next: "%f:". - * "\%(\a:\)\=" */ - STRCPY(ptr, "\\%(\\a:\\)\\="); - ptr += 10; - } -#endif - if (*efmp == 'f' && efmp[1] != NUL) { - if (efmp[1] != '\\' && efmp[1] != '%') { - /* A file name may contain spaces, but this isn't - * in "\f". For "%f:%l:%m" there may be a ":" in - * the file name. Use ".\{-1,}x" instead (x is - * the next character), the requirement that :999: - * follows should work. */ - STRCPY(ptr, ".\\{-1,}"); - ptr += 7; - } else { - /* File name followed by '\\' or '%': include as - * many file name chars as possible. */ - STRCPY(ptr, "\\f\\+"); - ptr += 4; - } - } else { - srcptr = (char_u *)fmt_pat[idx].pattern; - while ((*ptr = *srcptr++) != NUL) - ++ptr; - } - *ptr++ = '\\'; - *ptr++ = ')'; - } else if (*efmp == '*') { - if (*++efmp == '[' || *efmp == '\\') { - if ((*ptr++ = *efmp) == '[') { /* %*[^a-z0-9] etc. */ - if (efmp[1] == '^') - *ptr++ = *++efmp; - if (efmp < efm + len) { - *ptr++ = *++efmp; /* could be ']' */ - while (efmp < efm + len - && (*ptr++ = *++efmp) != ']') - /* skip */; - if (efmp == efm + len) { - EMSG(_("E374: Missing ] in format string")); - goto error2; - } - } - } else if (efmp < efm + len) /* %*\D, %*\s etc. */ - *ptr++ = *++efmp; - *ptr++ = '\\'; - *ptr++ = '+'; - } else { - /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */ - sprintf((char *)errmsg, - _("E375: Unsupported %%%c in format string"), *efmp); - EMSG(errmsg); - goto error2; - } - } else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) - *ptr++ = *efmp; /* regexp magic characters */ - else if (*efmp == '#') - *ptr++ = '*'; - else if (*efmp == '>') - fmt_ptr->conthere = TRUE; - else if (efmp == efm + 1) { /* analyse prefix */ - if (vim_strchr((char_u *)"+-", *efmp) != NULL) - fmt_ptr->flags = *efmp++; - if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) - fmt_ptr->prefix = *efmp; - else { - sprintf((char *)errmsg, - _("E376: Invalid %%%c in format string prefix"), *efmp); - EMSG(errmsg); - goto error2; - } - } else { - sprintf((char *)errmsg, - _("E377: Invalid %%%c in format string"), *efmp); - EMSG(errmsg); - goto error2; - } - } else { /* copy normal character */ - if (*efmp == '\\' && efmp + 1 < efm + len) - ++efmp; - else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) - *ptr++ = '\\'; /* escape regexp atoms */ - if (*efmp) - *ptr++ = *efmp; - } - } - *ptr++ = '$'; - *ptr = NUL; - if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) - goto error2; - /* - * Advance to next part - */ - efm = skip_to_option_part(efm + len); /* skip comma and spaces */ - } + fmt_first = parse_efm_option(efm); if (fmt_first == NULL) { /* nothing found */ - EMSG(_("E378: 'errorformat' contains no pattern")); goto error2; } @@ -899,18 +952,13 @@ error2: qf_init_ok: if (fd != NULL) fclose(fd); - for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first) { - fmt_first = fmt_ptr->next; - vim_regfree(fmt_ptr->prog); - xfree(fmt_ptr); - } + free_efm_list(&fmt_first); qf_clean_dir_stack(&dir_stack); qf_clean_dir_stack(&file_stack); qf_init_end: xfree(namebuf); xfree(errmsg); xfree(pattern); - xfree(fmtstr); xfree(growbuf); qf_update_buffer(qi, old_last); diff --git a/src/nvim/version.c b/src/nvim/version.c index c4fdcd61f9..3efc161b05 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -476,7 +476,7 @@ static int included_patches[] = { 1967, // 1966, // 1965 NA - // 1964, + 1964, // 1963 NA // 1962, 1961, From fd94e6313b3e7314561cbe90b4cacd44d1088c8f Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:05:58 -0500 Subject: [PATCH 20/26] vim-patch:7.4.1966 Problem: Coverity reports a resource leak. Solution: Close "fd" also when bailing out. https://github.com/vim/vim/commit/bcf7772a23624edc0942120e564f6b4ac95604ad --- src/nvim/quickfix.c | 5 ++--- src/nvim/version.c | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 1499c3e12f..39f95d19ae 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -941,7 +941,7 @@ restofline: } /* return number of matches */ retval = qi->qf_lists[qi->qf_curlist].qf_count; - goto qf_init_ok; + goto qf_init_end; } EMSG(_(e_readerrf)); error2: @@ -949,13 +949,12 @@ error2: qi->qf_listcount--; if (qi->qf_curlist > 0) --qi->qf_curlist; -qf_init_ok: +qf_init_end: if (fd != NULL) fclose(fd); free_efm_list(&fmt_first); qf_clean_dir_stack(&dir_stack); qf_clean_dir_stack(&file_stack); -qf_init_end: xfree(namebuf); xfree(errmsg); xfree(pattern); diff --git a/src/nvim/version.c b/src/nvim/version.c index 3efc161b05..576843e61d 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -474,7 +474,7 @@ static int included_patches[] = { // 1969 NA // 1968, 1967, - // 1966, + 1966, // 1965 NA 1964, // 1963 NA From 5f6eb62a316712554644a5a76d255df77fba0091 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 14 Dec 2016 10:55:21 -0500 Subject: [PATCH 21/26] vim-patch:7.4.1980 Problem: 'errorformat' is parsed for every call to ":caddexpr". Can't add to two location lists asynchronously. Solution: Keep the previously parsed data when appropriate. (mostly by Yegappan Lakshmanan) https://github.com/vim/vim/commit/361c8f0e517e41f1f1d34dae328044406fde80ac --- src/nvim/quickfix.c | 127 ++++++++++++++++++----------- src/nvim/testdir/test_quickfix.vim | 82 +++++++++++++++---- src/nvim/version.c | 2 +- 3 files changed, 147 insertions(+), 64 deletions(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 39f95d19ae..f4654628fb 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -48,8 +48,6 @@ struct dir_stack_T { char_u *dirname; }; -static struct dir_stack_T *dir_stack = NULL; - /* * For each error the next struct is allocated and linked in a list. */ @@ -97,6 +95,15 @@ struct qf_info_S { int qf_listcount; /* current number of lists */ int qf_curlist; /* current error list */ qf_list_T qf_lists[LISTCOUNT]; + + int qf_dir_curlist; ///< error list for qf_dir_stack + struct dir_stack_T *qf_dir_stack; + char_u *qf_directory; + struct dir_stack_T *qf_file_stack; + char_u *qf_currfile; + bool qf_multiline; + bool qf_multiignore; + bool qf_multiscan; }; static qf_info_T ql_info; /* global quickfix list */ @@ -464,25 +471,20 @@ qf_init_ext ( int enr = 0; FILE *fd = NULL; qfline_T *old_last = NULL; - efm_T *fmt_first = NULL; + static efm_T *fmt_first = NULL; efm_T *fmt_ptr; efm_T *fmt_start = NULL; char_u *efm; + static char_u *last_efm = NULL; char_u *ptr; size_t len; int i; int idx = 0; - bool multiline = false; - bool multiignore = false; - bool multiscan = false; int retval = -1; // default: return error flag - char_u *directory = NULL; - char_u *currfile = NULL; char_u *tail = NULL; char_u *p_buf = NULL; char_u *p_str = NULL; listitem_T *p_li = NULL; - struct dir_stack_T *file_stack = NULL; regmatch_T regmatch; namebuf = xmalloc(CMDBUFFSIZE + 1); @@ -513,7 +515,33 @@ qf_init_ext ( else efm = errorformat; - fmt_first = parse_efm_option(efm); + // If we are not adding or adding to another list: clear the state. + if (newlist || qi->qf_curlist != qi->qf_dir_curlist) { + qi->qf_dir_curlist = qi->qf_curlist; + qf_clean_dir_stack(&qi->qf_dir_stack); + qi->qf_directory = NULL; + qf_clean_dir_stack(&qi->qf_file_stack); + qi->qf_currfile = NULL; + qi->qf_multiline = false; + qi->qf_multiignore = false; + qi->qf_multiscan = false; + } + + // If the errorformat didn't change between calls, then reuse the previously + // parsed values. + if (last_efm == NULL || (STRCMP(last_efm, efm) != 0)) { + // free the previously parsed data + xfree(last_efm); + last_efm = NULL; + free_efm_list(&fmt_first); + + // parse the current 'efm' + fmt_first = parse_efm_option(efm); + if (fmt_first != NULL) { + last_efm = vim_strsave(efm); + } + } + if (fmt_first == NULL) { /* nothing found */ goto error2; } @@ -696,11 +724,11 @@ qf_init_ext ( restofline: for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) { idx = fmt_ptr->prefix; - if (multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) + if (qi->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) continue; namebuf[0] = NUL; pattern[0] = NUL; - if (!multiscan) + if (!qi->qf_multiscan) errmsg[0] = NUL; lnum = 0; col = 0; @@ -713,7 +741,7 @@ restofline: int r = vim_regexec(®match, linebuf, (colnr_T)0); fmt_ptr->prog = regmatch.regprog; if (r) { - if ((idx == 'C' || idx == 'Z') && !multiline) { + if ((idx == 'C' || idx == 'Z') && !qi->qf_multiline) { continue; } if (vim_strchr((char_u *)"EWI", idx) != NULL) { @@ -759,7 +787,7 @@ restofline: continue; type = *regmatch.startp[i]; } - if (fmt_ptr->flags == '+' && !multiscan) { // %+ + if (fmt_ptr->flags == '+' && !qi->qf_multiscan) { // %+ if (linelen > errmsglen) { // linelen + null terminator errmsg = xrealloc(errmsg, linelen + 1); @@ -820,7 +848,7 @@ restofline: break; } } - multiscan = false; + qi->qf_multiscan = false; if (fmt_ptr == NULL || idx == 'D' || idx == 'X') { if (fmt_ptr != NULL) { @@ -829,10 +857,12 @@ restofline: EMSG(_("E379: Missing or empty directory name")); goto error2; } - if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL) + qi->qf_directory = qf_push_dir(namebuf, &qi->qf_dir_stack, false); + if (qi->qf_directory == NULL) { goto error2; + } } else if (idx == 'X') /* leave directory */ - directory = qf_pop_dir(&dir_stack); + qi->qf_directory = qf_pop_dir(&qi->qf_dir_stack); } namebuf[0] = NUL; // no match found, remove file name lnum = 0; // don't jump to this line @@ -844,7 +874,7 @@ restofline: // copy whole line to error message STRLCPY(errmsg, linebuf, linelen + 1); if (fmt_ptr == NULL) { - multiline = multiignore = false; + qi->qf_multiline = qi->qf_multiignore = false; } } else if (fmt_ptr != NULL) { /* honor %> item */ @@ -852,14 +882,14 @@ restofline: fmt_start = fmt_ptr; if (vim_strchr((char_u *)"AEWI", idx) != NULL) { - multiline = true; // start of a multi-line message - multiignore = false; // reset continuation + qi->qf_multiline = true; // start of a multi-line message + qi->qf_multiignore = false; // reset continuation } else if (vim_strchr((char_u *)"CZ", idx) != NULL) { /* continuation of multi-line msg */ qfline_T *qfprev = qi->qf_lists[qi->qf_curlist].qf_last; if (qfprev == NULL) goto error2; - if (*errmsg && !multiignore) { + if (*errmsg && !qi->qf_multiignore) { size_t len = STRLEN(qfprev->qf_text); qfprev->qf_text = xrealloc(qfprev->qf_text, len + STRLEN(errmsg) + 2); qfprev->qf_text[len] = '\n'; @@ -875,12 +905,13 @@ restofline: qfprev->qf_col = col; qfprev->qf_viscol = use_viscol; if (!qfprev->qf_fnum) - qfprev->qf_fnum = qf_get_fnum(directory, + qfprev->qf_fnum = qf_get_fnum(qi, qi->qf_directory, *namebuf - || directory ? namebuf : currfile - && valid ? currfile : 0); + || qi->qf_directory + ? namebuf : qi->qf_currfile + && valid ? qi->qf_currfile : 0); if (idx == 'Z') { - multiline = multiignore = false; + qi->qf_multiline = qi->qf_multiignore = false; } line_breakcheck(); continue; @@ -889,31 +920,32 @@ restofline: valid = false; if (*namebuf == NUL || os_path_exists(namebuf)) { if (*namebuf && idx == 'P') { - currfile = qf_push_dir(namebuf, &file_stack); + qi->qf_currfile = qf_push_dir(namebuf, &qi->qf_file_stack, true); } else if (idx == 'Q') { - currfile = qf_pop_dir(&file_stack); + qi->qf_currfile = qf_pop_dir(&qi->qf_file_stack); } *namebuf = NUL; if (tail && *tail) { STRMOVE(IObuff, skipwhite(tail)); - multiscan = true; + qi->qf_multiscan = true; goto restofline; } } } if (fmt_ptr->flags == '-') { // generally exclude this line - if (multiline) { - multiignore = true; // also exclude continuation lines + if (qi->qf_multiline) { + // also exclude continuation lines + qi->qf_multiignore = true; } continue; } } if (qf_add_entry(qi, - directory, - (*namebuf || directory) + qi->qf_directory, + (*namebuf || qi->qf_directory) ? namebuf - : ((currfile && valid) ? currfile : (char_u *)NULL), + : ((qi->qf_currfile && valid) ? qi->qf_currfile : (char_u *)NULL), 0, errmsg, lnum, @@ -952,9 +984,6 @@ error2: qf_init_end: if (fd != NULL) fclose(fd); - free_efm_list(&fmt_first); - qf_clean_dir_stack(&dir_stack); - qf_clean_dir_stack(&file_stack); xfree(namebuf); xfree(errmsg); xfree(pattern); @@ -1071,7 +1100,7 @@ static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum, buf->b_has_qf_entry = true; } } else - qfp->qf_fnum = qf_get_fnum(dir, fname); + qfp->qf_fnum = qf_get_fnum(qi, dir, fname); qfp->qf_text = vim_strsave(mesg); qfp->qf_lnum = lnum; qfp->qf_col = col; @@ -1245,7 +1274,7 @@ void copy_loclist(win_T *from, win_T *to) // Get buffer number for file "dir.name". // Also sets the b_has_qf_entry flag. -static int qf_get_fnum(char_u *directory, char_u *fname) +static int qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname) { char_u *ptr; buf_T *buf; @@ -1267,7 +1296,7 @@ static int qf_get_fnum(char_u *directory, char_u *fname) */ if (!os_path_exists(ptr)) { xfree(ptr); - directory = qf_guess_filepath(fname); + directory = qf_guess_filepath(qi, fname); if (directory) ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE); else @@ -1288,7 +1317,7 @@ static int qf_get_fnum(char_u *directory, char_u *fname) // Push dirbuf onto the directory stack and return pointer to actual dir or // NULL on error. -static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr) +static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, bool is_file_stack) { struct dir_stack_T *ds_ptr; @@ -1301,7 +1330,7 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr) /* store directory on the stack */ if (vim_isAbsName(dirbuf) || (*stackptr)->next == NULL - || (*stackptr && dir_stack != *stackptr)) + || (*stackptr && is_file_stack)) (*stackptr)->dirname = vim_strsave(dirbuf); else { /* Okay we don't have an absolute path. @@ -1403,17 +1432,17 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr) * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb. * qf_guess_filepath will return NULL. */ -static char_u *qf_guess_filepath(char_u *filename) +static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename) { struct dir_stack_T *ds_ptr; struct dir_stack_T *ds_tmp; char_u *fullname; /* no dirs on the stack - there's nothing we can do */ - if (dir_stack == NULL) + if (qi->qf_dir_stack == NULL) return NULL; - ds_ptr = dir_stack->next; + ds_ptr = qi->qf_dir_stack->next; fullname = NULL; while (ds_ptr) { xfree(fullname); @@ -1429,15 +1458,14 @@ static char_u *qf_guess_filepath(char_u *filename) xfree(fullname); /* clean up all dirs we already left */ - while (dir_stack->next != ds_ptr) { - ds_tmp = dir_stack->next; - dir_stack->next = dir_stack->next->next; + while (qi->qf_dir_stack->next != ds_ptr) { + ds_tmp = qi->qf_dir_stack->next; + qi->qf_dir_stack->next = qi->qf_dir_stack->next->next; xfree(ds_tmp->dirname); xfree(ds_tmp); } return ds_ptr==NULL ? NULL : ds_ptr->dirname; - } /// When loading a file from the quickfix, the auto commands may modify it. @@ -2146,6 +2174,9 @@ static void qf_free(qf_info_T *qi, int idx) qi->qf_lists[idx].qf_ptr = NULL; qi->qf_lists[idx].qf_title = NULL; qi->qf_lists[idx].qf_index = 0; + + qf_clean_dir_stack(&qi->qf_dir_stack); + qf_clean_dir_stack(&qi->qf_file_stack); } /* diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 3bd7a8c4fb..2c6a3600e1 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -10,6 +10,7 @@ function! s:setup_commands(cchar) if a:cchar == 'c' command! -nargs=* -bang Xlist clist command! -nargs=* Xgetexpr cgetexpr + command! -nargs=* Xaddexpr caddexpr command! -nargs=* Xolder colder command! -nargs=* Xnewer cnewer command! -nargs=* Xopen copen @@ -33,6 +34,7 @@ function! s:setup_commands(cchar) else command! -nargs=* -bang Xlist llist command! -nargs=* Xgetexpr lgetexpr + command! -nargs=* Xaddexpr laddexpr command! -nargs=* Xolder lolder command! -nargs=* Xnewer lnewer command! -nargs=* Xopen lopen @@ -661,21 +663,25 @@ function! s:dir_stack_tests(cchar) let save_efm=&efm set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f' - let l = "Entering dir 'dir1/a'\n" . - \ 'habits2.txt:1:Nine Healthy Habits' . "\n" . - \ "Entering dir 'b'\n" . - \ 'habits3.txt:2:0 Hours of television' . "\n" . - \ 'habits2.txt:7:5 Small meals' . "\n" . - \ "Entering dir 'dir1/c'\n" . - \ 'habits4.txt:3:1 Hour of exercise' . "\n" . - \ "Leaving dir 'dir1/c'\n" . - \ "Leaving dir 'dir1/a'\n" . - \ 'habits1.txt:4:2 Liters of water' . "\n" . - \ "Entering dir 'dir2'\n" . - \ 'habits5.txt:5:3 Cups of hot green tea' . "\n" - \ "Leaving dir 'dir2'\n" + let lines = ["Entering dir 'dir1/a'", + \ 'habits2.txt:1:Nine Healthy Habits', + \ "Entering dir 'b'", + \ 'habits3.txt:2:0 Hours of television', + \ 'habits2.txt:7:5 Small meals', + \ "Entering dir 'dir1/c'", + \ 'habits4.txt:3:1 Hour of exercise', + \ "Leaving dir 'dir1/c'", + \ "Leaving dir 'dir1/a'", + \ 'habits1.txt:4:2 Liters of water', + \ "Entering dir 'dir2'", + \ 'habits5.txt:5:3 Cups of hot green tea', + \ "Leaving dir 'dir2'" + \] - Xgetexpr l + Xexpr "" + for l in lines + Xaddexpr l + endfor let qf = g:Xgetlist() @@ -762,7 +768,10 @@ function! Test_efm2() \ "(67,3) warning: 's' already defined" \] set efm=%+P[%f],(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%-Q - cgetexpr lines + cexpr "" + for l in lines + caddexpr l + endfor let l = getqflist() call assert_equal(9, len(l)) call assert_equal(21, l[2].lnum) @@ -1220,3 +1229,46 @@ function! Test_grep() call s:test_xgrep('c') call s:test_xgrep('l') endfunction + +function! Test_two_windows() + " Use one 'errorformat' for two windows. Add an expression to each of them, + " make sure they each keep their own state. + set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f' + call mkdir('Xone/a', 'p') + call mkdir('Xtwo/a', 'p') + let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7'] + call writefile(lines, 'Xone/a/one.txt') + call writefile(lines, 'Xtwo/a/two.txt') + + new one + let one_id = win_getid() + lexpr "" + new two + let two_id = win_getid() + lexpr "" + + laddexpr "Entering dir 'Xtwo/a'" + call win_gotoid(one_id) + laddexpr "Entering dir 'Xone/a'" + call win_gotoid(two_id) + laddexpr 'two.txt:5:two two two' + call win_gotoid(one_id) + laddexpr 'one.txt:3:one one one' + + let loc_one = getloclist(one_id) +echo string(loc_one) + call assert_equal('Xone/a/one.txt', bufname(loc_one[1].bufnr)) + call assert_equal(3, loc_one[1].lnum) + + let loc_two = getloclist(two_id) +echo string(loc_two) + call assert_equal('Xtwo/a/two.txt', bufname(loc_two[1].bufnr)) + call assert_equal(5, loc_two[1].lnum) + + call win_gotoid(one_id) + bwipe! + call win_gotoid(two_id) + bwipe! + call delete('Xone', 'rf') + call delete('Xtwo', 'rf') +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index 576843e61d..17bb4aa356 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -460,7 +460,7 @@ static int included_patches[] = { // 1983 NA // 1982 NA // 1981, - // 1980, + 1980, // 1979, // 1978, // 1977, From f613c61dae7be1c4f9eadc223a77684a128508b0 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 12 Dec 2016 15:06:02 -0500 Subject: [PATCH 22/26] vim-patch:7.4.1984 Problem: Not all quickfix features are tested. Solution: Add a few more tests. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/0fcc7c6dd1902b71e0e7d0a35ddabafef6455a83 --- src/nvim/testdir/test_quickfix.vim | 142 +++++++++++++++++++++++++++-- src/nvim/version.c | 2 +- 2 files changed, 134 insertions(+), 10 deletions(-) diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 2c6a3600e1..a91e65df6c 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -24,6 +24,11 @@ function! s:setup_commands(cchar) command! -nargs=* Xaddbuffer caddbuffer command! -nargs=* Xrewind crewind command! -nargs=* -bang Xnext cnext + command! -nargs=* -bang Xprev cprev + command! -nargs=* -bang Xfirst cfirst + command! -nargs=* -bang Xlast clast + command! -nargs=* -bang Xnfile cnfile + command! -nargs=* -bang Xpfile cpfile command! -nargs=* Xexpr cexpr command! -nargs=* Xvimgrep vimgrep command! -nargs=* Xgrep grep @@ -48,6 +53,11 @@ function! s:setup_commands(cchar) command! -nargs=* Xaddbuffer laddbuffer command! -nargs=* Xrewind lrewind command! -nargs=* -bang Xnext lnext + command! -nargs=* -bang Xprev lprev + command! -nargs=* -bang Xfirst lfirst + command! -nargs=* -bang Xlast llast + command! -nargs=* -bang Xnfile lnfile + command! -nargs=* -bang Xpfile lpfile command! -nargs=* Xexpr lexpr command! -nargs=* Xvimgrep lvimgrep command! -nargs=* Xgrep lgrep @@ -310,6 +320,56 @@ function Test_cbuffer() call XbufferTests('l') endfunction +function XexprTests(cchar) + call s:setup_commands(a:cchar) + + call assert_fails('Xexpr 10', 'E777:') +endfunction + +function Test_cexpr() + call XexprTests('c') + call XexprTests('l') +endfunction + +" Tests for :cnext, :cprev, :cfirst, :clast commands +function Xtest_browse(cchar) + call s:setup_commands(a:cchar) + + call s:create_test_file('Xqftestfile1') + call s:create_test_file('Xqftestfile2') + + Xgetexpr ['Xqftestfile1:5:Line5', + \ 'Xqftestfile1:6:Line6', + \ 'Xqftestfile2:10:Line10', + \ 'Xqftestfile2:11:Line11'] + + Xfirst + call assert_fails('Xprev', 'E553') + call assert_fails('Xpfile', 'E553') + Xnfile + call assert_equal('Xqftestfile2', bufname('%')) + call assert_equal(10, line('.')) + Xpfile + call assert_equal('Xqftestfile1', bufname('%')) + call assert_equal(6, line('.')) + Xlast + call assert_equal('Xqftestfile2', bufname('%')) + call assert_equal(11, line('.')) + call assert_fails('Xnext', 'E553') + call assert_fails('Xnfile', 'E553') + Xrewind + call assert_equal('Xqftestfile1', bufname('%')) + call assert_equal(5, line('.')) + + call delete('Xqftestfile1') + call delete('Xqftestfile2') +endfunction + +function Test_browse() + call Xtest_browse('c') + call Xtest_browse('l') +endfunction + function! s:test_xhelpgrep(cchar) call s:setup_commands(a:cchar) Xhelpgrep quickfix @@ -736,25 +796,61 @@ function! Test_efm_dirstack() call delete('habits1.txt') endfunction -" TODO: -" Add tests for the following formats in 'errorformat' -" %n %t %r %+ %- %O -function! Test_efm2() +" Tests for invalid error format specifies +function Xinvalid_efm_Tests(cchar) + call s:setup_commands(a:cchar) + let save_efm = &efm - " Test for invalid efm - set efm=%L%M%N - call assert_fails('cexpr "abc.txt:1:Hello world"', 'E376:') - call assert_fails('lexpr "abc.txt:1:Hello world"', 'E376:') + set efm=%f:%l:%m,%f:%f:%l:%m + call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E372:') + + set efm=%f:%l:%m,%f:%l:%r:%m + call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E373:') + + set efm=%f:%l:%m,%O:%f:%l:%m + call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E373:') + + set efm=%f:%l:%m,%f:%l:%*[^a-z + call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E374:') + + set efm=%f:%l:%m,%f:%l:%*c + call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E375:') + + set efm=%f:%l:%m,%L%M%N + call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E376:') + + set efm=%f:%l:%m,%f:%l:%m:%R + call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E377:') + + set efm= + call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E378:') + + set efm=%DEntering\ dir\ abc,%f:%l:%m + call assert_fails('Xexpr ["Entering dir abc", "abc.txt:1:Hello world"]', 'E379:') + + let &efm = save_efm +endfunction + +function Test_invalid_efm() + call Xinvalid_efm_Tests('c') + call Xinvalid_efm_Tests('l') +endfunction + +" TODO: +" Add tests for the following formats in 'errorformat' +" %r %O +function! Test_efm2() + let save_efm = &efm " Test for %s format in efm set efm=%f:%s cexpr 'Xtestfile:Line search text' - let l = getqflist() call assert_equal(l[0].pattern, '^\VLine search text\$') call assert_equal(l[0].lnum, 0) + " Test for %P, %Q and %t format specifiers let lines=["[Xtestfile1]", \ "(1,17) error: ';' missing", \ "(21,2) warning: variable 'z' not defined", @@ -776,6 +872,34 @@ function! Test_efm2() call assert_equal(9, len(l)) call assert_equal(21, l[2].lnum) call assert_equal(2, l[2].col) + call assert_equal('w', l[2].type) + call assert_equal('e', l[3].type) + + " Tests for %E, %C and %Z format specifiers + let lines = ["Error 275", + \ "line 42", + \ "column 3", + \ "' ' expected after '--'" + \] + set efm=%EError\ %n,%Cline\ %l,%Ccolumn\ %c,%Z%m + cgetexpr lines + let l = getqflist() + call assert_equal(275, l[0].nr) + call assert_equal(42, l[0].lnum) + call assert_equal(3, l[0].col) + call assert_equal('E', l[0].type) + call assert_equal("\n' ' expected after '--'", l[0].text) + + " Test for %> + let lines = ["Error in line 147 of foo.c:", + \"unknown variable 'i'" + \] + set efm=unknown\ variable\ %m,%E%>Error\ in\ line\ %l\ of\ %f:,%Z%m + cgetexpr lines + let l = getqflist() + call assert_equal(147, l[0].lnum) + call assert_equal('E', l[0].type) + call assert_equal("\nunknown variable 'i'", l[0].text) let &efm = save_efm endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index 17bb4aa356..b5168f565b 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -456,7 +456,7 @@ static int included_patches[] = { // 1987 NA // 1986, // 1985 NA - // 1984, + 1984, // 1983 NA // 1982 NA // 1981, From f224f3fbf11ffd3095843c597045ca95c8241fcf Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 14 Dec 2016 14:36:38 -0500 Subject: [PATCH 23/26] vim-patch:7.4.1997 Problem: Cannot easily scroll the quickfix window. Solution: Add ":cbottom". https://github.com/vim/vim/commit/dcb170018642ec144cd87d9d9fe076575b8d1263 --- runtime/doc/quickfix.txt | 6 ++++ src/nvim/ex_cmds.lua | 6 ++++ src/nvim/quickfix.c | 48 ++++++++++++++++++++---------- src/nvim/testdir/test_quickfix.vim | 13 ++++++++ src/nvim/version.c | 2 +- 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index 7c1fc30eba..eddcb72e3f 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -428,6 +428,12 @@ EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST: :lw[indow] [height] Same as ":cwindow", except use the window showing the location list for the current window. +:cbo[ttom] Put the cursor in the last line of the quickfix window + and scroll to make it visible. This is useful for + when errors are added by an asynchronous callback. + Only call it once in a while if there are many + updates to avoid a lot of redrawing. + Normally the quickfix window is at the bottom of the screen. If there are vertical splits, it's at the bottom of the rightmost column of windows. To make it always occupy the full width: > diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index b056fff667..e39e374e2e 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -357,6 +357,12 @@ return { addr_type=ADDR_LINES, func='ex_cbuffer', }, + { + command='cbottom', + flags=bit.bor(TRLBAR), + addr_type=ADDR_LINES, + func='ex_cbottom', + }, { command='cc', flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG), diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index f4654628fb..c40b7173c5 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2431,6 +2431,34 @@ void ex_copen(exarg_T *eap) update_topline(); /* scroll to show the line */ } +// Move the cursor in the quickfix window to "lnum". +static void qf_win_goto(win_T *win, linenr_T lnum) +{ + win_T *old_curwin = curwin; + + curwin = win; + curbuf = win->w_buffer; + curwin->w_cursor.lnum = lnum; + curwin->w_cursor.col = 0; + curwin->w_cursor.coladd = 0; + curwin->w_curswant = 0; + update_topline(); // scroll to show the line + redraw_later(VALID); + curwin->w_redr_status = true; // update ruler + curwin = old_curwin; + curbuf = curwin->w_buffer; +} + +// :cbottom command. +void ex_cbottom(exarg_T *eap) +{ + win_T *win = qf_find_win(&ql_info); + + if (win != NULL && win->w_cursor.lnum != win->w_buffer->b_ml.ml_line_count) { + qf_win_goto(win, win->w_buffer->b_ml.ml_line_count); + } +} + /* * Return the number of the current entry (line number in the quickfix * window). @@ -2467,24 +2495,14 @@ qf_win_pos_update ( if (win != NULL && qf_index <= win->w_buffer->b_ml.ml_line_count && old_qf_index != qf_index) { - win_T *old_curwin = curwin; - - curwin = win; - curbuf = win->w_buffer; if (qf_index > old_qf_index) { - curwin->w_redraw_top = old_qf_index; - curwin->w_redraw_bot = qf_index; + win->w_redraw_top = old_qf_index; + win->w_redraw_bot = qf_index; } else { - curwin->w_redraw_top = qf_index; - curwin->w_redraw_bot = old_qf_index; + win->w_redraw_top = qf_index; + win->w_redraw_bot = old_qf_index; } - curwin->w_cursor.lnum = qf_index; - curwin->w_cursor.col = 0; - update_topline(); /* scroll to show the line */ - redraw_later(VALID); - curwin->w_redr_status = TRUE; /* update ruler */ - curwin = old_curwin; - curbuf = curwin->w_buffer; + qf_win_goto(win, qf_index); } return win != NULL; } diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index a91e65df6c..7b141f17a4 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -1396,3 +1396,16 @@ echo string(loc_two) call delete('Xone', 'rf') call delete('Xtwo', 'rf') endfunc + +function Test_cbottom() + call setqflist([{'filename': 'foo', 'lnum': 42}]) + copen + let wid = win_getid() + call assert_equal(1, line('.')) + wincmd w + call setqflist([{'filename': 'var', 'lnum': 24}], 'a') + cbottom + call win_gotoid(wid) + call assert_equal(2, line('.')) + cclose +endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index b5168f565b..9a273dd66c 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -443,7 +443,7 @@ static int included_patches[] = { // 2000, // 1999, // 1998 NA - // 1997, + 1997, // 1996, // 1995 NA // 1994, From 2c59277ca867cb3cb0144adedcfe05373d5498de Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 14 Dec 2016 15:33:06 -0500 Subject: [PATCH 24/26] vim-patch:7.4.2010 Problem: There is a :cbottom command but no :lbottom command. Solution: Add :lbottom. (Yegappan Lakshmanan) https://github.com/vim/vim/commit/537ef08408c50e0c4104d57f74993b3b0ed9560d --- runtime/doc/index.txt | 2 ++ runtime/doc/quickfix.txt | 7 ++++++- src/nvim/ex_cmds.lua | 6 ++++++ src/nvim/quickfix.c | 14 ++++++++++++-- src/nvim/testdir/test_quickfix.vim | 23 +++++++++++++++++------ src/nvim/version.c | 2 +- 6 files changed, 44 insertions(+), 10 deletions(-) diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index bd2df5d1e5..1f4557fe30 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1129,6 +1129,7 @@ tag command action ~ |:caddfile| :caddf[ile] add error message to current quickfix list |:call| :cal[l] call a function |:catch| :cat[ch] part of a :try command +|:cbottom| :cbo[ttom] scroll to the bottom of the quickfix window |:cbuffer| :cb[uffer] parse error messages and jump to first error |:cc| :cc go to specific error |:cclose| :ccl[ose] close quickfix window @@ -1286,6 +1287,7 @@ tag command action ~ |:last| :la[st] go to the last file in the argument list |:language| :lan[guage] set the language (locale) |:later| :lat[er] go to newer change, redo +|:lbottom| :lbo[ttom] scroll to the bottom of the location window |:lbuffer| :lb[uffer] parse locations and jump to first location |:lcd| :lc[d] change directory locally |:lchdir| :lch[dir] change directory locally diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index eddcb72e3f..cbb2a23a48 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -1,4 +1,4 @@ -*quickfix.txt* For Vim version 7.4. Last change: 2016 Jul 01 +*quickfix.txt* For Vim version 7.4. Last change: 2016 Jul 07 VIM REFERENCE MANUAL by Bram Moolenaar @@ -428,12 +428,17 @@ EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST: :lw[indow] [height] Same as ":cwindow", except use the window showing the location list for the current window. + *:cbo* *:cbottom* :cbo[ttom] Put the cursor in the last line of the quickfix window and scroll to make it visible. This is useful for when errors are added by an asynchronous callback. Only call it once in a while if there are many updates to avoid a lot of redrawing. + *:lbo* *:lbottom* +:lbo[ttom] Same as ":cbottom", except use the window showing the + location list for the current window. + Normally the quickfix window is at the bottom of the screen. If there are vertical splits, it's at the bottom of the rightmost column of windows. To make it always occupy the full width: > diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index e39e374e2e..eaf18fc664 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1271,6 +1271,12 @@ return { addr_type=ADDR_LINES, func='ex_later', }, + { + command='lbottom', + flags=bit.bor(TRLBAR), + addr_type=ADDR_LINES, + func='ex_cbottom', + }, { command='lbuffer', flags=bit.bor(BANG, RANGE, NOTADR, WORD1, TRLBAR), diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index c40b7173c5..93d0df1076 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2449,10 +2449,20 @@ static void qf_win_goto(win_T *win, linenr_T lnum) curbuf = curwin->w_buffer; } -// :cbottom command. +// :cbottom/:lbottom command. void ex_cbottom(exarg_T *eap) { - win_T *win = qf_find_win(&ql_info); + qf_info_T *qi = &ql_info; + + if (eap->cmdidx == CMD_lbottom) { + qi = GET_LOC_LIST(curwin); + if (qi == NULL) { + EMSG(_(e_loclist)); + return; + } + } + + win_T *win = qf_find_win(qi); if (win != NULL && win->w_cursor.lnum != win->w_buffer->b_ml.ml_line_count) { qf_win_goto(win, win->w_buffer->b_ml.ml_line_count); diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 7b141f17a4..f30902b915 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -15,6 +15,7 @@ function! s:setup_commands(cchar) command! -nargs=* Xnewer cnewer command! -nargs=* Xopen copen command! -nargs=* Xwindow cwindow + command! -nargs=* Xbottom cbottom command! -nargs=* Xclose cclose command! -nargs=* -bang Xfile cfile command! -nargs=* Xgetfile cgetfile @@ -44,6 +45,7 @@ function! s:setup_commands(cchar) command! -nargs=* Xnewer lnewer command! -nargs=* Xopen lopen command! -nargs=* Xwindow lwindow + command! -nargs=* Xbottom lbottom command! -nargs=* Xclose lclose command! -nargs=* -bang Xfile lfile command! -nargs=* Xgetfile lgetfile @@ -200,6 +202,7 @@ function XwindowTests(cchar) Xwindow call assert_true(winnr('$') == 2 && winnr() == 2 && \ getline('.') ==# 'Xtestfile1|1 col 3| Line1') + redraw! " Close the window Xclose @@ -1397,15 +1400,23 @@ echo string(loc_two) call delete('Xtwo', 'rf') endfunc -function Test_cbottom() - call setqflist([{'filename': 'foo', 'lnum': 42}]) - copen +function XbottomTests(cchar) + call s:setup_commands(a:cchar) + + call g:Xsetlist([{'filename': 'foo', 'lnum': 42}]) + Xopen let wid = win_getid() call assert_equal(1, line('.')) wincmd w - call setqflist([{'filename': 'var', 'lnum': 24}], 'a') - cbottom + call g:Xsetlist([{'filename': 'var', 'lnum': 24}], 'a') + Xbottom call win_gotoid(wid) call assert_equal(2, line('.')) - cclose + Xclose endfunc + +" Tests for the :cbottom and :lbottom commands +function Test_cbottom() + call XbottomTests('c') + call XbottomTests('l') +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index 9a273dd66c..512d52cbc4 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -430,7 +430,7 @@ static int included_patches[] = { 2013, 2012, 2011, - // 2010, + 2010, // 2009, // 2008, 2007, From 7565b48e9cc4f64d7bf008d62b4a7479676a7b09 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 14 Dec 2016 15:44:31 -0500 Subject: [PATCH 25/26] vim-patch:8.0.0006 Problem: ":lb" is interpreted as ":lbottom" while the documentation says it means ":lbuffer". Solution: Adjust the order of the commands. (haya14busa, closes vim/vim#1093) https://github.com/vim/vim/commit/ebdd90ac282909c0bfcd6e83e70505abbbd5a38d --- src/nvim/ex_cmds.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index eaf18fc664..b998b81284 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1271,18 +1271,18 @@ return { addr_type=ADDR_LINES, func='ex_later', }, - { - command='lbottom', - flags=bit.bor(TRLBAR), - addr_type=ADDR_LINES, - func='ex_cbottom', - }, { command='lbuffer', flags=bit.bor(BANG, RANGE, NOTADR, WORD1, TRLBAR), addr_type=ADDR_LINES, func='ex_cbuffer', }, + { + command='lbottom', + flags=bit.bor(TRLBAR), + addr_type=ADDR_LINES, + func='ex_cbottom', + }, { command='lcd', flags=bit.bor(BANG, FILE1, TRLBAR, CMDWIN), From 3224ade9c3b6e339083ab9e66ce3d3f32e050e09 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 14 Dec 2016 16:16:37 -0500 Subject: [PATCH 26/26] lint --- src/nvim/buffer_defs.h | 10 +- src/nvim/eval.c | 3 +- src/nvim/quickfix.c | 380 +++++++++++++++++++++-------------------- 3 files changed, 205 insertions(+), 188 deletions(-) diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index da08357cb0..0418a737eb 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -1037,11 +1037,11 @@ struct window_S { */ int w_wrow, w_wcol; /* cursor position in window */ - linenr_T w_botline; /* number of the line below the bottom of - the window */ - int w_empty_rows; /* number of ~ rows in window */ - int w_filler_rows; /* number of filler rows at the end of the - window */ + linenr_T w_botline; // number of the line below the bottom of + // the window + int w_empty_rows; // number of ~ rows in window + int w_filler_rows; // number of filler rows at the end of the + // window /* * Info about the lines currently in the window is remembered to avoid diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 45364a1666..bdbd77337d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -15018,8 +15018,7 @@ static void set_qf_ll_list(win_T *wp, typval_T *args, typval_T *rettv) char_u *act = get_tv_string_chk(action_arg); if ((*act == 'a' || *act == 'r' || *act == ' ') && act[1] == NUL) { action = *act; - } - else { + } else { EMSG2(_(e_invact), act); return; } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 93d0df1076..33a84660c1 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -74,14 +74,14 @@ struct qfline_S { #define LISTCOUNT 10 typedef struct qf_list_S { - qfline_T *qf_start; /* pointer to the first error */ + qfline_T *qf_start; // pointer to the first error qfline_T *qf_last; // pointer to the last error - qfline_T *qf_ptr; /* pointer to the current error */ - int qf_count; /* number of errors (0 means no error list) */ - int qf_index; /* current index in the error list */ - int qf_nonevalid; /* TRUE if not a single valid entry found */ - char_u *qf_title; /* title derived from the command that created - * the error list */ + qfline_T *qf_ptr; // pointer to the current error + int qf_count; // number of errors (0 means no error list) + int qf_index; // current index in the error list + int qf_nonevalid; // TRUE if not a single valid entry found + char_u *qf_title; // title derived from the command that created + // the error list } qf_list_T; struct qf_info_S { @@ -201,16 +201,16 @@ static struct fmtpattern char *pattern; } fmt_pat[FMT_PATTERNS] = { - {'f', ".\\+"}, // only used when at end - {'n', "\\d\\+"}, - {'l', "\\d\\+"}, - {'c', "\\d\\+"}, - {'t', "."}, - {'m', ".\\+"}, - {'r', ".*"}, - {'p', "[- .]*"}, - {'v', "\\d\\+"}, - {'s', ".\\+"} + { 'f', ".\\+" }, // only used when at end + { 'n', "\\d\\+" }, + { 'l', "\\d\\+" }, + { 'c', "\\d\\+" }, + { 't', "." }, + { 'm', ".\\+" }, + { 'r', ".*" }, + { 'p', "[- .]*" }, // NOLINT(whitespace/tab) + { 'v', "\\d\\+" }, + { 's', ".\\+" } }; // Converts a 'errorformat' string to regular expression pattern @@ -232,8 +232,8 @@ static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr, } if (idx < FMT_PATTERNS) { if (fmt_ptr->addr[idx]) { - sprintf((char *)errmsg, - _("E372: Too many %%%c in format string"), *efmp); + snprintf((char *)errmsg, CMDBUFFSIZE + 1, + _("E372: Too many %%%c in format string"), *efmp); EMSG(errmsg); return -1; } @@ -242,8 +242,8 @@ static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr, && vim_strchr((char_u *)"DXOPQ", fmt_ptr->prefix) != NULL) || (idx == 6 && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)) { - sprintf((char *)errmsg, - _("E373: Unexpected %%%c in format string"), *efmp); + snprintf((char *)errmsg, CMDBUFFSIZE + 1, + _("E373: Unexpected %%%c in format string"), *efmp); EMSG(errmsg); return -1; } @@ -310,9 +310,9 @@ static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr, *ptr++ = '\\'; *ptr++ = '+'; } else { - // TODO: scanf()-like: %*ud, %*3c, %*f, ... ? - sprintf((char *)errmsg, - _("E375: Unsupported %%%c in format string"), *efmp); + // TODO(vim): scanf()-like: %*ud, %*3c, %*f, ... ? + snprintf((char *)errmsg, CMDBUFFSIZE + 1, + _("E375: Unsupported %%%c in format string"), *efmp); EMSG(errmsg); return -1; } @@ -329,14 +329,14 @@ static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr, if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) { fmt_ptr->prefix = *efmp; } else { - sprintf((char *)errmsg, - _("E376: Invalid %%%c in format string prefix"), *efmp); + snprintf((char *)errmsg, CMDBUFFSIZE + 1, + _("E376: Invalid %%%c in format string prefix"), *efmp); EMSG(errmsg); return -1; } } else { - sprintf((char *)errmsg, - _("E377: Invalid %%%c in format string"), *efmp); + snprintf((char *)errmsg, CMDBUFFSIZE + 1, + _("E377: Invalid %%%c in format string"), *efmp); EMSG(errmsg); return -1; } @@ -382,11 +382,7 @@ static efm_T * parse_efm_option(char_u *efm) for (int round = FMT_PATTERNS - 1; round >= 0; ) { i += STRLEN(fmt_pat[round--].pattern); } -#ifdef COLON_IN_FILENAME - i += 12; /* "%f" can become twelve chars longer */ -#else - i += 2; /* "%f" can become two chars longer */ -#endif + i += 2; // "%f" can become two chars longer char_u *fmtstr = xmalloc(i); while (efm[0] != NUL) { @@ -440,8 +436,8 @@ parse_efm_end: // Then "lnumfirst" and "lnumlast" specify the range of lines to use. // Set the title of the list to "qf_title". // Return -1 for error, number of errors for success. -static int -qf_init_ext ( +static int +qf_init_ext( qf_info_T *qi, char_u *efile, buf_T *buf, @@ -476,7 +472,6 @@ qf_init_ext ( efm_T *fmt_start = NULL; char_u *efm; static char_u *last_efm = NULL; - char_u *ptr; size_t len; int i; int idx = 0; @@ -497,11 +492,11 @@ qf_init_ext ( goto qf_init_end; } - if (newlist || qi->qf_curlist == qi->qf_listcount) - /* make place for a new list */ + if (newlist || qi->qf_curlist == qi->qf_listcount) { + // make place for a new list qf_new_list(qi, qf_title); - else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { - /* Adding to existing list, use last entry. */ + } else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { + // Adding to existing list, use last entry. old_last = qi->qf_lists[qi->qf_curlist].qf_last; } @@ -542,7 +537,7 @@ qf_init_ext ( } } - if (fmt_first == NULL) { /* nothing found */ + if (fmt_first == NULL) { // nothing found goto error2; } @@ -574,14 +569,16 @@ qf_init_ext ( /* Get the next line from the supplied string */ char_u *p; - if (*p_str == NUL) // Reached the end of the string + if (*p_str == NUL) { // Reached the end of the string break; + } p = vim_strchr(p_str, '\n'); - if (p != NULL) + if (p != NULL) { len = (size_t)(p - p_str) + 1; - else + } else { len = STRLEN(p_str); + } if (len > IOSIZE - 2) { linebuf = qf_grow_linebuf(&growbuf, &growbufsiz, len, &linelen); @@ -602,8 +599,9 @@ qf_init_ext ( p_li = p_li->li_next; // Skip non-string items } - if (p_li == NULL) // End of the list + if (p_li == NULL) { // End of the list break; + } len = STRLEN(p_li->li_tv.vval.v_string); if (len > IOSIZE - 2) { @@ -640,9 +638,9 @@ qf_init_ext ( linelen = STRLEN(IObuff); if (linelen == IOSIZE - 1 && !(IObuff[linelen - 1] == '\n' #ifdef USE_CRNL - || IObuff[linelen - 1] == '\r' + || IObuff[linelen - 1] == '\r' #endif - )) { + )) { // NOLINT(whitespace/parens) // The current line exceeds IObuff, continue reading using growbuf // until EOL or LINE_MAXLEN bytes is read. if (growbuf == NULL) { @@ -655,7 +653,7 @@ qf_init_ext ( growbuflen = linelen; for (;;) { - if (fgets((char*)growbuf + growbuflen, + if (fgets((char *)growbuf + growbuflen, (int)(growbufsiz - growbuflen), fd) == NULL) { break; } @@ -665,7 +663,7 @@ qf_init_ext ( #ifdef USE_CRNL || growbuf[growbuflen - 1] == '\r' #endif - ) { + ) { break; } if (growbufsiz == LINE_MAXLEN) { @@ -687,7 +685,7 @@ qf_init_ext ( #ifdef USE_CRNL || IObuff[IOSIZE - 1] == '\r' #endif - ) { + ) { break; } } @@ -724,12 +722,14 @@ qf_init_ext ( restofline: for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) { idx = fmt_ptr->prefix; - if (qi->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) + if (qi->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) { continue; + } namebuf[0] = NUL; pattern[0] = NUL; - if (!qi->qf_multiscan) + if (!qi->qf_multiscan) { errmsg[0] = NUL; + } lnum = 0; col = 0; use_viscol = false; @@ -794,9 +794,10 @@ restofline: errmsglen = linelen + 1; } STRLCPY(errmsg, linebuf, linelen + 1); - } else if ((i = (int)fmt_ptr->addr[5]) > 0) { /* %m */ - if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) + } else if ((i = (int)fmt_ptr->addr[5]) > 0) { // %m + if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) { continue; + } len = (size_t)(regmatch.endp[i] - regmatch.startp[i]); if (len > errmsglen) { // len + null terminator @@ -837,8 +838,9 @@ restofline: if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) continue; len = (size_t)(regmatch.endp[i] - regmatch.startp[i]); - if (len > CMDBUFFSIZE - 5) + if (len > CMDBUFFSIZE - 5) { len = CMDBUFFSIZE - 5; + } STRCPY(pattern, "^\\V"); STRNCAT(pattern, regmatch.startp[i], len); pattern[len + 3] = '\\'; @@ -861,8 +863,9 @@ restofline: if (qi->qf_directory == NULL) { goto error2; } - } else if (idx == 'X') /* leave directory */ + } else if (idx == 'X') { // leave directory qi->qf_directory = qf_pop_dir(&qi->qf_dir_stack); + } } namebuf[0] = NUL; // no match found, remove file name lnum = 0; // don't jump to this line @@ -885,10 +888,11 @@ restofline: qi->qf_multiline = true; // start of a multi-line message qi->qf_multiignore = false; // reset continuation } else if (vim_strchr((char_u *)"CZ", idx) - != NULL) { /* continuation of multi-line msg */ + != NULL) { // continuation of multi-line msg qfline_T *qfprev = qi->qf_lists[qi->qf_curlist].qf_last; - if (qfprev == NULL) + if (qfprev == NULL) { goto error2; + } if (*errmsg && !qi->qf_multiignore) { size_t len = STRLEN(qfprev->qf_text); qfprev->qf_text = xrealloc(qfprev->qf_text, len + STRLEN(errmsg) + 2); @@ -904,12 +908,13 @@ restofline: if (!qfprev->qf_col) qfprev->qf_col = col; qfprev->qf_viscol = use_viscol; - if (!qfprev->qf_fnum) + if (!qfprev->qf_fnum) { qfprev->qf_fnum = qf_get_fnum(qi, qi->qf_directory, *namebuf || qi->qf_directory ? namebuf : qi->qf_currfile && valid ? qi->qf_currfile : 0); + } if (idx == 'Z') { qi->qf_multiline = qi->qf_multiignore = false; } @@ -942,20 +947,21 @@ restofline: } if (qf_add_entry(qi, - qi->qf_directory, - (*namebuf || qi->qf_directory) - ? namebuf - : ((qi->qf_currfile && valid) ? qi->qf_currfile : (char_u *)NULL), - 0, - errmsg, - lnum, - col, - use_viscol, - pattern, - enr, - type, - valid) == FAIL) + qi->qf_directory, + (*namebuf || qi->qf_directory) + ? namebuf : ((qi->qf_currfile && valid) + ? qi->qf_currfile : (char_u *)NULL), + 0, + errmsg, + lnum, + col, + use_viscol, + pattern, + enr, + type, + valid) == FAIL) { goto error2; + } line_breakcheck(); } if (fd == NULL || !ferror(fd)) { @@ -979,11 +985,13 @@ restofline: error2: qf_free(qi, qi->qf_curlist); qi->qf_listcount--; - if (qi->qf_curlist > 0) - --qi->qf_curlist; + if (qi->qf_curlist > 0) { + qi->qf_curlist--; + } qf_init_end: - if (fd != NULL) + if (fd != NULL) { fclose(fd); + } xfree(namebuf); xfree(errmsg); xfree(pattern); @@ -1099,8 +1107,9 @@ static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum, if (buf != NULL) { buf->b_has_qf_entry = true; } - } else + } else { qfp->qf_fnum = qf_get_fnum(qi, dir, fname); + } qfp->qf_text = vim_strsave(mesg); qfp->qf_lnum = lnum; qfp->qf_col = col; @@ -1129,9 +1138,9 @@ static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum, (*lastp)->qf_next = qfp; } qfp->qf_next = NULL; - qfp->qf_cleared = FALSE; + qfp->qf_cleared = false; *lastp = qfp; - ++qi->qf_lists[qi->qf_curlist].qf_count; + qi->qf_lists[qi->qf_curlist].qf_count++; if (qi->qf_lists[qi->qf_curlist].qf_index == 0 && qfp->qf_valid) { /* first valid entry */ qi->qf_lists[qi->qf_curlist].qf_index = @@ -1227,22 +1236,22 @@ void copy_loclist(win_T *from, win_T *to) qfline_T *from_qfp; qfline_T *prevp; - /* copy all the location entries in this list */ + // copy all the location entries in this list for (i = 0, from_qfp = from_qfl->qf_start; i < from_qfl->qf_count && from_qfp != NULL; - ++i, from_qfp = from_qfp->qf_next) { + i++, from_qfp = from_qfp->qf_next) { if (qf_add_entry(to->w_llist, - NULL, - NULL, - 0, - from_qfp->qf_text, - from_qfp->qf_lnum, - from_qfp->qf_col, - from_qfp->qf_viscol, - from_qfp->qf_pattern, - from_qfp->qf_nr, - 0, - from_qfp->qf_valid) == FAIL) { + NULL, + NULL, + 0, + from_qfp->qf_text, + from_qfp->qf_lnum, + from_qfp->qf_col, + from_qfp->qf_viscol, + from_qfp->qf_pattern, + from_qfp->qf_nr, + 0, + from_qfp->qf_valid) == FAIL) { qf_free_all(to); return; } @@ -1252,10 +1261,11 @@ void copy_loclist(win_T *from, win_T *to) * field is copied here. */ prevp = to->w_llist->qf_lists[to->w_llist->qf_curlist].qf_last; - prevp->qf_fnum = from_qfp->qf_fnum; /* file number */ - prevp->qf_type = from_qfp->qf_type; /* error type */ - if (from_qfl->qf_ptr == from_qfp) - to_qfl->qf_ptr = prevp; /* current location */ + prevp->qf_fnum = from_qfp->qf_fnum; // file number + prevp->qf_type = from_qfp->qf_type; // error type + if (from_qfl->qf_ptr == from_qfp) { + to_qfl->qf_ptr = prevp; // current location + } } } @@ -1278,31 +1288,32 @@ static int qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname) { char_u *ptr; buf_T *buf; - if (fname == NULL || *fname == NUL) /* no file name */ + if (fname == NULL || *fname == NUL) { // no file name return 0; + } #ifdef BACKSLASH_IN_FILENAME - if (directory != NULL) + if (directory != NULL) { slash_adjust(directory); + } slash_adjust(fname); #endif if (directory != NULL && !vim_isAbsName(fname)) { - ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE); - /* - * Here we check if the file really exists. - * This should normally be true, but if make works without - * "leaving directory"-messages we might have missed a - * directory change. - */ + ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true); + // Here we check if the file really exists. + // This should normally be true, but if make works without + // "leaving directory"-messages we might have missed a + // directory change. if (!os_path_exists(ptr)) { xfree(ptr); directory = qf_guess_filepath(qi, fname); - if (directory) - ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE); - else + if (directory) { + ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true); + } else { ptr = vim_strsave(fname); + } } - /* Use concatenated directory name and file name */ + // Use concatenated directory name and file name buf = buflist_new(ptr, NULL, (linenr_T)0, 0); xfree(ptr); } else { @@ -1317,7 +1328,8 @@ static int qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname) // Push dirbuf onto the directory stack and return pointer to actual dir or // NULL on error. -static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, bool is_file_stack) +static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, + bool is_file_stack) { struct dir_stack_T *ds_ptr; @@ -1438,9 +1450,10 @@ static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename) struct dir_stack_T *ds_tmp; char_u *fullname; - /* no dirs on the stack - there's nothing we can do */ - if (qi->qf_dir_stack == NULL) + // no dirs on the stack - there's nothing we can do + if (qi->qf_dir_stack == NULL) { return NULL; + } ds_ptr = qi->qf_dir_stack->next; fullname = NULL; @@ -1457,7 +1470,7 @@ static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename) xfree(fullname); - /* clean up all dirs we already left */ + // clean up all dirs we already left while (qi->qf_dir_stack->next != ds_ptr) { ds_tmp = qi->qf_dir_stack->next; qi->qf_dir_stack->next = qi->qf_dir_stack->next->next; @@ -1465,7 +1478,7 @@ static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename) xfree(ds_tmp); } - return ds_ptr==NULL ? NULL : ds_ptr->dirname; + return ds_ptr == NULL ? NULL : ds_ptr->dirname; } /// When loading a file from the quickfix, the auto commands may modify it. @@ -2066,7 +2079,7 @@ void qf_list(exarg_T *eap) if (qfp == NULL) { break; } - ++i; + i++; os_breakcheck(); } } @@ -2138,8 +2151,8 @@ void qf_age(exarg_T *eap) static void qf_msg(qf_info_T *qi) { smsg(_("error list %d of %d; %d errors"), - qi->qf_curlist + 1, qi->qf_listcount, - qi->qf_lists[qi->qf_curlist].qf_count); + qi->qf_curlist + 1, qi->qf_listcount, + qi->qf_lists[qi->qf_curlist].qf_count); qf_update_buffer(qi, NULL); } @@ -2150,7 +2163,7 @@ static void qf_free(qf_info_T *qi, int idx) { qfline_T *qfp; qfline_T *qfpnext; - int stop = FALSE; + bool stop = false; while (qi->qf_lists[idx].qf_count && qi->qf_lists[idx].qf_start != NULL) { qfp = qi->qf_lists[idx].qf_start; @@ -2160,14 +2173,15 @@ static void qf_free(qf_info_T *qi, int idx) stop = (qfp == qfpnext); xfree(qfp->qf_pattern); xfree(qfp); - if (stop) - /* Somehow qf_count may have an incorrect value, set it to 1 - * to avoid crashing when it's wrong. - * TODO: Avoid qf_count being incorrect. */ + if (stop) { + // Somehow qf_count may have an incorrect value, set it to 1 + // to avoid crashing when it's wrong. + // TODO(vim): Avoid qf_count being incorrect. qi->qf_lists[idx].qf_count = 1; + } } qi->qf_lists[idx].qf_start = qfpnext; - --qi->qf_lists[idx].qf_count; + qi->qf_lists[idx].qf_count--; } xfree(qi->qf_lists[idx].qf_title); qi->qf_lists[idx].qf_start = NULL; @@ -2203,7 +2217,7 @@ void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long if (qi->qf_lists[idx].qf_count) for (i = 0, qfp = qi->qf_lists[idx].qf_start; i < qi->qf_lists[idx].qf_count && qfp != NULL; - ++i, qfp = qfp->qf_next) + i++, qfp = qfp->qf_next) { if (qfp->qf_fnum == curbuf->b_fnum) { found_one = true; if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) { @@ -2214,6 +2228,7 @@ void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long } else if (amount_after && qfp->qf_lnum > line2) qfp->qf_lnum += amount_after; } + } if (!found_one) { curbuf->b_has_qf_entry = false; @@ -2442,9 +2457,9 @@ static void qf_win_goto(win_T *win, linenr_T lnum) curwin->w_cursor.col = 0; curwin->w_cursor.coladd = 0; curwin->w_curswant = 0; - update_topline(); // scroll to show the line + update_topline(); // scroll to show the line redraw_later(VALID); - curwin->w_redr_status = true; // update ruler + curwin->w_redr_status = true; // update ruler curwin = old_curwin; curbuf = curwin->w_buffer; } @@ -2639,14 +2654,15 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) return; } - /* delete all existing lines */ - while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) - (void)ml_delete((linenr_T)1, FALSE); + // delete all existing lines + while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) { + (void)ml_delete((linenr_T)1, false); + } } /* Check if there is anything to display */ if (qi->qf_curlist < qi->qf_listcount) { - /* Add one line for each error */ + // Add one line for each error if (old_last == NULL) { qfp = qi->qf_lists[qi->qf_curlist].qf_start; lnum = 0; @@ -2694,9 +2710,10 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text, IObuff + len, IOSIZE - len); - if (ml_append_buf(buf, lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE) - == FAIL) + if (ml_append_buf(buf, lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, false) + == FAIL) { break; + } lnum++; qfp = qfp->qf_next; if (qfp == NULL) { @@ -2704,8 +2721,8 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) } } if (old_last == NULL) { - /* Delete the empty line which is now at the end */ - (void)ml_delete(lnum + 1, FALSE); + // Delete the empty line which is now at the end + (void)ml_delete(lnum + 1, false); } } @@ -2713,20 +2730,20 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) check_lnums(TRUE); if (old_last == NULL) { - /* Set the 'filetype' to "qf" each time after filling the buffer. This - * resembles reading a file into a buffer, it's more logical when using - * autocommands. */ + // Set the 'filetype' to "qf" each time after filling the buffer. This + // resembles reading a file into a buffer, it's more logical when using + // autocommands. set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL); - curbuf->b_p_ma = FALSE; + curbuf->b_p_ma = false; - keep_filetype = TRUE; /* don't detect 'filetype' */ + keep_filetype = true; // don't detect 'filetype' apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, - FALSE, curbuf); + false, curbuf); apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, - FALSE, curbuf); - keep_filetype = FALSE; + false, curbuf); + keep_filetype = false; - /* make sure it will be redrawn */ + // make sure it will be redrawn redraw_curbuf_later(NOT_VALID); } @@ -3433,23 +3450,22 @@ void ex_vimgrep(exarg_T *eap) ++lnum) { col = 0; while (vim_regexec_multi(®match, curwin, buf, lnum, - col, NULL) > 0) { - ; + col, NULL) > 0) { if (qf_add_entry(qi, - NULL, /* dir */ - fname, - 0, - ml_get_buf(buf, - regmatch.startpos[0].lnum + lnum, FALSE), - regmatch.startpos[0].lnum + lnum, - regmatch.startpos[0].col + 1, - FALSE, /* vis_col */ - NULL, /* search pattern */ - 0, /* nr */ - 0, /* type */ - TRUE /* valid */ - ) == FAIL) { - got_int = TRUE; + NULL, // dir + fname, + 0, + ml_get_buf(buf, + regmatch.startpos[0].lnum + lnum, false), + regmatch.startpos[0].lnum + lnum, + regmatch.startpos[0].col + 1, + false, // vis_col + NULL, // search pattern + 0, // nr + 0, // type + true) // valid + == FAIL) { + got_int = true; break; } found_match = TRUE; @@ -3831,10 +3847,10 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) qi = ll_get_or_alloc_list(wp); } - if (action == ' ' || qi->qf_curlist == qi->qf_listcount) - /* make place for a new list */ + if (action == ' ' || qi->qf_curlist == qi->qf_listcount) { + // make place for a new list qf_new_list(qi, title); - else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) { + } else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) { // Adding to existing list, use last entry. old_last = qi->qf_lists[qi->qf_curlist].qf_last; } else if (action == 'r') { @@ -3902,11 +3918,12 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) } } - if (qi->qf_lists[qi->qf_curlist].qf_index == 0) - /* no valid entry */ - qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE; - else - qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; + if (qi->qf_lists[qi->qf_curlist].qf_index == 0) { + // no valid entry + qi->qf_lists[qi->qf_curlist].qf_nonevalid = true; + } else { + qi->qf_lists[qi->qf_curlist].qf_nonevalid = false; + } if (action != 'a') { qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { @@ -4123,22 +4140,23 @@ void ex_helpgrep(exarg_T *eap) line[--l] = NUL; if (qf_add_entry(qi, - NULL, /* dir */ - fnames[fi], - 0, - line, - lnum, - (int)(regmatch.startp[0] - line) - + 1, /* col */ - FALSE, /* vis_col */ - NULL, /* search pattern */ - 0, /* nr */ - 1, /* type */ - TRUE /* valid */ - ) == FAIL) { - got_int = TRUE; - if (line != IObuff) + NULL, // dir + fnames[fi], + 0, + line, + lnum, + (int)(regmatch.startp[0] - line) + + 1, // col + false, // vis_col + NULL, // search pattern + 0, // nr + 1, // type + true) // valid + == FAIL) { + got_int = true; + if (line != IObuff) { xfree(line); + } break; } }