patch 9.1.0312: heredocs are not supported for :commands

Problem:  heredocs are not supported for :commands
          (@balki)
Solution: Add heredoc support
          (Yegappan Lakshmanan)

fixes: #14491
closes: #14528

Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/evalvars.c b/src/evalvars.c
index f16d475..62728ed 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -779,8 +779,10 @@
     int		eval_failed = FALSE;
     cctx_T	*cctx = vim9compile ? eap->cookie : NULL;
     int		count = 0;
+    int		heredoc_in_string = FALSE;
+    char_u	*line_arg = NULL;
 
-    if (eap->ea_getline == NULL)
+    if (eap->ea_getline == NULL && vim_strchr(cmd, '\n') == NULL)
     {
 	emsg(_(e_cannot_use_heredoc_here));
 	return NULL;
@@ -824,8 +826,14 @@
     if (*cmd != NUL && *cmd != comment_char)
     {
 	marker = skipwhite(cmd);
-	p = skiptowhite(marker);
-	if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char)
+	p = skiptowhite_or_nl(marker);
+	if (*p == NL)
+	{
+	    // heredoc in a string
+	    line_arg = p + 1;
+	    heredoc_in_string = TRUE;
+	}
+	else if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char)
 	{
 	    semsg(_(e_trailing_characters_str), p);
 	    return NULL;
@@ -859,12 +867,38 @@
 	int	mi = 0;
 	int	ti = 0;
 
-	vim_free(theline);
-	theline = eap->ea_getline(NUL, eap->cookie, 0, FALSE);
-	if (theline == NULL)
+	if (heredoc_in_string)
 	{
-	    semsg(_(e_missing_end_marker_str), marker);
-	    break;
+	    char_u	*next_line;
+
+	    // heredoc in a string separated by newlines.  Get the next line
+	    // from the string.
+
+	    if (*line_arg == NUL)
+	    {
+		semsg(_(e_missing_end_marker_str), marker);
+		break;
+	    }
+
+	    theline = line_arg;
+	    next_line = vim_strchr(theline, '\n');
+	    if (next_line == NULL)
+		line_arg += STRLEN(line_arg);
+	    else
+	    {
+		*next_line = NUL;
+		line_arg = next_line + 1;
+	    }
+	}
+	else
+	{
+	    vim_free(theline);
+	    theline = eap->ea_getline(NUL, eap->cookie, 0, FALSE);
+	    if (theline == NULL)
+	    {
+		semsg(_(e_missing_end_marker_str), marker);
+		break;
+	    }
 	}
 
 	// with "trim": skip the indent matching the :let line to find the
@@ -911,6 +945,8 @@
 	}
 	else
 	{
+	    int	    free_str = FALSE;
+
 	    if (evalstr && !eap->skip)
 	    {
 		str = eval_all_expr_in_str(str);
@@ -920,15 +956,20 @@
 		    eval_failed = TRUE;
 		    continue;
 		}
-		vim_free(theline);
-		theline = str;
+		free_str = TRUE;
 	    }
 
 	    if (list_append_string(l, str, -1) == FAIL)
 		break;
+	    if (free_str)
+		vim_free(str);
 	}
     }
-    vim_free(theline);
+    if (heredoc_in_string)
+	// Next command follows the heredoc in the string.
+	eap->nextcmd = line_arg;
+    else
+	vim_free(theline);
     vim_free(text_indent);
 
     if (vim9compile && cctx->ctx_skip != SKIP_YES && !eval_failed)