Compare commits

...

15 Commits

Author SHA1 Message Date
Bram Moolenaar
3ff2f09525 patch 8.0.0497: arabic support is not fully tested
Problem:    Arabic support is not fully tested.
Solution:   Add more tests for the untested functions.  Comment out
            unreachable code.
2017-03-21 13:22:44 +01:00
Bram Moolenaar
518c9b133b patch 8.0.0496: insufficient testing for folding
Problem:    Insufficient testing for folding.
Solution:   Add a couple more fold tests. (Dominique Pelle, closes #1579)
2017-03-21 11:48:39 +01:00
Bram Moolenaar
f5610da7a8 patch 8.0.0495: quotestar test uses timer instead of timeout
Problem:    The quotestar test uses a timer instead of a timeout, thus it
            cannot be rerun like a flaky test.
Solution:   Remove the timer and add a timeout. (Kazunobu Kuriyama)
2017-03-20 21:47:16 +01:00
Bram Moolenaar
1662ce104e patch 8.0.0494: build failure with older compiler on MS-Windows
Problem:    Build failure with older compiler on MS-Windows.
Solution:   Move declaration to start of block.
2017-03-19 21:47:50 +01:00
Bram Moolenaar
15618fa643 patch 8.0.0493: crash with cd command with very long argument
Problem:    Crash with cd command with very long argument.
Solution:   Check for running out of space. (Dominique pending, closes #1576)
2017-03-19 21:37:13 +01:00
Bram Moolenaar
81b9d0bd5c patch 8.0.0492: a failing client-server request can make Vim hang
Problem:    A failing client-server request can make Vim hang.
Solution:   Add a timeout argument to functions that wait.
2017-03-19 21:20:53 +01:00
Bram Moolenaar
bfd830d3e2 patch 8.0.0491: quotestar test fails when features are missing
Problem:    The quotestar test fails when a required feature is missing.
Solution:   Prepend "Skipped" to the thrown exception.
2017-03-19 21:01:14 +01:00
Bram Moolenaar
38e3483637 patch 8.0.0490: vertical split makes 'winfixwidth' window smaller
Problem:    Splitting a 'winfixwidth' window vertically makes it one column
            smaller. (Dominique Pelle)
Solution:   Add one to the width for the separator.
2017-03-19 20:22:36 +01:00
Bram Moolenaar
7dd4850698 patch 8.0.0489: clipboard and "* register is not tested
Problem:    Clipboard and "* register is not tested.
Solution:   Add a test for Mac and X11. (Kazunobu Kuriyama)
2017-03-19 20:04:22 +01:00
Bram Moolenaar
b4c5572e74 patch 8.0.0488: running tests leaves an "xxx" file behind
Problem:    Running tests leaves an "xxx" file behind.
Solution:   Delete the 'verbosefile' after resetting the option.
2017-03-19 19:11:35 +01:00
Bram Moolenaar
651e4056ac patch 8.0.0487: the autocmd test hangs on MS-Windows
Problem:    The autocmd test hangs on MS-Windows.
Solution:   Skip the hanging tests for now.
2017-03-19 18:34:46 +01:00
Bram Moolenaar
8c752bd6c4 patch 8.0.0486: crash and endless loop when closing windows in autocmd
Problem:    Crash and endless loop when closing windows in a SessionLoadPost
            autocommand.
Solution:   Check for valid tabpage.  (partly neovim #6308)
2017-03-19 17:09:56 +01:00
Bram Moolenaar
4520d440c5 patch 8.0.0485: not all windows commands are tested
Problem:    Not all windows commands are tested.
Solution:   Add more tests for windows commands. (Dominique Pelle,
            closes #1575) Run test_autocmd separately, it interferes with
            other tests.  Fix tests that depended on side effects.
2017-03-19 16:09:46 +01:00
Bram Moolenaar
ee85df3763 patch 8.0.0484: :lhelpgrep does not fail after a successful one
Problem:    Using :lhelpgrep with an argument that should fail does not
            produce an error if the previous :helpgrep worked.
Solution:   Use another way to detect that autocommands made the quickfix info
            invalid. (Yegappan Lakshmanan)
2017-03-19 14:19:50 +01:00
Bram Moolenaar
f79225ed4f patch 8.0.0483: illegal memory access when using :all
Problem:    Illegal memory access when using :all. (Dominique Pelle)
Solution:   Adjust the cursor position right after setting "curwin".
2017-03-18 23:11:04 +01:00
31 changed files with 1111 additions and 145 deletions

View File

@@ -6320,15 +6320,17 @@ reltimestr({time}) *reltimestr()*
{only available when compiled with the |+reltime| feature}
*remote_expr()* *E449*
remote_expr({server}, {string} [, {idvar}])
remote_expr({server}, {string} [, {idvar} [, {timeout}]])
Send the {string} to {server}. The string is sent as an
expression and the result is returned after evaluation.
The result must be a String or a |List|. A |List| is turned
into a String by joining the items with a line break in
between (not at the end), like with join(expr, "\n").
If {idvar} is present, it is taken as the name of a
variable and a {serverid} for later use with
If {idvar} is present and not empty, it is taken as the name
of a variable and a {serverid} for later use with
remote_read() is stored there.
If {timeout} is given the read times out after this many
seconds. Otherwise a timeout of 600 seconds is used.
See also |clientserver| |RemoteReply|.
This function is not available in the |sandbox|.
{only available when compiled with the |+clientserver| feature}
@@ -6367,9 +6369,10 @@ remote_peek({serverid} [, {retvar}]) *remote_peek()*
:let repl = ""
:echo "PEEK: ".remote_peek(id, "repl").": ".repl
remote_read({serverid}) *remote_read()*
remote_read({serverid}, [{timeout}]) *remote_read()*
Return the oldest available reply from {serverid} and consume
it. It blocks until a reply is available.
it. Unless a {timeout} in seconds is given, it blocks until a
reply is available.
See also |clientserver|.
This function is not available in the |sandbox|.
{only available when compiled with the |+clientserver| feature}

View File

@@ -2096,6 +2096,7 @@ test_arglist \
test_backspace_opt \
test_breakindent \
test_bufwintabinfo \
test_cd \
test_cdo \
test_changedtick \
test_channel \
@@ -2185,6 +2186,7 @@ test_arglist \
test_pyx2 \
test_pyx3 \
test_quickfix \
test_quotestar \
test_recover \
test_regexp_latin \
test_regexp_utf8 \

View File

@@ -24,7 +24,9 @@ static int chg_c_a2s(int cur_c);
static int chg_c_a2i(int cur_c);
static int chg_c_a2m(int cur_c);
static int chg_c_a2f(int cur_c);
#if 0
static int chg_c_i2m(int cur_c);
#endif
static int chg_c_f2m(int cur_c);
static int chg_c_laa2i(int hid_c);
static int chg_c_laa2f(int hid_c);
@@ -418,7 +420,10 @@ chg_c_a2f(int cur_c)
/*
* Change shape - from Initial to Medial
* This code is unreachable, because for the relevant characters ARABIC_CHAR()
* is FALSE;
*/
#if 0
static int
chg_c_i2m(int cur_c)
{
@@ -450,6 +455,7 @@ chg_c_i2m(int cur_c)
}
return 0;
}
#endif
/*
@@ -608,7 +614,11 @@ arabic_shape(
else if (!shape_c || A_is_f(shape_c) || A_is_s(shape_c) || prev_laa)
curr_c = A_is_valid(next_c) ? chg_c_a2i(c) : chg_c_a2s(c);
else if (A_is_valid(next_c))
#if 0
curr_c = A_is_iso(c) ? chg_c_a2m(c) : chg_c_i2m(c);
#else
curr_c = A_is_iso(c) ? chg_c_a2m(c) : 0;
#endif
else if (A_is_valid(prev_c))
curr_c = chg_c_a2f(c);
else

View File

@@ -739,10 +739,10 @@ static struct fst
{"reltimefloat", 1, 1, f_reltimefloat},
#endif
{"reltimestr", 1, 1, f_reltimestr},
{"remote_expr", 2, 3, f_remote_expr},
{"remote_expr", 2, 4, f_remote_expr},
{"remote_foreground", 1, 1, f_remote_foreground},
{"remote_peek", 1, 2, f_remote_peek},
{"remote_read", 1, 1, f_remote_read},
{"remote_read", 1, 2, f_remote_read},
{"remote_send", 2, 3, f_remote_send},
{"remote_startserver", 1, 1, f_remote_startserver},
{"remove", 2, 3, f_remove},
@@ -8515,6 +8515,7 @@ remote_common(typval_T *argvars, typval_T *rettv, int expr)
char_u *keys;
char_u *r = NULL;
char_u buf[NUMBUFLEN];
int timeout = 0;
# ifdef WIN32
HWND w;
# else
@@ -8528,16 +8529,19 @@ remote_common(typval_T *argvars, typval_T *rettv, int expr)
if (check_connection() == FAIL)
return;
# endif
if (argvars[2].v_type != VAR_UNKNOWN
&& argvars[3].v_type != VAR_UNKNOWN)
timeout = get_tv_number(&argvars[3]);
server_name = get_tv_string_chk(&argvars[0]);
if (server_name == NULL)
return; /* type error; errmsg already given */
keys = get_tv_string_buf(&argvars[1], buf);
# ifdef WIN32
if (serverSendToVim(server_name, keys, &r, &w, expr, TRUE) < 0)
if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
# else
if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, 0, TRUE)
< 0)
if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
0, TRUE) < 0)
# endif
{
if (r != NULL)
@@ -8555,13 +8559,15 @@ remote_common(typval_T *argvars, typval_T *rettv, int expr)
char_u str[30];
char_u *idvar;
sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
v.di_tv.v_type = VAR_STRING;
v.di_tv.vval.v_string = vim_strsave(str);
idvar = get_tv_string_chk(&argvars[2]);
if (idvar != NULL)
if (idvar != NULL && *idvar != NUL)
{
sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
v.di_tv.v_type = VAR_STRING;
v.di_tv.vval.v_string = vim_strsave(str);
set_var(idvar, &v.di_tv, FALSE);
vim_free(v.di_tv.vval.v_string);
vim_free(v.di_tv.vval.v_string);
}
}
}
#endif
@@ -8633,7 +8639,7 @@ f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
rettv->vval.v_number = -1;
else
{
s = serverGetReply((HWND)n, FALSE, FALSE, FALSE);
s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
rettv->vval.v_number = (s != NULL);
}
# else
@@ -8670,17 +8676,24 @@ f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
if (serverid != NULL && !check_restricted() && !check_secure())
{
int timeout = 0;
# ifdef WIN32
/* The server's HWND is encoded in the 'id' parameter */
long_u n = 0;
# endif
if (argvars[1].v_type != VAR_UNKNOWN)
timeout = get_tv_number(&argvars[1]);
# ifdef WIN32
sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
if (n != 0)
r = serverGetReply((HWND)n, FALSE, TRUE, TRUE);
r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
if (r == NULL)
# else
if (check_connection() == FAIL || serverReadReply(X_DISPLAY,
serverStrToWin(serverid), &r, FALSE) < 0)
if (check_connection() == FAIL
|| serverReadReply(X_DISPLAY, serverStrToWin(serverid),
&r, FALSE, timeout) < 0)
# endif
EMSG(_("E277: Unable to read a server reply"));
}

