mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.4594: need to write script to a file to be able to source them
Problem: Need to write script to a file to be able to source them. Solution: Make ":source" use lines from the current buffer. (Yegappan Lakshmanan et al., closes #9967)
This commit is contained in:
parent
95d2e7634c
commit
36a5b6867b
@ -197,6 +197,12 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
|
|||||||
:so[urce] {file} Read Ex commands from {file}. These are commands that
|
:so[urce] {file} Read Ex commands from {file}. These are commands that
|
||||||
start with a ":".
|
start with a ":".
|
||||||
Triggers the |SourcePre| autocommand.
|
Triggers the |SourcePre| autocommand.
|
||||||
|
|
||||||
|
:[range]so[urce] Read Ex commands from the [range] of lines in the
|
||||||
|
current buffer. When sourcing commands from the
|
||||||
|
current buffer, the same script-ID |<SID>| is used
|
||||||
|
even if the buffer is sourced multiple times.
|
||||||
|
|
||||||
*:source!*
|
*:source!*
|
||||||
:so[urce]! {file} Read Vim commands from {file}. These are commands
|
:so[urce]! {file} Read Vim commands from {file}. These are commands
|
||||||
that are executed from Normal mode, like you type
|
that are executed from Normal mode, like you type
|
||||||
|
@ -4333,12 +4333,6 @@ Vim script language:
|
|||||||
restore option values. Especially useful for new options. Problem: how
|
restore option values. Especially useful for new options. Problem: how
|
||||||
to avoid a performance penalty (esp. for string options)?
|
to avoid a performance penalty (esp. for string options)?
|
||||||
- range for ":exec", pass it on to the executed command. (Webb)
|
- range for ":exec", pass it on to the executed command. (Webb)
|
||||||
8 ":{range}source": source the lines from the current file.
|
|
||||||
You can already yank lines and use :@" to execute them.
|
|
||||||
Most of do_source() would not be used, need a new function.
|
|
||||||
It's easy when not doing breakpoints or profiling.
|
|
||||||
Requires copying the lines into a list and then creating a function to
|
|
||||||
execute lines from the list. Similar to getnextac().
|
|
||||||
7 ":include" command: just like ":source" but doesn't start a new scriptID?
|
7 ":include" command: just like ":source" but doesn't start a new scriptID?
|
||||||
Will be tricky for the list of script names.
|
Will be tricky for the list of script names.
|
||||||
8 Have a look at VSEL. Would it be useful to include? (Bigham)
|
8 Have a look at VSEL. Would it be useful to include? (Bigham)
|
||||||
|
@ -845,7 +845,7 @@ ga_concat(garray_T *gap, char_u *s)
|
|||||||
void
|
void
|
||||||
ga_concat_len(garray_T *gap, char_u *s, size_t len)
|
ga_concat_len(garray_T *gap, char_u *s, size_t len)
|
||||||
{
|
{
|
||||||
if (s == NULL || *s == NUL)
|
if (s == NULL || *s == NUL || len == 0)
|
||||||
return;
|
return;
|
||||||
if (ga_grow(gap, (int)len) == OK)
|
if (ga_grow(gap, (int)len) == OK)
|
||||||
{
|
{
|
||||||
|
@ -2507,7 +2507,7 @@ ex_loadkeymap(exarg_T *eap)
|
|||||||
int i;
|
int i;
|
||||||
char_u *save_cpo = p_cpo;
|
char_u *save_cpo = p_cpo;
|
||||||
|
|
||||||
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
if (!sourcing_a_script(eap))
|
||||||
{
|
{
|
||||||
emsg(_(e_using_loadkeymap_not_in_sourced_file));
|
emsg(_(e_using_loadkeymap_not_in_sourced_file));
|
||||||
return;
|
return;
|
||||||
|
@ -140,7 +140,7 @@ fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, int skip)
|
|||||||
if (eap != NULL)
|
if (eap != NULL)
|
||||||
{
|
{
|
||||||
evalarg->eval_cstack = eap->cstack;
|
evalarg->eval_cstack = eap->cstack;
|
||||||
if (getline_equal(eap->getline, eap->cookie, getsourceline))
|
if (sourcing_a_script(eap))
|
||||||
{
|
{
|
||||||
evalarg->eval_getline = eap->getline;
|
evalarg->eval_getline = eap->getline;
|
||||||
evalarg->eval_cookie = eap->cookie;
|
evalarg->eval_cookie = eap->cookie;
|
||||||
|
@ -1428,8 +1428,8 @@ EXCMD(CMD_snoremenu, "snoremenu", ex_menu,
|
|||||||
EX_RANGE|EX_ZEROR|EX_EXTRA|EX_TRLBAR|EX_NOTRLCOM|EX_CTRLV|EX_CMDWIN|EX_LOCK_OK,
|
EX_RANGE|EX_ZEROR|EX_EXTRA|EX_TRLBAR|EX_NOTRLCOM|EX_CTRLV|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_OTHER),
|
ADDR_OTHER),
|
||||||
EXCMD(CMD_source, "source", ex_source,
|
EXCMD(CMD_source, "source", ex_source,
|
||||||
EX_BANG|EX_FILE1|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
|
EX_RANGE|EX_DFLALL|EX_BANG|EX_FILE1|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
|
||||||
ADDR_NONE),
|
ADDR_LINES),
|
||||||
EXCMD(CMD_sort, "sort", ex_sort,
|
EXCMD(CMD_sort, "sort", ex_sort,
|
||||||
EX_RANGE|EX_DFLALL|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_NOTRLCOM|EX_MODIFY,
|
EX_RANGE|EX_DFLALL|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_NOTRLCOM|EX_MODIFY,
|
||||||
ADDR_LINES),
|
ADDR_LINES),
|
||||||
|
@ -42,4 +42,5 @@ char_u *get_autoload_prefix(scriptitem_T *si);
|
|||||||
char_u *may_prefix_autoload(char_u *name);
|
char_u *may_prefix_autoload(char_u *name);
|
||||||
char_u *autoload_name(char_u *name);
|
char_u *autoload_name(char_u *name);
|
||||||
int script_autoload(char_u *name, int reload);
|
int script_autoload(char_u *name, int reload);
|
||||||
|
int sourcing_a_script(exarg_T *eap);
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
285
src/scriptfile.c
285
src/scriptfile.c
@ -18,6 +18,11 @@
|
|||||||
static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
|
static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// last used sequence number for sourcing scripts (current_sctx.sc_seq)
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
static int last_current_SID_seq = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the execution stack.
|
* Initialize the execution stack.
|
||||||
*/
|
*/
|
||||||
@ -1074,12 +1079,270 @@ ExpandPackAddDir(
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cookie used to source Ex commands from a buffer.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
garray_T lines_to_source;
|
||||||
|
int lnum;
|
||||||
|
linenr_T sourcing_lnum;
|
||||||
|
} bufline_cookie_T;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Concatenate a Vim script line if it starts with a line continuation into a
|
||||||
|
* growarray (excluding the continuation chars and leading whitespace).
|
||||||
|
* Growsize of the growarray may be changed to speed up concatenations!
|
||||||
|
*
|
||||||
|
* Returns TRUE if this line did begin with a continuation (the next line
|
||||||
|
* should also be considered, if it exists); FALSE otherwise.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
concat_continued_line(
|
||||||
|
garray_T *ga,
|
||||||
|
int init_growsize,
|
||||||
|
char_u *nextline,
|
||||||
|
int options)
|
||||||
|
{
|
||||||
|
int comment_char = in_vim9script() ? '#' : '"';
|
||||||
|
char_u *p = skipwhite(nextline);
|
||||||
|
int contline;
|
||||||
|
int do_vim9_all = in_vim9script()
|
||||||
|
&& options == GETLINE_CONCAT_ALL;
|
||||||
|
int do_bar_cont = do_vim9_all
|
||||||
|
|| options == GETLINE_CONCAT_CONTBAR;
|
||||||
|
|
||||||
|
if (*p == NUL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// Concatenate the next line when it starts with a backslash.
|
||||||
|
/* Also check for a comment in between continuation lines: "\ */
|
||||||
|
// Also check for a Vim9 comment, empty line, line starting with '|',
|
||||||
|
// but not "||".
|
||||||
|
if ((p[0] == comment_char && p[1] == '\\' && p[2] == ' ')
|
||||||
|
|| (do_vim9_all && (*p == NUL
|
||||||
|
|| vim9_comment_start(p))))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
contline = (*p == '\\' || (do_bar_cont && p[0] == '|' && p[1] != '|'));
|
||||||
|
if (!contline)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
// Adjust the growsize to the current length to speed up concatenating many
|
||||||
|
// lines.
|
||||||
|
if (ga->ga_len > init_growsize)
|
||||||
|
ga->ga_growsize = ga->ga_len > 8000 ? 8000 : ga->ga_len;
|
||||||
|
if (*p == '\\')
|
||||||
|
ga_concat(ga, (char_u *)p + 1);
|
||||||
|
else if (*p == '|')
|
||||||
|
{
|
||||||
|
ga_concat(ga, (char_u *)" ");
|
||||||
|
ga_concat(ga, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get one full line from a sourced string (in-memory, no file).
|
||||||
|
* Called by do_cmdline() when it's called from source_using_linegetter().
|
||||||
|
*
|
||||||
|
* Returns a pointer to allocated line, or NULL for end-of-file.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
source_getbufline(
|
||||||
|
int c UNUSED,
|
||||||
|
void *cookie,
|
||||||
|
int indent UNUSED,
|
||||||
|
getline_opt_T opts)
|
||||||
|
{
|
||||||
|
bufline_cookie_T *p = cookie;
|
||||||
|
char_u *line;
|
||||||
|
garray_T ga;
|
||||||
|
|
||||||
|
SOURCING_LNUM = p->sourcing_lnum + 1;
|
||||||
|
|
||||||
|
if (p->lnum >= p->lines_to_source.ga_len)
|
||||||
|
return NULL;
|
||||||
|
line = ((char_u **)p->lines_to_source.ga_data)[p->lnum];
|
||||||
|
|
||||||
|
ga_init2(&ga, sizeof(char_u), 400);
|
||||||
|
ga_concat(&ga, (char_u *)line);
|
||||||
|
p->lnum++;
|
||||||
|
|
||||||
|
if ((opts != GETLINE_NONE) && vim_strchr(p_cpo, CPO_CONCAT) == NULL)
|
||||||
|
{
|
||||||
|
while (p->lnum < p->lines_to_source.ga_len)
|
||||||
|
{
|
||||||
|
line = ((char_u **)p->lines_to_source.ga_data)[p->lnum];
|
||||||
|
if (!concat_continued_line(&ga, 400, line, opts))
|
||||||
|
break;
|
||||||
|
p->sourcing_lnum++;
|
||||||
|
p->lnum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ga_append(&ga, NUL);
|
||||||
|
p->sourcing_lnum++;
|
||||||
|
|
||||||
|
return ga.ga_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Source Ex commands from the lines in 'cookie'.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
do_sourcebuffer(
|
||||||
|
void *cookie,
|
||||||
|
char_u *scriptname)
|
||||||
|
{
|
||||||
|
char_u *save_sourcing_name = SOURCING_NAME;
|
||||||
|
linenr_T save_sourcing_lnum = SOURCING_LNUM;
|
||||||
|
char_u sourcing_name_buf[256];
|
||||||
|
sctx_T save_current_sctx;
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
int sid;
|
||||||
|
funccal_entry_T funccalp_entry;
|
||||||
|
int save_estack_compiling = estack_compiling;
|
||||||
|
scriptitem_T *si = NULL;
|
||||||
|
#endif
|
||||||
|
int save_sticky_cmdmod_flags = sticky_cmdmod_flags;
|
||||||
|
int retval = FAIL;
|
||||||
|
ESTACK_CHECK_DECLARATION
|
||||||
|
|
||||||
|
if (save_sourcing_name == NULL)
|
||||||
|
SOURCING_NAME = (char_u *)scriptname;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vim_snprintf((char *)sourcing_name_buf, sizeof(sourcing_name_buf),
|
||||||
|
"%s called at %s:%ld", scriptname, save_sourcing_name,
|
||||||
|
save_sourcing_lnum);
|
||||||
|
SOURCING_NAME = sourcing_name_buf;
|
||||||
|
}
|
||||||
|
SOURCING_LNUM = 0;
|
||||||
|
|
||||||
|
// Keep the sourcing name/lnum, for recursive calls.
|
||||||
|
estack_push(ETYPE_SCRIPT, scriptname, 0);
|
||||||
|
ESTACK_CHECK_SETUP
|
||||||
|
|
||||||
|
// "legacy" does not apply to commands in the script
|
||||||
|
sticky_cmdmod_flags = 0;
|
||||||
|
|
||||||
|
save_current_sctx = current_sctx;
|
||||||
|
current_sctx.sc_version = 1; // default script version
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
estack_compiling = FALSE;
|
||||||
|
// Always use a new sequence number.
|
||||||
|
current_sctx.sc_seq = ++last_current_SID_seq;
|
||||||
|
current_sctx.sc_lnum = save_sourcing_lnum;
|
||||||
|
save_funccal(&funccalp_entry);
|
||||||
|
|
||||||
|
sid = find_script_by_name(scriptname);
|
||||||
|
if (sid < 0)
|
||||||
|
{
|
||||||
|
int error = OK;
|
||||||
|
|
||||||
|
// First time sourcing this buffer, create a new script item.
|
||||||
|
|
||||||
|
sid = get_new_scriptitem(&error);
|
||||||
|
if (error == FAIL)
|
||||||
|
goto theend;
|
||||||
|
current_sctx.sc_sid = sid;
|
||||||
|
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
|
si->sn_name = vim_strsave(scriptname);
|
||||||
|
si->sn_state = SN_STATE_NEW;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the buffer was sourced previously, reuse the script ID.
|
||||||
|
current_sctx.sc_sid = sid;
|
||||||
|
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
|
si->sn_state = SN_STATE_RELOAD;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
retval = do_cmdline(NULL, source_getbufline, cookie,
|
||||||
|
DOCMD_VERBOSE | DOCMD_NOWAIT | DOCMD_REPEAT);
|
||||||
|
|
||||||
|
if (got_int)
|
||||||
|
emsg(_(e_interrupted));
|
||||||
|
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
theend:
|
||||||
|
#endif
|
||||||
|
ESTACK_CHECK_NOW
|
||||||
|
estack_pop();
|
||||||
|
current_sctx = save_current_sctx;
|
||||||
|
SOURCING_LNUM = save_sourcing_lnum;
|
||||||
|
SOURCING_NAME = save_sourcing_name;
|
||||||
|
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
restore_funccal();
|
||||||
|
estack_compiling = save_estack_compiling;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* :source Ex commands from the current buffer
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
cmd_source_buffer(exarg_T *eap)
|
||||||
|
{
|
||||||
|
char_u *line = NULL;
|
||||||
|
linenr_T curr_lnum;
|
||||||
|
bufline_cookie_T cp;
|
||||||
|
char_u sname[32];
|
||||||
|
|
||||||
|
if (curbuf == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Use ":source buffer=<num>" as the script name
|
||||||
|
vim_snprintf((char *)sname, sizeof(sname), ":source buffer=%d",
|
||||||
|
curbuf->b_fnum);
|
||||||
|
|
||||||
|
ga_init2(&cp.lines_to_source, sizeof(char_u *), 100);
|
||||||
|
|
||||||
|
// Copy the lines from the buffer into a grow array
|
||||||
|
for (curr_lnum = eap->line1; curr_lnum <= eap->line2; curr_lnum++)
|
||||||
|
{
|
||||||
|
line = vim_strsave(ml_get(curr_lnum));
|
||||||
|
if (line == NULL)
|
||||||
|
goto errret;
|
||||||
|
if (ga_add_string(&cp.lines_to_source, line) == FAIL)
|
||||||
|
goto errret;
|
||||||
|
line = NULL;
|
||||||
|
}
|
||||||
|
cp.sourcing_lnum = 0;
|
||||||
|
cp.lnum = 0;
|
||||||
|
|
||||||
|
// Execute the Ex commands
|
||||||
|
do_sourcebuffer((void *)&cp, (char_u *)sname);
|
||||||
|
|
||||||
|
errret:
|
||||||
|
vim_free(line);
|
||||||
|
ga_clear_strings(&cp.lines_to_source);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_source(char_u *fname, exarg_T *eap)
|
cmd_source(char_u *fname, exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (*fname == NUL)
|
if (*fname != NUL && eap != NULL && eap->addr_count > 0)
|
||||||
emsg(_(e_argument_required));
|
{
|
||||||
|
// if a filename is specified to :source, then a range is not allowed
|
||||||
|
emsg(_(e_no_range_allowed));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eap != NULL && *fname == NUL)
|
||||||
|
{
|
||||||
|
if (eap->forceit)
|
||||||
|
// a file name is needed to source normal mode commands
|
||||||
|
emsg(_(e_argument_required));
|
||||||
|
else
|
||||||
|
// source ex commands from the current buffer
|
||||||
|
cmd_source_buffer(eap);
|
||||||
|
}
|
||||||
else if (eap != NULL && eap->forceit)
|
else if (eap != NULL && eap->forceit)
|
||||||
// ":source!": read Normal mode commands
|
// ":source!": read Normal mode commands
|
||||||
// Need to execute the commands directly. This is required at least
|
// Need to execute the commands directly. This is required at least
|
||||||
@ -1240,7 +1503,6 @@ do_source(
|
|||||||
int retval = FAIL;
|
int retval = FAIL;
|
||||||
sctx_T save_current_sctx;
|
sctx_T save_current_sctx;
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
static int last_current_SID_seq = 0;
|
|
||||||
funccal_entry_T funccalp_entry;
|
funccal_entry_T funccalp_entry;
|
||||||
int save_debug_break_level = debug_break_level;
|
int save_debug_break_level = debug_break_level;
|
||||||
int sid;
|
int sid;
|
||||||
@ -2015,6 +2277,17 @@ getsourceline(
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns TRUE if sourcing a script either from a file or a buffer.
|
||||||
|
* Otherwise returns FALSE.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
sourcing_a_script(exarg_T *eap)
|
||||||
|
{
|
||||||
|
return (getline_equal(eap->getline, eap->cookie, getsourceline)
|
||||||
|
|| getline_equal(eap->getline, eap->cookie, source_getbufline));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ":scriptencoding": Set encoding conversion for a sourced script.
|
* ":scriptencoding": Set encoding conversion for a sourced script.
|
||||||
*/
|
*/
|
||||||
@ -2024,7 +2297,7 @@ ex_scriptencoding(exarg_T *eap)
|
|||||||
source_cookie_T *sp;
|
source_cookie_T *sp;
|
||||||
char_u *name;
|
char_u *name;
|
||||||
|
|
||||||
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
if (!sourcing_a_script(eap))
|
||||||
{
|
{
|
||||||
emsg(_(e_scriptencoding_used_outside_of_sourced_file));
|
emsg(_(e_scriptencoding_used_outside_of_sourced_file));
|
||||||
return;
|
return;
|
||||||
@ -2055,7 +2328,7 @@ ex_scriptversion(exarg_T *eap UNUSED)
|
|||||||
{
|
{
|
||||||
int nr;
|
int nr;
|
||||||
|
|
||||||
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
if (!sourcing_a_script(eap))
|
||||||
{
|
{
|
||||||
emsg(_(e_scriptversion_used_outside_of_sourced_file));
|
emsg(_(e_scriptversion_used_outside_of_sourced_file));
|
||||||
return;
|
return;
|
||||||
@ -2087,7 +2360,7 @@ ex_scriptversion(exarg_T *eap UNUSED)
|
|||||||
void
|
void
|
||||||
ex_finish(exarg_T *eap)
|
ex_finish(exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (getline_equal(eap->getline, eap->cookie, getsourceline))
|
if (sourcing_a_script(eap))
|
||||||
do_finish(eap, FALSE);
|
do_finish(eap, FALSE);
|
||||||
else
|
else
|
||||||
emsg(_(e_finish_used_outside_of_sourced_file));
|
emsg(_(e_finish_used_outside_of_sourced_file));
|
||||||
|
@ -94,6 +94,12 @@ func Test_source_error()
|
|||||||
call assert_fails('scriptencoding utf-8', 'E167:')
|
call assert_fails('scriptencoding utf-8', 'E167:')
|
||||||
call assert_fails('finish', 'E168:')
|
call assert_fails('finish', 'E168:')
|
||||||
call assert_fails('scriptversion 2', 'E984:')
|
call assert_fails('scriptversion 2', 'E984:')
|
||||||
|
call assert_fails('source!', 'E471:')
|
||||||
|
new
|
||||||
|
call setline(1, ['', '', '', ''])
|
||||||
|
call assert_fails('1,3source Xscript.vim', 'E481:')
|
||||||
|
call assert_fails('1,3source! Xscript.vim', 'E481:')
|
||||||
|
bw!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test for sourcing a script recursively
|
" Test for sourcing a script recursively
|
||||||
@ -110,4 +116,233 @@ func Test_nested_script()
|
|||||||
call StopVimInTerminal(buf)
|
call StopVimInTerminal(buf)
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for sourcing a script from the current buffer
|
||||||
|
func Test_source_buffer()
|
||||||
|
new
|
||||||
|
" Source a simple script
|
||||||
|
let lines =<< trim END
|
||||||
|
let a = "Test"
|
||||||
|
let b = 20
|
||||||
|
|
||||||
|
let c = [1.1]
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal(['Test', 20, [1.1]], [g:a, g:b, g:c])
|
||||||
|
|
||||||
|
" Source a range of lines in the current buffer
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let a = 10
|
||||||
|
let a += 20
|
||||||
|
let a += 30
|
||||||
|
let a += 40
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
.source
|
||||||
|
call assert_equal(10, g:a)
|
||||||
|
3source
|
||||||
|
call assert_equal(40, g:a)
|
||||||
|
2,3source
|
||||||
|
call assert_equal(90, g:a)
|
||||||
|
|
||||||
|
" Source a script with line continuation lines
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let m = [
|
||||||
|
\ 1,
|
||||||
|
\ 2,
|
||||||
|
\ ]
|
||||||
|
call add(m, 3)
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal([1, 2, 3], g:m)
|
||||||
|
" Source a script with line continuation lines and a comment
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let m = [
|
||||||
|
"\ first entry
|
||||||
|
\ 'a',
|
||||||
|
"\ second entry
|
||||||
|
\ 'b',
|
||||||
|
\ ]
|
||||||
|
" third entry
|
||||||
|
call add(m, 'c')
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal(['a', 'b', 'c'], g:m)
|
||||||
|
" Source an incomplete line continuation line
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let k = [
|
||||||
|
\
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
call assert_fails('source', 'E697:')
|
||||||
|
" Source a function with a for loop
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let m = []
|
||||||
|
" test function
|
||||||
|
func! Xtest()
|
||||||
|
for i in range(5, 7)
|
||||||
|
call add(g:m, i)
|
||||||
|
endfor
|
||||||
|
endfunc
|
||||||
|
call Xtest()
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal([5, 6, 7], g:m)
|
||||||
|
" Source an empty buffer
|
||||||
|
%d _
|
||||||
|
source
|
||||||
|
|
||||||
|
" test for script local functions and variables
|
||||||
|
let lines =<< trim END
|
||||||
|
let s:var1 = 10
|
||||||
|
func s:F1()
|
||||||
|
let s:var1 += 1
|
||||||
|
return s:var1
|
||||||
|
endfunc
|
||||||
|
func s:F2()
|
||||||
|
endfunc
|
||||||
|
let g:ScriptID = expand("<SID>")
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_true(g:ScriptID != '')
|
||||||
|
call assert_true(exists('*' .. g:ScriptID .. 'F1'))
|
||||||
|
call assert_true(exists('*' .. g:ScriptID .. 'F2'))
|
||||||
|
call assert_equal(11, call(g:ScriptID .. 'F1', []))
|
||||||
|
|
||||||
|
" the same script ID should be used even if the buffer is sourced more than
|
||||||
|
" once
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let g:ScriptID = expand("<SID>")
|
||||||
|
let g:Count += 1
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
let g:Count = 0
|
||||||
|
source
|
||||||
|
call assert_true(g:ScriptID != '')
|
||||||
|
let scid = g:ScriptID
|
||||||
|
source
|
||||||
|
call assert_equal(scid, g:ScriptID)
|
||||||
|
call assert_equal(2, g:Count)
|
||||||
|
source
|
||||||
|
call assert_equal(scid, g:ScriptID)
|
||||||
|
call assert_equal(3, g:Count)
|
||||||
|
|
||||||
|
" test for the script line number
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
" comment
|
||||||
|
let g:Slnum1 = expand("<slnum>")
|
||||||
|
let i = 1 +
|
||||||
|
\ 2 +
|
||||||
|
"\ comment
|
||||||
|
\ 3
|
||||||
|
let g:Slnum2 = expand("<slnum>")
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal('2', g:Slnum1)
|
||||||
|
call assert_equal('7', g:Slnum2)
|
||||||
|
|
||||||
|
" test for retaining the same script number across source calls
|
||||||
|
let lines =<< trim END
|
||||||
|
let g:ScriptID1 = expand("<SID>")
|
||||||
|
let g:Slnum1 = expand("<slnum>")
|
||||||
|
let l =<< trim END
|
||||||
|
let g:Slnum2 = expand("<slnum>")
|
||||||
|
let g:ScriptID2 = expand("<SID>")
|
||||||
|
END
|
||||||
|
new
|
||||||
|
call setline(1, l)
|
||||||
|
source
|
||||||
|
bw!
|
||||||
|
let g:ScriptID3 = expand("<SID>")
|
||||||
|
let g:Slnum3 = expand("<slnum>")
|
||||||
|
END
|
||||||
|
call writefile(lines, 'Xscript')
|
||||||
|
source Xscript
|
||||||
|
call assert_true(g:ScriptID1 != g:ScriptID2)
|
||||||
|
call assert_equal(g:ScriptID1, g:ScriptID3)
|
||||||
|
call assert_equal('2', g:Slnum1)
|
||||||
|
call assert_equal('1', g:Slnum2)
|
||||||
|
call assert_equal('12', g:Slnum3)
|
||||||
|
call delete('Xscript')
|
||||||
|
|
||||||
|
" test for sourcing a heredoc
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let a = 1
|
||||||
|
let heredoc =<< trim DATA
|
||||||
|
red
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
DATA
|
||||||
|
let b = 2
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal(['red', ' green', 'blue'], g:heredoc)
|
||||||
|
|
||||||
|
" test for a while and for statement
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let a = 0
|
||||||
|
let b = 1
|
||||||
|
while b <= 10
|
||||||
|
let a += 10
|
||||||
|
let b += 1
|
||||||
|
endwhile
|
||||||
|
for i in range(5)
|
||||||
|
let a += 10
|
||||||
|
endfor
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal(150, g:a)
|
||||||
|
|
||||||
|
" test for sourcing the same buffer multiple times after changing a function
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
func Xtestfunc()
|
||||||
|
return "one"
|
||||||
|
endfunc
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal("one", Xtestfunc())
|
||||||
|
call setline(2, ' return "two"')
|
||||||
|
source
|
||||||
|
call assert_equal("two", Xtestfunc())
|
||||||
|
call setline(2, ' return "three"')
|
||||||
|
source
|
||||||
|
call assert_equal("three", Xtestfunc())
|
||||||
|
delfunc Xtestfunc
|
||||||
|
|
||||||
|
" test for sourcing a Vim9 script
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
# check dict
|
||||||
|
var x: number = 10
|
||||||
|
def g:Xtestfunc(): number
|
||||||
|
return x
|
||||||
|
enddef
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal(10, Xtestfunc())
|
||||||
|
|
||||||
|
%bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
4594,
|
||||||
/**/
|
/**/
|
||||||
4593,
|
4593,
|
||||||
/**/
|
/**/
|
||||||
|
@ -71,7 +71,7 @@ ex_vim9script(exarg_T *eap UNUSED)
|
|||||||
int found_noclear = FALSE;
|
int found_noclear = FALSE;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
|
||||||
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
if (!sourcing_a_script(eap))
|
||||||
{
|
{
|
||||||
emsg(_(e_vim9script_can_only_be_used_in_script));
|
emsg(_(e_vim9script_can_only_be_used_in_script));
|
||||||
return;
|
return;
|
||||||
@ -633,7 +633,7 @@ ex_import(exarg_T *eap)
|
|||||||
char_u *cmd_end;
|
char_u *cmd_end;
|
||||||
evalarg_T evalarg;
|
evalarg_T evalarg;
|
||||||
|
|
||||||
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
if (!sourcing_a_script(eap))
|
||||||
{
|
{
|
||||||
emsg(_(e_import_can_only_be_used_in_script));
|
emsg(_(e_import_can_only_be_used_in_script));
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user