To: vim_dev@googlegroups.com Subject: Patch 7.4.1980 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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) Files: src/quickfix.c, src/testdir/test_quickfix.vim *** ../vim-7.4.1979/src/quickfix.c 2016-07-01 18:16:47.497936191 +0200 --- src/quickfix.c 2016-07-02 15:36:46.750806082 +0200 *************** *** 21,28 **** char_u *dirname; }; - static struct dir_stack_T *dir_stack = NULL; - /* * For each error the next struct is allocated and linked in a list. */ --- 21,26 ---- *************** *** 73,78 **** --- 71,85 ---- 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; + int qf_multiline; + int qf_multiignore; + int qf_multiscan; }; static qf_info_T ql_info; /* global quickfix list */ *************** *** 116,125 **** static void qf_msg(qf_info_T *qi); static void qf_free(qf_info_T *qi, int idx); static char_u *qf_types(int, int); ! static int qf_get_fnum(char_u *, char_u *); ! static char_u *qf_push_dir(char_u *, struct dir_stack_T **); static char_u *qf_pop_dir(struct dir_stack_T **); ! static char_u *qf_guess_filepath(char_u *); static void qf_fmt_text(char_u *text, char_u *buf, int bufsize); static void qf_clean_dir_stack(struct dir_stack_T **); #ifdef FEAT_WINDOWS --- 123,132 ---- static void qf_msg(qf_info_T *qi); static void qf_free(qf_info_T *qi, int idx); static char_u *qf_types(int, int); ! static int qf_get_fnum(qf_info_T *qi, char_u *, char_u *); ! static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack); static char_u *qf_pop_dir(struct dir_stack_T **); ! static char_u *qf_guess_filepath(qf_info_T *qi, char_u *); static void qf_fmt_text(char_u *text, char_u *buf, int bufsize); static void qf_clean_dir_stack(struct dir_stack_T **); #ifdef FEAT_WINDOWS *************** *** 532,556 **** #ifdef FEAT_WINDOWS qfline_T *old_last = NULL; #endif ! efm_T *fmt_first = NULL; efm_T *fmt_ptr; efm_T *fmt_start = NULL; char_u *efm; char_u *ptr; int len; int i; int idx = 0; - int multiline = FALSE; - int multiignore = FALSE; - int 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 = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf); --- 539,558 ---- #ifdef FEAT_WINDOWS qfline_T *old_last = NULL; #endif ! 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; int len; int i; int idx = 0; int retval = -1; /* default: return error flag */ char_u *tail = NULL; char_u *p_buf = NULL; char_u *p_str = NULL; listitem_T *p_li = NULL; regmatch_T regmatch; namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf); *************** *** 587,593 **** else efm = errorformat; ! fmt_first = parse_efm_option(efm); if (fmt_first == NULL) /* nothing found */ goto error2; --- 589,626 ---- else efm = errorformat; ! /* ! * 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 */ ! vim_free(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; *************** *** 815,825 **** int r; idx = fmt_ptr->prefix; ! if (multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) continue; namebuf[0] = NUL; pattern[0] = NUL; ! if (!multiscan) errmsg[0] = NUL; lnum = 0; col = 0; --- 848,858 ---- int r; idx = fmt_ptr->prefix; ! if (qi->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) continue; namebuf[0] = NUL; pattern[0] = NUL; ! if (!qi->qf_multiscan) errmsg[0] = NUL; lnum = 0; col = 0; *************** *** 833,839 **** fmt_ptr->prog = regmatch.regprog; if (r) { ! if ((idx == 'C' || idx == 'Z') && !multiline) continue; if (vim_strchr((char_u *)"EWI", idx) != NULL) type = idx; --- 866,872 ---- fmt_ptr->prog = regmatch.regprog; if (r) { ! if ((idx == 'C' || idx == 'Z') && !qi->qf_multiline) continue; if (vim_strchr((char_u *)"EWI", idx) != NULL) type = idx; *************** *** 885,891 **** continue; type = *regmatch.startp[i]; } ! if (fmt_ptr->flags == '+' && !multiscan) /* %+ */ { if (linelen > errmsglen) { /* linelen + null terminator */ --- 918,924 ---- continue; type = *regmatch.startp[i]; } ! if (fmt_ptr->flags == '+' && !qi->qf_multiscan) /* %+ */ { if (linelen > errmsglen) { /* linelen + null terminator */ *************** *** 958,964 **** break; } } ! multiscan = FALSE; if (fmt_ptr == NULL || idx == 'D' || idx == 'X') { --- 991,997 ---- break; } } ! qi->qf_multiscan = FALSE; if (fmt_ptr == NULL || idx == 'D' || idx == 'X') { *************** *** 971,981 **** EMSG(_("E379: Missing or empty directory name")); goto error2; } ! if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL) goto error2; } else if (idx == 'X') /* leave directory */ ! directory = qf_pop_dir(&dir_stack); } namebuf[0] = NUL; /* no match found, remove file name */ lnum = 0; /* don't jump to this line */ --- 1004,1016 ---- EMSG(_("E379: Missing or empty directory name")); goto error2; } ! 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 */ ! 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 */ *************** *** 989,995 **** /* copy whole line to error message */ vim_strncpy(errmsg, linebuf, linelen); if (fmt_ptr == NULL) ! multiline = multiignore = FALSE; } else if (fmt_ptr != NULL) { --- 1024,1030 ---- /* copy whole line to error message */ vim_strncpy(errmsg, linebuf, linelen); if (fmt_ptr == NULL) ! qi->qf_multiline = qi->qf_multiignore = FALSE; } else if (fmt_ptr != NULL) { *************** *** 999,1006 **** if (vim_strchr((char_u *)"AEWI", idx) != NULL) { ! multiline = TRUE; /* start of a multi-line message */ ! multiignore = FALSE; /* reset continuation */ } else if (vim_strchr((char_u *)"CZ", idx) != NULL) { /* continuation of multi-line msg */ --- 1034,1041 ---- if (vim_strchr((char_u *)"AEWI", idx) != NULL) { ! 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 */ *************** *** 1008,1014 **** if (qfprev == NULL) goto error2; ! if (*errmsg && !multiignore) { len = (int)STRLEN(qfprev->qf_text); if ((ptr = alloc((unsigned)(len + STRLEN(errmsg) + 2))) --- 1043,1049 ---- if (qfprev == NULL) goto error2; ! if (*errmsg && !qi->qf_multiignore) { len = (int)STRLEN(qfprev->qf_text); if ((ptr = alloc((unsigned)(len + STRLEN(errmsg) + 2))) *************** *** 1030,1040 **** qfprev->qf_col = col; qfprev->qf_viscol = use_viscol; if (!qfprev->qf_fnum) ! qfprev->qf_fnum = qf_get_fnum(directory, ! *namebuf || directory ? namebuf ! : currfile && valid ? currfile : 0); if (idx == 'Z') ! multiline = multiignore = FALSE; line_breakcheck(); continue; } --- 1065,1077 ---- qfprev->qf_col = col; qfprev->qf_viscol = use_viscol; if (!qfprev->qf_fnum) ! qfprev->qf_fnum = qf_get_fnum(qi, qi->qf_directory, ! *namebuf || qi->qf_directory != NULL ! ? namebuf ! : qi->qf_currfile != NULL && valid ! ? qi->qf_currfile : 0); if (idx == 'Z') ! qi->qf_multiline = qi->qf_multiignore = FALSE; line_breakcheck(); continue; } *************** *** 1045,1075 **** if (*namebuf == NUL || mch_getperm(namebuf) >= 0) { if (*namebuf && idx == 'P') ! currfile = qf_push_dir(namebuf, &file_stack); else if (idx == 'Q') ! currfile = qf_pop_dir(&file_stack); *namebuf = NUL; if (tail && *tail) { STRMOVE(IObuff, skipwhite(tail)); ! multiscan = TRUE; goto restofline; } } } if (fmt_ptr->flags == '-') /* generally exclude this line */ { ! if (multiline) ! multiignore = TRUE; /* also exclude continuation lines */ continue; } } if (qf_add_entry(qi, ! directory, ! (*namebuf || directory) ? namebuf ! : ((currfile && valid) ? currfile : (char_u *)NULL), 0, errmsg, lnum, --- 1082,1115 ---- if (*namebuf == NUL || mch_getperm(namebuf) >= 0) { if (*namebuf && idx == 'P') ! qi->qf_currfile = ! qf_push_dir(namebuf, &qi->qf_file_stack, TRUE); else if (idx == 'Q') ! qi->qf_currfile = qf_pop_dir(&qi->qf_file_stack); *namebuf = NUL; if (tail && *tail) { STRMOVE(IObuff, skipwhite(tail)); ! qi->qf_multiscan = TRUE; goto restofline; } } } if (fmt_ptr->flags == '-') /* generally exclude this line */ { ! if (qi->qf_multiline) ! /* also exclude continuation lines */ ! qi->qf_multiignore = TRUE; continue; } } if (qf_add_entry(qi, ! qi->qf_directory, ! (*namebuf || qi->qf_directory != NULL) ? namebuf ! : ((qi->qf_currfile != NULL && valid) ! ? qi->qf_currfile : (char_u *)NULL), 0, errmsg, lnum, *************** *** 1112,1120 **** 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); vim_free(namebuf); vim_free(errmsg); vim_free(pattern); --- 1152,1157 ---- *************** *** 1248,1254 **** buf->b_has_qf_entry = TRUE; } else ! qfp->qf_fnum = qf_get_fnum(dir, fname); if ((qfp->qf_text = vim_strsave(mesg)) == NULL) { vim_free(qfp); --- 1285,1291 ---- buf->b_has_qf_entry = TRUE; } else ! qfp->qf_fnum = qf_get_fnum(qi, dir, fname); if ((qfp->qf_text = vim_strsave(mesg)) == NULL) { vim_free(qfp); *************** *** 1450,1456 **** * 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; --- 1487,1493 ---- * Also sets the b_has_qf_entry flag. */ static int ! qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname) { char_u *ptr; buf_T *buf; *************** *** 1478,1484 **** if (mch_getperm(ptr) < 0) { vim_free(ptr); ! directory = qf_guess_filepath(fname); if (directory) ptr = concat_fnames(directory, fname, TRUE); else --- 1515,1521 ---- if (mch_getperm(ptr) < 0) { vim_free(ptr); ! directory = qf_guess_filepath(qi, fname); if (directory) ptr = concat_fnames(directory, fname, TRUE); else *************** *** 1501,1507 **** * NULL on error. */ static char_u * ! qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr) { struct dir_stack_T *ds_new; struct dir_stack_T *ds_ptr; --- 1538,1544 ---- * NULL on error. */ static char_u * ! qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack) { struct dir_stack_T *ds_new; struct dir_stack_T *ds_ptr; *************** *** 1517,1523 **** /* store directory on the stack */ if (vim_isAbsName(dirbuf) || (*stackptr)->next == NULL ! || (*stackptr && dir_stack != *stackptr)) (*stackptr)->dirname = vim_strsave(dirbuf); else { --- 1554,1560 ---- /* store directory on the stack */ if (vim_isAbsName(dirbuf) || (*stackptr)->next == NULL ! || (*stackptr && is_file_stack)) (*stackptr)->dirname = vim_strsave(dirbuf); else { *************** *** 1629,1645 **** * qf_guess_filepath will return NULL. */ static char_u * ! qf_guess_filepath(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) return NULL; ! ds_ptr = dir_stack->next; fullname = NULL; while (ds_ptr) { --- 1666,1682 ---- * qf_guess_filepath will return NULL. */ 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 (qi->qf_dir_stack == NULL) return NULL; ! ds_ptr = qi->qf_dir_stack->next; fullname = NULL; while (ds_ptr) { *************** *** 1658,1673 **** vim_free(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; vim_free(ds_tmp->dirname); vim_free(ds_tmp); } return ds_ptr==NULL? NULL: ds_ptr->dirname; - } /* --- 1695,1709 ---- vim_free(fullname); /* 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; vim_free(ds_tmp->dirname); vim_free(ds_tmp); } return ds_ptr==NULL? NULL: ds_ptr->dirname; } /* *************** *** 2484,2489 **** --- 2520,2528 ---- vim_free(qi->qf_lists[idx].qf_title); 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); } /* *** ../vim-7.4.1979/src/testdir/test_quickfix.vim 2016-06-26 14:37:47.271106643 +0200 --- src/testdir/test_quickfix.vim 2016-07-02 14:57:39.768896066 +0200 *************** *** 10,15 **** --- 10,16 ---- 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,38 **** --- 34,40 ---- 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 *************** *** 679,699 **** 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" ! ! Xgetexpr l let qf = g:Xgetlist() --- 681,705 ---- let save_efm=&efm set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f' ! 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'" ! \] ! ! Xexpr "" ! for l in lines ! Xaddexpr l ! endfor let qf = g:Xgetlist() *************** *** 780,786 **** \ "(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) --- 786,795 ---- \ "(67,3) warning: 's' already defined" \] set efm=%+P[%f],(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%-Q ! cexpr "" ! for l in lines ! caddexpr l ! endfor let l = getqflist() call assert_equal(9, len(l)) call assert_equal(21, l[2].lnum) *************** *** 1238,1240 **** --- 1247,1292 ---- 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 *** ../vim-7.4.1979/src/version.c 2016-07-01 23:13:57.388275240 +0200 --- src/version.c 2016-07-02 13:38:08.614616837 +0200 *************** *** 760,761 **** --- 760,763 ---- { /* Add new patch number below this line */ + /**/ + 1980, /**/ -- hundred-and-one symptoms of being an internet addict: 177. You log off of your system because it's time to go to work. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///