View File

@@ -9033,6 +9033,11 @@ win_found:
win_remove(curwin, NULL);
aucmd_win_used = FALSE;
last_status(FALSE); /* may need to remove last status line */
if (!valid_tabpage_win(curtab))
/* no valid window in current tabpage */
close_tabpage(curtab);
restore_snapshot(SNAP_AUCMD_IDX, FALSE);
(void)win_comp_pos(); /* recompute window positions */
unblock_autocmds();

View File

@@ -373,6 +373,7 @@ serverSendToVim(
char_u **result, /* Result of eval'ed expression */
Window *server, /* Actual ID of receiving app */
Bool asExpr, /* Interpret as keystrokes or expr ? */
int timeout, /* seconds to wait or zero */
Bool localLoop, /* Throw away everything but result */
int silent) /* don't complain about no server */
{
@@ -485,7 +486,8 @@ serverSendToVim(
pending.nextPtr = pendingCommands;
pendingCommands = &pending;
ServerWait(dpy, w, WaitForPend, &pending, localLoop, 600);
ServerWait(dpy, w, WaitForPend, &pending, localLoop,
timeout > 0 ? timeout : 600);
/*
* Unregister the information about the pending command
@@ -790,6 +792,7 @@ WaitForReply(void *p)
/*
* Wait for replies from id (win)
* When "timeout" is non-zero wait up to this many seconds.
* Return 0 and the malloc'ed string when a reply is available.
* Return -1 if the window becomes invalid while waiting.
*/
@@ -798,13 +801,15 @@ serverReadReply(
Display *dpy,
Window win,
char_u **str,
int localLoop)
int localLoop,
int timeout)
{
int len;
char_u *s;
struct ServerReply *p;
ServerWait(dpy, win, WaitForReply, &win, localLoop, -1);
ServerWait(dpy, win, WaitForReply, &win, localLoop,
timeout > 0 ? timeout : -1);
if ((p = ServerReplyFind(win, SROP_Find)) != NULL && p->strings.ga_len > 0)
{

View File

@@ -3791,10 +3791,10 @@ cmdsrv_main(
}
else
ret = serverSendToVim(xterm_dpy, sname, *serverStr,
NULL, &srv, 0, 0, silent);
NULL, &srv, 0, 0, 0, silent);
# else
/* Win32 always works? */
ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, silent);
ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, 0, silent);
# endif
if (ret < 0)
{
@@ -3854,11 +3854,11 @@ cmdsrv_main(
while (memchr(done, 0, numFiles) != NULL)
{
# ifdef WIN32
p = serverGetReply(srv, NULL, TRUE, TRUE);
p = serverGetReply(srv, NULL, TRUE, TRUE, 0);
if (p == NULL)
break;
# else
if (serverReadReply(xterm_dpy, srv, &p, TRUE) < 0)
if (serverReadReply(xterm_dpy, srv, &p, TRUE, -1) < 0)
break;
# endif
j = atoi((char *)p);
@@ -3885,12 +3885,12 @@ cmdsrv_main(
# ifdef WIN32
/* Win32 always works? */
if (serverSendToVim(sname, (char_u *)argv[i + 1],
&res, NULL, 1, FALSE) < 0)
&res, NULL, 1, 0, FALSE) < 0)
# else
if (xterm_dpy == NULL)
mch_errmsg(_("No display: Send expression failed.\n"));
else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1],
&res, NULL, 1, 1, FALSE) < 0)
&res, NULL, 1, 0, 1, FALSE) < 0)
# endif
{
if (res != NULL && *res != NUL)
@@ -4194,7 +4194,7 @@ sendToLocalVim(char_u *cmd, int asExpr, char_u **result)
size_t len = STRLEN(cmd) + STRLEN(err) + 5;
char_u *msg;
msg = alloc(len);
msg = alloc((unsigned)len);
if (msg != NULL)
vim_snprintf((char *)msg, len, "%s: \"%s\"", err, cmd);
*result = msg;

View File

@@ -4637,13 +4637,23 @@ vim_findfile(void *search_ctx_arg)
if (!vim_isAbsName(stackp->ffs_fix_path)
&& search_ctx->ffsc_start_dir)
{
STRCPY(file_path, search_ctx->ffsc_start_dir);
add_pathsep(file_path);
if (STRLEN(search_ctx->ffsc_start_dir) + 1 < MAXPATHL)
{
STRCPY(file_path, search_ctx->ffsc_start_dir);
add_pathsep(file_path);
}
else
goto fail;
}
/* append the fix part of the search path */
STRCAT(file_path, stackp->ffs_fix_path);
add_pathsep(file_path);
if (STRLEN(file_path) + STRLEN(stackp->ffs_fix_path) + 1 < MAXPATHL)
{
STRCAT(file_path, stackp->ffs_fix_path);
add_pathsep(file_path);
}
else
goto fail;
#ifdef FEAT_PATH_EXTRA
rest_of_wildcards = stackp->ffs_wc_path;
@@ -4660,7 +4670,10 @@ vim_findfile(void *search_ctx_arg)
if (*p > 0)
{
(*p)--;
file_path[len++] = '*';
if (len + 1 < MAXPATHL)
file_path[len++] = '*';
else
goto fail;
}
if (*p == 0)
@@ -4688,7 +4701,10 @@ vim_findfile(void *search_ctx_arg)
*/
while (*rest_of_wildcards
&& !vim_ispathsep(*rest_of_wildcards))
file_path[len++] = *rest_of_wildcards++;
if (len + 1 < MAXPATHL)
file_path[len++] = *rest_of_wildcards++;
else
goto fail;
file_path[len] = NUL;
if (vim_ispathsep(*rest_of_wildcards))
@@ -4749,9 +4765,15 @@ vim_findfile(void *search_ctx_arg)
/* prepare the filename to be checked for existence
* below */
STRCPY(file_path, stackp->ffs_filearray[i]);
add_pathsep(file_path);
STRCAT(file_path, search_ctx->ffsc_file_to_search);
if (STRLEN(stackp->ffs_filearray[i]) + 1
+ STRLEN(search_ctx->ffsc_file_to_search) < MAXPATHL)
{
STRCPY(file_path, stackp->ffs_filearray[i]);
add_pathsep(file_path);
STRCAT(file_path, search_ctx->ffsc_file_to_search);
}
else
goto fail;
/*
* Try without extra suffix and then with suffixes
@@ -4924,9 +4946,15 @@ vim_findfile(void *search_ctx_arg)
if (*search_ctx->ffsc_start_dir == 0)
break;
STRCPY(file_path, search_ctx->ffsc_start_dir);
add_pathsep(file_path);
STRCAT(file_path, search_ctx->ffsc_fix_path);
if (STRLEN(search_ctx->ffsc_start_dir) + 1
+ STRLEN(search_ctx->ffsc_fix_path) < MAXPATHL)
{
STRCPY(file_path, search_ctx->ffsc_start_dir);
add_pathsep(file_path);
STRCAT(file_path, search_ctx->ffsc_fix_path);
}
else
goto fail;
/* create a new stack entry */
sptr = ff_create_stack_element(file_path,
@@ -4940,6 +4968,7 @@ vim_findfile(void *search_ctx_arg)
}
#endif
fail:
vim_free(file_path);
return NULL;
}

