// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
#include "nvim/api/private/converter.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/vimscript.h"
#include "nvim/ascii.h"
#include "nvim/autocmd.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ops.h"
#include "nvim/strings.h"
#include "nvim/vim.h"
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"
#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/vimscript.c.generated.h"
#endif
#define IS_USER_CMDIDX(idx) ((int)(idx) < 0)
/// Executes Vimscript (multiline block of Ex commands), like anonymous
/// |:source|.
///
/// Unlike |nvim_command()| this function supports heredocs, script-scope (s:),
/// etc.
///
/// On execution error: fails with VimL error, does not update v:errmsg.
///
/// @see |execute()|
/// @see |nvim_command()|
/// @see |nvim_cmd()|
///
/// @param src Vimscript code
/// @param output Capture and return all (non-error, non-shell |:!|) output
/// @param[out] err Error details (Vim error), if any
/// @return Output (non-error, non-shell |:!|) if `output` is true,
/// else empty string.
String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err)
FUNC_API_SINCE(7)
{
const int save_msg_silent = msg_silent;
garray_T *const save_capture_ga = capture_ga;
garray_T capture_local;
if (output) {
ga_init(&capture_local, 1, 80);
capture_ga = &capture_local;
}
try_start();
if (output) {
msg_silent++;
}
const sctx_T save_current_sctx = api_set_sctx(channel_id);
do_source_str(src.data, "nvim_exec()");
if (output) {
capture_ga = save_capture_ga;
msg_silent = save_msg_silent;
}
current_sctx = save_current_sctx;
try_end(err);
if (ERROR_SET(err)) {
goto theend;
}
if (output && capture_local.ga_len > 1) {
String s = (String){
.data = capture_local.ga_data,
.size = (size_t)capture_local.ga_len,
};
// redir usually (except :echon) prepends a newline.
if (s.data[0] == '\n') {
memmove(s.data, s.data + 1, s.size - 1);
s.data[s.size - 1] = '\0';
s.size = s.size - 1;
}
return s; // Caller will free the memory.
}
theend:
if (output) {
ga_clear(&capture_local);
}
return (String)STRING_INIT;
}
/// Executes an Ex command.
///
/// On execution error: fails with VimL error, does not update v:errmsg.
///
/// Prefer using |nvim_cmd()| or |nvim_exec()| over this. To evaluate multiple lines of Vim script
/// or an Ex command directly, use |nvim_exec()|. To construct an Ex command using a structured
/// format and then execute it, use |nvim_cmd()|. To modify an Ex command before evaluating it, use
/// |nvim_parse_cmd()| in conjunction with |nvim_cmd()|.
///
/// @param command Ex command string
/// @param[out] err Error details (Vim error), if any
void nvim_command(String command, Error *err)
FUNC_API_SINCE(1)
{
try_start();
do_cmdline_cmd(command.data);
try_end(err);
}
/// Evaluates a VimL |expression|.
/// Dictionaries and Lists are recursively expanded.
///
/// On execution error: fails with VimL error, does not update v:errmsg.
///
/// @param expr VimL expression string
/// @param[out] err Error details, if any
/// @return Evaluation result or expanded object
Object nvim_eval(String expr, Error *err)
FUNC_API_SINCE(1)
{
static int recursive = 0; // recursion depth
Object rv = OBJECT_INIT;
TRY_WRAP({
// Initialize `force_abort` and `suppress_errthrow` at the top level.
if (!recursive) {
force_abort = false;
suppress_errthrow = false;
current_exception = NULL;
// `did_emsg` is set by emsg(), which cancels execution.
did_emsg = false;
}
recursive++;
try_start();
typval_T rettv;
int ok = eval0(expr.data, &rettv, NULL, true);
if (!try_end(err)) {
if (ok == FAIL) {
// Should never happen, try_end() should get the error. #8371
api_set_error(err, kErrorTypeException,
"Failed to evaluate expression: '%.*s'", 256, expr.data);
}
|