Merge pull request #13083 from janlazo/vim-8.1.1281

vim-patch:8.1.{523,720,877,988,1015,1036},8.2.{1101,1820,1823,1829,1830,1831}
This commit is contained in:
Jan Edmund Lazo 2020-10-11 11:17:22 -04:00 committed by GitHub
commit b9776ff5b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 493 additions and 118 deletions

View File

@ -3170,7 +3170,7 @@ complete_info([{what}])
< <
*confirm()* *confirm()*
confirm({msg} [, {choices} [, {default} [, {type}]]]) confirm({msg} [, {choices} [, {default} [, {type}]]])
Confirm() offers the user a dialog, from which a choice can be confirm() offers the user a dialog, from which a choice can be
made. It returns the number of the choice. For the first made. It returns the number of the choice. For the first
choice this is 1. choice this is 1.
@ -3839,7 +3839,7 @@ feedkeys({string} [, {mode}]) *feedkeys()*
stuck, waiting for a character to be typed before the stuck, waiting for a character to be typed before the
script continues. script continues.
Note that if you manage to call feedkeys() while Note that if you manage to call feedkeys() while
executing commands, thus calling it recursively, the executing commands, thus calling it recursively, then
all typehead will be consumed by the last call. all typehead will be consumed by the last call.
'!' When used with 'x' will not end Insert mode. Can be '!' When used with 'x' will not end Insert mode. Can be
used in a test when a timer is set to exit Insert mode used in a test when a timer is set to exit Insert mode
@ -4639,10 +4639,16 @@ getloclist({nr},[, {what}]) *getloclist()*
If the optional {what} dictionary argument is supplied, then If the optional {what} dictionary argument is supplied, then
returns the items listed in {what} as a dictionary. Refer to returns the items listed in {what} as a dictionary. Refer to
|getqflist()| for the supported items in {what}. |getqflist()| for the supported items in {what}.
If {what} contains 'filewinid', then returns the id of the
window used to display files from the location list. This In addition to the items supported by |getqflist()| in {what},
field is applicable only when called from a location list the following item is supported by |getloclist()|:
window.
filewinid id of the window used to display files
from the location list. This field is
applicable only when called from a
location list window. See
|location-list-file-window| for more
details.
getmatches([{win}]) *getmatches()* getmatches([{win}]) *getmatches()*
Returns a |List| with all matches previously defined for the Returns a |List| with all matches previously defined for the
@ -4733,7 +4739,9 @@ getqflist([{what}]) *getqflist()*
id get information for the quickfix list with id get information for the quickfix list with
|quickfix-ID|; zero means the id for the |quickfix-ID|; zero means the id for the
current list or the list specified by "nr" current list or the list specified by "nr"
idx index of the current entry in the list idx index of the current entry in the quickfix
list specified by 'id' or 'nr'.
See |quickfix-index|
items quickfix list entries items quickfix list entries
lines parse a list of lines using 'efm' and return lines parse a list of lines using 'efm' and return
the resulting entries. Only a |List| type is the resulting entries. Only a |List| type is
@ -4742,6 +4750,9 @@ getqflist([{what}]) *getqflist()*
nr get information for this quickfix list; zero nr get information for this quickfix list; zero
means the current quickfix list and "$" means means the current quickfix list and "$" means
the last quickfix list the last quickfix list
qfbufnr number of the buffer displayed in the quickfix
window. Returns 0 if the quickfix buffer is
not present. See |quickfix-buffer|.
size number of entries in the quickfix list size number of entries in the quickfix list
title get the list title |quickfix-title| title get the list title |quickfix-title|
winid get the quickfix |window-ID| winid get the quickfix |window-ID|
@ -4770,6 +4781,8 @@ getqflist([{what}]) *getqflist()*
items quickfix list entries. If not present, set to items quickfix list entries. If not present, set to
an empty list. an empty list.
nr quickfix list number. If not present, set to 0 nr quickfix list number. If not present, set to 0
qfbufnr number of the buffer displayed in the quickfix
window. If not present, set to 0.
size number of entries in the quickfix list. If not size number of entries in the quickfix list. If not
present, set to 0. present, set to 0.
title quickfix list title text. If not present, set title quickfix list title text. If not present, set
@ -4926,6 +4939,19 @@ getwinpos([{timeout}]) *getwinpos()*
{timeout} can be used to specify how long to wait in msec for {timeout} can be used to specify how long to wait in msec for
a response from the terminal. When omitted 100 msec is used. a response from the terminal. When omitted 100 msec is used.
Use a longer time for a remote terminal.
When using a value less than 10 and no response is received
within that time, a previously reported position is returned,
if available. This can be used to poll for the position and
do some work in the meantime: >
while 1
let res = getwinpos(1)
if res[0] >= 0
break
endif
" Do some work here
endwhile
<
*getwinposx()* *getwinposx()*
getwinposx() The result is a Number, which is the X coordinate in pixels of getwinposx() The result is a Number, which is the X coordinate in pixels of
the left hand side of the GUI Vim window. The result will be the left hand side of the GUI Vim window. The result will be
@ -6263,6 +6289,7 @@ mode([expr]) Return a string that indicates the current mode.
nov Operator-pending (forced charwise |o_v|) nov Operator-pending (forced charwise |o_v|)
noV Operator-pending (forced linewise |o_V|) noV Operator-pending (forced linewise |o_V|)
noCTRL-V Operator-pending (forced blockwise |o_CTRL-V|) noCTRL-V Operator-pending (forced blockwise |o_CTRL-V|)
CTRL-V is one character
niI Normal using |i_CTRL-O| in |Insert-mode| niI Normal using |i_CTRL-O| in |Insert-mode|
niR Normal using |i_CTRL-O| in |Replace-mode| niR Normal using |i_CTRL-O| in |Replace-mode|
niV Normal using |i_CTRL-O| in |Virtual-Replace-mode| niV Normal using |i_CTRL-O| in |Virtual-Replace-mode|
@ -7622,16 +7649,22 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
efm errorformat to use when parsing text from efm errorformat to use when parsing text from
"lines". If this is not present, then the "lines". If this is not present, then the
'errorformat' option value is used. 'errorformat' option value is used.
See |quickfix-parse|
id quickfix list identifier |quickfix-ID| id quickfix list identifier |quickfix-ID|
idx index of the current entry in the quickfix
list specified by 'id' or 'nr'. If set to '$',
then the last entry in the list is set as the
current entry. See |quickfix-index|
items list of quickfix entries. Same as the {list} items list of quickfix entries. Same as the {list}
argument. argument.
lines use 'errorformat' to parse a list of lines and lines use 'errorformat' to parse a list of lines and
add the resulting entries to the quickfix list add the resulting entries to the quickfix list
{nr} or {id}. Only a |List| value is supported. {nr} or {id}. Only a |List| value is supported.
See |quickfix-parse|
nr list number in the quickfix stack; zero nr list number in the quickfix stack; zero
means the current quickfix list and "$" means means the current quickfix list and "$" means
the last quickfix list the last quickfix list.
title quickfix list title text title quickfix list title text. See |quickfix-title|
Unsupported keys in {what} are ignored. Unsupported keys in {what} are ignored.
If the "nr" item is not present, then the current quickfix list If the "nr" item is not present, then the current quickfix list
is modified. When creating a new quickfix list, "nr" can be is modified. When creating a new quickfix list, "nr" can be
@ -10356,14 +10389,14 @@ text...
commands are skipped. commands are skipped.
When {pattern} is omitted all errors are caught. When {pattern} is omitted all errors are caught.
Examples: > Examples: >
:catch /^Vim:Interrupt$/ " catch interrupts (CTRL-C) :catch /^Vim:Interrupt$/ " catch interrupts (CTRL-C)
:catch /^Vim\%((\a\+)\)\=:E/ " catch all Vim errors :catch /^Vim\%((\a\+)\)\=:E/ " catch all Vim errors
:catch /^Vim\%((\a\+)\)\=:/ " catch errors and interrupts :catch /^Vim\%((\a\+)\)\=:/ " catch errors and interrupts
:catch /^Vim(write):/ " catch all errors in :write :catch /^Vim(write):/ " catch all errors in :write
:catch /^Vim\%((\a\+)\)\=:E123/ " catch error E123 :catch /^Vim\%((\a\+)\)\=:E123:/ " catch error E123
:catch /my-exception/ " catch user exception :catch /my-exception/ " catch user exception
:catch /.*/ " catch everything :catch /.*/ " catch everything
:catch " same as /.*/ :catch " same as /.*/
< <
Another character can be used instead of / around the Another character can be used instead of / around the
{pattern}, so long as it does not have a special {pattern}, so long as it does not have a special