View File

@@ -2111,7 +2111,7 @@ Messaging_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
char *err = _(e_invexprmsg);
size_t len = STRLEN(str) + STRLEN(err) + 5;
res = alloc(len);
res = alloc((unsigned)len);
if (res != NULL)
vim_snprintf((char *)res, len, "%s: \"%s\"", err, str);
reply.dwData = COPYDATA_ERROR_RESULT;
@@ -2401,6 +2401,7 @@ serverSendToVim(
char_u **result, /* Result of eval'ed expression */
void *ptarget, /* HWND of server */
int asExpr, /* Expression or keys? */
int timeout, /* timeout in seconds or zero */
int silent) /* don't complain about no server */
{
HWND target;
@@ -2444,7 +2445,7 @@ serverSendToVim(
return -1;
if (asExpr)
retval = serverGetReply(target, &retcode, TRUE, TRUE);
retval = serverGetReply(target, &retcode, TRUE, TRUE, timeout);
if (result == NULL)
vim_free(retval);
@@ -2521,14 +2522,17 @@ save_reply(HWND server, char_u *reply, int expr)
* if "wait" is TRUE block until a message arrives (or the server exits).
*/
char_u *
serverGetReply(HWND server, int *expr_res, int remove, int wait)
serverGetReply(HWND server, int *expr_res, int remove, int wait, int timeout)
{
int i;
char_u *reply;
reply_T *rep;
int did_process = FALSE;
time_t start;
time_t now;
/* When waiting, loop until the message waiting for is received. */
time(&start);
for (;;)
{
/* Reset this here, in case a message arrives while we are going
@@ -2584,6 +2588,10 @@ serverGetReply(HWND server, int *expr_res, int remove, int wait)
#ifdef FEAT_TIMERS
check_due_timer();
#endif
time(&now);
if (timeout > 0 && (now - start) >= timeout)
break;
/* Wait for a SendMessage() call to us. This could be the reply
* we are waiting for. Use a timeout of a second, to catch the
* situation that the server died unexpectedly. */

View File

@@ -1,11 +1,11 @@
/* if_xcmdsrv.c */
int serverRegisterName(Display *dpy, char_u *name);
void serverChangeRegisteredWindow(Display *dpy, Window newwin);
int serverSendToVim(Display *dpy, char_u *name, char_u *cmd, char_u **result, Window *server, int asExpr, int localLoop, int silent);
int serverSendToVim(Display *dpy, char_u *name, char_u *cmd, char_u **result, Window *server, int asExpr, int timeout, int localLoop, int silent);
char_u *serverGetVimNames(Display *dpy);
Window serverStrToWin(char_u *str);
int serverSendReply(char_u *name, char_u *str);
int serverReadReply(Display *dpy, Window win, char_u **str, int localLoop);
int serverReadReply(Display *dpy, Window win, char_u **str, int localLoop, int timeout);
int serverPeekReply(Display *dpy, Window win, char_u **str);
void serverEventProc(Display *dpy, XEvent *eventPtr, int immediate);
void server_parse_messages(void);

View File

@@ -43,9 +43,9 @@ void serverInitMessaging(void);
void serverSetName(char_u *name);
char_u *serverGetVimNames(void);
int serverSendReply(char_u *name, char_u *reply);
int serverSendToVim(char_u *name, char_u *cmd, char_u **result, void *ptarget, int asExpr, int silent);
int serverSendToVim(char_u *name, char_u *cmd, char_u **result, void *ptarget, int asExpr, int timeout, int silent);
void serverForeground(char_u *name);
char_u *serverGetReply(HWND server, int *expr_res, int remove, int wait);
char_u *serverGetReply(HWND server, int *expr_res, int remove, int wait, int timeout);
void serverProcessPendingMessages(void);
char *charset_id2name(int id);
char *quality_id2name(DWORD id);

View File

@@ -26,6 +26,8 @@ int win_new_tabpage(int after);
int may_open_tabpage(void);
int make_tabpages(int maxcount);
int valid_tabpage(tabpage_T *tpc);
int valid_tabpage_win(tabpage_T *tpc);
void close_tabpage(tabpage_T *tpc);
tabpage_T *find_tabpage(int n);
int tabpage_index(tabpage_T *ftp);
void goto_tabpage(int n);

View File

@@ -5077,6 +5077,7 @@ ex_helpgrep(exarg_T *eap)
char_u *lang;
#endif
qf_info_T *qi = &ql_info;
qf_info_T *save_qi;
int new_qi = FALSE;
win_T *wp;
#ifdef FEAT_AUTOCMD
@@ -5130,6 +5131,9 @@ ex_helpgrep(exarg_T *eap)
}
}
/* Autocommands may change the list. Save it for later comparison */
save_qi = qi;
regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING);
regmatch.rm_ic = FALSE;
if (regmatch.regprog != NULL)
@@ -5262,7 +5266,7 @@ ex_helpgrep(exarg_T *eap)
{
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
curbuf->b_fname, TRUE, curbuf);
if (!new_qi && qi != &ql_info && qf_find_buf(qi) == NULL)
if (!new_qi && qi != save_qi && qf_find_buf(qi) == NULL)
/* autocommands made "qi" invalid */
return;
}

View File

@@ -137,6 +137,7 @@ NEW_TESTS = test_arabic.res \
test_arglist.res \
test_assert.res \
test_autochdir.res \
test_autocmd.res \
test_backspace_opt.res \
test_breakindent.res \
test_bufwintabinfo.res \
@@ -193,6 +194,7 @@ NEW_TESTS = test_arabic.res \
test_pyx2.res \
test_pyx3.res \
test_quickfix.res \
test_quotestar.res \
test_retab.res \
test_ruby.res \
test_search.res \

View File

@@ -175,10 +175,6 @@ while 1
for val in a[0]
call add(script, 'set ' . name . '=' . val)
call add(script, 'set ' . shortname . '=' . val)
if name == 'verbosefile' && !empty(val)
call add(script, 'call delete("'. val. '")')
endif
endfor
" setting an option can only fail when it's implemented.
@@ -192,6 +188,9 @@ while 1
call add(script, 'set ' . name . '&')
call add(script, 'set ' . shortname . '&')
if name == 'verbosefile'
call add(script, 'call delete("xxx")')
endif
if name == 'more'
call add(script, 'set nomore')

View File

@@ -228,6 +228,7 @@ let s:flaky = [
\ 'Test_pipe_through_sort_all()',
\ 'Test_pipe_through_sort_some()',
\ 'Test_quoteplus()',
\ 'Test_quotestar()',
\ 'Test_reltime()',
\ ]

View File

@@ -3,7 +3,7 @@
set belloff=all
source test_assign.vim
source test_autocmd.vim
source test_cd.vim
source test_changedtick.vim
source test_cursor_func.vim
source test_delete.vim

View File

