Skip to content

Commit b254af3

Browse files
committed
patch 8.0.1406: difficult to track changes to a quickfix list
Problem: Difficult to track changes to a quickfix list. Solution: Add a "changedtick" value. (Yegappan Lakshmanan, closes #2460)
1 parent c9e649a commit b254af3

5 files changed

Lines changed: 120 additions & 6 deletions

File tree

runtime/doc/eval.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4674,6 +4674,8 @@ getqflist([{what}]) *getqflist()*
46744674
If the optional {what} dictionary argument is supplied, then
46754675
returns only the items listed in {what} as a dictionary. The
46764676
following string items are supported in {what}:
4677+
changedtick get the total number of changes made
4678+
to the list
46774679
context get the context stored with |setqflist()|
46784680
efm errorformat to use when parsing "lines". If
46794681
not present, then the 'errorformat' option
@@ -4707,6 +4709,8 @@ getqflist([{what}]) *getqflist()*
47074709
"items" with the list of entries.
47084710

47094711
The returned dictionary contains the following entries:
4712+
changedtick total number of changes made to the
4713+
list |quickfix-changedtick|
47104714
context context information stored with |setqflist()|.
47114715
If not present, set to "".
47124716
id quickfix list ID |quickfix-ID|. If not

runtime/doc/quickfix.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ When a window with a location list is split, the new window gets a copy of the
6464
location list. When there are no longer any references to a location list,
6565
the location list is destroyed.
6666

67+
*quickfix-changedtick*
68+
Every quickfix and location list has a read-only changedtick variable that
69+
tracks the total number of changes made to the list. Every time the quickfix
70+
list is modified, this count is incremented. This can be used to perform an
71+
action only when the list has changed. The getqflist() and getloclist()
72+
functions can be used to query the current value of changedtick. You cannot
73+
change the changedtick variable.
74+
6775
The following quickfix commands can be used. The location list commands are
6876
similar to the quickfix commands, replacing the 'c' prefix in the quickfix
6977
command with 'l'.

src/quickfix.c

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ typedef struct qf_list_S
7676
int qf_multiline;
7777
int qf_multiignore;
7878
int qf_multiscan;
79+
long qf_changedtick;
7980
} qf_list_T;
8081

8182
/*
@@ -1668,6 +1669,7 @@ copy_loclist(win_T *from, win_T *to)
16681669

16691670
/* Assign a new ID for the location list */
16701671
to_qfl->qf_id = ++last_qf_id;
1672+
to_qfl->qf_changedtick = 0L;
16711673

16721674
/* When no valid entries are present in the list, qf_ptr points to
16731675
* the first item in the list */
@@ -2965,6 +2967,7 @@ qf_free(qf_info_T *qi, int idx)
29652967
free_tv(qfl->qf_ctx);
29662968
qfl->qf_ctx = NULL;
29672969
qfl->qf_id = 0;
2970+
qfl->qf_changedtick = 0L;
29682971
}
29692972

