mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch: port some userfunc.c refactorings from Vim (#32292)
Port one_function_arg() and get_function_body() from Vim.
vim-patch:8.2.2865: skipping over function body fails
Problem: Skipping over function body fails.
Solution: Do not define the function when skipping.
d87c21a918
Co-authored-by: Bram Moolenaar <Bram@vim.org>
This commit is contained in:
parent
289c9d21cb
commit
a857b251d1
@ -104,6 +104,48 @@ hashtab_T *func_tbl_get(void)
|
||||
return &func_hashtab;
|
||||
}
|
||||
|
||||
/// Get one function argument.
|
||||
/// Return a pointer to after the type.
|
||||
/// When something is wrong return "arg".
|
||||
static char *one_function_arg(char *arg, garray_T *newargs, bool skip)
|
||||
{
|
||||
char *p = arg;
|
||||
|
||||
while (ASCII_ISALNUM(*p) || *p == '_') {
|
||||
p++;
|
||||
}
|
||||
if (arg == p || isdigit((uint8_t)(*arg))
|
||||
|| (p - arg == 9 && strncmp(arg, "firstline", 9) == 0)
|
||||
|| (p - arg == 8 && strncmp(arg, "lastline", 8) == 0)) {
|
||||
if (!skip) {
|
||||
semsg(_("E125: Illegal argument: %s"), arg);
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
if (newargs != NULL) {
|
||||
ga_grow(newargs, 1);
|
||||
uint8_t c = (uint8_t)(*p);
|
||||
*p = NUL;
|
||||
char *arg_copy = xstrdup(arg);
|
||||
|
||||
// Check for duplicate argument name.
|
||||
for (int i = 0; i < newargs->ga_len; i++) {
|
||||
if (strcmp(((char **)(newargs->ga_data))[i], arg_copy) == 0) {
|
||||
semsg(_("E853: Duplicate argument name: %s"), arg_copy);
|
||||
xfree(arg_copy);
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
((char **)(newargs->ga_data))[newargs->ga_len] = arg_copy;
|
||||
newargs->ga_len++;
|
||||
|
||||
*p = (char)c;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/// Get function arguments.
|
||||
static int get_function_args(char **argp, char endchar, garray_T *newargs, int *varargs,
|
||||
garray_T *default_args, bool skip)
|
||||
@ -134,36 +176,11 @@ static int get_function_args(char **argp, char endchar, garray_T *newargs, int *
|
||||
mustend = true;
|
||||
} else {
|
||||
arg = p;
|
||||
while (ASCII_ISALNUM(*p) || *p == '_') {
|
||||
p++;
|
||||
}
|
||||
if (arg == p || isdigit((uint8_t)(*arg))
|
||||
|| (p - arg == 9 && strncmp(arg, "firstline", 9) == 0)
|
||||
|| (p - arg == 8 && strncmp(arg, "lastline", 8) == 0)) {
|
||||
if (!skip) {
|
||||
semsg(_("E125: Illegal argument: %s"), arg);
|
||||
}
|
||||
p = one_function_arg(p, newargs, skip);
|
||||
if (p == arg) {
|
||||
break;
|
||||
}
|
||||
if (newargs != NULL) {
|
||||
ga_grow(newargs, 1);
|
||||
uint8_t c = (uint8_t)(*p);
|
||||
*p = NUL;
|
||||
arg = xstrdup(arg);
|
||||
|
||||
// Check for duplicate argument name.
|
||||
for (int i = 0; i < newargs->ga_len; i++) {
|
||||
if (strcmp(((char **)(newargs->ga_data))[i], arg) == 0) {
|
||||
semsg(_("E853: Duplicate argument name: %s"), arg);
|
||||
xfree(arg);
|
||||
goto err_ret;
|
||||
}
|
||||
}
|
||||
((char **)(newargs->ga_data))[newargs->ga_len] = arg;
|
||||
newargs->ga_len++;
|
||||
|
||||
*p = (char)c;
|
||||
}
|
||||
if (*skipwhite(p) == '=' && default_args != NULL) {
|
||||
typval_T rettv;
|
||||
|
||||
@ -2186,8 +2203,6 @@ char *save_function_name(char **name, bool skip, int flags, funcdict_T *fudi)
|
||||
return saved;
|
||||
}
|
||||
|
||||
#define MAX_FUNC_NESTING 50
|
||||
|
||||
/// List functions.
|
||||
///
|
||||
/// @param regmatch When NULL, all of them.
|
||||
@ -2218,12 +2233,280 @@ static void list_functions(regmatch_T *regmatch)
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_FUNC_NESTING 50
|
||||
|
||||
/// Read the body of a function, put every line in "newlines".
|
||||
/// This stops at "endfunction".
|
||||
/// "newlines" must already have been initialized.
|
||||
static int get_function_body(exarg_T *eap, garray_T *newlines, char *line_arg_in,
|
||||
char **line_to_free, bool show_block)
|
||||
{
|
||||
bool saved_wait_return = need_wait_return;
|
||||
char *line_arg = line_arg_in;
|
||||
int indent = 2;
|
||||
int nesting = 0;
|
||||
char *skip_until = NULL;
|
||||
int ret = FAIL;
|
||||
bool is_heredoc = false;
|
||||
char *heredoc_trimmed = NULL;
|
||||
bool do_concat = true;
|
||||
|
||||
while (true) {
|
||||
if (KeyTyped) {
|
||||
msg_scroll = true;
|
||||
saved_wait_return = false;
|
||||
}
|
||||
need_wait_return = false;
|
||||
|
||||
char *theline;
|
||||
char *p;
|
||||
char *arg;
|
||||
|
||||
if (line_arg != NULL) {
|
||||
// Use eap->arg, split up in parts by line breaks.
|
||||
theline = line_arg;
|
||||
p = vim_strchr(theline, '\n');
|
||||
if (p == NULL) {
|
||||
line_arg += strlen(line_arg);
|
||||
} else {
|
||||
*p = NUL;
|
||||
line_arg = p + 1;
|
||||
}
|
||||
} else {
|
||||
xfree(*line_to_free);
|
||||
if (eap->ea_getline == NULL) {
|
||||
theline = getcmdline(':', 0, indent, do_concat);
|
||||
} else {
|
||||
theline = eap->ea_getline(':', eap->cookie, indent, do_concat);
|
||||
}
|
||||
*line_to_free = theline;
|
||||
}
|
||||
if (KeyTyped) {
|
||||
lines_left = Rows - 1;
|
||||
}
|
||||
if (theline == NULL) {
|
||||
if (skip_until != NULL) {
|
||||
semsg(_(e_missing_heredoc_end_marker_str), skip_until);
|
||||
} else {
|
||||
emsg(_("E126: Missing :endfunction"));
|
||||
}
|
||||
goto theend;
|
||||
}
|
||||
if (show_block) {
|
||||
assert(indent >= 0);
|
||||
ui_ext_cmdline_block_append((size_t)indent, theline);
|
||||
}
|
||||
|
||||
// Detect line continuation: SOURCING_LNUM increased more than one.
|
||||
linenr_T sourcing_lnum_off = get_sourced_lnum(eap->ea_getline, eap->cookie);
|
||||
if (SOURCING_LNUM < sourcing_lnum_off) {
|
||||
sourcing_lnum_off -= SOURCING_LNUM;
|
||||
} else {
|
||||
sourcing_lnum_off = 0;
|
||||
}
|
||||
|
||||
if (skip_until != NULL) {
|
||||
// Don't check for ":endfunc" between
|
||||
// * ":append" and "."
|
||||
// * ":python <<EOF" and "EOF"
|
||||
// * ":let {var-name} =<< [trim] {marker}" and "{marker}"
|
||||
if (heredoc_trimmed == NULL
|
||||
|| (is_heredoc && skipwhite(theline) == theline)
|
||||
|| strncmp(theline, heredoc_trimmed,
|
||||
strlen(heredoc_trimmed)) == 0) {
|
||||
if (heredoc_trimmed == NULL) {
|
||||
p = theline;
|
||||
} else if (is_heredoc) {
|
||||
p = skipwhite(theline) == theline
|
||||
? theline : theline + strlen(heredoc_trimmed);
|
||||
} else {
|
||||
p = theline + strlen(heredoc_trimmed);
|
||||
}
|
||||
if (strcmp(p, skip_until) == 0) {
|
||||
XFREE_CLEAR(skip_until);
|
||||
XFREE_CLEAR(heredoc_trimmed);
|
||||
do_concat = true;
|
||||
is_heredoc = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// skip ':' and blanks
|
||||
for (p = theline; ascii_iswhite(*p) || *p == ':'; p++) {}
|
||||
|
||||
// Check for "endfunction".
|
||||
if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0) {
|
||||
if (*p == '!') {
|
||||
p++;
|
||||
}
|
||||
char *nextcmd = NULL;
|
||||
if (*p == '|') {
|
||||
nextcmd = p + 1;
|
||||
} else if (line_arg != NULL && *skipwhite(line_arg) != NUL) {
|
||||
nextcmd = line_arg;
|
||||
} else if (*p != NUL && *p != '"' && p_verbose > 0) {
|
||||
swmsg(true, _("W22: Text found after :endfunction: %s"), p);
|
||||
}
|
||||
if (nextcmd != NULL) {
|
||||
// Another command follows. If the line came from "eap" we
|
||||
// can simply point into it, otherwise we need to change
|
||||
// "eap->cmdlinep".
|
||||
eap->nextcmd = nextcmd;
|
||||
if (*line_to_free != NULL) {
|
||||
xfree(*eap->cmdlinep);
|
||||
*eap->cmdlinep = *line_to_free;
|
||||
*line_to_free = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Increase indent inside "if", "while", "for" and "try", decrease
|
||||
// at "end".
|
||||
if (indent > 2 && strncmp(p, "end", 3) == 0) {
|
||||
indent -= 2;
|
||||
} else if (strncmp(p, "if", 2) == 0
|
||||
|| strncmp(p, "wh", 2) == 0
|
||||
|| strncmp(p, "for", 3) == 0
|
||||
|| strncmp(p, "try", 3) == 0) {
|
||||
indent += 2;
|
||||
}
|
||||
|
||||
// Check for defining a function inside this function.
|
||||
if (checkforcmd(&p, "function", 2)) {
|
||||
if (*p == '!') {
|
||||
p = skipwhite(p + 1);
|
||||
}
|
||||
p += eval_fname_script(p);
|
||||
xfree(trans_function_name(&p, true, 0, NULL, NULL));
|
||||
if (*skipwhite(p) == '(') {
|
||||
if (nesting == MAX_FUNC_NESTING - 1) {
|
||||
emsg(_(e_function_nesting_too_deep));
|
||||
} else {
|
||||
nesting++;
|
||||
indent += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for ":append", ":change", ":insert".
|
||||
p = skip_range(p, NULL);
|
||||
if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p'))
|
||||
|| (p[0] == 'c'
|
||||
&& (!ASCII_ISALPHA(p[1])
|
||||
|| (p[1] == 'h' && (!ASCII_ISALPHA(p[2])
|
||||
|| (p[2] == 'a'
|
||||
&& (strncmp(&p[3], "nge", 3) != 0
|
||||
|| !ASCII_ISALPHA(p[6])))))))
|
||||
|| (p[0] == 'i'
|
||||
&& (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
|
||||
&& (!ASCII_ISALPHA(p[2])
|
||||
|| (p[2] == 's')))))) {
|
||||
skip_until = xstrdup(".");
|
||||
}
|
||||
|
||||
// heredoc: Check for ":python <<EOF", ":lua <<EOF", etc.
|
||||
arg = skipwhite(skiptowhite(p));
|
||||
if (arg[0] == '<' && arg[1] == '<'
|
||||
&& ((p[0] == 'p' && p[1] == 'y'
|
||||
&& (!ASCII_ISALNUM(p[2]) || p[2] == 't'
|
||||
|| ((p[2] == '3' || p[2] == 'x')
|
||||
&& !ASCII_ISALPHA(p[3]))))
|
||||
|| (p[0] == 'p' && p[1] == 'e'
|
||||
&& (!ASCII_ISALPHA(p[2]) || p[2] == 'r'))
|
||||
|| (p[0] == 't' && p[1] == 'c'
|
||||
&& (!ASCII_ISALPHA(p[2]) || p[2] == 'l'))
|
||||
|| (p[0] == 'l' && p[1] == 'u' && p[2] == 'a'
|
||||
&& !ASCII_ISALPHA(p[3]))
|
||||
|| (p[0] == 'r' && p[1] == 'u' && p[2] == 'b'
|
||||
&& (!ASCII_ISALPHA(p[3]) || p[3] == 'y'))
|
||||
|| (p[0] == 'm' && p[1] == 'z'
|
||||
&& (!ASCII_ISALPHA(p[2]) || p[2] == 's')))) {
|
||||
// ":python <<" continues until a dot, like ":append"
|
||||
p = skipwhite(arg + 2);
|
||||
if (strncmp(p, "trim", 4) == 0) {
|
||||
// Ignore leading white space.
|
||||
p = skipwhite(p + 4);
|
||||
heredoc_trimmed = xmemdupz(theline, (size_t)(skipwhite(theline) - theline));
|
||||
}
|
||||
if (*p == NUL) {
|
||||
skip_until = xstrdup(".");
|
||||
} else {
|
||||
skip_until = xmemdupz(p, (size_t)(skiptowhite(p) - p));
|
||||
}
|
||||
do_concat = false;
|
||||
is_heredoc = true;
|
||||
}
|
||||
|
||||
// Check for ":let v =<< [trim] EOF"
|
||||
// and ":let [a, b] =<< [trim] EOF"
|
||||
arg = p;
|
||||
if (checkforcmd(&arg, "let", 2)) {
|
||||
int var_count = 0;
|
||||
int semicolon = 0;
|
||||
arg = (char *)skip_var_list(arg, &var_count, &semicolon, true);
|
||||
if (arg != NULL) {
|
||||
arg = skipwhite(arg);
|
||||
}
|
||||
if (arg != NULL && strncmp(arg, "=<<", 3) == 0) {
|
||||
p = skipwhite(arg + 3);
|
||||
while (true) {
|
||||
if (strncmp(p, "trim", 4) == 0) {
|
||||
// Ignore leading white space.
|
||||
p = skipwhite(p + 4);
|
||||
heredoc_trimmed = xmemdupz(theline, (size_t)(skipwhite(theline) - theline));
|
||||
continue;
|
||||
}
|
||||
if (strncmp(p, "eval", 4) == 0) {
|
||||
// Ignore leading white space.
|
||||
p = skipwhite(p + 4);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
skip_until = xmemdupz(p, (size_t)(skiptowhite(p) - p));
|
||||
do_concat = false;
|
||||
is_heredoc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the line to the function.
|
||||
ga_grow(newlines, 1 + (int)sourcing_lnum_off);
|
||||
|
||||
// Copy the line to newly allocated memory. get_one_sourceline()
|
||||
// allocates 250 bytes per line, this saves 80% on average. The cost
|
||||
// is an extra alloc/free.
|
||||
p = xstrdup(theline);
|
||||
((char **)(newlines->ga_data))[newlines->ga_len++] = p;
|
||||
|
||||
// Add NULL lines for continuation lines, so that the line count is
|
||||
// equal to the index in the growarray.
|
||||
while (sourcing_lnum_off-- > 0) {
|
||||
((char **)(newlines->ga_data))[newlines->ga_len++] = NULL;
|
||||
}
|
||||
|
||||
// Check for end of eap->arg.
|
||||
if (line_arg != NULL && *line_arg == NUL) {
|
||||
line_arg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Return OK when no error was detected.
|
||||
if (!did_emsg) {
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
theend:
|
||||
xfree(skip_until);
|
||||
xfree(heredoc_trimmed);
|
||||
need_wait_return |= saved_wait_return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// ":function"
|
||||
void ex_function(exarg_T *eap)
|
||||
{
|
||||
char *theline;
|
||||
char *line_to_free = NULL;
|
||||
bool saved_wait_return = need_wait_return;
|
||||
char *arg;
|
||||
char *line_arg = NULL;
|
||||
garray_T newargs;
|
||||
@ -2236,11 +2519,7 @@ void ex_function(exarg_T *eap)
|
||||
funcdict_T fudi;
|
||||
static int func_nr = 0; // number for nameless function
|
||||
hashtab_T *ht;
|
||||
bool is_heredoc = false;
|
||||
char *skip_until = NULL;
|
||||
char *heredoc_trimmed = NULL;
|
||||
bool show_block = false;
|
||||
bool do_concat = true;
|
||||
|
||||
// ":function" without argument: list functions.
|
||||
if (ends_excmd(*eap->arg)) {
|
||||
@ -2487,247 +2766,9 @@ void ex_function(exarg_T *eap)
|
||||
// Save the starting line number.
|
||||
linenr_T sourcing_lnum_top = SOURCING_LNUM;
|
||||
|
||||
int indent = 2;
|
||||
int nesting = 0;
|
||||
while (true) {
|
||||
if (KeyTyped) {
|
||||
msg_scroll = true;
|
||||
saved_wait_return = false;
|
||||
}
|
||||
need_wait_return = false;
|
||||
|
||||
if (line_arg != NULL) {
|
||||
// Use eap->arg, split up in parts by line breaks.
|
||||
theline = line_arg;
|
||||
p = vim_strchr(theline, '\n');
|
||||
if (p == NULL) {
|
||||
line_arg += strlen(line_arg);
|
||||
} else {
|
||||
*p = NUL;
|
||||
line_arg = p + 1;
|
||||
}
|
||||
} else {
|
||||
xfree(line_to_free);
|
||||
if (eap->ea_getline == NULL) {
|
||||
theline = getcmdline(':', 0, indent, do_concat);
|
||||
} else {
|
||||
theline = eap->ea_getline(':', eap->cookie, indent, do_concat);
|
||||
}
|
||||
line_to_free = theline;
|
||||
}
|
||||
if (KeyTyped) {
|
||||
lines_left = Rows - 1;
|
||||
}
|
||||
if (theline == NULL) {
|
||||
if (skip_until != NULL) {
|
||||
semsg(_(e_missing_heredoc_end_marker_str), skip_until);
|
||||
} else {
|
||||
emsg(_("E126: Missing :endfunction"));
|
||||
}
|
||||
goto erret;
|
||||
}
|
||||
if (show_block) {
|
||||
assert(indent >= 0);
|
||||
ui_ext_cmdline_block_append((size_t)indent, theline);
|
||||
}
|
||||
|
||||
// Detect line continuation: SOURCING_LNUM increased more than one.
|
||||
linenr_T sourcing_lnum_off = get_sourced_lnum(eap->ea_getline, eap->cookie);
|
||||
if (SOURCING_LNUM < sourcing_lnum_off) {
|
||||
sourcing_lnum_off -= SOURCING_LNUM;
|
||||
} else {
|
||||
sourcing_lnum_off = 0;
|
||||
}
|
||||
|
||||
if (skip_until != NULL) {
|
||||
// Don't check for ":endfunc" between
|
||||
// * ":append" and "."
|
||||
// * ":python <<EOF" and "EOF"
|
||||
// * ":let {var-name} =<< [trim] {marker}" and "{marker}"
|
||||
if (heredoc_trimmed == NULL
|
||||
|| (is_heredoc && skipwhite(theline) == theline)
|
||||
|| strncmp(theline, heredoc_trimmed,
|
||||
strlen(heredoc_trimmed)) == 0) {
|
||||
if (heredoc_trimmed == NULL) {
|
||||
p = theline;
|
||||
} else if (is_heredoc) {
|
||||
p = skipwhite(theline) == theline
|
||||
? theline : theline + strlen(heredoc_trimmed);
|
||||
} else {
|
||||
p = theline + strlen(heredoc_trimmed);
|
||||
}
|
||||
if (strcmp(p, skip_until) == 0) {
|
||||
XFREE_CLEAR(skip_until);
|
||||
XFREE_CLEAR(heredoc_trimmed);
|
||||
do_concat = true;
|
||||
is_heredoc = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// skip ':' and blanks
|
||||
for (p = theline; ascii_iswhite(*p) || *p == ':'; p++) {}
|
||||
|
||||
// Check for "endfunction".
|
||||
if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0) {
|
||||
if (*p == '!') {
|
||||
p++;
|
||||
}
|
||||
char *nextcmd = NULL;
|
||||
if (*p == '|') {
|
||||
nextcmd = p + 1;
|
||||
} else if (line_arg != NULL && *skipwhite(line_arg) != NUL) {
|
||||
nextcmd = line_arg;
|
||||
} else if (*p != NUL && *p != '"' && p_verbose > 0) {
|
||||
swmsg(true, _("W22: Text found after :endfunction: %s"), p);
|
||||
}
|
||||
if (nextcmd != NULL) {
|
||||
// Another command follows. If the line came from "eap" we
|
||||
// can simply point into it, otherwise we need to change
|
||||
// "eap->cmdlinep".
|
||||
eap->nextcmd = nextcmd;
|
||||
if (line_to_free != NULL) {
|
||||
xfree(*eap->cmdlinep);
|
||||
*eap->cmdlinep = line_to_free;
|
||||
line_to_free = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Increase indent inside "if", "while", "for" and "try", decrease
|
||||
// at "end".
|
||||
if (indent > 2 && strncmp(p, "end", 3) == 0) {
|
||||
indent -= 2;
|
||||
} else if (strncmp(p, "if", 2) == 0
|
||||
|| strncmp(p, "wh", 2) == 0
|
||||
|| strncmp(p, "for", 3) == 0
|
||||
|| strncmp(p, "try", 3) == 0) {
|
||||
indent += 2;
|
||||
}
|
||||
|
||||
// Check for defining a function inside this function.
|
||||
if (checkforcmd(&p, "function", 2)) {
|
||||
if (*p == '!') {
|
||||
p = skipwhite(p + 1);
|
||||
}
|
||||
p += eval_fname_script(p);
|
||||
xfree(trans_function_name(&p, true, 0, NULL, NULL));
|
||||
if (*skipwhite(p) == '(') {
|
||||
if (nesting == MAX_FUNC_NESTING - 1) {
|
||||
emsg(_(e_function_nesting_too_deep));
|
||||
} else {
|
||||
nesting++;
|
||||
indent += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for ":append", ":change", ":insert".
|
||||
p = skip_range(p, NULL);
|
||||
if ((p[0] == 'a' && (!ASCII_ISALPHA(p[1]) || p[1] == 'p'))
|
||||
|| (p[0] == 'c'
|
||||
&& (!ASCII_ISALPHA(p[1])
|
||||
|| (p[1] == 'h' && (!ASCII_ISALPHA(p[2])
|
||||
|| (p[2] == 'a'
|
||||
&& (strncmp(&p[3], "nge", 3) != 0
|
||||
|| !ASCII_ISALPHA(p[6])))))))
|
||||
|| (p[0] == 'i'
|
||||
&& (!ASCII_ISALPHA(p[1]) || (p[1] == 'n'
|
||||
&& (!ASCII_ISALPHA(p[2])
|
||||
|| (p[2] == 's')))))) {
|
||||
skip_until = xstrdup(".");
|
||||
}
|
||||
|
||||
// heredoc: Check for ":python <<EOF", ":lua <<EOF", etc.
|
||||
arg = skipwhite(skiptowhite(p));
|
||||
if (arg[0] == '<' && arg[1] == '<'
|
||||
&& ((p[0] == 'p' && p[1] == 'y'
|
||||
&& (!ASCII_ISALNUM(p[2]) || p[2] == 't'
|
||||
|| ((p[2] == '3' || p[2] == 'x')
|
||||
&& !ASCII_ISALPHA(p[3]))))
|
||||
|| (p[0] == 'p' && p[1] == 'e'
|
||||
&& (!ASCII_ISALPHA(p[2]) || p[2] == 'r'))
|
||||
|| (p[0] == 't' && p[1] == 'c'
|
||||
&& (!ASCII_ISALPHA(p[2]) || p[2] == 'l'))
|
||||
|| (p[0] == 'l' && p[1] == 'u' && p[2] == 'a'
|
||||
&& !ASCII_ISALPHA(p[3]))
|
||||
|| (p[0] == 'r' && p[1] == 'u' && p[2] == 'b'
|
||||
&& (!ASCII_ISALPHA(p[3]) || p[3] == 'y'))
|
||||
|| (p[0] == 'm' && p[1] == 'z'
|
||||
&& (!ASCII_ISALPHA(p[2]) || p[2] == 's')))) {
|
||||
// ":python <<" continues until a dot, like ":append"
|
||||
p = skipwhite(arg + 2);
|
||||
if (strncmp(p, "trim", 4) == 0) {
|
||||
// Ignore leading white space.
|
||||
p = skipwhite(p + 4);
|
||||
heredoc_trimmed = xmemdupz(theline, (size_t)(skipwhite(theline) - theline));
|
||||
}
|
||||
if (*p == NUL) {
|
||||
skip_until = xstrdup(".");
|
||||
} else {
|
||||
skip_until = xmemdupz(p, (size_t)(skiptowhite(p) - p));
|
||||
}
|
||||
do_concat = false;
|
||||
is_heredoc = true;
|
||||
}
|
||||
|
||||
// Check for ":let v =<< [trim] EOF"
|
||||
// and ":let [a, b] =<< [trim] EOF"
|
||||
arg = p;
|
||||
if (checkforcmd(&arg, "let", 2)) {
|
||||
int var_count = 0;
|
||||
int semicolon = 0;
|
||||
arg = (char *)skip_var_list(arg, &var_count, &semicolon, true);
|
||||
if (arg != NULL) {
|
||||
arg = skipwhite(arg);
|
||||
}
|
||||
if (arg != NULL && strncmp(arg, "=<<", 3) == 0) {
|
||||
p = skipwhite(arg + 3);
|
||||
while (true) {
|
||||
if (strncmp(p, "trim", 4) == 0) {
|
||||
// Ignore leading white space.
|
||||
p = skipwhite(p + 4);
|
||||
heredoc_trimmed = xmemdupz(theline, (size_t)(skipwhite(theline) - theline));
|
||||
continue;
|
||||
}
|
||||
if (strncmp(p, "eval", 4) == 0) {
|
||||
// Ignore leading white space.
|
||||
p = skipwhite(p + 4);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
skip_until = xmemdupz(p, (size_t)(skiptowhite(p) - p));
|
||||
do_concat = false;
|
||||
is_heredoc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the line to the function.
|
||||
ga_grow(&newlines, 1 + (int)sourcing_lnum_off);
|
||||
|
||||
// Copy the line to newly allocated memory. get_one_sourceline()
|
||||
// allocates 250 bytes per line, this saves 80% on average. The cost
|
||||
// is an extra alloc/free.
|
||||
p = xstrdup(theline);
|
||||
((char **)(newlines.ga_data))[newlines.ga_len++] = p;
|
||||
|
||||
// Add NULL lines for continuation lines, so that the line count is
|
||||
// equal to the index in the growarray.
|
||||
while (sourcing_lnum_off-- > 0) {
|
||||
((char **)(newlines.ga_data))[newlines.ga_len++] = NULL;
|
||||
}
|
||||
|
||||
// Check for end of eap->arg.
|
||||
if (line_arg != NULL && *line_arg == NUL) {
|
||||
line_arg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't define the function when skipping commands or when an error was
|
||||
// detected.
|
||||
if (eap->skip || did_emsg) {
|
||||
// Do not define the function when getting the body fails and when skipping.
|
||||
if (get_function_body(eap, &newlines, line_arg, &line_to_free, show_block) == FAIL
|
||||
|| eap->skip) {
|
||||
goto erret;
|
||||
}
|
||||
|
||||
@ -2879,13 +2920,10 @@ erret:
|
||||
errret_2:
|
||||
ga_clear_strings(&newlines);
|
||||
ret_free:
|
||||
xfree(skip_until);
|
||||
xfree(heredoc_trimmed);
|
||||
xfree(line_to_free);
|
||||
xfree(fudi.fd_newkey);
|
||||
xfree(name);
|
||||
did_emsg |= saved_did_emsg;
|
||||
need_wait_return |= saved_wait_return;
|
||||
if (show_block) {
|
||||
ui_ext_cmdline_block_leave();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user