diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 33 | ||||
-rw-r--r-- | src/nvim/eval/vars.c | 81 | ||||
-rw-r--r-- | src/nvim/globals.h | 5 |
3 files changed, 89 insertions, 30 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b240c36977..f8a9326703 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3100,8 +3100,13 @@ static int eval7(char **arg, typval_T *rettv, evalarg_T *const evalarg, bool wan ret = eval_option((const char **)arg, rettv, evaluate); break; // Environment variable: $VAR. + // Interpolated string: $"string" or $'string'. case '$': - ret = eval_env_var(arg, rettv, evaluate); + if ((*arg)[1] == '"' || (*arg)[1] == '\'') { + ret = eval_interp_string(arg, rettv, evaluate); + } else { + ret = eval_env_var(arg, rettv, evaluate); + } break; // Register contents: @r. @@ -4053,6 +4058,32 @@ static int eval_lit_string(char **arg, typval_T *rettv, int evaluate) return OK; } +int eval_interp_string(char **arg, typval_T *rettv, int evaluate) +{ + // *arg is on the '$' character. + (*arg)++; + + rettv->v_type = VAR_STRING; + + typval_T tv; + int ret; + if (**arg == '"') { + ret = eval_string(arg, &tv, evaluate); + } else { + ret = eval_lit_string(arg, &tv, evaluate); + } + + if (ret == FAIL || !evaluate) { + return ret; + } + + rettv->vval.v_string = eval_all_expr_in_str(tv.vval.v_string); + + tv_clear(&tv); + + return rettv->vval.v_string != NULL ? OK : FAIL; +} + /// @return the function name of the partial. char *partial_name(partial_T *pt) FUNC_ATTR_PURE diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index a8d1e01152..b86c49fd98 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -53,50 +53,73 @@ static const char *e_letunexp = N_("E18: Unexpected characters in :let"); static const char *e_lock_unlock = N_("E940: Cannot lock or unlock variable %s"); -/// 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 *eval_all_expr_in_str(char *str) +char *eval_all_expr_in_str(char *str) { garray_T ga; ga_init(&ga, 1, 80); char *p = str; - // Look for `=expr`, evaluate the expression and replace `=expr` with the - // result. while (*p != NUL) { - char *s = p; - while (*p != NUL && (*p != '`' || p[1] != '=')) { - p++; + bool escaped_brace = false; + + // Look for a block start. + char *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; } - ga_concat_len(&ga, s, (size_t)(p - s)); + + // 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 `= - int status = *p == NUL ? OK : skip_expr(&p, NULL); - if (status == FAIL || *p != '`') { - // invalid expression or missing ending backtick - if (status != FAIL) { - emsg(_("E1083: Missing backtick")); - } - xfree(ga.ga_data); + if (escaped_brace) { + // Skip the second brace. + ++p; + continue; + } + + // Skip the opening {. + char *block_start = ++p; + char *block_end = block_start; + if (*block_start != NUL && skip_expr(&block_end, NULL) == FAIL) { + ga_clear(&ga); return NULL; } - s += 2; // skip `= - char save_c = *p; - *p = NUL; - char *exprval = eval_to_string(s, true); - *p = save_c; - p++; - if (exprval == NULL) { - // expression evaluation failed - xfree(ga.ga_data); + block_end = skipwhite(block_end); + // The block must be closed by a }. + if (*block_end != '}') { + semsg(_(e_missing_close_curly_str), str); + ga_clear(&ga); return NULL; } - ga_concat(&ga, exprval); - xfree(exprval); + char save_c = *block_end; + *block_end = NUL; + char *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); + xfree(expr_val); + + p = block_end + 1; } ga_append(&ga, NUL); diff --git a/src/nvim/globals.h b/src/nvim/globals.h index e406d93494..11888a5df8 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1024,6 +1024,11 @@ EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld")); +EXTERN char e_stray_closing_curly_str[] +INIT(= N_("E1278: Stray '}' without a matching '{': %s")); +EXTERN char e_missing_close_curly_str[] +INIT(= N_("E1279: Missing '}': %s")); + EXTERN const char e_undobang_cannot_redo_or_move_branch[] INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); |