29702973
/*
@@ -3604,6 +3607,12 @@ qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
36043607
KeyTyped = old_KeyTyped;
36053608
}
36063609

3610+
static void
3611+
qf_list_changed(qf_info_T *qi, int qf_idx)
3612+
{
3613+
qi->qf_lists[qf_idx].qf_changedtick++;
3614+
}
3615+
36073616
/*
36083617
* Return TRUE when using ":vimgrep" for ":grep".
36093618
*/
@@ -3713,6 +3722,8 @@ ex_make(exarg_T *eap)
37133722
*eap->cmdlinep, enc);
37143723
if (wp != NULL)
37153724
qi = GET_LOC_LIST(wp);
3725+
if (res >= 0 && qi != NULL)
3726+
qf_list_changed(qi, qi->qf_curlist);
37163727
#ifdef FEAT_AUTOCMD
37173728
if (au_name != NULL)
37183729
{
@@ -4105,14 +4116,16 @@ ex_cfile(exarg_T *eap)
41054116
*/
41064117
res = qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile
41074118
&& eap->cmdidx != CMD_laddfile), *eap->cmdlinep, enc);
4119+
if (wp != NULL)
4120+
qi = GET_LOC_LIST(wp);
4121+
if (res >= 0 && qi != NULL)
4122+
qf_list_changed(qi, qi->qf_curlist);
41084123
#ifdef FEAT_AUTOCMD
41094124
if (au_name != NULL)
41104125
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, NULL, FALSE, curbuf);
41114126
#endif
41124127
if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile))
41134128
{
4114-
if (wp != NULL)
4115-
qi = GET_LOC_LIST(wp);
41164129
qf_jump(qi, 0, 0, eap->forceit); /* display first error */
41174130
}
41184131
}
@@ -4469,6 +4482,7 @@ ex_vimgrep(exarg_T *eap)
44694482
qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
44704483
qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start;
44714484
qi->qf_lists[qi->qf_curlist].qf_index = 1;
4485+
qf_list_changed(qi, qi->qf_curlist);
44724486

44734487
qf_update_buffer(qi, NULL);
44744488

@@ -4780,7 +4794,8 @@ enum {
47804794
QF_GETLIST_ID = 0x20,
47814795
QF_GETLIST_IDX = 0x40,
47824796
QF_GETLIST_SIZE = 0x80,
4783-
QF_GETLIST_ALL = 0xFF
4797+
QF_GETLIST_TICK = 0x100,
4798+
QF_GETLIST_ALL = 0x1FF
47844799
};
47854800

47864801
/*
@@ -4896,6 +4911,9 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
48964911
if (dict_find(what, (char_u *)"size", -1) != NULL)
48974912
flags |= QF_GETLIST_SIZE;
48984913

4914+
if (dict_find(what, (char_u *)"changedtick", -1) != NULL)
4915+
flags |= QF_GETLIST_TICK;
4916+
48994917
if (qi != NULL && qi->qf_listcount != 0)
49004918
{
49014919
qf_idx = qi->qf_curlist; /* default is the current list */
@@ -4963,6 +4981,8 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
49634981
status = dict_add_nr_str(retdict, "idx", 0L, NULL);
49644982
if ((status == OK) && (flags & QF_GETLIST_SIZE))
49654983
status = dict_add_nr_str(retdict, "size", 0L, NULL);
4984+
if ((status == OK) && (flags & QF_GETLIST_TICK))
4985+
status = dict_add_nr_str(retdict, "changedtick", 0L, NULL);
49664986

49674987
return status;
49684988
}
@@ -5035,6 +5055,10 @@ qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
50355055
status = dict_add_nr_str(retdict, "size",
50365056
qi->qf_lists[qf_idx].qf_count, NULL);
50375057

5058+
if ((status == OK) && (flags & QF_GETLIST_TICK))
5059+
status = dict_add_nr_str(retdict, "changedtick",
5060+
qi->qf_lists[qf_idx].qf_changedtick, NULL);
5061+
50385062
return status;
50395063
}
50405064

@@ -5304,6 +5328,9 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title)
53045328
retval = OK;
53055329
}
53065330

5331+
if (retval == OK)
5332+
qf_list_changed(qi, qf_idx);
5333+
53075334
return retval;
53085335
}
53095336

