diff options
author | bfredl <bjorn.linse@gmail.com> | 2022-06-12 00:37:39 +0200 |
---|---|---|
committer | bfredl <bjorn.linse@gmail.com> | 2022-06-12 16:09:42 +0200 |
commit | 4a275e3291d3eade38490801d9842640df3de202 (patch) | |
tree | 8aa5758bc82899645bdc799068b8eb3233a4cc69 | |
parent | 502f03fc064d1eb427d214521d5cb9f5425a15b4 (diff) | |
download | rneovim-4a275e3291d3eade38490801d9842640df3de202.tar.gz rneovim-4a275e3291d3eade38490801d9842640df3de202.tar.bz2 rneovim-4a275e3291d3eade38490801d9842640df3de202.zip |
refactor(api): move option code to own file
-rw-r--r-- | src/nvim/api/buffer.c | 38 | ||||
-rw-r--r-- | src/nvim/api/options.c | 509 | ||||
-rw-r--r-- | src/nvim/api/options.h | 9 | ||||
-rw-r--r-- | src/nvim/api/private/dispatch.c | 1 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 200 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 214 | ||||
-rw-r--r-- | src/nvim/api/window.c | 38 |
7 files changed, 519 insertions, 490 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 536be1d832..49a33d6039 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1035,44 +1035,6 @@ void nvim_buf_del_var(Buffer buffer, String name, Error *err) dict_set_var(buf->b_vars, name, NIL, true, false, err); } -/// Gets a buffer option value -/// -/// @param buffer Buffer handle, or 0 for current buffer -/// @param name Option name -/// @param[out] err Error details, if any -/// @return Option value -Object nvim_buf_get_option(Buffer buffer, String name, Error *err) - FUNC_API_SINCE(1) -{ - buf_T *buf = find_buffer_by_handle(buffer, err); - - if (!buf) { - return (Object)OBJECT_INIT; - } - - return get_option_from(buf, SREQ_BUF, name, err); -} - -/// Sets a buffer option value. Passing 'nil' as value deletes the option (only -/// works if there's a global fallback) -/// -/// @param channel_id -/// @param buffer Buffer handle, or 0 for current buffer -/// @param name Option name -/// @param value Option value -/// @param[out] err Error details, if any -void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err) - FUNC_API_SINCE(1) -{ - buf_T *buf = find_buffer_by_handle(buffer, err); - - if (!buf) { - return; - } - - set_option_to(channel_id, buf, SREQ_BUF, name, value, err); -} - /// Gets the full file name for the buffer /// /// @param buffer Buffer handle, or 0 for current buffer diff --git a/src/nvim/api/options.c b/src/nvim/api/options.c new file mode 100644 index 0000000000..61d4becd32 --- /dev/null +++ b/src/nvim/api/options.c @@ -0,0 +1,509 @@ +// 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 <inttypes.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "nvim/api/options.h" +#include "nvim/api/private/converter.h" +#include "nvim/api/private/helpers.h" +#include "nvim/autocmd.h" +#include "nvim/buffer.h" +#include "nvim/option.h" +#include "nvim/option_defs.h" +#include "nvim/window.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/options.c.generated.h" +#endif + +/// Gets the value of an option. The behavior of this function matches that of +/// |:set|: the local value of an option is returned if it exists; otherwise, +/// the global value is returned. Local values always correspond to the current +/// buffer or window. To get a buffer-local or window-local option for a +/// specific buffer or window, use |nvim_buf_get_option()| or +/// |nvim_win_get_option()|. +/// +/// @param name Option name +/// @param opts Optional parameters +/// - scope: One of 'global' or 'local'. Analogous to +/// |:setglobal| and |:setlocal|, respectively. +/// @param[out] err Error details, if any +/// @return Option value +Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) + FUNC_API_SINCE(9) +{ + Object rv = OBJECT_INIT; + + int scope = 0; + if (opts->scope.type == kObjectTypeString) { + if (!strcmp(opts->scope.data.string.data, "local")) { + scope = OPT_LOCAL; + } else if (!strcmp(opts->scope.data.string.data, "global")) { + scope = OPT_GLOBAL; + } else { + api_set_error(err, kErrorTypeValidation, "invalid scope: must be 'local' or 'global'"); + goto end; + } + } else if (HAS_KEY(opts->scope)) { + api_set_error(err, kErrorTypeValidation, "invalid value for key: scope"); + goto end; + } + + long numval = 0; + char *stringval = NULL; + switch (get_option_value(name.data, &numval, &stringval, scope)) { + case 0: + rv = STRING_OBJ(cstr_as_string(stringval)); + break; + case 1: + rv = INTEGER_OBJ(numval); + break; + case 2: + switch (numval) { + case 0: + case 1: + rv = BOOLEAN_OBJ(numval); + break; + default: + // Boolean options that return something other than 0 or 1 should return nil. Currently this + // only applies to 'autoread' which uses -1 as a local value to indicate "unset" + rv = NIL; + break; + } + break; + default: + api_set_error(err, kErrorTypeValidation, "unknown option '%s'", name.data); + goto end; + } + +end: + return rv; +} + +/// Sets the value of an option. The behavior of this function matches that of +/// |:set|: for global-local options, both the global and local value are set +/// unless otherwise specified with {scope}. +/// +/// Note the options {win} and {buf} cannot be used together. +/// +/// @param name Option name +/// @param value New option value +/// @param opts Optional parameters +/// - scope: One of 'global' or 'local'. Analogous to +/// |:setglobal| and |:setlocal|, respectively. +/// - win: |window-ID|. Used for setting window local option. +/// - buf: Buffer number. Used for setting buffer local option. +/// @param[out] err Error details, if any +void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error *err) + FUNC_API_SINCE(9) +{ + int scope = 0; + if (opts->scope.type == kObjectTypeString) { + if (!strcmp(opts->scope.data.string.data, "local")) { + scope = OPT_LOCAL; + } else if (!strcmp(opts->scope.data.string.data, "global")) { + scope = OPT_GLOBAL; + } else { + api_set_error(err, kErrorTypeValidation, "invalid scope: must be 'local' or 'global'"); + return; + } + } else if (HAS_KEY(opts->scope)) { + api_set_error(err, kErrorTypeValidation, "invalid value for key: scope"); + return; + } + + int opt_type = SREQ_GLOBAL; + void *to = NULL; + + if (opts->win.type == kObjectTypeInteger) { + opt_type = SREQ_WIN; + to = find_window_by_handle((int)opts->win.data.integer, err); + } else if (HAS_KEY(opts->win)) { + api_set_error(err, kErrorTypeValidation, "invalid value for key: win"); + return; + } + + if (opts->buf.type == kObjectTypeInteger) { + scope = OPT_LOCAL; + opt_type = SREQ_BUF; + to = find_buffer_by_handle((int)opts->buf.data.integer, err); + } else if (HAS_KEY(opts->buf)) { + api_set_error(err, kErrorTypeValidation, "invalid value for key: buf"); + return; + } + + if (HAS_KEY(opts->scope) && HAS_KEY(opts->buf)) { + api_set_error(err, kErrorTypeValidation, "scope and buf cannot be used together"); + return; + } + + if (HAS_KEY(opts->win) && HAS_KEY(opts->buf)) { + api_set_error(err, kErrorTypeValidation, "buf and win cannot be used together"); + return; + } + + long numval = 0; + char *stringval = NULL; + + switch (value.type) { + case kObjectTypeInteger: + numval = value.data.integer; + break; + case kObjectTypeBoolean: + numval = value.data.boolean ? 1 : 0; + break; + case kObjectTypeString: + stringval = value.data.string.data; + break; + case kObjectTypeNil: + scope |= OPT_CLEAR; + break; + default: + api_set_error(err, kErrorTypeValidation, "invalid value for option"); + return; + } + + set_option_value_for(name.data, numval, stringval, scope, opt_type, to, err); +} + +/// Gets the option information for all options. +/// +/// The dictionary has the full option names as keys and option metadata +/// dictionaries as detailed at |nvim_get_option_info|. +/// +/// @return dictionary of all options +Dictionary nvim_get_all_options_info(Error *err) + FUNC_API_SINCE(7) +{ + return get_all_vimoptions(); +} + +/// Gets the option information for one option +/// +/// Resulting dictionary has keys: +/// - name: Name of the option (like 'filetype') +/// - shortname: Shortened name of the option (like 'ft') +/// - type: type of option ("string", "number" or "boolean") +/// - default: The default value for the option +/// - was_set: Whether the option was set. +/// +/// - last_set_sid: Last set script id (if any) +/// - last_set_linenr: line number where option was set +/// - last_set_chan: Channel where option was set (0 for local) +/// +/// - scope: one of "global", "win", or "buf" +/// - global_local: whether win or buf option has a global value +/// +/// - commalist: List of comma separated values +/// - flaglist: List of single char flags +/// +/// +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option Information +Dictionary nvim_get_option_info(String name, Error *err) + FUNC_API_SINCE(7) +{ + return get_vimoption(name, err); +} +/// Sets the global value of an option. +/// +/// @param channel_id +/// @param name Option name +/// @param value New option value +/// @param[out] err Error details, if any +void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) + FUNC_API_SINCE(1) +{ + set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err); +} + +/// Gets the global value of an option. +/// +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option value (global) +Object nvim_get_option(String name, Error *err) + FUNC_API_SINCE(1) +{ + return get_option_from(NULL, SREQ_GLOBAL, name, err); +} + +/// Gets a buffer option value +/// +/// @param buffer Buffer handle, or 0 for current buffer +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option value +Object nvim_buf_get_option(Buffer buffer, String name, Error *err) + FUNC_API_SINCE(1) +{ + buf_T *buf = find_buffer_by_handle(buffer, err); + + if (!buf) { + return (Object)OBJECT_INIT; + } + + return get_option_from(buf, SREQ_BUF, name, err); +} + +/// Sets a buffer option value. Passing 'nil' as value deletes the option (only +/// works if there's a global fallback) +/// +/// @param channel_id +/// @param buffer Buffer handle, or 0 for current buffer +/// @param name Option name +/// @param value Option value +/// @param[out] err Error details, if any +void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err) + FUNC_API_SINCE(1) +{ + buf_T *buf = find_buffer_by_handle(buffer, err); + + if (!buf) { + return; + } + + set_option_to(channel_id, buf, SREQ_BUF, name, value, err); +} + +/// Gets a window option value +/// +/// @param window Window handle, or 0 for current window +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option value +Object nvim_win_get_option(Window window, String name, Error *err) + FUNC_API_SINCE(1) +{ + win_T *win = find_window_by_handle(window, err); + + if (!win) { + return (Object)OBJECT_INIT; + } + + return get_option_from(win, SREQ_WIN, name, err); +} + +/// Sets a window option value. Passing 'nil' as value deletes the option(only +/// works if there's a global fallback) +/// +/// @param channel_id +/// @param window Window handle, or 0 for current window +/// @param name Option name +/// @param value Option value +/// @param[out] err Error details, if any +void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object value, Error *err) + FUNC_API_SINCE(1) +{ + win_T *win = find_window_by_handle(window, err); + + if (!win) { + return; + } + + set_option_to(channel_id, win, SREQ_WIN, name, value, err); +} + +/// Gets the value of a global or local(buffer, window) option. +/// +/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer +/// to the window or buffer. +/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` +/// @param name The option name +/// @param[out] err Details of an error that may have occurred +/// @return the option value +Object get_option_from(void *from, int type, String name, Error *err) +{ + Object rv = OBJECT_INIT; + + if (name.size == 0) { + api_set_error(err, kErrorTypeValidation, "Empty option name"); + return rv; + } + + // Return values + int64_t numval; + char *stringval = NULL; + int flags = get_option_value_strict(name.data, &numval, &stringval, + type, from); + + if (!flags) { + api_set_error(err, kErrorTypeValidation, "Invalid option name: '%s'", + name.data); + return rv; + } + + if (flags & SOPT_BOOL) { + rv.type = kObjectTypeBoolean; + rv.data.boolean = numval ? true : false; + } else if (flags & SOPT_NUM) { + rv.type = kObjectTypeInteger; + rv.data.integer = numval; + } else if (flags & SOPT_STRING) { + if (stringval) { + rv.type = kObjectTypeString; + rv.data.string.data = stringval; + rv.data.string.size = strlen(stringval); + } else { + api_set_error(err, kErrorTypeException, + "Failed to get value for option '%s'", + name.data); + } + } else { + api_set_error(err, + kErrorTypeException, + "Unknown type for option '%s'", + name.data); + } + + return rv; +} + +/// Sets the value of a global or local(buffer, window) option. +/// +/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer +/// to the window or buffer. +/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` +/// @param name The option name +/// @param[out] err Details of an error that may have occurred +void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value, Error *err) +{ + if (name.size == 0) { + api_set_error(err, kErrorTypeValidation, "Empty option name"); + return; + } + + int flags = get_option_value_strict(name.data, NULL, NULL, type, to); + + if (flags == 0) { + api_set_error(err, kErrorTypeValidation, "Invalid option name '%s'", + name.data); + return; + } + + if (value.type == kObjectTypeNil) { + if (type == SREQ_GLOBAL) { + api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", + name.data); + return; + } else if (!(flags & SOPT_GLOBAL)) { + api_set_error(err, + kErrorTypeException, + "Cannot unset option '%s' " + "because it doesn't have a global value", + name.data); + return; + } else { + unset_global_local_option(name.data, to); + return; + } + } + + int numval = 0; + char *stringval = NULL; + + if (flags & SOPT_BOOL) { + if (value.type != kObjectTypeBoolean) { + api_set_error(err, + kErrorTypeValidation, + "Option '%s' requires a Boolean value", + name.data); + return; + } + + numval = value.data.boolean; + } else if (flags & SOPT_NUM) { + if (value.type != kObjectTypeInteger) { + api_set_error(err, kErrorTypeValidation, + "Option '%s' requires an integer value", + name.data); + return; + } + + if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { + api_set_error(err, kErrorTypeValidation, + "Value for option '%s' is out of range", + name.data); + return; + } + + numval = (int)value.data.integer; + } else { + if (value.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, + "Option '%s' requires a string value", + name.data); + return; + } + + stringval = value.data.string.data; + } + + WITH_SCRIPT_CONTEXT(channel_id, { + const int opt_flags = (type == SREQ_WIN && !(flags & SOPT_GLOBAL)) + ? 0 : (type == SREQ_GLOBAL) + ? OPT_GLOBAL : OPT_LOCAL; + + set_option_value_for(name.data, numval, stringval, + opt_flags, type, to, err); + }); +} + +void set_option_value_for(char *key, long numval, char *stringval, int opt_flags, int opt_type, + void *from, Error *err) +{ + switchwin_T switchwin; + aco_save_T aco; + + try_start(); + switch (opt_type) { + case SREQ_WIN: + if (switch_win_noblock(&switchwin, (win_T *)from, win_find_tabpage((win_T *)from), true) + == FAIL) { + restore_win_noblock(&switchwin, true); + if (try_end(err)) { + return; + } + api_set_error(err, + kErrorTypeException, + "Problem while switching windows"); + return; + } + set_option_value_err(key, numval, stringval, opt_flags, err); + restore_win_noblock(&switchwin, true); + break; + case SREQ_BUF: + aucmd_prepbuf(&aco, (buf_T *)from); + set_option_value_err(key, numval, stringval, opt_flags, err); + aucmd_restbuf(&aco); + break; + case SREQ_GLOBAL: + set_option_value_err(key, numval, stringval, opt_flags, err); + break; + } + + if (ERROR_SET(err)) { + return; + } + + try_end(err); +} + +static void set_option_value_err(char *key, long numval, char *stringval, int opt_flags, Error *err) +{ + char *errmsg; + + if ((errmsg = set_option_value(key, numval, stringval, opt_flags))) { + if (try_end(err)) { + return; + } + + api_set_error(err, kErrorTypeException, "%s", errmsg); + } +} diff --git a/src/nvim/api/options.h b/src/nvim/api/options.h new file mode 100644 index 0000000000..efbfec3a6c --- /dev/null +++ b/src/nvim/api/options.h @@ -0,0 +1,9 @@ +#ifndef NVIM_API_OPTIONS_H +#define NVIM_API_OPTIONS_H + +#include "nvim/api/private/defs.h" +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/options.h.generated.h" +#endif + +#endif // NVIM_API_OPTIONS_H diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c index 3da2c2cde4..d2ffd8879a 100644 --- a/src/nvim/api/private/dispatch.c +++ b/src/nvim/api/private/dispatch.c @@ -24,6 +24,7 @@ #include "nvim/api/autocmd.h" #include "nvim/api/buffer.h" #include "nvim/api/extmark.h" +#include "nvim/api/options.h" #include "nvim/api/tabpage.h" #include "nvim/api/ui.h" #include "nvim/api/vim.h" diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index bdbbe9aa88..13e3f70ce1 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -32,8 +32,6 @@ #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/helpers.h" -#include "nvim/option.h" -#include "nvim/option_defs.h" #include "nvim/ui.h" #include "nvim/version.h" #include "nvim/vim.h" @@ -262,151 +260,6 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva return rv; } -/// Gets the value of a global or local(buffer, window) option. -/// -/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer -/// to the window or buffer. -/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -/// @return the option value -Object get_option_from(void *from, int type, String name, Error *err) -{ - Object rv = OBJECT_INIT; - - if (name.size == 0) { - api_set_error(err, kErrorTypeValidation, "Empty option name"); - return rv; - } - - // Return values - int64_t numval; - char *stringval = NULL; - int flags = get_option_value_strict(name.data, &numval, &stringval, - type, from); - - if (!flags) { - api_set_error(err, kErrorTypeValidation, "Invalid option name: '%s'", - name.data); - return rv; - } - - if (flags & SOPT_BOOL) { - rv.type = kObjectTypeBoolean; - rv.data.boolean = numval ? true : false; - } else if (flags & SOPT_NUM) { - rv.type = kObjectTypeInteger; - rv.data.integer = numval; - } else if (flags & SOPT_STRING) { - if (stringval) { - rv.type = kObjectTypeString; - rv.data.string.data = stringval; - rv.data.string.size = strlen(stringval); - } else { - api_set_error(err, kErrorTypeException, - "Failed to get value for option '%s'", - name.data); - } - } else { - api_set_error(err, - kErrorTypeException, - "Unknown type for option '%s'", - name.data); - } - - return rv; -} - -/// Sets the value of a global or local(buffer, window) option. -/// -/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer -/// to the window or buffer. -/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value, Error *err) -{ - if (name.size == 0) { - api_set_error(err, kErrorTypeValidation, "Empty option name"); - return; - } - - int flags = get_option_value_strict(name.data, NULL, NULL, type, to); - - if (flags == 0) { - api_set_error(err, kErrorTypeValidation, "Invalid option name '%s'", - name.data); - return; - } - - if (value.type == kObjectTypeNil) { - if (type == SREQ_GLOBAL) { - api_set_error(err, kErrorTypeException, "Cannot unset option '%s'", - name.data); - return; - } else if (!(flags & SOPT_GLOBAL)) { - api_set_error(err, - kErrorTypeException, - "Cannot unset option '%s' " - "because it doesn't have a global value", - name.data); - return; - } else { - unset_global_local_option(name.data, to); - return; - } - } - - int numval = 0; - char *stringval = NULL; - - if (flags & SOPT_BOOL) { - if (value.type != kObjectTypeBoolean) { - api_set_error(err, - kErrorTypeValidation, - "Option '%s' requires a Boolean value", - name.data); - return; - } - - numval = value.data.boolean; - } else if (flags & SOPT_NUM) { - if (value.type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, - "Option '%s' requires an integer value", - name.data); - return; - } - - if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { - api_set_error(err, kErrorTypeValidation, - "Value for option '%s' is out of range", - name.data); - return; - } - - numval = (int)value.data.integer; - } else { - if (value.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "Option '%s' requires a string value", - name.data); - return; - } - - stringval = value.data.string.data; - } - - WITH_SCRIPT_CONTEXT(channel_id, { - const int opt_flags = (type == SREQ_WIN && !(flags & SOPT_GLOBAL)) - ? 0 : (type == SREQ_GLOBAL) - ? OPT_GLOBAL : OPT_LOCAL; - - set_option_value_for(name.data, numval, stringval, - opt_flags, type, to, err); - }); -} - buf_T *find_buffer_by_handle(Buffer buffer, Error *err) { if (buffer == 0) { @@ -1035,59 +888,6 @@ Object copy_object(Object obj) } } -void set_option_value_for(char *key, long numval, char *stringval, int opt_flags, int opt_type, - void *from, Error *err) -{ - switchwin_T switchwin; - aco_save_T aco; - - try_start(); - switch (opt_type) { - case SREQ_WIN: - if (switch_win_noblock(&switchwin, (win_T *)from, win_find_tabpage((win_T *)from), true) - == FAIL) { - restore_win_noblock(&switchwin, true); - if (try_end(err)) { - return; - } - api_set_error(err, - kErrorTypeException, - "Problem while switching windows"); - return; - } - set_option_value_err(key, numval, stringval, opt_flags, err); - restore_win_noblock(&switchwin, true); - break; - case SREQ_BUF: - aucmd_prepbuf(&aco, (buf_T *)from); - set_option_value_err(key, numval, stringval, opt_flags, err); - aucmd_restbuf(&aco); - break; - case SREQ_GLOBAL: - set_option_value_err(key, numval, stringval, opt_flags, err); - break; - } - - if (ERROR_SET(err)) { - return; - } - - try_end(err); -} - -static void set_option_value_err(char *key, long numval, char *stringval, int opt_flags, Error *err) -{ - char *errmsg; - - if ((errmsg = set_option_value(key, numval, stringval, opt_flags))) { - if (try_end(err)) { - return; - } - - api_set_error(err, kErrorTypeException, "%s", errmsg); - } -} - void api_set_error(Error *err, ErrorType errType, const char *format, ...) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PRINTF(3, 4) { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 5f7162cdd6..f4a6c5e9e3 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -708,220 +708,6 @@ void nvim_set_vvar(String name, Object value, Error *err) dict_set_var(&vimvardict, name, value, false, false, err); } -/// Gets the global value of an option. -/// -/// @param name Option name -/// @param[out] err Error details, if any -/// @return Option value (global) -Object nvim_get_option(String name, Error *err) - FUNC_API_SINCE(1) -{ - return get_option_from(NULL, SREQ_GLOBAL, name, err); -} - -/// Gets the value of an option. The behavior of this function matches that of -/// |:set|: the local value of an option is returned if it exists; otherwise, -/// the global value is returned. Local values always correspond to the current -/// buffer or window. To get a buffer-local or window-local option for a -/// specific buffer or window, use |nvim_buf_get_option()| or -/// |nvim_win_get_option()|. -/// -/// @param name Option name -/// @param opts Optional parameters -/// - scope: One of 'global' or 'local'. Analogous to -/// |:setglobal| and |:setlocal|, respectively. -/// @param[out] err Error details, if any -/// @return Option value -Object nvim_get_option_value(String name, Dict(option) *opts, Error *err) - FUNC_API_SINCE(9) -{ - Object rv = OBJECT_INIT; - - int scope = 0; - if (opts->scope.type == kObjectTypeString) { - if (!strcmp(opts->scope.data.string.data, "local")) { - scope = OPT_LOCAL; - } else if (!strcmp(opts->scope.data.string.data, "global")) { - scope = OPT_GLOBAL; - } else { - api_set_error(err, kErrorTypeValidation, "invalid scope: must be 'local' or 'global'"); - goto end; - } - } else if (HAS_KEY(opts->scope)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: scope"); - goto end; - } - - long numval = 0; - char *stringval = NULL; - switch (get_option_value(name.data, &numval, &stringval, scope)) { - case 0: - rv = STRING_OBJ(cstr_as_string(stringval)); - break; - case 1: - rv = INTEGER_OBJ(numval); - break; - case 2: - switch (numval) { - case 0: - case 1: - rv = BOOLEAN_OBJ(numval); - break; - default: - // Boolean options that return something other than 0 or 1 should return nil. Currently this - // only applies to 'autoread' which uses -1 as a local value to indicate "unset" - rv = NIL; - break; - } - break; - default: - api_set_error(err, kErrorTypeValidation, "unknown option '%s'", name.data); - goto end; - } - -end: - return rv; -} - -/// Sets the value of an option. The behavior of this function matches that of -/// |:set|: for global-local options, both the global and local value are set -/// unless otherwise specified with {scope}. -/// -/// Note the options {win} and {buf} cannot be used together. -/// -/// @param name Option name -/// @param value New option value -/// @param opts Optional parameters -/// - scope: One of 'global' or 'local'. Analogous to -/// |:setglobal| and |:setlocal|, respectively. -/// - win: |window-ID|. Used for setting window local option. -/// - buf: Buffer number. Used for setting buffer local option. -/// @param[out] err Error details, if any -void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error *err) - FUNC_API_SINCE(9) -{ - int scope = 0; - if (opts->scope.type == kObjectTypeString) { - if (!strcmp(opts->scope.data.string.data, "local")) { - scope = OPT_LOCAL; - } else if (!strcmp(opts->scope.data.string.data, "global")) { - scope = OPT_GLOBAL; - } else { - api_set_error(err, kErrorTypeValidation, "invalid scope: must be 'local' or 'global'"); - return; - } - } else if (HAS_KEY(opts->scope)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: scope"); - return; - } - - int opt_type = SREQ_GLOBAL; - void *to = NULL; - - if (opts->win.type == kObjectTypeInteger) { - opt_type = SREQ_WIN; - to = find_window_by_handle((int)opts->win.data.integer, err); - } else if (HAS_KEY(opts->win)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: win"); - return; - } - - if (opts->buf.type == kObjectTypeInteger) { - scope = OPT_LOCAL; - opt_type = SREQ_BUF; - to = find_buffer_by_handle((int)opts->buf.data.integer, err); - } else if (HAS_KEY(opts->buf)) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: buf"); - return; - } - - if (HAS_KEY(opts->scope) && HAS_KEY(opts->buf)) { - api_set_error(err, kErrorTypeValidation, "scope and buf cannot be used together"); - return; - } - - if (HAS_KEY(opts->win) && HAS_KEY(opts->buf)) { - api_set_error(err, kErrorTypeValidation, "buf and win cannot be used together"); - return; - } - - long numval = 0; - char *stringval = NULL; - - switch (value.type) { - case kObjectTypeInteger: - numval = value.data.integer; - break; - case kObjectTypeBoolean: - numval = value.data.boolean ? 1 : 0; - break; - case kObjectTypeString: - stringval = value.data.string.data; - break; - case kObjectTypeNil: - scope |= OPT_CLEAR; - break; - default: - api_set_error(err, kErrorTypeValidation, "invalid value for option"); - return; - } - - set_option_value_for(name.data, numval, stringval, scope, opt_type, to, err); -} - -/// Gets the option information for all options. -/// -/// The dictionary has the full option names as keys and option metadata -/// dictionaries as detailed at |nvim_get_option_info|. -/// -/// @return dictionary of all options -Dictionary nvim_get_all_options_info(Error *err) - FUNC_API_SINCE(7) -{ - return get_all_vimoptions(); -} - -/// Gets the option information for one option -/// -/// Resulting dictionary has keys: -/// - name: Name of the option (like 'filetype') -/// - shortname: Shortened name of the option (like 'ft') -/// - type: type of option ("string", "number" or "boolean") -/// - default: The default value for the option -/// - was_set: Whether the option was set. -/// -/// - last_set_sid: Last set script id (if any) -/// - last_set_linenr: line number where option was set -/// - last_set_chan: Channel where option was set (0 for local) -/// -/// - scope: one of "global", "win", or "buf" -/// - global_local: whether win or buf option has a global value -/// -/// - commalist: List of comma separated values -/// - flaglist: List of single char flags -/// -/// -/// @param name Option name -/// @param[out] err Error details, if any -/// @return Option Information -Dictionary nvim_get_option_info(String name, Error *err) - FUNC_API_SINCE(7) -{ - return get_vimoption(name, err); -} - -/// Sets the global value of an option. -/// -/// @param channel_id -/// @param name Option name -/// @param value New option value -/// @param[out] err Error details, if any -void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err) - FUNC_API_SINCE(1) -{ - set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err); -} - /// Echo a message. /// /// @param chunks A list of [text, hl_group] arrays, each representing a diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 9f2afc67a6..5a4ff70257 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -264,44 +264,6 @@ void nvim_win_del_var(Window window, String name, Error *err) dict_set_var(win->w_vars, name, NIL, true, false, err); } -/// Gets a window option value -/// -/// @param window Window handle, or 0 for current window -/// @param name Option name -/// @param[out] err Error details, if any -/// @return Option value -Object nvim_win_get_option(Window window, String name, Error *err) - FUNC_API_SINCE(1) -{ - win_T *win = find_window_by_handle(window, err); - - if (!win) { - return (Object)OBJECT_INIT; - } - - return get_option_from(win, SREQ_WIN, name, err); -} - -/// Sets a window option value. Passing 'nil' as value deletes the option(only -/// works if there's a global fallback) -/// -/// @param channel_id -/// @param window Window handle, or 0 for current window -/// @param name Option name -/// @param value Option value -/// @param[out] err Error details, if any -void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object value, Error *err) - FUNC_API_SINCE(1) -{ - win_T *win = find_window_by_handle(window, err); - - if (!win) { - return; - } - - set_option_to(channel_id, win, SREQ_WIN, name, value, err); -} - /// Gets the window position in display cells. First position is zero. /// /// @param window Window handle, or 0 for current window |