diff options
author | Yegappan Lakshmanan <yegappan@yahoo.com> | 2022-04-17 12:47:40 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-04-17 12:47:40 +0100 |
commit | efbfa867a146fcd93fdec2435597aa4ae7f1325c (patch) | |
tree | 0b8b54107db3708bfe5b5c0e572371d476f3c4ff /src/evalvars.c | |
parent | 68aaff4697bab4a278436e6f7ae042262223e51c (diff) |
patch 8.2.4770: cannot easily mix expression and heredocv8.2.4770
Problem: Cannot easily mix expression and heredoc.
Solution: Support in heredoc. (Yegappan Lakshmanan, closes #10138)
Diffstat (limited to 'src/evalvars.c')
-rw-r--r-- | src/evalvars.c | 133 |
1 files changed, 120 insertions, 13 deletions
diff --git a/src/evalvars.c b/src/evalvars.c index 8f8df0cf9d..5f04406265 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -603,6 +603,66 @@ list_script_vars(int *first) } /* + * Evaluate all the Vim expressions (`=expr`) in string "str" and return the + * resulting string. The caller must free the returned string. + */ + static 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; + + 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); + if (*p == NUL) + break; // no backtick expression found + + s = p; + p += 2; // skip `= + + status = *p == NUL ? OK : skip_expr(&p, NULL); + if (status == FAIL || *p != '`') + { + // invalid expression or missing ending backtick + if (status != FAIL) + emsg(_(e_missing_backtick)); + vim_free(ga.ga_data); + return NULL; + } + s += 2; // skip `= + save_c = *p; + *p = NUL; + exprval = eval_to_string(s, TRUE); + *p = save_c; + p++; + if (exprval == NULL) + { + // expression evaluation failed + vim_free(ga.ga_data); + return NULL; + } + ga_concat(&ga, exprval); + vim_free(exprval); + } + ga_append(&ga, NUL); + + return ga.ga_data; +} + +/* * Get a list of lines from a HERE document. The here document is a list of * lines surrounded by a marker. * cmd << {marker} @@ -619,7 +679,7 @@ list_script_vars(int *first) * tcl, mzscheme), script_get is set to TRUE. In this case, if the marker is * missing, then '.' is accepted as a marker. * - * Returns a List with {lines} or NULL. + * Returns a List with {lines} or NULL on failure. */ list_T * heredoc_get(exarg_T *eap, char_u *cmd, int script_get) @@ -628,11 +688,14 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get) char_u *marker; list_T *l; char_u *p; + char_u *str; int marker_indent_len = 0; int text_indent_len = 0; char_u *text_indent = NULL; char_u dot[] = "."; int comment_char = in_vim9script() ? '#' : '"'; + int evalstr = FALSE; + int eval_failed = FALSE; if (eap->getline == NULL) { @@ -642,21 +705,36 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get) // Check for the optional 'trim' word before the marker cmd = skipwhite(cmd); - if (STRNCMP(cmd, "trim", 4) == 0 && (cmd[4] == NUL || VIM_ISWHITE(cmd[4]))) + + while (TRUE) { - cmd = skipwhite(cmd + 4); + if (STRNCMP(cmd, "trim", 4) == 0 + && (cmd[4] == NUL || VIM_ISWHITE(cmd[4]))) + { + cmd = skipwhite(cmd + 4); + + // Trim the indentation from all the lines in the here document. + // The amount of indentation trimmed is the same as the indentation + // of the first line after the :let command line. To find the end + // marker the indent of the :let command line is trimmed. + p = *eap->cmdlinep; + while (VIM_ISWHITE(*p)) + { + p++; + marker_indent_len++; + } + text_indent_len = -1; - // Trim the indentation from all the lines in the here document. - // The amount of indentation trimmed is the same as the indentation of - // the first line after the :let command line. To find the end marker - // the indent of the :let command line is trimmed. - p = *eap->cmdlinep; - while (VIM_ISWHITE(*p)) + continue; + } + if (STRNCMP(cmd, "eval", 4) == 0 + && (cmd[4] == NUL || VIM_ISWHITE(cmd[4]))) { - p++; - marker_indent_len++; + cmd = skipwhite(cmd + 4); + evalstr = TRUE; + continue; } - text_indent_len = -1; + break; } // The marker is the next word. @@ -716,6 +794,14 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get) break; } + // If expression evaluation failed in the heredoc, then skip till the + // end marker. + if (eval_failed) + { + vim_free(theline); + continue; + } + if (text_indent_len == -1 && *theline != NUL) { // set the text indent from the first line. @@ -734,12 +820,33 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get) if (theline[ti] != text_indent[ti]) break; - if (list_append_string(l, theline + ti, -1) == FAIL) + str = theline + ti; + if (evalstr) + { + str = eval_all_expr_in_str(str); + if (str == NULL) + { + // expression evaluation failed + vim_free(theline); + eval_failed = TRUE; + continue; + } + vim_free(theline); + theline = str; + } + + if (list_append_string(l, str, -1) == FAIL) break; vim_free(theline); } vim_free(text_indent); + if (eval_failed) + { + // expression evaluation in the heredoc failed + list_free(l); + return NULL; + } return l; } |