@@ -1,4 +1,6 @@
" Simplistic testing of Arabic mode.
" NOTE: This just checks if the code works. If you know Arabic please add
" functional tests that check the shaping works with real text.
if !has('arabic') || !has('multi_byte')
finish
@@ -417,7 +419,7 @@ func Test_shape_isolated()
bwipe!
endfunc
func Test_shape_medial()
func Test_shape_iso_to_medial()
new
set arabicshape
@@ -470,3 +472,142 @@ func Test_shape_medial()
bwipe!
endfunc
func Test_shape_final()
new
set arabicshape
" Shaping arabic {testchar} arabic Tests chg_c_a2f().
" pair[0] = testchar, pair[1] = current-result, pair[2] = previous-result
for pair in [[s:a_HAMZA, s:a_s_HAMZA, s:a_s_BEH],
\[s:a_ALEF_MADDA, s:a_f_ALEF_MADDA, s:a_i_BEH],
\[s:a_ALEF_HAMZA_ABOVE, s:a_f_ALEF_HAMZA_ABOVE, s:a_i_BEH],
\[s:a_WAW_HAMZA, s:a_f_WAW_HAMZA, s:a_i_BEH],
\[s:a_ALEF_HAMZA_BELOW, s:a_f_ALEF_HAMZA_BELOW, s:a_i_BEH],
\[s:a_YEH_HAMZA, s:a_f_YEH_HAMZA, s:a_i_BEH],
\[s:a_ALEF, s:a_f_ALEF, s:a_i_BEH],
\[s:a_BEH, s:a_f_BEH, s:a_i_BEH],
\[s:a_TEH_MARBUTA, s:a_f_TEH_MARBUTA, s:a_i_BEH],
\[s:a_TEH, s:a_f_TEH, s:a_i_BEH],
\[s:a_THEH, s:a_f_THEH, s:a_i_BEH],
\[s:a_JEEM, s:a_f_JEEM, s:a_i_BEH],
\[s:a_HAH, s:a_f_HAH, s:a_i_BEH],
\[s:a_KHAH, s:a_f_KHAH, s:a_i_BEH],
\[s:a_DAL, s:a_f_DAL, s:a_i_BEH],
\[s:a_THAL, s:a_f_THAL, s:a_i_BEH],
\[s:a_REH, s:a_f_REH, s:a_i_BEH],
\[s:a_ZAIN, s:a_f_ZAIN, s:a_i_BEH],
\[s:a_SEEN, s:a_f_SEEN, s:a_i_BEH],
\[s:a_SHEEN, s:a_f_SHEEN, s:a_i_BEH],
\[s:a_SAD, s:a_f_SAD, s:a_i_BEH],
\[s:a_DAD, s:a_f_DAD, s:a_i_BEH],
\[s:a_TAH, s:a_f_TAH, s:a_i_BEH],
\[s:a_ZAH, s:a_f_ZAH, s:a_i_BEH],
\[s:a_AIN, s:a_f_AIN, s:a_i_BEH],
\[s:a_GHAIN, s:a_f_GHAIN, s:a_i_BEH],
\[s:a_TATWEEL, s:a_TATWEEL, s:a_i_BEH],
\[s:a_FEH, s:a_f_FEH, s:a_i_BEH],
\[s:a_QAF, s:a_f_QAF, s:a_i_BEH],
\[s:a_KAF, s:a_f_KAF, s:a_i_BEH],
\[s:a_LAM, s:a_f_LAM, s:a_i_BEH],
\[s:a_MEEM, s:a_f_MEEM, s:a_i_BEH],
\[s:a_NOON, s:a_f_NOON, s:a_i_BEH],
\[s:a_HEH, s:a_f_HEH, s:a_i_BEH],
\[s:a_WAW, s:a_f_WAW, s:a_i_BEH],
\[s:a_ALEF_MAKSURA, s:a_f_ALEF_MAKSURA, s:a_i_BEH],
\[s:a_YEH, s:a_f_YEH, s:a_i_BEH],
\ ]
call setline(1, ' ' . pair[0] . s:a_BEH)
call assert_equal([' ' . pair[1] . pair[2]], ScreenLines(1, 3))
endfor
set arabicshape&
bwipe!
endfunc
func Test_shape_final_to_medial()
new
set arabicshape
" Shaping arabic {testchar} arabic Tests chg_c_f2m().
" This does not test much...
" pair[0] = testchar, pair[1] = current-result
for pair in [[s:a_f_YEH_HAMZA, s:a_f_BEH],
\[s:a_f_WAW_HAMZA, s:a_s_BEH],
\[s:a_f_ALEF, s:a_s_BEH],
\[s:a_f_TEH_MARBUTA, s:a_s_BEH],
\[s:a_f_DAL, s:a_s_BEH],
\[s:a_f_THAL, s:a_s_BEH],
\[s:a_f_REH, s:a_s_BEH],
\[s:a_f_ZAIN, s:a_s_BEH],
\[s:a_f_WAW, s:a_s_BEH],
\[s:a_f_ALEF_MAKSURA, s:a_s_BEH],
\[s:a_f_BEH, s:a_f_BEH],
\[s:a_f_TEH, s:a_f_BEH],
\[s:a_f_THEH, s:a_f_BEH],
\[s:a_f_JEEM, s:a_f_BEH],
\[s:a_f_HAH, s:a_f_BEH],
\[s:a_f_KHAH, s:a_f_BEH],
\[s:a_f_SEEN, s:a_f_BEH],
\[s:a_f_SHEEN, s:a_f_BEH],
\[s:a_f_SAD, s:a_f_BEH],
\[s:a_f_DAD, s:a_f_BEH],
\[s:a_f_TAH, s:a_f_BEH],
\[s:a_f_ZAH, s:a_f_BEH],
\[s:a_f_AIN, s:a_f_BEH],
\[s:a_f_GHAIN, s:a_f_BEH],
\[s:a_f_FEH, s:a_f_BEH],
\[s:a_f_QAF, s:a_f_BEH],
\[s:a_f_KAF, s:a_f_BEH],
\[s:a_f_LAM, s:a_f_BEH],
\[s:a_f_MEEM, s:a_f_BEH],
\[s:a_f_NOON, s:a_f_BEH],
\[s:a_f_HEH, s:a_f_BEH],
\[s:a_f_YEH, s:a_f_BEH],
\ ]
call setline(1, ' ' . s:a_BEH . pair[0])
call assert_equal([' ' . pair[1] . pair[0]], ScreenLines(1, 3))
endfor
set arabicshape&
bwipe!
endfunc
func Test_shape_combination_final()
new
set arabicshape
" Shaping arabic {testchar} arabic Tests chg_c_laa2f().
" pair[0] = testchar, pair[1] = current-result
for pair in [[s:a_ALEF_MADDA, s:a_f_LAM_ALEF_MADDA_ABOVE],
\ [s:a_ALEF_HAMZA_ABOVE, s:a_f_LAM_ALEF_HAMZA_ABOVE],
\ [s:a_ALEF_HAMZA_BELOW, s:a_f_LAM_ALEF_HAMZA_BELOW],
\ [s:a_ALEF, s:a_f_LAM_ALEF],
\ ]
" The test char is a composing char, put on s:a_LAM.
call setline(1, ' ' . s:a_LAM . pair[0] . s:a_BEH)
call assert_equal([' ' . pair[1] . s:a_i_BEH], ScreenLines(1, 3))
endfor
set arabicshape&
bwipe!
endfunc
func Test_shape_combination_isolated()
new
set arabicshape
" Shaping arabic {testchar} arabic Tests chg_c_laa2i().
" pair[0] = testchar, pair[1] = current-result
for pair in [[s:a_ALEF_MADDA, s:a_s_LAM_ALEF_MADDA_ABOVE],
\ [s:a_ALEF_HAMZA_ABOVE, s:a_s_LAM_ALEF_HAMZA_ABOVE],
\ [s:a_ALEF_HAMZA_BELOW, s:a_s_LAM_ALEF_HAMZA_BELOW],
\ [s:a_ALEF, s:a_s_LAM_ALEF],
\ ]
" The test char is a composing char, put on s:a_LAM.
call setline(1, ' ' . s:a_LAM . pair[0] . ' ')
call assert_equal([' ' . pair[1] . ' '], ScreenLines(1, 3))
endfor
set arabicshape&
bwipe!
endfunc

View File

@@ -1,5 +1,7 @@
" Tests for autocommands
set belloff=all
function! s:cleanup_buffers() abort
for bnr in range(1, bufnr('$'))
if bufloaded(bnr) && bufnr('%') != bnr
@@ -318,6 +320,8 @@ func Test_three_windows()
call assert_equal('Xanother', expand('%'))
au!
enew
bwipe! Xtestje1
call delete('Xtestje1')
call delete('Xtestje2')
call delete('Xtestje3')
@@ -341,3 +345,72 @@ func Test_BufEnter()
call delete('Xdir', 'd')
au! BufEnter
endfunc
" Closing a window might cause an endless loop
" E814 for older Vims
function Test_autocmd_bufwipe_in_SessLoadPost()
if has('win32')
throw 'Skipped: test hangs on MS-Windows'
endif
tabnew
set noswapfile
let g:bufnr=bufnr('%')
mksession!
let content=['set nocp noswapfile',
\ 'let v:swapchoice="e"',
\ 'augroup test_autocmd_sessionload',
\ 'autocmd!',
\ 'autocmd SessionLoadPost * 4bw!',
\ 'augroup END'
\ ]
call writefile(content, 'Xvimrc')
let a=system(v:progpath. ' -u Xvimrc --noplugins -S Session.vim')
call assert_match('E814', a)
unlet! g:bufnr
set swapfile
for file in ['Session.vim', 'Xvimrc']
call delete(file)
endfor
endfunc
" SEGV occurs in older versions.
function Test_autocmd_bufwipe_in_SessLoadPost2()
if has('win32')
throw 'Skipped: test hangs on MS-Windows'
endif
tabnew
set noswapfile
let g:bufnr=bufnr('%')
mksession!
let content = ['set nocp noswapfile',
\ 'function! DeleteInactiveBufs()',
\ ' tabfirst',
\ ' let tabblist = []',
\ ' for i in range(1, tabpagenr(''$''))',
\ ' call extend(tabblist, tabpagebuflist(i))',
\ ' endfor',
\ ' for b in range(1, bufnr(''$''))',
\ ' if bufexists(b) && buflisted(b) && (index(tabblist, b) == -1 || bufname(b) =~# ''^$'')',
\ ' exec ''bwipeout '' . b',
\ ' endif',
\ ' endfor',
\ 'call append("1", "SessionLoadPost DONE")',
\ 'endfunction',
\ 'au SessionLoadPost * call DeleteInactiveBufs()']
call writefile(content, 'Xvimrc')
let a=system(v:progpath. ' -u Xvimrc --noplugins -S Session.vim')
" this probably only matches on unix
if has("unix")
call assert_notmatch('Caught deadly signal SEGV', a)
endif
call assert_match('SessionLoadPost DONE', a)
unlet! g:bufnr
set swapfile
for file in ['Session.vim', 'Xvimrc']
call delete(file)
endfor
endfunc

13
src/testdir/test_cd.vim Normal file
View File

@@ -0,0 +1,13 @@
" Test for :cd
func Test_cd_large_path()
" This used to crash with a heap write overflow.
call assert_fails('cd ' . repeat('x', 5000), 'E472:')
endfunc
func Test_cd_up_and_down()
let path = getcwd()
cd ..
exe 'cd ' . path
call assert_equal(path, getcwd())
endfunc

