Merge #8962 from janlazo/vim-8.0.0733

This commit is contained in:
Justin M. Keyes 2018-09-07 09:51:59 +02:00 committed by GitHub
commit 50eadfe2e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 474 additions and 192 deletions

View File

@ -6851,10 +6851,12 @@ setpos({expr}, {list})
setqflist({list} [, {action}[, {what}]]) *setqflist()*
Create or replace or add to the quickfix list using the items
in {list}. Each item in {list} is a dictionary.
Non-dictionary items in {list} are ignored. Each dictionary
item can contain the following entries:
Create or replace or add to the quickfix list.
When {what} is not present, use the items in {list}. Each
item must be a dictionary. Non-dictionary items in {list} are
ignored. Each dictionary item can contain the following
entries:
bufnr buffer number; must be the number of a valid
buffer
@ -6899,7 +6901,10 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
freed.
If {action} is not present or is set to ' ', then a new list
is created.
is created. The new quickfix list is added after the current
quickfix list in the stack and all the following lists are
freed. To add a new quickfix list at the end of the stack,
set "nr" in {what} to '$'.
If {title} is given, it will be used to set |w:quickfix_title|
after opening the quickfix window.
@ -6909,6 +6914,10 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
argument is ignored. The following items can be specified in
{what}:
context any Vim type can be stored as a context
text use 'errorformat' to extract items from the
text and add the resulting entries to the
quickfix list {nr}. The value can be a string
with one line or a list with multiple lines.
items list of quickfix entries. Same as the {list}
argument.
nr list number in the quickfix stack; zero

View File

