To: vim_dev@googlegroups.com Subject: Patch 8.2.4603 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 || 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 || 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=" 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=" 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=" 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("") + 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("") + au SourcePost * let g:XsourcePost=6 + \ | let g:XsourcePostFile = expand("") + 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 + 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("") + 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 -- Bram@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 ///