Compare commits

...

20 Commits

Author SHA1 Message Date
Dominique Pelle
ee41052ccb patch 8.2.3156: Vim9: term_getansicolors() test fails without +termguicolors
Problem:    Vim9: term_getansicolors() test fails without +termguicolors.
Solution:   Add a check for the feature. (Dominique Pellé, closes #8555)
2021-07-12 22:15:24 +02:00
Dominique Pelle
042414fa00 patch 8.2.3155: some option related code not covered by tests
Problem:    Some option related code not covered by tests.
Solution:   Add a few test cases. (Dominique Pellé, closes #8552)
2021-07-12 21:43:19 +02:00
Yegappan Lakshmanan
841e498c5d patch 8.2.3154: Vim9: some type checks for builtin functions fail
Problem:    Vim9: some type checks for builtin functions fail.
Solution:   Correct the type checks. (Yegappan Lakshmanan, closes #8551,
            closes #8550)
2021-07-11 22:04:25 +02:00
Tsuyoshi CHO
7b7a118e74 patch 8.2.3153: URLs with a dash in the scheme are not recognized
Problem:    URLs with a dash in the scheme are not recognized.
Solution:   Allow for a scheme with a dash, but not at the start or end.
            (Tsuyoshi CHO, closes #8299)
2021-07-11 21:51:17 +02:00
Bram Moolenaar
11005b078d patch 8.2.3152: Vim9: accessing "s:" results in an error
Problem:    Vim9: accessing "s:" results in an error.
Solution:   Do not try to lookup a script variable for "s:". (closes #8549)
2021-07-11 20:59:00 +02:00
Bram Moolenaar
ffcfddc759 patch 8.2.3151: Vim9: profiling fails if nested function is also profiled
Problem:    Vim9: profiling fails if nested function is also profiled.
Solution:   Use the compile type from the outer function. (closes #8543)
2021-07-11 20:22:30 +02:00
Yegappan Lakshmanan
c72bdd28ac patch 8.2.3150: Vim9: argument types are not checked at compile time
Problem:    Vim9: argument types are not checked at compile time.
Solution:   Add more type checks. (Yegappan Lakshmanan, closes #8545)
2021-07-11 19:44:18 +02:00
Bram Moolenaar
cc7eb2aa7a patch 8.2.3149: some plugins have a problem with the error check
Problem:    Some plugins have a problem with the error check for using
            :command with -complete but without -nargs.
Solution:   In legacy script only give a warning message.
2021-07-11 19:12:04 +02:00
Bram Moolenaar
5231224e11 patch 8.2.3148: Vim9: function arg type check does not handle base offset
Problem:    Vim9: function arg type check does not handle base offset.
Solution:   Take the base offset into account when checking builtin function
            argument types.
2021-07-11 18:23:19 +02:00
Bram Moolenaar
648594eaf7 patch 8.2.3147: Vim9: profiling does not work with a nested function
Problem:    Vim9: profiling does not work with a nested function.
Solution:   Also compile a nested function without profiling. (closes #8543)
            Handle that compiling may cause the table of compiled functions to
            change.
2021-07-11 17:55:01 +02:00
Bram Moolenaar
c03fe66ade patch 8.2.3146: Vim9: line number wrong for :execute argument
Problem:    Vim9: line number wrong for :execute argument.
Solution:   Use the line number of the :execute command itself. (closes #8537)
2021-07-11 16:52:45 +02:00
Bram Moolenaar
4ece152ad6 patch 8.2.3145: Vim9: profile test fails without profile feature
Problem:    Vim9: profile test fails without profile feature.
Solution:   Check the profile feature is present.
2021-07-11 16:31:51 +02:00
Bram Moolenaar
0f1227f7d5 patch 8.2.3144: Vim9: no error when using an invalid value for a line number
Problem:    Vim9: no error when using an invalid value for a line number.
Solution:   Give an error if the string value is not recognized.
            (closes #8536)
2021-07-11 16:01:58 +02:00
Bram Moolenaar
d9162550aa patch 8.2.3143: Vim9: wrong context if lambda called from profiled function
Problem:    Vim9: A lambda may be compiled with the wrong context if it is
            called from a profiled function.
Solution:   Compile the lambda with and without profiling. (closes #8543)
2021-07-11 15:26:13 +02:00
Bram Moolenaar
1aeddeb8bd patch 8.2.3142: Vim9: type check for has_key() argument is too strict
Problem:    Vim9: type check for has_key() argument is too strict.
Solution:   Also allow for a number key argument. (closes #8542)
2021-07-11 14:55:49 +02:00
Martin Tournoij
de69a7353e patch 8.2.3141: no error when using :complete for :command without -nargs
Problem:    No error when using :complete for :command without -nargs.
Solution:   Give an error. (Martin Tournoij, closes #8544, closes #8541)
2021-07-11 14:28:25 +02:00
Bram Moolenaar
482d2f37a5 patch 8.2.3140: MS-Windows: ipv6 channel test is very flaky also without GUI
Problem:    MS-Windows: ipv6 channel test is very flaky also without the GUI.
Solution:   Skip the test also without the GUI.
2021-07-10 22:21:40 +02:00
Yegappan Lakshmanan
a2438132a6 patch 8.2.3139: functions for string manipulation are spread out
Problem:    Functions for string manipulation are spread out.
Solution:   Move string related functions to a new source file. (Yegappan
            Lakshmanan, closes #8470)
2021-07-10 21:29:18 +02:00
Bram Moolenaar
31e21766d6 patch 8.2.3138: debugger test fails
Problem:    Debugger test fails.
Solution:   Adjust eval command.
2021-07-10 20:43:59 +02:00
Bram Moolenaar
c323527d67 patch 8.2.3137: Vim9: no error when a line only has a variable name
Problem:    Vim9: no error when a line only has a variable name.
Solution:   Give an error when an expression is evaluated without an effect.
            (closes #8538)
2021-07-10 19:42:03 +02:00
40 changed files with 2250 additions and 1722 deletions

View File

@@ -134,6 +134,7 @@ SRC_ALL = \
src/spell.h \
src/spellfile.c \
src/spellsuggest.c \
src/strings.c \
src/structs.h \
src/syntax.c \
src/tag.c \
@@ -296,6 +297,7 @@ SRC_ALL = \
src/proto/spell.pro \
src/proto/spellfile.pro \
src/proto/spellsuggest.pro \
src/proto/strings.pro \
src/proto/syntax.pro \
src/proto/tag.pro \
src/proto/term.pro \

View File

@@ -162,6 +162,7 @@ SRC += \
spell.c \
spellfile.c \
spellsuggest.c \
strings.c \
syntax.c \
tag.c \
term.c \

View File

@@ -809,6 +809,7 @@ OBJ = \
$(OUTDIR)/spell.o \
$(OUTDIR)/spellfile.o \
$(OUTDIR)/spellsuggest.o \
$(OUTDIR)/strings.o \
$(OUTDIR)/syntax.o \
$(OUTDIR)/tag.o \
$(OUTDIR)/term.o \

View File

@@ -819,6 +819,7 @@ OBJ = \
$(OUTDIR)\spell.obj \
$(OUTDIR)\spellfile.obj \
$(OUTDIR)\spellsuggest.obj \
$(OUTDIR)\strings.obj \
$(OUTDIR)\syntax.obj \
$(OUTDIR)\tag.obj \
$(OUTDIR)\term.obj \
@@ -1792,6 +1793,8 @@ $(OUTDIR)/spellfile.obj: $(OUTDIR) spellfile.c $(INCL)
$(OUTDIR)/spellsuggest.obj: $(OUTDIR) spellsuggest.c $(INCL)
$(OUTDIR)/strings.obj: $(OUTDIR) strings.c $(INCL)
$(OUTDIR)/syntax.obj: $(OUTDIR) syntax.c $(INCL)
$(OUTDIR)/tag.obj: $(OUTDIR) tag.c $(INCL)
@@ -2012,6 +2015,7 @@ proto.h: \
proto/spell.pro \
proto/spellfile.pro \
proto/spellsuggest.pro \
proto/strings.pro \
proto/syntax.pro \
proto/tag.pro \
proto/term.pro \

View File

@@ -393,6 +393,7 @@ SRC = \
spell.c \
spellfile.c \
spellsuggest.c \
strings.c \
syntax.c \
tag.c \
term.c \
@@ -512,6 +513,7 @@ OBJ = \
spell.obj \
spellfile.obj \
spellsuggest.obj \
strings.obj \
syntax.obj \
tag.obj \
term.obj \
@@ -1048,6 +1050,10 @@ spellsuggest.obj : spellsuggest.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
proto.h errors.h globals.h
strings.obj : strings.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h option.h structs.h \
regexp.h gui.h beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h \
proto.h errors.h globals.h
syntax.obj : syntax.c vim.h [.auto]config.h feature.h os_unix.h \
ascii.h keymap.h term.h macros.h structs.h regexp.h \
gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \

View File

@@ -1677,6 +1677,7 @@ BASIC_SRC = \
spell.c \
spellfile.c \
spellsuggest.c \
strings.c \
syntax.c \
tag.c \
term.c \
@@ -1828,6 +1829,7 @@ OBJ_COMMON = \
objects/spell.o \
objects/spellfile.o \
objects/spellsuggest.o \
objects/strings.o \
objects/syntax.o \
objects/tag.o \
objects/term.o \
@@ -2011,6 +2013,7 @@ PRO_AUTO = \
spell.pro \
spellfile.pro \
spellsuggest.pro \
strings.pro \
syntax.pro \
tag.pro \
term.pro \
@@ -3516,6 +3519,9 @@ objects/spellfile.o: spellfile.c
objects/spellsuggest.o: spellsuggest.c
$(CCC) -o $@ spellsuggest.c
objects/strings.o: strings.c
$(CCC) -o $@ strings.c
objects/syntax.o: syntax.c
$(CCC) -o $@ syntax.c
@@ -4049,6 +4055,10 @@ objects/spellsuggest.o: spellsuggest.c vim.h protodef.h auto/config.h feature.h
os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
proto.h errors.h globals.h
objects/strings.o: strings.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
proto.h errors.h globals.h
objects/syntax.o: syntax.c vim.h protodef.h auto/config.h feature.h os_unix.h \
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \

View File

@@ -80,6 +80,7 @@ sign.c | signs
spell.c | spell checking core
spellfile.c | spell file handling
spellsuggest.c | spell correction suggestions
strings.c | string manipulation functions
syntax.c | syntax and other highlighting
tag.c | tags
term.c | terminal handling, termcap codes

View File

@@ -494,3 +494,9 @@ EXTERN char e_no_white_space_allowed_between_option_and[]
INIT(= N_("E1205: No white space allowed between option and"));
EXTERN char e_dict_required_for_argument_nr[]
INIT(= N_("E1206: Dictionary required for argument %d"));
EXTERN char e_expression_without_effect_str[]
INIT(= N_("E1207: Expression without an effect: %s"));
EXTERN char e_complete_used_without_nargs[]
INIT(= N_("E1208: -complete used without -nargs"));
EXTERN char e_invalid_value_for_line_number_str[]
INIT(= N_("E1209: Invalid value for a line number: \"%s\""));

View File

@@ -57,6 +57,7 @@ static int eval7_leader(typval_T *rettv, int numeric_only, char_u *start_leader,
static int free_unref_items(int copyID);
static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
static char_u *eval_next_line(evalarg_T *evalarg);
/*
* Return "n1" divided by "n2", taking care of dividing by zero.
@@ -2113,7 +2114,7 @@ getline_peek_skip_comments(evalarg_T *evalarg)
* FALSE.
* "arg" must point somewhere inside a line, not at the start.
*/
char_u *
static char_u *
eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
{
char_u *p = skipwhite(arg);
@@ -2144,7 +2145,7 @@ eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext)
* To be called after eval_next_non_blank() sets "getnext" to TRUE.
* Only called for Vim9 script.
*/
char_u *
static char_u *
eval_next_line(evalarg_T *evalarg)
{
garray_T *gap = &evalarg->eval_ga;
@@ -5171,50 +5172,6 @@ echo_string(
return echo_string_core(tv, tofree, numbuf, copyID, TRUE, FALSE, FALSE);
}
/*
* Return string "str" in ' quotes, doubling ' characters.
* If "str" is NULL an empty string is assumed.
* If "function" is TRUE make it function('string').
*/
char_u *
string_quote(char_u *str, int function)
{
unsigned len;
char_u *p, *r, *s;
len = (function ? 13 : 3);
if (str != NULL)
{
len += (unsigned)STRLEN(str);
for (p = str; *p != NUL; MB_PTR_ADV(p))
if (*p == '\'')
++len;
}
s = r = alloc(len);
if (r != NULL)
{
if (function)
{
STRCPY(r, "function('");
r += 10;
}
else
*r++ = '\'';
if (str != NULL)
for (p = str; *p != NUL; )
{
if (*p == '\'')
*r++ = '\'';
MB_COPY_CHAR(p, r);
}
*r++ = '\'';
if (function)
*r++ = ')';
*r++ = NUL;
}
return s;
}
/*
* Convert the specified byte index of line 'lnum' in buffer 'buf' to a
* character index. Works only for loaded buffers. Returns -1 on failure.
@@ -5419,6 +5376,8 @@ var2fpos(
}
return &pos;
}
if (in_vim9script())
semsg(_(e_invalid_value_for_line_number_str), name);
return NULL;
}
@@ -6232,6 +6191,7 @@ ex_execute(exarg_T *eap)
char_u *p;
garray_T ga;
int len;
long start_lnum = SOURCING_LNUM;
ga_init2(&ga, 1, 80);
@@ -6285,6 +6245,9 @@ ex_execute(exarg_T *eap)
if (ret != FAIL && ga.ga_data != NULL)
{
// use the first line of continuation lines for messages
SOURCING_LNUM = start_lnum;
if (eap->cmdidx == CMD_echomsg || eap->cmdidx == CMD_echoerr)
{
// Mark the already saved text as finishing the line, so that what

File diff suppressed because it is too large Load Diff

View File

@@ -2660,7 +2660,8 @@ eval_variable(
}
else if (rettv != NULL)
{
if (ht != NULL && ht == get_script_local_ht())
if (ht != NULL && ht == get_script_local_ht()
&& tv != &SCRIPT_SV(current_sctx.sc_sid)->sv_var.di_tv)
{
svar_T *sv = find_typval_in_script(tv);

View File

@@ -208,7 +208,7 @@ cause_errthrow(
* not skipped. Errors in those commands may affect what of the subsequent
* commands are regarded part of catch and finally clauses. Catching the
* exception would then cause execution of commands not intended by the
* user, who wouldn't even get aware of the problem. Therefor, discard the
* user, who wouldn't even get aware of the problem. Therefore, discard the
* exception currently being thrown to prevent it from being caught. Just
* execute finally clauses and terminate.
*/
@@ -896,11 +896,28 @@ ex_eval(exarg_T *eap)
{
typval_T tv;
evalarg_T evalarg;
int name_only = FALSE;
char_u *p;
long lnum = SOURCING_LNUM;
if (in_vim9script())
{
char_u *alias;
p = eap->arg;
get_name_len(&p, &alias, FALSE, FALSE);
name_only = ends_excmd2(eap->arg, skipwhite(p));
vim_free(alias);
}
fill_evalarg_from_eap(&evalarg, eap, eap->skip);
if (eval0(eap->arg, &tv, eap, &evalarg) == OK)
{
clear_tv(&tv);
if (in_vim9script() && name_only && lnum == SOURCING_LNUM)
semsg(_(e_expression_without_effect_str), eap->arg);
}
clear_evalarg(&evalarg, eap);
}
@@ -1287,7 +1304,7 @@ ex_continue(exarg_T *eap)
{
// Try to find the matching ":while". This might stop at a try
// conditional not in its finally clause (which is then to be executed
// next). Therefor, inactivate all conditionals except the ":while"
// next). Therefore, inactivate all conditionals except the ":while"
// itself (if reached).
idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, FALSE);
if (idx >= 0 && (cstack->cs_flags[idx] & (CSF_WHILE | CSF_FOR)))

View File

@@ -4961,6 +4961,37 @@ f_getimstatus(typval_T *argvars UNUSED, typval_T *rettv)
rettv->vval.v_number = im_get_status();
# endif
}
/*
* iconv() function
*/
void
f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
{
char_u buf1[NUMBUFLEN];
char_u buf2[NUMBUFLEN];
char_u *from, *to, *str;
vimconv_T vimconv;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
str = tv_get_string(&argvars[0]);
from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
vimconv.vc_type = CONV_NONE;
convert_setup(&vimconv, from, to);
// If the encodings are equal, no conversion needed.
if (vimconv.vc_type == CONV_NONE)
rettv->vval.v_string = vim_strsave(str);
else
rettv->vval.v_string = string_convert(&vimconv, str, NULL);
convert_setup(&vimconv, NULL, NULL);
vim_free(from);
vim_free(to);
}
#endif
/*

View File

@@ -3613,6 +3613,12 @@ verbose_open(void)
*/
void
give_warning(char_u *message, int hl)
{
give_warning_with_source(message, hl, FALSE);
}
void
give_warning_with_source(char_u *message, int hl, int with_source)
{
// Don't do this for ":silent".
if (msg_silent != 0)
@@ -3629,8 +3635,21 @@ give_warning(char_u *message, int hl)
keep_msg_attr = HL_ATTR(HLF_W);
else
keep_msg_attr = 0;
if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0)
if (with_source)
{
// Do what msg() does, but with a column offset if the warning should
// be after the mode message.
msg_start();
msg_source(HL_ATTR(HLF_W));
msg_puts(" ");
msg_puts_attr((char *)message, HL_ATTR(HLF_W) | MSG_HIST);
msg_clr_eos();
(void)msg_end();
}
else if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0)
set_keep_msg(message, keep_msg_attr);
msg_didout = FALSE; // overwrite this message
msg_nowait = TRUE; // don't wait for this message
msg_col = 0;

View File

@@ -695,7 +695,8 @@ f_mode(typval_T *argvars, typval_T *rettv)
if (finish_op)
{
buf[1] = 'o';
// to be able to detect force-linewise/blockwise/characterwise operations
// to be able to detect force-linewise/blockwise/characterwise
// operations
buf[2] = motion_force;
}
else if (restart_edit == 'I' || restart_edit == 'R'
@@ -2099,29 +2100,6 @@ match_user(char_u *name)
return result;
}
/*
* Concatenate two strings and return the result in allocated memory.
* Returns NULL when out of memory.
*/
char_u *
concat_str(char_u *str1, char_u *str2)
{
char_u *dest;
size_t l = str1 == NULL ? 0 : STRLEN(str1);
dest = alloc(l + (str2 == NULL ? 0 : STRLEN(str2)) + 1L);
if (dest != NULL)
{
if (str1 == NULL)
*dest = NUL;
else
STRCPY(dest, str1);
if (str2 != NULL)
STRCPY(dest + l, str2);
}
return dest;
}
static void
prepare_to_exit(void)
{
@@ -2622,8 +2600,8 @@ path_is_url(char_u *p)
}
/*
* Check if "fname" starts with "name://". Return URL_SLASH if it does.
* Return URL_BACKSLASH for "name:\\".
* Check if "fname" starts with "name://" or "name:\\".
* Return URL_SLASH for "name://", URL_BACKSLASH for "name:\\".
* Return zero otherwise.
*/
int
@@ -2631,7 +2609,22 @@ path_with_url(char_u *fname)
{
char_u *p;
for (p = fname; isalpha(*p); ++p)
// We accept alphabetic characters and a dash in scheme part.
// RFC 3986 allows for more, but it increases the risk of matching
// non-URL text.
// first character must be alpha
if (!isalpha(*fname))
return 0;
// check body: alpha or dash
for (p = fname; (isalpha(*p) || (*p == '-')); ++p)
;
// check last char is not a dash
if (p[-1] == '-')
return 0;
// "://" or ":\\" must follow
return path_is_url(p);
}

View File

@@ -1267,42 +1267,6 @@ free_all_mem(void)
}
#endif
/*
* Copy "string" into newly allocated memory.
*/
char_u *
vim_strsave(char_u *string)
{
char_u *p;
size_t len;
len = STRLEN(string) + 1;
p = alloc(len);
if (p != NULL)
mch_memmove(p, string, len);
return p;
}
/*
* Copy up to "len" bytes of "string" into newly allocated memory and
* terminate with a NUL.
* The allocated memory always has size "len + 1", also when "string" is
* shorter.
*/
char_u *
vim_strnsave(char_u *string, size_t len)
{
char_u *p;
p = alloc(len + 1);
if (p != NULL)
{
STRNCPY(p, string, len);
p[len] = NUL;
}
return p;
}
/*
* Copy "p[len]" into allocated memory, ignoring NUL characters.
* Returns NULL when out of memory.
@@ -1317,465 +1281,6 @@ vim_memsave(char_u *p, size_t len)
return ret;
}
/*
* Same as vim_strsave(), but any characters found in esc_chars are preceded
* by a backslash.
*/
char_u *
vim_strsave_escaped(char_u *string, char_u *esc_chars)
{
return vim_strsave_escaped_ext(string, esc_chars, '\\', FALSE);
}
/*
* Same as vim_strsave_escaped(), but when "bsl" is TRUE also escape
* characters where rem_backslash() would remove the backslash.
* Escape the characters with "cc".
*/
char_u *
vim_strsave_escaped_ext(
char_u *string,
char_u *esc_chars,
int cc,
int bsl)
{
char_u *p;
char_u *p2;
char_u *escaped_string;
unsigned length;
int l;
/*
* First count the number of backslashes required.
* Then allocate the memory and insert them.
*/
length = 1; // count the trailing NUL
for (p = string; *p; p++)
{
if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
{
length += l; // count a multibyte char
p += l - 1;
continue;
}
if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
++length; // count a backslash
++length; // count an ordinary char
}
escaped_string = alloc(length);
if (escaped_string != NULL)
{
p2 = escaped_string;
for (p = string; *p; p++)
{
if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
{
mch_memmove(p2, p, (size_t)l);
p2 += l;
p += l - 1; // skip multibyte char
continue;
}
if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
*p2++ = cc;
*p2++ = *p;
}
*p2 = NUL;
}
return escaped_string;
}
/*
* Return TRUE when 'shell' has "csh" in the tail.
*/
int
csh_like_shell(void)
{
return (strstr((char *)gettail(p_sh), "csh") != NULL);
}
/*
* Escape "string" for use as a shell argument with system().
* This uses single quotes, except when we know we need to use double quotes
* (MS-DOS and MS-Windows not using PowerShell and without 'shellslash' set).
* PowerShell also uses a novel escaping for enclosed single quotes - double
* them up.
* Escape a newline, depending on the 'shell' option.
* When "do_special" is TRUE also replace "!", "%", "#" and things starting
* with "<" like "<cfile>".
* When "do_newline" is FALSE do not escape newline unless it is csh shell.
* Returns the result in allocated memory, NULL if we have run out.
*/
char_u *
vim_strsave_shellescape(char_u *string, int do_special, int do_newline)
{
unsigned length;
char_u *p;
char_u *d;
char_u *escaped_string;
int l;
int csh_like;
char_u *shname;
int powershell;
# ifdef MSWIN
int double_quotes;
# endif
// Only csh and similar shells expand '!' within single quotes. For sh and
// the like we must not put a backslash before it, it will be taken
// literally. If do_special is set the '!' will be escaped twice.
// Csh also needs to have "\n" escaped twice when do_special is set.
csh_like = csh_like_shell();
// PowerShell uses it's own version for quoting single quotes
shname = gettail(p_sh);
powershell = strstr((char *)shname, "pwsh") != NULL;
# ifdef MSWIN
powershell = powershell || strstr((char *)shname, "powershell") != NULL;
// PowerShell only accepts single quotes so override shellslash.
double_quotes = !powershell && !p_ssl;
# endif
// First count the number of extra bytes required.
length = (unsigned)STRLEN(string) + 3; // two quotes and a trailing NUL
for (p = string; *p != NUL; MB_PTR_ADV(p))
{
# ifdef MSWIN
if (double_quotes)
{
if (*p == '"')
++length; // " -> ""
}
else
# endif
if (*p == '\'')
{
if (powershell)
length +=2; // ' => ''
else
length += 3; // ' => '\''
}
if ((*p == '\n' && (csh_like || do_newline))
|| (*p == '!' && (csh_like || do_special)))
{
++length; // insert backslash
if (csh_like && do_special)
++length; // insert backslash
}
if (do_special && find_cmdline_var(p, &l) >= 0)
{
++length; // insert backslash
p += l - 1;
}
}
// Allocate memory for the result and fill it.
escaped_string = alloc(length);
if (escaped_string != NULL)
{
d = escaped_string;
// add opening quote
# ifdef MSWIN
if (double_quotes)
*d++ = '"';
else
# endif
*d++ = '\'';
for (p = string; *p != NUL; )
{
# ifdef MSWIN
if (double_quotes)
{
if (*p == '"')
{
*d++ = '"';
*d++ = '"';
++p;
continue;
}
}
else
# endif
if (*p == '\'')
{
if (powershell)
{
*d++ = '\'';
*d++ = '\'';
}
else
{
*d++ = '\'';
*d++ = '\\';
*d++ = '\'';
*d++ = '\'';
}
++p;
continue;
}
if ((*p == '\n' && (csh_like || do_newline))
|| (*p == '!' && (csh_like || do_special)))
{
*d++ = '\\';
if (csh_like && do_special)
*d++ = '\\';
*d++ = *p++;
continue;
}
if (do_special && find_cmdline_var(p, &l) >= 0)
{
*d++ = '\\'; // insert backslash
while (--l >= 0) // copy the var
*d++ = *p++;
continue;
}
MB_COPY_CHAR(p, d);
}
// add terminating quote and finish with a NUL
# ifdef MSWIN
if (double_quotes)
*d++ = '"';
else
# endif
*d++ = '\'';
*d = NUL;
}
return escaped_string;
}
/*
* Like vim_strsave(), but make all characters uppercase.
* This uses ASCII lower-to-upper case translation, language independent.
*/
char_u *
vim_strsave_up(char_u *string)
{
char_u *p1;
p1 = vim_strsave(string);
vim_strup(p1);
return p1;
}
/*
* Like vim_strnsave(), but make all characters uppercase.
* This uses ASCII lower-to-upper case translation, language independent.
*/
char_u *
vim_strnsave_up(char_u *string, size_t len)
{
char_u *p1;
p1 = vim_strnsave(string, len);
vim_strup(p1);
return p1;
}
/*
* ASCII lower-to-upper case translation, language independent.
*/
void
vim_strup(
char_u *p)
{
char_u *p2;
int c;
if (p != NULL)
{
p2 = p;
while ((c = *p2) != NUL)
#ifdef EBCDIC
*p2++ = isalpha(c) ? toupper(c) : c;
#else
*p2++ = (c < 'a' || c > 'z') ? c : (c - 0x20);
#endif
}
}
#if defined(FEAT_EVAL) || defined(FEAT_SPELL) || defined(PROTO)
/*
* Make string "s" all upper-case and return it in allocated memory.
* Handles multi-byte characters as well as possible.
* Returns NULL when out of memory.
*/
char_u *
strup_save(char_u *orig)
{
char_u *p;
char_u *res;
res = p = vim_strsave(orig);
if (res != NULL)
while (*p != NUL)
{
int l;
if (enc_utf8)
{
int c, uc;
int newl;
char_u *s;
c = utf_ptr2char(p);
l = utf_ptr2len(p);
if (c == 0)
{
// overlong sequence, use only the first byte
c = *p;
l = 1;
}
uc = utf_toupper(c);
// Reallocate string when byte count changes. This is rare,
// thus it's OK to do another malloc()/free().
newl = utf_char2len(uc);
if (newl != l)
{
s = alloc(STRLEN(res) + 1 + newl - l);
if (s == NULL)
{
vim_free(res);
return NULL;
}
mch_memmove(s, res, p - res);
STRCPY(s + (p - res) + newl, p + l);
p = s + (p - res);
vim_free(res);
res = s;
}
utf_char2bytes(uc, p);
p += newl;
}
else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
p += l; // skip multi-byte character
else
{
*p = TOUPPER_LOC(*p); // note that toupper() can be a macro
p++;
}
}
return res;
}
/*
* Make string "s" all lower-case and return it in allocated memory.
* Handles multi-byte characters as well as possible.
* Returns NULL when out of memory.
*/
char_u *
strlow_save(char_u *orig)
{
char_u *p;
char_u *res;
res = p = vim_strsave(orig);
if (res != NULL)
while (*p != NUL)
{
int l;
if (enc_utf8)
{
int c, lc;
int newl;
char_u *s;
c = utf_ptr2char(p);
l = utf_ptr2len(p);
if (c == 0)
{
// overlong sequence, use only the first byte
c = *p;
l = 1;
}
lc = utf_tolower(c);
// Reallocate string when byte count changes. This is rare,
// thus it's OK to do another malloc()/free().
newl = utf_char2len(lc);
if (newl != l)
{
s = alloc(STRLEN(res) + 1 + newl - l);
if (s == NULL)
{
vim_free(res);
return NULL;
}
mch_memmove(s, res, p - res);
STRCPY(s + (p - res) + newl, p + l);
p = s + (p - res);
vim_free(res);
res = s;
}
utf_char2bytes(lc, p);
p += newl;
}
else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
p += l; // skip multi-byte character
else
{
*p = TOLOWER_LOC(*p); // note that tolower() can be a macro
p++;
}
}
return res;
}
#endif
/*
* delete spaces at the end of a string
*/
void
del_trailing_spaces(char_u *ptr)
{
char_u *q;
q = ptr + STRLEN(ptr);
while (--q > ptr && VIM_ISWHITE(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V)
*q = NUL;
}
/*
* Like strncpy(), but always terminate the result with one NUL.
* "to" must be "len + 1" long!
*/
void
vim_strncpy(char_u *to, char_u *from, size_t len)
{
STRNCPY(to, from, len);
to[len] = NUL;
}
/*
* Like strcat(), but make sure the result fits in "tosize" bytes and is
* always NUL terminated. "from" and "to" may overlap.
*/
void
vim_strcat(char_u *to, char_u *from, size_t tosize)
{
size_t tolen = STRLEN(to);
size_t fromlen = STRLEN(from);
if (tolen + fromlen + 1 > tosize)
{
mch_memmove(to + tolen, from, tosize - tolen - 1);
to[tosize - 1] = NUL;
}
else
mch_memmove(to + tolen, from, fromlen + 1);
}
/*
* Isolate one part of a string option where parts are separated with
* "sep_chars".
@@ -1848,180 +1353,6 @@ vim_memset(void *ptr, int c, size_t size)
}
#endif
#if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) || defined(PROTO)
/*
* Compare two strings, ignoring case, using current locale.
* Doesn't work for multi-byte characters.
* return 0 for match, < 0 for smaller, > 0 for bigger
*/
int
vim_stricmp(char *s1, char *s2)
{
int i;
for (;;)
{
i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
if (i != 0)
return i; // this character different
if (*s1 == NUL)
break; // strings match until NUL
++s1;
++s2;
}
return 0; // strings match
}
#endif
#if (!defined(HAVE_STRNCASECMP) && !defined(HAVE_STRNICMP)) || defined(PROTO)
/*
* Compare two strings, for length "len", ignoring case, using current locale.
* Doesn't work for multi-byte characters.
* return 0 for match, < 0 for smaller, > 0 for bigger
*/
int
vim_strnicmp(char *s1, char *s2, size_t len)
{
int i;
while (len > 0)
{
i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
if (i != 0)
return i; // this character different
if (*s1 == NUL)
break; // strings match until NUL
++s1;
++s2;
--len;
}
return 0; // strings match
}
#endif
/*
* Search for first occurrence of "c" in "string".
* Version of strchr() that handles unsigned char strings with characters from
* 128 to 255 correctly. It also doesn't return a pointer to the NUL at the
* end of the string.
*/
char_u *
vim_strchr(char_u *string, int c)
{
char_u *p;
int b;
p = string;
if (enc_utf8 && c >= 0x80)
{
while (*p != NUL)
{
int l = utfc_ptr2len(p);
// Avoid matching an illegal byte here.
if (utf_ptr2char(p) == c && l > 1)
return p;
p += l;
}
return NULL;
}
if (enc_dbcs != 0 && c > 255)
{
int n2 = c & 0xff;
c = ((unsigned)c >> 8) & 0xff;
while ((b = *p) != NUL)
{
if (b == c && p[1] == n2)
return p;
p += (*mb_ptr2len)(p);
}
return NULL;
}
if (has_mbyte)
{
while ((b = *p) != NUL)
{
if (b == c)
return p;
p += (*mb_ptr2len)(p);
}
return NULL;
}
while ((b = *p) != NUL)
{
if (b == c)
return p;
++p;
}
return NULL;
}
/*
* Version of strchr() that only works for bytes and handles unsigned char
* strings with characters above 128 correctly. It also doesn't return a
* pointer to the NUL at the end of the string.
*/
char_u *
vim_strbyte(char_u *string, int c)
{
char_u *p = string;
while (*p != NUL)
{
if (*p == c)
return p;
++p;
}
return NULL;
}
/*
* Search for last occurrence of "c" in "string".
* Version of strrchr() that handles unsigned char strings with characters from
* 128 to 255 correctly. It also doesn't return a pointer to the NUL at the
* end of the string.
* Return NULL if not found.
* Does not handle multi-byte char for "c"!
*/
char_u *
vim_strrchr(char_u *string, int c)
{
char_u *retval = NULL;
char_u *p = string;
while (*p)
{
if (*p == c)
retval = p;
MB_PTR_ADV(p);
}
return retval;
}
/*
* Vim's version of strpbrk(), in case it's missing.
* Don't generate a prototype for this, causes problems when it's not used.
*/
#ifndef PROTO
# ifndef HAVE_STRPBRK
# ifdef vim_strpbrk
# undef vim_strpbrk
# endif
char_u *
vim_strpbrk(char_u *s, char_u *charset)
{
while (*s)
{
if (vim_strchr(charset, *s) != NULL)
return s;
MB_PTR_ADV(s);
}
return NULL;
}
# endif
#endif
/*
* Vim has its own isspace() function, because on some machines isspace()
* can't handle characters above 128.
@@ -3974,25 +3305,6 @@ qsort(
}
#endif
/*
* Sort an array of strings.
*/
static int sort_compare(const void *s1, const void *s2);
static int
sort_compare(const void *s1, const void *s2)
{
return STRCMP(*(char **)s1, *(char **)s2);
}
void
sort_strings(
char_u **files,
int count)
{
qsort((void *)files, (size_t)count, sizeof(char_u *), sort_compare);
}
/*
* The putenv() implementation below comes from the "screen" program.
* Included with permission from Juergen Weigert.
@@ -4304,24 +3616,6 @@ put_bytes(FILE *fd, long_u nr, int len)
#endif
#if defined(FEAT_QUICKFIX) || defined(FEAT_SPELL) || defined(PROTO)
/*
* Return TRUE if string "s" contains a non-ASCII character (128 or higher).
* When "s" is NULL FALSE is returned.
*/
int
has_non_ascii(char_u *s)
{
char_u *p;
if (s != NULL)
for (p = s; *p != NUL; ++p)
if (*p >= 128)
return TRUE;
return FALSE;
}
#endif
#ifndef PROTO // proto is defined in vim.h
# ifdef ELAPSED_TIMEVAL
/*

View File

@@ -211,6 +211,7 @@ void mbyte_im_set_active(int active_arg);
# include "spell.pro"
# include "spellfile.pro"
# include "spellsuggest.pro"
# include "strings.pro"
# include "syntax.pro"
# include "tag.pro"
# include "term.pro"

View File

@@ -32,8 +32,6 @@ int next_for_item(void *fi_void, char_u *arg);
void free_for_info(void *fi_void);
void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
int pattern_match(char_u *pat, char_u *text, int ic);
char_u *eval_next_non_blank(char_u *arg, evalarg_T *evalarg, int *getnext);
char_u *eval_next_line(evalarg_T *evalarg);
char_u *skipwhite_and_linebreak(char_u *arg, evalarg_T *evalarg);
void clear_evalarg(evalarg_T *evalarg, exarg_T *eap);
int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg);
@@ -55,7 +53,6 @@ int set_ref_in_list_items(list_T *l, int copyID, ht_stack_T **ht_stack);
int set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_T **list_stack);
char_u *echo_string_core(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID, int echo_style, int restore_copyID, int composite_val);
char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
char_u *string_quote(char_u *str, int function);
int buf_byteidx_to_charidx(buf_T *buf, int lnum, int byteidx);
int buf_charidx_to_byteidx(buf_T *buf, int lnum, int charidx);
pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum, int charcol);

View File

@@ -23,5 +23,4 @@ int dynamic_feature(char_u *feature);
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
void range_list_materialize(list_T *list);
long do_searchpair(char_u *spat, char_u *mpat, char_u *epat, int dir, typval_T *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long time_limit);
void f_string(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */

View File

@@ -86,4 +86,5 @@ char_u *string_convert(vimconv_T *vcp, char_u *ptr, int *lenp);
char_u *string_convert_ext(vimconv_T *vcp, char_u *ptr, int *lenp, int *unconvlenp);
void f_setcellwidths(typval_T *argvars, typval_T *rettv);
void f_charclass(typval_T *argvars, typval_T *rettv);
void f_iconv(typval_T *argvars UNUSED, typval_T *rettv);
/* vim: set ft=c : */

View File

@@ -69,6 +69,7 @@ void verbose_leave_scroll(void);
void verbose_stop(void);
int verbose_open(void);
void give_warning(char_u *message, int hl);
void give_warning_with_source(char_u *message, int hl, int with_source);
void give_warning2(char_u *message, char_u *a1, int hl);
void msg_advance(int col);
int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd);

View File

@@ -36,7 +36,6 @@ void vim_setenv(char_u *name, char_u *val);
char_u *get_env_name(expand_T *xp, int idx);
char_u *get_users(expand_T *xp, int idx);
int match_user(char_u *name);
char_u *concat_str(char_u *str1, char_u *str2);
void preserve_exit(void);
void line_breakcheck(void);
void fast_breakcheck(void);

View File

@@ -31,28 +31,9 @@ void *lalloc_id(size_t size, int message, alloc_id_T id);
void *mem_realloc(void *ptr, size_t size);
void do_outofmem_msg(size_t size);
void free_all_mem(void);
char_u *vim_strsave(char_u *string);
char_u *vim_strnsave(char_u *string, size_t len);
char_u *vim_memsave(char_u *p, size_t len);
char_u *vim_strsave_escaped(char_u *string, char_u *esc_chars);
char_u *vim_strsave_escaped_ext(char_u *string, char_u *esc_chars, int cc, int bsl);
int csh_like_shell(void);
char_u *vim_strsave_shellescape(char_u *string, int do_special, int do_newline);
char_u *vim_strsave_up(char_u *string);
char_u *vim_strnsave_up(char_u *string, size_t len);
void vim_strup(char_u *p);
char_u *strup_save(char_u *orig);
char_u *strlow_save(char_u *orig);
void del_trailing_spaces(char_u *ptr);
void vim_strncpy(char_u *to, char_u *from, size_t len);
void vim_strcat(char_u *to, char_u *from, size_t tosize);
int copy_option_part(char_u **option, char_u *buf, int maxlen, char *sep_chars);
void vim_free(void *x);
int vim_stricmp(char *s1, char *s2);
int vim_strnicmp(char *s1, char *s2, size_t len);
char_u *vim_strchr(char_u *string, int c);
char_u *vim_strbyte(char_u *string, int c);
char_u *vim_strrchr(char_u *string, int c);
int vim_isspace(int x);
void ga_clear(garray_T *gap);
void ga_clear_strings(garray_T *gap);
@@ -93,14 +74,12 @@ int get_shape_idx(int mouse);
void update_mouseshape(int shape_idx);
int vim_chdir(char_u *new_dir);
int get_user_name(char_u *buf, int len);
void sort_strings(char_u **files, int count);
int filewritable(char_u *fname);
int get2c(FILE *fd);
int get3c(FILE *fd);
int get4c(FILE *fd);
char_u *read_string(FILE *fd, int cnt);
int put_bytes(FILE *fd, long_u nr, int len);
int has_non_ascii(char_u *s);
int mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc);
int build_argv_from_string(char_u *cmd, char ***argv, int *argc);
int build_argv_from_list(list_T *l, char ***argv, int *argc);

45
src/proto/strings.pro Normal file
View File

@@ -0,0 +1,45 @@
/* strings.c */
char_u *vim_strsave(char_u *string);
char_u *vim_strnsave(char_u *string, size_t len);
char_u *vim_strsave_escaped(char_u *string, char_u *esc_chars);
char_u *vim_strsave_escaped_ext(char_u *string, char_u *esc_chars, int cc, int bsl);
int csh_like_shell(void);
char_u *vim_strsave_shellescape(char_u *string, int do_special, int do_newline);
char_u *vim_strsave_up(char_u *string);
char_u *vim_strnsave_up(char_u *string, size_t len);
void vim_strup(char_u *p);
char_u *strlow_save(char_u *orig);
void del_trailing_spaces(char_u *ptr);
void vim_strncpy(char_u *to, char_u *from, size_t len);
void vim_strcat(char_u *to, char_u *from, size_t tosize);
int vim_stricmp(char *s1, char *s2);
int vim_strnicmp(char *s1, char *s2, size_t len);
char_u *vim_strchr(char_u *string, int c);
char_u *vim_strbyte(char_u *string, int c);
char_u *vim_strrchr(char_u *string, int c);
void sort_strings(char_u **files, int count);
int has_non_ascii(char_u *s);
char_u *concat_str(char_u *str1, char_u *str2);
char_u *string_quote(char_u *str, int function);
void f_byteidx(typval_T *argvars, typval_T *rettv);
void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
void f_charidx(typval_T *argvars, typval_T *rettv);
void f_str2list(typval_T *argvars, typval_T *rettv);
void f_str2nr(typval_T *argvars, typval_T *rettv);
void f_strgetchar(typval_T *argvars, typval_T *rettv);
void f_stridx(typval_T *argvars, typval_T *rettv);
void f_string(typval_T *argvars, typval_T *rettv);
void f_strlen(typval_T *argvars, typval_T *rettv);
void f_strcharlen(typval_T *argvars, typval_T *rettv);
void f_strchars(typval_T *argvars, typval_T *rettv);
void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
void f_strwidth(typval_T *argvars, typval_T *rettv);
void f_strcharpart(typval_T *argvars, typval_T *rettv);
void f_strpart(typval_T *argvars, typval_T *rettv);
void f_strridx(typval_T *argvars, typval_T *rettv);
void f_strtrans(typval_T *argvars, typval_T *rettv);
void f_tolower(typval_T *argvars, typval_T *rettv);
void f_toupper(typval_T *argvars, typval_T *rettv);
void f_tr(typval_T *argvars, typval_T *rettv);
void f_trim(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */

1563
src/strings.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -381,6 +381,35 @@ func Test_balt()
call assert_equal('OtherBuffer', bufname())
endfunc
" Test for buffer match URL(scheme) check
" scheme is alpha and inner hyphen only.
func Test_buffer_scheme()
CheckMSWindows
set noshellslash
%bwipe!
let bufnames = [
\ #{id: 'b0', name: 'test://xyz/foo/b0' , match: 1},
\ #{id: 'b1', name: 'test+abc://xyz/foo/b1', match: 0},
\ #{id: 'b2', name: 'test_abc://xyz/foo/b2', match: 0},
\ #{id: 'b3', name: 'test-abc://xyz/foo/b3', match: 1},
\ #{id: 'b4', name: '-test://xyz/foo/b4' , match: 0},
\ #{id: 'b5', name: 'test-://xyz/foo/b5' , match: 0},
\]
for buf in bufnames
new `=buf.name`
if buf.match
call assert_equal(buf.name, getbufinfo(buf.id)[0].name)
else
" slashes will have become backslashes
call assert_notequal(buf.name, getbufinfo(buf.id)[0].name)
endif
bwipe
endfor
set shellslash&
endfunc
" Test for the 'maxmem' and 'maxmemtot' options
func Test_buffer_maxmem()
" use 1KB per buffer and 2KB for all the buffers

View File

@@ -253,9 +253,9 @@ endfunc
func Test_communicate_ipv6()
CheckIPv6
" FIXME: this test is very flaky on MS-Windows with the GUI
if has('gui_running') && has('win32')
throw 'Skipped: test is very flaky with MS-Windows in GUI'
" FIXME: this test is very flaky on MS-Windows
if has('win32')
throw 'Skipped: test is very flaky with MS-Windows'
endif
call Test_communicate()

View File

@@ -1006,7 +1006,7 @@ func Test_debug_def_function()
}
# comment
def Inner()
eval 1
eval 1 + 2
enddef
enddef
@@ -1019,16 +1019,16 @@ func Test_debug_def_function()
enddef
def g:FuncForLoop()
eval 1
eval 1 + 2
for i in [11, 22, 33]
eval i
eval i + 2
endfor
echo "done"
enddef
def g:FuncWithSplitLine()
eval 1
| eval 2
eval 1 + 2
| eval 2 + 3
enddef
END
call writefile(file, 'Xtest.vim')
@@ -1080,7 +1080,7 @@ func Test_debug_def_function()
call RunDbgCmd(buf, ':breakadd func 2 FuncForLoop')
call RunDbgCmd(buf, ':call FuncForLoop()', ['function FuncForLoop', 'line 2: for i in [11, 22, 33]'])
call RunDbgCmd(buf, 'echo i', ['11'])
call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 3: eval i'])
call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 3: eval i + 2'])
call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 4: endfor'])
call RunDbgCmd(buf, 'next', ['function FuncForLoop', 'line 2: for i in [11, 22, 33]'])
call RunDbgCmd(buf, 'echo i', ['22'])
@@ -1089,7 +1089,7 @@ func Test_debug_def_function()
call RunDbgCmd(buf, 'cont')
call RunDbgCmd(buf, ':breakadd func FuncWithSplitLine')
call RunDbgCmd(buf, ':call FuncWithSplitLine()', ['function FuncWithSplitLine', 'line 1: eval 1 | eval 2'])
call RunDbgCmd(buf, ':call FuncWithSplitLine()', ['function FuncWithSplitLine', 'line 1: eval 1 + 2 | eval 2 + 3'])
call RunDbgCmd(buf, 'cont')
call StopVimInTerminal(buf)

View File

@@ -933,6 +933,28 @@ func Test_opt_local_to_global()
set autoread&
endfunc
func Test_set_in_sandbox()
" Some boolean options cannot be set in sandbox, some can.
call assert_fails('sandbox set modelineexpr', 'E48:')
sandbox set number
call assert_true(&number)
set number&
" Some boolean options cannot be set in sandbox, some can.
if has('python') || has('python3')
call assert_fails('sandbox set pyxversion=3', 'E48:')
endif
sandbox set tabstop=4
call assert_equal(4, &tabstop)
set tabstop&
" Some string options cannot be set in sandbox, some can.
call assert_fails('sandbox set backupdir=/tmp', 'E48:')
sandbox set filetype=perl
call assert_equal('perl', &filetype)
set filetype&
endfunc
" Test for incrementing, decrementing and multiplying a number option value
func Test_opt_num_op()
set shiftwidth=4
@@ -1149,4 +1171,26 @@ func Test_opt_errorbells()
set noerrorbells
endfunc
func Test_opt_scrolljump()
help
resize 10
" Test with positive 'scrolljump'.
set scrolljump=2
norm! Lj
call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0,
\ 'topline':3, 'coladd':0, 'skipcol':0, 'curswant':0},
\ winsaveview())
" Test with negative 'scrolljump' (percentage of window height).
set scrolljump=-40
norm! ggLj
call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0,
\ 'topline':5, 'coladd':0, 'skipcol':0, 'curswant':0},
\ winsaveview())
set scrolljump&
bw
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -26,4 +26,23 @@ function Test_set_add()
let &wig = wig_save
endfunction
" :set, :setlocal, :setglobal without arguments show values of options.
func Test_set_no_arg()
set textwidth=79
let a = execute('set')
call assert_match("^\n--- Options ---\n.*textwidth=79\\>", a)
set textwidth&
setlocal textwidth=78
let a = execute('setlocal')
call assert_match("^\n--- Local option values ---\n.*textwidth=78\\>", a)
setlocal textwidth&
setglobal textwidth=77
let a = execute('setglobal')
call assert_match("^\n--- Global option values ---\n.*textwidth=77\\>", a)
setglobal textwidth&
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -1,5 +1,7 @@
" Tests for user defined commands
source vim9.vim
" Test for <mods> in user defined commands
function Test_cmdmods()
let g:mods = ''
@@ -275,6 +277,24 @@ func Test_CmdErrors()
call assert_fails('com! -count=x DoCmd :', 'E178:')
call assert_fails('com! -range=x DoCmd :', 'E178:')
com! -complete=file DoCmd :
call assert_match('E1208:', v:warningmsg)
let v:warningmsg = ''
com! -nargs=0 -complete=file DoCmd :
call assert_match('E1208:', v:warningmsg)
let lines =<< trim END
vim9script
com! -complete=file DoCmd :
END
call CheckScriptFailure(lines, 'E1208', 2)
let lines =<< trim END
vim9script
com! -nargs=0 -complete=file DoCmd :
END
call CheckScriptFailure(lines, 'E1208', 2)
com! -nargs=0 DoCmd :
call assert_fails('DoCmd x', 'E488:')
@@ -338,34 +358,30 @@ func Test_CmdCompletion()
call feedkeys(":com DoC\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"com DoC', @:)
com! -complete=behave DoCmd :
com! -nargs=1 -complete=behave DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd mswin xterm', @:)
" This does not work. Why?
"call feedkeys(":DoCmd x\<C-A>\<C-B>\"\<CR>", 'tx')
"call assert_equal('"DoCmd xterm', @:)
com! -complete=custom,CustomComplete DoCmd :
com! -nargs=* -complete=custom,CustomComplete DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd January February Mars', @:)
com! -complete=customlist,CustomCompleteList DoCmd :
com! -nargs=? -complete=customlist,CustomCompleteList DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd Monday Tuesday Wednesday', @:)
com! -complete=custom,CustomCompleteList DoCmd :
com! -nargs=+ -complete=custom,CustomCompleteList DoCmd :
call assert_fails("call feedkeys(':DoCmd \<C-D>', 'tx')", 'E730:')
com! -complete=customlist,CustomComp DoCmd :
com! -nargs=+ -complete=customlist,CustomComp DoCmd :
call assert_fails("call feedkeys(':DoCmd \<C-D>', 'tx')", 'E117:')
" custom completion without a function
com! -complete=custom, DoCmd
com! -nargs=? -complete=custom, DoCmd
call assert_beeps("call feedkeys(':DoCmd \t', 'tx')")
" custom completion failure with the wrong function
com! -complete=custom,min DoCmd
com! -nargs=? -complete=custom,min DoCmd
call assert_fails("call feedkeys(':DoCmd \t', 'tx')", 'E118:')
delcom DoCmd
@@ -500,21 +516,21 @@ func Test_command_list()
\ execute('command DoCmd'))
" Test with various -complete= argument values (non-exhaustive list)
command! -complete=arglist DoCmd :
command! -nargs=1 -complete=arglist DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
\ .. "\n DoCmd 0 arglist :",
\ .. "\n DoCmd 1 arglist :",
\ execute('command DoCmd'))
command! -complete=augroup DoCmd :
command! -nargs=* -complete=augroup DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
\ .. "\n DoCmd 0 augroup :",
\ .. "\n DoCmd * augroup :",
\ execute('command DoCmd'))
command! -complete=custom,CustomComplete DoCmd :
command! -nargs=? -complete=custom,CustomComplete DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
\ .. "\n DoCmd 0 custom :",
\ .. "\n DoCmd ? custom :",
\ execute('command DoCmd'))
command! -complete=customlist,CustomComplete DoCmd :
command! -nargs=+ -complete=customlist,CustomComplete DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
\ .. "\n DoCmd 0 customlist :",
\ .. "\n DoCmd + customlist :",
\ execute('command DoCmd'))
" Test with various -narg= argument values.

View File

@@ -213,12 +213,19 @@ def Test_assert_notmatch()
CheckDefFailure(['assert_notmatch("a", "b", null)'], 'E1013: Argument 3: type mismatch, expected string but got special')
enddef
def Test_assert_report()
CheckDefAndScriptFailure2(['assert_report([1, 2])'], 'E1013: Argument 1: type mismatch, expected string but got list<number>', 'E1174: String required for argument 1')
enddef
def Test_balloon_show()
CheckGui
CheckFeature balloon_eval
assert_fails('balloon_show(10)', 'E1174:')
assert_fails('balloon_show(true)', 'E1174:')
CheckDefAndScriptFailure2(['balloon_show(1.2)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1')
CheckDefAndScriptFailure2(['balloon_show({"a": 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E1174: String required for argument 1')
enddef
def Test_balloon_split()
@@ -387,6 +394,13 @@ enddef
def Test_charcol()
CheckDefFailure(['charcol(10)'], 'E1013: Argument 1: type mismatch, expected string but got number')
CheckDefFailure(['charcol({a: 10})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>')
new
setline(1, ['abcdefgh'])
cursor(1, 4)
assert_equal(4, charcol('.'))
assert_equal(9, charcol([1, '$']))
assert_equal(0, charcol([10, '$']))
bw!
enddef
def Test_charidx()
@@ -412,8 +426,11 @@ enddef
def Test_col()
new
setline(1, 'asdf')
col([1, '$'])->assert_equal(5)
setline(1, 'abcdefgh')
cursor(1, 4)
assert_equal(4, col('.'))
col([1, '$'])->assert_equal(9)
assert_equal(0, col([10, '$']))
assert_fails('col(true)', 'E1174:')
@@ -474,7 +491,7 @@ def Test_cursor()
var lines =<< trim END
cursor('2', 1)
END
CheckDefExecAndScriptFailure(lines, 'E475:')
CheckDefExecAndScriptFailure(lines, 'E1209:')
enddef
def Test_debugbreak()
@@ -1036,6 +1053,25 @@ def Test_getjumplist()
CheckDefFailure(['getjumplist(1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_getline()
var lines =<< trim END
new
setline(1, ['hello', 'there', 'again'])
assert_equal('hello', getline(1))
assert_equal('hello', getline('.'))
normal 2Gvjv
assert_equal('there', getline("'<"))
assert_equal('again', getline("'>"))
END
CheckDefAndScriptSuccess(lines)
lines =<< trim END
echo getline('1')
END
CheckDefExecAndScriptFailure(lines, 'E1209:')
enddef
def Test_getmarklist()
CheckDefFailure(['getmarklist([])'], 'E1013: Argument 1: type mismatch, expected string but got list<unknown>')
assert_equal([], getmarklist(10000))
@@ -1049,7 +1085,7 @@ enddef
def Test_getpos()
CheckDefFailure(['getpos(10)'], 'E1013: Argument 1: type mismatch, expected string but got number')
assert_equal([0, 1, 1, 0], getpos('.'))
assert_equal([0, 0, 0, 0], getpos('a'))
CheckDefExecFailure(['getpos("a")'], 'E1209:')
enddef
def Test_getqflist()
@@ -1131,6 +1167,12 @@ def Test_has()
enddef
def Test_has_key()
var d = {123: 'xx'}
assert_true(has_key(d, '123'))
assert_true(has_key(d, 123))
assert_false(has_key(d, 'x'))
assert_false(has_key(d, 99))
CheckDefAndScriptFailure2(['has_key([1, 2], "k")'], 'E1013: Argument 1: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
CheckDefAndScriptFailure2(['has_key({"a": 10}, ["a"])'], 'E1013: Argument 2: type mismatch, expected string but got list<string>', 'E730: Using a List as a String')
enddef
@@ -1478,11 +1520,50 @@ def Test_or()
CheckDefFailure(['or(0x1, "x")'], 'E1013: Argument 2: type mismatch, expected number but got string')
enddef
def Test_popup_atcursor()
CheckDefAndScriptFailure2(['popup_atcursor({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
CheckDefAndScriptFailure2(['popup_atcursor("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
# Pass variable of type 'any' to popup_atcursor()
var what: any = 'Hello'
var popupID = what->popup_atcursor({moved: 'any'})
assert_equal(0, popupID->popup_getoptions().tabpage)
popupID->popup_close()
enddef
def Test_popup_beval()
CheckDefAndScriptFailure2(['popup_beval({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
CheckDefAndScriptFailure2(['popup_beval("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
enddef
def Test_popup_create()
# Pass variable of type 'any' to popup_create()
var what: any = 'Hello'
var popupID = what->popup_create({})
assert_equal(0, popupID->popup_getoptions().tabpage)
popupID->popup_close()
enddef
def Test_popup_dialog()
CheckDefAndScriptFailure2(['popup_dialog({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
CheckDefAndScriptFailure2(['popup_dialog("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
enddef
def Test_popup_locate()
CheckDefAndScriptFailure2(['popup_locate("a", 20)'], 'E1013: Argument 1: type mismatch, expected number but got string', 'E1030: Using a String as a Number')
CheckDefAndScriptFailure2(['popup_locate(10, "b")'], 'E1013: Argument 2: type mismatch, expected number but got string', 'E1030: Using a String as a Number')
enddef
def Test_popup_menu()
CheckDefAndScriptFailure2(['popup_menu({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
CheckDefAndScriptFailure2(['popup_menu("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
enddef
def Test_popup_notification()
CheckDefAndScriptFailure2(['popup_notification({"a": 10}, {})'], 'E1013: Argument 1: type mismatch, expected string but got dict<number>', 'E450: buffer number, text or a list required')
CheckDefAndScriptFailure2(['popup_notification("a", [1, 2])'], 'E1013: Argument 2: type mismatch, expected dict<any> but got list<number>', 'E715: Dictionary required')
enddef
def Test_prevnonblank()
CheckDefFailure(['prevnonblank(null)'], 'E1013: Argument 1: type mismatch, expected string but got special')
assert_equal(0, prevnonblank(1))
@@ -1862,6 +1943,17 @@ def Test_setfperm()
CheckDefFailure(['setfperm("a", 0z10)'], 'E1013: Argument 2: type mismatch, expected string but got blob')
enddef
def Test_setline()
new
setline(1, range(1, 4))
assert_equal(['1', '2', '3', '4'], getline(1, '$'))
setline(1, ['a', 'b', 'c', 'd'])
assert_equal(['a', 'b', 'c', 'd'], getline(1, '$'))
setline(1, 'one')
assert_equal(['one', 'b', 'c', 'd'], getline(1, '$'))
bw!
enddef
def Test_setloclist()
var items = [{filename: '/tmp/file', lnum: 1, valid: true}]
var what = {items: items}
@@ -2125,6 +2217,7 @@ enddef
def Test_term_getansicolors()
CheckRunVimInTerminal
CheckFeature termguicolors
CheckDefAndScriptFailure2(['term_getansicolors(["a"])'], 'E1013: Argument 1: type mismatch, expected string but got list<string>', 'E745: Using a List as a Number')
enddef
@@ -2276,10 +2369,20 @@ enddef
def Test_virtcol()
CheckDefAndScriptFailure2(['virtcol(1.1)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1')
new
setline(1, ['abcdefgh'])
cursor(1, 4)
assert_equal(4, virtcol('.'))
assert_equal(4, virtcol([1, 4]))
assert_equal(9, virtcol([1, '$']))
assert_equal(0, virtcol([10, '$']))
bw!
enddef
def Test_win_execute()
assert_equal("\n" .. winnr(), win_execute(win_getid(), 'echo winnr()'))
assert_equal("\n" .. winnr(), 'echo winnr()'->win_execute(win_getid()))
assert_equal("\n" .. winnr(), win_execute(win_getid(), 'echo winnr()', 'silent'))
assert_equal('', win_execute(342343, 'echo winnr()'))
enddef

View File

@@ -647,7 +647,7 @@ def Test_expr4_equal()
CheckDefFailure(["var x = 'a' == "], 'E1097:', 3)
CheckScriptFailure(['vim9script', "var x = 'a' == "], 'E15:', 2)
CheckDefExecAndScriptFailure2(['var items: any', 'eval 1', 'eval 2', 'if items == []', 'endif'], 'E691:', 'E1072:', 4)
CheckDefExecAndScriptFailure2(['var items: any', 'eval 1 + 1', 'eval 2 + 2', 'if items == []', 'endif'], 'E691:', 'E1072:', 4)
CheckDefExecAndScriptFailure(['var x: any = "a"', 'echo x == true'], 'E1072: Cannot compare string with bool', 2)
CheckDefExecAndScriptFailure(["var x: any = true", 'echo x == ""'], 'E1072: Cannot compare bool with string', 2)
@@ -2478,6 +2478,13 @@ def Test_expr7_dict_vim9script()
else
CheckDefAndScriptFailure(lines, 'E117:', 0)
endif
lines =<< trim END
vim9script
var x = 99
assert_equal({x: 99}, s:)
END
CheckScriptSuccess(lines)
enddef
def Test_expr7_call_2bool()

View File

@@ -2538,7 +2538,7 @@ def Test_restore_modifiers()
set eventignore=
autocmd QuickFixCmdPost * copen
def AutocmdsDisabled()
eval 0
eval 1 + 2
enddef
func Func()
noautocmd call s:AutocmdsDisabled()
@@ -2551,8 +2551,8 @@ def Test_restore_modifiers()
enddef
def StackTop()
eval 1
eval 2
eval 1 + 2
eval 2 + 3
# call not on fourth line
StackBot()
enddef

View File

@@ -691,7 +691,7 @@ enddef
def Test_cnext_works_in_catch()
var lines =<< trim END
vim9script
au BufEnter * eval 0
au BufEnter * eval 1 + 2
writefile(['text'], 'Xfile1')
writefile(['text'], 'Xfile2')
var items = [
@@ -1754,6 +1754,21 @@ def Test_script_var_shadows_function()
CheckScriptFailure(lines, 'E1041:', 5)
enddef
def Test_script_var_shadows_command()
var lines =<< trim END
var undo = 1
undo = 2
assert_equal(2, undo)
END
CheckDefAndScriptSuccess(lines)
lines =<< trim END
var undo = 1
undo
END
CheckDefAndScriptFailure(lines, 'E1207:', 2)
enddef
def s:RetSome(): string
return 'some'
enddef
@@ -2270,7 +2285,7 @@ def Test_if_const_expr()
assert_equal(false, res)
# with constant "false" expression may be invalid so long as the syntax is OK
if false | eval 0 | endif
if false | eval 1 + 2 | endif
if false | eval burp + 234 | endif
if false | echo burp 234 'asd' | endif
if false
@@ -4152,6 +4167,58 @@ def Test_option_modifier()
set hlsearch&
enddef
" This must be called last, it may cause following :def functions to fail
def Test_xxx_echoerr_line_number()
var lines =<< trim END
echoerr 'some'
.. ' error'
.. ' continued'
END
CheckDefExecAndScriptFailure(lines, 'some error continued', 1)
enddef
def ProfiledWithLambda()
var n = 3
echo [[1, 2], [3, 4]]->filter((_, l) => l[0] == n)
enddef
def ProfiledNested()
var x = 0
def Nested(): any
return x
enddef
Nested()
enddef
def ProfiledNestedProfiled()
var x = 0
def Nested(): any
return x
enddef
Nested()
enddef
" Execute this near the end, profiling doesn't stop until Vim exists.
" This only tests that it works, not the profiling output.
def Test_xx_profile_with_lambda()
CheckFeature profile
profile start Xprofile.log
profile func ProfiledWithLambda
ProfiledWithLambda()
profile func ProfiledNested
ProfiledNested()
# Also profile the nested function. Use a different function, although the
# contents is the same, to make sure it was not already compiled.
profile func *
ProfiledNestedProfiled()
profdel func *
profile pause
enddef
" Keep this last, it messes up highlighting.
def Test_substitute_cmd()
new

View File

@@ -824,6 +824,9 @@ f_assert_report(typval_T *argvars, typval_T *rettv)
{
garray_T ga;
if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
return;
prepare_assert_error(&ga);
ga_concat(&ga, tv_get_string(&argvars[0]));
assert_error(&ga);

View File

@@ -1019,20 +1019,22 @@ ex_command(exarg_T *eap)
// we are listing commands
p = skipwhite(end);
if (!has_attr && ends_excmd2(eap->arg, p))
{
uc_list(name, end - name);
}
else if (!ASCII_ISUPPER(*name))
{
emsg(_("E183: User defined commands must start with an uppercase letter"));
return;
}
else if ((name_len == 1 && *name == 'X')
|| (name_len <= 4
&& STRNCMP(name, "Next", name_len > 4 ? 4 : name_len) == 0))
{
emsg(_("E841: Reserved name, cannot be used for user defined command"));
return;
else if (compl > 0 && (argt & EX_EXTRA) == 0)
{
// Some plugins rely on silently ignoring the mistake, only make this
// an error in Vim9 script.
if (in_vim9script())
emsg(_(e_complete_used_without_nargs));
else
give_warning_with_source(
(char_u *)_(e_complete_used_without_nargs), TRUE, TRUE);
}
else
uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg,

View File

@@ -755,6 +755,46 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
3156,
/**/
3155,
/**/
3154,
/**/
3153,
/**/
3152,
/**/
3151,
/**/
3150,
/**/
3149,
/**/
3148,
/**/
3147,
/**/
3146,
/**/
3145,
/**/
3144,
/**/
3143,
/**/
3142,
/**/
3141,
/**/
3140,
/**/
3139,
/**/
3138,
/**/
3137,
/**/
3136,
/**/

View File

@@ -1781,6 +1781,7 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
garray_T *stack = &cctx->ctx_type_stack;
int argoff;
type_T **argtypes = NULL;
type_T *shuffled_argtypes[MAX_FUNC_ARGS];
type_T *maptype = NULL;
RETURN_OK_IF_SKIP(cctx);
@@ -1800,6 +1801,16 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
{
// Check the types of the arguments.
argtypes = ((type_T **)stack->ga_data) + stack->ga_len - argcount;
if (method_call && argoff > 1)
{
int i;
for (i = 0; i < argcount; ++i)
shuffled_argtypes[i] = (i < argoff - 1)
? argtypes[i + 1]
: (i == argoff - 1) ? argtypes[0] : argtypes[i];
argtypes = shuffled_argtypes;
}
if (internal_func_check_arg_types(argtypes, func_idx, argcount,
cctx) == FAIL)
return FAIL;
@@ -3624,6 +3635,13 @@ compile_lambda(char_u **arg, cctx_T *cctx)
ufunc->uf_ret_type = &t_unknown;
compile_def_function(ufunc, FALSE, cctx->ctx_compile_type, cctx);
#ifdef FEAT_PROFILE
// When the outer function is compiled for profiling, the lambda may be
// called without profiling. Compile it here in the right context.
if (cctx->ctx_compile_type == CT_PROFILE)
compile_def_function(ufunc, FALSE, CT_NONE, cctx);
#endif
// evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg"
// points into it. Point to the original line to avoid a dangling pointer.
if (evalarg.eval_tofree_cmdline != NULL)
@@ -5552,6 +5570,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
char_u *lambda_name;
ufunc_T *ufunc;
int r = FAIL;
compiletype_T compile_type;
if (eap->forceit)
{
@@ -5618,14 +5637,27 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
}
}
if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
&& compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), cctx)
== FAIL)
compile_type = COMPILE_TYPE(ufunc);
#ifdef FEAT_PROFILE
// If the outer function is profiled, also compile the nested function for
// profiling.
if (cctx->ctx_compile_type == CT_PROFILE)
compile_type = CT_PROFILE;
#endif
if (func_needs_compiling(ufunc, compile_type)
&& compile_def_function(ufunc, TRUE, compile_type, cctx) == FAIL)
{
func_ptr_unref(ufunc);
goto theend;
}
#ifdef FEAT_PROFILE
// When the outer function is compiled for profiling, the nested function
// may be called without profiling. Compile it here in the right context.
if (compile_type == CT_PROFILE && func_needs_compiling(ufunc, CT_NONE))
compile_def_function(ufunc, FALSE, CT_NONE, cctx);
#endif
if (is_global)
{
char_u *func_name = vim_strnsave(name_start + 2,
@@ -8563,6 +8595,37 @@ compile_throw(char_u *arg, cctx_T *cctx UNUSED)
return p;
}
static char_u *
compile_eval(char_u *arg, cctx_T *cctx)
{
char_u *p = arg;
int name_only;
char_u *alias;
long lnum = SOURCING_LNUM;
// find_ex_command() will consider a variable name an expression, assuming
// that something follows on the next line. Check that something actually
// follows, otherwise it's probably a misplaced command.
get_name_len(&p, &alias, FALSE, FALSE);
name_only = ends_excmd2(arg, skipwhite(p));
vim_free(alias);
p = arg;
if (compile_expr0(&p, cctx) == FAIL)
return NULL;
if (name_only && lnum == SOURCING_LNUM)
{
semsg(_(e_expression_without_effect_str), arg);
return NULL;
}
// drop the result
generate_instr_drop(cctx, ISN_DROP, 1);
return skipwhite(p);
}
/*
* compile "echo expr"
* compile "echomsg expr"
@@ -9630,13 +9693,7 @@ compile_def_function(
break;
case CMD_eval:
if (compile_expr0(&p, &cctx) == FAIL)
goto erret;
// drop the result
generate_instr_drop(&cctx, ISN_DROP, 1);
line = skipwhite(p);
line = compile_eval(p, &cctx);
break;
case CMD_echo:

View File

@@ -197,6 +197,7 @@ call_dfunc(
int idx;
estack_T *entry;
funclocal_T *floc = NULL;
int res = OK;
if (dfunc->df_deleted)
{
@@ -219,14 +220,6 @@ call_dfunc(
(((dfunc_T *)def_functions.ga_data)
+ ectx->ec_dfunc_idx)->df_ufunc);
}
// Profiling might be enabled/disabled along the way. This should not
// fail, since the function was compiled before and toggling profiling
// doesn't change any errors.
if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
&& compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
== FAIL)
return FAIL;
}
#endif
@@ -235,10 +228,14 @@ call_dfunc(
// When debugging and using "cont" switches to the not-debugged
// instructions, may need to still compile them.
if ((func_needs_compiling(ufunc, COMPILE_TYPE(ufunc))
&& compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL)
== FAIL)
|| INSTRUCTIONS(dfunc) == NULL)
if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)))
{
res = compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL);
// compile_def_function() may cause def_functions.ga_data to change
dfunc = ((dfunc_T *)def_functions.ga_data) + cdf_idx;
}
if (res == FAIL || INSTRUCTIONS(dfunc) == NULL)
{
if (did_emsg_cumul + did_emsg == did_emsg_before)
semsg(_(e_function_is_not_compiled_str),