From 35767912bbe9da4556aab122ba00488c56dd9f17 Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Tue, 27 Oct 2020 22:20:52 -0400 Subject: [PATCH 1/4] api/options: add option metadata --- src/nvim/api/vim.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++ src/nvim/option.c | 52 +++++++++++++++++++++--------------------- src/nvim/option.h | 21 +++++++++++++++++ 3 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 77002697fe..c5dc89410a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -970,6 +970,62 @@ Object nvim_get_option(String name, Error *err) return get_option_from(NULL, SREQ_GLOBAL, name, err); } +Dictionary nvim_get_vimoption_info(Error *err) + FUNC_API_SINCE(7) +{ + Dictionary retval = ARRAY_DICT_INIT; + + vimoption_T *all_options = get_all_vimoptions(); + + int i = 0; + vimoption_T opt; + while (true) { + opt = all_options[i++]; + if (opt.fullname == NULL) { + break; + } + + Dictionary opt_dict = ARRAY_DICT_INIT; + + PUT(opt_dict, "fullname", STRING_OBJ(cstr_to_string(opt.fullname))); + PUT(opt_dict, "shortname", STRING_OBJ(cstr_to_string(opt.shortname))); + PUT(opt_dict, "is_global", BOOLEAN_OBJ(opt.flags & OPT_GLOBAL)); + PUT(opt_dict, "is_local", BOOLEAN_OBJ(opt.flags & OPT_LOCAL)); + PUT(opt_dict, "flag", INTEGER_OBJ(opt.flags)); + PUT(opt_dict, "sourced_sid", INTEGER_OBJ(opt.last_set.script_ctx.sc_sid)); + PUT(opt_dict, "sourced_lnum", INTEGER_OBJ(opt.last_set.script_ctx.sc_lnum)); + PUT(opt_dict, "type", STRING_OBJ(get_option_type_string(opt))); + + PUT(retval, opt.fullname, DICTIONARY_OBJ(opt_dict)); + } + + return retval; +} + +Dictionary nvim_get_option_info(String name, Error *err) + FUNC_API_SINCE(7) +{ + Dictionary retval = ARRAY_DICT_INIT; + + get_option_from(NULL, SREQ_GLOBAL, name, err); + if (ERROR_SET(err)) { + return retval; + } + + int opt_idx = findoption_len((const char *)name.data, name.size); + vimoption_T opt = get_vimoption(opt_idx); + + PUT(retval, "fullname", STRING_OBJ(cstr_to_string(opt.fullname))); + PUT(retval, "shortname", STRING_OBJ(cstr_to_string(opt.shortname))); + PUT(retval, "is_global", BOOLEAN_OBJ(opt.flags & OPT_GLOBAL)); + PUT(retval, "is_local", BOOLEAN_OBJ(opt.flags & OPT_LOCAL)); + PUT(retval, "flag", INTEGER_OBJ(opt.flags)); + PUT(retval, "sourced_sid", INTEGER_OBJ(opt.last_set.script_ctx.sc_sid)); + PUT(retval, "sourced_lnum", INTEGER_OBJ(opt.last_set.script_ctx.sc_lnum)); + + return retval; +} + /// Sets an option value. /// /// @param channel_id diff --git a/src/nvim/option.c b/src/nvim/option.c index 0034117ddc..5e3f917bed 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -102,13 +102,6 @@ #define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x)) #define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x)) - -// WV_ and BV_ values get typecasted to this for the "indir" field -typedef enum { - PV_NONE = 0, - PV_MAXVAL = 0xffff // to avoid warnings for value out of range -} idopt_T; - /* * Options local to a window have a value local to a buffer and global to all * buffers. Indicate this by setting "var" to VAR_WIN. @@ -195,20 +188,6 @@ static long p_sts_nopaste; static long p_tw_nopaste; static long p_wm_nopaste; -typedef struct vimoption { - char *fullname; // full option name - char *shortname; // permissible abbreviation - uint32_t flags; // see below - char_u *var; // global option: pointer to variable; - // window-local option: VAR_WIN; - // buffer-local option: global value - idopt_T indir; // global option: PV_NONE; - // local option: indirect option index - char_u *def_val[2]; // default values for variable (vi and vim) - LastSet last_set; // script in which the option was last set -# define SCTX_INIT , { 0, 0, 0 } -} vimoption_T; - #define VI_DEFAULT 0 // def_val[VI_DEFAULT] is Vi default value #define VIM_DEFAULT 1 // def_val[VIM_DEFAULT] is Vim default value @@ -3617,10 +3596,14 @@ static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) { int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; int indir = (int)options[opt_idx].indir; - const LastSet last_set = { .script_ctx = - { script_ctx.sc_sid, script_ctx.sc_seq, - script_ctx.sc_lnum + sourcing_lnum }, - current_channel_id }; + const LastSet last_set = { + .script_ctx = { + script_ctx.sc_sid, + script_ctx.sc_seq, + script_ctx.sc_lnum + sourcing_lnum + }, + current_channel_id + }; // Remember where the option was set. For local options need to do that // in the buffer or window structure. @@ -7174,3 +7157,22 @@ long get_sidescrolloff_value(void) { return curwin->w_p_siso < 0 ? p_siso : curwin->w_p_siso; } + +vimoption_T get_vimoption(int opt_idx) +{ + return options[opt_idx]; +} + +vimoption_T* get_all_vimoptions(void) +{ + return options; +} + +String get_option_type_string(vimoption_T opt) +{ + return cstr_to_string( + opt.flags & P_BOOL ? "boolean" + : opt.flags & P_NUM ? "number" + : opt.flags & P_STRING ? "string" + : "unknown"); +} diff --git a/src/nvim/option.h b/src/nvim/option.h index 60f14dea44..1bf28e1ce8 100644 --- a/src/nvim/option.h +++ b/src/nvim/option.h @@ -21,6 +21,27 @@ typedef enum { OPT_NOWIN = 32, ///< Don’t set window-local options. } OptionFlags; +// WV_ and BV_ values get typecasted to this for the "indir" field +typedef enum { + PV_NONE = 0, + PV_MAXVAL = 0xffff // to avoid warnings for value out of range +} idopt_T; + +typedef struct vimoption { + char *fullname; // full option name + char *shortname; // permissible abbreviation + uint32_t flags; // see below + char_u *var; // global option: pointer to variable; + // window-local option: VAR_WIN; + // buffer-local option: global value + idopt_T indir; // global option: PV_NONE; + // local option: indirect option index + char_u *def_val[2]; // default values for variable (vi and vim) + LastSet last_set; // script in which the option was last set +# define SCTX_INIT , { 0, 0, 0 } +} vimoption_T; + + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "option.h.generated.h" #endif From 3b3c006ae34256637f101ea85a84998377f56e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= Date: Tue, 1 Dec 2020 22:10:41 +0100 Subject: [PATCH 2/4] api/options: cleanup --- src/nvim/api/vim.c | 50 ++------------------ src/nvim/option.c | 104 ++++++++++++++++++++++++++++++++++------- src/nvim/option.h | 21 --------- src/nvim/option_defs.h | 1 - 4 files changed, 90 insertions(+), 86 deletions(-) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index c5dc89410a..b3576bc436 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -970,60 +970,16 @@ Object nvim_get_option(String name, Error *err) return get_option_from(NULL, SREQ_GLOBAL, name, err); } -Dictionary nvim_get_vimoption_info(Error *err) +Dictionary nvim_get_options_info(Error *err) FUNC_API_SINCE(7) { - Dictionary retval = ARRAY_DICT_INIT; - - vimoption_T *all_options = get_all_vimoptions(); - - int i = 0; - vimoption_T opt; - while (true) { - opt = all_options[i++]; - if (opt.fullname == NULL) { - break; - } - - Dictionary opt_dict = ARRAY_DICT_INIT; - - PUT(opt_dict, "fullname", STRING_OBJ(cstr_to_string(opt.fullname))); - PUT(opt_dict, "shortname", STRING_OBJ(cstr_to_string(opt.shortname))); - PUT(opt_dict, "is_global", BOOLEAN_OBJ(opt.flags & OPT_GLOBAL)); - PUT(opt_dict, "is_local", BOOLEAN_OBJ(opt.flags & OPT_LOCAL)); - PUT(opt_dict, "flag", INTEGER_OBJ(opt.flags)); - PUT(opt_dict, "sourced_sid", INTEGER_OBJ(opt.last_set.script_ctx.sc_sid)); - PUT(opt_dict, "sourced_lnum", INTEGER_OBJ(opt.last_set.script_ctx.sc_lnum)); - PUT(opt_dict, "type", STRING_OBJ(get_option_type_string(opt))); - - PUT(retval, opt.fullname, DICTIONARY_OBJ(opt_dict)); - } - - return retval; + return get_all_vimoptions(); } Dictionary nvim_get_option_info(String name, Error *err) FUNC_API_SINCE(7) { - Dictionary retval = ARRAY_DICT_INIT; - - get_option_from(NULL, SREQ_GLOBAL, name, err); - if (ERROR_SET(err)) { - return retval; - } - - int opt_idx = findoption_len((const char *)name.data, name.size); - vimoption_T opt = get_vimoption(opt_idx); - - PUT(retval, "fullname", STRING_OBJ(cstr_to_string(opt.fullname))); - PUT(retval, "shortname", STRING_OBJ(cstr_to_string(opt.shortname))); - PUT(retval, "is_global", BOOLEAN_OBJ(opt.flags & OPT_GLOBAL)); - PUT(retval, "is_local", BOOLEAN_OBJ(opt.flags & OPT_LOCAL)); - PUT(retval, "flag", INTEGER_OBJ(opt.flags)); - PUT(retval, "sourced_sid", INTEGER_OBJ(opt.last_set.script_ctx.sc_sid)); - PUT(retval, "sourced_lnum", INTEGER_OBJ(opt.last_set.script_ctx.sc_lnum)); - - return retval; + return get_vimoption(name, err); } /// Sets an option value. diff --git a/src/nvim/option.c b/src/nvim/option.c index 5e3f917bed..12468adbe8 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -102,6 +102,13 @@ #define OPT_BUF(x) (idopt_T)(PV_BUF + (int)(x)) #define OPT_BOTH(x) (idopt_T)(PV_BOTH + (int)(x)) + +// WV_ and BV_ values get typecasted to this for the "indir" field +typedef enum { + PV_NONE = 0, + PV_MAXVAL = 0xffff // to avoid warnings for value out of range +} idopt_T; + /* * Options local to a window have a value local to a buffer and global to all * buffers. Indicate this by setting "var" to VAR_WIN. @@ -188,6 +195,20 @@ static long p_sts_nopaste; static long p_tw_nopaste; static long p_wm_nopaste; +typedef struct vimoption { + char *fullname; // full option name + char *shortname; // permissible abbreviation + uint32_t flags; // see below + char_u *var; // global option: pointer to variable; + // window-local option: VAR_WIN; + // buffer-local option: global value + idopt_T indir; // global option: PV_NONE; + // local option: indirect option index + char_u *def_val[2]; // default values for variable (vi and vim) + LastSet last_set; // script in which the option was last set +# define SCTX_INIT , { 0, 0, 0 } +} vimoption_T; + #define VI_DEFAULT 0 // def_val[VI_DEFAULT] is Vi default value #define VIM_DEFAULT 1 // def_val[VIM_DEFAULT] is Vim default value @@ -331,9 +352,6 @@ void set_init_1(bool clean_arg) langmap_init(); - // Be nocompatible - p_cp = false; - /* * Find default value for 'shell' option. * Don't use it if it is empty. @@ -662,7 +680,7 @@ set_options_default( { for (int i = 0; options[i].fullname; i++) { if (!(options[i].flags & P_NODEFAULT)) { - set_option_default(i, opt_flags, p_cp); + set_option_default(i, opt_flags, false); } } @@ -742,7 +760,7 @@ void set_init_2(bool headless) // which results in the actual value computed from the window height. idx = findoption("scroll"); if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { - set_option_default(idx, OPT_LOCAL, p_cp); + set_option_default(idx, OPT_LOCAL, false); } comp_col(); @@ -1092,7 +1110,7 @@ int do_set( if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL) { arg += len; - cp_val = p_cp; + cp_val = false; if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') { if (arg[3] == 'm') { // "opt&vim": set to Vim default cp_val = false; @@ -4933,7 +4951,7 @@ static int optval_default(vimoption_T *p, char_u *varp) if (varp == NULL) { return true; // hidden option is always at default } - dvi = ((p->flags & P_VI_DEF) || p_cp) ? VI_DEFAULT : VIM_DEFAULT; + dvi = (p->flags & P_VI_DEF) ? VI_DEFAULT : VIM_DEFAULT; if (p->flags & P_NUM) { return *(long *)varp == (long)(intptr_t)p->def_val[dvi]; } @@ -7158,21 +7176,73 @@ long get_sidescrolloff_value(void) return curwin->w_p_siso < 0 ? p_siso : curwin->w_p_siso; } -vimoption_T get_vimoption(int opt_idx) +Dictionary get_vimoption(String name, Error *err) { - return options[opt_idx]; + int opt_idx = findoption_len((const char *)name.data, name.size); + if (opt_idx < 0) { + api_set_error(err, kErrorTypeValidation, "no such option %s", name.data); + return (Dictionary)ARRAY_DICT_INIT; + } + return vimoption2dict(&options[opt_idx]); } -vimoption_T* get_all_vimoptions(void) +Dictionary get_all_vimoptions(void) { - return options; + Dictionary retval = ARRAY_DICT_INIT; + for (size_t i = 0; i < PARAM_COUNT; i++) { + Dictionary opt_dict = vimoption2dict(&options[i]); + PUT(retval, options[i].fullname, DICTIONARY_OBJ(opt_dict)); + } + return retval; } -String get_option_type_string(vimoption_T opt) +static Dictionary vimoption2dict(vimoption_T *opt) { - return cstr_to_string( - opt.flags & P_BOOL ? "boolean" - : opt.flags & P_NUM ? "number" - : opt.flags & P_STRING ? "string" - : "unknown"); + Dictionary dict = ARRAY_DICT_INIT; + + PUT(dict, "name", STRING_OBJ(cstr_to_string(opt->fullname))); + PUT(dict, "shortname", STRING_OBJ(cstr_to_string(opt->shortname))); +#define PUT_IF(dict, name, condition) do if (condition) \ + { PUT(dict, name, BOOLEAN_OBJ(true)); } while (0) + PUT_IF(dict, "win", opt->indir & PV_WIN); + PUT_IF(dict, "buf", opt->indir & PV_BUF); + // welcome to the jungle + PUT_IF(dict, "global_local", opt->indir & PV_BOTH); + PUT_IF(dict, "commalist", opt->flags & P_COMMA); + PUT_IF(dict, "flaglist", opt->flags & P_FLAGLIST); + + PUT_IF(dict, "was_set", opt->flags & P_WAS_SET); + + PUT(dict, "flag", INTEGER_OBJ(opt->flags)); // TODO(bfredl): lol tj + PUT(dict, "last_set_sid", INTEGER_OBJ(opt->last_set.script_ctx.sc_sid)); + if (opt->last_set.script_ctx.sc_lnum > 0) { + PUT(dict, "last_set_linenr", + INTEGER_OBJ(opt->last_set.script_ctx.sc_lnum)); + } + if (opt->last_set.channel_id > 0) { + PUT(dict, "last_set_lchan", + INTEGER_OBJ((int64_t)opt->last_set.channel_id)); + } + + const char *type; + Object def; + // TODO(bfredl): do you even nocp? + char_u *def_val = opt->def_val[(opt->flags & P_VI_DEF) + ? VI_DEFAULT : VIM_DEFAULT]; + if (opt->flags & P_STRING) { + type = "string"; + def = STRING_OBJ(cstr_to_string(def_val ? (char *)def_val : "")); + } else if (opt->flags & P_NUM) { + type = "string"; + def = INTEGER_OBJ((Integer)(intptr_t)def_val); + } else if (opt->flags & P_BOOL) { + type = "boolean"; + def = BOOLEAN_OBJ((intptr_t)def_val); + } else { + type = ""; def = NIL; + } + PUT(dict, "type", STRING_OBJ(cstr_to_string(type))); + PUT(dict, "default", def); + + return dict; } diff --git a/src/nvim/option.h b/src/nvim/option.h index 1bf28e1ce8..60f14dea44 100644 --- a/src/nvim/option.h +++ b/src/nvim/option.h @@ -21,27 +21,6 @@ typedef enum { OPT_NOWIN = 32, ///< Don’t set window-local options. } OptionFlags; -// WV_ and BV_ values get typecasted to this for the "indir" field -typedef enum { - PV_NONE = 0, - PV_MAXVAL = 0xffff // to avoid warnings for value out of range -} idopt_T; - -typedef struct vimoption { - char *fullname; // full option name - char *shortname; // permissible abbreviation - uint32_t flags; // see below - char_u *var; // global option: pointer to variable; - // window-local option: VAR_WIN; - // buffer-local option: global value - idopt_T indir; // global option: PV_NONE; - // local option: indirect option index - char_u *def_val[2]; // default values for variable (vi and vim) - LastSet last_set; // script in which the option was last set -# define SCTX_INIT , { 0, 0, 0 } -} vimoption_T; - - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "option.h.generated.h" #endif diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index af0ea7f4a2..ec2160d365 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -372,7 +372,6 @@ EXTERN long p_cwh; // 'cmdwinheight' EXTERN long p_ch; // 'cmdheight' EXTERN long p_columns; // 'columns' EXTERN int p_confirm; // 'confirm' -EXTERN int p_cp; // 'compatible' EXTERN char_u *p_cot; // 'completeopt' # ifdef BACKSLASH_IN_FILENAME EXTERN char_u *p_csl; // 'completeslash' From ced951c2aacd175c21c68a5bbf7fdf459954d0ab Mon Sep 17 00:00:00 2001 From: TJ DeVries Date: Thu, 3 Dec 2020 20:59:36 -0500 Subject: [PATCH 3/4] api/options: fixup --- runtime/doc/api.txt | 44 ++++++++++++++++++++++++-- src/nvim/api/vim.c | 26 ++++++++++++++++ src/nvim/option.c | 39 ++++++++++++----------- test/functional/api/vim_spec.lua | 53 ++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 20 deletions(-) diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 58633455c3..755e7becb3 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -933,6 +933,39 @@ nvim_get_option({name}) *nvim_get_option()* Return: ~ Option value (global) +nvim_get_option_info({name}) *nvim_get_option_info()* + Gets the option information for one option + + Resulting dictionary has keys: + • name (string): Name of the option + • shortname (shortname): Shortened name of the option + • type (string): Name of the type of option + • default (Any): The default value for the option + + Script-Related Keys: + • was_set (bool): Whether the option was set. + • last_set_sid (int): Last set script id + • last_set_linenr (int): Last set script id, -1 if invalid. + • last_set_lchan (int): Last set script id, -1 if invalid. + + Flag-Related Keys: + • win (bool): Window-local option + • buf (bool): Buffer-local option + • global_local (bool): Global or Buffer local option + • flaglist (bool): List of single char flags + + Parameters: ~ + {name} Option name + + Return: ~ + Option Information + +nvim_get_options_info() *nvim_get_options_info()* + Gets the option information for all options. + + Return: ~ + Map + nvim_get_proc({pid}) *nvim_get_proc()* Gets info describing process `pid` . @@ -950,11 +983,16 @@ nvim_get_runtime_file({name}, {all}) *nvim_get_runtime_file()* 'name' can contain wildcards. For example nvim_get_runtime_file("colors/*.vim", true) will return all - color scheme files. + color scheme files. Always use forward slashes (/) in the + search pattern for subdirectories regardless of platform. It is not an error to not find any files. An empty array is returned then. + To find a directory, `name` must end with a forward slash, + like "rplugin/python/". Without the slash it would instead + look for an ordinary file called "rplugin/python". + Attributes: ~ {fast} @@ -1535,7 +1573,9 @@ nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()* {ns_id} number of namespace for this highlight {name} highlight group name, like ErrorMsg {val} highlight definiton map, like - |nvim_get_hl_by_name|. + |nvim_get_hl_by_name|. in addition the following + keys are also recognized: `default` : don't + override existing definition, like `hi default` nvim_set_hl_ns({ns_id}) *nvim_set_hl_ns()* Set active namespace for highlights. diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b3576bc436..a95aa0f170 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -970,12 +970,38 @@ Object nvim_get_option(String name, Error *err) return get_option_from(NULL, SREQ_GLOBAL, name, err); } +/// Gets the option information for all options. +/// @return Map Dictionary nvim_get_options_info(Error *err) FUNC_API_SINCE(7) { return get_all_vimoptions(); } +/// Gets the option information for one option +/// +/// Resulting dictionary has keys: +/// - name (string): Name of the option +/// - shortname (shortname): Shortened name of the option +/// - type (string): Name of the type of option +/// - default (Any): The default value for the option +/// +/// Script-Related Keys: +/// - was_set (bool): Whether the option was set. +/// - last_set_sid (int): Last set script id +/// - last_set_linenr (int): Last set script id, -1 if invalid. +/// - last_set_lchan (int): Last set script id, -1 if invalid. +/// +/// Flag-Related Keys: +/// - win (bool): Window-local option +/// - buf (bool): Buffer-local option +/// - global_local (bool): Global or Buffer local option +/// - flaglist (bool): 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) { diff --git a/src/nvim/option.c b/src/nvim/option.c index 12468adbe8..85f38b02ae 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -7180,7 +7180,7 @@ Dictionary get_vimoption(String name, Error *err) { int opt_idx = findoption_len((const char *)name.data, name.size); if (opt_idx < 0) { - api_set_error(err, kErrorTypeValidation, "no such option %s", name.data); + api_set_error(err, kErrorTypeValidation, "no such option: '%s'", name.data); return (Dictionary)ARRAY_DICT_INIT; } return vimoption2dict(&options[opt_idx]); @@ -7202,27 +7202,30 @@ static Dictionary vimoption2dict(vimoption_T *opt) PUT(dict, "name", STRING_OBJ(cstr_to_string(opt->fullname))); PUT(dict, "shortname", STRING_OBJ(cstr_to_string(opt->shortname))); -#define PUT_IF(dict, name, condition) do if (condition) \ - { PUT(dict, name, BOOLEAN_OBJ(true)); } while (0) - PUT_IF(dict, "win", opt->indir & PV_WIN); - PUT_IF(dict, "buf", opt->indir & PV_BUF); + +#define PUT_BOOL(dict, name, condition) \ + PUT(dict, name, BOOLEAN_OBJ(condition)); + + PUT_BOOL(dict, "win", opt->indir & PV_WIN); + PUT_BOOL(dict, "buf", opt->indir & PV_BUF); + // welcome to the jungle - PUT_IF(dict, "global_local", opt->indir & PV_BOTH); - PUT_IF(dict, "commalist", opt->flags & P_COMMA); - PUT_IF(dict, "flaglist", opt->flags & P_FLAGLIST); + PUT_BOOL(dict, "global_local", opt->indir & PV_BOTH); + PUT_BOOL(dict, "commalist", opt->flags & P_COMMA); + PUT_BOOL(dict, "flaglist", opt->flags & P_FLAGLIST); - PUT_IF(dict, "was_set", opt->flags & P_WAS_SET); + PUT_BOOL(dict, "was_set", opt->flags & P_WAS_SET); +#undef PUT_BOOL - PUT(dict, "flag", INTEGER_OBJ(opt->flags)); // TODO(bfredl): lol tj PUT(dict, "last_set_sid", INTEGER_OBJ(opt->last_set.script_ctx.sc_sid)); - if (opt->last_set.script_ctx.sc_lnum > 0) { - PUT(dict, "last_set_linenr", - INTEGER_OBJ(opt->last_set.script_ctx.sc_lnum)); - } - if (opt->last_set.channel_id > 0) { - PUT(dict, "last_set_lchan", - INTEGER_OBJ((int64_t)opt->last_set.channel_id)); - } + PUT(dict, "last_set_linenr", + opt->last_set.script_ctx.sc_lnum > 0 + ? INTEGER_OBJ(opt->last_set.script_ctx.sc_lnum) + : INTEGER_OBJ(-1)); + PUT(dict, "last_set_lchan", + opt->last_set.channel_id > 0 + ? INTEGER_OBJ((int64_t)opt->last_set.channel_id) + : INTEGER_OBJ(-1)); const char *type; Object def; diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index eb5fd7eca7..8880d88f5e 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1921,4 +1921,57 @@ describe('API', function() eq({}, meths.get_runtime_file("foobarlang/", true)) end) end) + + describe('nvim_get_options_info', function() + it('should have key value pairs of option names', function() + local options_info = meths.get_options_info() + neq(nil, options_info.listchars) + neq(nil, options_info.tabstop) + end) + end) + + describe('nvim_get_option_info', function() + it('should error for unknown options', function() + eq("no such option: 'bogus'", + pcall_err(meths.get_option_info, 'bogus')) + end) + + it('should return the same options for short and long name', function() + eq( + meths.get_option_info('winhl'), + meths.get_option_info('winhighlight') + ) + end) + + it('should have information about window options', function() + local winhl_info = meths.get_option_info('winhl') + eq(true, winhl_info.win) + eq(false, winhl_info.buf) + eq('string', winhl_info.type) + eq('winhighlight', winhl_info.name) + eq('winhl', winhl_info.shortname) + eq('', winhl_info.default) + end) + + it('should have information about buffer options', function() + local filetype_info = meths.get_option_info('filetype') + eq(false, filetype_info.win) + eq(true, filetype_info.buf) + eq('string', filetype_info.type) + eq('filetype', filetype_info.name) + eq('ft', filetype_info.shortname) + eq('', filetype_info.default) + end) + + it('should have information about global options', function() + local showcmd_info = meths.get_option_info('showcmd') + eq(false, showcmd_info.win) + eq(false, showcmd_info.buf) + eq(false, showcmd_info.global_local) + eq('boolean', showcmd_info.type) + eq('showcmd', showcmd_info.name) + eq('sc', showcmd_info.shortname) + eq(true, showcmd_info.default) + end) + end) end) From 17a58043a3fc49179a47590e905ed3a7d5a29907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Linse?= Date: Fri, 4 Dec 2020 10:59:58 +0100 Subject: [PATCH 4/4] api/options: cleanup the fixup --- src/nvim/api/private/helpers.h | 5 ++ src/nvim/api/vim.c | 35 +++++++------- src/nvim/option.c | 44 ++++++++--------- test/functional/api/vim_spec.lua | 82 ++++++++++++++++++++------------ 4 files changed, 97 insertions(+), 69 deletions(-) diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 271fd5b485..055abb797f 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -16,6 +16,7 @@ #define BOOLEAN_OBJ(b) ((Object) { \ .type = kObjectTypeBoolean, \ .data.boolean = b }) +#define BOOL(b) BOOLEAN_OBJ(b) #define INTEGER_OBJ(i) ((Object) { \ .type = kObjectTypeInteger, \ @@ -29,6 +30,8 @@ .type = kObjectTypeString, \ .data.string = s }) +#define CSTR_TO_OBJ(s) STRING_OBJ(cstr_to_string(s)) + #define BUFFER_OBJ(s) ((Object) { \ .type = kObjectTypeBuffer, \ .data.integer = s }) @@ -59,6 +62,8 @@ #define PUT(dict, k, v) \ kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v })) +#define PUT_BOOL(dict, name, condition) PUT(dict, name, BOOLEAN_OBJ(condition)); + #define ADD(array, item) \ kv_push(array, item) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index a95aa0f170..8ac820abd9 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -971,8 +971,12 @@ Object nvim_get_option(String name, Error *err) } /// Gets the option information for all options. -/// @return Map -Dictionary nvim_get_options_info(Error *err) +/// +/// 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(); @@ -981,22 +985,21 @@ Dictionary nvim_get_options_info(Error *err) /// Gets the option information for one option /// /// Resulting dictionary has keys: -/// - name (string): Name of the option -/// - shortname (shortname): Shortened name of the option -/// - type (string): Name of the type of option -/// - default (Any): The default value for the option +/// - name: Name of the option (like 'filetype') +/// - shortname: Shortened name of the option (like 'ft') +/// - type: type of option ("string", "integer" or "boolean") +/// - default: The default value for the option +/// - was_set: Whether the option was set. /// -/// Script-Related Keys: -/// - was_set (bool): Whether the option was set. -/// - last_set_sid (int): Last set script id -/// - last_set_linenr (int): Last set script id, -1 if invalid. -/// - last_set_lchan (int): Last set script id, -1 if invalid. +/// - 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) /// -/// Flag-Related Keys: -/// - win (bool): Window-local option -/// - buf (bool): Buffer-local option -/// - global_local (bool): Global or Buffer local option -/// - flaglist (bool): List of single char flags +/// - 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 diff --git a/src/nvim/option.c b/src/nvim/option.c index 85f38b02ae..acca6fe681 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -7200,32 +7200,30 @@ static Dictionary vimoption2dict(vimoption_T *opt) { Dictionary dict = ARRAY_DICT_INIT; - PUT(dict, "name", STRING_OBJ(cstr_to_string(opt->fullname))); - PUT(dict, "shortname", STRING_OBJ(cstr_to_string(opt->shortname))); + PUT(dict, "name", CSTR_TO_OBJ(opt->fullname)); + PUT(dict, "shortname", CSTR_TO_OBJ(opt->shortname)); -#define PUT_BOOL(dict, name, condition) \ - PUT(dict, name, BOOLEAN_OBJ(condition)); + const char *scope; + if (opt->indir & PV_BUF) { + scope = "buf"; + } else if (opt->indir & PV_WIN) { + scope = "win"; + } else { + scope = "global"; + } - PUT_BOOL(dict, "win", opt->indir & PV_WIN); - PUT_BOOL(dict, "buf", opt->indir & PV_BUF); + PUT(dict, "scope", CSTR_TO_OBJ(scope)); // welcome to the jungle - PUT_BOOL(dict, "global_local", opt->indir & PV_BOTH); - PUT_BOOL(dict, "commalist", opt->flags & P_COMMA); - PUT_BOOL(dict, "flaglist", opt->flags & P_FLAGLIST); + PUT(dict, "global_local", BOOL(opt->indir & PV_BOTH)); + PUT(dict, "commalist", BOOL(opt->flags & P_COMMA)); + PUT(dict, "flaglist", BOOL(opt->flags & P_FLAGLIST)); - PUT_BOOL(dict, "was_set", opt->flags & P_WAS_SET); -#undef PUT_BOOL + PUT(dict, "was_set", BOOL(opt->flags & P_WAS_SET)); PUT(dict, "last_set_sid", INTEGER_OBJ(opt->last_set.script_ctx.sc_sid)); - PUT(dict, "last_set_linenr", - opt->last_set.script_ctx.sc_lnum > 0 - ? INTEGER_OBJ(opt->last_set.script_ctx.sc_lnum) - : INTEGER_OBJ(-1)); - PUT(dict, "last_set_lchan", - opt->last_set.channel_id > 0 - ? INTEGER_OBJ((int64_t)opt->last_set.channel_id) - : INTEGER_OBJ(-1)); + PUT(dict, "last_set_linenr", INTEGER_OBJ(opt->last_set.script_ctx.sc_lnum)); + PUT(dict, "last_set_chan", INTEGER_OBJ((int64_t)opt->last_set.channel_id)); const char *type; Object def; @@ -7234,17 +7232,17 @@ static Dictionary vimoption2dict(vimoption_T *opt) ? VI_DEFAULT : VIM_DEFAULT]; if (opt->flags & P_STRING) { type = "string"; - def = STRING_OBJ(cstr_to_string(def_val ? (char *)def_val : "")); + def = CSTR_TO_OBJ(def_val ? (char *)def_val : ""); } else if (opt->flags & P_NUM) { - type = "string"; + type = "number"; def = INTEGER_OBJ((Integer)(intptr_t)def_val); } else if (opt->flags & P_BOOL) { type = "boolean"; - def = BOOLEAN_OBJ((intptr_t)def_val); + def = BOOL((intptr_t)def_val); } else { type = ""; def = NIL; } - PUT(dict, "type", STRING_OBJ(cstr_to_string(type))); + PUT(dict, "type", CSTR_TO_OBJ(type)); PUT(dict, "default", def); return dict; diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 8880d88f5e..c42d5c34cc 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1922,56 +1922,78 @@ describe('API', function() end) end) - describe('nvim_get_options_info', function() + describe('nvim_get_all_options_info', function() it('should have key value pairs of option names', function() - local options_info = meths.get_options_info() + local options_info = meths.get_all_options_info() neq(nil, options_info.listchars) neq(nil, options_info.tabstop) + + eq(meths.get_option_info'winhighlight', options_info.winhighlight) end) end) describe('nvim_get_option_info', function() it('should error for unknown options', function() - eq("no such option: 'bogus'", - pcall_err(meths.get_option_info, 'bogus')) + eq("no such option: 'bogus'", pcall_err(meths.get_option_info, 'bogus')) end) it('should return the same options for short and long name', function() - eq( - meths.get_option_info('winhl'), - meths.get_option_info('winhighlight') - ) + eq(meths.get_option_info'winhl', meths.get_option_info'winhighlight') end) it('should have information about window options', function() - local winhl_info = meths.get_option_info('winhl') - eq(true, winhl_info.win) - eq(false, winhl_info.buf) - eq('string', winhl_info.type) - eq('winhighlight', winhl_info.name) - eq('winhl', winhl_info.shortname) - eq('', winhl_info.default) + eq({ + commalist = false; + default = ""; + flaglist = false; + global_local = false; + last_set_chan = 0; + last_set_linenr = 0; + last_set_sid = 0; + name = "winhighlight"; + scope = "win"; + shortname = "winhl"; + type = "string"; + was_set = false; + }, meths.get_option_info'winhl') end) it('should have information about buffer options', function() - local filetype_info = meths.get_option_info('filetype') - eq(false, filetype_info.win) - eq(true, filetype_info.buf) - eq('string', filetype_info.type) - eq('filetype', filetype_info.name) - eq('ft', filetype_info.shortname) - eq('', filetype_info.default) + eq({ + commalist = false, + default = "", + flaglist = false, + global_local = false, + last_set_chan = 0, + last_set_linenr = 0, + last_set_sid = 0, + name = "filetype", + scope = "buf", + shortname = "ft", + type = "string", + was_set = false + }, meths.get_option_info'filetype') end) it('should have information about global options', function() - local showcmd_info = meths.get_option_info('showcmd') - eq(false, showcmd_info.win) - eq(false, showcmd_info.buf) - eq(false, showcmd_info.global_local) - eq('boolean', showcmd_info.type) - eq('showcmd', showcmd_info.name) - eq('sc', showcmd_info.shortname) - eq(true, showcmd_info.default) + -- precondition: the option was changed from its default + -- in test setup. + eq(false, meths.get_option'showcmd') + + eq({ + commalist = false, + default = true, + flaglist = false, + global_local = false, + last_set_chan = 0, + last_set_linenr = 0, + last_set_sid = -2, + name = "showcmd", + scope = "global", + shortname = "sc", + type = "boolean", + was_set = true + }, meths.get_option_info'showcmd') end) end) end)