View File

@ -43,6 +43,7 @@ A location list is a window-local quickfix list. You get one after commands
like `:lvimgrep`, `:lgrep`, `:lhelpgrep`, `:lmake`, etc., which create a like `:lvimgrep`, `:lgrep`, `:lhelpgrep`, `:lmake`, etc., which create a
location list instead of a quickfix list as the corresponding `:vimgrep`, location list instead of a quickfix list as the corresponding `:vimgrep`,
`:grep`, `:helpgrep`, `:make` do. `:grep`, `:helpgrep`, `:make` do.
*location-list-file-window*
A location list is associated with a window and each window can have a A location list is associated with a window and each window can have a
separate location list. A location list can be associated with only one separate location list. A location list can be associated with only one
window. The location list is independent of the quickfix list. window. The location list is independent of the quickfix list.
@ -539,6 +540,7 @@ location list.
second quickfix window. If [height] is given the second quickfix window. If [height] is given the
existing window will be resized to it. existing window will be resized to it.
*quickfix-buffer*
The window will contain a special buffer, with The window will contain a special buffer, with
'buftype' equal to "quickfix". Don't change this! 'buftype' equal to "quickfix". Don't change this!
The window will have the w:quickfix_title variable set The window will have the w:quickfix_title variable set
@ -547,7 +549,11 @@ location list.
status line if the value of 'statusline' is adjusted status line if the value of 'statusline' is adjusted
properly. Whenever this buffer is modified by a properly. Whenever this buffer is modified by a
quickfix command or function, the |b:changedtick| quickfix command or function, the |b:changedtick|
variable is incremented. variable is incremented. You can get the number of
this buffer using the getqflist() and getloclist()
functions by passing the 'qfbufnr' item. For a
location list, this buffer is wiped out when the
location list is removed.
*:lop* *:lopen* *:lop* *:lopen*
:lop[en] [height] Open a window to show the location list for the :lop[en] [height] Open a window to show the location list for the
@ -713,11 +719,20 @@ using these functions are below:
" get the quickfix list window id " get the quickfix list window id
:echo getqflist({'winid' : 0}).winid :echo getqflist({'winid' : 0}).winid
" get the quickfix list window buffer number
:echo getqflist({'qfbufnr' : 0}).qfbufnr
" get the context of the current location list " get the context of the current location list
:echo getloclist(0, {'context' : 0}).context :echo getloclist(0, {'context' : 0}).context
" get the location list window id of the third window " get the location list window id of the third window
:echo getloclist(3, {'winid' : 0}).winid :echo getloclist(3, {'winid' : 0}).winid
" get the location list window buffer number of the third window
:echo getloclist(3, {'qfbufnr' : 0}).qfbufnr
" get the file window id of a location list window (winnr: 4)
:echo getloclist(4, {'filewinid' : 0}).filewinid
< <
*setqflist-examples* *setqflist-examples*
The |setqflist()| and |setloclist()| functions can be used to set the various The |setqflist()| and |setloclist()| functions can be used to set the various
@ -732,6 +747,9 @@ using these functions are below:
" set the title of the current quickfix list " set the title of the current quickfix list
:call setqflist([], 'a', {'title' : 'Mytitle'}) :call setqflist([], 'a', {'title' : 'Mytitle'})
" change the current entry in the list specified by an identifier
:call setqflist([], 'a', {'id' : qfid, 'idx' : 10})
" set the context of a quickfix list specified by an identifier " set the context of a quickfix list specified by an identifier
:call setqflist([], 'a', {'id' : qfid, 'context' : {'val' : 100}}) :call setqflist([], 'a', {'id' : qfid, 'context' : {'val' : 100}})

View File

