Skip to content
Permalink
Browse files

patch 8.1.1116: cannot enforce a Vim script style

Problem:    Cannot enforce a Vim script style.
Solution:   Add the :scriptversion command. (closes #3857)
  • Loading branch information...
brammool committed Apr 4, 2019
1 parent 8f4aeb5 commit 558ca4ae55096f8763ab8515a304cda9c57f18a7
Showing with 177 additions and 32 deletions.
  1. +44 −10 runtime/doc/eval.txt
  2. +12 −1 runtime/doc/repeat.txt
  3. +1 −0 src/buffer.c
  4. +33 −5 src/eval.c
  5. +3 −1 src/evalfunc.c
  6. +9 −9 src/ex_cmdidxs.h
  7. +3 −0 src/ex_cmds.h
  8. +29 −5 src/ex_cmds2.c
  9. +1 −0 src/main.c
  10. +2 −1 src/option.c
  11. +1 −0 src/proto/ex_cmds2.pro
  12. +1 −0 src/structs.h
  13. +36 −0 src/testdir/test_eval_stuff.vim
  14. +2 −0 src/version.c
@@ -27,10 +27,11 @@ done, the features in this document are not available. See |+eval| and
7. Commands |expression-commands|
8. Exception handling |exception-handling|
9. Examples |eval-examples|
10. No +eval feature |no-eval-feature|
11. The sandbox |eval-sandbox|
12. Textlock |textlock|
13. Testing |testing|
10. Vim script version |vimscript-version|
11. No +eval feature |no-eval-feature|
12. The sandbox |eval-sandbox|
13. Textlock |textlock|
14. Testing |testing|

{Vi does not have any of these commands}

@@ -1037,6 +1038,7 @@ result is a new list with the two lists Concatenated.

For String concatenation ".." is preferred, since "." is ambiguous, it is also
used for |Dict| member access and floating point numbers.
When |vimscript-version| is 2 or higher, using "." is not allowed.

expr7 * expr7 Number multiplication *expr-star*
expr7 / expr7 Number division *expr-/*
@@ -10476,6 +10478,8 @@ vertsplit Compiled with vertically split windows |:vsplit|.
vim_starting True while initial source'ing takes place. |startup|
*vim_starting*
viminfo Compiled with viminfo support.
vimscript-1 Compiled Vim script version 1 support
vimscript-2 Compiled Vim script version 2 support
virtualedit Compiled with 'virtualedit' option. (always true)
visual Compiled with Visual mode. (always true)
visualextra Compiled with extra Visual mode commands. (always
@@ -10966,16 +10970,19 @@ This does NOT work: >
When the selected range of items is partly past the
end of the list, items will be added.

*:let+=* *:let-=* *:letstar=*
*:let/=* *:let%=* *:let.=* *E734*
*:let+=* *:let-=* *:letstar=*
*:let/=* *:let%=* *:let.=* *:let..=* *E734* *E985*
:let {var} += {expr1} Like ":let {var} = {var} + {expr1}".
:let {var} -= {expr1} Like ":let {var} = {var} - {expr1}".
:let {var} *= {expr1} Like ":let {var} = {var} * {expr1}".
:let {var} /= {expr1} Like ":let {var} = {var} / {expr1}".
:let {var} %= {expr1} Like ":let {var} = {var} % {expr1}".
:let {var} .= {expr1} Like ":let {var} = {var} . {expr1}".
:let {var} ..= {expr1} Like ":let {var} = {var} .. {expr1}".
These fail if {var} was not set yet and when the type
of {var} and {expr1} don't fit the operator.
`.=` is not supported with Vim script version 2 and
later, see |vimscript-version|.


:let ${env-name} = {expr1} *:let-environment* *:let-$*
@@ -12609,7 +12616,34 @@ code can be used: >
unlet scriptnames_output

==============================================================================
10. No +eval feature *no-eval-feature*
10. Vim script versions *vimscript-version* *vimscript-versions*

Over time many features have been added to Vim script. This includes Ex
commands, functions, variable types, etc. Each individual feature can be
checked with the |has()| and |exists()| functions.

Sometimes old syntax of functionality gets in the way of making Vim better.
When support is taken away this will break older Vim scripts. To make this
explicit the |:scriptversion| command can be used. When a Vim script is not
compatible with older versions of Vim this will give an explicit error,
instead of failing in mysterious ways. >

:scriptversion 1
< This is the original Vim script, same as not using a |:scriptversion|
command. Can be used to go back to old syntax for a range of lines.
Test for support with: >
has('vimscript-1')

:scriptversion 2
< String concatenation with "." is not supported, use ".." instead.
This avoids the ambiguity using "." for Dict member access and
floating point numbers. Now ".5" means the number 0.5.
Test for support with: >
has('vimscript-2')


==============================================================================
11. No +eval feature *no-eval-feature*

When the |+eval| feature was disabled at compile time, none of the expression
evaluation commands are available. To prevent this from causing Vim scripts
@@ -12640,7 +12674,7 @@ When the |+eval| feature is available the command is skipped because of the
silently ignored, and the command is executed.

==============================================================================
11. The sandbox *eval-sandbox* *sandbox* *E48*
12. The sandbox *eval-sandbox* *sandbox* *E48*

The 'foldexpr', 'formatexpr', 'includeexpr', 'indentexpr', 'statusline' and
'foldtext' options may be evaluated in a sandbox. This means that you are
@@ -12679,7 +12713,7 @@ Note that when in the sandbox and saving an option value and restoring it, the
option will still be marked as it was set in the sandbox.

==============================================================================
12. Textlock *textlock*
13. Textlock *textlock*

In a few situations it is not allowed to change the text in the buffer, jump
to another window and some other things that might confuse or break what Vim
@@ -12695,7 +12729,7 @@ This is not allowed when the textlock is active:
- etc.

==============================================================================
13. Testing *testing*
14. Testing *testing*

Vim can be tested after building it, usually with "make test".
The tests are located in the directory "src/testdir".
@@ -1,4 +1,4 @@
*repeat.txt* For Vim version 8.1. Last change: 2018 Dec 18
*repeat.txt* For Vim version 8.1. Last change: 2019 Apr 04


VIM REFERENCE MANUAL by Bram Moolenaar
@@ -325,6 +325,17 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
<
{not in Vi}

:scriptv[ersion] {version} *:scriptv* *:scriptversion*
*E999* *E984*
Specify the version of Vim for the lines that follow.
Does not apply to sourced scripts.

If {version} is higher than what the current Vim
version supports E999 will be given. You either need
to rewrite the script to make it work with an older
Vim version, or update Vim to a newer version. See
|vimscript-version| for what changed between versions.

*:scr* *:scriptnames*
:scr[iptnames] List all sourced script names, in the order they were
first sourced. The number is used for the script ID
@@ -5493,6 +5493,7 @@ chk_modeline(
current_sctx.sc_sid = SID_MODELINE;
current_sctx.sc_seq = 0;
current_sctx.sc_lnum = 0;
current_sctx.sc_version = 1;
#endif
// Make sure no risky things are executed as a side effect.
secure = 1;
@@ -1249,21 +1249,27 @@ ex_let(exarg_T *eap)
char_u op[2];
char_u *argend;
int first = TRUE;
int concat;

argend = skip_var_list(arg, &var_count, &semicolon);
if (argend == NULL)
return;
if (argend > arg && argend[-1] == '.') // for var.='str'
--argend;
expr = skipwhite(argend);
if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%.", *expr) != NULL
&& expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0))
concat = expr[0] == '.'
&& ((expr[1] == '=' && current_sctx.sc_version < 2)
|| (expr[1] == '.' && expr[2] == '='));
if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%", *expr) != NULL
&& expr[1] == '=') || concat))
{
/*
* ":let" without "=": list variables
*/
if (*arg == '[')
emsg(_(e_invarg));
else if (expr[0] == '.')
emsg(_("E985: .= is not supported with script version 2"));
else if (!ends_excmd(*arg))
/* ":let var1 var2" */
arg = list_arg_vars(eap, arg, &first);
@@ -3817,7 +3823,7 @@ eval4(char_u **arg, typval_T *rettv, int evaluate)
* Handle fourth level expression:
* + number addition
* - number subtraction
* . string concatenation
* . string concatenation (if script version is 1)
* .. string concatenation
*
* "arg" must point to the first non-white of the expression.
@@ -3838,6 +3844,7 @@ eval5(char_u **arg, typval_T *rettv, int evaluate)
char_u *s1, *s2;
char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
char_u *p;
int concat;

/*
* Get the first variable.
@@ -3850,8 +3857,11 @@ eval5(char_u **arg, typval_T *rettv, int evaluate)
*/
for (;;)
{
// "." is only string concatenation when scriptversion is 1
op = **arg;
if (op != '+' && op != '-' && op != '.')
concat = op == '.'
&& (*(*arg + 1) == '.' || current_sctx.sc_version < 2);
if (op != '+' && op != '-' && !concat)
break;

if ((op != '+' || (rettv->v_type != VAR_LIST
@@ -4224,6 +4234,17 @@ eval7(
*arg = skipwhite(*arg + 1);
end_leader = *arg;

if (**arg == '.' && (!isdigit(*(*arg + 1))
#ifdef FEAT_FLOAT
|| current_sctx.sc_version < 2
#endif
))
{
semsg(_(e_invexpr2), *arg);
++*arg;
return FAIL;
}

switch (**arg)
{
/*
@@ -4239,16 +4260,23 @@ eval7(
case '7':
case '8':
case '9':
case '.':
{
#ifdef FEAT_FLOAT
char_u *p = skipdigits(*arg + 1);
char_u *p;
int get_float = FALSE;

/* We accept a float when the format matches
* "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
* strict to avoid backwards compatibility problems.
* With script version 2 and later the leading digit can be
* omitted.
* Don't look for a float after the "." operator, so that
* ":let vers = 1.2.3" doesn't fail. */
if (**arg == '.')
p = *arg;
else
p = skipdigits(*arg + 1);
if (!want_string && p[0] == '.' && vim_isdigit(p[1]))
{
get_float = TRUE;
@@ -6631,10 +6631,12 @@ f_has(typval_T *argvars, typval_T *rettv)
#ifdef FEAT_VARTABS
"vartabs",
#endif
"vertsplit",
#ifdef FEAT_VIMINFO
"viminfo",
#endif
"vertsplit",
"vimscript-1",
"vimscript-2",
"virtualedit",
"visual",
"visualextra",
@@ -24,13 +24,13 @@ static const unsigned short cmdidxs1[26] =
/* q */ 348,
/* r */ 351,
/* s */ 371,
/* t */ 438,
/* u */ 481,
/* v */ 492,
/* w */ 510,
/* x */ 524,
/* y */ 533,
/* z */ 534
/* t */ 439,
/* u */ 482,
/* v */ 493,
/* w */ 511,
/* x */ 525,
/* y */ 534,
/* z */ 535
};

/*
@@ -59,7 +59,7 @@ static const unsigned char cmdidxs2[26][26] =
/* p */ { 1, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 0, 0, 16, 17, 26, 0, 27, 0, 28, 0 },
/* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 19, 0, 0, 0, 0 },
/* s */ { 2, 6, 15, 0, 18, 22, 0, 24, 25, 0, 0, 28, 30, 34, 38, 40, 0, 48, 0, 49, 0, 61, 62, 0, 63, 0 },
/* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 49, 0, 50, 0, 62, 63, 0, 64, 0 },
/* t */ { 2, 0, 19, 0, 22, 24, 0, 25, 0, 26, 0, 27, 31, 34, 36, 37, 0, 38, 40, 0, 41, 0, 0, 0, 0, 0 },
/* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* v */ { 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 12, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0 },
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

static const int command_count = 547;
static const int command_count = 548;
@@ -1269,6 +1269,9 @@ EX(CMD_scriptnames, "scriptnames", ex_scriptnames,
EX(CMD_scriptencoding, "scriptencoding", ex_scriptencoding,
WORD1|TRLBAR|CMDWIN,
ADDR_LINES),
EX(CMD_scriptversion, "scriptversion", ex_scriptversion,
WORD1|TRLBAR|CMDWIN,
ADDR_LINES),
EX(CMD_scscope, "scscope", ex_scscope,
EXTRA|NOTRLCOM,
ADDR_LINES),
@@ -2321,7 +2321,7 @@ check_changed_any(
else
#endif
/* Try auto-writing the buffer. If this fails but the buffer no
* longer exists it's not changed, that's OK. */
* longer exists it's not changed, that's OK. */
if (check_changed(buf, (p_awa ? CCGD_AW : 0)
| CCGD_MULTWIN
| CCGD_ALLBUF) && bufref_valid(&bufref))
@@ -4501,12 +4501,14 @@ do_source(
* Also starts profiling timer for nested script. */
save_funccal(&funccalp_entry);

save_current_sctx = current_sctx;
current_sctx.sc_lnum = 0;
current_sctx.sc_version = 1;

// Check if this script was sourced before to finds its SID.
// If it's new, generate a new SID.
// Always use a new sequence number.
save_current_sctx = current_sctx;
current_sctx.sc_seq = ++last_current_SID_seq;
current_sctx.sc_lnum = 0;
# ifdef UNIX
stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
# endif
@@ -5077,10 +5079,9 @@ script_line_end(void)

/*
* ":scriptencoding": Set encoding conversion for a sourced script.
* Without the multi-byte feature it's simply ignored.
*/
void
ex_scriptencoding(exarg_T *eap UNUSED)
ex_scriptencoding(exarg_T *eap)
{
struct source_cookie *sp;
char_u *name;
@@ -5108,6 +5109,29 @@ ex_scriptencoding(exarg_T *eap UNUSED)
vim_free(name);
}

/*
* ":scriptversion": Set Vim script version for a sourced script.
*/
void
ex_scriptversion(exarg_T *eap UNUSED)
{
int nr;

if (!getline_equal(eap->getline, eap->cookie, getsourceline))
{
emsg(_("E984: :scriptversion used outside of a sourced file"));
return;
}

nr = getdigits(&eap->arg);
if (nr == 0 || *eap->arg != NUL)
emsg(_(e_invarg));
else if (nr > 2)
semsg(_("E999: scriptversion not supported: %d"), nr);
else
current_sctx.sc_version = nr;
}

#if defined(FEAT_EVAL) || defined(PROTO)
/*
* ":finish": Mark a sourced file as finished.
@@ -3166,6 +3166,7 @@ process_env(
current_sctx.sc_sid = SID_ENV;
current_sctx.sc_seq = 0;
current_sctx.sc_lnum = 0;
current_sctx.sc_version = 1;
#endif
do_cmdline_cmd(initstr);
sourcing_name = save_sourcing_name;

0 comments on commit 558ca4a

Please sign in to comment.
You can’t perform that action at this time.