aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/vimscript.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-29 22:39:54 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-29 22:39:54 +0000
commit21cb7d04c387e4198ca8098a884c78b56ffcf4c2 (patch)
tree84fe5690df1551f0bb2bdfe1a13aacd29ebc1de7 /src/nvim/api/vimscript.c
parentd9c904f85a23a496df4eb6be42aa43f007b22d50 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-colorcolchar.tar.gz
rneovim-colorcolchar.tar.bz2
rneovim-colorcolchar.zip
Merge remote-tracking branch 'upstream/master' into colorcolcharcolorcolchar
Diffstat (limited to 'src/nvim/api/vimscript.c')
-rw-r--r--src/nvim/api/vimscript.c195
1 files changed, 108 insertions, 87 deletions
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index af1b23b712..c75bf21572 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -1,6 +1,3 @@
-// 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 <stdbool.h>
#include <stddef.h>
@@ -8,23 +5,22 @@
#include <string.h>
#include "klib/kvec.h"
+#include "nvim/api/keysets_defs.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/buffer_defs.h"
+#include "nvim/ascii_defs.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
-#include "nvim/eval/typval_defs.h"
#include "nvim/eval/userfunc.h"
#include "nvim/ex_docmd.h"
+#include "nvim/func_attr.h"
#include "nvim/garray.h"
#include "nvim/globals.h"
#include "nvim/memory.h"
-#include "nvim/pos.h"
#include "nvim/runtime.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.h"
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"
@@ -38,39 +34,57 @@
/// Unlike |nvim_command()| this function supports heredocs, script-scope (s:),
/// etc.
///
-/// On execution error: fails with VimL error, updates v:errmsg.
+/// On execution error: fails with Vimscript error, updates 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 opts Optional parameters.
+/// - output: (boolean, default false) Whether to 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)
+/// @return Dictionary containing information about execution, with these keys:
+/// - output: (string|nil) Output if `opts.output` is true.
+Dictionary nvim_exec2(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err)
+ FUNC_API_SINCE(11)
+{
+ Dictionary result = ARRAY_DICT_INIT;
+
+ String output = exec_impl(channel_id, src, opts, err);
+ if (ERROR_SET(err)) {
+ return result;
+ }
+
+ if (opts->output) {
+ PUT(result, "output", STRING_OBJ(output));
+ }
+
+ return result;
+}
+
+String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *err)
{
const int save_msg_silent = msg_silent;
garray_T *const save_capture_ga = capture_ga;
const int save_msg_col = msg_col;
garray_T capture_local;
- if (output) {
+ if (opts->output) {
ga_init(&capture_local, 1, 80);
capture_ga = &capture_local;
}
try_start();
- if (output) {
+ if (opts->output) {
msg_silent++;
msg_col = 0; // prevent leading spaces
}
const sctx_T save_current_sctx = api_set_sctx(channel_id);
- do_source_str(src.data, "nvim_exec()");
- if (output) {
+ do_source_str(src.data, "nvim_exec2()");
+ if (opts->output) {
capture_ga = save_capture_ga;
msg_silent = save_msg_silent;
// Put msg_col back where it was, since nothing should have been written.
@@ -84,7 +98,7 @@ String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err)
goto theend;
}
- if (output && capture_local.ga_len > 1) {
+ if (opts->output && capture_local.ga_len > 1) {
String s = (String){
.data = capture_local.ga_data,
.size = (size_t)capture_local.ga_len,
@@ -98,7 +112,7 @@ String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err)
return s; // Caller will free the memory.
}
theend:
- if (output) {
+ if (opts->output) {
ga_clear(&capture_local);
}
return (String)STRING_INIT;
@@ -106,10 +120,10 @@ theend:
/// Executes an Ex command.
///
-/// On execution error: fails with VimL error, updates v:errmsg.
+/// On execution error: fails with Vimscript error, updates 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
+/// Prefer using |nvim_cmd()| or |nvim_exec2()| over this. To evaluate multiple lines of Vim script
+/// or an Ex command directly, use |nvim_exec2()|. 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()|.
///
@@ -123,12 +137,12 @@ void nvim_command(String command, Error *err)
try_end(err);
}
-/// Evaluates a VimL |expression|.
+/// Evaluates a Vimscript |expression|.
/// Dictionaries and Lists are recursively expanded.
///
-/// On execution error: fails with VimL error, updates v:errmsg.
+/// On execution error: fails with Vimscript error, updates v:errmsg.
///
-/// @param expr VimL expression string
+/// @param expr Vimscript expression string
/// @param[out] err Error details, if any
/// @return Evaluation result or expanded object
Object nvim_eval(String expr, Error *err)
@@ -137,39 +151,42 @@ Object nvim_eval(String expr, Error *err)
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;
- did_throw = false;
- // `did_emsg` is set by emsg(), which cancels execution.
- did_emsg = false;
- }
- recursive++;
- try_start();
+ // Initialize `force_abort` and `suppress_errthrow` at the top level.
+ if (!recursive) {
+ force_abort = false;
+ suppress_errthrow = false;
+ did_throw = false;
+ // `did_emsg` is set by emsg(), which cancels execution.
+ did_emsg = false;
+ }
- typval_T rettv;
- int ok = eval0(expr.data, &rettv, NULL, true);
+ recursive++;
- 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);
- } else {
- rv = vim_to_object(&rettv);
- }
- }
+ typval_T rettv;
+ int ok;
- tv_clear(&rettv);
- recursive--;
+ TRY_WRAP(err, {
+ ok = eval0(expr.data, &rettv, NULL, &EVALARG_EVALUATE);
+ clear_evalarg(&EVALARG_EVALUATE, NULL);
});
+ if (!ERROR_SET(err)) {
+ if (ok == FAIL) {
+ // Should never happen, try_end() (in TRY_WRAP) should get the error. #8371
+ api_set_error(err, kErrorTypeException,
+ "Failed to evaluate expression: '%.*s'", 256, expr.data);
+ } else {
+ rv = vim_to_object(&rettv);
+ }
+ }
+
+ tv_clear(&rettv);
+ recursive--;
+
return rv;
}
-/// Calls a VimL function.
+/// Calls a Vimscript function.
///
/// @param fn Function name
/// @param args Function arguments
@@ -196,34 +213,37 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
}
}
- TRY_WRAP({
- // Initialize `force_abort` and `suppress_errthrow` at the top level.
- if (!recursive) {
- force_abort = false;
- suppress_errthrow = false;
- did_throw = false;
- // `did_emsg` is set by emsg(), which cancels execution.
- did_emsg = false;
- }
- recursive++;
- try_start();
- typval_T rettv;
- funcexe_T funcexe = FUNCEXE_INIT;
- funcexe.fe_firstline = curwin->w_cursor.lnum;
- funcexe.fe_lastline = curwin->w_cursor.lnum;
- funcexe.fe_evaluate = true;
- funcexe.fe_selfdict = self;
+ // Initialize `force_abort` and `suppress_errthrow` at the top level.
+ if (!recursive) {
+ force_abort = false;
+ suppress_errthrow = false;
+ did_throw = false;
+ // `did_emsg` is set by emsg(), which cancels execution.
+ did_emsg = false;
+ }
+ recursive++;
+
+ typval_T rettv;
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.fe_firstline = curwin->w_cursor.lnum;
+ funcexe.fe_lastline = curwin->w_cursor.lnum;
+ funcexe.fe_evaluate = true;
+ funcexe.fe_selfdict = self;
+
+ TRY_WRAP(err, {
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
// (see above) to capture abort-causing non-exception errors.
(void)call_func(fn.data, (int)fn.size, &rettv, (int)args.size,
vim_args, &funcexe);
- if (!try_end(err)) {
- rv = vim_to_object(&rettv);
- }
- tv_clear(&rettv);
- recursive--;
});
+ if (!ERROR_SET(err)) {
+ rv = vim_to_object(&rettv);
+ }
+
+ tv_clear(&rettv);
+ recursive--;
+
free_vim_args:
while (i > 0) {
tv_clear(&vim_args[--i]);
@@ -232,9 +252,9 @@ free_vim_args:
return rv;
}
-/// Calls a VimL function with the given arguments.
+/// Calls a Vimscript function with the given arguments.
///
-/// On execution error: fails with VimL error, updates v:errmsg.
+/// On execution error: fails with Vimscript error, updates v:errmsg.
///
/// @param fn Function to call
/// @param args Function arguments packed in an Array
@@ -246,12 +266,12 @@ Object nvim_call_function(String fn, Array args, Error *err)
return _call_function(fn, args, NULL, err);
}
-/// Calls a VimL |Dictionary-function| with the given arguments.
+/// Calls a Vimscript |Dictionary-function| with the given arguments.
///
-/// On execution error: fails with VimL error, updates v:errmsg.
+/// On execution error: fails with Vimscript error, updates v:errmsg.
///
-/// @param dict Dictionary, or String evaluating to a VimL |self| dict
-/// @param fn Name of the function defined on the VimL dict
+/// @param dict Dictionary, or String evaluating to a Vimscript |self| dict
+/// @param fn Name of the function defined on the Vimscript dict
/// @param args Function arguments packed in an Array
/// @param[out] err Error details, if any
/// @return Result of the function call
@@ -265,10 +285,11 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
switch (dict.type) {
case kObjectTypeString:
try_start();
- if (eval0(dict.data.string.data, &rettv, NULL, true) == FAIL) {
+ if (eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE) == FAIL) {
api_set_error(err, kErrorTypeException,
"Failed to evaluate dict expression");
}
+ clear_evalarg(&EVALARG_EVALUATE, NULL);
if (try_end(err)) {
return rv;
}
@@ -336,7 +357,7 @@ typedef struct {
typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// @endcond
-/// Parse a VimL expression.
+/// Parse a Vimscript expression.
///
/// @param[in] expr Expression to parse. Always treated as a single line.
/// @param[in] flags Flags:
@@ -375,7 +396,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// stringified without "kExprNode" prefix.
/// - "start": a pair [line, column] describing where node is "started"
/// where "line" is always 0 (will not be 0 if you will be
-/// using nvim_parse_viml() on e.g. ":let", but that is not
+/// using this API on e.g. ":let", but that is not
/// present yet). Both elements are Integers.
/// - "len": “length” of the node. This and "start" are there for
/// debugging purposes primary (debugging parser and providing
@@ -475,7 +496,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
};
err_dict.items[0] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("message"),
- .value = STRING_OBJ(cstr_to_string(east.err.msg)),
+ .value = CSTR_TO_OBJ(east.err.msg),
};
if (east.err.arg == NULL) {
err_dict.items[1] = (KeyValuePair) {
@@ -512,7 +533,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
chunk_arr.items[0] = INTEGER_OBJ((Integer)chunk.start.line);
chunk_arr.items[1] = INTEGER_OBJ((Integer)chunk.start.col);
chunk_arr.items[2] = INTEGER_OBJ((Integer)chunk.end_col);
- chunk_arr.items[3] = STRING_OBJ(cstr_to_string(chunk.group));
+ chunk_arr.items[3] = CSTR_TO_OBJ(chunk.group);
hl.items[i] = ARRAY_OBJ(chunk_arr);
}
ret.items[ret.size++] = (KeyValuePair) {
@@ -589,7 +610,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
kv_drop(ast_conv_stack, 1);
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("type"),
- .value = STRING_OBJ(cstr_to_string(east_node_type_tab[node->type])),
+ .value = CSTR_TO_OBJ(east_node_type_tab[node->type]),
};
Array start_array = {
.items = xmalloc(2 * sizeof(start_array.items[0])),
@@ -674,11 +695,11 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, E
case kExprNodeComparison:
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("cmp_type"),
- .value = STRING_OBJ(cstr_to_string(eltkn_cmp_type_tab[node->data.cmp.type])),
+ .value = CSTR_TO_OBJ(eltkn_cmp_type_tab[node->data.cmp.type]),
};
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("ccs_strategy"),
- .value = STRING_OBJ(cstr_to_string(ccs_tab[node->data.cmp.ccs])),
+ .value = CSTR_TO_OBJ(ccs_tab[node->data.cmp.ccs]),
};
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("invert"),