changeset 17178:40c4cb095d53 v8.1.1588

patch 8.1.1588: in :let-heredoc line continuation is recognized commit https://github.com/vim/vim/commit/e96a2498f9a2d3e93ac07431f6d4afd77f30afdf Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jun 25 04:12:16 2019 +0200 patch 8.1.1588: in :let-heredoc line continuation is recognized Problem: In :let-heredoc line continuation is recognized. Solution: Do not consume line continuation. (Ozaki Kiichi, closes https://github.com/vim/vim/issues/4580)
author Bram Moolenaar <Bram@vim.org>
date Tue, 25 Jun 2019 04:15:08 +0200
parents b58feb1a84f0
children 9c7fd1b6445b
files src/autocmd.c src/digraph.c src/eval.c src/evalfunc.c src/ex_cmds.c src/ex_cmds.h src/ex_cmds2.c src/ex_docmd.c src/ex_getln.c src/normal.c src/ops.c src/proto/autocmd.pro src/proto/ex_cmds2.pro src/proto/ex_docmd.pro src/proto/ex_getln.pro src/proto/userfunc.pro src/testdir/test_let.vim src/testdir/test_startup.vim src/userfunc.c src/version.c
diffstat 20 files changed, 70 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -2329,7 +2329,7 @@ auto_next_pat(
  * Returns allocated string, or NULL for end of autocommands.
  */
     char_u *
-getnextac(int c UNUSED, void *cookie, int indent UNUSED)
+getnextac(int c UNUSED, void *cookie, int indent UNUSED, int do_concat UNUSED)
 {
     AutoPatCmd	    *acp = (AutoPatCmd *)cookie;
     char_u	    *retval;
--- a/src/digraph.c
+++ b/src/digraph.c
@@ -2378,7 +2378,7 @@ ex_loadkeymap(exarg_T *eap)
      */
     for (;;)
     {
-	line = eap->getline(0, eap->cookie, 0);
+	line = eap->getline(0, eap->cookie, 0, TRUE);
 	if (line == NULL)
 	    break;
 
--- a/src/eval.c
+++ b/src/eval.c
@@ -1307,7 +1307,7 @@ heredoc_get(exarg_T *eap, char_u *cmd)
 	int	mi = 0;
 	int	ti = 0;
 
-	theline = eap->getline(NUL, eap->cookie, 0);
+	theline = eap->getline(NUL, eap->cookie, 0, FALSE);
 	if (theline == NULL)
 	{
 	    semsg(_("E990: Missing end marker '%s'"), marker);
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -3234,7 +3234,8 @@ execute_redir_str(char_u *value, int val
 get_list_line(
     int	    c UNUSED,
     void    *cookie,
-    int	    indent UNUSED)
+    int	    indent UNUSED,
+    int	    do_concat UNUSED)
 {
     listitem_T **p = (listitem_T **)cookie;
     listitem_T *item = *p;
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -4540,7 +4540,7 @@ ex_append(exarg_T *eap)
 #ifdef FEAT_EVAL
 		    eap->cstack->cs_looplevel > 0 ? -1 :
 #endif
-		    NUL, eap->cookie, indent);
+		    NUL, eap->cookie, indent, TRUE);
 	    State = save_State;
 	}
 	lines_left = Rows - 1;
@@ -5388,7 +5388,7 @@ do_sub(exarg_T *eap)
 			    for ( ; i <= (long)ec; ++i)
 				msg_putchar('^');
 
-			    resp = getexmodeline('?', NULL, 0);
+			    resp = getexmodeline('?', NULL, 0, TRUE);
 			    if (resp != NULL)
 			    {
 				typed = *resp;
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1837,7 +1837,7 @@ struct exarg
     int		bad_char;	/* BAD_KEEP, BAD_DROP or replacement byte */
     int		useridx;	/* user command index */
     char	*errmsg;	/* returned error message */
-    char_u	*(*getline)(int, void *, int);
+    char_u	*(*getline)(int, void *, int, int);
     void	*cookie;	/* argument for getline() */
 #ifdef FEAT_EVAL
     struct condstack *cstack;	/* condition stack for ":if" etc. */
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -371,6 +371,7 @@ check_due_timer(void)
 	    int	save_trylevel = trylevel;
 	    int save_did_throw = did_throw;
 	    int save_ex_pressedreturn = get_pressedreturn();
+	    int save_may_garbage_collect = may_garbage_collect;
 	    except_T *save_current_exception = current_exception;
 	    vimvars_save_T vvsave;
 
@@ -385,7 +386,9 @@ check_due_timer(void)
 	    trylevel = 0;
 	    did_throw = FALSE;
 	    current_exception = NULL;
+	    may_garbage_collect = FALSE;
 	    save_vimvars(&vvsave);
+
 	    timer->tr_firing = TRUE;
 	    timer_callback(timer);
 	    timer->tr_firing = FALSE;
@@ -407,6 +410,7 @@ check_due_timer(void)
 	    must_redraw = must_redraw > save_must_redraw
 					      ? must_redraw : save_must_redraw;
 	    set_pressedreturn(save_ex_pressedreturn);
+	    may_garbage_collect = save_may_garbage_collect;
 
 	    /* Only fire the timer again if it repeats and stop_timer() wasn't
 	     * called while inside the callback (tr_id == -1). */
@@ -3611,7 +3615,7 @@ do_source(
     cookie.conv.vc_type = CONV_NONE;		/* no conversion */
 
     /* Read the first line so we can check for a UTF-8 BOM. */
-    firstline = getsourceline(0, (void *)&cookie, 0);
+    firstline = getsourceline(0, (void *)&cookie, 0, TRUE);
     if (firstline != NULL && STRLEN(firstline) >= 3 && firstline[0] == 0xef
 			      && firstline[1] == 0xbb && firstline[2] == 0xbf)
     {
@@ -3794,7 +3798,7 @@ free_scriptnames(void)
  * Return NULL for end-of-file or some error.
  */
     char_u *
-getsourceline(int c UNUSED, void *cookie, int indent UNUSED)
+getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
 {
     struct source_cookie *sp = (struct source_cookie *)cookie;
     char_u		*line;
@@ -3833,7 +3837,7 @@ getsourceline(int c UNUSED, void *cookie
 
     /* Only concatenate lines starting with a \ when 'cpoptions' doesn't
      * contain the 'C' flag. */
-    if (line != NULL && (vim_strchr(p_cpo, CPO_CONCAT) == NULL))
+    if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL)
     {
 	/* compensate for the one line read-ahead */
 	--sourcing_lnum;
@@ -4212,7 +4216,7 @@ do_finish(exarg_T *eap, int reanimate)
  */
     int
 source_finished(
-    char_u	*(*fgetline)(int, void *, int),
+    char_u	*(*fgetline)(int, void *, int, int),
     void	*cookie)
 {
     return (getline_equal(fgetline, cookie, getsourceline)
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -20,9 +20,9 @@ static int	ex_pressedreturn = FALSE;
 #endif
 
 #ifdef FEAT_EVAL
-static char_u	*do_one_cmd(char_u **, int, struct condstack *, char_u *(*fgetline)(int, void *, int), void *cookie);
+static char_u	*do_one_cmd(char_u **, int, struct condstack *, char_u *(*fgetline)(int, void *, int, int), void *cookie);
 #else
-static char_u	*do_one_cmd(char_u **, int, char_u *(*fgetline)(int, void *, int), void *cookie);
+static char_u	*do_one_cmd(char_u **, int, char_u *(*fgetline)(int, void *, int, int), void *cookie);
 static int	if_level = 0;		/* depth in :if */
 #endif
 static void	free_cmdmod(void);
@@ -431,11 +431,11 @@ struct loop_cookie
     int		current_line;		/* last read line from growarray */
     int		repeating;		/* TRUE when looping a second time */
     /* When "repeating" is FALSE use "getline" and "cookie" to get lines */
-    char_u	*(*getline)(int, void *, int);
+    char_u	*(*getline)(int, void *, int, int);
     void	*cookie;
 };
 
-static char_u	*get_loop_line(int c, void *cookie, int indent);
+static char_u	*get_loop_line(int c, void *cookie, int indent, int do_concat);
 static int	store_loop_line(garray_T *gap, char_u *line);
 static void	free_cmdlines(garray_T *gap);
 
@@ -619,7 +619,7 @@ do_cmdline_cmd(char_u *cmd)
     int
 do_cmdline(
     char_u	*cmdline,
-    char_u	*(*fgetline)(int, void *, int),
+    char_u	*(*fgetline)(int, void *, int, int),
     void	*cookie,		/* argument for fgetline() */
     int		flags)
 {
@@ -644,7 +644,7 @@ do_cmdline(
     struct msglist	*private_msg_list;
 
     /* "fgetline" and "cookie" passed to do_one_cmd() */
-    char_u	*(*cmd_getline)(int, void *, int);
+    char_u	*(*cmd_getline)(int, void *, int, int);
     void	*cmd_cookie;
     struct loop_cookie cmd_loop_cookie;
     void	*real_cookie;
@@ -894,7 +894,7 @@ do_cmdline(
 #else
 		    0
 #endif
-			    )) == NULL)
+		    , TRUE)) == NULL)
 	    {
 		/* Don't call wait_return for aborted command line.  The NULL
 		 * returned for the end of a sourced file or executed function
@@ -1424,7 +1424,7 @@ do_cmdline(
  * Obtain a line when inside a ":while" or ":for" loop.
  */
     static char_u *
-get_loop_line(int c, void *cookie, int indent)
+get_loop_line(int c, void *cookie, int indent, int do_concat)
 {
     struct loop_cookie	*cp = (struct loop_cookie *)cookie;
     wcmd_T		*wp;
@@ -1437,9 +1437,9 @@ get_loop_line(int c, void *cookie, int i
 
 	/* First time inside the ":while"/":for": get line normally. */
 	if (cp->getline == NULL)
-	    line = getcmdline(c, 0L, indent);
+	    line = getcmdline(c, 0L, indent, do_concat);
 	else
-	    line = cp->getline(c, cp->cookie, indent);
+	    line = cp->getline(c, cp->cookie, indent, do_concat);
 	if (line != NULL && store_loop_line(cp->lines_gap, line) == OK)
 	    ++cp->current_line;
 
@@ -1487,12 +1487,12 @@ free_cmdlines(garray_T *gap)
  */
     int
 getline_equal(
-    char_u	*(*fgetline)(int, void *, int),
+    char_u	*(*fgetline)(int, void *, int, int),
     void	*cookie UNUSED,		/* argument for fgetline() */
-    char_u	*(*func)(int, void *, int))
+    char_u	*(*func)(int, void *, int, int))
 {
 #ifdef FEAT_EVAL
-    char_u		*(*gp)(int, void *, int);
+    char_u		*(*gp)(int, void *, int, int);
     struct loop_cookie *cp;
 
     /* When "fgetline" is "get_loop_line()" use the "cookie" to find the
@@ -1517,11 +1517,11 @@ getline_equal(
  */
     void *
 getline_cookie(
-    char_u	*(*fgetline)(int, void *, int) UNUSED,
+    char_u	*(*fgetline)(int, void *, int, int) UNUSED,
     void	*cookie)		/* argument for fgetline() */
 {
 #ifdef FEAT_EVAL
-    char_u		*(*gp)(int, void *, int);
+    char_u		*(*gp)(int, void *, int, int);
     struct loop_cookie *cp;
 
     /* When "fgetline" is "get_loop_line()" use the "cookie" to find the
@@ -1654,7 +1654,7 @@ do_one_cmd(
 #ifdef FEAT_EVAL
     struct condstack	*cstack,
 #endif
-    char_u		*(*fgetline)(int, void *, int),
+    char_u		*(*fgetline)(int, void *, int, int),
     void		*cookie)		/* argument for fgetline() */
 {
     char_u		*p;
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -838,7 +838,8 @@ cmdline_init(void)
 getcmdline(
     int		firstc,
     long	count,		// only used for incremental search
-    int		indent)		// indent for inside conditionals
+    int		indent,		// indent for inside conditionals
+    int		do_concat UNUSED)
 {
     return getcmdline_int(firstc, count, indent, TRUE);
 }
@@ -2687,12 +2688,13 @@ correct_cmdspos(int idx, int cells)
 getexline(
     int		c,		/* normally ':', NUL for ":append" */
     void	*cookie UNUSED,
-    int		indent)		/* indent for inside conditionals */
+    int		indent,		/* indent for inside conditionals */
+    int		do_concat)
 {
     /* When executing a register, remove ':' that's in front of each line. */
     if (exec_from_reg && vpeekc() == ':')
 	(void)vgetc();
-    return getcmdline(c, 1L, indent);
+    return getcmdline(c, 1L, indent, do_concat);
 }
 
 /*
@@ -2706,7 +2708,8 @@ getexmodeline(
     int		promptc,	/* normally ':', NUL for ":append" and '?' for
 				   :s prompt */
     void	*cookie UNUSED,
-    int		indent)		/* indent for inside conditionals */
+    int		indent,		/* indent for inside conditionals */
+    int		do_concat UNUSED)
 {
     garray_T	line_ga;
     char_u	*pend;
@@ -7409,7 +7412,7 @@ script_get(exarg_T *eap, char_u *cmd)
 #ifdef FEAT_EVAL
 	    eap->cstack->cs_looplevel > 0 ? -1 :
 #endif
-	    NUL, eap->cookie, 0);
+	    NUL, eap->cookie, 0, TRUE);
 
 	if (theline == NULL || STRCMP(end_pattern, theline) == 0)
 	{
--- a/src/normal.c
+++ b/src/normal.c
@@ -6237,7 +6237,7 @@ nv_search(cmdarg_T *cap)
 
     /* When using 'incsearch' the cursor may be moved to set a different search
      * start position. */
-    cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0);
+    cap->searchbuf = getcmdline(cap->cmdchar, cap->count1, 0, TRUE);
 
     if (cap->searchbuf == NULL)
     {
--- a/src/ops.c
+++ b/src/ops.c
@@ -788,7 +788,7 @@ get_expr_register(void)
 {
     char_u	*new_line;
 
-    new_line = getcmdline('=', 0L, 0);
+    new_line = getcmdline('=', 0L, 0, TRUE);
     if (new_line == NULL)
 	return NUL;
     if (*new_line == NUL)	/* use previous line */
--- a/src/proto/autocmd.pro
+++ b/src/proto/autocmd.pro
@@ -30,7 +30,7 @@ int has_completechanged(void);
 void block_autocmds(void);
 void unblock_autocmds(void);
 int is_autocmd_blocked(void);
-char_u *getnextac(int c, void *cookie, int indent);
+char_u *getnextac(int c, void *cookie, int indent, int do_concat);
 int has_autocmd(event_T event, char_u *sfname, buf_T *buf);
 char_u *get_augroup_name(expand_T *xp, int idx);
 char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd);
--- a/src/proto/ex_cmds2.pro
+++ b/src/proto/ex_cmds2.pro
@@ -81,7 +81,7 @@ void ex_scriptnames(exarg_T *eap);
 void scriptnames_slash_adjust(void);
 char_u *get_scriptname(scid_T id);
 void free_scriptnames(void);
-char_u *getsourceline(int c, void *cookie, int indent);
+char_u *getsourceline(int c, void *cookie, int indent, int do_concat);
 void script_line_start(void);
 void script_line_exec(void);
 void script_line_end(void);
@@ -89,7 +89,7 @@ void ex_scriptencoding(exarg_T *eap);
 void ex_scriptversion(exarg_T *eap);
 void ex_finish(exarg_T *eap);
 void do_finish(exarg_T *eap, int reanimate);
-int source_finished(char_u *(*fgetline)(int, void *, int), void *cookie);
+int source_finished(char_u *(*fgetline)(int, void *, int, int), void *cookie);
 void ex_checktime(exarg_T *eap);
 char_u *get_mess_lang(void);
 void set_lang_var(void);
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -1,9 +1,9 @@
 /* ex_docmd.c */
 void do_exmode(int improved);
 int do_cmdline_cmd(char_u *cmd);
-int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int), void *cookie, int flags);
-int getline_equal(char_u *(*fgetline)(int, void *, int), void *cookie, char_u *(*func)(int, void *, int));
-void *getline_cookie(char_u *(*fgetline)(int, void *, int), void *cookie);
+int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int, int), void *cookie, int flags);
+int getline_equal(char_u *(*fgetline)(int, void *, int, int), void *cookie, char_u *(*func)(int, void *, int, int));
+void *getline_cookie(char_u *(*fgetline)(int, void *, int, int), void *cookie);
 int parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only);
 int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
 int checkforcmd(char_u **pp, char *cmd, int len);
--- a/src/proto/ex_getln.pro
+++ b/src/proto/ex_getln.pro
@@ -1,14 +1,14 @@
 /* ex_getln.c */
 void cmdline_init(void);
-char_u *getcmdline(int firstc, long count, int indent);
+char_u *getcmdline(int firstc, long count, int indent, int do_concat);
 char_u *getcmdline_prompt(int firstc, char_u *prompt, int attr, int xp_context, char_u *xp_arg);
 int text_locked(void);
 void text_locked_msg(void);
 char *get_text_locked_msg(void);
 int curbuf_locked(void);
 int allbuf_locked(void);
-char_u *getexline(int c, void *cookie, int indent);
-char_u *getexmodeline(int promptc, void *cookie, int indent);
+char_u *getexline(int c, void *cookie, int indent, int do_concat);
+char_u *getexmodeline(int promptc, void *cookie, int indent, int do_concat);
 int cmdline_overstrike(void);
 int cmdline_at_end(void);
 colnr_T cmdline_getvcol_cursor(void);
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -30,7 +30,7 @@ void ex_call(exarg_T *eap);
 int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv);
 void discard_pending_return(void *rettv);
 char_u *get_return_cmd(void *rettv);
