summaryrefslogtreecommitdiffstats
path: root/src/evalvars.c
diff options
context:
space:
mode:
authorLemonBoy <thatlemon@gmail.com>2022-05-06 13:14:50 +0100
committerBram Moolenaar <Bram@vim.org>2022-05-06 13:14:50 +0100
commit2eaef106e4a7fc9dc74a7e672b5f550ec1f9786e (patch)
tree543832333e5ef90b9e51477457a7e65572274227 /src/evalvars.c
parente7d6dbc5721342e3d6b04cf285e4510b5569e707 (diff)
patch 8.2.4883: string interpolation only works in heredocv8.2.4883
Problem: String interpolation only works in heredoc. Solution: Support interpolated strings. Use syntax for heredoc consistent with strings, similar to C#. (closes #10327)
Diffstat (limited to 'src/evalvars.c')
-rw-r--r--src/evalvars.c93
1 files changed, 61 insertions, 32 deletions
diff --git a/src/evalvars.c b/src/evalvars.c
index c51b5976d4..2f285189b6 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -603,59 +603,88 @@ list_script_vars(int *first)
}
/*
- * Evaluate all the Vim expressions (`=expr`) in string "str" and return the
+ * Evaluate all the Vim expressions ({expr}) in string "str" and return the
* resulting string. The caller must free the returned string.
*/
- static char_u *
+ char_u *
eval_all_expr_in_str(char_u *str)
{
garray_T ga;
- char_u *s;
char_u *p;
char_u save_c;
- char_u *exprval;
- int status;
+ char_u *expr_val;
ga_init2(&ga, 1, 80);
p = str;
- // Look for `=expr`, evaluate the expression and replace `=expr` with the
- // result.
while (*p != NUL)
{
- s = p;
- while (*p != NUL && (*p != '`' || p[1] != '='))
- p++;
- ga_concat_len(&ga, s, p - s);
+ char_u *lit_start;
+ char_u *block_start;
+ char_u *block_end;
+ int escaped_brace = FALSE;
+
+ // Look for a block start.
+ lit_start = p;
+ while (*p != '{' && *p != '}' && *p != NUL)
+ ++p;
+
+ if (*p != NUL && *p == p[1])
+ {
+ // Escaped brace, unescape and continue.
+ // Include the brace in the literal string.
+ ++p;
+ escaped_brace = TRUE;
+ }
+ else if (*p == '}')
+ {
+ semsg(_(e_stray_closing_curly_str), str);
+ ga_clear(&ga);
+ return NULL;
+ }
+
+ // Append the literal part.
+ ga_concat_len(&ga, lit_start, (size_t)(p - lit_start));
+
if (*p == NUL)
- break; // no backtick expression found
+ break;
- s = p;
- p += 2; // skip `=
+ if (escaped_brace)
+ {
+ // Skip the second brace.
+ ++p;
+ continue;
+ }
- status = *p == NUL ? OK : skip_expr(&p, NULL);
- if (status == FAIL || *p != '`')
+ // Skip the opening {.
+ block_start = ++p;
+ block_end = block_start;
+ if (*block_start != NUL && skip_expr(&block_end, NULL) == FAIL)
{
- // invalid expression or missing ending backtick
- if (status != FAIL)
- emsg(_(e_missing_backtick));
- vim_free(ga.ga_data);
+ ga_clear(&ga);
return NULL;
}
- s += 2; // skip `=
- save_c = *p;
- *p = NUL;
- exprval = eval_to_string(s, TRUE);
- *p = save_c;
- p++;
- if (exprval == NULL)
+ block_end = skipwhite(block_end);
+ // The block must be closed by a }.
+ if (*block_end != '}')
{
- // expression evaluation failed
- vim_free(ga.ga_data);
+ semsg(_(e_missing_close_curly_str), str);
+ ga_clear(&ga);
return NULL;
}
- ga_concat(&ga, exprval);
- vim_free(exprval);
+ save_c = *block_end;
+ *block_end = NUL;
+ expr_val = eval_to_string(block_start, TRUE);
+ *block_end = save_c;
+ if (expr_val == NULL)
+ {
+ ga_clear(&ga);
+ return NULL;
+ }
+ ga_concat(&ga, expr_val);
+ vim_free(expr_val);
+
+ p = block_end + 1;
}
ga_append(&ga, NUL);
@@ -825,7 +854,7 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get, int vim9compile)
str = theline + ti;
if (vim9compile)
{
- if (compile_heredoc_string(str, evalstr, cctx) == FAIL)
+ if (compile_all_expr_in_str(str, evalstr, cctx) == FAIL)
{
vim_free(theline);
vim_free(text_indent);