@ -252,7 +252,7 @@ open_buffer (
msg_silent = old_msg_silent;
// Help buffer is filtered.
if (curbuf->b_help) {
if (bt_help(curbuf)) {
fix_help_buffer();
}
} else if (read_stdin) {
@ -841,8 +841,8 @@ void goto_buffer(exarg_T *eap, int start, int dir, int count)
* aborting() returns FALSE when closing a window. */
enter_cleanup(&cs);
/* Quitting means closing the split window, nothing else. */
win_close(curwin, TRUE);
// Quitting means closing the split window, nothing else.
win_close(curwin, true);
swap_exists_action = SEA_NONE;
swap_exists_did_quit = TRUE;
@ -4651,10 +4651,10 @@ void ex_buffer_all(exarg_T *eap)
&& !ONE_WINDOW
&& !(wp->w_closing || wp->w_buffer->b_locked > 0)
) {
win_close(wp, FALSE);
wpnext = firstwin; /* just in case an autocommand does
something strange with windows */
tpnext = first_tabpage; /* start all over...*/
win_close(wp, false);
wpnext = firstwin; // just in case an autocommand does
// something strange with windows
tpnext = first_tabpage; // start all over...
open_wins = 0;
} else
++open_wins;
@ -4723,9 +4723,9 @@ void ex_buffer_all(exarg_T *eap)
* aborting() returns FALSE when closing a window. */
enter_cleanup(&cs);
/* User selected Quit at ATTENTION prompt; close this window. */
win_close(curwin, TRUE);
--open_wins;
// User selected Quit at ATTENTION prompt; close this window.
win_close(curwin, true);
open_wins--;
swap_exists_action = SEA_NONE;
swap_exists_did_quit = TRUE;
@ -4930,6 +4930,12 @@ chk_modeline (
return retval;
}
// Return true if "buf" is a help buffer.
bool bt_help(const buf_T *const buf)
{
return buf != NULL && buf->b_help;
}
/*
* Return special buffer name.
* Returns NULL when the buffer has a normal file name.

View File

@ -4514,7 +4514,7 @@ void ex_help(exarg_T *eap)
* Re-use an existing help window or open a new one.
* Always open a new one for ":tab help".
*/
if (!curwin->w_buffer->b_help
if (!bt_help(curwin->w_buffer)
|| cmdmod.tab != 0
) {
if (cmdmod.tab != 0) {
@ -4522,7 +4522,7 @@ void ex_help(exarg_T *eap)
} else {
wp = NULL;
FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) {
if (wp2->w_buffer != NULL && wp2->w_buffer->b_help) {
if (bt_help(wp2->w_buffer)) {
wp = wp2;
break;
}
@ -5509,8 +5509,8 @@ static int next_sign_typenr = 1;
void ex_helpclose(exarg_T *eap)
{
FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
if (win->w_buffer->b_help) {
win_close(win, FALSE);
if (bt_help(win->w_buffer)) {
win_close(win, false);
return;
}
}

View File

@ -6192,7 +6192,7 @@ static int open_cmdwin(void)
wp = curwin;
set_bufref(&bufref, curbuf);
win_goto(old_curwin);
win_close(wp, TRUE);
win_close(wp, true);
// win_close() may have already wiped the buffer when 'bh' is
// set to 'wipe'.

View File

@ -1540,7 +1540,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
{
int arg_idx; /* index in argument list */
int i;
int advance = TRUE;
bool advance = true;
win_T *win;
/*
@ -1551,8 +1551,8 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
/* When w_arg_idx is -1 remove the window (see create_windows()). */
if (curwin->w_arg_idx == -1) {
win_close(curwin, TRUE);
advance = FALSE;
win_close(curwin, true);
advance = false;
}
arg_idx = 1;
@ -1562,9 +1562,9 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
}
// When w_arg_idx is -1 remove the window (see create_windows()).
if (curwin->w_arg_idx == -1) {
++arg_idx;
win_close(curwin, TRUE);
advance = FALSE;
arg_idx++;
win_close(curwin, true);
advance = false;
continue;
}
@ -1579,7 +1579,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
win_enter(curwin->w_next, false);
}
}
advance = TRUE;
advance = true;
// Only open the file if there is no file in this window yet (that can
// happen when vimrc contains ":sall").
@ -1598,8 +1598,8 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
did_emsg = FALSE; /* avoid hit-enter prompt */
getout(1);
}
win_close(curwin, TRUE);
advance = FALSE;
win_close(curwin, true);
advance = false;
}
if (arg_idx == GARGCOUNT - 1)
arg_had_last = TRUE;

View File

@ -91,6 +91,14 @@ typedef struct qf_list_S {
char_u *qf_title; ///< title derived from the command that created
///< the error list or set by setqflist
typval_T *qf_ctx; ///< context set by setqflist/setloclist
struct dir_stack_T *qf_dir_stack;
char_u *qf_directory;
struct dir_stack_T *qf_file_stack;
char_u *qf_currfile;
bool qf_multiline;
bool qf_multiignore;
bool qf_multiscan;
} qf_list_T;
/// Quickfix/Location list stack definition
@ -106,15 +114,6 @@ struct qf_info_S {
int qf_listcount; /* current number of lists */
int qf_curlist; /* current error list */
qf_list_T qf_lists[LISTCOUNT];
int qf_dir_curlist; ///< error list for qf_dir_stack
struct dir_stack_T *qf_dir_stack;
char_u *qf_directory;
struct dir_stack_T *qf_file_stack;
char_u *qf_currfile;
bool qf_multiline;
bool qf_multiignore;
bool qf_multiscan;
};
static qf_info_T ql_info; /* global quickfix list */
@ -223,9 +222,8 @@ int qf_init(win_T *wp, char_u *efile, char_u *errorformat, int newlist,
qi = ll_get_or_alloc_list(wp);
}
return qf_init_ext(qi, efile, curbuf, NULL, errorformat, newlist,
(linenr_T)0, (linenr_T)0,
qf_title, enc);
return qf_init_ext(qi, qi->qf_curlist, efile, curbuf, NULL, errorformat,
newlist, (linenr_T)0, (linenr_T)0, qf_title, enc);
}
// Maximum number of bytes allowed per line while reading an errorfile.
@ -712,8 +710,8 @@ static int qf_get_nextline(qfstate_T *state)
/// Parse a line and get the quickfix fields.
/// Return the QF_ status.
static int qf_parse_line(qf_info_T *qi, char_u *linebuf, size_t linelen,
efm_T *fmt_first, qffields_T *fields)
static int qf_parse_line(qf_info_T *qi, int qf_idx, char_u *linebuf,
size_t linelen, efm_T *fmt_first, qffields_T *fields)
{
efm_T *fmt_ptr;
size_t len;
@ -721,7 +719,7 @@ static int qf_parse_line(qf_info_T *qi, char_u *linebuf, size_t linelen,
int idx = 0;
char_u *tail = NULL;
regmatch_T regmatch;
qf_list_T *qfl = &qi->qf_lists[qf_idx];
// Always ignore case when looking for a matching error.
regmatch.rm_ic = true;
@ -740,12 +738,12 @@ static int qf_parse_line(qf_info_T *qi, char_u *linebuf, size_t linelen,
restofline:
for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) {
idx = fmt_ptr->prefix;
if (qi->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) {
if (qfl->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) {
continue;
}
fields->namebuf[0] = NUL;
fields->pattern[0] = NUL;
if (!qi->qf_multiscan) {
if (!qfl->qf_multiscan) {
fields->errmsg[0] = NUL;
}
fields->lnum = 0;
@ -759,7 +757,7 @@ restofline:
int r = vim_regexec(&regmatch, linebuf, (colnr_T)0);
fmt_ptr->prog = regmatch.regprog;
if (r) {
if ((idx == 'C' || idx == 'Z') && !qi->qf_multiline) {
if ((idx == 'C' || idx == 'Z') && !qfl->qf_multiline) {
continue;
}
if (vim_strchr((char_u *)"EWI", idx) != NULL) {
@ -809,7 +807,7 @@ restofline:
}
fields->type = *regmatch.startp[i];
}
if (fmt_ptr->flags == '+' && !qi->qf_multiscan) { // %+
if (fmt_ptr->flags == '+' && !qfl->qf_multiscan) { // %+
if (linelen >= fields->errmsglen) {
// linelen + null terminator
fields->errmsg = xrealloc(fields->errmsg, linelen + 1);
@ -877,7 +875,7 @@ restofline:
break;
}
}
qi->qf_multiscan = false;
qfl->qf_multiscan = false;
if (fmt_ptr == NULL || idx == 'D' || idx == 'X') {
if (fmt_ptr != NULL) {
@ -886,13 +884,13 @@ restofline:
EMSG(_("E379: Missing or empty directory name"));
return QF_FAIL;
}
qi->qf_directory = qf_push_dir(fields->namebuf, &qi->qf_dir_stack,
false);
if (qi->qf_directory == NULL) {
qfl->qf_directory = qf_push_dir(fields->namebuf, &qfl->qf_dir_stack,
false);
if (qfl->qf_directory == NULL) {
return QF_FAIL;
}
} else if (idx == 'X') { // leave directory
qi->qf_directory = qf_pop_dir(&qi->qf_dir_stack);
qfl->qf_directory = qf_pop_dir(&qfl->qf_dir_stack);
}
}
fields->namebuf[0] = NUL; // no match found, remove file name
@ -906,7 +904,7 @@ restofline:
// copy whole line to error message
STRLCPY(fields->errmsg, linebuf, linelen + 1);
if (fmt_ptr == NULL) {
qi->qf_multiline = qi->qf_multiignore = false;
qfl->qf_multiline = qfl->qf_multiignore = false;
}
} else {
// honor %> item
@ -915,12 +913,12 @@ restofline:
}
if (vim_strchr((char_u *)"AEWI", idx) != NULL) {
qi->qf_multiline = true; // start of a multi-line message
qi->qf_multiignore = false; // reset continuation
qfl->qf_multiline = true; // start of a multi-line message
qfl->qf_multiignore = false; // reset continuation
} else if (vim_strchr((char_u *)"CZ", idx)
!= NULL) { // continuation of multi-line msg
if (!qi->qf_multiignore) {
qfline_T *qfprev = qi->qf_lists[qi->qf_curlist].qf_last;
if (!qfl->qf_multiignore) {
qfline_T *qfprev = qfl->qf_last;
if (qfprev == NULL) {
return QF_FAIL;
}
@ -945,15 +943,15 @@ restofline:
}
qfprev->qf_viscol = fields->use_viscol;
if (!qfprev->qf_fnum) {
qfprev->qf_fnum = qf_get_fnum(qi, qi->qf_directory,
*fields->namebuf || qi->qf_directory
qfprev->qf_fnum = qf_get_fnum(qi, qf_idx, qfl->qf_directory,
*fields->namebuf || qfl->qf_directory
? fields->namebuf
: qi->qf_currfile && fields->valid
? qi->qf_currfile : 0);
: qfl->qf_currfile && fields->valid
? qfl->qf_currfile : 0);
}
}
if (idx == 'Z') {
qi->qf_multiline = qi->qf_multiignore = false;
qfl->qf_multiline = qfl->qf_multiignore = false;
}
line_breakcheck();
@ -963,23 +961,23 @@ restofline:
fields->valid = false;
if (*fields->namebuf == NUL || os_path_exists(fields->namebuf)) {
if (*fields->namebuf && idx == 'P') {
qi->qf_currfile = qf_push_dir(fields->namebuf, &qi->qf_file_stack,
true);
qfl->qf_currfile = qf_push_dir(fields->namebuf, &qfl->qf_file_stack,
true);
} else if (idx == 'Q') {
qi->qf_currfile = qf_pop_dir(&qi->qf_file_stack);
qfl->qf_currfile = qf_pop_dir(&qfl->qf_file_stack);
}
*fields->namebuf = NUL;
if (tail && *tail) {
STRMOVE(IObuff, skipwhite(tail));
qi->qf_multiscan = true;
qfl->qf_multiscan = true;
goto restofline;
}
}
}
if (fmt_ptr->flags == '-') { // generally exclude this line
if (qi->qf_multiline) {
if (qfl->qf_multiline) {
// also exclude continuation lines
qi->qf_multiignore = true;
qfl->qf_multiignore = true;
}
return QF_IGNORE_LINE;
}
@ -999,6 +997,7 @@ restofline:
static int
qf_init_ext(
qf_info_T *qi,
int qf_idx,
char_u *efile,
buf_T *buf,
typval_T *tv,
@ -1041,17 +1040,20 @@ qf_init_ext(
goto qf_init_end;
}
if (newlist || qi->qf_curlist == qi->qf_listcount) {
if (newlist || qf_idx == qi->qf_listcount) {
// make place for a new list
qf_new_list(qi, qf_title);
qf_idx = qi->qf_curlist;
} else {
// Adding to existing list, use last entry.
adding = true;
if (qi->qf_lists[qi->qf_curlist].qf_count > 0) {
old_last = qi->qf_lists[qi->qf_curlist].qf_last;
if (qi->qf_lists[qf_idx].qf_count > 0) {
old_last = qi->qf_lists[qf_idx].qf_last;
}
}
qf_list_T *qfl = &qi->qf_lists[qf_idx];
// Use the local value of 'errorformat' if it's set.
if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) {
efm = buf->b_p_efm;
@ -1059,18 +1061,6 @@ qf_init_ext(
efm = errorformat;
}
// If we are not adding or adding to another list: clear the state.
if (newlist || qi->qf_curlist != qi->qf_dir_curlist) {
qi->qf_dir_curlist = qi->qf_curlist;
qf_clean_dir_stack(&qi->qf_dir_stack);
qi->qf_directory = NULL;
qf_clean_dir_stack(&qi->qf_file_stack);
qi->qf_currfile = NULL;
qi->qf_multiline = false;
qi->qf_multiignore = false;
qi->qf_multiscan = false;
}
// If the errorformat didn't change between calls, then reuse the previously
// parsed values.
if (last_efm == NULL || (STRCMP(last_efm, efm) != 0)) {
@ -1120,8 +1110,8 @@ qf_init_ext(
break;
}
status = qf_parse_line(qi, state.linebuf, state.linelen, fmt_first,
&fields);
status = qf_parse_line(qi, qf_idx, state.linebuf, state.linelen,
fmt_first, &fields);
if (status == QF_FAIL) {
goto error2;
}
@ -1130,11 +1120,11 @@ qf_init_ext(
}
if (qf_add_entry(qi,
qi->qf_curlist,
qi->qf_directory,
(*fields.namebuf || qi->qf_directory)
? fields.namebuf : ((qi->qf_currfile && fields.valid)
? qi->qf_currfile : (char_u *)NULL),
qf_idx,
qfl->qf_directory,
(*fields.namebuf || qfl->qf_directory)
? fields.namebuf : ((qfl->qf_currfile && fields.valid)
? qfl->qf_currfile : (char_u *)NULL),
0,
fields.errmsg,
fields.lnum,
@ -1149,25 +1139,25 @@ qf_init_ext(
line_breakcheck();
}
if (state.fd == NULL || !ferror(state.fd)) {
if (qi->qf_lists[qi->qf_curlist].qf_index == 0) {
/* no valid entry found */
qi->qf_lists[qi->qf_curlist].qf_ptr =
qi->qf_lists[qi->qf_curlist].qf_start;
qi->qf_lists[qi->qf_curlist].qf_index = 1;
qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE;
if (qfl->qf_index == 0) {
// no valid entry found
qfl->qf_ptr = qfl->qf_start;
qfl->qf_index = 1;
qfl->qf_nonevalid = true;
} else {
qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
if (qi->qf_lists[qi->qf_curlist].qf_ptr == NULL)
qi->qf_lists[qi->qf_curlist].qf_ptr =
qi->qf_lists[qi->qf_curlist].qf_start;
qfl->qf_nonevalid = false;
if (qfl->qf_ptr == NULL) {
qfl->qf_ptr = qfl->qf_start;
}
}
/* return number of matches */
retval = qi->qf_lists[qi->qf_curlist].qf_count;
// return number of matches
retval = qfl->qf_count;
goto qf_init_end;
}
EMSG(_(e_readerrf));
error2:
if (!adding) {
// Error when creating a new list. Free the new list
qf_free(qi, qi->qf_curlist);
qi->qf_listcount--;
if (qi->qf_curlist > 0) {
@ -1183,7 +1173,9 @@ qf_init_end:
xfree(fields.pattern);
xfree(state.growbuf);
qf_update_buffer(qi, old_last);
if (qf_idx == qi->qf_curlist) {
qf_update_buffer(qi, old_last);
}
if (state.vc.vc_type != CONV_NONE) {
convert_setup(&state.vc, NULL, NULL);
@ -1206,9 +1198,9 @@ static void qf_store_title(qf_info_T *qi, int qf_idx, char_u *title)
}
}
/*
* Prepare for adding a new quickfix list.
*/
// Prepare for adding a new quickfix list. If the current list is in the
// middle of the stack, then all the following lists are freed and then
// the new list is added.
static void qf_new_list(qf_info_T *qi, char_u *qf_title)
{
int i;
@ -1305,7 +1297,7 @@ static int qf_add_entry(qf_info_T *qi, int qf_idx, char_u *dir, char_u *fname,
(qi == &ql_info) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
}
} else {
qfp->qf_fnum = qf_get_fnum(qi, dir, fname);
qfp->qf_fnum = qf_get_fnum(qi, qf_idx, dir, fname);
}
qfp->qf_text = vim_strsave(mesg);
qfp->qf_lnum = lnum;
@ -1488,7 +1480,8 @@ void copy_loclist(win_T *from, win_T *to)
// Get buffer number for file "directory/fname".
// Also sets the b_has_qf_entry flag.
static int qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname)
static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *directory,
char_u *fname)
{
char_u *ptr = NULL;
char_u *bufname;
@ -1511,7 +1504,7 @@ static int qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname)
// directory change.
if (!os_path_exists(ptr)) {
xfree(ptr);
directory = qf_guess_filepath(qi, fname);
directory = qf_guess_filepath(qi, qf_idx, fname);
if (directory) {
ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true);
} else {
@ -1661,18 +1654,19 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr)
* Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb.
* qf_guess_filepath will return NULL.
*/
static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename)
static char_u *qf_guess_filepath(qf_info_T *qi, int qf_idx, char_u *filename)
{
struct dir_stack_T *ds_ptr;
struct dir_stack_T *ds_tmp;
char_u *fullname;
qf_list_T *qfl = &qi->qf_lists[qf_idx];
// no dirs on the stack - there's nothing we can do
if (qi->qf_dir_stack == NULL) {
if (qfl->qf_dir_stack == NULL) {
return NULL;
}
ds_ptr = qi->qf_dir_stack->next;
ds_ptr = qfl->qf_dir_stack->next;
fullname = NULL;
while (ds_ptr) {
xfree(fullname);
@ -1688,9 +1682,9 @@ static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename)
xfree(fullname);
// clean up all dirs we already left
while (qi->qf_dir_stack->next != ds_ptr) {
ds_tmp = qi->qf_dir_stack->next;
qi->qf_dir_stack->next = qi->qf_dir_stack->next->next;
while (qfl->qf_dir_stack->next != ds_ptr) {
ds_tmp = qfl->qf_dir_stack->next;
qfl->qf_dir_stack->next = qfl->qf_dir_stack->next->next;
xfree(ds_tmp->dirname);
xfree(ds_tmp);
}
@ -1845,12 +1839,12 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
/*
* For ":helpgrep" find a help window or open one.
*/
if (qf_ptr->qf_type == 1 && (!curwin->w_buffer->b_help || cmdmod.tab != 0)) {
if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) {
win_T *wp = NULL;
if (cmdmod.tab == 0) {
FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) {
if (wp2->w_buffer != NULL && wp2->w_buffer->b_help) {
if (bt_help(wp2->w_buffer)) {
wp = wp2;
break;
}
@ -2415,11 +2409,12 @@ static void qf_free_items(qf_info_T *qi, int idx)
qfline_T *qfp;
qfline_T *qfpnext;
bool stop = false;
qf_list_T *qfl = &qi->qf_lists[idx];
while (qi->qf_lists[idx].qf_count && qi->qf_lists[idx].qf_start != NULL) {
qfp = qi->qf_lists[idx].qf_start;
while (qfl->qf_count && qfl->qf_start != NULL) {
qfp = qfl->qf_start;
qfpnext = qfp->qf_next;
if (qi->qf_lists[idx].qf_title != NULL && !stop) {
if (qfl->qf_title != NULL && !stop) {
xfree(qfp->qf_text);
stop = (qfp == qfpnext);
xfree(qfp->qf_pattern);
@ -2428,40 +2423,41 @@ static void qf_free_items(qf_info_T *qi, int idx)
// Somehow qf_count may have an incorrect value, set it to 1
// to avoid crashing when it's wrong.
// TODO(vim): Avoid qf_count being incorrect.
qi->qf_lists[idx].qf_count = 1;
qfl->qf_count = 1;
}
}
qi->qf_lists[idx].qf_start = qfpnext;
qi->qf_lists[idx].qf_count--;
qfl->qf_start = qfpnext;
qfl->qf_count--;
}
qi->qf_lists[idx].qf_start = NULL;
qi->qf_lists[idx].qf_ptr = NULL;
qi->qf_lists[idx].qf_index = 0;
qi->qf_lists[idx].qf_start = NULL;
qi->qf_lists[idx].qf_last = NULL;
qi->qf_lists[idx].qf_ptr = NULL;
qi->qf_lists[idx].qf_nonevalid = true;
qfl->qf_start = NULL;
qfl->qf_ptr = NULL;
qfl->qf_index = 0;
qfl->qf_start = NULL;
qfl->qf_last = NULL;
qfl->qf_ptr = NULL;
qfl->qf_nonevalid = true;
qf_clean_dir_stack(&qi->qf_dir_stack);
qi->qf_directory = NULL;
qf_clean_dir_stack(&qi->qf_file_stack);
qi->qf_currfile = NULL;
qi->qf_multiline = false;
qi->qf_multiignore = false;
qi->qf_multiscan = false;
qf_clean_dir_stack(&qfl->qf_dir_stack);
qfl->qf_directory = NULL;
qf_clean_dir_stack(&qfl->qf_file_stack);
qfl->qf_currfile = NULL;
qfl->qf_multiline = false;
qfl->qf_multiignore = false;
qfl->qf_multiscan = false;
}
/// Free error list "idx". Frees all the entries in the quickfix list,
/// associated context information and the title.
static void qf_free(qf_info_T *qi, int idx)
{
qf_list_T *qfl = &qi->qf_lists[idx];
qf_free_items(qi, idx);
xfree(qi->qf_lists[idx].qf_title);
qi->qf_lists[idx].qf_title = NULL;
tv_free(qi->qf_lists[idx].qf_ctx);
qi->qf_lists[idx].qf_ctx = NULL;
xfree(qfl->qf_title);
qfl->qf_title = NULL;
tv_free(qfl->qf_ctx);
qfl->qf_ctx = NULL;
}
/*
@ -2601,8 +2597,9 @@ void ex_cclose(exarg_T *eap)
/* Find existing quickfix window and close it. */
win = qf_find_win(qi);
if (win != NULL)
win_close(win, FALSE);
if (win != NULL) {
win_close(win, false);
}
}
/*
@ -4333,7 +4330,8 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list,
return retval;
}
static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
char_u *title)
{
dictitem_T *di;
int retval = FAIL;
@ -4353,25 +4351,32 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
if ((action == ' ' || action == 'a') && qf_idx == qi->qf_listcount) {
// When creating a new list, accept qf_idx pointing to the next
// non-available list
// non-available list and add the new list at the end of the
// stack.
newlist = true;
qf_idx = qi->qf_listcount - 1;
} else if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
return FAIL;
} else {
} else if (action != ' ') {
newlist = false; // use the specified list
}
} else if (di->di_tv.v_type == VAR_STRING
&& strequal((const char *)di->di_tv.vval.v_string, "$")
&& qi->qf_listcount > 0) {
qf_idx = qi->qf_listcount - 1;
newlist = false;
&& strequal((const char *)di->di_tv.vval.v_string, "$")) {
if (qi->qf_listcount > 0) {
qf_idx = qi->qf_listcount - 1;
} else if (newlist) {
qf_idx = 0;
} else {
return FAIL;
}
} else {
return FAIL;
}
}
if (newlist) {
qf_new_list(qi, NULL);
qi->qf_curlist = qf_idx;
qf_new_list(qi, title);
qf_idx = qi->qf_curlist;
}
@ -4396,6 +4401,24 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
}
}
if ((di = tv_dict_find(what, S_LEN("text"))) != NULL) {
// Only string and list values are supported
if ((di->di_tv.v_type == VAR_STRING
&& di->di_tv.vval.v_string != NULL)
|| (di->di_tv.v_type == VAR_LIST
&& di->di_tv.vval.v_list != NULL)) {
if (action == 'r') {
qf_free_items(qi, qf_idx);
}
if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, p_efm,
false, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
retval = OK;
}
} else {
return FAIL;
}
}
if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) {
tv_free(qi->qf_lists[qf_idx].qf_ctx);
@ -4483,7 +4506,7 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
// Free the entire quickfix or location list stack
qf_free_stack(wp, qi);
} else if (what != NULL) {
retval = qf_set_properties(qi, what, action);
retval = qf_set_properties(qi, what, action, title);
} else {
retval = qf_add_entries(qi, qi->qf_curlist, list, title, action);
}
@ -4603,7 +4626,7 @@ void ex_cbuffer(exarg_T *eap)
qf_title = IObuff;
}
if (qf_init_ext(qi, NULL, buf, NULL, p_efm,
if (qf_init_ext(qi, qi->qf_curlist, NULL, buf, NULL, p_efm,
(eap->cmdidx != CMD_caddbuffer
&& eap->cmdidx != CMD_laddbuffer),
eap->line1, eap->line2, qf_title, NULL) > 0) {
@ -4668,7 +4691,7 @@ void ex_cexpr(exarg_T *eap)
if (eval0(eap->arg, &tv, NULL, true) != FAIL) {
if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL)
|| tv.v_type == VAR_LIST) {
if (qf_init_ext(qi, NULL, NULL, &tv, p_efm,
if (qf_init_ext(qi, qi->qf_curlist, NULL, NULL, &tv, p_efm,
(eap->cmdidx != CMD_caddexpr
&& eap->cmdidx != CMD_laddexpr),
(linenr_T)0, (linenr_T)0, *eap->cmdlinep, NULL) > 0) {
@ -4725,16 +4748,26 @@ void ex_helpgrep(exarg_T *eap)
p_cpo = empty_option;
if (eap->cmdidx == CMD_lhelpgrep) {
qi = NULL;
win_T *wp = NULL;
/* Find an existing help window */
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer != NULL && wp->w_buffer->b_help) {
qi = wp->w_llist;
// If the current window is a help window, then use it
if (bt_help(curwin->w_buffer)) {
wp = curwin;
} else {
// Find an existing help window
FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) {
if (bt_help(wp2->w_buffer)) {
wp = wp2;
break;
}
}
}
/* Help window not found */
if (wp == NULL) { // Help window not found
qi = NULL;
} else {
qi = wp->w_llist;
}
if (qi == NULL) {
/* Allocate a new location list for help text matches */
qi = ll_new_list();
@ -4855,11 +4888,13 @@ void ex_helpgrep(exarg_T *eap)
if (eap->cmdidx == CMD_lhelpgrep) {
/* If the help window is not opened or if it already points to the
* correct location list, then free the new location list. */
if (!curwin->w_buffer->b_help || curwin->w_llist == qi) {
if (new_qi)
if (!bt_help(curwin->w_buffer) || curwin->w_llist == qi) {
if (new_qi) {
ll_free_all(&qi);
} else if (curwin->w_llist == NULL)
}
} else if (curwin->w_llist == NULL) {
curwin->w_llist = qi;
}
}
}

View File

@ -2608,11 +2608,11 @@ static int jumpto_tag(
win_enter(curwin_save, true);
}
--RedrawingDisabled;
RedrawingDisabled--;
} else {
--RedrawingDisabled;
if (postponed_split) { /* close the window */
win_close(curwin, FALSE);
RedrawingDisabled--;
if (postponed_split) { // close the window
win_close(curwin, false);
postponed_split = 0;
}
}

View File

@ -11,7 +11,7 @@ func s:setup_commands(cchar)
command! -nargs=* -bang Xlist <mods>clist<bang> <args>
command! -nargs=* Xgetexpr <mods>cgetexpr <args>
command! -nargs=* Xaddexpr <mods>caddexpr <args>
command! -nargs=* Xolder <mods>colder <args>
command! -nargs=* -count Xolder <mods><count>colder <args>
command! -nargs=* Xnewer <mods>cnewer <args>
command! -nargs=* Xopen <mods>copen <args>
command! -nargs=* Xwindow <mods>cwindow <args>
@ -43,7 +43,7 @@ func s:setup_commands(cchar)
command! -nargs=* -bang Xlist <mods>llist<bang> <args>
command! -nargs=* Xgetexpr <mods>lgetexpr <args>
command! -nargs=* Xaddexpr <mods>laddexpr <args>
command! -nargs=* Xolder <mods>lolder <args>
command! -nargs=* -count Xolder <mods><count>lolder <args>
command! -nargs=* Xnewer <mods>lnewer <args>
command! -nargs=* Xopen <mods>lopen <args>
command! -nargs=* Xwindow <mods>lwindow <args>
@ -1727,7 +1727,7 @@ func Xproperty_tests(cchar)
call assert_equal('N2', g:Xgetlist({'nr':2, 'title':1}).title)
" Changing the title of an earlier quickfix list
call g:Xsetlist([], ' ', {'title' : 'NewTitle', 'nr' : 2})
call g:Xsetlist([], 'r', {'title' : 'NewTitle', 'nr' : 2})
call assert_equal('NewTitle', g:Xgetlist({'nr':2, 'title':1}).title)
" Changing the title of an invalid quickfix list
@ -1794,10 +1794,10 @@ func Xproperty_tests(cchar)
Xexpr "One"
Xexpr "Two"
Xexpr "Three"
call g:Xsetlist([], ' ', {'context' : [1], 'nr' : 1})
call g:Xsetlist([], ' ', {'context' : [2], 'nr' : 2})
call g:Xsetlist([], 'r', {'context' : [1], 'nr' : 1})
call g:Xsetlist([], 'a', {'context' : [2], 'nr' : 2})
" Also, check for setting the context using quickfix list number zero.
call g:Xsetlist([], ' ', {'context' : [3], 'nr' : 0})
call g:Xsetlist([], 'r', {'context' : [3], 'nr' : 0})
call test_garbagecollect_now()
let l = g:Xgetlist({'nr' : 1, 'context' : 1})
call assert_equal([1], l.context)
@ -1844,6 +1844,11 @@ func Xproperty_tests(cchar)
let l = g:Xgetlist({'items':1})
call assert_equal(0, len(l.items))
" The following used to crash Vim with address sanitizer
call g:Xsetlist([], 'f')
call g:Xsetlist([], 'a', {'items' : [{'filename':'F1', 'lnum':10}]})
call assert_equal(10, g:Xgetlist({'items':1}).items[0].lnum)
" Save and restore the quickfix stack
call g:Xsetlist([], 'f')
call assert_equal(0, g:Xgetlist({'nr':'$'}).nr)
@ -2266,6 +2271,233 @@ func Xchangedtick_tests(cchar)
endfunc
func Test_changedtick()
call Xchangedtick_tests('c')
call Xchangedtick_tests('l')
call Xchangedtick_tests('c')
call Xchangedtick_tests('l')
endfunc
" Tests for parsing an expression using setqflist()
func Xsetexpr_tests(cchar)
call s:setup_commands(a:cchar)
let t = ["File1:10:Line10", "File1:20:Line20"]
call g:Xsetlist([], ' ', {'text' : t})
call g:Xsetlist([], 'a', {'text' : "File1:30:Line30"})
let l = g:Xgetlist()
call assert_equal(3, len(l))
call assert_equal(20, l[1].lnum)
call assert_equal('Line30', l[2].text)
call g:Xsetlist([], 'r', {'text' : "File2:5:Line5"})
let l = g:Xgetlist()
call assert_equal(1, len(l))
call assert_equal('Line5', l[0].text)
call assert_equal(-1, g:Xsetlist([], 'a', {'text' : 10}))
call g:Xsetlist([], 'f')
" Add entries to multiple lists
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:10:Line10"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:20:Line20"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:15:Line15"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:25:Line25"]})
call assert_equal('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text)
call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text)
endfunc
func Test_setexpr()
call Xsetexpr_tests('c')
call Xsetexpr_tests('l')
endfunc
" Tests for per quickfix/location list directory stack
func Xmultidirstack_tests(cchar)
call s:setup_commands(a:cchar)
call g:Xsetlist([], 'f')
Xexpr "" | Xexpr ""
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "Entering dir 'Xone/a'"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "Entering dir 'Xtwo/a'"})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "one.txt:3:one one one"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "two.txt:5:two two two"})
let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1})
call assert_equal('Xone/a/one.txt', bufname(l1.items[1].bufnr))
call assert_equal(3, l1.items[1].lnum)
call assert_equal('Xtwo/a/two.txt', bufname(l2.items[1].bufnr))
call assert_equal(5, l2.items[1].lnum)
endfunc
func Test_multidirstack()
call mkdir('Xone/a', 'p')
call mkdir('Xtwo/a', 'p')
let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
call writefile(lines, 'Xone/a/one.txt')
call writefile(lines, 'Xtwo/a/two.txt')
let save_efm = &efm
set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
call Xmultidirstack_tests('c')
call Xmultidirstack_tests('l')
let &efm = save_efm
call delete('Xone', 'rf')
call delete('Xtwo', 'rf')
endfunc
" Tests for per quickfix/location list file stack
func Xmultifilestack_tests(cchar)
call s:setup_commands(a:cchar)
call g:Xsetlist([], 'f')
Xexpr "" | Xexpr ""
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "[one.txt]"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "[two.txt]"})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "(3,5) one one one"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "(5,9) two two two"})
let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1})
call assert_equal('one.txt', bufname(l1.items[1].bufnr))
call assert_equal(3, l1.items[1].lnum)
call assert_equal('two.txt', bufname(l2.items[1].bufnr))
call assert_equal(5, l2.items[1].lnum)
endfunc
func Test_multifilestack()
let lines = ['1', '2', 'one one one', '4', 'two two two', '6', '7']
call writefile(lines, 'one.txt')
call writefile(lines, 'two.txt')
let save_efm = &efm
set efm=%+P[%f],(%l\\,%c)\ %m,%-Q
call Xmultifilestack_tests('c')
call Xmultifilestack_tests('l')
let &efm = save_efm
call delete('one.txt')
call delete('two.txt')
endfunc
" Tests for per buffer 'efm' setting
func Test_perbuf_efm()
call writefile(["File1-10-Line10"], 'one.txt')
call writefile(["File2#20#Line20"], 'two.txt')
set efm=%f#%l#%m
new | only
new
setlocal efm=%f-%l-%m
cfile one.txt
wincmd w
caddfile two.txt
let l = getqflist()
call assert_equal(10, l[0].lnum)
call assert_equal('Line20', l[1].text)
set efm&
new | only
call delete('one.txt')
call delete('two.txt')
endfunc
" Open multiple help windows using ":lhelpgrep
" This test used to crash Vim
func Test_Multi_LL_Help()
new | only
lhelpgrep window
lopen
e#
lhelpgrep buffer
call assert_equal(3, winnr('$'))
call assert_true(len(getloclist(1)) != 0)
call assert_true(len(getloclist(2)) != 0)
new | only
endfunc
" Tests for adding new quickfix lists using setqflist()
func XaddQf_tests(cchar)
call s:setup_commands(a:cchar)
" Create a new list using ' ' for action
call g:Xsetlist([], 'f')
call g:Xsetlist([], ' ', {'title' : 'Test1'})
let l = g:Xgetlist({'nr' : '$', 'all' : 1})
call assert_equal(1, l.nr)
call assert_equal('Test1', l.title)
" Create a new list using ' ' for action and '$' for 'nr'
call g:Xsetlist([], 'f')
call g:Xsetlist([], ' ', {'title' : 'Test2', 'nr' : '$'})
let l = g:Xgetlist({'nr' : '$', 'all' : 1})
call assert_equal(1, l.nr)
call assert_equal('Test2', l.title)
" Create a new list using 'a' for action
call g:Xsetlist([], 'f')
call g:Xsetlist([], 'a', {'title' : 'Test3'})
let l = g:Xgetlist({'nr' : '$', 'all' : 1})
call assert_equal(1, l.nr)
call assert_equal('Test3', l.title)
" Create a new list using 'a' for action and '$' for 'nr'
call g:Xsetlist([], 'f')
call g:Xsetlist([], 'a', {'title' : 'Test3', 'nr' : '$'})
call g:Xsetlist([], 'a', {'title' : 'Test4'})
let l = g:Xgetlist({'nr' : '$', 'all' : 1})
call assert_equal(1, l.nr)
call assert_equal('Test4', l.title)
" Adding a quickfix list should remove all the lists following the current
" list.
Xexpr "" | Xexpr "" | Xexpr ""
silent! 10Xolder
call g:Xsetlist([], ' ', {'title' : 'Test5'})
let l = g:Xgetlist({'nr' : '$', 'all' : 1})
call assert_equal(2, l.nr)
call assert_equal('Test5', l.title)
" Add a quickfix list using '$' as the list number.
let lastqf = g:Xgetlist({'nr':'$'}).nr
silent! 99Xolder
call g:Xsetlist([], ' ', {'nr' : '$', 'title' : 'Test6'})
let l = g:Xgetlist({'nr' : '$', 'all' : 1})
call assert_equal(lastqf + 1, l.nr)
call assert_equal('Test6', l.title)
" Add a quickfix list using 'nr' set to one more than the quickfix
" list size.
let lastqf = g:Xgetlist({'nr':'$'}).nr
silent! 99Xolder
call g:Xsetlist([], ' ', {'nr' : lastqf + 1, 'title' : 'Test7'})
let l = g:Xgetlist({'nr' : '$', 'all' : 1})
call assert_equal(lastqf + 1, l.nr)
call assert_equal('Test7', l.title)
" Add a quickfix list to a stack with 10 lists using 'nr' set to '$'
exe repeat('Xexpr "" |', 9) . 'Xexpr ""'
silent! 99Xolder
call g:Xsetlist([], ' ', {'nr' : '$', 'title' : 'Test8'})
let l = g:Xgetlist({'nr' : '$', 'all' : 1})
call assert_equal(10, l.nr)
call assert_equal('Test8', l.title)
" Add a quickfix list using 'nr' set to a value greater than 10
call assert_equal(-1, g:Xsetlist([], ' ', {'nr' : 12, 'title' : 'Test9'}))
" Try adding a quickfix list with 'nr' set to a value greater than the
" quickfix list size but less than 10.
call g:Xsetlist([], 'f')
Xexpr "" | Xexpr "" | Xexpr ""
silent! 99Xolder
call assert_equal(-1, g:Xsetlist([], ' ', {'nr' : 8, 'title' : 'Test10'}))
" Add a quickfix list using 'nr' set to a some string or list
call assert_equal(-1, g:Xsetlist([], ' ', {'nr' : [1,2], 'title' : 'Test11'}))
endfunc
func Test_add_qf()
call XaddQf_tests('c')
call XaddQf_tests('l')
endfunc

View File

@ -1859,20 +1859,18 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf,
return true;
}
/*
* Close window "win". Only works for the current tab page.
* If "free_buf" is TRUE related buffer may be unloaded.
*
* Called by :quit, :close, :xit, :wq and findtag().
* Returns FAIL when the window was not closed.
*/
int win_close(win_T *win, int free_buf)
// Close window "win". Only works for the current tab page.
// If "free_buf" is true related buffer may be unloaded.
//
// Called by :quit, :close, :xit, :wq and findtag().
// Returns FAIL when the window was not closed.
int win_close(win_T *win, bool free_buf)
{
win_T *wp;
int other_buffer = FALSE;
int close_curwin = FALSE;
int dir;
int help_window = FALSE;
bool help_window = false;
tabpage_T *prev_curtab = curtab;
frame_T *win_frame = win->w_frame->fr_parent;
@ -1902,10 +1900,11 @@ int win_close(win_T *win, int free_buf)
/* When closing the help window, try restoring a snapshot after closing
* the window. Otherwise clear the snapshot, it's now invalid. */
if (win->w_buffer != NULL && win->w_buffer->b_help)
help_window = TRUE;
else
if (bt_help(win->w_buffer)) {
help_window = true;
} else {
clear_snapshot(curtab, SNAP_HELP_IDX);
}
if (win == curwin) {
/*
@ -1967,10 +1966,11 @@ int win_close(win_T *win, int free_buf)
if (only_one_window() && win_valid(win) && win->w_buffer == NULL
&& (last_window() || curtab != prev_curtab
|| close_last_window_tabpage(win, free_buf, prev_curtab))) {
/* Autocommands have close all windows, quit now. Restore
* curwin->w_buffer, otherwise writing ShaDa file may fail. */
if (curwin->w_buffer == NULL)
// Autocommands have closed all windows, quit now. Restore
// curwin->w_buffer, otherwise writing ShaDa file may fail.
if (curwin->w_buffer == NULL) {
curwin->w_buffer = curbuf;
}
getout(0);
}
// Autocommands may have moved to another tab page.
@ -5341,7 +5341,7 @@ bool only_one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
int count = 0;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer != NULL
&& (!((wp->w_buffer->b_help && !curbuf->b_help)
&& (!((bt_help(wp->w_buffer) && !bt_help(curbuf))
|| wp->w_p_pvw) || wp == curwin) && wp != aucmd_win) {
count++;
}