changeset 9175:d415c079f84e v7.4.1871

commit https://github.com/vim/vim/commit/864293abb72d62604d8d6b458addfb43c14230c3 Author: Bram Moolenaar <Bram@vim.org> 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)
author Christian Brabandt <cb@256bit.org>
date Thu, 02 Jun 2016 13:45:05 +0200
parents 650a14c77ccf
children 92e68e3030c6
files src/quickfix.c src/version.c
diffstat 2 files changed, 95 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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,