@@ -5407,7 +5434,11 @@ set_errorlist(
54075434
else if (what != NULL)
54085435
retval = qf_set_properties(qi, what, action, title);
54095436
else
5437+
{
54105438
retval = qf_add_entries(qi, qi->qf_curlist, list, title, action);
5439+
if (retval == OK)
5440+
qf_list_changed(qi, qi->qf_curlist);
5441+
}
54115442

54125443
return retval;
54135444
}
@@ -5540,6 +5571,8 @@ ex_cbuffer(exarg_T *eap)
55405571
&& eap->cmdidx != CMD_laddbuffer),
55415572
eap->line1, eap->line2,
55425573
qf_title, NULL);
5574+
if (res >= 0)
5575+
qf_list_changed(qi, qi->qf_curlist);
55435576
#ifdef FEAT_AUTOCMD
55445577
if (au_name != NULL)
55455578
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
@@ -5609,6 +5642,8 @@ ex_cexpr(exarg_T *eap)
56095642
&& eap->cmdidx != CMD_laddexpr),
56105643
(linenr_T)0, (linenr_T)0, *eap->cmdlinep,
56115644
NULL);
5645+
if (res >= 0)
5646+
qf_list_changed(qi, qi->qf_curlist);
56125647
#ifdef FEAT_AUTOCMD
56135648
if (au_name != NULL)
56145649
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
@@ -5829,6 +5864,7 @@ ex_helpgrep(exarg_T *eap)
58295864
/* Darn, some plugin changed the value. */
58305865
free_string_option(save_cpo);
58315866

5867+
qf_list_changed(qi, qi->qf_curlist);
58325868
qf_update_buffer(qi, NULL);
58335869

58345870
#ifdef FEAT_AUTOCMD

src/testdir/test_quickfix.vim

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,6 +2132,8 @@ func Test_Autocmd()
21322132

21332133
call delete('Xtest')
21342134
call delete('Xempty')
2135+
au! QuickFixCmdPre
2136+
au! QuickFixCmdPost
21352137
endfunc
21362138

21372139
func Test_Autocmd_Exception()
@@ -2896,7 +2898,8 @@ func Xgetlist_empty_tests(cchar)
28962898
call assert_equal(0, g:Xgetlist({'size' : 0}).size)
28972899
call assert_equal('', g:Xgetlist({'title' : 0}).title)
28982900
call assert_equal(0, g:Xgetlist({'winid' : 0}).winid)
2899-
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0}, g:Xgetlist({'all' : 0}))
2901+
call assert_equal(0, g:Xgetlist({'changedtick' : 0}).changedtick)
2902+
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, 'changedtick': 0}, g:Xgetlist({'all' : 0}))
29002903

29012904
" Empty quickfix list
29022905
Xexpr ""
@@ -2908,6 +2911,7 @@ func Xgetlist_empty_tests(cchar)
29082911
call assert_equal(0, g:Xgetlist({'size' : 0}).size)
29092912
call assert_notequal('', g:Xgetlist({'title' : 0}).title)
29102913
call assert_equal(0, g:Xgetlist({'winid' : 0}).winid)
2914+
call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
29112915

29122916
let qfid = g:Xgetlist({'id' : 0}).id
29132917
call g:Xsetlist([], 'f')
@@ -2921,7 +2925,8 @@ func Xgetlist_empty_tests(cchar)
29212925
call assert_equal(0, g:Xgetlist({'id' : qfid, 'size' : 0}).size)
29222926
call assert_equal('', g:Xgetlist({'id' : qfid, 'title' : 0}).title)
29232927
call assert_equal(0, g:Xgetlist({'id' : qfid, 'winid' : 0}).winid)
2924-
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0}))
2928+
call assert_equal(0, g:Xgetlist({'id' : qfid, 'changedtick' : 0}).changedtick)
2929+
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, 'changedtick' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0}))
29252930

29262931
" Non-existing quickfix list number
29272932
call assert_equal('', g:Xgetlist({'nr' : 5, 'context' : 0}).context)
@@ -2932,10 +2937,69 @@ func Xgetlist_empty_tests(cchar)
29322937
call assert_equal(0, g:Xgetlist({'nr' : 5, 'size' : 0}).size)
29332938
call assert_equal('', g:Xgetlist({'nr' : 5, 'title' : 0}).title)
29342939
call assert_equal(0, g:Xgetlist({'nr' : 5, 'winid' : 0}).winid)
2935-
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0}, g:Xgetlist({'nr' : 5, 'all' : 0}))
2940+
call assert_equal(0, g:Xgetlist({'nr' : 5, 'changedtick' : 0}).changedtick)
2941+
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, 'changedtick' : 0}, g:Xgetlist({'nr' : 5, 'all' : 0}))
29362942
endfunc
29372943