-char_u *get_func_line(int c, void *cookie, int indent);
+char_u *get_func_line(int c, void *cookie, int indent, int do_concat);
 void func_line_start(void *cookie);
 void func_line_exec(void *cookie);
 void func_line_end(void *cookie);
--- a/src/testdir/test_let.vim
+++ b/src/testdir/test_let.vim
@@ -237,6 +237,14 @@ END
   END
   call assert_equal(['something', 'endfunc'], var1)
 
+  " not concatenate lines
+  let var1 =<< END
+some
+  \thing
+  \ else
+END
+  call assert_equal(['some', '  \thing', '  \ else'], var1)
+
   " ignore "python << xx"
   let var1 =<<END
 something
--- a/src/testdir/test_startup.vim
+++ b/src/testdir/test_startup.vim
@@ -157,6 +157,7 @@ endfunc
 " horizontally or vertically.
 func Test_o_arg()
   let after =<< trim [CODE]
+    set cpo&vim
     call writefile([winnr("$"),
 		\ winheight(1), winheight(2), &lines,
 		\ winwidth(1), winwidth(2), &columns,
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -2007,6 +2007,7 @@ ex_function(exarg_T *eap)
     hashtab_T	*ht;
     int		todo;
     hashitem_T	*hi;
+    int		do_concat = TRUE;
     int		sourcing_lnum_off;
 
     /*
@@ -2303,9 +2304,9 @@ ex_function(exarg_T *eap)
 	{
 	    vim_free(line_to_free);
 	    if (eap->getline == NULL)
-		theline = getcmdline(':', 0L, indent);
+		theline = getcmdline(':', 0L, indent, do_concat);
 	    else
-		theline = eap->getline(':', eap->cookie, indent);
+		theline = eap->getline(':', eap->cookie, indent, do_concat);
 	    line_to_free = theline;
 	}
 	if (KeyTyped)
@@ -2334,6 +2335,7 @@ ex_function(exarg_T *eap)
 		{
 		    VIM_CLEAR(skip_until);
 		    VIM_CLEAR(trimmed);
+		    do_concat = TRUE;
 		}
 	    }
 	}
@@ -2458,6 +2460,7 @@ ex_function(exarg_T *eap)
 		    skip_until = vim_strsave((char_u *)".");
 		else
 		    skip_until = vim_strnsave(p, (int)(skiptowhite(p) - p));
+		do_concat = FALSE;
 	    }
 	}
 
@@ -3511,7 +3514,8 @@ get_return_cmd(void *rettv)
 get_func_line(
     int	    c UNUSED,
     void    *cookie,
-    int	    indent UNUSED)
+    int	    indent UNUSED,
+    int	    do_concat UNUSED)
 {
     funccall_T	*fcp = (funccall_T *)cookie;
     ufunc_T	*fp = fcp->func;
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1588,
+/**/
     1587,
 /**/
     1586,