@ -5397,18 +5397,12 @@ bool buf_hide(const buf_T *const buf)
char_u *buf_spname(buf_T *buf) char_u *buf_spname(buf_T *buf)
{ {
if (bt_quickfix(buf)) { if (bt_quickfix(buf)) {
win_T *win; // Differentiate between the quickfix and location list buffers using
tabpage_T *tp; // the buffer number stored in the global quickfix stack.
if (buf->b_fnum == qf_stack_get_bufnr()) {
/*
* For location list window, w_llist_ref points to the location list.
* For quickfix window, w_llist_ref is NULL.
*/
if (find_win_for_buf(buf, &win, &tp) && win->w_llist_ref != NULL) {
return (char_u *)_(msg_loclist);
} else {
return (char_u *)_(msg_qflist); return (char_u *)_(msg_qflist);
} }
return (char_u *)_(msg_loclist);
} }
// There is no _file_ when 'buftype' is "nofile", b_sfname // There is no _file_ when 'buftype' is "nofile", b_sfname
// contains the name as specified by the user. // contains the name as specified by the user.

View File

@ -73,6 +73,7 @@ struct qfline_S {
// There is a stack of error lists. // There is a stack of error lists.
#define LISTCOUNT 10 #define LISTCOUNT 10
#define INVALID_QFIDX (-1) #define INVALID_QFIDX (-1)
#define INVALID_QFBUFNR (0)
/// Quickfix list type. /// Quickfix list type.
typedef enum typedef enum
@ -123,6 +124,7 @@ struct qf_info_S {
int qf_curlist; // current error list int qf_curlist; // current error list
qf_list_T qf_lists[LISTCOUNT]; qf_list_T qf_lists[LISTCOUNT];
qfltype_T qfl_type; // type of list qfltype_T qfl_type; // type of list
int qf_bufnr; // quickfix window buffer number
}; };
static qf_info_T ql_info; // global quickfix list static qf_info_T ql_info; // global quickfix list
@ -1092,6 +1094,7 @@ qf_init_ext(
) )
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(1)
{ {
qf_list_T *qfl;
qfstate_T state = { 0 }; qfstate_T state = { 0 };
qffields_T fields = { 0 }; qffields_T fields = { 0 };
qfline_T *old_last = NULL; qfline_T *old_last = NULL;
@ -1115,15 +1118,16 @@ qf_init_ext(
// make place for a new list // make place for a new list
qf_new_list(qi, qf_title); qf_new_list(qi, qf_title);
qf_idx = qi->qf_curlist; qf_idx = qi->qf_curlist;
qfl = qf_get_list(qi, qf_idx);
} else { } else {
// Adding to existing list, use last entry. // Adding to existing list, use last entry.
adding = true; adding = true;
if (!qf_list_empty(qf_get_list(qi, qf_idx) )) { qfl = qf_get_list(qi, qf_idx);
old_last = qi->qf_lists[qf_idx].qf_last; if (!qf_list_empty(qfl)) {
old_last = qfl->qf_last;
} }
} }
qf_list_T *qfl = qf_get_list(qi, qf_idx);
// Use the local value of 'errorformat' if it's set. // Use the local value of 'errorformat' if it's set.
if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) { if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) {
@ -1694,6 +1698,28 @@ static void locstack_queue_delreq(qf_info_T *qi)
qf_delq_head = q; qf_delq_head = q;
} }
// Return the global quickfix stack window buffer number.
int qf_stack_get_bufnr(void)
{
return ql_info.qf_bufnr;
}
// Wipe the quickfix window buffer (if present) for the specified
// quickfix/location list.
static void wipe_qf_buffer(qf_info_T *qi)
FUNC_ATTR_NONNULL_ALL
{
if (qi->qf_bufnr != INVALID_QFBUFNR) {
buf_T *const qfbuf = buflist_findnr(qi->qf_bufnr);
if (qfbuf != NULL && qfbuf->b_nwindows == 0) {
// If the quickfix buffer is not loaded in any window, then
// wipe the buffer.
close_buffer(NULL, qfbuf, DOBUF_WIPE, false);
qi->qf_bufnr = INVALID_QFBUFNR;
}
}
}
/// Free a location list stack /// Free a location list stack
static void ll_free_all(qf_info_T **pqi) static void ll_free_all(qf_info_T **pqi)
{ {
@ -1713,6 +1739,9 @@ static void ll_free_all(qf_info_T **pqi)
if (quickfix_busy > 0) { if (quickfix_busy > 0) {
locstack_queue_delreq(qi); locstack_queue_delreq(qi);
} else { } else {
// If the quickfix window buffer is loaded, then wipe it
wipe_qf_buffer(qi);
for (i = 0; i < qi->qf_listcount; i++) { for (i = 0; i < qi->qf_listcount; i++) {
qf_free(qf_get_list(qi, i)); qf_free(qf_get_list(qi, i));
} }
@ -1872,6 +1901,7 @@ static qf_info_T *qf_alloc_stack(qfltype_T qfltype)
qf_info_T *qi = xcalloc(1, sizeof(qf_info_T)); qf_info_T *qi = xcalloc(1, sizeof(qf_info_T));
qi->qf_refcount++; qi->qf_refcount++;
qi->qfl_type = qfltype; qi->qfl_type = qfltype;
qi->qf_bufnr = INVALID_QFBUFNR;
return qi; return qi;
} }
@ -2453,12 +2483,13 @@ static void win_set_loclist(win_T *wp, qf_info_T *qi)
qi->qf_refcount++; qi->qf_refcount++;
} }
/// Find a help window or open one. /// Find a help window or open one. If 'newwin' is true, then open a new help
static int jump_to_help_window(qf_info_T *qi, int *opened_window) /// window.
static int jump_to_help_window(qf_info_T *qi, bool newwin, int *opened_window)
{ {
win_T *wp = NULL; win_T *wp = NULL;
if (cmdmod.tab != 0) { if (cmdmod.tab != 0 || newwin) {
wp = NULL; wp = NULL;
} else { } else {
wp = qf_find_help_win(); wp = qf_find_help_win();
@ -2476,8 +2507,10 @@ static int jump_to_help_window(qf_info_T *qi, int *opened_window)
flags |= WSP_TOP; flags |= WSP_TOP;
} }
if (IS_LL_STACK(qi)) { // If the user asks to open a new window, then copy the location list.
flags |= WSP_NEWLOC; // don't copy the location list // Otherwise, don't copy the location list.
if (IS_LL_STACK(qi) && !newwin) {
flags |= WSP_NEWLOC;
} }
if (win_split(0, flags) == FAIL) { if (win_split(0, flags) == FAIL) {
@ -2490,8 +2523,10 @@ static int jump_to_help_window(qf_info_T *qi, int *opened_window)
win_setheight((int)p_hh); win_setheight((int)p_hh);
} }
if (IS_LL_STACK(qi)) { // not a quickfix list // When using location list, the new window should use the supplied
// The new window should use the supplied location list // location list. If the user asks to open a new window, then the new
// window will get a copy of the location list.
if (IS_LL_STACK(qi) && !newwin) {
win_set_loclist(curwin, qi); win_set_loclist(curwin, qi);
} }
} }
@ -2503,7 +2538,8 @@ static int jump_to_help_window(qf_info_T *qi, int *opened_window)
return OK; return OK;
} }
// Find a non-quickfix window using the given location list. // Find a non-quickfix window in the current tabpage using the given location
// list stack.
// Returns NULL if a matching window is not found. // Returns NULL if a matching window is not found.
static win_T *qf_find_win_with_loclist(const qf_info_T *ll) static win_T *qf_find_win_with_loclist(const qf_info_T *ll)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
@ -2652,14 +2688,19 @@ static void qf_goto_win_with_qfl_file(int qf_fnum)
// Find a suitable window for opening a file (qf_fnum) from the // Find a suitable window for opening a file (qf_fnum) from the
// quickfix/location list and jump to it. If the file is already opened in a // quickfix/location list and jump to it. If the file is already opened in a
// window, jump to it. Otherwise open a new window to display the file. This is // window, jump to it. Otherwise open a new window to display the file. If
// called from either a quickfix or a location list window. // 'newwin' is true, then always open a new window. This is called from either
static int qf_jump_to_usable_window(int qf_fnum, int *opened_window) // a quickfix or a location list window.
static int qf_jump_to_usable_window(int qf_fnum, bool newwin,
int *opened_window)
{ {
win_T *usable_win_ptr = NULL; win_T *usable_win_ptr = NULL;
bool usable_win = false; bool usable_win = false;
qf_info_T *ll_ref = curwin->w_llist_ref; // If opening a new window, then don't use the location list referred by
// the current window. Otherwise two windows will refer to the same
// location list.
qf_info_T *ll_ref = newwin ? NULL : curwin->w_llist_ref;
if (ll_ref != NULL) { if (ll_ref != NULL) {
// Find a non-quickfix window with this location list // Find a non-quickfix window with this location list
usable_win_ptr = qf_find_win_with_loclist(ll_ref); usable_win_ptr = qf_find_win_with_loclist(ll_ref);
@ -2684,7 +2725,7 @@ static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
// If there is only one window and it is the quickfix window, create a // If there is only one window and it is the quickfix window, create a
// new one above the quickfix window. // new one above the quickfix window.
if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win) { if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win || newwin) {
if (qf_open_new_file_win(ll_ref) != OK) { if (qf_open_new_file_win(ll_ref) != OK) {
return FAIL; return FAIL;
} }
@ -2823,11 +2864,12 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
} }
/// Find a usable window for opening a file from the quickfix/location list. If /// Find a usable window for opening a file from the quickfix/location list. If
/// a window is not found then open a new window. /// a window is not found then open a new window. If 'newwin' is true, then open
/// a new window.
/// Returns OK if successfully jumped or opened a window. Returns FAIL if not /// Returns OK if successfully jumped or opened a window. Returns FAIL if not
/// able to jump/open a window. Returns NOTDONE if a file is not associated /// able to jump/open a window. Returns NOTDONE if a file is not associated
/// with the entry. /// with the entry.
static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin,
int *opened_window) int *opened_window)
{ {
qf_list_T *qfl = qf_get_curlist(qi); qf_list_T *qfl = qf_get_curlist(qi);
@ -2837,7 +2879,7 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr,
// For ":helpgrep" find a help window or open one. // For ":helpgrep" find a help window or open one.
if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) { if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) {
if (jump_to_help_window(qi, opened_window) == FAIL) { if (jump_to_help_window(qi, newwin, opened_window) == FAIL) {
return FAIL; return FAIL;
} }
} }
@ -2861,7 +2903,8 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr,
return NOTDONE; return NOTDONE;
} }
if (qf_jump_to_usable_window(qf_ptr->qf_fnum, opened_window) == FAIL) { if (qf_jump_to_usable_window(qf_ptr->qf_fnum, newwin, opened_window)
== FAIL) {
return FAIL; return FAIL;
} }
} }
@ -2924,14 +2967,23 @@ static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
return retval; return retval;
} }
/// jump to a quickfix ltne /// Jump to a quickfix line and try to use an existing window.
/// if dir == FORWARD go "errornr" valid entries forward
/// if dir == BACKWARD go "errornr" valid entries backward
/// if dir == FORWARD_FILE go "errornr" valid entries files backward
/// if dir == BACKWARD_FILE go "errornr" valid entries files backward
/// else if "errornr" is zero, redisplay the same line
/// else go to entry "errornr"
void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit) void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
{
qf_jump_newwin(qi, dir, errornr, forceit, false);
}
// Jump to a quickfix line.
// If dir == 0 go to entry "errornr".
// If dir == FORWARD go "errornr" valid entries forward.
// If dir == BACKWARD go "errornr" valid entries backward.
// If dir == FORWARD_FILE go "errornr" valid entries files backward.
// If dir == BACKWARD_FILE go "errornr" valid entries files backward
// else if "errornr" is zero, redisplay the same line
// If 'forceit' is true, then can discard changes to the current buffer.
// If 'newwin' is true, then open the file in a new window.
static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit,
bool newwin)
{ {
qf_list_T *qfl; qf_list_T *qfl;
qfline_T *qf_ptr; qfline_T *qf_ptr;
@ -2975,7 +3027,7 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
print_message = false; print_message = false;
} }
retval = qf_jump_open_window(qi, qf_ptr, &opened_window); retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
if (retval == FAIL) { if (retval == FAIL) {
goto failed; goto failed;
} }
@ -3277,7 +3329,7 @@ void qf_history(exarg_T *eap)
qf_info_T *qi = qf_cmd_get_stack(eap, false); qf_info_T *qi = qf_cmd_get_stack(eap, false);
int i; int i;
if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi))) { if (qf_stack_empty(qi)) {
MSG(_("No entries")); MSG(_("No entries"));
} else { } else {
for (i = 0; i < qi->qf_listcount; i++) { for (i = 0; i < qi->qf_listcount; i++) {
@ -3445,14 +3497,9 @@ void qf_view_result(bool split)
} }
if (split) { if (split) {
char cmd[32]; // Open the selected entry in a new window
qf_jump_newwin(qi, 0, (int)curwin->w_cursor.lnum, false, true);
snprintf(cmd, sizeof(cmd), "split +%" PRId64 "%s", do_cmdline_cmd("clearjumps");
(int64_t)curwin->w_cursor.lnum,
IS_LL_WINDOW(curwin) ? "ll" : "cc");
if (do_cmdline_cmd(cmd) == OK) {
do_cmdline_cmd("clearjumps");
}
return; return;
} }
@ -3483,7 +3530,7 @@ void ex_cwindow(exarg_T *eap)
// it if we have errors; otherwise, leave it closed. // it if we have errors; otherwise, leave it closed.
if (qf_stack_empty(qi) if (qf_stack_empty(qi)
|| qfl->qf_nonevalid || qfl->qf_nonevalid
|| qf_list_empty(qf_get_curlist(qi))) { || qf_list_empty(qfl)) {
if (win != NULL) { if (win != NULL) {
ex_cclose(eap); ex_cclose(eap);
} }
@ -3536,10 +3583,23 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz,
return OK; return OK;
} }
// Set options for the buffer in the quickfix or location list window.
static void qf_set_cwindow_options(void)
{
// switch off 'swapfile'
set_option_value("swf", 0L, NULL, OPT_LOCAL);
set_option_value("bt", 0L, "quickfix", OPT_LOCAL);
set_option_value("bh", 0L, "hide", OPT_LOCAL);
RESET_BINDING(curwin);
curwin->w_p_diff = false;
set_option_value("fdm", 0L, "manual", OPT_LOCAL);
}
// Open a new quickfix or location list window, load the quickfix buffer and // Open a new quickfix or location list window, load the quickfix buffer and
// set the appropriate options for the window. // set the appropriate options for the window.
// Returns FAIL if the window could not be opened. // Returns FAIL if the window could not be opened.
static int qf_open_new_cwindow(const qf_info_T *qi, int height) static int qf_open_new_cwindow(qf_info_T *qi, int height)
FUNC_ATTR_NONNULL_ALL
{ {
win_T *oldwin = curwin; win_T *oldwin = curwin;
const tabpage_T *const prevtab = curtab; const tabpage_T *const prevtab = curtab;
@ -3583,13 +3643,15 @@ static int qf_open_new_cwindow(const qf_info_T *qi, int height)
// Create a new quickfix buffer // Create a new quickfix buffer
(void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin); (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin);
// switch off 'swapfile' // save the number of the new buffer
set_option_value("swf", 0L, NULL, OPT_LOCAL); qi->qf_bufnr = curbuf->b_fnum;
set_option_value("bt", 0L, "quickfix", OPT_LOCAL); }
set_option_value("bh", 0L, "wipe", OPT_LOCAL);
RESET_BINDING(curwin); // Set the options for the quickfix buffer/window (if not already done)
curwin->w_p_diff = false; // Do this even if the quickfix buffer was already present, as an autocmd
set_option_value("fdm", 0L, "manual", OPT_LOCAL); // might have previously deleted (:bdelete) the quickfix buffer.
if (curbuf->b_p_bt[0] != 'q') {
qf_set_cwindow_options();
} }
// Only set the height when still in the same tab page and there is no // Only set the height when still in the same tab page and there is no
@ -3778,9 +3840,18 @@ static win_T *qf_find_win(const qf_info_T *qi)
// Find a quickfix buffer. // Find a quickfix buffer.
// Searches in windows opened in all the tabs. // Searches in windows opened in all the tabs.
static buf_T *qf_find_buf(const qf_info_T *qi) static buf_T *qf_find_buf(qf_info_T *qi)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{ {
if (qi->qf_bufnr != INVALID_QFBUFNR) {
buf_T *const qfbuf = buflist_findnr(qi->qf_bufnr);
if (qfbuf != NULL) {
return qfbuf;
}
// buffer is no longer present
qi->qf_bufnr = INVALID_QFBUFNR;
}
FOR_ALL_TAB_WINDOWS(tp, win) { FOR_ALL_TAB_WINDOWS(tp, win) {
if (is_qf_win(win, qi)) { if (is_qf_win(win, qi)) {
return win->w_buffer; return win->w_buffer;
@ -4922,7 +4993,7 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid,
/// Search for a pattern in all the lines in a buffer and add the matching lines /// Search for a pattern in all the lines in a buffer and add the matching lines
/// to a quickfix list. /// to a quickfix list.
static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf, static bool vgr_match_buflines(qf_list_T *qfl, char_u *fname, buf_T *buf,
regmmatch_T *regmatch, long *tomatch, regmmatch_T *regmatch, long *tomatch,
int duplicate_name, int flags) int duplicate_name, int flags)
FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5) FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5)
@ -4936,7 +5007,7 @@ static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf,
// Pass the buffer number so that it gets used even for a // Pass the buffer number so that it gets used even for a
// dummy buffer, unless duplicate_name is set, then the // dummy buffer, unless duplicate_name is set, then the
// buffer will be wiped out below. // buffer will be wiped out below.
if (qf_add_entry(qf_get_curlist(qi), if (qf_add_entry(qfl,
NULL, // dir NULL, // dir
fname, fname,
NULL, NULL,
@ -5129,7 +5200,8 @@ void ex_vimgrep(exarg_T *eap)
} else { } else {
// Try for a match in all lines of the buffer. // Try for a match in all lines of the buffer.
// For ":1vimgrep" look for first match only. // For ":1vimgrep" look for first match only.
found_match = vgr_match_buflines(qi, fname, buf, &regmatch, &tomatch, found_match = vgr_match_buflines(qf_get_curlist(qi),
fname, buf, &regmatch, &tomatch,
duplicate_name, flags); duplicate_name, flags);
if (using_dummy) { if (using_dummy) {
@ -5508,7 +5580,8 @@ enum {
QF_GETLIST_SIZE = 0x80, QF_GETLIST_SIZE = 0x80,
QF_GETLIST_TICK = 0x100, QF_GETLIST_TICK = 0x100,
QF_GETLIST_FILEWINID = 0x200, QF_GETLIST_FILEWINID = 0x200,
QF_GETLIST_ALL = 0x3FF, QF_GETLIST_QFBUFNR = 0x400,
QF_GETLIST_ALL = 0x7FF,
}; };
/// Parse text from 'di' and return the quickfix list items. /// Parse text from 'di' and return the quickfix list items.
@ -5563,6 +5636,15 @@ static int qf_winid(qf_info_T *qi)
return 0; return 0;
} }
// Returns the number of the buffer displayed in the quickfix/location list
// window. If there is no buffer associated with the list, then returns 0.
static int qf_getprop_qfbufnr(const qf_info_T *qi, dict_T *retdict)
FUNC_ATTR_NONNULL_ARG(2)
{
return tv_dict_add_nr(retdict, S_LEN("qfbufnr"),
(qi == NULL) ? 0 : qi->qf_bufnr);
}
/// Convert the keys in 'what' to quickfix list property flags. /// Convert the keys in 'what' to quickfix list property flags.
static int qf_getprop_keys2flags(const dict_T *what, bool loclist) static int qf_getprop_keys2flags(const dict_T *what, bool loclist)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
@ -5606,6 +5688,9 @@ static int qf_getprop_keys2flags(const dict_T *what, bool loclist)
if (loclist && tv_dict_find(what, S_LEN("filewinid")) != NULL) { if (loclist && tv_dict_find(what, S_LEN("filewinid")) != NULL) {
flags |= QF_GETLIST_FILEWINID; flags |= QF_GETLIST_FILEWINID;
} }
if (tv_dict_find(what, S_LEN("qfbufnr")) != NULL) {
flags |= QF_GETLIST_QFBUFNR;
}
return flags; return flags;
} }
@ -5697,6 +5782,9 @@ static int qf_getprop_defaults(qf_info_T *qi,
if ((status == OK) && locstack && (flags & QF_GETLIST_FILEWINID)) { if ((status == OK) && locstack && (flags & QF_GETLIST_FILEWINID)) {
status = tv_dict_add_nr(retdict, S_LEN("filewinid"), 0); status = tv_dict_add_nr(retdict, S_LEN("filewinid"), 0);
} }
if ((status == OK) && (flags & QF_GETLIST_QFBUFNR)) {
status = qf_getprop_qfbufnr(qi, retdict);
}
return status; return status;
} }
@ -5831,6 +5919,9 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
if ((status == OK) && (wp != NULL) && (flags & QF_GETLIST_FILEWINID)) { if ((status == OK) && (wp != NULL) && (flags & QF_GETLIST_FILEWINID)) {
status = qf_getprop_filewinid(wp, qi, retdict); status = qf_getprop_filewinid(wp, qi, retdict);
} }
if ((status == OK) && (flags & QF_GETLIST_QFBUFNR)) {
status = qf_getprop_qfbufnr(qi, retdict);
}
return status; return status;
} }
@ -6119,6 +6210,49 @@ static int qf_setprop_context(qf_list_T *qfl, dictitem_T *di)
return OK; return OK;
} }
// Set the current index in the specified quickfix list
static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl,
const dictitem_T *di)
FUNC_ATTR_NONNULL_ALL
{
int newidx;
// If the specified index is '$', then use the last entry
if (di->di_tv.v_type == VAR_STRING
&& di->di_tv.vval.v_string != NULL
&& STRCMP(di->di_tv.vval.v_string, "$") == 0) {
newidx = qfl->qf_count;
} else {
// Otherwise use the specified index
bool denote = false;
newidx = (int)tv_get_number_chk(&di->di_tv, &denote);
if (denote) {
return FAIL;
}
}
if (newidx < 1) { // sanity check
return FAIL;
}
if (newidx > qfl->qf_count) {
newidx = qfl->qf_count;
}
const int old_qfidx = qfl->qf_index;
qfline_T *const qf_ptr = get_nth_entry(qfl, newidx, &newidx);
if (qf_ptr == NULL) {
return FAIL;
}
qfl->qf_ptr = qf_ptr;
qfl->qf_index = newidx;
// If the current list is modified and it is displayed in the quickfix
// window, then Update it.
if (qi->qf_lists[qi->qf_curlist].qf_id == qfl->qf_id) {
qf_win_pos_update(qi, old_qfidx);
}
return OK;
}
/// Set quickfix/location list properties (title, items, context). /// Set quickfix/location list properties (title, items, context).
/// Also used to add items from parsing a list of lines. /// Also used to add items from parsing a list of lines.
/// Used by the setqflist() and setloclist() Vim script functions. /// Used by the setqflist() and setloclist() Vim script functions.
@ -6154,6 +6288,9 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) { if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) {
retval = qf_setprop_context(qfl, di); retval = qf_setprop_context(qfl, di);
} }
if ((di = tv_dict_find(what, S_LEN("idx"))) != NULL) {
retval = qf_setprop_curidx(qi, qfl, di);
}
if (retval == OK) { if (retval == OK) {
qf_list_changed(qfl); qf_list_changed(qfl);
@ -6162,19 +6299,6 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
return retval; return retval;
} }
/// Find the non-location list window with the specified location list stack in
/// the current tabpage.
static win_T * find_win_with_ll(qf_info_T *qi)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if ((wp->w_llist == qi) && !bt_quickfix(wp->w_buffer)) {
return wp;
}
}
return NULL;
}
// Free the entire quickfix/location list stack. // Free the entire quickfix/location list stack.
// If the quickfix/location list window is open, then clear it. // If the quickfix/location list window is open, then clear it.
static void qf_free_stack(win_T *wp, qf_info_T *qi) static void qf_free_stack(win_T *wp, qf_info_T *qi)
@ -6189,12 +6313,10 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi)
qf_update_buffer(qi, NULL); qf_update_buffer(qi, NULL);
} }
win_T *llwin = NULL;
win_T *orig_wp = wp;
if (wp != NULL && IS_LL_WINDOW(wp)) { if (wp != NULL && IS_LL_WINDOW(wp)) {
// If in the location list window, then use the non-location list // If in the location list window, then use the non-location list
// window with this location list (if present) // window with this location list (if present)
llwin = find_win_with_ll(qi); win_T *const llwin = qf_find_win_with_loclist(qi);
if (llwin != NULL) { if (llwin != NULL) {
wp = llwin; wp = llwin;
} }
@ -6205,16 +6327,17 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi)
// quickfix list // quickfix list
qi->qf_curlist = 0; qi->qf_curlist = 0;
qi->qf_listcount = 0; qi->qf_listcount = 0;
} else if (IS_LL_WINDOW(orig_wp)) { } else if (qfwin != NULL) {
// If the location list window is open, then create a new empty location // If the location list window is open, then create a new empty location
// list // list
qf_info_T *new_ll = qf_alloc_stack(QFLT_LOCATION); qf_info_T *new_ll = qf_alloc_stack(QFLT_LOCATION);
new_ll->qf_bufnr = qfwin->w_buffer->b_fnum;
// first free the list reference in the location list window // first free the list reference in the location list window
ll_free_all(&orig_wp->w_llist_ref); ll_free_all(&qfwin->w_llist_ref);
orig_wp->w_llist_ref = new_ll; qfwin->w_llist_ref = new_ll;
if (llwin != NULL) { if (wp != qfwin) {
win_set_loclist(wp, new_ll); win_set_loclist(wp, new_ll);
} }
} }
@ -6239,6 +6362,12 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
return OK; return OK;
} }
// A dict argument cannot be specified with a non-empty list argument
if (list != NULL && tv_list_len(list) != 0 && what != NULL) {
EMSG2(_(e_invarg2), _("cannot have both a list and a \"what\" argument"));
return FAIL;
}
incr_quickfix_busy(); incr_quickfix_busy();
if (what != NULL) { if (what != NULL) {
@ -6538,7 +6667,7 @@ static qf_info_T *hgr_get_ll(bool *new_ll)
// Search for a pattern in a help file. // Search for a pattern in a help file.
static void hgr_search_file( static void hgr_search_file(
qf_info_T *qi, qf_list_T *qfl,
char_u *fname, char_u *fname,
regmatch_T *p_regmatch) regmatch_T *p_regmatch)
FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_NONNULL_ARG(1, 3)
@ -6560,7 +6689,7 @@ static void hgr_search_file(
line[--l] = NUL; line[--l] = NUL;
} }
if (qf_add_entry(qf_get_curlist(qi), if (qf_add_entry(qfl,
NULL, // dir NULL, // dir
fname, fname,
NULL, NULL,
@ -6593,7 +6722,7 @@ static void hgr_search_file(
// Search for a pattern in all the help files in the doc directory under // Search for a pattern in all the help files in the doc directory under
// the given directory. // the given directory.
static void hgr_search_files_in_dir( static void hgr_search_files_in_dir(
qf_info_T *qi, qf_list_T *qfl,
char_u *dirname, char_u *dirname,
regmatch_T *p_regmatch, regmatch_T *p_regmatch,
const char_u *lang) const char_u *lang)
@ -6618,7 +6747,7 @@ static void hgr_search_files_in_dir(
continue; continue;
} }
hgr_search_file(qi, fnames[fi], p_regmatch); hgr_search_file(qfl, fnames[fi], p_regmatch);
} }
FreeWild(fcount, fnames); FreeWild(fcount, fnames);
} }
@ -6628,7 +6757,7 @@ static void hgr_search_files_in_dir(
// and add the matches to a quickfix list. // and add the matches to a quickfix list.
// 'lang' is the language specifier. If supplied, then only matches in the // 'lang' is the language specifier. If supplied, then only matches in the
// specified language are found. // specified language are found.
static void hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch, static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch,
const char_u *lang) const char_u *lang)
FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_NONNULL_ARG(1, 2)
{ {
@ -6637,7 +6766,7 @@ static void hgr_search_in_rtp(qf_info_T *qi, regmatch_T *p_regmatch,
while (*p != NUL && !got_int) { while (*p != NUL && !got_int) {
copy_option_part(&p, NameBuff, MAXPATHL, ","); copy_option_part(&p, NameBuff, MAXPATHL, ",");
hgr_search_files_in_dir(qi, NameBuff, p_regmatch, lang); hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, lang);
} }
} }
@ -6679,12 +6808,12 @@ void ex_helpgrep(exarg_T *eap)
if (regmatch.regprog != NULL) { if (regmatch.regprog != NULL) {
// Create a new quickfix list. // Create a new quickfix list.
qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep)); qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep));
qf_list_T *const qfl = qf_get_curlist(qi);
hgr_search_in_rtp(qi, &regmatch, lang); hgr_search_in_rtp(qfl, &regmatch, lang);
vim_regfree(regmatch.regprog); vim_regfree(regmatch.regprog);
qf_list_T *qfl = qf_get_curlist(qi);
qfl->qf_nonevalid = false; qfl->qf_nonevalid = false;
qfl->qf_ptr = qfl->qf_start; qfl->qf_ptr = qfl->qf_start;
qfl->qf_index = 1; qfl->qf_index = 1;

