/* vi:set ts=8 sts=4 sw=4 noet:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
* See README.txt for an overview of the Vim source code.
*/
/*
* vim9script.c: :vim9script, :import, :export and friends
*/
#include "vim.h"
#if defined(FEAT_EVAL)
# include "vim9.h"
#endif
/*
* Return TRUE when currently using Vim9 script syntax.
* Does not go up the stack, a ":function" inside vim9script uses legacy
* syntax.
*/
int
in_vim9script(void)
{
// "sc_version" is also set when compiling a ":def" function in legacy
// script.
return (current_sctx.sc_version == SCRIPT_VERSION_VIM9
|| (cmdmod.cmod_flags & CMOD_VIM9CMD))
&& !(cmdmod.cmod_flags & CMOD_LEGACY);
}
#if defined(FEAT_EVAL) || defined(PROTO)
/*
* Return TRUE when currently in a script with script version smaller than
* "max_version" or command modifiers forced it.
*/
int
in_old_script(int max_version)
{
return (current_sctx.sc_version < max_version
&& !(cmdmod.cmod_flags & CMOD_VIM9CMD))
|| (cmdmod.cmod_flags & CMOD_LEGACY);
}
/*
* Return TRUE if the current script is Vim9 script.
* This also returns TRUE in a legacy function in a Vim9 script.
*/
int
current_script_is_vim9(void)
{
return SCRIPT_ID_VALID(current_sctx.sc_sid)
&& SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
== SCRIPT_VERSION_VIM9;
}
#endif
/*
* ":vim9script".
*/
void
ex_vim9script(exarg_T *eap UNUSED)
{
#ifdef FEAT_EVAL
int sid = current_sctx.sc_sid;
scriptitem_T *si;
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
{
emsg(_(e_vim9script_can_only_be_used_in_script));
return;
}
si = SCRIPT_ITEM(sid);
if (si->sn_state == SN_STATE_HAD_COMMAND)
{
emsg(_(e_vim9script_must_be_first_command_in_script));
return;
}
if (!IS_WHITE_OR_NUL(*eap->arg) && STRCMP(eap->arg, "noclear") != 0)
{
semsg(_(e_invarg2), eap->arg);
return;
}
if (si->sn_state == SN_STATE_RELOAD && IS_WHITE_OR_NUL(*eap->arg))
{
hashtab_T *ht = &SCRIPT_VARS(sid);
// Reloading a script without the "noclear" argument: clear
// script-local variables and functions.
hashtab_free_contents(ht);
hash_init(ht);
delete_script_functions(sid);
// old imports and script variables are no longer valid
free_imports_and_script_vars(sid);
}
si->sn_state = SN_STATE_HAD_COMMAND;
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
si->sn_version = SCRIPT_VERSION_VIM9;
if (STRCMP(p_cpo, CPO_VIM) != 0)
{
si->sn_save_cpo = vim_strsave(p_cpo);
set_option_value((char_u *)"cpo", 0L, (char_u *)CPO_VIM, OPT_NO_REDRAW);
}
#else
// No check for this being the first command, it doesn't matter.
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
#endif
}
/*
* When in Vim9 script give an error and return FAIL.
*/
int
not_in_vim9(exarg_T *eap)
{
if (in_vim9script())
switch (eap->cmdidx)
{
case CMD_k:
if (eap->addr_count > 0)
{
emsg(_(e_norange));
return FAIL;
}
// FALLTHROUGH
case CMD_append:
case CMD_change:
case CMD_insert:
case CMD_open:
case CMD_t:
case CMD_xit:
semsg(_(e_command_not_supported_in_vim9_script_missing_var_str), eap->cmd);
return FAIL;
default: break;
}
return OK;
}
/*
* Give an error message if "p" points at "#{" and return TRUE.
* This avoids that using a legacy style #{} dictionary leads to difficult to
* understand errors.
*/
int
vim9_bad_comment(char_u *p)
{
if (p[0] == '#' && p[1] == '{' && p[2] != '{')
{
emsg(_(e_cannot_use_hash_curly_to_start_comment));
return TRUE;
}
return FALSE;
}
/*
* Return TRUE if "p" points at a "#" not followed by one '{'.
* Does not check for white space.
*/
int
vim9_comment_start(char_u *p)
{
return p[0] == '#' && (