View File

@@ -6,22 +6,12 @@ endif
source shared.vim
let s:where = 0
func Abort(id)
call assert_report('Test timed out at ' . s:where)
call FinishTesting()
endfunc
func Test_client_server()
let cmd = GetVimCommand()
if cmd == ''
return
endif
" Some of these commands may hang when failing.
call timer_start(10000, 'Abort')
let s:where = 1
let name = 'XVIMTEST'
let cmd .= ' --servername ' . name
let g:job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
@@ -30,62 +20,53 @@ func Test_client_server()
call assert_report('Cannot run the Vim server')
return
endif
let s:where = 2
" Takes a short while for the server to be active.
call WaitFor('serverlist() =~ "' . name . '"')
call assert_match(name, serverlist())
let s:where = 3
call remote_foreground(name)
let s:where = 4
call remote_send(name, ":let testvar = 'yes'\<CR>")
let s:where = 5
call WaitFor('remote_expr("' . name . '", "testvar") == "yes"')
let s:where = 6
call assert_equal('yes', remote_expr(name, "testvar"))
let s:where = 7
call WaitFor('remote_expr("' . name . '", "testvar", "", 1) == "yes"')
call assert_equal('yes', remote_expr(name, "testvar", "", 2))
if has('unix') && has('gui') && !has('gui_running')
" Running in a terminal and the GUI is avaiable: Tell the server to open
" the GUI and check that the remote command still works.
" Need to wait for the GUI to start up, otherwise the send hangs in trying
" to send to the terminal window.
call remote_send(name, ":gui -f\<CR>")
let s:where = 8
sleep 500m
if has('gui_athena') || has('gui_motif')
" For those GUIs, ignore the 'failed to create input context' error.
call remote_send(name, ":call test_ignore_error('E285') | gui -f\<CR>")
else
call remote_send(name, ":gui -f\<CR>")
endif
" Wait for the server to be up and answering requests.
call WaitFor('remote_expr("' . name . '", "v:version", "", 1) != ""')
call remote_send(name, ":let testvar = 'maybe'\<CR>")
let s:where = 9
call WaitFor('remote_expr("' . name . '", "testvar") == "maybe"')
let s:where = 10
call assert_equal('maybe', remote_expr(name, "testvar"))
let s:where = 11
call WaitFor('remote_expr("' . name . '", "testvar", "", 1) == "maybe"')
call assert_equal('maybe', remote_expr(name, "testvar", "", 2))
endif
call assert_fails('call remote_send("XXX", ":let testvar = ''yes''\<CR>")', 'E241')
let s:where = 12
" Expression evaluated locally.
if v:servername == ''
call remote_startserver('MYSELF')
let s:where = 13
call assert_equal('MYSELF', v:servername)
" May get MYSELF1 when running the test again.
call assert_match('MYSELF', v:servername)
endif
let g:testvar = 'myself'
call assert_equal('myself', remote_expr(v:servername, 'testvar'))
let s:where = 14
call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid')
let s:where = 15
call assert_equal('got it', remote_read(g:myserverid))
let s:where = 16
call assert_equal('got it', remote_read(g:myserverid, 2))
call remote_send(name, ":call server2client(expand('<client>'), 'another')\<CR>", 'g:myserverid')
let s:where = 151
let peek_result = 'nothing'
let r = remote_peek(g:myserverid, 'peek_result')
let s:where = 161
" unpredictable whether the result is already avaialble.
if r > 0
call assert_equal('another', peek_result)
@@ -96,16 +77,11 @@ func Test_client_server()
endif
let g:peek_result = 'empty'
call WaitFor('remote_peek(g:myserverid, "g:peek_result") > 0')
let s:where = 171
call assert_equal('another', g:peek_result)
let s:where = 181
call assert_equal('another', remote_read(g:myserverid))
let s:where = 191
call assert_equal('another', remote_read(g:myserverid, 2))
call remote_send(name, ":qa!\<CR>")
let s:where = 17
call WaitFor('job_status(g:job) == "dead"')
let s:where = 18
if job_status(g:job) != 'dead'
call assert_report('Server did not exit')
call job_stop(g:job, 'kill')

View File

@@ -8,6 +8,7 @@ func Test_file_delete()
call assert_equal(0, delete('Xfile'))
call assert_fails('call readfile("Xfile")', 'E484:')
call assert_equal(-1, delete('Xfile'))
bwipe Xfile
endfunc
func Test_dir_delete()
@@ -35,6 +36,8 @@ func Test_recursive_delete()
call assert_equal(0, delete('Xdir1', 'rf'))
call assert_false(isdirectory('Xdir1'))
call assert_equal(-1, delete('Xdir1', 'd'))
bwipe Xdir1/Xfile
bwipe Xdir1/subdir/Xfile
endfunc
func Test_symlink_delete()
@@ -49,6 +52,7 @@ func Test_symlink_delete()
call assert_equal(0, delete('Xlink'))
call assert_equal(-1, delete('Xlink'))
call assert_equal(0, delete('Xfile'))
bwipe Xfile
endfunc
func Test_symlink_dir_delete()
@@ -96,4 +100,8 @@ func Test_symlink_recursive_delete()
call assert_equal(['a', 'b'], readfile('Xdir4/Xfile'))
call assert_equal(0, delete('Xdir4/Xfile'))
call assert_equal(0, delete('Xdir4', 'd'))
bwipe Xdir3/Xfile
bwipe Xdir3/subdir/Xfile
bwipe Xdir4/Xfile
endfunc

View File

@@ -33,8 +33,8 @@ func Test_fnamemodify()
call assert_equal('''abc"%"def''', fnamemodify('abc"%"def', ':S'))
call assert_equal('''abc''\'''' ''\''''def''', fnamemodify('abc'' ''def', ':S'))
call assert_equal('''abc''\''''%''\''''def''', fnamemodify('abc''%''def', ':S'))
call assert_equal(expand('%:r:S'), shellescape(expand('%:r')))
sp test_alot.vim
call assert_equal(expand('%:r:S'), shellescape(expand('%:r')))
call assert_equal('test_alot,''test_alot'',test_alot.vim', join([expand('%:r'), expand('%:r:S'), expand('%')], ','))
quit

View File

@@ -9,8 +9,8 @@ func! Test_address_fold()
call setline(1, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
\ 'after fold 1', 'after fold 2', 'after fold 3'])
setl fen fdm=marker
" The next ccommands should all copy the same part of the buffer,
" regardless of the adressing type, since the part to be copied
" The next commands should all copy the same part of the buffer,
" regardless of the addressing type, since the part to be copied
" is folded away
:1y
call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1))
@@ -360,3 +360,56 @@ func! Test_move_folds_around_indent()
call assert_equal([0, 1, 1, 1, 1, 0, 0, 0, 1, 1], map(range(1, line('$')), 'foldlevel(v:val)'))
bw!
endfunc
func Test_folddoopen_folddoclosed()
new
call setline(1, range(1, 9))
set foldmethod=manual
1,3 fold
6,8 fold
" Test without range.
folddoopen s/$/o/
folddoclosed s/$/c/
call assert_equal(['1c', '2c', '3c',
\ '4o', '5o',
\ '6c', '7c', '8c',
\ '9o'], getline(1, '$'))
" Test with range.
call setline(1, range(1, 9))
1,8 folddoopen s/$/o/
4,$ folddoclosed s/$/c/
call assert_equal(['1', '2', '3',
\ '4o', '5o',
\ '6c', '7c', '8c',
\ '9'], getline(1, '$'))
set foldmethod&
bw!
endfunc
func Test_fold_error()
new
call setline(1, [1, 2])
for fm in ['indent', 'expr', 'syntax', 'diff']
exe 'set foldmethod=' . fm
call assert_fails('norm zf', 'E350:')
call assert_fails('norm zd', 'E351:')
call assert_fails('norm zE', 'E352:')
endfor
set foldmethod=manual
call assert_fails('norm zd', 'E490:')
call assert_fails('norm zo', 'E490:')
call assert_fails('3fold', 'E16:')
set foldmethod=marker
set nomodifiable
call assert_fails('1,2fold', 'E21:')
set modifiable&
set foldmethod&
bw!
endfunc

View File

@@ -460,8 +460,8 @@ func Test_getbufvar()
let bd = getbufvar(bnr, '',def_num)
call assert_equal(1, len(bd))
call assert_equal('', getbufvar(9, ''))
call assert_equal(def_num, getbufvar(9, '', def_num))
call assert_equal('', getbufvar(9999, ''))
call assert_equal(def_num, getbufvar(9999, '', def_num))
unlet def_num
call assert_equal(0, getbufvar(bnr, '&autoindent'))

View File

