Compare commits

...

13 Commits

Author SHA1 Message Date
Bram Moolenaar
14944c04bd patch 8.2.1663: options window entries cannot be translated
Problem:    Options window entries cannot be translated.
Solution:   Use AddOption() for all explanations. (closes #6800)
2020-09-11 20:51:26 +02:00
Bram Moolenaar
0e655111e9 patch 8.2.1662: :mksession does not restore shared terminal buffer properly
Problem:    :mksession does not restore shared terminal buffer properly.
Solution:   Keep a hashtab with terminal buffers. (Rob Pilling, closes #6930)
2020-09-11 20:36:36 +02:00
Bram Moolenaar
c6a67c92bc patch 8.2.1661: cannot connect to 127.0.0.1 for host with only IPv6 addresses
Problem:    Cannot connect to 127.0.0.1 for host with only IPv6 addresses.
Solution:   pass AI_V4MAPPED flag to getaddrinfo. (Filipe Brandenburger,
            closes #6931)
2020-09-11 19:28:19 +02:00
Bram Moolenaar
c0c71e9d98 patch 8.2.1660: assert functions require passing expected as first argument
Problem:    Assert functions require passing expected result as the first
            argument, which isn't obvious.
Solution:   Use a method, as in "runtest()->assert_equal(expected)".
2020-09-11 19:09:48 +02:00
Bram Moolenaar
96fdf4348a patch 8.2.1659: spellfile code not completely tested
Problem:    Spellfile code not completely tested.
Solution:   Add a few more test cases. (Yegappan Lakshmanan, closes #6929)
2020-09-11 18:11:50 +02:00
Bram Moolenaar
a810db3f17 patch 8.2.1658: expand('<stack>') has trailing ".."
Problem:    Expand('<stack>') has trailing "..".
Solution:   Remove the "..". (closes #6927)
2020-09-11 17:59:23 +02:00
Bram Moolenaar
8b848cafb0 patch 8.2.1657: Vim9: no proper error for nested ":def!"
Problem:    Vim9: no proper error for nested ":def!".
Solution:   Check for "!". (closes #6920)
2020-09-10 22:28:01 +02:00
Bram Moolenaar
dfa3d5524e patch 8.2.1656: Vim9: callstack wrong if :def function calls :def function
Problem:    Vim9: callstack wrong if :def function calls :def function.
Solution:   Set the line number before calling. (closes #6914)
2020-09-10 22:05:08 +02:00
Bram Moolenaar
895a7a472d patch 8.2.1655: cannot build with Strawberry Perl 5.32.0
Problem:    Cannot build with Strawberry Perl 5.32.0.
Solution:   Use Perl_sv_2pvbyte_flags. (closes #6921)
2020-09-10 21:36:11 +02:00
Bram Moolenaar
ad9ec5e799 patch 8.2.1654: when job writes to hidden buffer current window is wrong
Problem:    When job writes to hidden buffer current window has display
            errors.  (Johnny McArthur)
Solution:   Use aucmd_prepbuf() instead of switch_to_win_for_buf().
            (closes #6925)
2020-09-10 21:25:45 +02:00
Bram Moolenaar
4f25b1aba0 patch 8.2.1653: expand('<stack>') does not include the final line number
Problem:    Expand('<stack>') does not include the final line number.
Solution:   Add the line nuber. (closes #6927)
2020-09-10 19:25:05 +02:00
Bram Moolenaar
a953b5cf4f patch 8.2.1652: cannot translate lines in the options window
Problem:    Cannot translate lines in the options window.
Solution:   Use the AddOption() function to split descriptions where indicated
            by a line break. (issue #6800)
2020-09-10 14:25:25 +02:00
Bram Moolenaar
64e2db6dc6 patch 8.2.1651: spellfile code not completely tested
Problem:    Spellfile code not completely tested.
Solution:   Add a few more test cases. (Yegappan Lakshmanan, closes #6918)
2020-09-09 22:43:19 +02:00
24 changed files with 1048 additions and 767 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -977,8 +977,8 @@ channel_open(
CLEAR_FIELD(hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
# ifdef AI_ADDRCONFIG
hints.ai_flags = AI_ADDRCONFIG;
# if defined(AI_ADDRCONFIG) && defined(AI_V4MAPPED)
hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED;
# endif
// Set port number manually in order to prevent name resolution services
// from being invoked in the environment where AI_NUMERICSERV is not
@@ -2619,9 +2619,7 @@ invoke_one_time_callback(
static void
append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
{
bufref_T save_curbuf = {NULL, 0, 0};
win_T *save_curwin = NULL;
tabpage_T *save_curtab = NULL;
aco_save_T aco;
linenr_T lnum = buffer->b_ml.ml_line_count;
int save_write_to = buffer->b_write_to_channel;
chanpart_T *ch_part = &channel->ch_part[part];
@@ -2647,12 +2645,13 @@ append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
}
// Append to the buffer
ch_log(channel, "appending line %d to buffer", (int)lnum + 1 - empty);
ch_log(channel, "appending line %d to buffer %s",
(int)lnum + 1 - empty, buffer->b_fname);
buffer->b_p_ma = TRUE;
// Save curbuf/curwin/curtab and make "buffer" the current buffer.
switch_to_win_for_buf(buffer, &save_curwin, &save_curtab, &save_curbuf);
// set curbuf to be our buf, temporarily
aucmd_prepbuf(&aco, buffer);
u_sync(TRUE);
// ignore undo failure, undo is not very useful here
@@ -2668,8 +2667,8 @@ append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
ml_append(lnum, msg, 0, FALSE);
appended_lines_mark(lnum, 1L);
// Restore curbuf/curwin/curtab
restore_win_for_buf(save_curwin, save_curtab, &save_curbuf);
// reset notion of buffer
aucmd_restbuf(&aco);
if (ch_part->ch_nomodifiable)
buffer->b_p_ma = FALSE;
@@ -2693,9 +2692,10 @@ append_to_buffer(buf_T *buffer, char_u *msg, channel_T *channel, ch_part_T part)
// down. If the topline is outdated update it now.
if (move_cursor || wp->w_topline > buffer->b_ml.ml_line_count)
{
win_T *save_curwin = curwin;
if (move_cursor)
++wp->w_cursor.lnum;
save_curwin = curwin;
curwin = wp;
curbuf = curwin->w_buffer;
scroll_cursor_bot(0, FALSE);

View File

@@ -105,7 +105,7 @@ do_debug(char_u *cmd)
vim_free(debug_newval);
debug_newval = NULL;
}
sname = estack_sfile(FALSE);
sname = estack_sfile(ESTACK_NONE);
if (sname != NULL)
msg((char *)sname);
vim_free(sname);
@@ -344,7 +344,7 @@ do_checkbacktracelevel(void)
}
else
{
char_u *sname = estack_sfile(FALSE);
char_u *sname = estack_sfile(ESTACK_NONE);
int max = get_maxbacktrace_level(sname);
if (debug_backtrace_level > max)
@@ -365,7 +365,7 @@ do_showbacktrace(char_u *cmd)
int i = 0;
int max;
sname = estack_sfile(FALSE);
sname = estack_sfile(ESTACK_NONE);
max = get_maxbacktrace_level(sname);
if (sname != NULL)
{

View File

@@ -256,4 +256,6 @@ EXTERN char e_assert_fails_fourth_argument[]
INIT(= N_("E1115: assert_fails() fourth argument must be a number"));
EXTERN char e_assert_fails_fifth_argument[]
INIT(= N_("E1116: assert_fails() fifth argument must be a string"));
EXTERN char e_cannot_use_bang_with_nested_def[]
INIT(= N_("E1117: Cannot use ! with nested :def"));
#endif

View File

@@ -8389,6 +8389,7 @@ find_cmdline_var(char_u *src, int *usedlen)
* '<cexpr>' to C-expression under the cursor
* '<cfile>' to path name under the cursor
* '<sfile>' to sourced file name
* '<stack>' to call stack
* '<slnum>' to sourced file line number
* '<afile>' to file name for autocommand
* '<abuf>' to buffer number for autocommand
@@ -8606,7 +8607,8 @@ eval_vars(
case SPEC_SFILE: // file name for ":so" command
case SPEC_STACK: // call stack
result = estack_sfile(spec_idx == SPEC_SFILE);
result = estack_sfile(spec_idx == SPEC_SFILE
? ESTACK_SFILE : ESTACK_STACK);
if (result == NULL)
{
*errormsg = spec_idx == SPEC_SFILE

View File

@@ -290,7 +290,7 @@ cause_errthrow(
// Get the source name and lnum now, it may change before
// reaching do_errthrow().
elem->sfile = estack_sfile(FALSE);
elem->sfile = estack_sfile(ESTACK_NONE);
elem->slnum = SOURCING_LNUM;
}
}
@@ -549,7 +549,7 @@ throw_exception(void *value, except_type_T type, char_u *cmdname)
}
else
{
excp->throw_name = estack_sfile(FALSE);
excp->throw_name = estack_sfile(ESTACK_NONE);
if (excp->throw_name == NULL)
excp->throw_name = vim_strsave((char_u *)"");
if (excp->throw_name == NULL)

View File

@@ -81,7 +81,7 @@ hash_clear(hashtab_T *ht)
vim_free(ht->ht_array);
}
#if defined(FEAT_SPELL) || defined(PROTO)
#if defined(FEAT_SPELL) || defined(FEAT_TERMINAL) || defined(PROTO)
/*
* Free the array of a hash table and all the keys it contains. The keys must
* have been allocated. "off" is the offset from the start of the allocate

View File

@@ -241,6 +241,9 @@ typedef int perl_key;
# else
# define Perl_sv_2pv dll_Perl_sv_2pv
# endif
# if (PERL_REVISION == 5) && (PERL_VERSION >= 32)
# define Perl_sv_2pvbyte_flags dll_Perl_sv_2pvbyte_flags
# endif
# define Perl_sv_2pvbyte dll_Perl_sv_2pvbyte
# define Perl_sv_bless dll_Perl_sv_bless
# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
@@ -397,6 +400,9 @@ static char* (*Perl_sv_2pv_nolen)(pTHX_ SV*);
static char* (*Perl_sv_2pv)(pTHX_ SV*, STRLEN*);
# endif
static char* (*Perl_sv_2pvbyte)(pTHX_ SV*, STRLEN*);
# if (PERL_REVISION == 5) && (PERL_VERSION >= 32)
static char* (*Perl_sv_2pvbyte_flags)(pTHX_ SV*, STRLEN*, I32);
# endif
static SV* (*Perl_sv_bless)(pTHX_ SV*, HV*);
# if (PERL_REVISION == 5) && (PERL_VERSION >= 8)
static void (*Perl_sv_catpvn_flags)(pTHX_ SV* , const char*, STRLEN, I32);
@@ -553,6 +559,9 @@ static struct {
{"Perl_sv_2pv", (PERL_PROC*)&Perl_sv_2pv},
# endif
{"Perl_sv_2pvbyte", (PERL_PROC*)&Perl_sv_2pvbyte},
# if (PERL_REVISION == 5) && (PERL_VERSION >= 32)
{"Perl_sv_2pvbyte_flags", (PERL_PROC*)&Perl_sv_2pvbyte_flags},
# endif
# ifdef PERL589_OR_LATER
{"Perl_sv_2iv_flags", (PERL_PROC*)&Perl_sv_2iv_flags},
{"Perl_newXS_flags", (PERL_PROC*)&Perl_newXS_flags},

View File

@@ -461,7 +461,7 @@ get_emsg_source(void)
if (SOURCING_NAME != NULL && other_sourcing_name())
{
char_u *sname = estack_sfile(FALSE);
char_u *sname = estack_sfile(ESTACK_NONE);
char_u *tofree = sname;
if (sname == NULL)

View File

@@ -4,7 +4,7 @@ estack_T *estack_push(etype_T type, char_u *name, long lnum);
estack_T *estack_push_ufunc(ufunc_T *ufunc, long lnum);
int estack_top_is_ufunc(ufunc_T *ufunc, long lnum);
estack_T *estack_pop(void);
char_u *estack_sfile(int is_sfile);
char_u *estack_sfile(estack_arg_T which);
void ex_runtime(exarg_T *eap);
int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
int do_in_runtimepath(char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);

View File

@@ -2,7 +2,7 @@
void init_job_options(jobopt_T *opt);
buf_T *term_start(typval_T *argvar, char **argv, jobopt_T *opt, int flags);
void ex_terminal(exarg_T *eap);
int term_write_session(FILE *fd, win_T *wp);
int term_write_session(FILE *fd, win_T *wp, hashtab_T *terminal_bufs);
int term_should_restore(buf_T *buf);
void free_terminal(buf_T *buf);
void free_unused_terminals(void);

View File

@@ -111,10 +111,10 @@ estack_pop(void)
/*
* Get the current value for <sfile> in allocated memory.
* "is_sfile" is TRUE for <sfile> itself.
* "which" is ESTACK_SFILE for <sfile> and ESTACK_STACK for <stack>.
*/
char_u *
estack_sfile(int is_sfile UNUSED)
estack_sfile(estack_arg_T which UNUSED)
{
estack_T *entry;
#ifdef FEAT_EVAL
@@ -127,7 +127,7 @@ estack_sfile(int is_sfile UNUSED)
entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
#ifdef FEAT_EVAL
if (is_sfile && entry->es_type != ETYPE_UFUNC)
if (which == ESTACK_SFILE && entry->es_type != ETYPE_UFUNC)
#endif
{
if (entry->es_name == NULL)
@@ -144,6 +144,9 @@ estack_sfile(int is_sfile UNUSED)
entry = ((estack_T *)exestack.ga_data) + idx;
if (entry->es_name != NULL)
{
long lnum = 0;
char *dots;
len = STRLEN(entry->es_name) + 15;
type_name = "";
if (entry->es_type != last_type)
@@ -159,15 +162,20 @@ estack_sfile(int is_sfile UNUSED)
len += STRLEN(type_name);
if (ga_grow(&ga, (int)len) == FAIL)
break;
if (idx == exestack.ga_len - 1 || entry->es_lnum == 0)
// For the bottom entry: do not add the line number, it is used
// in <slnum>. Also leave it out when the number is not set.
vim_snprintf((char *)ga.ga_data + ga.ga_len, len, "%s%s%s",
type_name, entry->es_name,
idx == exestack.ga_len - 1 ? "" : "..");
if (idx == exestack.ga_len - 1)
lnum = which == ESTACK_STACK ? SOURCING_LNUM : 0;
else
vim_snprintf((char *)ga.ga_data + ga.ga_len, len, "%s%s[%ld]..",
type_name, entry->es_name, entry->es_lnum);
lnum = entry->es_lnum;
dots = idx == exestack.ga_len - 1 ? "" : "..";
if (lnum == 0)
// For the bottom entry of <sfile>: do not add the line number,
// it is used in <slnum>. Also leave it out when the number is
// not set.
vim_snprintf((char *)ga.ga_data + ga.ga_len, len, "%s%s%s",
type_name, entry->es_name, dots);
else
vim_snprintf((char *)ga.ga_data + ga.ga_len, len, "%s%s[%ld]%s",
type_name, entry->es_name, lnum, dots);
ga.ga_len += (int)STRLEN((char *)ga.ga_data + ga.ga_len);
}
}

View File

@@ -305,8 +305,12 @@ put_view(
win_T *wp,
int add_edit, // add ":edit" command to view
unsigned *flagp, // vop_flags or ssop_flags
int current_arg_idx) // current argument index of the window, use
// -1 if unknown
int current_arg_idx // current argument index of the window, use
// -1 if unknown
#ifdef FEAT_TERMINAL
, hashtab_T *terminal_bufs
#endif
)
{
win_T *save_curwin;
int f;
@@ -349,7 +353,7 @@ put_view(
# ifdef FEAT_TERMINAL
if (bt_terminal(wp->w_buffer))
{
if (term_write_session(fd, wp) == FAIL)
if (term_write_session(fd, wp, terminal_bufs) == FAIL)
return FAIL;
}
else
@@ -588,6 +592,12 @@ makeopens(
frame_T *tab_topframe;
int cur_arg_idx = 0;
int next_arg_idx = 0;
int ret = FAIL;
#ifdef FEAT_TERMINAL
hashtab_T terminal_bufs;
hash_init(&terminal_bufs);
#endif
if (ssop_flags & SSOP_BUFFERS)
only_save_windows = FALSE; // Save ALL buffers
@@ -596,25 +606,25 @@ makeopens(
// sessionable variables.
#ifdef FEAT_EVAL
if (put_line(fd, "let v:this_session=expand(\"<sfile>:p\")") == FAIL)
return FAIL;
goto fail;
if (ssop_flags & SSOP_GLOBALS)
if (store_session_globals(fd) == FAIL)
return FAIL;
goto fail;
#endif
// Close all windows and tabs but one.
if (put_line(fd, "silent only") == FAIL)
return FAIL;
goto fail;
if ((ssop_flags & SSOP_TABPAGES)
&& put_line(fd, "silent tabonly") == FAIL)
return FAIL;
goto fail;
// Now a :cd command to the session directory or the current directory
if (ssop_flags & SSOP_SESDIR)
{
if (put_line(fd, "exe \"cd \" . escape(expand(\"<sfile>:p:h\"), ' ')")
== FAIL)
return FAIL;
goto fail;
}
else if (ssop_flags & SSOP_CURDIR)
{
@@ -625,7 +635,7 @@ makeopens(
|| put_eol(fd) == FAIL)
{
vim_free(sname);
return FAIL;
goto fail;
}
vim_free(sname);
}
@@ -633,27 +643,27 @@ makeopens(
// If there is an empty, unnamed buffer we will wipe it out later.
// Remember the buffer number.
if (put_line(fd, "if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''") == FAIL)
return FAIL;
goto fail;
if (put_line(fd, " let s:wipebuf = bufnr('%')") == FAIL)
return FAIL;
goto fail;
if (put_line(fd, "endif") == FAIL)
return FAIL;
goto fail;
// Now save the current files, current buffer first.
if (put_line(fd, "set shortmess=aoO") == FAIL)
return FAIL;
goto fail;
// the global argument list
if (ses_arglist(fd, "argglobal", &global_alist.al_ga,
!(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL)
return FAIL;
goto fail;
if (ssop_flags & SSOP_RESIZE)
{
// Note: after the restore we still check it worked!
if (fprintf(fd, "set lines=%ld columns=%ld" , Rows, Columns) < 0
|| put_eol(fd) == FAIL)
return FAIL;
goto fail;
}
#ifdef FEAT_GUI
@@ -665,7 +675,7 @@ makeopens(
{
// Note: after the restore we still check it worked!
if (fprintf(fd, "winpos %d %d", x, y) < 0 || put_eol(fd) == FAIL)
return FAIL;
goto fail;
}
}
#endif
@@ -677,7 +687,7 @@ makeopens(
if (p_stal == 1 && first_tabpage->tp_next != NULL)
{
if (put_line(fd, "set stal=2") == FAIL)
return FAIL;
goto fail;
restore_stal = TRUE;
}
@@ -695,9 +705,9 @@ makeopens(
// later local options won't be copied to the new tabs.
FOR_ALL_TABPAGES(tp)
if (tp->tp_next != NULL && put_line(fd, "tabnew") == FAIL)
return FAIL;
goto fail;
if (first_tabpage->tp_next != NULL && put_line(fd, "tabrewind") == FAIL)
return FAIL;
goto fail;
}
for (tabnr = 1; ; ++tabnr)
{
@@ -739,13 +749,13 @@ makeopens(
)
{
if (need_tabnext && put_line(fd, "tabnext") == FAIL)
return FAIL;
goto fail;
need_tabnext = FALSE;
if (fputs("edit ", fd) < 0
|| ses_fname(fd, wp->w_buffer, &ssop_flags, TRUE)
== FAIL)
return FAIL;
goto fail;
if (!wp->w_arg_idx_invalid)
edited_win = wp;
break;
@@ -754,17 +764,17 @@ makeopens(
// If no file got edited create an empty tab page.
if (need_tabnext && put_line(fd, "tabnext") == FAIL)
return FAIL;
goto fail;
// Save current window layout.
if (put_line(fd, "set splitbelow splitright") == FAIL)
return FAIL;
goto fail;
if (ses_win_rec(fd, tab_topframe) == FAIL)
return FAIL;
goto fail;
if (!p_sb && put_line(fd, "set nosplitbelow") == FAIL)
return FAIL;
goto fail;
if (!p_spr && put_line(fd, "set nosplitright") == FAIL)
return FAIL;
goto fail;
// Check if window sizes can be restored (no windows omitted).
// Remember the window number of the current window after restoring.
@@ -781,7 +791,7 @@ makeopens(
// Go to the first window.
if (put_line(fd, "wincmd t") == FAIL)
return FAIL;
goto fail;
// If more than one window, see if sizes can be restored.
// First set 'winheight' and 'winwidth' to 1 to avoid the windows being
@@ -794,9 +804,9 @@ makeopens(
|| put_line(fd, "set winheight=1") == FAIL
|| put_line(fd, "set winminwidth=0") == FAIL
|| put_line(fd, "set winwidth=1") == FAIL)
return FAIL;
goto fail;
if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL)
return FAIL;
goto fail;
// Restore the tab-local working directory if specified
// Do this before the windows, so that the window-local directory can
@@ -806,7 +816,7 @@ makeopens(
if (fputs("tcd ", fd) < 0
|| ses_put_fname(fd, tp->tp_localdir, &ssop_flags) == FAIL
|| put_eol(fd) == FAIL)
return FAIL;
goto fail;
did_lcd = TRUE;
}
@@ -815,11 +825,14 @@ makeopens(
{
if (!ses_do_win(wp))
continue;
if (put_view(fd, wp, wp != edited_win, &ssop_flags,
cur_arg_idx) == FAIL)
return FAIL;
if (put_view(fd, wp, wp != edited_win, &ssop_flags, cur_arg_idx
#ifdef FEAT_TERMINAL
, &terminal_bufs
#endif
) == FAIL)
goto fail;
if (nr > 1 && put_line(fd, "wincmd w") == FAIL)
return FAIL;
goto fail;
next_arg_idx = wp->w_arg_idx;
}
@@ -831,12 +844,12 @@ makeopens(
// Restore cursor to the current window if it's not the first one.
if (cnr > 1 && (fprintf(fd, "%dwincmd w", cnr) < 0
|| put_eol(fd) == FAIL))
return FAIL;
goto fail;
// Restore window sizes again after jumping around in windows, because
// the current window has a minimum size while others may not.
if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL)
return FAIL;
goto fail;
// Don't continue in another tab page when doing only the current one
// or when at the last tab page.
@@ -848,10 +861,10 @@ makeopens(
{
if (fprintf(fd, "tabnext %d", tabpage_index(curtab)) < 0
|| put_eol(fd) == FAIL)
return FAIL;
goto fail;
}
if (restore_stal && put_line(fd, "set stal=1") == FAIL)
return FAIL;
goto fail;
// Now put the remaining buffers into the buffer list.
// This is near the end, so that when 'hidden' is set we don't create extra
@@ -872,38 +885,43 @@ makeopens(
if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L
: buf->b_wininfo->wi_fpos.lnum) < 0
|| ses_fname(fd, buf, &ssop_flags, TRUE) == FAIL)
return FAIL;
goto fail;
}
}
// Wipe out an empty unnamed buffer we started in.
if (put_line(fd, "if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0")
== FAIL)
return FAIL;
goto fail;
if (put_line(fd, " silent exe 'bwipe ' . s:wipebuf") == FAIL)
return FAIL;
goto fail;
if (put_line(fd, "endif") == FAIL)
return FAIL;
goto fail;
if (put_line(fd, "unlet! s:wipebuf") == FAIL)
return FAIL;
goto fail;
// Re-apply 'winheight', 'winwidth' and 'shortmess'.
if (fprintf(fd, "set winheight=%ld winwidth=%ld shortmess=%s",
p_wh, p_wiw, p_shm) < 0 || put_eol(fd) == FAIL)
return FAIL;
goto fail;
// Re-apply 'winminheight' and 'winminwidth'.
if (fprintf(fd, "set winminheight=%ld winminwidth=%ld",
p_wmh, p_wmw) < 0 || put_eol(fd) == FAIL)
return FAIL;
goto fail;
// Lastly, execute the x.vim file if it exists.
if (put_line(fd, "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"") == FAIL
|| put_line(fd, "if filereadable(s:sx)") == FAIL
|| put_line(fd, " exe \"source \" . fnameescape(s:sx)") == FAIL
|| put_line(fd, "endif") == FAIL)
return FAIL;
goto fail;
return OK;
ret = OK;
fail:
#ifdef FEAT_TERMINAL
hash_clear_all(&terminal_bufs, 0);
#endif
return ret;
}
/*
@@ -1084,6 +1102,11 @@ ex_mkrc(exarg_T *eap)
char_u *viewFile = NULL;
unsigned *flagp;
#endif
#ifdef FEAT_TERMINAL
hashtab_T terminal_bufs;
hash_init(&terminal_bufs);
#endif
if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview)
{
@@ -1240,8 +1263,11 @@ ex_mkrc(exarg_T *eap)
}
else
{
failed |= (put_view(fd, curwin, !using_vdir, flagp,
-1) == FAIL);
failed |= (put_view(fd, curwin, !using_vdir, flagp, -1
#ifdef FEAT_TERMINAL
, &terminal_bufs
#endif
) == FAIL);
}
if (put_line(fd, "let &so = s:so_save | let &siso = s:siso_save")
== FAIL)

View File

@@ -935,9 +935,30 @@ theend:
* Return FAIL if writing fails.
*/
int
term_write_session(FILE *fd, win_T *wp)
term_write_session(FILE *fd, win_T *wp, hashtab_T *terminal_bufs)
{
term_T *term = wp->w_buffer->b_term;
const int bufnr = wp->w_buffer->b_fnum;
term_T *term = wp->w_buffer->b_term;
if (wp->w_buffer->b_nwindows > 1)
{
// There are multiple views into this terminal buffer. We don't want to
// create the terminal multiple times. If it's the first time, create,
// otherwise link to the first buffer.
char id_as_str[NUMBUFLEN];
hashitem_T *entry;
vim_snprintf(id_as_str, sizeof(id_as_str), "%d", bufnr);
entry = hash_find(terminal_bufs, (char_u *)id_as_str);
if (!HASHITEM_EMPTY(entry))
{
// we've already opened this terminal buffer
if (fprintf(fd, "execute 'buffer ' . s:term_buf_%d", bufnr) < 0)
return FAIL;
return put_eol(fd);
}
}
// Create the terminal and run the command. This is not without
// risk, but let's assume the user only creates a session when this
@@ -951,6 +972,19 @@ term_write_session(FILE *fd, win_T *wp)
#endif
if (term->tl_command != NULL && fputs((char *)term->tl_command, fd) < 0)
return FAIL;
if (put_eol(fd) != OK)
return FAIL;
if (fprintf(fd, "let s:term_buf_%d = bufnr()", bufnr) < 0)
return FAIL;
if (wp->w_buffer->b_nwindows > 1)
{
char *hash_key = alloc(NUMBUFLEN);
vim_snprintf(hash_key, NUMBUFLEN, "%d", bufnr);
hash_add(terminal_bufs, (char_u *)hash_key);
}
return put_eol(fd);
}

View File

@@ -39,9 +39,9 @@ endfunc
func Test_expand_sfile_and_stack()
call assert_match('test_expand_func\.vim$', s:sfile)
let expected = 'script .*testdir/runtest.vim\[\d\+\]\.\.function RunTheTest\[\d\+\]\.\.Test_expand_sfile_and_stack$'
call assert_match(expected , expand('<sfile>'))
call assert_match(expected , expand('<stack>'))
let expected = 'script .*testdir/runtest.vim\[\d\+\]\.\.function RunTheTest\[\d\+\]\.\.Test_expand_sfile_and_stack'
call assert_match(expected .. '$', expand('<sfile>'))
call assert_match(expected .. '\[4\]' , expand('<stack>'))
" Call in script-local function
call assert_match('script .*testdir/runtest.vim\[\d\+\]\.\.function RunTheTest\[\d\+\]\.\.Test_expand_sfile_and_stack\[7\]\.\.<SNR>\d\+_expand_sfile$', s:expand_sfile())
@@ -53,11 +53,12 @@ func Test_expand_sfile_and_stack()
" Use <stack> from sourced script.
let lines =<< trim END
" comment here
let g:stack_value = expand('<stack>')
END
call writefile(lines, 'Xstack')
source Xstack
call assert_match('\<Xstack$', g:stack_value)
call assert_match('\<Xstack\[2\]$', g:stack_value)
call delete('Xstack')
endfunc

View File

@@ -455,6 +455,32 @@ func Test_mksession_terminal_restore_other()
call delete('Xtest_mks.out')
endfunc
func Test_mksession_terminal_shared_windows()
terminal
let term_buf = bufnr()
new
execute "buffer" term_buf
mksession! Xtest_mks.out
let lines = readfile('Xtest_mks.out')
let found_creation = 0
let found_use = 0
for line in lines
if line =~ '^terminal'
let found_creation = 1
call assert_match('terminal ++curwin ++cols=\d\+ ++rows=\d\+', line)
elseif line =~ "^execute 'buffer ' . s:term_buf_" . term_buf . "$"
let found_use = 1
endif
endfor
call assert_true(found_creation && found_use)
call StopShellInTerminal(term_buf)
call delete('Xtest_mks.out')
endfunc
endif " has('terminal')
" Test :mkview with a file argument.

View File

@@ -112,6 +112,7 @@ foobar/?
set spelllang=
call assert_fails("call spellbadword('maxch')", 'E756:')
call assert_fails("spelldump", 'E756:')
call delete('Xwords.spl')
call delete('Xwords')

View File

@@ -179,6 +179,11 @@ func Spellfile_Test(content, emsg)
" Add the spell file header and version (VIMspell2)
let v = 0z56494D7370656C6C32 + a:content
call writefile(v, splfile, 'b')
" 'encoding' is set before each test to clear the previously loaded suggest
" file from memory.
set encoding=utf-8
set runtimepath=./Xtest
set spelllang=Xtest
if a:emsg != ''
@@ -299,6 +304,12 @@ func Test_spellfile_format_error()
" SN_SOFO: missing sofoto
call Spellfile_Test(0z0600000000050001610000, 'E759:')
" SN_SOFO: empty sofofrom and sofoto
call Spellfile_Test(0z06000000000400000000FF000000000000000000000000, '')
" SN_SOFO: multi-byte characters in sofofrom and sofoto
call Spellfile_Test(0z0600000000080002CF810002CF82FF000000000000000000000000, '')
" SN_COMPOUND: compmax is less than 2
call Spellfile_Test(0z08000000000101, 'E759:')
@@ -308,6 +319,12 @@ func Test_spellfile_format_error()
" SN_COMPOUND: missing compoptions
call Spellfile_Test(0z080000000005040101, 'E758:')
" SN_COMPOUND: missing comppattern
call Spellfile_Test(0z08000000000704010100000001, 'E758:')
" SN_COMPOUND: incorrect comppatlen
call Spellfile_Test(0z080000000007040101000000020165, 'E758:')
" SN_INFO: missing info
call Spellfile_Test(0z0F0000000005040101, '')
@@ -317,6 +334,12 @@ func Test_spellfile_format_error()
" SN_MAP: missing midword
call Spellfile_Test(0z0700000000040102, '')
" SN_MAP: empty map string
call Spellfile_Test(0z070000000000FF000000000000000000000000, '')
" SN_MAP: duplicate multibyte character
call Spellfile_Test(0z070000000004DC81DC81, 'E783:')
" SN_SYLLABLE: missing SYLLABLE item
call Spellfile_Test(0z0900000000040102, '')
@@ -333,12 +356,21 @@ func Test_spellfile_format_error()
" LWORDTREE: missing tree node value
call Spellfile_Test(0zFF0000000402, 'E758:')
" LWORDTREE: incorrect sibling node count
call Spellfile_Test(0zFF00000001040000000000000000, 'E759:')
" KWORDTREE: missing tree node
call Spellfile_Test(0zFF0000000000000004, 'E758:')
" PREFIXTREE: missing tree node
call Spellfile_Test(0zFF000000000000000000000004, 'E758:')
" PREFIXTREE: incorrect prefcondnr
call Spellfile_Test(0zFF000000000000000000000002010200000020, 'E759:')
" PREFIXTREE: invalid nodeidx
call Spellfile_Test(0zFF00000000000000000000000201010000, 'E759:')
let &rtp = save_rtp
call delete('Xtest', 'rf')
endfunc
@@ -506,6 +538,14 @@ func Test_wordlist_dic()
let output = execute('mkspell! -ascii Xwordlist.spl Xwordlist.dic')
call assert_match('Ignored 1 words with non-ASCII characters', output)
" keep case of a word
let lines =<< trim [END]
example/=
[END]
call writefile(lines, 'Xwordlist.dic')
let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
call assert_match('Compressed keep-case:', output)
call delete('Xwordlist.spl')
call delete('Xwordlist.dic')
endfunc
@@ -513,8 +553,14 @@ endfunc
" Test for the :mkspell command
func Test_mkspell()
call assert_fails('mkspell Xtest_us.spl', 'E751:')
call assert_fails('mkspell Xtest.spl abc', 'E484:')
call assert_fails('mkspell a b c d e f g h i j k', 'E754:')
" create a .aff file but not the .dic file
call writefile([], 'Xtest.aff')
call assert_fails('mkspell Xtest.spl Xtest', 'E484:')
call delete('Xtest.aff')
call writefile([], 'Xtest.spl')
call writefile([], 'Xtest.dic')
call assert_fails('mkspell Xtest.spl Xtest.dic', 'E13:')
@@ -706,6 +752,43 @@ func Test_aff_file_format_error()
let output = execute('mkspell! Xtest.spl Xtest')
call assert_match('Illegal flag in Xtest.aff line 2: L', output)
" missing character in UPP entry. The character table is used only in a
" non-utf8 encoding
call writefile(['FOL abc', 'LOW abc', 'UPP A'], 'Xtest.aff')
let save_encoding = &encoding
set encoding=cp949
call assert_fails('mkspell! Xtest.spl Xtest', 'E761:')
let &encoding = save_encoding
" character range doesn't match between FOL and LOW entries
call writefile(["FOL \u0102bc", 'LOW abc', 'UPP ABC'], 'Xtest.aff')
let save_encoding = &encoding
set encoding=cp949
call assert_fails('mkspell! Xtest.spl Xtest', 'E762:')
let &encoding = save_encoding
" character range doesn't match between FOL and UPP entries
call writefile(["FOL \u0102bc", "LOW \u0102bc", 'UPP ABC'], 'Xtest.aff')
let save_encoding = &encoding
set encoding=cp949
call assert_fails('mkspell! Xtest.spl Xtest', 'E762:')
let &encoding = save_encoding
" additional characters in LOW and UPP entries
call writefile(["FOL ab", "LOW abc", 'UPP ABC'], 'Xtest.aff')
let save_encoding = &encoding
set encoding=cp949
call assert_fails('mkspell! Xtest.spl Xtest', 'E761:')
let &encoding = save_encoding
" missing UPP entry
call writefile(["FOL abc", "LOW abc"], 'Xtest.aff')
let save_encoding = &encoding
set encoding=cp949
let output = execute('mkspell! Xtest.spl Xtest')
call assert_match('Missing FOL/LOW/UPP line in Xtest.aff', output)
let &encoding = save_encoding
" duplicate word in the .dic file
call writefile(['2', 'good', 'good', 'good'], 'Xtest.dic')
call writefile(['NAME vim'], 'Xtest.aff')
@@ -713,6 +796,20 @@ func Test_aff_file_format_error()
call assert_match('First duplicate word in Xtest.dic line 3: good', output)
call assert_match('2 duplicate word(s) in Xtest.dic', output)
" use multiple .aff files with different values for COMPOUNDWORDMAX and
" MIDWORD (number and string)
call writefile(['1', 'world'], 'Xtest_US.dic')
call writefile(['1', 'world'], 'Xtest_CA.dic')
call writefile(["COMPOUNDWORDMAX 3", "MIDWORD '-"], 'Xtest_US.aff')
call writefile(["COMPOUNDWORDMAX 4", "MIDWORD '="], 'Xtest_CA.aff')
let output = execute('mkspell! Xtest.spl Xtest_US Xtest_CA')
call assert_match('COMPOUNDWORDMAX value differs from what is used in another .aff file', output)
call assert_match('MIDWORD value differs from what is used in another .aff file', output)
call delete('Xtest_US.dic')
call delete('Xtest_CA.dic')
call delete('Xtest_US.aff')
call delete('Xtest_CA.aff')
call delete('Xtest.dic')
call delete('Xtest.aff')
call delete('Xtest.spl')

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,7 @@
prepare_assert_error(garray_T *gap)
{
char buf[NUMBUFLEN];
char_u *sname = estack_sfile(FALSE);
char_u *sname = estack_sfile(ESTACK_NONE);
ga_init2(gap, 1, 100);
if (sname != NULL)

View File

@@ -750,6 +750,32 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1663,
/**/
1662,
/**/
1661,
/**/
1660,
/**/
1659,
/**/
1658,
/**/
1657,
/**/
1656,
/**/
1655,
/**/
1654,
/**/
1653,
/**/
1652,
/**/
1651,
/**/
1650,
/**/

View File

@@ -2097,8 +2097,7 @@ typedef struct stat stat_T;
# define USE_PRINTF_FORMAT_ATTRIBUTE
#endif
typedef enum
{
typedef enum {
ASSERT_EQUAL,
ASSERT_NOTEQUAL,
ASSERT_MATCH,
@@ -2128,6 +2127,13 @@ typedef enum {
USEPOPUP_HIDDEN // use info popup initially hidden
} use_popup_T;
// Argument for estack_sfile().
typedef enum {
ESTACK_NONE,
ESTACK_SFILE,
ESTACK_STACK
} estack_arg_T;
// Flags for assignment functions.
#define LET_IS_CONST 1 // ":const"
#define LET_NO_COMMAND 2 // "var = expr" without ":let" or ":const"

View File

@@ -4320,6 +4320,12 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
ufunc_T *ufunc;
int r;
if (*name_start == '!')
{
emsg(_(e_cannot_use_bang_with_nested_def));
return NULL;
}
// Only g:Func() can use a namespace.
if (name_start[1] == ':' && !is_global)
{

View File

@@ -1665,6 +1665,7 @@ call_def_function(
// call a :def function
case ISN_DCALL:
SOURCING_LNUM = iptr->isn_lnum;
if (call_dfunc(iptr->isn_arg.dfunc.cdf_idx,
iptr->isn_arg.dfunc.cdf_argcount,
&ectx) == FAIL)