Patch 8.2.4603
Problem: Sourcing buffer lines is too complicated.
Solution: Simplify the code. Make it possible to source Vim9 script lines.
(Yegappan Lakshmanan, closes #9974)
Files: runtime/doc/repeat.txt, src/ex_docmd.c, src/proto/
scriptfile.pro,
src/scriptfile.c, src/structs.h, src/testdir/test_source.vim
*** ../vim-8.2.4602/runtime/doc/repeat.txt 2022-03-19 12:56:42.525503835 +0000
--- runtime/doc/repeat.txt 2022-03-21 19:32:54.478829840 +0000
***************
*** 192,198 ****
:[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!*
:so[urce]! {file} Read Vim commands from {file}. These are commands
--- 201,213 ----
:[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. If a
! buffer is sourced more than once, then the functions
! in the buffer are redefined again.
! Sourcing a buffer with a Vim9 script more than once
! works like |vim9-reload|.
! To source a script in the Vim9 context, the |:vim9cmd|
! modifier can be used.
*:source!*
:so[urce]! {file} Read Vim commands from {file}. These are commands
***************
*** 414,423 ****
':source!' command. Useful for long command sequences. Can be combined with
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
! have to type any needed keyboard input. The ':source!' command reads from a
! script file character by character, interpreting each character as if you
! typed it.
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
--- 431,440 ----
':source!' command. Useful for long command sequences. Can be combined with
the ':map' command to put complicated commands under a function key.
! The ':source' command reads Ex commands from a file or a buffer line by line.
! You will have to type any needed keyboard input. The ':source!' command reads
! from a script file character by character, interpreting each character as if
! you typed it.
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
*** ../vim-8.2.4602/src/ex_docmd.c 2022-03-18 19:44:44.935089439 +0000
--- src/ex_docmd.c 2022-03-21 19:32:54.478829840 +0000
***************
*** 2572,2578 ****
#ifdef FEAT_EVAL
// Set flag that any command was executed, used by ex_vim9script().
// Not if this was a command that wasn't executed or :endif.
! if (getline_equal(ea.getline, ea.cookie, getsourceline)
&& current_sctx.sc_sid > 0
&& ea.cmdidx != CMD_endif
&& (cstack->cs_idx < 0
--- 2572,2578 ----
#ifdef FEAT_EVAL
// Set flag that any command was executed, used by ex_vim9script().
// Not if this was a command that wasn't executed or :endif.
! if (sourcing_a_script(&ea)
&& current_sctx.sc_sid > 0
&& ea.cmdidx != CMD_endif
&& (cstack->cs_idx < 0
*** ../vim-8.2.4602/src/proto/
scriptfile.pro 2022-03-19 12:56:42.529503830 +0000
--- src/proto/
scriptfile.pro 2022-03-21 19:32:54.478829840 +0000
***************
*** 32,37 ****
--- 32,38 ----
void free_autoload_scriptnames(void);
linenr_T get_sourced_lnum(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
char_u *getsourceline(int c, void *cookie, int indent, getline_opt_T options);
+ int sourcing_a_script(exarg_T *eap);
void ex_scriptencoding(exarg_T *eap);
void ex_scriptversion(exarg_T *eap);
void ex_finish(exarg_T *eap);
***************
*** 42,46 ****
char_u *may_prefix_autoload(char_u *name);
char_u *autoload_name(char_u *name);
int script_autoload(char_u *name, int reload);
- int sourcing_a_script(exarg_T *eap);
/* vim: set ft=c : */
--- 43,46 ----
*** ../vim-8.2.4602/src/scriptfile.c 2022-03-19 12:56:42.529503830 +0000
--- src/scriptfile.c 2022-03-21 19:42:41.068686515 +0000
***************
*** 23,28 ****
--- 23,30 ----
static int last_current_SID_seq = 0;
#endif
+ static int do_source_ext(char_u *fname, int check_other, int is_vimrc, int *ret_sid, exarg_T *eap);
+
/*
* Initialize the execution stack.
*/
***************
*** 1079,1329 ****
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
cmd_source(char_u *fname, exarg_T *eap)
{
--- 1081,1086 ----
***************
*** 1341,1347 ****
emsg(_(e_argument_required));
else
// source ex commands from the current buffer
! cmd_source_buffer(eap);
}
else if (eap != NULL && eap->forceit)
// ":source!": read Normal mode commands
--- 1098,1104 ----
emsg(_(e_argument_required));
else
// source ex commands from the current buffer
! do_source_ext(NULL, FALSE, FALSE, NULL, eap);
}
else if (eap != NULL && eap->forceit)
// ":source!": read Normal mode commands
***************
*** 1480,1500 ****
#endif
/*
! * do_source: Read the file "fname" and execute its lines as EX commands.
* When "ret_sid" is not NULL and we loaded the script before, don't load it
* again.
*
* This function may be called recursively!
*
* 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.
*/
! int
! do_source(
char_u *fname,
int check_other, // check for .vimrc and _vimrc
int is_vimrc, // DOSO_ value
! int *ret_sid UNUSED)
{
source_cookie_T cookie;
char_u *p;
--- 1237,1309 ----
#endif
/*
! * 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_u *
! do_source_buffer_init(source_cookie_T *sp, exarg_T *eap)
! {
! linenr_T curr_lnum;
! char_u *line = NULL;
! char_u *fname;
!
! CLEAR_FIELD(*sp);
!
! if (curbuf == NULL)
! return NULL;
!
! // Use ":source buffer=<num>" as the script name
! vim_snprintf((char *)IObuff, IOSIZE, ":source buffer=%d", curbuf->b_fnum);
! fname = vim_strsave(IObuff);
! if (fname == NULL)
! return NULL;
!
! ga_init2(&sp->buflines, 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(&sp->buflines, line) == FAIL)
! goto errret;
! line = NULL;
! }
! sp->buf_lnum = 0;
! sp->source_from_buf = TRUE;
!
! return fname;
!
! errret:
! vim_free(fname);
! vim_free(line);
! ga_clear_strings(&sp->buflines);
! return NULL;
! }
!
! /*
! * Read the file "fname" and execute its lines as EX commands.
* When "ret_sid" is not NULL and we loaded the script before, don't load it
* again.
*
+ * The 'eap' argument is used when sourcing lines from a buffer instead of a
+ * file.
+ *
* This function may be called recursively!
*
* 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.
*/
! static int
! do_source_ext(
char_u *fname,
int check_other, // check for .vimrc and _vimrc
int is_vimrc, // DOSO_ value
! int *ret_sid UNUSED,
! exarg_T *eap)
{
source_cookie_T cookie;
char_u *p;
***************
*** 1520,1536 ****
int trigger_source_post = FALSE;
ESTACK_CHECK_DECLARATION
! p = expand_env_save(fname);
! if (p == NULL)
! return retval;
! fname_exp = fix_fname(p);
! vim_free(p);
! if (fname_exp == NULL)
! return retval;
! if (mch_isdir(fname_exp))
{
! smsg(_("Cannot source a directory: \"%s\""), fname);
! goto theend;
}
#ifdef FEAT_EVAL
estack_compiling = FALSE;
--- 1329,1356 ----
int trigger_source_post = FALSE;
ESTACK_CHECK_DECLARATION
! CLEAR_FIELD(cookie);
! if (fname == NULL)
{
! // sourcing lines from a buffer
! fname_exp = do_source_buffer_init(&cookie, eap);
! if (fname_exp == NULL)
! return FAIL;
! }
! else
! {
! p = expand_env_save(fname);
! if (p == NULL)
! return retval;
! fname_exp = fix_fname(p);
! vim_free(p);
! if (fname_exp == NULL)
! return retval;
! if (mch_isdir(fname_exp))
! {
! smsg(_("Cannot source a directory: \"%s\""), fname);
! goto theend;
! }
}
#ifdef FEAT_EVAL
estack_compiling = FALSE;
***************
*** 1567,1577 ****
// Apply SourcePre autocommands, they may get the file.
apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
#ifdef USE_FOPEN_NOINH
! cookie.fp = fopen_noinh_readbin((char *)fname_exp);
#else
! cookie.fp = mch_fopen((char *)fname_exp, READBIN);
#endif
if (cookie.fp == NULL && check_other)
{
// Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
--- 1387,1400 ----
// Apply SourcePre autocommands, they may get the file.
apply_autocmds(EVENT_SOURCEPRE, fname_exp, fname_exp, FALSE, curbuf);
+ if (!cookie.source_from_buf)
+ {
#ifdef USE_FOPEN_NOINH
! cookie.fp = fopen_noinh_readbin((char *)fname_exp);
#else
! cookie.fp = mch_fopen((char *)fname_exp, READBIN);
#endif
+ }
if (cookie.fp == NULL && check_other)
{
// Try again, replacing file name ".vimrc" by "_vimrc" or vice versa,
***************
*** 1594,1600 ****
}
}
! if (cookie.fp == NULL)
{
if (p_verbose > 0)
{
--- 1417,1423 ----
}
}
! if (cookie.fp == NULL && !cookie.source_from_buf)
{
if (p_verbose > 0)
{
***************
*** 1632,1643 ****
cookie.fileformat = EOL_DOS;
else
cookie.fileformat = EOL_UNKNOWN;
- cookie.error = FALSE;
#endif
! cookie.nextline = NULL;
! cookie.sourcing_lnum = 0;
! cookie.finished = FALSE;
#ifdef FEAT_EVAL
// Check if this script has a breakpoint.
--- 1455,1468 ----
cookie.fileformat = EOL_DOS;
else
cookie.fileformat = EOL_UNKNOWN;
#endif
! if (fname == NULL)
! // When sourcing a range of lines from a buffer, use the buffer line
! // number.
! cookie.sourcing_lnum = eap->line1 - 1;
! else
! cookie.sourcing_lnum = 0;
#ifdef FEAT_EVAL
// Check if this script has a breakpoint.
***************
*** 1661,1667 ****
sticky_cmdmod_flags = 0;
save_current_sctx = current_sctx;
! current_sctx.sc_version = 1; // default script version
#ifdef FEAT_EVAL
# ifdef FEAT_PROFILE
--- 1486,1497 ----
sticky_cmdmod_flags = 0;
save_current_sctx = current_sctx;
! if (cmdmod.cmod_flags & CMOD_VIM9CMD)
! // When the ":vim9cmd" command modifier is used, source the script as a
! // Vim9 script.
! current_sctx.sc_version = SCRIPT_VERSION_VIM9;
! else
! current_sctx.sc_version = 1; // default script version
#ifdef FEAT_EVAL
# ifdef FEAT_PROFILE
***************
*** 1874,1880 ****
#endif
current_sctx = save_current_sctx;
! fclose(cookie.fp);
vim_free(cookie.nextline);
vim_free(firstline);
convert_setup(&cookie.conv, NULL, NULL);
--- 1704,1713 ----
#endif
current_sctx = save_current_sctx;
! if (cookie.fp != NULL)
! fclose(cookie.fp);
! if (cookie.source_from_buf)
! ga_clear_strings(&cookie.buflines);
vim_free(cookie.nextline);
vim_free(firstline);
convert_setup(&cookie.conv, NULL, NULL);
***************
*** 1891,1896 ****
--- 1724,1740 ----
return retval;
}
+ int
+ do_source(
+ char_u *fname,
+ int check_other, // check for .vimrc and _vimrc
+ int is_vimrc, // DOSO_ value
+ int *ret_sid UNUSED)
+ {
+ return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL);
+ }
+
+
#if defined(FEAT_EVAL) || defined(PROTO)
/*
***************
*** 2038,2048 ****
// make room to read at least 120 (more) characters
if (ga_grow(&ga, 120) == FAIL)
break;
! buf = (char_u *)ga.ga_data;
!
! if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
! sp->fp) == NULL)
! break;
len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
#ifdef USE_CRNL
// Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
--- 1882,1902 ----
// make room to read at least 120 (more) characters
if (ga_grow(&ga, 120) == FAIL)
break;
! if (sp->source_from_buf)
! {
! if (sp->buf_lnum >= sp->buflines.ga_len)
! break; // all the lines are processed
! ga_concat(&ga, ((char_u **)sp->buflines.ga_data)[sp->buf_lnum]);
! sp->buf_lnum++;
! buf = (char_u *)ga.ga_data;
! }
! else
! {
! buf = (char_u *)ga.ga_data;
! if (fgets((char *)buf + ga.ga_len, ga.ga_maxlen - ga.ga_len,
! sp->fp) == NULL)
! break;
! }
len = ga.ga_len + (int)STRLEN(buf + ga.ga_len);
#ifdef USE_CRNL
// Ignore a trailing CTRL-Z, when in Dos mode. Only recognize the
***************
*** 2145,2151 ****
#ifdef FEAT_EVAL
// If breakpoints have been added/deleted need to check for it.
! if (sp->dbg_tick < debug_tick)
{
sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM);
sp->dbg_tick = debug_tick;
--- 1999,2005 ----
#ifdef FEAT_EVAL
// If breakpoints have been added/deleted need to check for it.
! if ((sp->dbg_tick < debug_tick) && !sp->source_from_buf)
{
sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM);
sp->dbg_tick = debug_tick;
***************
*** 2161,2167 ****
// Get current line. If there is a read-ahead line, use it, otherwise get
// one now. "fp" is NULL if actually using a string.
! if (sp->finished || sp->fp == NULL)
line = NULL;
else if (sp->nextline == NULL)
line = get_one_sourceline(sp);
--- 2015,2021 ----
// Get current line. If there is a read-ahead line, use it, otherwise get
// one now. "fp" is NULL if actually using a string.
! if (sp->finished || (!sp->source_from_buf && sp->fp == NULL))
line = NULL;
else if (sp->nextline == NULL)
line = get_one_sourceline(sp);
***************
*** 2265,2271 ****
#ifdef FEAT_EVAL
// Did we encounter a breakpoint?
! if (sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM)
{
dbg_breakpoint(sp->fname, SOURCING_LNUM);
// Find next breakpoint.
--- 2119,2126 ----
#ifdef FEAT_EVAL
// Did we encounter a breakpoint?
! if (!sp->source_from_buf && sp->breakpoint != 0
! && sp->breakpoint <= SOURCING_LNUM)
{
dbg_breakpoint(sp->fname, SOURCING_LNUM);
// Find next breakpoint.
***************
*** 2284,2291 ****
int
sourcing_a_script(exarg_T *eap)
{
! return (getline_equal(eap->getline, eap->cookie, getsourceline)
! || getline_equal(eap->getline, eap->cookie, source_getbufline));
}
/*
--- 2139,2145 ----
int
sourcing_a_script(exarg_T *eap)
{
! return (getline_equal(eap->getline, eap->cookie, getsourceline));
}
/*
*** ../vim-8.2.4602/src/structs.h 2022-02-24 13:28:36.570222354 +0000
--- src/structs.h 2022-03-21 19:40:09.457226040 +0000
***************
*** 4426,4431 ****
--- 4426,4434 ----
char_u *nextline; // if not NULL: line that was read ahead
linenr_T sourcing_lnum; // line number of the source file
int finished; // ":finish" used
+ int source_from_buf;// TRUE if sourcing from current buffer
+ int buf_lnum; // line number in the current buffer
+ garray_T buflines; // lines in the current buffer
#ifdef USE_CRNL
int fileformat; // EOL_UNKNOWN, EOL_UNIX or EOL_DOS
int error; // TRUE if LF found after CR-LF
*** ../vim-8.2.4602/src/testdir/test_source.vim 2022-03-19 12:56:42.533503825 +0000
--- src/testdir/test_source.vim 2022-03-21 19:32:54.482829827 +0000
***************
*** 146,151 ****
--- 146,168 ----
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
***************
*** 327,332 ****
--- 344,406 ----
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()
+ new
+
" test for sourcing a Vim9 script
%d _
let lines =<< trim END
***************
*** 342,347 ****
--- 416,613 ----
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)
+
%bw!
endfunc
*** ../vim-8.2.4602/src/version.c 2022-03-20 21:14:08.438143810 +0000
--- src/version.c 2022-03-21 19:38:55.261492905 +0000
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 4603,
/**/
--
Not too long ago, unzipping in public was illegal...
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///