@@ -190,6 +190,7 @@ static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *re
190190static void wipe_dummy_buffer (buf_T * buf , char_u * dirname_start );
191191static void unload_dummy_buffer (buf_T * buf , char_u * dirname_start );
192192static qf_info_T * ll_get_or_alloc_list (win_T * );
193+ static int entry_is_closer_to_target (qfline_T * entry , qfline_T * other_entry , int target_fnum , int target_lnum , int target_col );
193194
194195// Quickfix window check helper macro
195196#define IS_QF_WINDOW (wp ) (bt_quickfix((wp)->w_buffer) && (wp)->w_llist_ref == NULL)
@@ -7499,6 +7500,62 @@ qf_add_entry_from_dict(
74997500 return status ;
75007501}
75017502
7503+ /*
7504+ * Check if `entry` is closer to the target than `other_entry`.
7505+ *
7506+ * Only returns TRUE if `entry` is definitively closer. If it's further
7507+ * away, or there's not enough information to tell, return FALSE.
7508+ */
7509+ static int
7510+ entry_is_closer_to_target (
7511+ qfline_T * entry ,
7512+ qfline_T * other_entry ,
7513+ int target_fnum ,
7514+ int target_lnum ,
7515+ int target_col )
7516+ {
7517+ // First, compare entries to target file.
7518+ if (!target_fnum )
7519+ // Without a target file, we can't know which is closer.
7520+ return FALSE;
7521+
7522+ int is_target_file = entry -> qf_fnum && entry -> qf_fnum == target_fnum ;
7523+ int other_is_target_file = other_entry -> qf_fnum && other_entry -> qf_fnum == target_fnum ;
7524+ if (!is_target_file && other_is_target_file )
7525+ return FALSE;
7526+ else if (is_target_file && !other_is_target_file )
7527+ return TRUE;
7528+
7529+ // Both entries are pointing at the exact same file. Now compare line
7530+ // numbers.
7531+ if (!target_lnum )
7532+ // Without a target line number, we can't know which is closer.
7533+ return FALSE;
7534+
7535+ int line_distance = entry -> qf_lnum ? labs (entry -> qf_lnum - target_lnum ) : INT_MAX ;
7536+ int other_line_distance = other_entry -> qf_lnum ? labs (other_entry -> qf_lnum - target_lnum ) : INT_MAX ;
7537+ if (line_distance > other_line_distance )
7538+ return FALSE;
7539+ else if (line_distance < other_line_distance )
7540+ return TRUE;
7541+
7542+ // Both entries are pointing at the exact same line number (or no line
7543+ // number at all). Now compare columns.
7544+ if (!target_col )
7545+ // Without a target column, we can't know which is closer.
7546+ return FALSE;
7547+
7548+ int column_distance = entry -> qf_col ? abs (entry -> qf_col - target_col ) : INT_MAX ;
7549+ int other_column_distance = other_entry -> qf_col ? abs (other_entry -> qf_col - target_col ): INT_MAX ;
7550+ if (column_distance > other_column_distance )
7551+ return FALSE;
7552+ else if (column_distance < other_column_distance )
7553+ return TRUE;
7554+
7555+ // It's a complete tie! The exact same file, line, and column.
7556+ return FALSE;
7557+ }
7558+
75027559/*
75037560 * Add list of entries to quickfix/location list. Each list entry is
75047561 * a dictionary with item information.
@@ -7518,21 +7575,54 @@ qf_add_entries(
75187575 int retval = OK ;
75197576 int valid_entry = FALSE;
75207577
7578+ // If there's an entry selected in the quickfix list, remember its location
7579+ // (file, line, column), so we can select the nearest entry in the updated
7580+ // quickfix list.
7581+ int prev_fnum = 0 ;
7582+ int prev_lnum = 0 ;
7583+ int prev_col = 0 ;
7584+ if (qfl -> qf_ptr )
7585+ {
7586+ prev_fnum = qfl -> qf_ptr -> qf_fnum ;
7587+ prev_lnum = qfl -> qf_ptr -> qf_lnum ;
7588+ prev_col = qfl -> qf_ptr -> qf_col ;
7589+ }
7590+
7591+ int select_first_entry = FALSE;
7592+ int select_nearest_entry = FALSE;
7593+
75217594 if (action == ' ' || qf_idx == qi -> qf_listcount )
75227595 {
7596+ select_first_entry = TRUE;
75237597 // make place for a new list
75247598 qf_new_list (qi , title );
75257599 qf_idx = qi -> qf_curlist ;
75267600 qfl = qf_get_list (qi , qf_idx );
75277601 }
7528- else if (action == 'a' && !qf_list_empty (qfl ))
7529- // Adding to existing list, use last entry.
7530- old_last = qfl -> qf_last ;
7602+ else if (action == 'a' )
7603+ {
7604+ if (qf_list_empty (qfl ))
7605+ // Appending to empty list, select first entry.
7606+ select_first_entry = TRUE;
7607+ else
7608+ // Adding to existing list, use last entry.
7609+ old_last = qfl -> qf_last ;
7610+ }
75317611 else if (action == 'r' )
75327612 {
7613+ select_first_entry = TRUE;
75337614 qf_free_items (qfl );
75347615 qf_store_title (qfl , title );
75357616 }
7617+ else if (action == 'u' )
7618+ {
7619+ select_nearest_entry = TRUE;
7620+ qf_free_items (qfl );
7621+ qf_store_title (qfl , title );
7622+ }
7623+
7624+ qfline_T * entry_to_select = NULL ;
7625+ int entry_to_select_index = 0 ;
75367626
75377627 FOR_ALL_LIST_ITEMS (list , li )
75387628 {
@@ -7547,6 +7637,18 @@ qf_add_entries(
75477637 & valid_entry );
75487638 if (retval == QF_FAIL )
75497639 break ;
7640+
7641+ qfline_T * entry = qfl -> qf_last ;
7642+ if (
7643+ (select_first_entry && entry_to_select == NULL ) ||
7644+ (select_nearest_entry &&
7645+ (entry_to_select == NULL ||
7646+ entry_is_closer_to_target (entry , entry_to_select , prev_fnum ,
7647+ prev_lnum , prev_col ))))
7648+ {
7649+ entry_to_select = entry ;
7650+ entry_to_select_index = qfl -> qf_count ;
7651+ }
75507652 }
75517653
75527654 // Check if any valid error entries are added to the list.
@@ -7556,14 +7658,12 @@ qf_add_entries(
75567658 // no valid entry
75577659 qfl -> qf_nonevalid = TRUE;
75587660
7559- // If not appending to the list, set the current error to the first entry
7560- if (action != 'a' )
7561- qfl -> qf_ptr = qfl -> qf_start ;
7562-
7563- // Update the current error index if not appending to the list or if the
7564- // list was empty before and it is not empty now.
7565- if ((action != 'a' || qfl -> qf_index == 0 ) && !qf_list_empty (qfl ))
7566- qfl -> qf_index = 1 ;
7661+ // Set the current error.
7662+ if (entry_to_select )
7663+ {
7664+ qfl -> qf_ptr = entry_to_select ;
7665+ qfl -> qf_index = entry_to_select_index ;
7666+ }
75677667
75687668 // Don't update the cursor in quickfix window when appending entries
75697669 qf_update_buffer (qi , old_last );
@@ -7700,7 +7800,7 @@ qf_setprop_items_from_lines(
77007800 if (di -> di_tv .v_type != VAR_LIST || di -> di_tv .vval .v_list == NULL )
77017801 return FAIL ;
77027802
7703- if (action == 'r' )
7803+ if (action == 'r' || action == 'u' )
77047804 qf_free_items (& qi -> qf_lists [qf_idx ]);
77057805 if (qf_init_ext (qi , qf_idx , NULL , NULL , & di -> di_tv , errorformat ,
77067806 FALSE, (linenr_T )0 , (linenr_T )0 , NULL , NULL ) >= 0 )
@@ -7897,8 +7997,8 @@ qf_free_stack(win_T *wp, qf_info_T *qi)
78977997/*
78987998 * Populate the quickfix list with the items supplied in the list
78997999 * of dictionaries. "title" will be copied to w:quickfix_title.
7900- * "action" is 'a' for add, 'r' for replace. Otherwise create a new list.
7901- * When "what" is not NULL then only set some properties.
8000+ * "action" is 'a' for add, 'r' for replace, 'u' for update. Otherwise
8001+ * create a new list. When "what" is not NULL then only set some properties.
79028002 */
79038003 int
79048004set_errorlist (
@@ -8740,7 +8840,7 @@ set_qf_ll_list(
87408840 act = tv_get_string_chk (action_arg );
87418841 if (act == NULL )
87428842 return ; // type error; errmsg already given
8743- if ((* act == 'a' || * act == 'r' || * act == ' ' || * act == 'f' ) &&
8843+ if ((* act == 'a' || * act == 'r' || * act == 'u' || * act == ' ' || * act == 'f' ) &&
87448844 act [1 ] == NUL )
87458845 action = * act ;
87468846 else
0 commit comments