mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
Merge pull request #28486 from zeertzjq/vim-8.2.4603
vim-patch:8.2.{4594,4603,4607,4647,4974}
This commit is contained in:
@@ -192,14 +192,23 @@ Using Vim scripts *using-scripts*
|
|||||||
For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
|
For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
|
||||||
|
|
||||||
*:so* *:source* *load-vim-script*
|
*:so* *:source* *load-vim-script*
|
||||||
:[range]so[urce] [file] Runs |Ex-commands| or Lua code (".lua" files) from
|
:so[urce] {file} Runs |Ex-commands| or Lua code (".lua" files) from
|
||||||
[file].
|
{file}.
|
||||||
If no [file], the current buffer is used and treated
|
|
||||||
as Lua code if 'filetype' is "lua" or its filename
|
|
||||||
ends with ".lua".
|
|
||||||
Triggers the |SourcePre| autocommand.
|
Triggers the |SourcePre| autocommand.
|
||||||
|
|
||||||
|
:[range]so[urce] Read Ex commands or Lua code from the [range] of lines
|
||||||
|
in the current buffer. When [range] is omitted read
|
||||||
|
all lines. The buffer is treated as Lua code if its
|
||||||
|
'filetype' is "lua" or its filename ends with ".lua".
|
||||||
|
|
||||||
|
When sourcing commands or Lua code from the current
|
||||||
|
buffer, the same script-ID |<SID>| is used even if the
|
||||||
|
buffer is sourced multiple times. If a buffer is
|
||||||
|
sourced more than once, then the functions in the
|
||||||
|
buffer are defined again.
|
||||||
|
|
||||||
*:source!*
|
*:source!*
|
||||||
:[range]so[urce]! {file}
|
:so[urce]! {file}
|
||||||
Runs |Normal-mode| commands from {file}. When used
|
Runs |Normal-mode| commands from {file}. When used
|
||||||
after |:global|, |:argdo|, |:windo|, |:bufdo|, in
|
after |:global|, |:argdo|, |:windo|, |:bufdo|, in
|
||||||
a loop or when another command follows the display
|
a loop or when another command follows the display
|
||||||
@@ -389,10 +398,10 @@ An alternative is to put the commands in a file, and execute them with the
|
|||||||
':source!' command. Useful for long command sequences. Can be combined with
|
':source!' command. Useful for long command sequences. Can be combined with
|
||||||
the ':map' command to put complicated commands under a function key.
|
the ':map' command to put complicated commands under a function key.
|
||||||
|
|
||||||
The ':source' command reads Ex commands from a file line by line. You will
|
The ':source' command reads Ex commands from a file or a buffer line by line.
|
||||||
have to type any needed keyboard input. The ':source!' command reads from a
|
You will have to type any needed keyboard input. The ':source!' command reads
|
||||||
script file character by character, interpreting each character as if you
|
from a script file character by character, interpreting each character as if
|
||||||
typed it.
|
you typed it.
|
||||||
|
|
||||||
Example: When you give the ":!ls" command you get the |hit-enter| prompt. If
|
Example: When you give the ":!ls" command you get the |hit-enter| prompt. If
|
||||||
you ':source' a file with the line "!ls" in it, you will have to type the
|
you ':source' a file with the line "!ls" in it, you will have to type the
|
||||||
|
@@ -759,7 +759,7 @@ void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getline_equal(eap->ea_getline, eap->cookie, getsourceline)) {
|
if (sourcing_a_script(eap)) {
|
||||||
evalarg->eval_getline = eap->ea_getline;
|
evalarg->eval_getline = eap->ea_getline;
|
||||||
evalarg->eval_cookie = eap->cookie;
|
evalarg->eval_cookie = eap->cookie;
|
||||||
}
|
}
|
||||||
|
@@ -2533,7 +2533,7 @@ M.cmds = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
command = 'source',
|
command = 'source',
|
||||||
flags = bit.bor(RANGE, DFLALL, WHOLEFOLD, BANG, FILE1, TRLBAR, SBOXOK, CMDWIN, LOCK_OK),
|
flags = bit.bor(RANGE, DFLALL, BANG, FILE1, TRLBAR, SBOXOK, CMDWIN, LOCK_OK),
|
||||||
addr_type = 'ADDR_LINES',
|
addr_type = 'ADDR_LINES',
|
||||||
func = 'ex_source',
|
func = 'ex_source',
|
||||||
},
|
},
|
||||||
|
@@ -198,12 +198,13 @@ void ga_concat(garray_T *gap, const char *restrict s)
|
|||||||
void ga_concat_len(garray_T *const gap, const char *restrict s, const size_t len)
|
void ga_concat_len(garray_T *const gap, const char *restrict s, const size_t len)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
if (len) {
|
if (len == 0) {
|
||||||
ga_grow(gap, (int)len);
|
return;
|
||||||
char *data = gap->ga_data;
|
|
||||||
memcpy(data + gap->ga_len, s, len);
|
|
||||||
gap->ga_len += (int)len;
|
|
||||||
}
|
}
|
||||||
|
ga_grow(gap, (int)len);
|
||||||
|
char *data = gap->ga_data;
|
||||||
|
memcpy(data + gap->ga_len, s, len);
|
||||||
|
gap->ga_len += (int)len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append one byte to a growarray which contains bytes.
|
/// Append one byte to a growarray which contains bytes.
|
||||||
|
@@ -1461,19 +1461,12 @@ static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, const char *name
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nlua_source_str(const char *code, char *name)
|
void nlua_exec_ga(garray_T *ga, char *name)
|
||||||
{
|
{
|
||||||
const sctx_T save_current_sctx = current_sctx;
|
char *code = ga_concat_strings_sep(ga, "\n");
|
||||||
current_sctx.sc_sid = SID_STR;
|
|
||||||
current_sctx.sc_seq = 0;
|
|
||||||
current_sctx.sc_lnum = 0;
|
|
||||||
estack_push(ETYPE_SCRIPT, name, 0);
|
|
||||||
|
|
||||||
size_t len = strlen(code);
|
size_t len = strlen(code);
|
||||||
nlua_typval_exec(code, len, name, NULL, 0, false, NULL);
|
nlua_typval_exec(code, len, name, NULL, 0, false, NULL);
|
||||||
|
xfree(code);
|
||||||
estack_pop();
|
|
||||||
current_sctx = save_current_sctx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call a LuaCallable given some typvals
|
/// Call a LuaCallable given some typvals
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include "nvim/api/private/helpers.h"
|
#include "nvim/api/private/helpers.h"
|
||||||
#include "nvim/cmdexpand_defs.h" // IWYU pragma: keep
|
#include "nvim/cmdexpand_defs.h" // IWYU pragma: keep
|
||||||
#include "nvim/ex_cmds_defs.h" // IWYU pragma: keep
|
#include "nvim/ex_cmds_defs.h" // IWYU pragma: keep
|
||||||
|
#include "nvim/garray_defs.h" // IWYU pragma: keep
|
||||||
#include "nvim/macros_defs.h"
|
#include "nvim/macros_defs.h"
|
||||||
#include "nvim/types_defs.h"
|
#include "nvim/types_defs.h"
|
||||||
#include "nvim/usercmd.h" // IWYU pragma: keep
|
#include "nvim/usercmd.h" // IWYU pragma: keep
|
||||||
|
@@ -75,7 +75,10 @@ typedef struct {
|
|||||||
FILE *fp; ///< opened file for sourcing
|
FILE *fp; ///< opened file for sourcing
|
||||||
char *nextline; ///< if not NULL: line that was read ahead
|
char *nextline; ///< if not NULL: line that was read ahead
|
||||||
linenr_T sourcing_lnum; ///< line number of the source file
|
linenr_T sourcing_lnum; ///< line number of the source file
|
||||||
int finished; ///< ":finish" used
|
bool finished; ///< ":finish" used
|
||||||
|
bool source_from_buf_or_str; ///< true if sourcing from a buffer or string
|
||||||
|
int buf_lnum; ///< line number in the buffer or string
|
||||||
|
garray_T buflines; ///< lines in the buffer or string
|
||||||
#ifdef USE_CRNL
|
#ifdef USE_CRNL
|
||||||
int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS
|
int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS
|
||||||
bool error; ///< true if LF found after CR-LF
|
bool error; ///< true if LF found after CR-LF
|
||||||
@@ -106,6 +109,7 @@ garray_T script_items = { 0, 0, sizeof(scriptitem_T *), 20, NULL };
|
|||||||
/// The names of packages that once were loaded are remembered.
|
/// The names of packages that once were loaded are remembered.
|
||||||
static garray_T ga_loaded = { 0, 0, sizeof(char *), 4, NULL };
|
static garray_T ga_loaded = { 0, 0, sizeof(char *), 4, NULL };
|
||||||
|
|
||||||
|
/// last used sequence number for sourcing scripts (current_sctx.sc_seq)
|
||||||
static int last_current_SID_seq = 0;
|
static int last_current_SID_seq = 0;
|
||||||
|
|
||||||
/// Initialize the execution stack.
|
/// Initialize the execution stack.
|
||||||
@@ -1825,8 +1829,20 @@ freeall:
|
|||||||
|
|
||||||
static void cmd_source(char *fname, exarg_T *eap)
|
static void cmd_source(char *fname, exarg_T *eap)
|
||||||
{
|
{
|
||||||
|
if (*fname != NUL && eap != NULL && eap->addr_count > 0) {
|
||||||
|
// if a filename is specified to :source, then a range is not allowed
|
||||||
|
emsg(_(e_norange));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (eap != NULL && *fname == NUL) {
|
if (eap != NULL && *fname == NUL) {
|
||||||
cmd_source_buffer(eap, false);
|
if (eap->forceit) {
|
||||||
|
// a file name is needed to source normal mode commands
|
||||||
|
emsg(_(e_argreq));
|
||||||
|
} else {
|
||||||
|
// source ex commands from the current buffer
|
||||||
|
cmd_source_buffer(eap, false);
|
||||||
|
}
|
||||||
} 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
|
||||||
@@ -1934,42 +1950,6 @@ static bool concat_continued_line(garray_T *const ga, const int init_growsize, c
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *buf;
|
|
||||||
size_t offset;
|
|
||||||
} GetStrLineCookie;
|
|
||||||
|
|
||||||
/// Get one full line from a sourced string (in-memory, no file).
|
|
||||||
/// Called by do_cmdline() when it's called from do_source_str().
|
|
||||||
///
|
|
||||||
/// @return pointer to allocated line, or NULL for end-of-file or
|
|
||||||
/// some error.
|
|
||||||
static char *get_str_line(int c, void *cookie, int indent, bool do_concat)
|
|
||||||
{
|
|
||||||
GetStrLineCookie *p = cookie;
|
|
||||||
if (strlen(p->buf) <= p->offset) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
const char *line = p->buf + p->offset;
|
|
||||||
const char *eol = skip_to_newline(line);
|
|
||||||
garray_T ga;
|
|
||||||
ga_init(&ga, sizeof(char), 400);
|
|
||||||
ga_concat_len(&ga, line, (size_t)(eol - line));
|
|
||||||
if (do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL) {
|
|
||||||
while (eol[0] != NUL) {
|
|
||||||
line = eol + 1;
|
|
||||||
const char *const next_eol = skip_to_newline(line);
|
|
||||||
if (!concat_continued_line(&ga, 400, line, (size_t)(next_eol - line))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
eol = next_eol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ga_append(&ga, NUL);
|
|
||||||
p->offset = (size_t)(eol - p->buf) + 1;
|
|
||||||
return ga.ga_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new script item and allocate script-local vars. @see new_script_vars
|
/// Create a new script item and allocate script-local vars. @see new_script_vars
|
||||||
///
|
///
|
||||||
/// @param name File name of the script. NULL for anonymous :source.
|
/// @param name File name of the script. NULL for anonymous :source.
|
||||||
@@ -1977,6 +1957,7 @@ static char *get_str_line(int c, void *cookie, int indent, bool do_concat)
|
|||||||
///
|
///
|
||||||
/// @return pointer to the created script item.
|
/// @return pointer to the created script item.
|
||||||
scriptitem_T *new_script_item(char *const name, scid_T *const sid_out)
|
scriptitem_T *new_script_item(char *const name, scid_T *const sid_out)
|
||||||
|
FUNC_ATTR_NONNULL_RET
|
||||||
{
|
{
|
||||||
static scid_T last_current_SID = 0;
|
static scid_T last_current_SID = 0;
|
||||||
const scid_T sid = ++last_current_SID;
|
const scid_T sid = ++last_current_SID;
|
||||||
@@ -1999,99 +1980,97 @@ scriptitem_T *new_script_item(char *const name, scid_T *const sid_out)
|
|||||||
return SCRIPT_ITEM(sid);
|
return SCRIPT_ITEM(sid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int source_using_linegetter(void *cookie, LineGetter fgetline, const char *traceback_name)
|
/// Initialization for sourcing lines from the current buffer. Reads all the
|
||||||
|
/// lines from the buffer and stores it in the cookie grow array.
|
||||||
|
/// Returns a pointer to the name ":source buffer=<n>" on success and NULL on failure.
|
||||||
|
static char *do_source_buffer_init(source_cookie_T *sp, const exarg_T *eap, bool ex_lua)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
char *save_sourcing_name = SOURCING_NAME;
|
if (curbuf == NULL) {
|
||||||
linenr_T save_sourcing_lnum = SOURCING_LNUM;
|
return NULL;
|
||||||
char sourcing_name_buf[256];
|
|
||||||
char *sname;
|
|
||||||
if (save_sourcing_name == NULL) {
|
|
||||||
sname = (char *)traceback_name;
|
|
||||||
} else {
|
|
||||||
snprintf(sourcing_name_buf, sizeof(sourcing_name_buf),
|
|
||||||
"%s called at %s:%" PRIdLINENR, traceback_name, save_sourcing_name,
|
|
||||||
save_sourcing_lnum);
|
|
||||||
sname = sourcing_name_buf;
|
|
||||||
}
|
}
|
||||||
estack_push(ETYPE_SCRIPT, sname, 0);
|
|
||||||
|
|
||||||
const sctx_T save_current_sctx = current_sctx;
|
if (ex_lua) {
|
||||||
if (!script_is_lua(current_sctx.sc_sid)) {
|
// Use ":{range}lua buffer=<num>" as the script name
|
||||||
current_sctx.sc_sid = SID_STR;
|
snprintf(IObuff, IOSIZE, ":{range}lua buffer=%d", curbuf->b_fnum);
|
||||||
|
} else {
|
||||||
|
// Use ":source buffer=<num>" as the script name
|
||||||
|
snprintf(IObuff, IOSIZE, ":source buffer=%d", curbuf->b_fnum);
|
||||||
}
|
}
|
||||||
current_sctx.sc_seq = 0;
|
char *fname = xstrdup(IObuff);
|
||||||
current_sctx.sc_lnum = save_sourcing_lnum;
|
|
||||||
funccal_entry_T entry;
|
ga_init(&sp->buflines, sizeof(char *), 100);
|
||||||
save_funccal(&entry);
|
// Copy the lines from the buffer into a grow array
|
||||||
int retval = do_cmdline(NULL, fgetline, cookie,
|
for (linenr_T curr_lnum = eap->line1; curr_lnum <= eap->line2; curr_lnum++) {
|
||||||
DOCMD_VERBOSE | DOCMD_NOWAIT | DOCMD_REPEAT);
|
GA_APPEND(char *, &sp->buflines, xstrdup(ml_get(curr_lnum)));
|
||||||
estack_pop();
|
}
|
||||||
current_sctx = save_current_sctx;
|
sp->buf_lnum = 0;
|
||||||
restore_funccal();
|
sp->source_from_buf_or_str = true;
|
||||||
return retval;
|
// When sourcing a range of lines from a buffer, use buffer line number.
|
||||||
|
sp->sourcing_lnum = eap->line1 - 1;
|
||||||
|
|
||||||
|
return fname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialization for sourcing lines from a string. Reads all the
|
||||||
|
/// lines from the string and stores it in the cookie grow array.
|
||||||
|
static void do_source_str_init(source_cookie_T *sp, const char *str)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
ga_init(&sp->buflines, sizeof(char *), 100);
|
||||||
|
// Copy the lines from the string into a grow array
|
||||||
|
while (*str != NUL) {
|
||||||
|
const char *eol = skip_to_newline(str);
|
||||||
|
GA_APPEND(char *, &sp->buflines, xmemdupz(str, (size_t)(eol - str)));
|
||||||
|
str = eol + (*eol != NUL);
|
||||||
|
}
|
||||||
|
sp->buf_lnum = 0;
|
||||||
|
sp->source_from_buf_or_str = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_source_buffer(const exarg_T *const eap, bool ex_lua)
|
void cmd_source_buffer(const exarg_T *const eap, bool ex_lua)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
if (curbuf == NULL) {
|
do_source_ext(NULL, false, DOSO_NONE, NULL, eap, ex_lua, NULL);
|
||||||
return;
|
|
||||||
}
|
|
||||||
garray_T ga;
|
|
||||||
ga_init(&ga, sizeof(char), 400);
|
|
||||||
const linenr_T final_lnum = eap->line2;
|
|
||||||
// Copy the contents to be executed.
|
|
||||||
for (linenr_T curr_lnum = eap->line1; curr_lnum <= final_lnum; curr_lnum++) {
|
|
||||||
// Adjust growsize to current length to speed up concatenating many lines.
|
|
||||||
if (ga.ga_len > 400) {
|
|
||||||
ga_set_growsize(&ga, MIN(ga.ga_len, 8000));
|
|
||||||
}
|
|
||||||
ga_concat(&ga, ml_get(curr_lnum));
|
|
||||||
ga_append(&ga, NL);
|
|
||||||
}
|
|
||||||
((char *)ga.ga_data)[ga.ga_len - 1] = NUL;
|
|
||||||
if (ex_lua || strequal(curbuf->b_p_ft, "lua")
|
|
||||||
|| (curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua"))) {
|
|
||||||
char *name = ex_lua ? ":{range}lua" : ":source (no file)";
|
|
||||||
nlua_source_str(ga.ga_data, name);
|
|
||||||
} else {
|
|
||||||
const GetStrLineCookie cookie = {
|
|
||||||
.buf = ga.ga_data,
|
|
||||||
.offset = 0,
|
|
||||||
};
|
|
||||||
source_using_linegetter((void *)&cookie, get_str_line, ":source (no file)");
|
|
||||||
}
|
|
||||||
ga_clear(&ga);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes lines in `src` as Ex commands.
|
/// Executes lines in `str` as Ex commands.
|
||||||
///
|
///
|
||||||
/// @see do_source()
|
/// @see do_source_ext()
|
||||||
int do_source_str(const char *cmd, const char *traceback_name)
|
int do_source_str(const char *str, char *traceback_name)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
GetStrLineCookie cookie = {
|
char *const sourcing_name = SOURCING_NAME;
|
||||||
.buf = (char *)cmd,
|
const linenr_T sourcing_lnum = SOURCING_LNUM;
|
||||||
.offset = 0,
|
char sname_buf[256];
|
||||||
};
|
if (sourcing_name != NULL) {
|
||||||
return source_using_linegetter((void *)&cookie, get_str_line, traceback_name);
|
snprintf(sname_buf, sizeof(sname_buf), "%s called at %s:%" PRIdLINENR,
|
||||||
|
traceback_name, sourcing_name, sourcing_lnum);
|
||||||
|
traceback_name = sname_buf;
|
||||||
|
}
|
||||||
|
return do_source_ext(traceback_name, false, DOSO_NONE, NULL, NULL, false, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When fname is a 'lua' file nlua_exec_file() is invoked to source it.
|
/// When fname is a .lua file nlua_exec_file() is invoked to source it.
|
||||||
/// Otherwise reads the file `fname` and executes its lines as Ex commands.
|
/// Otherwise reads the file `fname` and executes its lines as Ex commands.
|
||||||
///
|
///
|
||||||
/// This function may be called recursively!
|
/// This function may be called recursively!
|
||||||
///
|
///
|
||||||
/// @see do_source_str
|
/// @see do_source_str
|
||||||
///
|
///
|
||||||
/// @param fname
|
/// @param fname if NULL, source from the current buffer
|
||||||
/// @param check_other check for .vimrc and _vimrc
|
/// @param check_other check for .vimrc and _vimrc
|
||||||
/// @param is_vimrc DOSO_ value
|
/// @param is_vimrc DOSO_ value
|
||||||
/// @param ret_sid if not NULL and we loaded the script before, don't load it again
|
/// @param ret_sid if not NULL and we loaded the script before, don't load it again
|
||||||
|
/// @param eap used when sourcing lines from a buffer instead of a file
|
||||||
|
/// @param str if not NULL, source from the given string
|
||||||
///
|
///
|
||||||
/// @return FAIL if file could not be opened, OK otherwise
|
/// @return FAIL if file could not be opened, OK otherwise
|
||||||
///
|
///
|
||||||
/// If a scriptitem_T was found or created "*ret_sid" is set to the SID.
|
/// If a scriptitem_T was found or created "*ret_sid" is set to the SID.
|
||||||
int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
static int do_source_ext(char *const fname, const bool check_other, const int is_vimrc,
|
||||||
|
int *const ret_sid, const exarg_T *const eap, const bool ex_lua,
|
||||||
|
const char *const str)
|
||||||
{
|
{
|
||||||
source_cookie_T cookie;
|
source_cookie_T cookie;
|
||||||
uint8_t *firstline = NULL;
|
uint8_t *firstline = NULL;
|
||||||
@@ -2101,22 +2080,36 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
proftime_T wait_start;
|
proftime_T wait_start;
|
||||||
bool trigger_source_post = false;
|
bool trigger_source_post = false;
|
||||||
|
|
||||||
char *p = expand_env_save(fname);
|
CLEAR_FIELD(cookie);
|
||||||
if (p == NULL) {
|
char *fname_exp = NULL;
|
||||||
return retval;
|
if (fname == NULL) {
|
||||||
}
|
assert(str == NULL);
|
||||||
char *fname_exp = fix_fname(p);
|
// sourcing lines from a buffer
|
||||||
xfree(p);
|
fname_exp = do_source_buffer_init(&cookie, eap, ex_lua);
|
||||||
if (fname_exp == NULL) {
|
if (fname_exp == NULL) {
|
||||||
return retval;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if (os_isdir(fname_exp)) {
|
} else if (str != NULL) {
|
||||||
smsg(0, _("Cannot source a directory: \"%s\""), fname);
|
do_source_str_init(&cookie, str);
|
||||||
goto theend;
|
fname_exp = xstrdup(fname);
|
||||||
|
} else {
|
||||||
|
char *p = expand_env_save(fname);
|
||||||
|
if (p == NULL) {
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
fname_exp = fix_fname(p);
|
||||||
|
xfree(p);
|
||||||
|
if (fname_exp == NULL) {
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
if (os_isdir(fname_exp)) {
|
||||||
|
smsg(0, _("Cannot source a directory: \"%s\""), fname);
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if we loaded this script before.
|
// See if we loaded this script before.
|
||||||
int sid = find_script_by_name(fname_exp);
|
int sid = str != NULL ? SID_STR : find_script_by_name(fname_exp);
|
||||||
if (sid > 0 && ret_sid != NULL) {
|
if (sid > 0 && ret_sid != NULL) {
|
||||||
// Already loaded and no need to load again, return here.
|
// Already loaded and no need to load again, return here.
|
||||||
*ret_sid = sid;
|
*ret_sid = sid;
|
||||||
@@ -2124,26 +2117,30 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
goto theend;
|
goto theend;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply SourceCmd autocommands, they should get the file and source it.
|
if (str == NULL) {
|
||||||
if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
|
// Apply SourceCmd autocommands, they should get the file and source it.
|
||||||
&& apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
|
if (has_autocmd(EVENT_SOURCECMD, fname_exp, NULL)
|
||||||
false, curbuf)) {
|
&& apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
|
||||||
retval = aborting() ? FAIL : OK;
|
false, curbuf)) {
|
||||||
if (retval == OK) {
|
retval = aborting() ? FAIL : OK;
|
||||||
// Apply SourcePost autocommands.
|
if (retval == OK) {
|
||||||
apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
|
// Apply SourcePost autocommands.
|
||||||
|
apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
|
||||||
|
}
|
||||||
|
goto theend;
|
||||||
}
|
}
|
||||||
goto theend;
|
|
||||||
|
// Apply SourcePre autocommands, they may get the file.
|
||||||
|
apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, false, curbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply SourcePre autocommands, they may get the file.
|
if (!cookie.source_from_buf_or_str) {
|
||||||
apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, false, curbuf);
|
cookie.fp = fopen_noinh_readbin(fname_exp);
|
||||||
|
}
|
||||||
cookie.fp = fopen_noinh_readbin(fname_exp);
|
|
||||||
if (cookie.fp == NULL && check_other) {
|
if (cookie.fp == NULL && check_other) {
|
||||||
// Try again, replacing file name ".nvimrc" by "_nvimrc" or vice versa,
|
// Try again, replacing file name ".nvimrc" by "_nvimrc" or vice versa,
|
||||||
// and ".exrc" by "_exrc" or vice versa.
|
// and ".exrc" by "_exrc" or vice versa.
|
||||||
p = path_tail(fname_exp);
|
char *p = path_tail(fname_exp);
|
||||||
if ((*p == '.' || *p == '_')
|
if ((*p == '.' || *p == '_')
|
||||||
&& (STRICMP(p + 1, "nvimrc") == 0 || STRICMP(p + 1, "exrc") == 0)) {
|
&& (STRICMP(p + 1, "nvimrc") == 0 || STRICMP(p + 1, "exrc") == 0)) {
|
||||||
*p = (*p == '_') ? '.' : '_';
|
*p = (*p == '_') ? '.' : '_';
|
||||||
@@ -2151,7 +2148,7 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cookie.fp == NULL) {
|
if (cookie.fp == NULL && !cookie.source_from_buf_or_str) {
|
||||||
if (p_verbose > 1) {
|
if (p_verbose > 1) {
|
||||||
verbose_enter();
|
verbose_enter();
|
||||||
if (SOURCING_NAME == NULL) {
|
if (SOURCING_NAME == NULL) {
|
||||||
@@ -2188,13 +2185,8 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
} else {
|
} else {
|
||||||
cookie.fileformat = EOL_UNKNOWN;
|
cookie.fileformat = EOL_UNKNOWN;
|
||||||
}
|
}
|
||||||
cookie.error = false;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cookie.nextline = NULL;
|
|
||||||
cookie.sourcing_lnum = 0;
|
|
||||||
cookie.finished = false;
|
|
||||||
|
|
||||||
// Check if this script has a breakpoint.
|
// Check if this script has a breakpoint.
|
||||||
cookie.breakpoint = dbg_find_breakpoint(true, fname_exp, 0);
|
cookie.breakpoint = dbg_find_breakpoint(true, fname_exp, 0);
|
||||||
cookie.fname = fname_exp;
|
cookie.fname = fname_exp;
|
||||||
@@ -2223,15 +2215,13 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
|
|
||||||
const sctx_T save_current_sctx = current_sctx;
|
const sctx_T save_current_sctx = current_sctx;
|
||||||
|
|
||||||
current_sctx.sc_lnum = 0;
|
|
||||||
|
|
||||||
// Always use a new sequence number.
|
// Always use a new sequence number.
|
||||||
current_sctx.sc_seq = ++last_current_SID_seq;
|
current_sctx.sc_seq = ++last_current_SID_seq;
|
||||||
|
|
||||||
if (sid > 0) {
|
if (sid > 0) {
|
||||||
// loading the same script again
|
// loading the same script again
|
||||||
si = SCRIPT_ITEM(sid);
|
si = SCRIPT_ITEM(sid);
|
||||||
} else {
|
} else if (str == NULL) {
|
||||||
// It's new, generate a new SID.
|
// It's new, generate a new SID.
|
||||||
si = new_script_item(fname_exp, &sid);
|
si = new_script_item(fname_exp, &sid);
|
||||||
si->sn_lua = path_with_extension(fname_exp, "lua");
|
si->sn_lua = path_with_extension(fname_exp, "lua");
|
||||||
@@ -2240,12 +2230,20 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
*ret_sid = sid;
|
*ret_sid = sid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current_sctx.sc_sid = sid;
|
// Sourcing a string doesn't allocate a script item immediately.
|
||||||
|
assert((si != NULL) == (str == NULL));
|
||||||
|
|
||||||
|
// Don't change sc_sid to SID_STR when sourcing a string from a Lua script,
|
||||||
|
// as keeping the current sc_sid allows more useful :verbose messages.
|
||||||
|
if (str == NULL || !script_is_lua(current_sctx.sc_sid)) {
|
||||||
|
current_sctx.sc_sid = sid;
|
||||||
|
current_sctx.sc_lnum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Keep the sourcing name/lnum, for recursive calls.
|
// Keep the sourcing name/lnum, for recursive calls.
|
||||||
estack_push(ETYPE_SCRIPT, si->sn_name, 0);
|
estack_push(ETYPE_SCRIPT, si != NULL ? si->sn_name : fname_exp, 0);
|
||||||
|
|
||||||
if (l_do_profiling == PROF_YES) {
|
if (l_do_profiling == PROF_YES && si != NULL) {
|
||||||
bool forceit = false;
|
bool forceit = false;
|
||||||
|
|
||||||
// Check if we do profiling for this script.
|
// Check if we do profiling for this script.
|
||||||
@@ -2262,7 +2260,12 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
|
|
||||||
cookie.conv.vc_type = CONV_NONE; // no conversion
|
cookie.conv.vc_type = CONV_NONE; // no conversion
|
||||||
|
|
||||||
if (si->sn_lua) {
|
if (fname == NULL
|
||||||
|
&& (ex_lua || strequal(curbuf->b_p_ft, "lua")
|
||||||
|
|| (curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua")))) {
|
||||||
|
// Source lines from the current buffer as lua
|
||||||
|
nlua_exec_ga(&cookie.buflines, fname_exp);
|
||||||
|
} else if (si != NULL && si->sn_lua) {
|
||||||
// Source the file as lua
|
// Source the file as lua
|
||||||
nlua_exec_file(fname_exp);
|
nlua_exec_file(fname_exp);
|
||||||
} else {
|
} else {
|
||||||
@@ -2272,7 +2275,7 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
&& firstline[1] == 0xbb && firstline[2] == 0xbf) {
|
&& firstline[1] == 0xbb && firstline[2] == 0xbf) {
|
||||||
// Found BOM; setup conversion, skip over BOM and recode the line.
|
// Found BOM; setup conversion, skip over BOM and recode the line.
|
||||||
convert_setup(&cookie.conv, "utf-8", p_enc);
|
convert_setup(&cookie.conv, "utf-8", p_enc);
|
||||||
p = string_convert(&cookie.conv, (char *)firstline + 3, NULL);
|
char *p = string_convert(&cookie.conv, (char *)firstline + 3, NULL);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
p = xstrdup((char *)firstline + 3);
|
p = xstrdup((char *)firstline + 3);
|
||||||
}
|
}
|
||||||
@@ -2285,7 +2288,7 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
}
|
}
|
||||||
retval = OK;
|
retval = OK;
|
||||||
|
|
||||||
if (l_do_profiling == PROF_YES) {
|
if (l_do_profiling == PROF_YES && si != NULL) {
|
||||||
// Get "si" again, "script_items" may have been reallocated.
|
// Get "si" again, "script_items" may have been reallocated.
|
||||||
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
if (si->sn_prof_on) {
|
if (si->sn_prof_on) {
|
||||||
@@ -2332,12 +2335,17 @@ int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid)
|
|||||||
if (l_do_profiling == PROF_YES) {
|
if (l_do_profiling == PROF_YES) {
|
||||||
prof_child_exit(&wait_start); // leaving a child now
|
prof_child_exit(&wait_start); // leaving a child now
|
||||||
}
|
}
|
||||||
fclose(cookie.fp);
|
if (cookie.fp != NULL) {
|
||||||
|
fclose(cookie.fp);
|
||||||
|
}
|
||||||
|
if (cookie.source_from_buf_or_str) {
|
||||||
|
ga_clear_strings(&cookie.buflines);
|
||||||
|
}
|
||||||
xfree(cookie.nextline);
|
xfree(cookie.nextline);
|
||||||
xfree(firstline);
|
xfree(firstline);
|
||||||
convert_setup(&cookie.conv, NULL, NULL);
|
convert_setup(&cookie.conv, NULL, NULL);
|
||||||
|
|
||||||
if (trigger_source_post) {
|
if (str == NULL && trigger_source_post) {
|
||||||
apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
|
apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2346,6 +2354,13 @@ theend:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @param check_other check for .vimrc and _vimrc
|
||||||
|
/// @param is_vimrc DOSO_ value
|
||||||
|
int do_source(char *fname, bool check_other, int is_vimrc, int *ret_sid)
|
||||||
|
{
|
||||||
|
return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if the script with the given script ID is a Lua script.
|
/// Checks if the script with the given script ID is a Lua script.
|
||||||
bool script_is_lua(scid_T sid)
|
bool script_is_lua(scid_T sid)
|
||||||
{
|
{
|
||||||
@@ -2608,7 +2623,7 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat)
|
|||||||
char *line;
|
char *line;
|
||||||
|
|
||||||
// If breakpoints have been added/deleted need to check for it.
|
// If breakpoints have been added/deleted need to check for it.
|
||||||
if (sp->dbg_tick < debug_tick) {
|
if ((sp->dbg_tick < debug_tick) && !sp->source_from_buf_or_str) {
|
||||||
sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM);
|
sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM);
|
||||||
sp->dbg_tick = debug_tick;
|
sp->dbg_tick = debug_tick;
|
||||||
}
|
}
|
||||||
@@ -2619,7 +2634,7 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat)
|
|||||||
SOURCING_LNUM = sp->sourcing_lnum + 1;
|
SOURCING_LNUM = sp->sourcing_lnum + 1;
|
||||||
// Get current line. If there is a read-ahead line, use it, otherwise get
|
// Get current line. If there is a read-ahead line, use it, otherwise get
|
||||||
// one now. "fp" is NULL if actually using a string.
|
// one now. "fp" is NULL if actually using a string.
|
||||||
if (sp->finished || sp->fp == NULL) {
|
if (sp->finished || (!sp->source_from_buf_or_str && sp->fp == NULL)) {
|
||||||
line = NULL;
|
line = NULL;
|
||||||
} else if (sp->nextline == NULL) {
|
} else if (sp->nextline == NULL) {
|
||||||
line = get_one_sourceline(sp);
|
line = get_one_sourceline(sp);
|
||||||
@@ -2672,7 +2687,8 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Did we encounter a breakpoint?
|
// Did we encounter a breakpoint?
|
||||||
if (sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM) {
|
if (!sp->source_from_buf_or_str
|
||||||
|
&& sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM) {
|
||||||
dbg_breakpoint(sp->fname, SOURCING_LNUM);
|
dbg_breakpoint(sp->fname, SOURCING_LNUM);
|
||||||
// Find next breakpoint.
|
// Find next breakpoint.
|
||||||
sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM);
|
sp->breakpoint = dbg_find_breakpoint(true, sp->fname, SOURCING_LNUM);
|
||||||
@@ -2701,19 +2717,28 @@ static char *get_one_sourceline(source_cookie_T *sp)
|
|||||||
while (true) {
|
while (true) {
|
||||||
// make room to read at least 120 (more) characters
|
// make room to read at least 120 (more) characters
|
||||||
ga_grow(&ga, 120);
|
ga_grow(&ga, 120);
|
||||||
buf = ga.ga_data;
|
if (sp->source_from_buf_or_str) {
|
||||||
|
if (sp->buf_lnum >= sp->buflines.ga_len) {
|
||||||
retry:
|
break; // all the lines are processed
|
||||||
errno = 0;
|
|
||||||
if (fgets(buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
|
|
||||||
sp->fp) == NULL) {
|
|
||||||
if (errno == EINTR) {
|
|
||||||
goto retry;
|
|
||||||
}
|
}
|
||||||
|
ga_concat(&ga, ((char **)sp->buflines.ga_data)[sp->buf_lnum]);
|
||||||
break;
|
sp->buf_lnum++;
|
||||||
|
ga_grow(&ga, 1);
|
||||||
|
buf = (char *)ga.ga_data;
|
||||||
|
buf[ga.ga_len++] = NUL;
|
||||||
|
len = ga.ga_len;
|
||||||
|
} else {
|
||||||
|
buf = ga.ga_data;
|
||||||
|
retry:
|
||||||
|
errno = 0;
|
||||||
|
if (fgets(buf + ga.ga_len, ga.ga_maxlen - ga.ga_len, sp->fp) == NULL) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = ga.ga_len + (int)strlen(buf + ga.ga_len);
|
||||||
}
|
}
|
||||||
len = ga.ga_len + (int)strlen(buf + ga.ga_len);
|
|
||||||
#ifdef USE_CRNL
|
#ifdef USE_CRNL
|
||||||
// Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
|
// Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
|
||||||
// CTRL-Z by its own, or after a NL.
|
// CTRL-Z by its own, or after a NL.
|
||||||
@@ -2784,11 +2809,18 @@ retry:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if sourcing a script either from a file or a buffer or a string.
|
||||||
|
/// Otherwise returns false.
|
||||||
|
int sourcing_a_script(exarg_T *eap)
|
||||||
|
{
|
||||||
|
return getline_equal(eap->ea_getline, eap->cookie, getsourceline);
|
||||||
|
}
|
||||||
|
|
||||||
/// ":scriptencoding": Set encoding conversion for a sourced script.
|
/// ":scriptencoding": Set encoding conversion for a sourced script.
|
||||||
/// Without the multi-byte feature it's simply ignored.
|
/// Without the multi-byte feature it's simply ignored.
|
||||||
void ex_scriptencoding(exarg_T *eap)
|
void ex_scriptencoding(exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (!getline_equal(eap->ea_getline, eap->cookie, getsourceline)) {
|
if (!sourcing_a_script(eap)) {
|
||||||
emsg(_("E167: :scriptencoding used outside of a sourced file"));
|
emsg(_("E167: :scriptencoding used outside of a sourced file"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2807,7 +2839,7 @@ void ex_scriptencoding(exarg_T *eap)
|
|||||||
/// ":finish": Mark a sourced file as finished.
|
/// ":finish": Mark a sourced file as finished.
|
||||||
void ex_finish(exarg_T *eap)
|
void ex_finish(exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (getline_equal(eap->ea_getline, eap->cookie, getsourceline)) {
|
if (sourcing_a_script(eap)) {
|
||||||
do_finish(eap, false);
|
do_finish(eap, false);
|
||||||
} else {
|
} else {
|
||||||
emsg(_("E168: :finish used outside of a sourced file"));
|
emsg(_("E168: :finish used outside of a sourced file"));
|
||||||
|
@@ -140,7 +140,7 @@ describe('API', function()
|
|||||||
it(':verbose set {option}?', function()
|
it(':verbose set {option}?', function()
|
||||||
api.nvim_exec2('set nowrap', { output = false })
|
api.nvim_exec2('set nowrap', { output = false })
|
||||||
eq(
|
eq(
|
||||||
{ output = 'nowrap\n\tLast set from anonymous :source' },
|
{ output = 'nowrap\n\tLast set from anonymous :source line 1' },
|
||||||
api.nvim_exec2('verbose set wrap?', { output = true })
|
api.nvim_exec2('verbose set wrap?', { output = true })
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ describe('API', function()
|
|||||||
{ output = false }
|
{ output = false }
|
||||||
)
|
)
|
||||||
eq(
|
eq(
|
||||||
{ output = 'nowrap\n\tLast set from anonymous :source (script id 1)' },
|
{ output = 'nowrap\n\tLast set from anonymous :source (script id 1) line 2' },
|
||||||
api.nvim_exec2('verbose set wrap?', { output = true })
|
api.nvim_exec2('verbose set wrap?', { output = true })
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
@@ -296,16 +296,21 @@ describe('API', function()
|
|||||||
eq('ñxx', api.nvim_get_current_line())
|
eq('ñxx', api.nvim_get_current_line())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('can use :finish', function()
|
||||||
|
api.nvim_exec2('let g:var = 123\nfinish\nlet g:var = 456', {})
|
||||||
|
eq(123, api.nvim_get_var('var'))
|
||||||
|
end)
|
||||||
|
|
||||||
it('execution error', function()
|
it('execution error', function()
|
||||||
eq(
|
eq(
|
||||||
'nvim_exec2(): Vim:E492: Not an editor command: bogus_command',
|
'nvim_exec2(), line 1: Vim:E492: Not an editor command: bogus_command',
|
||||||
pcall_err(request, 'nvim_exec2', 'bogus_command', {})
|
pcall_err(request, 'nvim_exec2', 'bogus_command', {})
|
||||||
)
|
)
|
||||||
eq('', api.nvim_eval('v:errmsg')) -- v:errmsg was not updated.
|
eq('', api.nvim_eval('v:errmsg')) -- v:errmsg was not updated.
|
||||||
eq('', eval('v:exception'))
|
eq('', eval('v:exception'))
|
||||||
|
|
||||||
eq(
|
eq(
|
||||||
'nvim_exec2(): Vim(buffer):E86: Buffer 23487 does not exist',
|
'nvim_exec2(), line 1: Vim(buffer):E86: Buffer 23487 does not exist',
|
||||||
pcall_err(request, 'nvim_exec2', 'buffer 23487', {})
|
pcall_err(request, 'nvim_exec2', 'buffer 23487', {})
|
||||||
)
|
)
|
||||||
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
|
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
|
||||||
@@ -338,17 +343,28 @@ describe('API', function()
|
|||||||
write_file(sourcing_fname, 'call nvim_exec2("source ' .. fname .. '", {"output": v:false})\n')
|
write_file(sourcing_fname, 'call nvim_exec2("source ' .. fname .. '", {"output": v:false})\n')
|
||||||
api.nvim_exec2('set verbose=2', { output = false })
|
api.nvim_exec2('set verbose=2', { output = false })
|
||||||
local traceback_output = dedent([[
|
local traceback_output = dedent([[
|
||||||
line 0: sourcing "%s"
|
sourcing "nvim_exec2()"
|
||||||
line 0: sourcing "%s"
|
line 1: sourcing "nvim_exec2() called at nvim_exec2():1"
|
||||||
|
line 1: sourcing "%s"
|
||||||
|
line 1: sourcing "nvim_exec2() called at %s:1"
|
||||||
|
line 1: sourcing "%s"
|
||||||
hello
|
hello
|
||||||
finished sourcing %s
|
finished sourcing %s
|
||||||
continuing in nvim_exec2() called at %s:1
|
continuing in nvim_exec2() called at %s:1
|
||||||
|
finished sourcing nvim_exec2() called at %s:1
|
||||||
|
continuing in %s
|
||||||
finished sourcing %s
|
finished sourcing %s
|
||||||
continuing in nvim_exec2() called at nvim_exec2():0]]):format(
|
continuing in nvim_exec2() called at nvim_exec2():1
|
||||||
|
finished sourcing nvim_exec2() called at nvim_exec2():1
|
||||||
|
continuing in nvim_exec2()
|
||||||
|
finished sourcing nvim_exec2()]]):format(
|
||||||
|
sourcing_fname,
|
||||||
sourcing_fname,
|
sourcing_fname,
|
||||||
fname,
|
fname,
|
||||||
fname,
|
fname,
|
||||||
sourcing_fname,
|
sourcing_fname,
|
||||||
|
sourcing_fname,
|
||||||
|
sourcing_fname,
|
||||||
sourcing_fname
|
sourcing_fname
|
||||||
)
|
)
|
||||||
eq(
|
eq(
|
||||||
|
@@ -97,14 +97,26 @@ describe(':cquit', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('exits with redir msg for multiple exit codes after :cquit 1 2', function()
|
it('exits with redir msg for multiple exit codes after :cquit 1 2', function()
|
||||||
test_cq('cquit 1 2', nil, 'nvim_exec2(): Vim(cquit):E488: Trailing characters: 2: cquit 1 2')
|
test_cq(
|
||||||
|
'cquit 1 2',
|
||||||
|
nil,
|
||||||
|
'nvim_exec2(), line 1: Vim(cquit):E488: Trailing characters: 2: cquit 1 2'
|
||||||
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('exits with redir msg for non-number exit code after :cquit X', function()
|
it('exits with redir msg for non-number exit code after :cquit X', function()
|
||||||
test_cq('cquit X', nil, 'nvim_exec2(): Vim(cquit):E488: Trailing characters: X: cquit X')
|
test_cq(
|
||||||
|
'cquit X',
|
||||||
|
nil,
|
||||||
|
'nvim_exec2(), line 1: Vim(cquit):E488: Trailing characters: X: cquit X'
|
||||||
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('exits with redir msg for negative exit code after :cquit -1', function()
|
it('exits with redir msg for negative exit code after :cquit -1', function()
|
||||||
test_cq('cquit -1', nil, 'nvim_exec2(): Vim(cquit):E488: Trailing characters: -1: cquit -1')
|
test_cq(
|
||||||
|
'cquit -1',
|
||||||
|
nil,
|
||||||
|
'nvim_exec2(), line 1: Vim(cquit):E488: Trailing characters: -1: cquit -1'
|
||||||
|
)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@@ -42,59 +42,62 @@ describe('named marks', function()
|
|||||||
it('errors when set out of range with :mark', function()
|
it('errors when set out of range with :mark', function()
|
||||||
command('edit ' .. file1)
|
command('edit ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, '1000mark x')
|
local err = pcall_err(n.exec_capture, '1000mark x')
|
||||||
eq('nvim_exec2(): Vim(mark):E16: Invalid range: 1000mark x', err)
|
eq('nvim_exec2(), line 1: Vim(mark):E16: Invalid range: 1000mark x', err)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('errors when set out of range with :k', function()
|
it('errors when set out of range with :k', function()
|
||||||
command('edit ' .. file1)
|
command('edit ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, '1000kx')
|
local err = pcall_err(n.exec_capture, '1000kx')
|
||||||
eq('nvim_exec2(): Vim(k):E16: Invalid range: 1000kx', err)
|
eq('nvim_exec2(), line 1: Vim(k):E16: Invalid range: 1000kx', err)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('errors on unknown mark name with :mark', function()
|
it('errors on unknown mark name with :mark', function()
|
||||||
command('edit ' .. file1)
|
command('edit ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, 'mark #')
|
local err = pcall_err(n.exec_capture, 'mark #')
|
||||||
eq('nvim_exec2(): Vim(mark):E191: Argument must be a letter or forward/backward quote', err)
|
eq(
|
||||||
|
'nvim_exec2(), line 1: Vim(mark):E191: Argument must be a letter or forward/backward quote',
|
||||||
|
err
|
||||||
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("errors on unknown mark name with '", function()
|
it("errors on unknown mark name with '", function()
|
||||||
command('edit ' .. file1)
|
command('edit ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, "normal! '#")
|
local err = pcall_err(n.exec_capture, "normal! '#")
|
||||||
eq('nvim_exec2(): Vim(normal):E78: Unknown mark', err)
|
eq('nvim_exec2(), line 1: Vim(normal):E78: Unknown mark', err)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('errors on unknown mark name with `', function()
|
it('errors on unknown mark name with `', function()
|
||||||
command('edit ' .. file1)
|
command('edit ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, 'normal! `#')
|
local err = pcall_err(n.exec_capture, 'normal! `#')
|
||||||
eq('nvim_exec2(): Vim(normal):E78: Unknown mark', err)
|
eq('nvim_exec2(), line 1: Vim(normal):E78: Unknown mark', err)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("errors when moving to a mark that is not set with '", function()
|
it("errors when moving to a mark that is not set with '", function()
|
||||||
command('edit ' .. file1)
|
command('edit ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, "normal! 'z")
|
local err = pcall_err(n.exec_capture, "normal! 'z")
|
||||||
eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
|
eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
|
||||||
err = pcall_err(n.exec_capture, "normal! '.")
|
err = pcall_err(n.exec_capture, "normal! '.")
|
||||||
eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
|
eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('errors when moving to a mark that is not set with `', function()
|
it('errors when moving to a mark that is not set with `', function()
|
||||||
command('edit ' .. file1)
|
command('edit ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, 'normal! `z')
|
local err = pcall_err(n.exec_capture, 'normal! `z')
|
||||||
eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
|
eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
|
||||||
err = pcall_err(n.exec_capture, 'normal! `>')
|
err = pcall_err(n.exec_capture, 'normal! `>')
|
||||||
eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
|
eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("errors when moving to a global mark that is not set with '", function()
|
it("errors when moving to a global mark that is not set with '", function()
|
||||||
command('edit ' .. file1)
|
command('edit ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, "normal! 'Z")
|
local err = pcall_err(n.exec_capture, "normal! 'Z")
|
||||||
eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
|
eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('errors when moving to a global mark that is not set with `', function()
|
it('errors when moving to a global mark that is not set with `', function()
|
||||||
command('edit ' .. file1)
|
command('edit ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, 'normal! `Z')
|
local err = pcall_err(n.exec_capture, 'normal! `Z')
|
||||||
eq('nvim_exec2(): Vim(normal):E20: Mark not set', err)
|
eq('nvim_exec2(), line 1: Vim(normal):E20: Mark not set', err)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("can move to them using '", function()
|
it("can move to them using '", function()
|
||||||
@@ -169,7 +172,7 @@ describe('named marks', function()
|
|||||||
command('next')
|
command('next')
|
||||||
command('bw! ' .. file1)
|
command('bw! ' .. file1)
|
||||||
local err = pcall_err(n.exec_capture, "normal! 'A")
|
local err = pcall_err(n.exec_capture, "normal! 'A")
|
||||||
eq('nvim_exec2(): Vim(normal):E92: Buffer 1 not found', err)
|
eq('nvim_exec2(), line 1: Vim(normal):E92: Buffer 1 not found', err)
|
||||||
os.remove(file1)
|
os.remove(file1)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@@ -101,16 +101,14 @@ describe(':source', function()
|
|||||||
\ k: "v"
|
\ k: "v"
|
||||||
"\ (o_o)
|
"\ (o_o)
|
||||||
\ }
|
\ }
|
||||||
let c = expand("<SID>")->empty()
|
let c = expand("<SID>")
|
||||||
let s:s = 0zbeef.cafe
|
let s:s = 0zbeef.cafe
|
||||||
let d = s:s]])
|
let d = s:s]])
|
||||||
|
|
||||||
command('source')
|
command('source')
|
||||||
eq('2', exec_capture('echo a'))
|
eq('2', exec_capture('echo a'))
|
||||||
eq("{'k': 'v'}", exec_capture('echo b'))
|
eq("{'k': 'v'}", exec_capture('echo b'))
|
||||||
|
eq('<SNR>1_', exec_capture('echo c'))
|
||||||
-- Script items are created only on script var access
|
|
||||||
eq('1', exec_capture('echo c'))
|
|
||||||
eq('0zBEEFCAFE', exec_capture('echo d'))
|
eq('0zBEEFCAFE', exec_capture('echo d'))
|
||||||
|
|
||||||
exec('set cpoptions+=C')
|
exec('set cpoptions+=C')
|
||||||
@@ -136,6 +134,10 @@ describe(':source', function()
|
|||||||
feed_command(':source')
|
feed_command(':source')
|
||||||
eq('3', exec_capture('echo a'))
|
eq('3', exec_capture('echo a'))
|
||||||
|
|
||||||
|
-- Source last line only
|
||||||
|
feed_command(':$source')
|
||||||
|
eq('Vim(echo):E117: Unknown function: s:C', exc_exec('echo D()'))
|
||||||
|
|
||||||
-- Source from 2nd line to end of file
|
-- Source from 2nd line to end of file
|
||||||
feed('ggjVG')
|
feed('ggjVG')
|
||||||
feed_command(':source')
|
feed_command(':source')
|
||||||
@@ -143,9 +145,9 @@ describe(':source', function()
|
|||||||
eq("{'K': 'V'}", exec_capture('echo b'))
|
eq("{'K': 'V'}", exec_capture('echo b'))
|
||||||
eq('<SNR>1_C()', exec_capture('echo D()'))
|
eq('<SNR>1_C()', exec_capture('echo D()'))
|
||||||
|
|
||||||
-- Source last line only
|
-- Source last line after the lines that define s:C() have been sourced
|
||||||
feed_command(':$source')
|
feed_command(':$source')
|
||||||
eq('Vim(echo):E117: Unknown function: s:C', exc_exec('echo D()'))
|
eq('<SNR>1_C()', exec_capture('echo D()'))
|
||||||
|
|
||||||
exec('set cpoptions+=C')
|
exec('set cpoptions+=C')
|
||||||
eq("Vim(let):E723: Missing end of Dictionary '}': ", exc_exec("'<,'>source"))
|
eq("Vim(let):E723: Missing end of Dictionary '}': ", exc_exec("'<,'>source"))
|
||||||
@@ -248,9 +250,9 @@ describe(':source', function()
|
|||||||
|
|
||||||
eq(12, eval('g:c'))
|
eq(12, eval('g:c'))
|
||||||
eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
|
eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
|
||||||
eq(':source (no file)', api.nvim_get_var('sfile_value'))
|
eq(':source buffer=1', api.nvim_get_var('sfile_value'))
|
||||||
eq(':source (no file)', api.nvim_get_var('stack_value'))
|
eq(':source buffer=1', api.nvim_get_var('stack_value'))
|
||||||
eq(':source (no file)', api.nvim_get_var('script_value'))
|
eq(':source buffer=1', api.nvim_get_var('script_value'))
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -256,7 +256,7 @@ TestHL2 xxx guibg=Green
|
|||||||
local result = exec_capture(':verbose set tw?')
|
local result = exec_capture(':verbose set tw?')
|
||||||
local loc = get_last_set_location(40)
|
local loc = get_last_set_location(40)
|
||||||
if loc == 'Lua (run Nvim with -V1 for more details)' then
|
if loc == 'Lua (run Nvim with -V1 for more details)' then
|
||||||
loc = 'anonymous :source (script id 1)'
|
loc = 'anonymous :source (script id 1) line 5'
|
||||||
end
|
end
|
||||||
eq(
|
eq(
|
||||||
string.format(
|
string.format(
|
||||||
|
@@ -148,10 +148,10 @@ describe('assert function:', function()
|
|||||||
call assert_true('', 'file two')
|
call assert_true('', 'file two')
|
||||||
]])
|
]])
|
||||||
expected_errors({
|
expected_errors({
|
||||||
'nvim_exec2(): equal assertion failed: Expected 1 but got 100',
|
'nvim_exec2() line 1: equal assertion failed: Expected 1 but got 100',
|
||||||
"nvim_exec2(): true assertion failed: Expected False but got 'true'",
|
"nvim_exec2() line 2: true assertion failed: Expected False but got 'true'",
|
||||||
"nvim_exec2(): false assertion failed: Expected True but got 'false'",
|
"nvim_exec2() line 3: false assertion failed: Expected True but got 'false'",
|
||||||
"nvim_exec2(): file two: Expected True but got ''",
|
"nvim_exec2() line 1: file two: Expected True but got ''",
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@@ -207,7 +207,8 @@ describe(':lua', function()
|
|||||||
|
|
||||||
-- ":{range}lua" fails on invalid Lua code.
|
-- ":{range}lua" fails on invalid Lua code.
|
||||||
eq(
|
eq(
|
||||||
[[:{range}lua: Vim(lua):E5107: Error loading lua [string ":{range}lua"]:0: '=' expected near '<eof>']],
|
[[:{range}lua buffer=1: Vim(lua):E5107: Error loading lua ]]
|
||||||
|
.. [[[string ":{range}lua buffer=1"]:0: '=' expected near '<eof>']],
|
||||||
pcall_err(command, '1lua')
|
pcall_err(command, '1lua')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -3956,7 +3956,7 @@ stack traceback:
|
|||||||
|
|
||||||
it('failure modes', function()
|
it('failure modes', function()
|
||||||
matches(
|
matches(
|
||||||
'nvim_exec2%(%): Vim:E492: Not an editor command: fooooo',
|
'nvim_exec2%(%), line 1: Vim:E492: Not an editor command: fooooo',
|
||||||
pcall_err(exec_lua, [[vim.api.nvim_win_call(0, function() vim.cmd 'fooooo' end)]])
|
pcall_err(exec_lua, [[vim.api.nvim_win_call(0, function() vim.cmd 'fooooo' end)]])
|
||||||
)
|
)
|
||||||
eq(
|
eq(
|
||||||
|
@@ -92,6 +92,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
|
||||||
@@ -108,4 +114,548 @@ 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)
|
||||||
|
|
||||||
|
" Make sure the script line number is correct when sourcing a range of
|
||||||
|
" lines.
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
Line 1
|
||||||
|
Line 2
|
||||||
|
func Xtestfunc()
|
||||||
|
return expand("<sflnum>")
|
||||||
|
endfunc
|
||||||
|
Line 3
|
||||||
|
Line 4
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
3,5source
|
||||||
|
call assert_equal('4', Xtestfunc())
|
||||||
|
delfunc Xtestfunc
|
||||||
|
|
||||||
|
" 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 using try/catch
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let Trace = '1'
|
||||||
|
try
|
||||||
|
let a1 = b1
|
||||||
|
catch
|
||||||
|
let Trace ..= '2'
|
||||||
|
finally
|
||||||
|
let Trace ..= '3'
|
||||||
|
endtry
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal("123", g:Trace)
|
||||||
|
|
||||||
|
" test with the finish command
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let g:Color = 'blue'
|
||||||
|
finish
|
||||||
|
let g:Color = 'green'
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal('blue', g:Color)
|
||||||
|
|
||||||
|
" Test for the SourcePre and SourcePost autocmds
|
||||||
|
augroup Xtest
|
||||||
|
au!
|
||||||
|
au SourcePre * let g:XsourcePre=4
|
||||||
|
\ | let g:XsourcePreFile = expand("<afile>")
|
||||||
|
au SourcePost * let g:XsourcePost=6
|
||||||
|
\ | let g:XsourcePostFile = expand("<afile>")
|
||||||
|
augroup END
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
let a = 1
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal(4, g:XsourcePre)
|
||||||
|
call assert_equal(6, g:XsourcePost)
|
||||||
|
call assert_equal(':source buffer=' .. bufnr(), g:XsourcePreFile)
|
||||||
|
call assert_equal(':source buffer=' .. bufnr(), g:XsourcePostFile)
|
||||||
|
augroup Xtest
|
||||||
|
au!
|
||||||
|
augroup END
|
||||||
|
augroup! Xtest
|
||||||
|
|
||||||
|
%bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
" Test for sourcing a Vim9 script from the current buffer
|
||||||
|
func Test_source_buffer_vim9()
|
||||||
|
throw 'Skipped: Vim9 script is N/A'
|
||||||
|
new
|
||||||
|
|
||||||
|
" 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())
|
||||||
|
|
||||||
|
" test for sourcing a vim9 script with line continuation
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
|
||||||
|
g:Str1 = "hello "
|
||||||
|
.. "world"
|
||||||
|
.. ", how are you?"
|
||||||
|
g:Colors = [
|
||||||
|
'red',
|
||||||
|
# comment
|
||||||
|
'blue'
|
||||||
|
]
|
||||||
|
g:Dict = {
|
||||||
|
a: 22,
|
||||||
|
# comment
|
||||||
|
b: 33
|
||||||
|
}
|
||||||
|
|
||||||
|
# calling a function with line continuation
|
||||||
|
def Sum(...values: list<number>): number
|
||||||
|
var sum: number = 0
|
||||||
|
for v in values
|
||||||
|
sum += v
|
||||||
|
endfor
|
||||||
|
return sum
|
||||||
|
enddef
|
||||||
|
g:Total1 = Sum(10,
|
||||||
|
20,
|
||||||
|
30)
|
||||||
|
|
||||||
|
var i: number = 0
|
||||||
|
while i < 10
|
||||||
|
# while loop
|
||||||
|
i +=
|
||||||
|
1
|
||||||
|
endwhile
|
||||||
|
g:Count1 = i
|
||||||
|
|
||||||
|
# for loop
|
||||||
|
g:Count2 = 0
|
||||||
|
for j in range(10, 20)
|
||||||
|
g:Count2 +=
|
||||||
|
i
|
||||||
|
endfor
|
||||||
|
|
||||||
|
g:Total2 = 10 +
|
||||||
|
20 -
|
||||||
|
5
|
||||||
|
|
||||||
|
g:Result1 = g:Total2 > 1
|
||||||
|
? 'red'
|
||||||
|
: 'blue'
|
||||||
|
|
||||||
|
g:Str2 = 'x'
|
||||||
|
->repeat(10)
|
||||||
|
->trim()
|
||||||
|
->strpart(4)
|
||||||
|
|
||||||
|
g:Result2 = g:Dict
|
||||||
|
.a
|
||||||
|
|
||||||
|
augroup Test
|
||||||
|
au!
|
||||||
|
au BufNewFile Xfile g:readFile = 1
|
||||||
|
| g:readExtra = 2
|
||||||
|
augroup END
|
||||||
|
g:readFile = 0
|
||||||
|
g:readExtra = 0
|
||||||
|
new Xfile
|
||||||
|
bwipe!
|
||||||
|
augroup Test
|
||||||
|
au!
|
||||||
|
augroup END
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal("hello world, how are you?", g:Str1)
|
||||||
|
call assert_equal(['red', 'blue'], g:Colors)
|
||||||
|
call assert_equal(#{a: 22, b: 33}, g:Dict)
|
||||||
|
call assert_equal(60, g:Total1)
|
||||||
|
call assert_equal(10, g:Count1)
|
||||||
|
call assert_equal(110, g:Count2)
|
||||||
|
call assert_equal(25, g:Total2)
|
||||||
|
call assert_equal('red', g:Result1)
|
||||||
|
call assert_equal('xxxxxx', g:Str2)
|
||||||
|
call assert_equal(22, g:Result2)
|
||||||
|
call assert_equal(1, g:readFile)
|
||||||
|
call assert_equal(2, g:readExtra)
|
||||||
|
|
||||||
|
" test for sourcing the same buffer multiple times after changing a function
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
def g:Xtestfunc(): string
|
||||||
|
return "one"
|
||||||
|
enddef
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal("one", Xtestfunc())
|
||||||
|
call setline(3, ' return "two"')
|
||||||
|
source
|
||||||
|
call assert_equal("two", Xtestfunc())
|
||||||
|
call setline(3, ' return "three"')
|
||||||
|
source
|
||||||
|
call assert_equal("three", Xtestfunc())
|
||||||
|
delfunc Xtestfunc
|
||||||
|
|
||||||
|
" Test for sourcing a range of lines. Make sure the script line number is
|
||||||
|
" correct.
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
Line 1
|
||||||
|
Line 2
|
||||||
|
vim9script
|
||||||
|
def g:Xtestfunc(): string
|
||||||
|
return expand("<sflnum>")
|
||||||
|
enddef
|
||||||
|
Line 3
|
||||||
|
Line 4
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
3,6source
|
||||||
|
call assert_equal('5', Xtestfunc())
|
||||||
|
delfunc Xtestfunc
|
||||||
|
|
||||||
|
" test for sourcing a heredoc
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
var a = 1
|
||||||
|
g:heredoc =<< trim DATA
|
||||||
|
red
|
||||||
|
green
|
||||||
|
blue
|
||||||
|
DATA
|
||||||
|
var b = 2
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal(['red', ' green', 'blue'], g:heredoc)
|
||||||
|
|
||||||
|
" test for using the :vim9cmd modifier
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
first line
|
||||||
|
g:Math = {
|
||||||
|
pi: 3.12,
|
||||||
|
e: 2.71828
|
||||||
|
}
|
||||||
|
g:Editors = [
|
||||||
|
'vim',
|
||||||
|
# comment
|
||||||
|
'nano'
|
||||||
|
]
|
||||||
|
last line
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
vim9cmd :2,10source
|
||||||
|
call assert_equal(#{pi: 3.12, e: 2.71828}, g:Math)
|
||||||
|
call assert_equal(['vim', 'nano'], g:Editors)
|
||||||
|
|
||||||
|
" test for using try/catch
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
g:Trace = '1'
|
||||||
|
try
|
||||||
|
a1 = b1
|
||||||
|
catch
|
||||||
|
g:Trace ..= '2'
|
||||||
|
finally
|
||||||
|
g:Trace ..= '3'
|
||||||
|
endtry
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal('123', g:Trace)
|
||||||
|
|
||||||
|
" test with the finish command
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
g:Color = 'red'
|
||||||
|
finish
|
||||||
|
g:Color = 'blue'
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
source
|
||||||
|
call assert_equal('red', g:Color)
|
||||||
|
|
||||||
|
" test for ++clear argument to clear all the functions/variables
|
||||||
|
%d _
|
||||||
|
let lines =<< trim END
|
||||||
|
g:ScriptVarFound = exists("color")
|
||||||
|
g:MyFuncFound = exists('*Myfunc')
|
||||||
|
if g:MyFuncFound
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
var color = 'blue'
|
||||||
|
def Myfunc()
|
||||||
|
enddef
|
||||||
|
END
|
||||||
|
call setline(1, lines)
|
||||||
|
vim9cmd source
|
||||||
|
call assert_false(g:MyFuncFound)
|
||||||
|
call assert_false(g:ScriptVarFound)
|
||||||
|
vim9cmd source
|
||||||
|
call assert_true(g:MyFuncFound)
|
||||||
|
call assert_true(g:ScriptVarFound)
|
||||||
|
vim9cmd source ++clear
|
||||||
|
call assert_false(g:MyFuncFound)
|
||||||
|
call assert_false(g:ScriptVarFound)
|
||||||
|
vim9cmd source ++clear
|
||||||
|
call assert_false(g:MyFuncFound)
|
||||||
|
call assert_false(g:ScriptVarFound)
|
||||||
|
call assert_fails('vim9cmd source ++clearx', 'E475:')
|
||||||
|
call assert_fails('vim9cmd source ++abcde', 'E484:')
|
||||||
|
|
||||||
|
%bw!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_source_buffer_long_line()
|
||||||
|
" This was reading past the end of the line.
|
||||||
|
new
|
||||||
|
norm300gr0
|
||||||
|
so
|
||||||
|
bwipe!
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
new
|
||||||
|
norm 10a0000000000ø00000000000
|
||||||
|
norm i0000000000000000000
|
||||||
|
silent! so
|
||||||
|
END
|
||||||
|
call writefile(lines, 'Xtest.vim')
|
||||||
|
source Xtest.vim
|
||||||
|
bwipe!
|
||||||
|
call delete('Xtest.vim')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
Reference in New Issue
Block a user