mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 11:15:14 -07:00
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)
361c8f0e51
This commit is contained in:
parent
fd94e6313b
commit
5f6eb62a31
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -10,6 +10,7 @@ function! s:setup_commands(cchar)
|
||||
if a:cchar == 'c'
|
||||
command! -nargs=* -bang Xlist <mods>clist<bang> <args>
|
||||
command! -nargs=* Xgetexpr <mods>cgetexpr <args>
|
||||
command! -nargs=* Xaddexpr <mods>caddexpr <args>
|
||||
command! -nargs=* Xolder <mods>colder <args>
|
||||
command! -nargs=* Xnewer <mods>cnewer <args>
|
||||
command! -nargs=* Xopen <mods>copen <args>
|
||||
@ -33,6 +34,7 @@ function! s:setup_commands(cchar)
|
||||
else
|
||||
command! -nargs=* -bang Xlist <mods>llist<bang> <args>
|
||||
command! -nargs=* Xgetexpr <mods>lgetexpr <args>
|
||||
command! -nargs=* Xaddexpr <mods>laddexpr <args>
|
||||
command! -nargs=* Xolder <mods>lolder <args>
|
||||
command! -nargs=* Xnewer <mods>lnewer <args>
|
||||
command! -nargs=* Xopen <mods>lopen <args>
|
||||
@ -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
|
||||
|
@ -460,7 +460,7 @@ static int included_patches[] = {
|
||||
// 1983 NA
|
||||
// 1982 NA
|
||||
// 1981,
|
||||
// 1980,
|
||||
1980,
|
||||
// 1979,
|
||||
// 1978,
|
||||
// 1977,
|
||||
|
Loading…
Reference in New Issue
Block a user