# HG changeset patch # User Bram Moolenaar # Date 1609185604 -3600 # Node ID 517fca70e0849a989d9c958126dd8783a7cc4fb5 # Parent 3366c49544bc937e5519e5687181434945a91099 patch 8.2.2239: Vim9: concatenating lines with backslash is inconvenient Commit: https://github.com/vim/vim/commit/dcc58e031ded8b846a39146112b9b075cbb977d9 Author: Bram Moolenaar Date: Mon Dec 28 20:53:21 2020 +0100 patch 8.2.2239: Vim9: concatenating lines with backslash is inconvenient Problem: Vim9: concatenating lines with backslash is inconvenient. Solution: Support concatenating lines starting with '|', useful for :autocmd, :command, etc. (closes #6702) diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -6,7 +6,7 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE -Vim9 script commands and expressions. *Vim9* +Vim9 script commands and expressions. *Vim9* *vim9* Most expression help is in |eval.txt|. This file is about the new syntax and features in Vim9 script. @@ -113,11 +113,12 @@ In Vi # is a command to list text with n To improve readability there must be a space between a command and the # that starts a comment: > - var = value # comment - var = value# error! + var name = value # comment + var name = value# error! -In legacy script # is also used for the alternate file name. In Vim9 script -you need to use %% instead. Instead of ## use %%% (stands for all arguments). +In legacy Vim script # is also used for the alternate file name. In Vim9 +script you need to use %% instead. Instead of ## use %%% (stands for all +arguments). Vim9 functions ~ @@ -209,13 +210,13 @@ if you are developing a plugin and want something you don't have to worry about the old name still hanging around. If you do want to keep items, use: > - vimscript noclear + vim9script noclear You want to use this in scripts that use a `finish` command to bail out at some point when loaded again. E.g. when a buffer local option is set: > - vimscript noclear + vim9script noclear setlocal completefunc=SomeFunc - if exists('*SomeFunc') | finish | endif + if exists('*g:SomeFunc') | finish | endif def g:SomeFunc() .... @@ -385,9 +386,13 @@ No line break is allowed in the argument This does not work: > filter(list, (k, v) => v > 0) -This also does not work: +This also does not work: > filter(list, (k, v) => v > 0) +But you can use a backslash to concatenate the lines before parsing: > + filter(list, (k, + \ v) + \ => v > 0) Additionally, a lambda can contain statements in {}: > var Lambda = (arg) => { @@ -404,8 +409,8 @@ wrap it in parenthesis: > Automatic line continuation ~ In many cases it is obvious that an expression continues on the next line. In -those cases there is no need to prefix the line with a backslash -|line-continuation|. For example, when a list spans multiple lines: > +those cases there is no need to prefix the line with a backslash (see +|line-continuation|). For example, when a list spans multiple lines: > var mylist = [ 'one', 'two', @@ -442,6 +447,12 @@ before it: > var result = MyDict .member +For commands that have an argument that is a list of commands, the | character +at the start of the line indicates line continuation: > + autocmd BufNewFile *.match if condition + | echo 'match' + | endif + < *E1050* To make it possible for the operator at the start of the line to be recognized, it is required to put a colon before a range. This will add @@ -941,7 +952,7 @@ that you don't do that. Namespace ~ - *:vim9script* *:vim9* + *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 diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -5,7 +5,6 @@ int use_typecheck(type_T *actual, type_T int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx); imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx); imported_T *find_imported_in_script(char_u *name, size_t len, int sid); -int vim9_comment_start(char_u *p); char_u *peek_next_line_from_context(cctx_T *cctx); char_u *next_line_from_context(cctx_T *cctx, int skip_comment); char_u *to_name_end(char_u *arg, int use_namespace); @@ -15,7 +14,7 @@ void error_white_both(char_u *op, int le int assignment_len(char_u *p, int *heredoc); void vim9_declare_error(char_u *name); int check_vim9_unlet(char_u *name); -int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx); +int compile_def_function(ufunc_T *ufunc, int check_return_type, cctx_T *outer_cctx); void set_function_type(ufunc_T *ufunc); void delete_instr(isn_T *isn); void unlink_def_function(ufunc_T *ufunc); diff --git a/src/proto/vim9script.pro b/src/proto/vim9script.pro --- a/src/proto/vim9script.pro +++ b/src/proto/vim9script.pro @@ -2,6 +2,7 @@ int in_vim9script(void); void ex_vim9script(exarg_T *eap); int not_in_vim9(exarg_T *eap); +int vim9_comment_start(char_u *p); void ex_export(exarg_T *eap); void free_imports_and_script_vars(int sid); void mark_imports_for_reload(int sid); diff --git a/src/scriptfile.c b/src/scriptfile.c --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1739,6 +1739,10 @@ getsourceline( struct source_cookie *sp = (struct source_cookie *)cookie; char_u *line; char_u *p; + int do_vim9_all = in_vim9script() + && options == GETLINE_CONCAT_ALL; + int do_vim9_cont = do_vim9_all + || options == GETLINE_CONCAT_CONTDEF; #ifdef FEAT_EVAL // If breakpoints have been added/deleted need to check for it. @@ -1785,17 +1789,15 @@ getsourceline( // backslash. We always need to read the next line, keep it in // sp->nextline. /* Also check for a comment in between continuation lines: "\ */ - // Also check for a Vim9 comment and empty line. + // Also check for a Vim9 comment, empty line, line starting with '|', + // but not "||". sp->nextline = get_one_sourceline(sp); if (sp->nextline != NULL && (*(p = skipwhite(sp->nextline)) == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' ') -#ifdef FEAT_EVAL - || (in_vim9script() - && options == GETLINE_CONCAT_ALL - && (*p == NUL || vim9_comment_start(p))) -#endif - )) + || (do_vim9_all && (*p == NUL + || vim9_comment_start(p))) + || (do_vim9_cont && p[0] == '|' && p[1] != '|'))) { garray_T ga; @@ -1803,6 +1805,11 @@ getsourceline( ga_concat(&ga, line); if (*p == '\\') ga_concat(&ga, p + 1); + else if (*p == '|') + { + ga_concat(&ga, (char_u *)" "); + ga_concat(&ga, p); + } for (;;) { vim_free(sp->nextline); @@ -1810,7 +1817,7 @@ getsourceline( if (sp->nextline == NULL) break; p = skipwhite(sp->nextline); - if (*p == '\\') + if (*p == '\\' || (do_vim9_cont && p[0] == '|' && p[1] != '|')) { // Adjust the growsize to the current length to speed up // concatenating many lines. @@ -1821,15 +1828,16 @@ getsourceline( else ga.ga_growsize = ga.ga_len; } - ga_concat(&ga, p + 1); + if (*p == '\\') + ga_concat(&ga, p + 1); + else + { + ga_concat(&ga, (char_u *)" "); + ga_concat(&ga, p); + } } else if (!(p[0] == '"' && p[1] == '\\' && p[2] == ' ') -#ifdef FEAT_EVAL - && !(in_vim9script() - && options == GETLINE_CONCAT_ALL - && (*p == NUL || vim9_comment_start(p))) -#endif - ) + && !(do_vim9_all && (*p == NUL || vim9_comment_start(p)))) break; /* drop a # comment or "\ comment line */ } diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -1565,7 +1565,8 @@ typedef void (*cfunc_free_T)(void *state // type of getline() last argument typedef enum { GETLINE_NONE, // do not concatenate any lines - GETLINE_CONCAT_CONT, // concatenate continuation lines + GETLINE_CONCAT_CONT, // concatenate continuation lines in Vim9 script + GETLINE_CONCAT_CONTDEF, // concatenate continuation lines always GETLINE_CONCAT_ALL // concatenate continuation and Vim9 # comment lines } getline_opt_T; diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -548,13 +548,33 @@ def Test_command_modifier_other() bwipe! au BufNewFile Xfile g:readFile = 1 + | g:readExtra = 2 g:readFile = 0 + g:readExtra = 0 edit Xfile assert_equal(1, g:readFile) + assert_equal(2, g:readExtra) bwipe! g:readFile = 0 noautocmd edit Xfile assert_equal(0, g:readFile) + au! BufNewFile + + au BufNewFile Xfile g:readFile = 1 + | g:readExtra = 2 + | g:readMore = 3 + g:readFile = 0 + g:readExtra = 0 + g:readMore = 0 + edit Xfile + assert_equal(1, g:readFile) + assert_equal(2, g:readExtra) + assert_equal(3, g:readMore) + bwipe! + au! BufNewFile + unlet g:readFile + unlet g:readExtra + unlet g:readMore noswapfile edit XnoSwap assert_equal(0, &l:swapfile) diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2960,7 +2960,7 @@ define_function(exarg_T *eap, char_u *na static int func_nr = 0; // number for nameless function int paren; hashitem_T *hi; - getline_opt_T getline_options = GETLINE_CONCAT_CONT; + getline_opt_T getline_options; linenr_T sourcing_lnum_off; linenr_T sourcing_lnum_top; int is_heredoc = FALSE; @@ -3291,6 +3291,8 @@ define_function(exarg_T *eap, char_u *na indent = 2; nesting = 0; nesting_def[nesting] = (eap->cmdidx == CMD_def); + getline_options = eap->cmdidx == CMD_def + ? GETLINE_CONCAT_CONTDEF : GETLINE_CONCAT_CONT; for (;;) { if (KeyTyped) @@ -3365,7 +3367,8 @@ define_function(exarg_T *eap, char_u *na { VIM_CLEAR(skip_until); VIM_CLEAR(heredoc_trimmed); - getline_options = GETLINE_CONCAT_CONT; + getline_options = eap->cmdidx == CMD_def + ? GETLINE_CONCAT_CONTDEF : GETLINE_CONCAT_CONT; is_heredoc = FALSE; } } diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2239, +/**/ 2238, /**/ 2237, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2165,15 +2165,6 @@ free_imported(cctx_T *cctx) } /* - * Return TRUE if "p" points at a "#". Does not check for white space. - */ - int -vim9_comment_start(char_u *p) -{ - return p[0] == '#'; -} - -/* * Return a pointer to the next line that isn't empty or only contains a * comment. Skips over white space. * Returns NULL if there is none. diff --git a/src/vim9script.c b/src/vim9script.c --- a/src/vim9script.c +++ b/src/vim9script.c @@ -103,6 +103,15 @@ not_in_vim9(exarg_T *eap) return OK; } +/* + * Return TRUE if "p" points at a "#". Does not check for white space. + */ + int +vim9_comment_start(char_u *p) +{ + return p[0] == '#'; +} + #if defined(FEAT_EVAL) || defined(PROTO) /*