diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index f830eb407e..b5c2b4ceb9 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -3262,6 +3262,9 @@ A jump table for the options with a short description can be found at |Q_op|. stlnc:c ' ' or '=' statusline of the non-current windows vert:c '|' vertical separators |:vsplit| fold:c '-' filling 'foldtext' + foldopen:c '-' mark the beginning of a fold + foldclose:c '+' show a closed fold + foldsep:c '|' open fold middle character diff:c '-' deleted lines of the 'diff' option eob:c '~' empty lines below the end of a buffer @@ -4949,7 +4952,7 @@ A jump table for the options with a short description can be found at |Q_op|. *'listchars'* *'lcs'* 'listchars' 'lcs' string (default "eol:$") - global + global or local to window |global-local| Strings to use in 'list' mode and for the |:list| command. It is a comma separated list of string settings. *lcs-eol* diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 195a2025a5..60ef9c1a00 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -354,13 +354,15 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. Vim version, or update Vim to a newer version. See |vimscript-version| for what changed between versions. -:vim9[script] [noclear] *:vim9* *:vim9script* +:vim9s[cript] [noclear] *:vim9s* *:vim9script* Marks a script file as containing |Vim9-script| commands. Also see |vim9-namespace|. Must be the first command in the file. For [noclear] see |vim9-reload|. Without the |+eval| feature this changes the syntax for some commands. + See |:vim9cmd| for executing one command with Vim9 + syntax and semantics. *:scr* *:scriptnames* :scr[iptnames] List all sourced script names, in the order they were diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 804a98ad98..def68d312a 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -51,6 +51,7 @@ The Vim9 script syntax and semantics are used in: - a function defined with the `:def` command - a script file where the first command is `vim9script` - an autocommand defined in the context of the above +- a command prefixed with the `vim9cmd` command modifier When using `:function` in a Vim9 script file the legacy syntax is used, with the highest |scriptversion|. However, this can be confusing and is therefore @@ -60,6 +61,12 @@ Vim9 script and legacy Vim script can be mixed. There is no requirement to rewrite old scripts, they keep working as before. You may want to use a few `:def` functions for code that needs to be fast. + *:vim9* *:vim9cmd* +:vim9[cmd] {cmd} + Execute {cmd} using Vim9 script syntax and semantics. + Useful when typing a command and in a legacy script or + function. + ============================================================================== 2. Differences from legacy Vim script *vim9-differences* @@ -1044,9 +1051,9 @@ that you don't do that. Namespace ~ *vim9-namespace* To recognize a file that can be imported the `vim9script` statement must -appear as the first statement in the file. It tells Vim to interpret the -script in its own namespace, instead of the global namespace. If a file -starts with: > +appear as the first statement in the file (see |vim9-mix| for an exception). +It tells Vim to interpret the script in its own namespace, instead of the +global namespace. If a file starts with: > vim9script var myvar = 'yes' Then "myvar" will only exist in this file. While without `vim9script` it would @@ -1066,6 +1073,27 @@ Vim default value, like with: > One of the effects is that |line-continuation| is always enabled. The original value of 'cpoptions' is restored at the end of the script. + *vim9-mix* +There is one way to use both legacy and Vim9 syntax in one script file: > + " comments may go here + if !has('vim9script') + " legacy script commands go here + finish + endif + vim9script + # Vim9 script commands go here +This allows for writing a script that takes advantage of the Vim9 script +syntax if possible, but will also work on an Vim version without it. + +This can only work in two ways: +1. The "if" statement evaluates to false, the commands up to `endif` are + skipped and `vim9script` is then the first command actually executed. +2. The "if" statement evaluates to true, the commands up to `endif` are + executed and `finish` bails out before reaching `vim9script`. + +TODO: The "vim9script" feature does not exist yet, it will only be added once +the Vim9 script syntax has been fully implemented. + Export ~ *:export* *:exp* diff --git a/runtime/filetype.vim b/runtime/filetype.vim index e4910e3719..259e5eeb3c 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -216,6 +216,9 @@ au BufNewFile,BufRead *.bc setf bc " BDF font au BufNewFile,BufRead *.bdf setf bdf +" Beancount +au BufNewFile,BufRead *.beancount setf beancount + " BibTeX bibliography database file au BufNewFile,BufRead *.bib setf bib @@ -1488,6 +1491,9 @@ au BufNewFile,BufRead *.sdl,*.pr setf sdl " sed au BufNewFile,BufRead *.sed setf sed +" svelte +au BufNewFile,BufRead *.svelte setf svelte + " Sieve (RFC 3028, 5228) au BufNewFile,BufRead *.siv,*.sieve setf sieve diff --git a/src/buffer.c b/src/buffer.c index a36e3b12aa..0169717bd5 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -4559,7 +4559,7 @@ build_stl_str_hl( case STL_VIRTCOL_ALT: // In list mode virtcol needs to be recomputed virtcol = wp->w_virtcol; - if (wp->w_p_list && lcs_tab1 == NUL) + if (wp->w_p_list && wp->w_lcs_chars.tab1 == NUL) { wp->w_p_list = FALSE; getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); diff --git a/src/charset.c b/src/charset.c index 4289360e47..d06a273643 100644 --- a/src/charset.c +++ b/src/charset.c @@ -753,7 +753,7 @@ vim_strnsize(char_u *s, int len) #ifdef FEAT_VARTABS # define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \ - if (*(p) == TAB && (!(wp)->w_p_list || lcs_tab1)) \ + if (*(p) == TAB && (!(wp)->w_p_list || wp->w_lcs_chars.tab1)) \ { \ return tabstop_padding(col, (buf)->b_p_ts, (buf)->b_p_vts_array); \ } \ @@ -761,7 +761,7 @@ vim_strnsize(char_u *s, int len) return ptr2cells(p); #else # define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \ - if (*(p) == TAB && (!(wp)->w_p_list || lcs_tab1)) \ + if (*(p) == TAB && (!(wp)->w_p_list || wp->w_lcs_chars.tab1)) \ { \ int ts; \ ts = (buf)->b_p_ts; \ @@ -1153,7 +1153,7 @@ win_nolbr_chartabsize( { int n; - if (*s == TAB && (!wp->w_p_list || lcs_tab1)) + if (*s == TAB && (!wp->w_p_list || wp->w_lcs_chars.tab1)) { # ifdef FEAT_VARTABS return tabstop_padding(col, wp->w_buffer->b_p_ts, @@ -1248,7 +1248,7 @@ getvcol( * use a simple loop. * Also use this when 'list' is set but tabs take their normal size. */ - if ((!wp->w_p_list || lcs_tab1 != NUL) + if ((!wp->w_p_list || wp->w_lcs_chars.tab1 != NUL) #ifdef FEAT_LINEBREAK && !wp->w_p_lbr && *get_showbreak_value(wp) == NUL && !wp->w_p_bri #endif diff --git a/src/drawline.c b/src/drawline.c index 2794f70c0e..377ef10d38 100644 --- a/src/drawline.c +++ b/src/drawline.c @@ -248,9 +248,9 @@ win_line( int c_final = NUL; // final char, mandatory if set int extra_attr = 0; // attributes when n_extra != 0 static char_u *at_end_str = (char_u *)""; // used for p_extra when - // displaying lcs_eol at end-of-line - int lcs_eol_one = lcs_eol; // lcs_eol until it's been used - int lcs_prec_todo = lcs_prec; // lcs_prec until it's been used + // displaying eol at end-of-line + int lcs_eol_one = wp->w_lcs_chars.eol; // eol until it's been used + int lcs_prec_todo = wp->w_lcs_chars.prec; // prec until it's been used // saved "extra" items for when draw_state becomes WL_LINE (again) int saved_n_extra = 0; @@ -735,11 +735,14 @@ win_line( if (wp->w_p_list) { - if (lcs_space || lcs_trail || lcs_lead || lcs_nbsp) + if (wp->w_lcs_chars.space + || wp->w_lcs_chars.trail + || wp->w_lcs_chars.lead + || wp->w_lcs_chars.nbsp) extra_check = TRUE; // find start of trailing whitespace - if (lcs_trail) + if (wp->w_lcs_chars.trail) { trailcol = (colnr_T)STRLEN(ptr); while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1])) @@ -747,7 +750,7 @@ win_line( trailcol += (colnr_T) (ptr - line); } // find end of leading whitespace - if (lcs_lead) + if (wp->w_lcs_chars.lead) { leadcol = 0; while (VIM_ISWHITE(ptr[leadcol])) @@ -2000,22 +2003,23 @@ win_line( } #endif - // 'list': Change char 160 to lcs_nbsp and space to lcs_space. - // But not when the character is followed by a composing - // character (use mb_l to check that). + // 'list': Change char 160 to 'nbsp' and space to 'space' + // setting in 'listchars'. But not when the character is + // followed by a composing character (use mb_l to check that). if (wp->w_p_list && ((((c == 160 && mb_l == 1) || (mb_utf8 && ((mb_c == 160 && mb_l == 2) || (mb_c == 0x202f && mb_l == 3)))) - && lcs_nbsp) + && wp->w_lcs_chars.nbsp) || (c == ' ' && mb_l == 1 - && lcs_space + && wp->w_lcs_chars.space && ptr - line >= leadcol && ptr - line <= trailcol))) { - c = (c == ' ') ? lcs_space : lcs_nbsp; + c = (c == ' ') ? wp->w_lcs_chars.space : + wp->w_lcs_chars.nbsp; if (area_attr == 0 && search_attr == 0) { n_attr = 1; @@ -2036,7 +2040,8 @@ win_line( if ((trailcol != MAXCOL && ptr > line + trailcol && c == ' ') || (leadcol != 0 && ptr < line + leadcol && c == ' ')) { - c = (ptr > line + trailcol) ? lcs_trail : lcs_lead; + c = (ptr > line + trailcol) ? wp->w_lcs_chars.trail + : wp->w_lcs_chars.lead; if (!attr_pri) { n_attr = 1; @@ -2061,7 +2066,7 @@ win_line( // when getting a character from the file, we may have to // turn it into something else on the way to putting it // into "ScreenLines". - if (c == TAB && (!wp->w_p_list || lcs_tab1)) + if (c == TAB && (!wp->w_p_list || wp->w_lcs_chars.tab1)) { int tab_len = 0; long vcol_adjusted = vcol; // removed showbreak length @@ -2101,18 +2106,19 @@ win_line( // there are characters to conceal tab_len += vcol_off; // boguscols before FIX_FOR_BOGUSCOLS macro from above - if (wp->w_p_list && lcs_tab1 && old_boguscols > 0 - && n_extra > tab_len) + if (wp->w_p_list && wp->w_lcs_chars.tab1 + && old_boguscols > 0 + && n_extra > tab_len) tab_len += n_extra - tab_len; #endif // if n_extra > 0, it gives the number of chars, to // use for a tab, else we need to calculate the width // for a tab - len = (tab_len * mb_char2len(lcs_tab2)); + len = (tab_len * mb_char2len(wp->w_lcs_chars.tab2)); if (n_extra > 0) len += n_extra - tab_len; - c = lcs_tab1; + c = wp->w_lcs_chars.tab1; p = alloc(len + 1); vim_memset(p, ' ', len); p[len] = NUL; @@ -2120,7 +2126,7 @@ win_line( p_extra_free = p; for (i = 0; i < tab_len; i++) { - int lcs = lcs_tab2; + int lcs = wp->w_lcs_chars.tab2; if (*p == NUL) { @@ -2128,10 +2134,10 @@ win_line( break; } - // if lcs_tab3 is given, need to change the char + // if tab3 is given, need to change the char // for tab - if (lcs_tab3 && i == tab_len - 1) - lcs = lcs_tab3; + if (wp->w_lcs_chars.tab3 && i == tab_len - 1) + lcs = wp->w_lcs_chars.tab3; mb_char2bytes(lcs, p); p += mb_char2len(lcs); n_extra += mb_char2len(lcs) @@ -2162,21 +2168,23 @@ win_line( // correctly set further below (effectively reverts the // FIX_FOR_BOGSUCOLS macro if (n_extra == tab_len + vc_saved && wp->w_p_list - && lcs_tab1) + && wp->w_lcs_chars.tab1) tab_len += vc_saved; } #endif mb_utf8 = FALSE; // don't draw as UTF-8 if (wp->w_p_list) { - c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1; + c = (n_extra == 0 && wp->w_lcs_chars.tab3) + ? wp->w_lcs_chars.tab3 + : wp->w_lcs_chars.tab1; #ifdef FEAT_LINEBREAK if (wp->w_p_lbr) c_extra = NUL; // using p_extra from above else #endif - c_extra = lcs_tab2; - c_final = lcs_tab3; + c_extra = wp->w_lcs_chars.tab2; + c_final = wp->w_lcs_chars.tab3; n_attr = tab_len + 1; extra_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_8)); saved_attr2 = char_attr; // save current attr @@ -2241,8 +2249,8 @@ win_line( c_final = NUL; } } - if (wp->w_p_list && lcs_eol > 0) - c = lcs_eol; + if (wp->w_p_list && wp->w_lcs_chars.eol > 0) + c = wp->w_lcs_chars.eol; else c = ' '; lcs_eol_one = -1; @@ -2344,7 +2352,8 @@ win_line( // don't do search HL for the rest of the line if (line_attr != 0 && char_attr == search_attr && (did_line_attr > 1 - || (wp->w_p_list && lcs_eol > 0))) + || (wp->w_p_list && + wp->w_lcs_chars.eol > 0))) char_attr = line_attr; # ifdef FEAT_DIFF if (diff_hlf == HLF_TXD) @@ -2404,8 +2413,8 @@ win_line( c = match_conc; else if (syn_get_sub_char() != NUL) c = syn_get_sub_char(); - else if (lcs_conceal != NUL) - c = lcs_conceal; + else if (wp->w_lcs_chars.conceal != NUL) + c = wp->w_lcs_chars.conceal; else c = ' '; @@ -2552,7 +2561,7 @@ win_line( && draw_state > WL_NR && c != NUL) { - c = lcs_prec; + c = wp->w_lcs_chars.prec; lcs_prec_todo = NUL; if (has_mbyte && (*mb_char2cells)(mb_c) > 1) { @@ -2598,7 +2607,7 @@ win_line( // highlight match at end of line. If it's beyond the last // char on the screen, just overwrite that one (tricky!) Not // needed when a '$' was displayed for 'list'. - if (lcs_eol == lcs_eol_one + if (wp->w_lcs_chars.eol == lcs_eol_one && ((area_attr != 0 && vcol == fromcol && (VIsual_mode != Ctrl_V || lnum == VIsual.lnum @@ -2768,7 +2777,7 @@ win_line( // Show "extends" character from 'listchars' if beyond the line end and // 'list' is set. - if (lcs_ext != NUL + if (wp->w_lcs_chars.ext != NUL && wp->w_p_list && !wp->w_p_wrap #ifdef FEAT_DIFF @@ -2783,7 +2792,7 @@ win_line( || (wp->w_p_list && lcs_eol_one > 0) || (n_extra && (c_extra != NUL || *p_extra != NUL)))) { - c = lcs_ext; + c = wp->w_lcs_chars.ext; char_attr = hl_combine_attr(win_attr, HL_ATTR(HLF_AT)); mb_c = c; if (enc_utf8 && utf_char2len(c) > 1) @@ -3040,7 +3049,8 @@ win_line( #ifdef FEAT_DIFF || filler_todo > 0 #endif - || (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str) + || (wp->w_p_list && wp->w_lcs_chars.eol != NUL + && p_extra != at_end_str) || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL))) ) { @@ -3165,7 +3175,7 @@ win_line( #endif saved_char_attr = 0; n_extra = 0; - lcs_prec_todo = lcs_prec; + lcs_prec_todo = wp->w_lcs_chars.prec; #ifdef FEAT_LINEBREAK # ifdef FEAT_DIFF if (filler_todo <= 0) diff --git a/src/drawscreen.c b/src/drawscreen.c index b376ff7906..786944e715 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -696,7 +696,7 @@ win_redr_ruler(win_T *wp, int always, int ignore_pum) // In list mode virtcol needs to be recomputed virtcol = wp->w_virtcol; - if (wp->w_p_list && lcs_tab1 == NUL) + if (wp->w_p_list && wp->w_lcs_chars.tab1 == NUL) { wp->w_p_list = FALSE; getvvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); diff --git a/src/errors.h b/src/errors.h index 927e1ffde9..05f90b14b1 100644 --- a/src/errors.h +++ b/src/errors.h @@ -363,3 +363,5 @@ EXTERN char e_register_name_must_be_one_char_str[] INIT(= N_("E1162: Register name must be one character: %s")); EXTERN char e_variable_nr_type_mismatch_expected_str_but_got_str[] INIT(= N_("E1163: Variable %d: type mismatch, expected %s but got %s")); +EXTERN char e_vim9cmd_must_be_followed_by_command[] + INIT(= N_("E1164: vim9cmd must be followed by a command")); diff --git a/src/eval.c b/src/eval.c index aae6ee8ffa..444c0faf38 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3421,7 +3421,21 @@ eval7( */ case '(': ret = NOTDONE; if (in_vim9script()) + { ret = get_lambda_tv(arg, rettv, TRUE, evalarg); + if (ret == OK && evaluate) + { + ufunc_T *ufunc = rettv->vval.v_partial->pt_func; + + // compile it here to get the return type + if (compile_def_function(ufunc, + TRUE, PROFILING(ufunc), NULL) == FAIL) + { + clear_tv(rettv); + ret = FAIL; + } + } + } if (ret == NOTDONE) { *arg = skipwhite_and_linebreak(*arg + 1, evalarg); diff --git a/src/evalfunc.c b/src/evalfunc.c index 54a126cadf..1a83f0f49f 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -9771,7 +9771,8 @@ f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv) { cchar = syn_get_sub_char(); if (cchar == NUL && curwin->w_p_cole == 1) - cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal; + cchar = (curwin->w_lcs_chars.conceal == NUL) ? ' ' + : curwin->w_lcs_chars.conceal; if (cchar != NUL) { if (has_mbyte) diff --git a/src/evalvars.c b/src/evalvars.c index 5b931cd5e2..4129592fb8 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -2778,7 +2778,6 @@ get_script_local_ht(void) lookup_scriptvar( char_u *name, size_t len, - void *lvar UNUSED, cctx_T *dummy UNUSED) { hashtab_T *ht = get_script_local_ht(); diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h index 4c7201c513..5d66a72461 100644 --- a/src/ex_cmdidxs.h +++ b/src/ex_cmdidxs.h @@ -27,10 +27,10 @@ static const unsigned short cmdidxs1[26] = /* t */ 460, /* u */ 505, /* v */ 516, - /* w */ 536, - /* x */ 550, - /* y */ 560, - /* z */ 561 + /* w */ 537, + /* x */ 551, + /* y */ 561, + /* z */ 562 }; /* @@ -62,11 +62,11 @@ static const unsigned char cmdidxs2[26][26] = /* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 50, 0, 51, 0, 63, 64, 0, 65, 0 }, /* t */ { 2, 0, 19, 0, 24, 26, 0, 27, 0, 28, 0, 29, 33, 36, 38, 39, 0, 40, 42, 0, 43, 0, 0, 0, 0, 0 }, /* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* v */ { 1, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 11, 14, 0, 0, 0, 0, 17, 0, 18, 0, 0, 0, 0, 0 }, + /* v */ { 1, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 12, 15, 0, 0, 0, 0, 18, 0, 19, 0, 0, 0, 0, 0 }, /* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 12, 13, 0, 0, 0, 0 }, /* x */ { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 0, 0, 0, 7, 0, 0, 8, 0, 0, 0, 0, 0 }, /* y */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; -static const int command_count = 576; +static const int command_count = 577; diff --git a/src/ex_cmds.h b/src/ex_cmds.h index b530adf174..a6b07a0dd9 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -1685,6 +1685,9 @@ EXCMD(CMD_vimgrep, "vimgrep", ex_vimgrep, EXCMD(CMD_vimgrepadd, "vimgrepadd", ex_vimgrep, EX_RANGE|EX_BANG|EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM|EX_TRLBAR|EX_XFILE|EX_LOCK_OK, ADDR_OTHER), +EXCMD(CMD_vim9cmd, "vim9cmd", ex_wrongmodifier, + EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_vim9script, "vim9script", ex_vim9script, EX_WORD1|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), diff --git a/src/ex_docmd.c b/src/ex_docmd.c index b5bdcd3cde..111fbc8fb5 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -1743,7 +1743,7 @@ do_one_cmd( int starts_with_colon = FALSE; #ifdef FEAT_EVAL int may_have_range; - int vim9script = in_vim9script(); + int vim9script; int did_set_expr_line = FALSE; #endif int sourcing = flags & DOCMD_VERBOSE; @@ -1791,7 +1791,9 @@ do_one_cmd( if (parse_command_modifiers(&ea, &errormsg, &cmdmod, FALSE) == FAIL) goto doend; apply_cmdmod(&cmdmod); - +#ifdef FEAT_EVAL + vim9script = in_vim9script(); +#endif after_modifier = ea.cmd; #ifdef FEAT_EVAL @@ -1961,12 +1963,16 @@ do_one_cmd( /* * strange vi behaviour: * ":3" jumps to line 3 - * ":3|..." prints line 3 - * ":|" prints current line + * ":3|..." prints line 3 (not in Vim9 script) + * ":|" prints current line (not in Vim9 script) */ if (ea.skip) // skip this if inside :if goto doend; - if (*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) + if ((*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) +#ifdef FEAT_EVAL + && !vim9script +#endif + ) { ea.cmdidx = CMD_print; ea.argt = EX_RANGE+EX_COUNT+EX_TRLBAR; @@ -2595,8 +2601,12 @@ do_one_cmd( #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) + && current_sctx.sc_sid > 0 + && ea.cmdidx != CMD_endif + && (cstack->cs_idx < 0 + || (cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE))) SCRIPT_ITEM(current_sctx.sc_sid)->sn_state = SN_STATE_HAD_COMMAND; /* @@ -2939,6 +2949,17 @@ parse_command_modifiers( cmod->cmod_split |= WSP_VERT; continue; } + if (checkforcmd(&eap->cmd, "vim9cmd", 4)) + { + if (ends_excmd2(p, eap->cmd)) + { + *errormsg = + _(e_vim9cmd_must_be_followed_by_command); + return FAIL; + } + cmod->cmod_flags |= CMOD_VIM9CMD; + continue; + } if (!checkforcmd(&p, "verbose", 4)) break; if (vim_isdigit(*eap->cmd)) @@ -3296,7 +3317,7 @@ skip_option_env_lead(char_u *start) find_ex_command( exarg_T *eap, int *full UNUSED, - int (*lookup)(char_u *, size_t, void *, cctx_T *) UNUSED, + int (*lookup)(char_u *, size_t, cctx_T *) UNUSED, cctx_T *cctx UNUSED) { int len; @@ -3405,7 +3426,7 @@ find_ex_command( // Recognize an assignment if we recognize the variable name: // "g:var = expr" - // "var = expr" where "var" is a local var name. + // "var = expr" where "var" is a variable name. if (*eap->cmd == '@') p = eap->cmd + 2; oplen = assignment_len(skipwhite(p), &heredoc); @@ -3415,7 +3436,7 @@ find_ex_command( || *eap->cmd == '&' || *eap->cmd == '$' || *eap->cmd == '@' - || lookup(eap->cmd, p - eap->cmd, NULL, cctx) == OK) + || lookup(eap->cmd, p - eap->cmd, cctx) == OK) { eap->cmdidx = CMD_var; return eap->cmd; @@ -3434,7 +3455,7 @@ find_ex_command( // If it is an ID it might be a variable with an operator on the next // line, if the variable exists it can't be an Ex command. if (p > eap->cmd && ends_excmd(*skipwhite(p)) - && (lookup(eap->cmd, p - eap->cmd, NULL, cctx) == OK + && (lookup(eap->cmd, p - eap->cmd, cctx) == OK || (ASCII_ISALPHA(eap->cmd[0]) && eap->cmd[1] == ':'))) { eap->cmdidx = CMD_eval; diff --git a/src/globals.h b/src/globals.h index 1975fa6d38..e66f902ba4 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1344,26 +1344,14 @@ EXTERN char_u *homedir INIT(= NULL); // directory is not a local directory, globaldir is NULL. EXTERN char_u *globaldir INIT(= NULL); -// Characters from 'listchars' option -EXTERN int lcs_eol INIT(= '$'); -EXTERN int lcs_ext INIT(= NUL); -EXTERN int lcs_prec INIT(= NUL); -EXTERN int lcs_nbsp INIT(= NUL); -EXTERN int lcs_space INIT(= NUL); -EXTERN int lcs_tab1 INIT(= NUL); -EXTERN int lcs_tab2 INIT(= NUL); -EXTERN int lcs_tab3 INIT(= NUL); -EXTERN int lcs_trail INIT(= NUL); -EXTERN int lcs_lead INIT(= NUL); -#ifdef FEAT_CONCEAL -EXTERN int lcs_conceal INIT(= ' '); -#endif - // Characters from 'fillchars' option EXTERN int fill_stl INIT(= ' '); EXTERN int fill_stlnc INIT(= ' '); EXTERN int fill_vert INIT(= ' '); EXTERN int fill_fold INIT(= '-'); +EXTERN int fill_foldopen INIT(= '-'); +EXTERN int fill_foldclosed INIT(= '+'); +EXTERN int fill_foldsep INIT(= '|'); EXTERN int fill_diff INIT(= '-'); EXTERN int fill_eob INIT(= '~'); diff --git a/src/indent.c b/src/indent.c index 6ac6182df4..e1c6f522a9 100644 --- a/src/indent.c +++ b/src/indent.c @@ -432,7 +432,8 @@ get_indent_str( { if (*ptr == TAB) { - if (!list || lcs_tab1) // count a tab for what it is worth + if (!list || curwin->w_lcs_chars.tab1) + // count a tab for what it is worth count += ts - (count % ts); else // In list mode, when tab is not set, count screen char width @@ -462,7 +463,7 @@ get_indent_str_vtab(char_u *ptr, int ts, int *vts, int list) { if (*ptr == TAB) // count a tab for what it is worth { - if (!list || lcs_tab1) + if (!list || curwin->w_lcs_chars.tab1) count += tabstop_padding(count, ts, vts); else // In list mode, when tab is not set, count screen char width diff --git a/src/message.c b/src/message.c index 755b11f0d9..de5183cf97 100644 --- a/src/message.c +++ b/src/message.c @@ -248,6 +248,13 @@ trunc_string( int i; int n; + if (*s == NUL) + { + if (buflen > 0) + *buf = NUL; + return; + } + if (room_in < 3) room = 0; half = room / 2; @@ -1846,14 +1853,14 @@ msg_prt_line(char_u *s, int list) if (list) { // find start of trailing whitespace - if (lcs_trail) + if (curwin->w_lcs_chars.trail) { trail = s + STRLEN(s); while (trail > s && VIM_ISWHITE(trail[-1])) --trail; } // find end of leading whitespace - if (lcs_lead) + if (curwin->w_lcs_chars.lead) { lead = s; while (VIM_ISWHITE(lead[0])) @@ -1866,7 +1873,7 @@ msg_prt_line(char_u *s, int list) // output a space for an empty line, otherwise the line will be // overwritten - if (*s == NUL && !(list && lcs_eol != NUL)) + if (*s == NUL && !(list && curwin->w_lcs_chars.eol != NUL)) msg_putchar(' '); while (!got_int) @@ -1888,11 +1895,11 @@ msg_prt_line(char_u *s, int list) { STRCPY(buf, "?"); } - else if (lcs_nbsp != NUL && list + else if (curwin->w_lcs_chars.nbsp != NUL && list && (mb_ptr2char(s) == 160 || mb_ptr2char(s) == 0x202f)) { - mb_char2bytes(lcs_nbsp, buf); + mb_char2bytes(curwin->w_lcs_chars.nbsp, buf); buf[(*mb_ptr2len)(buf)] = NUL; } else @@ -1908,7 +1915,7 @@ msg_prt_line(char_u *s, int list) { attr = 0; c = *s++; - if (c == TAB && (!list || lcs_tab1)) + if (c == TAB && (!list || curwin->w_lcs_chars.tab1)) { // tab amount depends on current column #ifdef FEAT_VARTABS @@ -1925,24 +1932,26 @@ msg_prt_line(char_u *s, int list) } else { - c = (n_extra == 0 && lcs_tab3) ? lcs_tab3 : lcs_tab1; - c_extra = lcs_tab2; - c_final = lcs_tab3; + c = (n_extra == 0 && curwin->w_lcs_chars.tab3) + ? curwin->w_lcs_chars.tab3 + : curwin->w_lcs_chars.tab1; + c_extra = curwin->w_lcs_chars.tab2; + c_final = curwin->w_lcs_chars.tab3; attr = HL_ATTR(HLF_8); } } - else if (c == 160 && list && lcs_nbsp != NUL) + else if (c == 160 && list && curwin->w_lcs_chars.nbsp != NUL) { - c = lcs_nbsp; + c = curwin->w_lcs_chars.nbsp; attr = HL_ATTR(HLF_8); } - else if (c == NUL && list && lcs_eol != NUL) + else if (c == NUL && list && curwin->w_lcs_chars.eol != NUL) { p_extra = (char_u *)""; c_extra = NUL; c_final = NUL; n_extra = 1; - c = lcs_eol; + c = curwin->w_lcs_chars.eol; attr = HL_ATTR(HLF_AT); --s; } @@ -1959,17 +1968,17 @@ msg_prt_line(char_u *s, int list) } else if (c == ' ' && lead != NULL && s <= lead) { - c = lcs_lead; + c = curwin->w_lcs_chars.lead; attr = HL_ATTR(HLF_8); } else if (c == ' ' && trail != NULL && s > trail) { - c = lcs_trail; + c = curwin->w_lcs_chars.trail; attr = HL_ATTR(HLF_8); } - else if (c == ' ' && list && lcs_space != NUL) + else if (c == ' ' && list && curwin->w_lcs_chars.space != NUL) { - c = lcs_space; + c = curwin->w_lcs_chars.space; attr = HL_ATTR(HLF_8); } } diff --git a/src/message_test.c b/src/message_test.c index 85a29b4712..88335de26c 100644 --- a/src/message_test.c +++ b/src/message_test.c @@ -49,6 +49,15 @@ test_trunc_string(void) char_u *buf; /*allocated every time to find uninit errors */ char_u *s; + // Should not write anything to destination if buflen is 0. + trunc_string((char_u *)"", NULL, 1, 0); + + // Truncating an empty string does nothing. + buf = alloc(1); + trunc_string((char_u *)"", buf, 1, 1); + assert(buf[0] == NUL); + vim_free(buf); + // in place buf = alloc(40); STRCPY(buf, "text"); diff --git a/src/misc1.c b/src/misc1.c index 5d87b11975..d9ff18729d 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -403,7 +403,7 @@ plines_win_nofold(win_T *wp, linenr_T lnum) * If list mode is on, then the '$' at the end of the line may take up one * extra column. */ - if (wp->w_p_list && lcs_eol != NUL) + if (wp->w_p_list && wp->w_lcs_chars.eol != NUL) col += 1; /* @@ -460,7 +460,8 @@ plines_win_col(win_T *wp, linenr_T lnum, long column) * from one screen line to the next (when 'columns' is not a multiple of * 'ts') -- webb. */ - if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || lcs_tab1)) + if (*s == TAB && (State & NORMAL) && (!wp->w_p_list || + wp->w_lcs_chars.tab1)) col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1; /* diff --git a/src/mouse.c b/src/mouse.c index 2190ece859..10667ec7a2 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -2009,7 +2009,7 @@ retnomove: count |= CURSOR_MOVED; // Cursor has moved # ifdef FEAT_FOLDING - if (mouse_char == '+') + if (mouse_char == fill_foldclosed) count |= MOUSE_FOLD_OPEN; else if (mouse_char != ' ') count |= MOUSE_FOLD_CLOSE; diff --git a/src/option.c b/src/option.c index 9a3b6f858e..6d55089ac1 100644 --- a/src/option.c +++ b/src/option.c @@ -2359,9 +2359,11 @@ didset_options2(void) // Parse default for 'wildmode' check_opt_wim(); - (void)set_chars_option(&p_lcs); + // Parse default for 'listchars'. + (void)set_chars_option(curwin, &curwin->w_p_lcs); + // Parse default for 'fillchars'. - (void)set_chars_option(&p_fcs); + (void)set_chars_option(curwin, &p_fcs); #ifdef FEAT_CLIPBOARD // Parse default for 'clipboard' @@ -5171,6 +5173,11 @@ unset_global_local_option(char_u *name, void *from) case PV_MENC: clear_string_option(&buf->b_p_menc); break; + case PV_LCS: + clear_string_option(&((win_T *)from)->w_p_lcs); + set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs); + redraw_later(NOT_VALID); + break; } } #endif @@ -5229,6 +5236,8 @@ get_varp_scope(struct vimoption *p, int opt_flags) #endif case PV_BKC: return (char_u *)&(curbuf->b_p_bkc); case PV_MENC: return (char_u *)&(curbuf->b_p_menc); + case PV_LCS: return (char_u *)&(curwin->w_p_lcs); + } return NULL; // "cannot happen" } @@ -5326,6 +5335,8 @@ get_varp(struct vimoption *p) case PV_ARAB: return (char_u *)&(curwin->w_p_arab); #endif case PV_LIST: return (char_u *)&(curwin->w_p_list); + case PV_LCS: return *curwin->w_p_lcs != NUL + ? (char_u *)&(curwin->w_p_lcs) : p->var; #ifdef FEAT_SPELL case PV_SPELL: return (char_u *)&(curwin->w_p_spell); #endif @@ -5556,6 +5567,7 @@ after_copy_winopt(win_T *wp UNUSED) fill_culopt_flags(NULL, wp); check_colorcolumn(wp); #endif + set_chars_option(wp, &wp->w_p_lcs); } /* @@ -5571,6 +5583,7 @@ copy_winopt(winopt_T *from, winopt_T *to) to->wo_arab = from->wo_arab; #endif to->wo_list = from->wo_list; + to->wo_lcs = vim_strsave(from->wo_lcs); to->wo_nu = from->wo_nu; to->wo_rnu = from->wo_rnu; #ifdef FEAT_LINEBREAK @@ -5705,6 +5718,7 @@ check_winopt(winopt_T *wop UNUSED) check_string_option(&wop->wo_briopt); #endif check_string_option(&wop->wo_wcr); + check_string_option(&wop->wo_lcs); } /* @@ -5750,6 +5764,7 @@ clear_winopt(winopt_T *wop UNUSED) clear_string_option(&wop->wo_twk); clear_string_option(&wop->wo_tws); #endif + clear_string_option(&wop->wo_lcs); } #ifdef FEAT_EVAL diff --git a/src/option.h b/src/option.h index 6b2f48a194..7d23d6c60b 100644 --- a/src/option.h +++ b/src/option.h @@ -1260,6 +1260,7 @@ enum enum { WV_LIST = 0 + , WV_LCS #ifdef FEAT_ARABIC , WV_ARAB #endif diff --git a/src/optiondefs.h b/src/optiondefs.h index 865db96197..624b52eb22 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -188,6 +188,7 @@ #ifdef FEAT_LINEBREAK # define PV_LBR OPT_WIN(WV_LBR) #endif +#define PV_LCS OPT_BOTH(OPT_WIN(WV_LCS)) #define PV_NU OPT_WIN(WV_NU) #define PV_RNU OPT_WIN(WV_RNU) #ifdef FEAT_LINEBREAK @@ -1683,7 +1684,7 @@ static struct vimoption options[] = (char_u *)VAR_WIN, PV_LIST, {(char_u *)FALSE, (char_u *)0L} SCTX_INIT}, {"listchars", "lcs", P_STRING|P_VI_DEF|P_RALL|P_ONECOMMA|P_NODUP, - (char_u *)&p_lcs, PV_NONE, + (char_u *)&p_lcs, PV_LCS, {(char_u *)"eol:$", (char_u *)0L} SCTX_INIT}, {"loadplugins", "lpl", P_BOOL|P_VI_DEF, (char_u *)&p_lpl, PV_NONE, diff --git a/src/optionstr.c b/src/optionstr.c index 34a8d377e0..96c7b39a44 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -862,10 +862,24 @@ did_set_string_option( { if (check_opt_strings(p_ambw, p_ambw_values, FALSE) != OK) errmsg = e_invarg; - else if (set_chars_option(&p_lcs) != NULL) - errmsg = _("E834: Conflicts with value of 'listchars'"); - else if (set_chars_option(&p_fcs) != NULL) + else if (set_chars_option(curwin, &p_fcs) != NULL) errmsg = _("E835: Conflicts with value of 'fillchars'"); + else + { + tabpage_T *tp; + win_T *wp; + + FOR_ALL_TAB_WINDOWS(tp, wp) + { + if (set_chars_option(wp, &wp->w_p_lcs) != NULL) + { + errmsg = _("E834: Conflicts with value of 'listchars'"); + goto ambw_end; + } + } + } +ambw_end: + {} } // 'background' @@ -1302,16 +1316,37 @@ did_set_string_option( } } - // 'listchars' + // global 'listchars' else if (varp == &p_lcs) { - errmsg = set_chars_option(varp); + errmsg = set_chars_option(curwin, varp); + if (errmsg == NULL) + { + tabpage_T *tp; + win_T *wp; + + // The current window is set to use the global 'listchars' value. + // So clear the window-local value. + if (!(opt_flags & OPT_GLOBAL)) + clear_string_option(&curwin->w_p_lcs); + FOR_ALL_TAB_WINDOWS(tp, wp) + { + errmsg = set_chars_option(wp, &wp->w_p_lcs); + if (errmsg) + break; + } + redraw_all_later(NOT_VALID); + } } + // local 'listchars' + else if (varp == &curwin->w_p_lcs) + errmsg = set_chars_option(curwin, varp); + // 'fillchars' else if (varp == &p_fcs) { - errmsg = set_chars_option(varp); + errmsg = set_chars_option(curwin, varp); } #ifdef FEAT_CMDWIN diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro index ce160d7de5..144dc7cd8b 100644 --- a/src/proto/evalvars.pro +++ b/src/proto/evalvars.pro @@ -60,7 +60,7 @@ void check_vars(char_u *name, int len); dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload); dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload); hashtab_T *get_script_local_ht(void); -int lookup_scriptvar(char_u *name, size_t len, void *lvar, cctx_T *dummy); +int lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy); hashtab_T *find_var_ht(char_u *name, char_u **varname); char_u *get_var_value(char_u *name); void new_script_vars(scid_T id); diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index 91e3871303..a05e897922 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -13,9 +13,10 @@ void undo_cmdmod(cmdmod_T *cmod); int parse_cmd_address(exarg_T *eap, char **errormsg, int silent); int checkforcmd(char_u **pp, char *cmd, int len); char_u *skip_option_env_lead(char_u *start); -char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, void *, cctx_T *), cctx_T *cctx); +char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, cctx_T *), cctx_T *cctx); int modifier_len(char_u *cmd); int cmd_exists(char_u *name); +void f_fullcommand(typval_T *argvars, typval_T *rettv); cmdidx_T excmd_get_cmdidx(char_u *cmd, int len); long excmd_get_argt(cmdidx_T idx); char_u *skip_range(char_u *cmd, int skip_star, int *ctx); diff --git a/src/proto/screen.pro b/src/proto/screen.pro index 3f475ec12c..1ab40df0c9 100644 --- a/src/proto/screen.pro +++ b/src/proto/screen.pro @@ -55,5 +55,5 @@ void comp_col(void); int number_width(win_T *wp); int screen_screencol(void); int screen_screenrow(void); -char *set_chars_option(char_u **varp); +char *set_chars_option(win_T *wp, char_u **varp); /* vim: set ft=c : */ diff --git a/src/screen.c b/src/screen.c index 7e71d423f7..5081325eef 100644 --- a/src/screen.c +++ b/src/screen.c @@ -272,9 +272,9 @@ fill_foldcolumn( { if (win_foldinfo.fi_lnum == lnum && first_level + i >= win_foldinfo.fi_low_level) - p[i] = '-'; + p[i] = fill_foldopen; else if (first_level == 1) - p[i] = '|'; + p[i] = fill_foldsep; else if (first_level + i <= 9) p[i] = '0' + first_level + i; else @@ -284,7 +284,7 @@ fill_foldcolumn( } } if (closed) - p[i >= fdc ? i - 1 : i] = '+'; + p[i >= fdc ? i - 1 : i] = fill_foldclosed; } #endif // FEAT_FOLDING @@ -4786,10 +4786,11 @@ screen_screenrow(void) /* * Handle setting 'listchars' or 'fillchars'. + * Assume monocell characters. * Returns error message, NULL if it's OK. */ char * -set_chars_option(char_u **varp) +set_chars_option(win_T *wp, char_u **varp) { int round, i, len, entries; char_u *p, *s; @@ -4801,35 +4802,42 @@ set_chars_option(char_u **varp) }; static struct charstab filltab[] = { - {&fill_stl, "stl"}, - {&fill_stlnc, "stlnc"}, - {&fill_vert, "vert"}, - {&fill_fold, "fold"}, - {&fill_diff, "diff"}, - {&fill_eob, "eob"}, + {&fill_stl, "stl"}, + {&fill_stlnc, "stlnc"}, + {&fill_vert, "vert"}, + {&fill_fold, "fold"}, + {&fill_foldopen, "foldopen"}, + {&fill_foldclosed, "foldclose"}, + {&fill_foldsep, "foldsep"}, + {&fill_diff, "diff"}, + {&fill_eob, "eob"}, }; - static struct charstab lcstab[] = + static lcs_chars_T lcs_chars; + struct charstab lcstab[] = { - {&lcs_eol, "eol"}, - {&lcs_ext, "extends"}, - {&lcs_nbsp, "nbsp"}, - {&lcs_prec, "precedes"}, - {&lcs_space, "space"}, - {&lcs_tab2, "tab"}, - {&lcs_trail, "trail"}, - {&lcs_lead, "lead"}, + {&lcs_chars.eol, "eol"}, + {&lcs_chars.ext, "extends"}, + {&lcs_chars.nbsp, "nbsp"}, + {&lcs_chars.prec, "precedes"}, + {&lcs_chars.space, "space"}, + {&lcs_chars.tab2, "tab"}, + {&lcs_chars.trail, "trail"}, + {&lcs_chars.lead, "lead"}, #ifdef FEAT_CONCEAL - {&lcs_conceal, "conceal"}, + {&lcs_chars.conceal, "conceal"}, #else - {NULL, "conceal"}, + {NULL, "conceal"}, #endif }; struct charstab *tab; - if (varp == &p_lcs) + if (varp == &p_lcs || varp == &wp->w_p_lcs) { tab = lcstab; + CLEAR_FIELD(lcs_chars); entries = sizeof(lcstab) / sizeof(struct charstab); + if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) + varp = &p_lcs; } else { @@ -4846,16 +4854,20 @@ set_chars_option(char_u **varp) // 'fillchars', NUL for 'listchars' for (i = 0; i < entries; ++i) if (tab[i].cp != NULL) - *(tab[i].cp) = (varp == &p_lcs ? NUL : ' '); + *(tab[i].cp) = + ((varp == &p_lcs || varp == &wp->w_p_lcs) ? NUL : ' '); - if (varp == &p_lcs) + if (varp == &p_lcs || varp == &wp->w_p_lcs) { - lcs_tab1 = NUL; - lcs_tab3 = NUL; + lcs_chars.tab1 = NUL; + lcs_chars.tab3 = NUL; } else { fill_diff = '-'; + fill_foldopen = '-'; + fill_foldclosed = '+'; + fill_foldsep = '|'; fill_eob = '~'; } } @@ -4874,7 +4886,7 @@ set_chars_option(char_u **varp) c1 = mb_ptr2char_adv(&s); if (mb_char2cells(c1) > 1) continue; - if (tab[i].cp == &lcs_tab2) + if (tab[i].cp == &lcs_chars.tab2) { if (*s == NUL) continue; @@ -4893,11 +4905,11 @@ set_chars_option(char_u **varp) { if (round) { - if (tab[i].cp == &lcs_tab2) + if (tab[i].cp == &lcs_chars.tab2) { - lcs_tab1 = c1; - lcs_tab2 = c2; - lcs_tab3 = c3; + lcs_chars.tab1 = c1; + lcs_chars.tab2 = c2; + lcs_chars.tab3 = c3; } else if (tab[i].cp != NULL) *(tab[i].cp) = c1; @@ -4915,6 +4927,8 @@ set_chars_option(char_u **varp) ++p; } } + if (tab == lcstab) + wp->w_lcs_chars = lcs_chars; return NULL; // no error } diff --git a/src/structs.h b/src/structs.h index b379c7cd2b..e831a9c859 100644 --- a/src/structs.h +++ b/src/structs.h @@ -225,6 +225,8 @@ typedef struct #endif int wo_list; #define w_p_list w_onebuf_opt.wo_list // 'list' + char_u *wo_lcs; +#define w_p_lcs w_onebuf_opt.wo_lcs // 'listchars' int wo_nu; #define w_p_nu w_onebuf_opt.wo_nu // 'number' int wo_rnu; @@ -642,6 +644,7 @@ typedef struct #define CMOD_LOCKMARKS 0x0800 // ":lockmarks" #define CMOD_KEEPPATTERNS 0x1000 // ":keeppatterns" #define CMOD_NOSWAPFILE 0x2000 // ":noswapfile" +#define CMOD_VIM9CMD 0x4000 // ":vim9cmd" int cmod_split; // flags for win_split() int cmod_tab; // > 0 when ":tab" was used @@ -3343,6 +3346,26 @@ typedef struct { } winbar_item_T; #endif +/* + * Characters from the 'listchars' option + */ +typedef struct +{ + int eol; + int ext; + int prec; + int nbsp; + int space; + int tab1; + int tab2; + int tab3; + int trail; + int lead; +#ifdef FEAT_CONCEAL + int conceal; +#endif +} lcs_chars_T; + /* * Structure which contains all information that belongs to a window * @@ -3391,6 +3414,8 @@ struct window_S colnr_T w_old_visual_col; // last known start of visual part colnr_T w_old_curswant; // last known value of Curswant + lcs_chars_T w_lcs_chars; // 'listchars' characters + /* * "w_topline", "w_leftcol" and "w_skipcol" specify the offsets for * displaying the buffer. diff --git a/src/testdir/dumps/Test_wildmenu_1.dump b/src/testdir/dumps/Test_wildmenu_1.dump index a118969584..76b930dfde 100644 --- a/src/testdir/dumps/Test_wildmenu_1.dump +++ b/src/testdir/dumps/Test_wildmenu_1.dump @@ -4,5 +4,5 @@ |~| @73 |~| @73 |~| @73 -|v+0#0000001#ffff4012|i|m|9|s|c|r|i|p|t| +3#0000000#ffffff0@1|v|i|m|g|r|e|p| @1|v|i|m|g|r|e|p|a|d@1| @43 -|:+0&&|v|i|m|9|s|c|r|i|p|t> @63 +|v+0#0000001#ffff4012|i|m|9|c|m|d| +3#0000000#ffffff0@1|v|i|m|9|s|c|r|i|p|t| @1|v|i|m|g|r|e|p| @1|v|i|m|g|r|e|p|a|d@1| @34 +|:+0&&|v|i|m|9|c|m|d> @66 diff --git a/src/testdir/dumps/Test_wildmenu_2.dump b/src/testdir/dumps/Test_wildmenu_2.dump index 46b41ae075..17b6b02487 100644 --- a/src/testdir/dumps/Test_wildmenu_2.dump +++ b/src/testdir/dumps/Test_wildmenu_2.dump @@ -4,5 +4,5 @@ |~| @73 |~| @73 |~| @73 -|v+3#0000000&|i|m|9|s|c|r|i|p|t| @1|v+0#0000001#ffff4012|i|m|g|r|e|p| +3#0000000#ffffff0@1|v|i|m|g|r|e|p|a|d@1| @43 -|:+0&&|v|i|m|g|r|e|p> @66 +|v+3#0000000&|i|m|9|c|m|d| @1|v+0#0000001#ffff4012|i|m|9|s|c|r|i|p|t| +3#0000000#ffffff0@1|v|i|m|g|r|e|p| @1|v|i|m|g|r|e|p|a|d@1| @34 +|:+0&&|v|i|m|9|s|c|r|i|p|t> @63 diff --git a/src/testdir/dumps/Test_wildmenu_3.dump b/src/testdir/dumps/Test_wildmenu_3.dump index 44749367df..578c8f05b7 100644 --- a/src/testdir/dumps/Test_wildmenu_3.dump +++ b/src/testdir/dumps/Test_wildmenu_3.dump @@ -4,5 +4,5 @@ |~| @73 |~| @73 |~| @73 -|v+3#0000000&|i|m|9|s|c|r|i|p|t| @1|v|i|m|g|r|e|p| @1|v+0#0000001#ffff4012|i|m|g|r|e|p|a|d@1| +3#0000000#ffffff0@43 -|:+0&&|v|i|m|g|r|e|p|a|d@1> @63 +|v+3#0000000&|i|m|9|c|m|d| @1|v|i|m|9|s|c|r|i|p|t| @1|v+0#0000001#ffff4012|i|m|g|r|e|p| +3#0000000#ffffff0@1|v|i|m|g|r|e|p|a|d@1| @34 +|:+0&&|v|i|m|g|r|e|p> @66 diff --git a/src/testdir/dumps/Test_wildmenu_4.dump b/src/testdir/dumps/Test_wildmenu_4.dump index 3703fd5292..4b16a3768c 100644 --- a/src/testdir/dumps/Test_wildmenu_4.dump +++ b/src/testdir/dumps/Test_wildmenu_4.dump @@ -4,5 +4,5 @@ |~| @73 |~| @73 |~| @73 -|v+3#0000000&|i|m|9|s|c|r|i|p|t| @1|v|i|m|g|r|e|p| @1|v|i|m|g|r|e|p|a|d@1| @43 +|v+3#0000000&|i|m|9|c|m|d| @1|v|i|m|9|s|c|r|i|p|t| @1|v|i|m|g|r|e|p| @1|v|i|m|g|r|e|p|a|d@1| @34 |:+0&&|v|i|m> @70 diff --git a/src/testdir/term_util.vim b/src/testdir/term_util.vim index cfc850ba00..8541ef353b 100644 --- a/src/testdir/term_util.vim +++ b/src/testdir/term_util.vim @@ -179,5 +179,9 @@ func Run_shell_in_terminal(options) return buf endfunc +" Return concatenated lines in terminal. +func Term_getlines(buf, lines) + return join(map(a:lines, 'term_getline(a:buf, v:val)'), '') +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 8faa25fe8a..05d90f74d1 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -119,7 +119,7 @@ func Test_wildmenu_screendump() call term_sendkeys(buf, "\") call VerifyScreenDump(buf, 'Test_wildmenu_3', {}) - call term_sendkeys(buf, "\") + call term_sendkeys(buf, "\\") call VerifyScreenDump(buf, 'Test_wildmenu_4', {}) call term_sendkeys(buf, "\") diff --git a/src/testdir/test_display.vim b/src/testdir/test_display.vim index 5bf9e5eac8..4616da5653 100644 --- a/src/testdir/test_display.vim +++ b/src/testdir/test_display.vim @@ -279,4 +279,58 @@ func Test_eob_fillchars() close endfunc +" Test for 'foldopen', 'foldclose' and 'foldsep' in 'fillchars' +func Test_fold_fillchars() + new + set fdc=2 foldenable foldmethod=manual + call setline(1, ['one', 'two', 'three', 'four', 'five']) + 2,4fold + " First check for the default setting for a closed fold + let lines = ScreenLines([1, 3], 8) + let expected = [ + \ ' one ', + \ '+ +-- 3', + \ ' five ' + \ ] + call assert_equal(expected, lines) + normal 2Gzo + " check the characters for an open fold + let lines = ScreenLines([1, 5], 8) + let expected = [ + \ ' one ', + \ '- two ', + \ '| three ', + \ '| four ', + \ ' five ' + \ ] + call assert_equal(expected, lines) + + " change the setting + set fillchars=vert:\|,fold:-,eob:~,foldopen:[,foldclose:],foldsep:- + + " check the characters for an open fold + let lines = ScreenLines([1, 5], 8) + let expected = [ + \ ' one ', + \ '[ two ', + \ '- three ', + \ '- four ', + \ ' five ' + \ ] + call assert_equal(expected, lines) + + " check the characters for a closed fold + normal 2Gzc + let lines = ScreenLines([1, 3], 8) + let expected = [ + \ ' one ', + \ '] +-- 3', + \ ' five ' + \ ] + call assert_equal(expected, lines) + + %bw! + set fillchars& fdc& foldmethod& foldenable& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index 4104ec2b32..ba8879c82d 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -79,6 +79,7 @@ let s:filename_checks = { \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'], \ 'bc': ['file.bc'], \ 'bdf': ['file.bdf'], + \ 'beancount': ['file.beancount'], \ 'bib': ['file.bib'], \ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'], \ 'blank': ['file.bl'], @@ -426,6 +427,7 @@ let s:filename_checks = { \ 'sdc': ['file.sdc'], \ 'sdl': ['file.sdl', 'file.pr'], \ 'sed': ['file.sed'], + \ 'svelte': ['file.svelte'], \ 'sensors': ['/etc/sensors.conf', '/etc/sensors3.conf', 'any/etc/sensors.conf', 'any/etc/sensors3.conf'], \ 'services': ['/etc/services', 'any/etc/services'], \ 'setserial': ['/etc/serial.conf', 'any/etc/serial.conf'], diff --git a/src/testdir/test_listchars.vim b/src/testdir/test_listchars.vim index 69c98b9269..172407a8da 100644 --- a/src/testdir/test_listchars.vim +++ b/src/testdir/test_listchars.vim @@ -234,4 +234,130 @@ func Test_listchars_composing() set listchars& ff& endfunction +" Check for the value of the 'listchars' option +func s:CheckListCharsValue(expected) + call assert_equal(a:expected, &listchars) + call assert_equal(a:expected, getwinvar(0, '&listchars')) +endfunc + +" Test for using a window local value for 'listchars' +func Test_listchars_window_local() + %bw! + set list listchars& + new + " set a local value for 'listchars' + setlocal listchars=tab:+-,eol:# + call s:CheckListCharsValue('tab:+-,eol:#') + " When local value is reset, global value should be used + setlocal listchars= + call s:CheckListCharsValue('eol:$') + " Use 'setlocal <' to copy global value + setlocal listchars=space:.,extends:> + setlocal listchars< + call s:CheckListCharsValue('eol:$') + " Use 'set <' to copy global value + setlocal listchars=space:.,extends:> + set listchars< + call s:CheckListCharsValue('eol:$') + " Changing global setting should not change the local setting + setlocal listchars=space:.,extends:> + setglobal listchars=tab:+-,eol:# + call s:CheckListCharsValue('space:.,extends:>') + " when split opening a new window, local value should be copied + split + call s:CheckListCharsValue('space:.,extends:>') + " clearing local value in one window should not change the other window + set listchars& + call s:CheckListCharsValue('eol:$') + close + call s:CheckListCharsValue('space:.,extends:>') + + " use different values for 'listchars' items in two different windows + call setline(1, ["\t one two "]) + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + split + setlocal listchars=tab:[.],lead:#,space:_,trail:.,eol:& + split + set listchars=tab:+-+,lead:^,space:>,trail:<,eol:% + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + " changing the global setting should not change the local value + setglobal listchars=tab:[.],lead:#,space:_,trail:.,eol:& + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + set listchars< + call assert_equal(['[......]##one__two..&'], ScreenLines(1, virtcol('$'))) + + " Using setglobal in a window with local setting should not affect the + " window. But should impact other windows using the global setting. + enew! | only + call setline(1, ["\t one two "]) + set listchars=tab:[.],lead:#,space:_,trail:.,eol:& + split + setlocal listchars=tab:+-+,lead:^,space:>,trail:<,eol:% + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + setglobal listchars=tab:{.},lead:-,space:=,trail:#,eol:$ + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$'))) + + " Setting the global setting to the default value should not impact a window + " using a local setting + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + setglobal listchars&vim + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['^I one two $'], ScreenLines(1, virtcol('$'))) + + " Setting the local setting to the default value should not impact a window + " using a global setting + set listchars=tab:{.},lead:-,space:=,trail:#,eol:$ + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + setlocal listchars&vim + call assert_equal(['^I one two $'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['{......}--one==two##$'], ScreenLines(1, virtcol('$'))) + + " Using set in a window with a local setting should change it to use the + " global setting and also impact other windows using the global setting + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + set listchars=tab:+-+,lead:^,space:>,trail:<,eol:% + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + + " Setting invalid value for a local setting should not impact the local and + " global settings + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + let cmd = 'setlocal listchars=tab:{.},lead:-,space:=,trail:#,eol:$,x' + call assert_fails(cmd, 'E474:') + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + + " Setting invalid value for a global setting should not impact the local and + " global settings + split + setlocal listchars=tab:<->,lead:_,space:.,trail:@,eol:# + let cmd = 'setglobal listchars=tab:{.},lead:-,space:=,trail:#,eol:$,x' + call assert_fails(cmd, 'E474:') + call assert_equal(['<------>__one..two@@#'], ScreenLines(1, virtcol('$'))) + close + call assert_equal(['+------+^^one>>two<<%'], ScreenLines(1, virtcol('$'))) + + %bw! + set list& listchars& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_listlbr.vim b/src/testdir/test_listlbr.vim index 37bc44bb69..24bd25679a 100644 --- a/src/testdir/test_listlbr.vim +++ b/src/testdir/test_listlbr.vim @@ -43,6 +43,7 @@ func Test_set_linebreak() endfunc func Test_linebreak_with_list() + set listchars= call s:test_windows('setl ts=4 sbr=+ list listchars=') call setline(1, "\tabcdef hijklmn\tpqrstuvwxyz_1060ABCDEFGHIJKLMNOP ") let lines = s:screen_lines([1, 4], winwidth(0)) @@ -54,6 +55,7 @@ func Test_linebreak_with_list() \ ] call s:compare_lines(expect, lines) call s:close_windows() + set listchars&vim endfunc func Test_linebreak_with_nolist() diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 6826acfd05..6ade326226 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -709,7 +709,7 @@ def Test_helpgrep_vim9_restore_cpo() var dir = 'Xruntime/after' &rtp ..= ',' .. dir mkdir(dir .. '/ftplugin', 'p') - writefile(['vim9'], dir .. '/ftplugin/qf.vim') + writefile(['vim9script'], dir .. '/ftplugin/qf.vim') filetype plugin on silent helpgrep grail cwindow diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index 7599df2c54..392a091a1a 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -1108,6 +1108,8 @@ def Test_assign_lambda() assert_equal(123, FuncRef_Func()) var FuncRef_Any: any = () => 123 assert_equal(123, FuncRef_Any()) + var FuncRef_Number: func(): number = () => 321 + assert_equal(321, FuncRef_Number()) END CheckScriptSuccess(lines) @@ -1115,8 +1117,12 @@ def Test_assign_lambda() var Ref: func(number) Ref = (j) => !j END - CheckDefFailure(lines, 'E1012: Type mismatch; expected func(number) but got func(any): bool') - CheckScriptFailure(['vim9script'] + lines, 'E1012: Type mismatch; expected func(number) but got func(any): any') + CheckDefAndScriptFailure(lines, 'E1012: Type mismatch; expected func(number) but got func(any): bool') + + lines =<< trim END + echo filter([1, 2, 3], (_, v: string) => v + 1) + END + CheckDefAndScriptFailure(lines, 'E1051:') enddef def Test_heredoc() diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index ef0a5fe2e8..9a0460bdeb 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -5,6 +5,16 @@ source vim9.vim source term_util.vim source view_util.vim +def Test_vim9cmd() + var lines =<< trim END + vim9cmd var x = 123 + let s:y = 'yes' + vim9c assert_equal(123, x) + vim9cm assert_equal('yes', y) + END + CheckScriptSuccess(lines) +enddef + def Test_edit_wildcards() var filename = 'Xtest' edit `=filename` @@ -313,6 +323,11 @@ def Test_for_linebreak() CheckScriptSuccess(lines) enddef +def MethodAfterLinebreak(arg: string) + arg + ->setline(1) +enddef + def Test_method_call_linebreak() var lines =<< trim END vim9script @@ -351,6 +366,11 @@ def Test_method_call_linebreak() g:shortlist = [1, 2] CheckDefAndScriptSuccess(lines) unlet g:shortlist + + new + MethodAfterLinebreak('foobar') + assert_equal('foobar', getline(1)) + bwipe! enddef def Test_method_call_whitespace() diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 4bcd974e50..c24d32f933 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -31,18 +31,8 @@ def TestCompilingError() call writefile(lines, 'XTest_compile_error') var buf = RunVimInTerminal('-S XTest_compile_error', {rows: 10, wait_for_ruler: 0}) - var text = '' - for loop in range(100) - text = '' - for i in range(1, 9) - text ..= term_getline(buf, i) - endfor - if text =~ 'Variable not found: nothing' - break - endif - sleep 20m - endfor - assert_match('Error detected while compiling command line.*Fails.*Variable not found: nothing', text) + call WaitForAssert(() => assert_match('Error detected while compiling command line.*Fails.*Variable not found: nothing', + Term_getlines(buf, range(1, 9)))) # clean up call StopVimInTerminal(buf) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 85eea13fdd..f444bb5a8d 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -22,6 +22,17 @@ def Test_range_only() :3 list assert_equal('three$', Screenline(&lines)) + + # missing command does not print the line + var lines =<< trim END + vim9script + :1| + assert_equal('three$', Screenline(&lines)) + :| + assert_equal('three$', Screenline(&lines)) + END + CheckScriptSuccess(lines) + bwipe! # won't generate anything @@ -724,6 +735,27 @@ def Test_try_catch_fails() CheckDefFailure(['throw xxx'], 'E1001:') enddef +def Try_catch_skipped() + var l = [] + try + finally + endtry + + if 1 + else + try + endtry + endif +enddef + +" The skipped try/endtry was updating the wrong instruction. +def Test_try_catch_skipped() + var instr = execute('disassemble Try_catch_skipped') + assert_match("NEWLIST size 0\n", instr) +enddef + + + def Test_throw_vimscript() # only checks line continuation var lines =<< trim END @@ -755,7 +787,7 @@ def Test_throw_vimscript() enddef def Test_error_in_nested_function() - # an error in a nested :function aborts executin in the calling :def function + # an error in a nested :function aborts executing in the calling :def function var lines =<< trim END vim9script def Func() @@ -1230,6 +1262,27 @@ def Test_use_import_in_mapping() nunmap enddef +def Test_vim9script_mix() + var lines =<< trim END + if has(g:feature) + " legacy script + let g:legacy = 1 + finish + endif + vim9script + g:legacy = 0 + END + g:feature = 'eval' + g:legacy = -1 + CheckScriptSuccess(lines) + assert_equal(1, g:legacy) + + g:feature = 'noteval' + g:legacy = -1 + CheckScriptSuccess(lines) + assert_equal(0, g:legacy) +enddef + def Test_vim9script_fails() CheckScriptFailure(['scriptversion 2', 'vim9script'], 'E1039:') CheckScriptFailure(['vim9script', 'scriptversion 2'], 'E1040:') diff --git a/src/version.c b/src/version.c index f209b7de88..769537cb09 100644 --- a/src/version.c +++ b/src/version.c @@ -765,6 +765,44 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2529, +/**/ + 2528, +/**/ + 2527, +/**/ + 2526, +/**/ + 2525, +/**/ + 2524, +/**/ + 2523, +/**/ + 2522, +/**/ + 2521, +/**/ + 2520, +/**/ + 2519, +/**/ + 2518, +/**/ + 2517, +/**/ + 2516, +/**/ + 2515, +/**/ + 2514, +/**/ + 2513, +/**/ + 2512, +/**/ + 2511, /**/ 2510, /**/ diff --git a/src/vim.h b/src/vim.h index c52f11121c..817e277860 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1796,6 +1796,12 @@ typedef struct timeval proftime_T; typedef int proftime_T; // dummy for function prototypes #endif +#ifdef FEAT_PROFILE +# define PROFILING(ufunc) (do_profiling == PROF_YES && (ufunc)->uf_profiling) +#else +# define PROFILING(ufunc) FALSE +#endif + /* * When compiling with 32 bit Perl time_t is 32 bits in the Perl code but 64 * bits elsewhere. That causes memory corruption. Define time_T and use it diff --git a/src/vim9.h b/src/vim9.h index c2a3916fd7..1cf4b3c659 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -418,11 +418,9 @@ extern garray_T def_functions; #define LNUM_VARIABLE_RANGE_ABOVE -888 #ifdef FEAT_PROFILE -# define PROFILING(ufunc) (do_profiling == PROF_YES && (ufunc)->uf_profiling) # define INSTRUCTIONS(dfunc) \ ((do_profiling == PROF_YES && (dfunc->df_ufunc)->uf_profiling) \ ? (dfunc)->df_instr_prof : (dfunc)->df_instr) #else -# define PROFILING(ufunc) FALSE # define INSTRUCTIONS(dfunc) ((dfunc)->df_instr) #endif diff --git a/src/vim9compile.c b/src/vim9compile.c index 5742123c06..84c9108cac 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -372,6 +372,19 @@ script_var_exists(char_u *name, size_t len, int vim9script, cctx_T *cctx) return FAIL; } +/* + * Return TRUE if "name" is a local variable, argument, script variable or + * imported. + */ + static int +variable_exists(char_u *name, size_t len, cctx_T *cctx) +{ + return lookup_local(name, len, NULL, cctx) == OK + || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK + || script_var_exists(name, len, FALSE, cctx) == OK + || find_imported(name, len, cctx) != NULL; +} + /* * Check if "p[len]" is already defined, either in script "import_sid" or in * compilation context "cctx". "cctx" is NULL at the script level. @@ -6444,10 +6457,7 @@ may_compile_assignment(exarg_T *eap, char_u **line, cctx_T *cctx) || *eap->cmd == '$' || *eap->cmd == '@' || ((len) > 2 && eap->cmd[1] == ':') - || lookup_local(eap->cmd, len, NULL, cctx) == OK - || arg_exists(eap->cmd, len, NULL, NULL, NULL, cctx) == OK - || script_var_exists(eap->cmd, len, FALSE, cctx) == OK - || find_imported(eap->cmd, len, cctx) != NULL) + || variable_exists(eap->cmd, len, cctx)) { *line = compile_assignment(eap->cmd, eap, CMD_SIZE, cctx); if (*line == NULL || *line == eap->cmd) @@ -7719,17 +7729,21 @@ compile_endtry(char_u *arg, cctx_T *cctx) compile_endblock(cctx); - if (try_isn->isn_arg.try.try_finally == 0) - // No :finally encountered, use the try_finaly field to point to - // ENDTRY, so that TRYCONT can jump there. - try_isn->isn_arg.try.try_finally = cctx->ctx_instr.ga_len; + if (cctx->ctx_skip != SKIP_YES) + { + if (try_isn->isn_arg.try.try_finally == 0) + // No :finally encountered, use the try_finaly field to point to + // ENDTRY, so that TRYCONT can jump there. + try_isn->isn_arg.try.try_finally = instr->ga_len; - if (cctx->ctx_skip != SKIP_YES && generate_instr(cctx, ISN_ENDTRY) == NULL) - return NULL; + if (cctx->ctx_skip != SKIP_YES + && generate_instr(cctx, ISN_ENDTRY) == NULL) + return NULL; #ifdef FEAT_PROFILE if (cctx->ctx_profiling) generate_instr(cctx, ISN_PROF_START); #endif + } return arg; } @@ -8328,7 +8342,7 @@ compile_def_function( } } p = find_ex_command(&ea, NULL, starts_with_colon ? NULL - : (int (*)(char_u *, size_t, void *, cctx_T *))lookup_local, + : (int (*)(char_u *, size_t, cctx_T *))variable_exists, &cctx); if (p == NULL) diff --git a/src/vim9script.c b/src/vim9script.c index fea478592d..d40104cb7a 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -23,7 +23,8 @@ in_vim9script(void) // Do not go up the stack, a ":function" inside vim9script uses legacy // syntax. "sc_version" is also set when compiling a ":def" function in // legacy script. - return current_sctx.sc_version == SCRIPT_VERSION_VIM9; + return current_sctx.sc_version == SCRIPT_VERSION_VIM9 + || (cmdmod.cmod_flags & CMOD_VIM9CMD); } /*