View File

@ -4186,7 +4186,7 @@ current_search(
curwin->w_cursor = end_pos; curwin->w_cursor = end_pos;
if (lt(VIsual, end_pos) && forward) { if (lt(VIsual, end_pos) && forward) {
dec_cursor(); dec_cursor();
} else if (VIsual_active && lt(curwin->w_cursor, VIsual)) { } else if (VIsual_active && lt(curwin->w_cursor, VIsual) && forward) {
curwin->w_cursor = pos; // put the cursor on the start of the match curwin->w_cursor = pos; // put the cursor on the start of the match
} }
VIsual_active = true; VIsual_active = true;

View File

@ -158,7 +158,16 @@ func Test_gn_command()
set wrapscan&vim set wrapscan&vim
set belloff&vim set belloff&vim
endfu endfunc
func Test_gN_repeat()
new
call setline(1, 'this list is a list with a list of a list.')
/list
normal $gNgNgNx
call assert_equal('list with a list of a list', @")
bwipe!
endfunc
func Test_gn_multi_line() func Test_gn_multi_line()
new new

View File

@ -1916,6 +1916,13 @@ func HistoryTest(cchar)
call g:Xsetlist([], 'f') call g:Xsetlist([], 'f')
let l = split(execute(a:cchar . 'hist'), "\n") let l = split(execute(a:cchar . 'hist'), "\n")
call assert_equal('No entries', l[0]) call assert_equal('No entries', l[0])
" An empty list should still show the stack history
call g:Xsetlist([])
let res = split(execute(a:cchar . 'hist'), "\n")
call assert_equal('> error list 1 of 1; 0 ' . common, res[0])
call g:Xsetlist([], 'f')
endfunc endfunc
func Test_history() func Test_history()
@ -2166,6 +2173,9 @@ func Xproperty_tests(cchar)
call assert_equal(['Colors'], newl2.context) call assert_equal(['Colors'], newl2.context)
call assert_equal('Line10', newl2.items[0].text) call assert_equal('Line10', newl2.items[0].text)
call g:Xsetlist([], 'f') call g:Xsetlist([], 'f')
" Cannot specify both a non-empty list argument and a dict argument
call assert_fails("call g:Xsetlist([{}], ' ', {})", 'E475:')
endfunc endfunc
func Test_qf_property() func Test_qf_property()
@ -2173,6 +2183,56 @@ func Test_qf_property()
call Xproperty_tests('l') call Xproperty_tests('l')
endfunc endfunc
" Test for setting the current index in the location/quickfix list
func Xtest_setqfidx(cchar)
call s:setup_commands(a:cchar)
Xgetexpr "F1:10:1:Line1\nF2:20:2:Line2\nF3:30:3:Line3"
Xgetexpr "F4:10:1:Line1\nF5:20:2:Line2\nF6:30:3:Line3"
Xgetexpr "F7:10:1:Line1\nF8:20:2:Line2\nF9:30:3:Line3"
call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 2})
call g:Xsetlist([], 'a', {'nr' : 2, 'idx' : 2})
call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 3})
Xolder 2
Xopen
call assert_equal(3, line('.'))
Xnewer
call assert_equal(2, line('.'))
Xnewer
call assert_equal(2, line('.'))
" Update the current index with the quickfix window open
wincmd w
call g:Xsetlist([], 'a', {'nr' : 3, 'idx' : 3})
Xopen
call assert_equal(3, line('.'))
Xclose
" Set the current index to the last entry
call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : '$'})
call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
" A large value should set the index to the last index
call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 1})
call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 999})
call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
" Invalid index values
call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : -1})
call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 0})
call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
call g:Xsetlist([], 'a', {'nr' : 1, 'idx' : 'xx'})
call assert_equal(3, g:Xgetlist({'nr' : 1, 'idx' : 0}).idx)
call assert_fails("call g:Xsetlist([], 'a', {'nr':1, 'idx':[]})", 'E745:')
call g:Xsetlist([], 'f')
new | only
endfunc
func Test_setqfidx()
call Xtest_setqfidx('c')
call Xtest_setqfidx('l')
endfunc
" Tests for the QuickFixCmdPre/QuickFixCmdPost autocommands " Tests for the QuickFixCmdPre/QuickFixCmdPost autocommands
func QfAutoCmdHandler(loc, cmd) func QfAutoCmdHandler(loc, cmd)
call add(g:acmds, a:loc . a:cmd) call add(g:acmds, a:loc . a:cmd)
@ -3160,19 +3220,21 @@ func Xgetlist_empty_tests(cchar)
call assert_equal(0, g:Xgetlist({'changedtick' : 0}).changedtick) call assert_equal(0, g:Xgetlist({'changedtick' : 0}).changedtick)
if a:cchar == 'c' if a:cchar == 'c'
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
\ 'items' : [], 'nr' : 0, 'size' : 0, \ 'items' : [], 'nr' : 0, 'size' : 0, 'qfbufnr' : 0,
\ 'title' : '', 'winid' : 0, 'changedtick': 0}, \ 'title' : '', 'winid' : 0, 'changedtick': 0},
\ g:Xgetlist({'all' : 0})) \ g:Xgetlist({'all' : 0}))
else else
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
\ 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '', \ 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '',
\ 'winid' : 0, 'changedtick': 0, 'filewinid' : 0}, \ 'winid' : 0, 'changedtick': 0, 'filewinid' : 0,
\ 'qfbufnr' : 0},
\ g:Xgetlist({'all' : 0})) \ g:Xgetlist({'all' : 0}))
endif endif
" Quickfix window with empty stack " Quickfix window with empty stack
silent! Xopen silent! Xopen
let qfwinid = (a:cchar == 'c') ? win_getid() : 0 let qfwinid = (a:cchar == 'c') ? win_getid() : 0
let qfbufnr = (a:cchar == 'c') ? bufnr('') : 0
call assert_equal(qfwinid, g:Xgetlist({'winid' : 0}).winid) call assert_equal(qfwinid, g:Xgetlist({'winid' : 0}).winid)
Xclose Xclose
@ -3204,11 +3266,12 @@ func Xgetlist_empty_tests(cchar)
if a:cchar == 'c' if a:cchar == 'c'
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
\ 'qfbufnr' : qfbufnr,
\ 'changedtick' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0})) \ 'changedtick' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0}))
else else
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
\ 'changedtick' : 0, 'filewinid' : 0}, \ 'changedtick' : 0, 'filewinid' : 0, 'qfbufnr' : 0},
\ g:Xgetlist({'id' : qfid, 'all' : 0})) \ g:Xgetlist({'id' : qfid, 'all' : 0}))
endif endif
@ -3225,11 +3288,12 @@ func Xgetlist_empty_tests(cchar)
if a:cchar == 'c' if a:cchar == 'c'
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
\ 'changedtick' : 0}, g:Xgetlist({'nr' : 5, 'all' : 0})) \ 'changedtick' : 0, 'qfbufnr' : qfbufnr},
\ g:Xgetlist({'nr' : 5, 'all' : 0}))
else else
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [], call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0, \ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
\ 'changedtick' : 0, 'filewinid' : 0}, \ 'changedtick' : 0, 'filewinid' : 0, 'qfbufnr' : 0},
\ g:Xgetlist({'nr' : 5, 'all' : 0})) \ g:Xgetlist({'nr' : 5, 'all' : 0}))
endif endif
endfunc endfunc
@ -3869,6 +3933,52 @@ func Test_curswant()
cclose | helpclose cclose | helpclose
endfunc endfunc
" Test for opening a file from the quickfix window using CTRL-W <Enter>
" doesn't leave an empty buffer around.
func Test_splitview()
call s:create_test_file('Xtestfile1')
call s:create_test_file('Xtestfile2')
new | only
let last_bufnr = bufnr('Test_sv_1', 1)
let l = ['Xtestfile1:2:Line2', 'Xtestfile2:4:Line4']
cgetexpr l
copen
let numbufs = len(getbufinfo())
exe "normal \<C-W>\<CR>"
copen
exe "normal j\<C-W>\<CR>"
" Make sure new empty buffers are not created
call assert_equal(numbufs, len(getbufinfo()))
" Creating a new buffer should use the next available buffer number
call assert_equal(last_bufnr + 4, bufnr("Test_sv_2", 1))
bwipe Test_sv_1
bwipe Test_sv_2
new | only
" When split opening files from location list window, make sure that two
" windows doesn't refer to the same location list
lgetexpr l
let locid = getloclist(0, {'id' : 0}).id
lopen
exe "normal \<C-W>\<CR>"
call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
new | only
" When split opening files from a helpgrep location list window, a new help
" window should be opend with a copy of the location list.
lhelpgrep window
let locid = getloclist(0, {'id' : 0}).id
lwindow
exe "normal j\<C-W>\<CR>"
call assert_notequal(locid, getloclist(0, {'id' : 0}).id)
call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
new | only
call delete('Xtestfile1')
call delete('Xtestfile2')
endfunc
" Test for parsing entries using visual screen column " Test for parsing entries using visual screen column
func Test_viscol() func Test_viscol()
enew enew
@ -3925,6 +4035,83 @@ func Test_viscol()
call delete('Xfile1') call delete('Xfile1')
endfunc endfunc
" Test for the quickfix window buffer
func Xqfbuf_test(cchar)
call s:setup_commands(a:cchar)
" Quickfix buffer should be reused across closing and opening a quickfix
" window
Xexpr "F1:10:Line10"
Xopen
let qfbnum = bufnr('')
Xclose
" Even after the quickfix window is closed, the buffer should be loaded
call assert_true(bufloaded(qfbnum))
call assert_true(qfbnum, g:Xgetlist({'qfbufnr' : 0}).qfbufnr)
Xopen
" Buffer should be reused when opening the window again
call assert_equal(qfbnum, bufnr(''))
Xclose
if a:cchar == 'l'
%bwipe
" For a location list, when both the file window and the location list
" window for the list are closed, then the buffer should be freed.
new | only
lexpr "F1:10:Line10"
let wid = win_getid()
lopen
let qfbnum = bufnr('')
call assert_match(qfbnum . ' %a- "\[Location List]"', execute('ls'))
close
" When the location list window is closed, the buffer name should not
" change to 'Quickfix List'
call assert_match(qfbnum . 'u h- "\[Location List]"', execute('ls!'))
call assert_true(bufloaded(qfbnum))
" After deleting a location list buffer using ":bdelete", opening the
" location list window should mark the buffer as a location list buffer.
exe "bdelete " . qfbnum
lopen
call assert_equal("quickfix", &buftype)
call assert_equal(1, getwininfo(win_getid(winnr()))[0].loclist)
call assert_equal(wid, getloclist(0, {'filewinid' : 0}).filewinid)
call assert_false(&swapfile)
lclose
" When the location list is cleared for the window, the buffer should be
" removed
call setloclist(0, [], 'f')
call assert_false(bufexists(qfbnum))
call assert_equal(0, getloclist(0, {'qfbufnr' : 0}).qfbufnr)
" When the location list is freed with the location list window open, the
" location list buffer should not be lost. It should be reused when the
" location list is again populated.
lexpr "F1:10:Line10"
lopen
let wid = win_getid()
let qfbnum = bufnr('')
wincmd p
call setloclist(0, [], 'f')
lexpr "F1:10:Line10"
lopen
call assert_equal(wid, win_getid())
call assert_equal(qfbnum, bufnr(''))
lclose
" When the window with the location list is closed, the buffer should be
" removed
new | only
call assert_false(bufexists(qfbnum))
endif
endfunc
func Test_qfbuf()
call Xqfbuf_test('c')
call Xqfbuf_test('l')
endfunc
" Test to make sure that an empty quickfix buffer is not reused for loading " Test to make sure that an empty quickfix buffer is not reused for loading
" a normal buffer. " a normal buffer.
func Test_empty_qfbuf() func Test_empty_qfbuf()

View File

@ -2578,9 +2578,14 @@ int win_close(win_T *win, bool free_buf)
return OK; return OK;
} }
/* Free independent synblock before the buffer is freed. */ // Free independent synblock before the buffer is freed.
if (win->w_buffer != NULL) if (win->w_buffer != NULL) {
reset_synblock(win); reset_synblock(win);
}
// When the quickfix/location list window is closed, unlist the buffer.
if (win->w_buffer != NULL && bt_quickfix(win->w_buffer)) {
win->w_buffer->b_p_bl = false;
}
/* /*
* Close the link to the buffer. * Close the link to the buffer.

View File

@ -27,7 +27,7 @@ describe('setqflist()', function()
setqflist({''}, 'r', 'foo') setqflist({''}, 'r', 'foo')
command('copen') command('copen')
eq('foo', get_cur_win_var('quickfix_title')) eq('foo', get_cur_win_var('quickfix_title'))
setqflist({''}, 'r', {['title'] = 'qf_title'}) setqflist({}, 'r', {['title'] = 'qf_title'})
eq('qf_title', get_cur_win_var('quickfix_title')) eq('qf_title', get_cur_win_var('quickfix_title'))
end) end)