29382944
func Test_getqflist()
29392945
call Xgetlist_empty_tests('c')
29402946
call Xgetlist_empty_tests('l')
29412947
endfunc
2948+
2949+
" Tests for the quickfix/location list changedtick
2950+
func Xqftick_tests(cchar)
2951+
call s:setup_commands(a:cchar)
2952+
2953+
call g:Xsetlist([], 'f')
2954+
2955+
Xexpr "F1:10:Line10"
2956+
let qfid = g:Xgetlist({'id' : 0}).id
2957+
call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
2958+
Xaddexpr "F2:20:Line20\nF2:21:Line21"
2959+
call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
2960+
call g:Xsetlist([], 'a', {'lines' : ["F3:30:Line30", "F3:31:Line31"]})
2961+
call assert_equal(3, g:Xgetlist({'changedtick' : 0}).changedtick)
2962+
call g:Xsetlist([], 'r', {'lines' : ["F4:40:Line40"]})
2963+
call assert_equal(4, g:Xgetlist({'changedtick' : 0}).changedtick)
2964+
call g:Xsetlist([], 'a', {'title' : 'New Title'})
2965+
call assert_equal(5, g:Xgetlist({'changedtick' : 0}).changedtick)
2966+
2967+
enew!
2968+
call append(0, ["F5:50:L50", "F6:60:L60"])
2969+
Xaddbuffer
2970+
call assert_equal(6, g:Xgetlist({'changedtick' : 0}).changedtick)
2971+
enew!
2972+
2973+
call g:Xsetlist([], 'a', {'context' : {'bus' : 'pci'}})
2974+
call assert_equal(7, g:Xgetlist({'changedtick' : 0}).changedtick)
2975+
call g:Xsetlist([{'filename' : 'F7', 'lnum' : 10, 'text' : 'L7'},
2976+
\ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], 'a')
2977+
call assert_equal(8, g:Xgetlist({'changedtick' : 0}).changedtick)
2978+
call g:Xsetlist([{'filename' : 'F7', 'lnum' : 10, 'text' : 'L7'},
2979+
\ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], ' ')
2980+
call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
2981+
call g:Xsetlist([{'filename' : 'F7', 'lnum' : 10, 'text' : 'L7'},
2982+
\ {'filename' : 'F7', 'lnum' : 11, 'text' : 'L11'}], 'r')
2983+
call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
2984+
2985+
call writefile(["F8:80:L80", "F8:81:L81"], "Xone")
2986+
Xfile Xone
2987+
call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
2988+
Xaddfile Xone
2989+
call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick)
2990+
2991+
" Test case for updating a non-current quickfix list
2992+
call g:Xsetlist([], 'f')
2993+
Xexpr "F1:1:L1"
2994+
Xexpr "F2:2:L2"
2995+
call g:Xsetlist([], 'a', {'nr' : 1, "lines" : ["F10:10:L10"]})
2996+
call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick)
2997+
call assert_equal(2, g:Xgetlist({'nr' : 1, 'changedtick' : 0}).changedtick)
2998+
2999+
call delete("Xone")
3000+
endfunc
3001+
3002+
func Test_qf_tick()
3003+
call Xqftick_tests('c')
3004+
call Xqftick_tests('l')
3005+
endfunc

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@ static char *(features[]) =
771771

772772
static int included_patches[] =
773773
{ /* Add new patch number below this line */
774+
/**/
775+
1406,
774776
/**/
775777
1405,
776778
/**/

0 commit comments

Comments
 (0)