@@ -31,7 +31,8 @@ func s:setup_commands(cchar)
command! -nargs=* -bang Xnfile <mods>cnfile<bang> <args>
command! -nargs=* -bang Xpfile <mods>cpfile<bang> <args>
command! -nargs=* Xexpr <mods>cexpr <args>
command! -nargs=* Xvimgrep <mods>vimgrep <args>
command! -range -nargs=* Xvimgrep <mods><count>vimgrep <args>
command! -nargs=* Xvimgrepadd <mods>vimgrepadd <args>
command! -nargs=* Xgrep <mods> grep <args>
command! -nargs=* Xgrepadd <mods> grepadd <args>
command! -nargs=* Xhelpgrep helpgrep <args>
@@ -61,7 +62,8 @@ func s:setup_commands(cchar)
command! -nargs=* -bang Xnfile <mods>lnfile<bang> <args>
command! -nargs=* -bang Xpfile <mods>lpfile<bang> <args>
command! -nargs=* Xexpr <mods>lexpr <args>
command! -nargs=* Xvimgrep <mods>lvimgrep <args>
command! -range -nargs=* Xvimgrep <mods><count>lvimgrep <args>
command! -nargs=* Xvimgrepadd <mods>lvimgrepadd <args>
command! -nargs=* Xgrep <mods> lgrep <args>
command! -nargs=* Xgrepadd <mods> lgrepadd <args>
command! -nargs=* Xhelpgrep lhelpgrep <args>
@@ -85,57 +87,52 @@ func XlistTests(cchar)
\ 'non-error 3', 'Xtestfile3:3:1:Line3']
" List only valid entries
redir => result
Xlist
redir END
let l = split(result, "\n")
let l = split(execute('Xlist', ''), "\n")
call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
\ ' 4 Xtestfile2:2 col 2: Line2',
\ ' 6 Xtestfile3:3 col 1: Line3'], l)
" List all the entries
redir => result
Xlist!
redir END
let l = split(result, "\n")
let l = split(execute('Xlist!', ''), "\n")
call assert_equal([' 1: non-error 1', ' 2 Xtestfile1:1 col 3: Line1',
\ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2',
\ ' 5: non-error 3', ' 6 Xtestfile3:3 col 1: Line3'], l)
" List a range of errors
redir => result
Xlist 3,6
redir END
let l = split(result, "\n")
let l = split(execute('Xlist 3,6', ''), "\n")
call assert_equal([' 4 Xtestfile2:2 col 2: Line2',
\ ' 6 Xtestfile3:3 col 1: Line3'], l)
redir => result
Xlist! 3,4
redir END
let l = split(result, "\n")
let l = split(execute('Xlist! 3,4', ''), "\n")
call assert_equal([' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
redir => result
Xlist -6,-4
redir END
let l = split(result, "\n")
let l = split(execute('Xlist -6,-4', ''), "\n")
call assert_equal([' 2 Xtestfile1:1 col 3: Line1'], l)
redir => result
Xlist! -5,-3
redir END
let l = split(result, "\n")
let l = split(execute('Xlist! -5,-3', ''), "\n")
call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
\ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
" Test for '+'
redir => result
Xlist! +2
redir END
let l = split(result, "\n")
let l = split(execute('Xlist! +2', ''), "\n")
call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
\ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
" Different types of errors
call g:Xsetlist([{'lnum':10,'col':5,'type':'W', 'text':'Warning','nr':11},
\ {'lnum':20,'col':10,'type':'e','text':'Error','nr':22},
\ {'lnum':30,'col':15,'type':'i','text':'Info','nr':33},
\ {'lnum':40,'col':20,'type':'x', 'text':'Other','nr':44},
\ {'lnum':50,'col':25,'type':"\<C-A>",'text':'one','nr':55}])
let l = split(execute('Xlist', ""), "\n")
call assert_equal([' 1:10 col 5 warning 11: Warning',
\ ' 2:20 col 10 error 22: Error',
\ ' 3:30 col 15 info 33: Info',
\ ' 4:40 col 20 x 44: Other',
\ ' 5:50 col 25 55: one'], l)
" Error cases
call assert_fails('Xlist abc', 'E488:')
endfunc
func Test_clist()
@@ -324,6 +321,23 @@ func XbufferTests(cchar)
\ l[3].lnum == 750 && l[3].col == 25 && l[3].text ==# 'Line 750')
enew!
" Check for invalid buffer
call assert_fails('Xbuffer 199', 'E474:')
" Check for unloaded buffer
edit Xtestfile1
let bnr = bufnr('%')
enew!
call assert_fails('Xbuffer ' . bnr, 'E681:')
" Check for invalid range
" Using Xbuffer will not run the range check in the cbuffer/lbuffer
" commands. So directly call the commands.
if (a:cchar == 'c')
call assert_fails('900,999cbuffer', 'E16:')
else
call assert_fails('900,999lbuffer', 'E16:')
endif
endfunc
func Test_cbuffer()
@@ -372,6 +386,9 @@ func Xtest_browse(cchar)
call assert_equal('Xqftestfile1', bufname('%'))
call assert_equal(5, line('.'))
Xexpr ""
call assert_fails('Xnext', 'E42:')
call delete('Xqftestfile1')
call delete('Xqftestfile2')
endfunc
@@ -411,6 +428,9 @@ func s:test_xhelpgrep(cchar)
call assert_true(w:quickfix_title =~ title_text, w:quickfix_title)
" This wipes out the buffer, make sure that doesn't cause trouble.
Xclose
" Search for non existing help string
call assert_fails('Xhelpgrep a1b2c3', 'E480:')
endfunc
func Test_helpgrep()
@@ -604,7 +624,7 @@ func Test_locationlist()
wincmd n | only
augroup! testgroup
endfunc
endfunc
func Test_locationlist_curwin_was_closed()
augroup testgroup
@@ -623,7 +643,7 @@ func Test_locationlist_curwin_was_closed()
call assert_fails('lrewind', 'E924:')
augroup! testgroup
endfunc
endfunc
func Test_locationlist_cross_tab_jump()
call writefile(['loclistfoo'], 'loclistfoo')
@@ -760,7 +780,7 @@ func Test_efm1()
call delete('Xerrorfile1')
call delete('Xerrorfile2')
call delete('Xtestfile')
endfunc
endfunc
" Test for quickfix directory stack support
func s:dir_stack_tests(cchar)
@@ -919,20 +939,26 @@ func Test_efm2()
call assert_equal(l[0].pattern, '^\VLine search text\$')
call assert_equal(l[0].lnum, 0)
let l = split(execute('clist', ''), "\n")
call assert_equal([' 1 Xtestfile:^\VLine search text\$: '], l)
" Test for %P, %Q and %t format specifiers
let lines=["[Xtestfile1]",
\ "(1,17) error: ';' missing",
\ "(21,2) warning: variable 'z' not defined",
\ "(67,3) error: end of file found before string ended",
\ "--",
\ "",
\ "[Xtestfile2]",
\ "--",
\ "",
\ "[Xtestfile3]",
\ "NEW compiler v1.1",
\ "(2,2) warning: variable 'x' not defined",
\ "(67,3) warning: 's' already defined"
\ "(67,3) warning: 's' already defined",
\ "--"
\]
set efm=%+P[%f],(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%-Q
set efm=%+P[%f]%r,(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%+Q--%r
" To exercise the push/pop file functionality in quickfix, the test files
" need to be created.
call writefile(['Line1'], 'Xtestfile1')
@@ -943,7 +969,7 @@ func Test_efm2()
caddexpr l
endfor
let l = getqflist()
call assert_equal(9, len(l))
call assert_equal(12, len(l))
call assert_equal(21, l[2].lnum)
call assert_equal(2, l[2].col)
call assert_equal('w', l[2].type)
@@ -1098,6 +1124,13 @@ func SetXlistTests(cchar, bnum)
call g:Xsetlist([])
let l = g:Xgetlist()
call assert_equal(0, len(l))
" Error cases:
" Refer to a non-existing buffer and pass a non-dictionary type
call assert_fails("call g:Xsetlist([{'bufnr':998, 'lnum':4}," .
\ " {'bufnr':999, 'lnum':5}])", 'E92:')
call g:Xsetlist([[1, 2,3]])
call assert_equal(0, len(g:Xgetlist()))
endfunc
func Test_setqflist()
@@ -1116,7 +1149,8 @@ func Xlist_empty_middle(cchar)
call s:setup_commands(a:cchar)
" create three quickfix lists
Xvimgrep Test_ test_quickfix.vim
let @/ = 'Test_'
Xvimgrep // test_quickfix.vim
let testlen = len(g:Xgetlist())
call assert_true(testlen > 0)
Xvimgrep empty test_quickfix.vim
@@ -1609,6 +1643,22 @@ func Xproperty_tests(cchar)
call g:Xsetlist([], ' ', {'title' : 'N3'})
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 assert_equal('NewTitle', g:Xgetlist({'nr':2, 'title':1}).title)
" Changing the title of an invalid quickfix list
call assert_equal(-1, g:Xsetlist([], ' ',
\ {'title' : 'SomeTitle', 'nr' : 99}))
call assert_equal(-1, g:Xsetlist([], ' ',
\ {'title' : 'SomeTitle', 'nr' : 'abc'}))
if a:cchar == 'c'
copen
call assert_equal({'winid':win_getid()}, getqflist({'winid':1}))
cclose
endif
" Invalid arguments
call assert_fails('call g:Xgetlist([])', 'E715')
call assert_fails('call g:Xsetlist([], "a", [])', 'E715')
@@ -1616,16 +1666,18 @@ func Xproperty_tests(cchar)
call assert_equal(-1, s)
call assert_equal({}, g:Xgetlist({'abc':1}))
call assert_equal({}, g:Xgetlist({'nr':99, 'title':1}))
call assert_equal({}, g:Xgetlist({'nr':[], 'title':1}))
if a:cchar == 'l'
call assert_equal({}, getloclist(99, {'title': 1}))
endif
endfunc
endfunc
func Test_qf_property()
call Xproperty_tests('c')
call Xproperty_tests('l')
endfunc
endfunc
" Tests for the QuickFixCmdPre/QuickFixCmdPost autocommands
func QfAutoCmdHandler(loc, cmd)
@@ -1774,3 +1826,55 @@ func Test_cwindow_jump()
enew | only
set efm&vim
endfunc
func XvimgrepTests(cchar)
call s:setup_commands(a:cchar)
call writefile(['Editor:VIM vim',
\ 'Editor:Emacs EmAcS',
\ 'Editor:Notepad NOTEPAD'], 'Xtestfile1')
call writefile(['Linux', 'MacOS', 'MS-Windows'], 'Xtestfile2')
" Error cases
call assert_fails('Xvimgrep /abc *', 'E682:')
let @/=''
call assert_fails('Xvimgrep // *', 'E35:')
call assert_fails('Xvimgrep abc', 'E683:')
call assert_fails('Xvimgrep a1b2c3 Xtestfile1', 'E480:')
call assert_fails('Xvimgrep pat Xa1b2c3', 'E480:')
Xexpr ""
Xvimgrepadd Notepad Xtestfile1
Xvimgrepadd MacOS Xtestfile2
let l = g:Xgetlist()
call assert_equal(2, len(l))
call assert_equal('Editor:Notepad NOTEPAD', l[0].text)
Xvimgrep #\cvim#g Xtestfile?
let l = g:Xgetlist()
call assert_equal(2, len(l))
call assert_equal(8, l[0].col)
call assert_equal(12, l[1].col)
1Xvimgrep ?Editor? Xtestfile*
let l = g:Xgetlist()
call assert_equal(1, len(l))
call assert_equal('Editor:VIM vim', l[0].text)
edit +3 Xtestfile2
Xvimgrep +\cemacs+j Xtestfile1
let l = g:Xgetlist()
call assert_equal('Xtestfile2', bufname(''))
call assert_equal('Editor:Emacs EmAcS', l[0].text)
call delete('Xtestfile1')
call delete('Xtestfile2')
endfunc
" Tests for the :vimgrep command
func Test_vimgrep()
call XvimgrepTests('c')
call XvimgrepTests('l')
endfunc

View File

@@ -0,0 +1,119 @@
" *-register (quotestar) tests
if !has('clipboard')
finish
endif
source shared.vim
func Do_test_quotestar_for_macunix()
if empty(exepath('pbcopy')) || empty(exepath('pbpaste'))
return 'Test requires pbcopy(1) and pbpaste(1)'
endif
let @* = ''
" Test #1: Pasteboard to Vim
let test_msg = "text from pasteboard to vim via quotestar"
" Write a piece of text to the pasteboard.
call system('/bin/echo -n "' . test_msg . '" | pbcopy')
" See if the *-register is changed as expected.
call assert_equal(test_msg, @*)
" Test #2: Vim to Pasteboard
let test_msg = "text from vim to pasteboard via quotestar"
" Write a piece of text to the *-register.
let @* = test_msg
" See if the pasteboard is changed as expected.
call assert_equal(test_msg, system('pbpaste'))
return ''
endfunc
func Do_test_quotestar_for_x11()
if !has('clientserver') || !has('job')
return 'Test requires the client-server and job features'
endif
let cmd = GetVimCommand()
if cmd == ''
return 'GetVimCommand() failed'
endif
let name = 'XVIMCLIPBOARD'
let cmd .= ' --servername ' . name
let g:job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
call WaitFor('job_status(g:job) == "run"')
if job_status(g:job) != 'run'
call assert_report('Cannot run the Vim server')
return ''
endif
" Takes a short while for the server to be active.
call WaitFor('serverlist() =~ "' . name . '"')
call assert_match(name, serverlist())
" Clear the *-register of this vim instance.
let @* = ''
" Try to change the *-register of the server.
call remote_foreground(name)
call remote_send(name, ":let @* = 'yes'\<CR>")
call WaitFor('remote_expr("' . name . '", "@*", "", 1) == "yes"')
call assert_equal('yes', remote_expr(name, "@*", "", 2))
" Check that the *-register of this vim instance is changed as expected.
call assert_equal('yes', @*)
if has('unix') && has('gui') && !has('gui_running')
let @* = ''
" Running in a terminal and the GUI is avaiable: Tell the server to open
" the GUI and check that the remote command still works.
" Need to wait for the GUI to start up, otherwise the send hangs in trying
" to send to the terminal window.
if has('gui_athena') || has('gui_motif')
" For those GUIs, ignore the 'failed to create input context' error.
call remote_send(name, ":call test_ignore_error('E285') | gui -f\<CR>")
else
call remote_send(name, ":gui -f\<CR>")
endif
" Wait for the server to be up and answering requests.
call WaitFor('remote_expr("' . name . '", "v:version", "", 1) != ""')
call remote_send(name, ":let @* = 'maybe'\<CR>")
call WaitFor('remote_expr("' . name . '", "@*", "", 1) == "maybe"')
call assert_equal('maybe', remote_expr(name, "@*", "", 2))
call assert_equal('maybe', @*)
endif
call remote_send(name, ":qa!\<CR>")
call WaitFor('job_status(g:job) == "dead"')
if job_status(g:job) != 'dead'
call assert_report('Server did not exit')
call job_stop(g:job, 'kill')
endif
return ''
endfunc
func Test_quotestar()
let skipped = ''
let quotestar_saved = @*
if has('macunix')
let skipped = Do_test_quotestar_for_macunix()
elseif !empty("$DISPLAY")
let skipped = Do_test_quotestar_for_x11()
else
let skipped = "Test is not implemented yet for this platform."
endif
let @* = quotestar_saved
if !empty(skipped)
throw 'Skipped: ' . skipped
endif
endfunc

View File

@@ -67,4 +67,309 @@ function Test_window_cmd_wincmd_gf()
augroup! test_window_cmd_wincmd_gf
endfunc
func Test_window_quit()
e Xa
split Xb
call assert_equal(2, winnr('$'))
call assert_equal('Xb', bufname(winbufnr(1)))
call assert_equal('Xa', bufname(winbufnr(2)))
wincmd q
call assert_equal(1, winnr('$'))
call assert_equal('Xa', bufname(winbufnr(1)))
bw Xa Xb
endfunc
func Test_window_horizontal_split()
call assert_equal(1, winnr('$'))
3wincmd s
call assert_equal(2, winnr('$'))
call assert_equal(3, winheight(0))
call assert_equal(winwidth(1), winwidth(2))
call assert_fails('botright topleft wincmd s', 'E442:')
bw
endfunc
func Test_window_vertical_split()
call assert_equal(1, winnr('$'))
3wincmd v
call assert_equal(2, winnr('$'))
call assert_equal(3, winwidth(0))
call assert_equal(winheight(1), winheight(2))
call assert_fails('botright topleft wincmd v', 'E442:')
bw
endfunc
func Test_window_split_edit_alternate()
e Xa
e Xb
wincmd ^
call assert_equal('Xa', bufname(winbufnr(1)))
call assert_equal('Xb', bufname(winbufnr(2)))
bw Xa Xb
endfunc
func Test_window_preview()
" Open a preview window
pedit Xa
call assert_equal(2, winnr('$'))
call assert_equal(0, &previewwindow)
" Go to the preview window
wincmd P
call assert_equal(1, &previewwindow)
" Close preview window
wincmd z
call assert_equal(1, winnr('$'))
call assert_equal(0, &previewwindow)
call assert_fails('wincmd P', 'E441:')
endfunc
func Test_window_exchange()
e Xa
" Nothing happens with window exchange when there is 1 window
wincmd x
call assert_equal(1, winnr('$'))
split Xb
split Xc
call assert_equal('Xc', bufname(winbufnr(1)))
call assert_equal('Xb', bufname(winbufnr(2)))
call assert_equal('Xa', bufname(winbufnr(3)))
" Exchange current window 1 with window 3
3wincmd x
call assert_equal('Xa', bufname(winbufnr(1)))
call assert_equal('Xb', bufname(winbufnr(2)))
call assert_equal('Xc', bufname(winbufnr(3)))
" Exchange window with next when at the top window
wincmd x
call assert_equal('Xb', bufname(winbufnr(1)))
call assert_equal('Xa', bufname(winbufnr(2)))
call assert_equal('Xc', bufname(winbufnr(3)))
" Exchange window with next when at the middle window
wincmd j
wincmd x
call assert_equal('Xb', bufname(winbufnr(1)))
call assert_equal('Xc', bufname(winbufnr(2)))
call assert_equal('Xa', bufname(winbufnr(3)))
" Exchange window with next when at the bottom window.
" When there is no next window, it exchanges with the previous window.
wincmd j
wincmd x
call assert_equal('Xb', bufname(winbufnr(1)))
call assert_equal('Xa', bufname(winbufnr(2)))
call assert_equal('Xc', bufname(winbufnr(3)))
bw Xa Xb Xc
endfunc
func Test_window_rotate()
e Xa
split Xb
split Xc
call assert_equal('Xc', bufname(winbufnr(1)))
call assert_equal('Xb', bufname(winbufnr(2)))
call assert_equal('Xa', bufname(winbufnr(3)))
" Rotate downwards
wincmd r
call assert_equal('Xa', bufname(winbufnr(1)))
call assert_equal('Xc', bufname(winbufnr(2)))
call assert_equal('Xb', bufname(winbufnr(3)))
2wincmd r
call assert_equal('Xc', bufname(winbufnr(1)))
call assert_equal('Xb', bufname(winbufnr(2)))
call assert_equal('Xa', bufname(winbufnr(3)))
" Rotate upwards
wincmd R
call assert_equal('Xb', bufname(winbufnr(1)))
call assert_equal('Xa', bufname(winbufnr(2)))
call assert_equal('Xc', bufname(winbufnr(3)))
2wincmd R
call assert_equal('Xc', bufname(winbufnr(1)))
call assert_equal('Xb', bufname(winbufnr(2)))
call assert_equal('Xa', bufname(winbufnr(3)))
bot vsplit
call assert_fails('wincmd R', 'E443:')
bw Xa Xb Xc
endfunc
func Test_window_height()
e Xa
split Xb
let [wh1, wh2] = [winheight(1), winheight(2)]
" Active window (1) should have the same height or 1 more
" than the other window.
call assert_inrange(wh2, wh2 + 1, wh1)
wincmd -
call assert_equal(wh1 - 1, winheight(1))
call assert_equal(wh2 + 1, winheight(2))
wincmd +
call assert_equal(wh1, winheight(1))
call assert_equal(wh2, winheight(2))
2wincmd _
call assert_equal(2, winheight(1))
call assert_equal(wh1 + wh2 - 2, winheight(2))
wincmd =
call assert_equal(wh1, winheight(1))
call assert_equal(wh2, winheight(2))
2wincmd _
set winfixheight
split Xc
let [wh1, wh2, wh3] = [winheight(1), winheight(2), winheight(3)]
call assert_equal(2, winheight(2))
call assert_inrange(wh3, wh3 + 1, wh1)
3wincmd +
call assert_equal(2, winheight(2))
call assert_equal(wh1 + 3, winheight(1))
call assert_equal(wh3 - 3, winheight(3))
wincmd =
call assert_equal(2, winheight(2))
call assert_equal(wh1, winheight(1))
call assert_equal(wh3, winheight(3))
wincmd j
set winfixheight&
wincmd =
let [wh1, wh2, wh3] = [winheight(1), winheight(2), winheight(3)]
" Current window (2) should have the same height or 1 more
" than the other windows.
call assert_inrange(wh1, wh1 + 1, wh2)
call assert_inrange(wh3, wh3 + 1, wh2)
bw Xa Xb Xc
endfunc
func Test_window_width()
e Xa
vsplit Xb
let [ww1, ww2] = [winwidth(1), winwidth(2)]
" Active window (1) should have the same width or 1 more
" than the other window.
call assert_inrange(ww2, ww2 + 1, ww1)
wincmd <
call assert_equal(ww1 - 1, winwidth(1))
call assert_equal(ww2 + 1, winwidth(2))
wincmd >
call assert_equal(ww1, winwidth(1))
call assert_equal(ww2, winwidth(2))
2wincmd |
call assert_equal(2, winwidth(1))
call assert_equal(ww1 + ww2 - 2, winwidth(2))
wincmd =
call assert_equal(ww1, winwidth(1))
call assert_equal(ww2, winwidth(2))
2wincmd |
set winfixwidth
vsplit Xc
let [ww1, ww2, ww3] = [winwidth(1), winwidth(2), winwidth(3)]
call assert_equal(2, winwidth(2))
call assert_inrange(ww3, ww3 + 1, ww1)
3wincmd >
call assert_equal(2, winwidth(2))
call assert_equal(ww1 + 3, winwidth(1))
call assert_equal(ww3 - 3, winwidth(3))
wincmd =
call assert_equal(2, winwidth(2))
call assert_equal(ww1, winwidth(1))
call assert_equal(ww3, winwidth(3))
wincmd l
set winfixwidth&
wincmd =
let [ww1, ww2, ww3] = [winwidth(1), winwidth(2), winwidth(3)]
" Current window (2) should have the same width or 1 more
" than the other windows.
call assert_inrange(ww1, ww1 + 1, ww2)
call assert_inrange(ww3, ww3 + 1, ww2)
bw Xa Xb Xc
endfunc
func Test_window_jump_tag()
help
/iccf
call assert_match('^|iccf|', getline('.'))
call assert_equal(2, winnr('$'))
2wincmd }
call assert_equal(3, winnr('$'))
call assert_match('^|iccf|', getline('.'))
wincmd k
call assert_match('\*iccf\*', getline('.'))
call assert_equal(2, winheight(0))
wincmd z
set previewheight=4
help
/bugs
wincmd }
wincmd k
call assert_match('\*bugs\*', getline('.'))
call assert_equal(4, winheight(0))
set previewheight&
%bw!
endfunc
func Test_window_newtab()
e Xa
call assert_equal(1, tabpagenr('$'))
call assert_equal("\nAlready only one window", execute('wincmd T'))
split Xb
split Xc
wincmd T
call assert_equal(2, tabpagenr('$'))
call assert_equal(['Xb', 'Xa'], map(tabpagebuflist(1), 'bufname(v:val)'))
call assert_equal(['Xc' ], map(tabpagebuflist(2), 'bufname(v:val)'))
%bw!
endfunc
func Test_next_split_all()
" This was causing an illegal memory access.
n x
norm axxx
split
split
s/x
s/x
all
bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -764,6 +764,36 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
497,
/**/
496,
/**/
495,
/**/
494,
/**/
493,
/**/
492,
/**/
491,
/**/
490,
/**/
489,
/**/
488,
/**/
487,
/**/
486,
/**/
485,
/**/
484,
/**/
483,
/**/
482,
/**/

View File

@@ -2506,7 +2506,9 @@ typedef enum {
# define ELAPSED_INIT(v) v = GetTickCount()
# define ELAPSED_FUNC(v) elapsed(v)
# define ELAPSED_TYPE DWORD
long elapsed(DWORD start_tick);
# ifndef PROTO
long elapsed(DWORD start_tick);
# endif
# endif
#endif

View File

@@ -870,9 +870,9 @@ win_split_ins(
/* We don't like to take lines for the new window from a
* 'winfixwidth' window. Take them from a window to the left or right
* instead, if possible. */
* instead, if possible. Add one for the separator. */
if (oldwin->w_p_wfw)
win_setwidth_win(oldwin->w_width + new_size, oldwin);
win_setwidth_win(oldwin->w_width + new_size + 1, oldwin);
/* Only make all windows the same width if one of them (except oldwin)
* is wider than one of the split windows. */
@@ -2107,7 +2107,7 @@ win_equal_rec(
}
/*
* close all windows for buffer 'buf'
* Close all windows for buffer "buf".
*/
void
close_windows(
@@ -2131,7 +2131,10 @@ close_windows(
#endif
)
{
win_close(wp, FALSE);
if (win_close(wp, FALSE) == FAIL)
/* If closing the window fails give up, to avoid looping
* forever. */
break;
/* Start all over, autocommands may change the window layout. */
wp = firstwin;
@@ -2450,6 +2453,10 @@ win_close(win_T *win, int free_buf)
#endif
curbuf = curwin->w_buffer;
close_curwin = TRUE;
/* The cursor position may be invalid if the buffer changed after last
* using the window. */
check_cursor();
}
if (p_ea && (*p_ead == 'b' || *p_ead == dir))
win_equal(curwin, TRUE, dir);
@@ -3754,6 +3761,58 @@ valid_tabpage(tabpage_T *tpc)
return FALSE;
}
/*
* Return TRUE when "tpc" points to a valid tab page and at least one window is
* valid.
*/
int
valid_tabpage_win(tabpage_T *tpc)
{
tabpage_T *tp;
win_T *wp;
FOR_ALL_TABPAGES(tp)
{
if (tp == tpc)
{
FOR_ALL_WINDOWS_IN_TAB(tp, wp)
{
if (win_valid_any_tab(wp))
return TRUE;
}
return FALSE;
}
}
/* shouldn't happen */
return FALSE;
}
/*
* Close tabpage "tab", assuming it has no windows in it.
* There must be another tabpage or this will crash.
*/
void
close_tabpage(tabpage_T *tab)
{
tabpage_T *ptp;
if (tab == first_tabpage)
{
first_tabpage = tab->tp_next;
ptp = first_tabpage;
}
else
{
for (ptp = first_tabpage; ptp != NULL && ptp->tp_next != tab;
ptp = ptp->tp_next)
;
ptp->tp_next = tab->tp_next;
}
goto_tabpage_tp(ptp, FALSE, FALSE);
free_tabpage(tab);
}
/*
* Find tab page "n" (first one is 1). Returns NULL when not found.
*/