# HG changeset patch # User Christian Brabandt # Date 1464867905 -7200 # Node ID d415c079f84ebce9c674f800933a20db68bc141f # Parent 650a14c77ccfc78edbde780c4b51f43567eb1008 commit https://github.com/vim/vim/commit/864293abb72d62604d8d6b458addfb43c14230c3 Author: Bram Moolenaar Date: Thu Jun 2 13:40:04 2016 +0200 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 #841) diff --git a/src/quickfix.c b/src/quickfix.c --- a/src/quickfix.c +++ b/src/quickfix.c @@ -126,9 +126,9 @@ static int qf_win_pos_update(qf_info_T * static int is_qf_win(win_T *win, qf_info_T *qi); static win_T *qf_find_win(qf_info_T *qi); static buf_T *qf_find_buf(qf_info_T *qi); -static void qf_update_buffer(qf_info_T *qi, int update_cursor); +static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last); static void qf_set_title_var(qf_info_T *qi); -static void qf_fill_buffer(qf_info_T *qi); +static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last); #endif static char_u *get_mef_name(void); static void restore_start_dir(char_u *dirname_start); @@ -207,7 +207,8 @@ qf_grow_linebuf(char_u **growbuf, int *g /* * 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 "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". @@ -245,6 +246,9 @@ qf_init_ext( int enr = 0; FILE *fd = NULL; qfline_T *qfprev = NULL; /* init to make SASC shut up */ +#ifdef FEAT_WINDOWS + qfline_T *old_last = NULL; +#endif char_u *efmp; efm_T *fmt_first = NULL; efm_T *fmt_last = NULL; @@ -304,10 +308,13 @@ 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; + } /* * Each part of the format string is copied and modified from errorformat to @@ -1051,7 +1058,7 @@ qf_init_end: vim_free(growbuf); #ifdef FEAT_WINDOWS - qf_update_buffer(qi, TRUE); + qf_update_buffer(qi, old_last); #endif return retval; @@ -2347,7 +2354,7 @@ qf_msg(qf_info_T *qi) qi->qf_curlist + 1, qi->qf_listcount, qi->qf_lists[qi->qf_curlist].qf_count); #ifdef FEAT_WINDOWS - qf_update_buffer(qi, TRUE); + qf_update_buffer(qi, NULL); #endif } @@ -2649,7 +2656,7 @@ ex_copen(exarg_T *eap) /* * 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; @@ -2777,7 +2784,7 @@ 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, int update_cursor) +qf_update_buffer(qf_info_T *qi, qfline_T *old_last) { buf_T *buf; win_T *win; @@ -2788,8 +2795,11 @@ qf_update_buffer(qf_info_T *qi, int upda 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) { @@ -2799,13 +2809,20 @@ qf_update_buffer(qf_info_T *qi, int upda 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); } } @@ -2823,9 +2840,12 @@ qf_set_title_var(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) +qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) { linenr_T lnum; qfline_T *qfp; @@ -2833,16 +2853,34 @@ 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 @@ -2887,35 +2925,40 @@ 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) - == FAIL) + 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; #ifdef FEAT_AUTOCMD - keep_filetype = TRUE; /* don't detect 'filetype' */ - apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, + 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, + apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, FALSE, curbuf); - keep_filetype = FALSE; + keep_filetype = FALSE; #endif - - /* 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; @@ -3847,7 +3890,7 @@ ex_vimgrep(exarg_T *eap) qi->qf_lists[qi->qf_curlist].qf_index = 1; #ifdef FEAT_WINDOWS - qf_update_buffer(qi, TRUE); + qf_update_buffer(qi, NULL); #endif #ifdef FEAT_AUTOCMD @@ -4176,7 +4219,8 @@ get_errorlist(win_T *wp, list_T *list) /* * Populate the quickfix list with the items supplied in the list - * of dictionaries. "title" will be copied to w:quickfix_title + * 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( @@ -4193,6 +4237,9 @@ set_errorlist( int col, nr; int vcol; qfline_T *prevp = NULL; +#ifdef FEAT_WINDOWS + qfline_T *old_last = NULL; +#endif int valid, status; int retval = OK; qf_info_T *qi = &ql_info; @@ -4209,10 +4256,15 @@ set_errorlist( /* 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) ; +#ifdef FEAT_WINDOWS + old_last = prevp; +#endif + } else if (action == 'r') { qf_free(qi, qi->qf_curlist); @@ -4296,7 +4348,7 @@ set_errorlist( #ifdef FEAT_WINDOWS /* Don't update the cursor in quickfix window when appending entries */ - qf_update_buffer(qi, (action != 'a')); + qf_update_buffer(qi, old_last); #endif return retval; @@ -4603,7 +4655,7 @@ ex_helpgrep(exarg_T *eap) free_string_option(save_cpo); #ifdef FEAT_WINDOWS - qf_update_buffer(qi, TRUE); + qf_update_buffer(qi, NULL); #endif #ifdef FEAT_AUTOCMD diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1871, +/**/ 1870, /**/ 1869,