aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api/helpers.c189
-rw-r--r--src/api/helpers.h19
-rw-r--r--src/api/vim.c13
-rw-r--r--src/api/vim.h10
-rw-r--r--src/option.c177
-rw-r--r--src/option.h9
-rw-r--r--src/option_defs.h18
-rw-r--r--src/vim.h5
8 files changed, 415 insertions, 25 deletions
diff --git a/src/api/helpers.c b/src/api/helpers.c
index 584249fcc6..40888f351d 100644
--- a/src/api/helpers.c
+++ b/src/api/helpers.c
@@ -5,8 +5,11 @@
#include "api/helpers.h"
#include "api/defs.h"
#include "../vim.h"
+#include "../window.h"
#include "memory.h"
#include "eval.h"
+#include "option.h"
+#include "option_defs.h"
#include "lib/khash.h"
@@ -22,6 +25,20 @@ static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup);
static bool object_to_vim(Object obj, typval_T *tv, Error *err);
+static void set_option_value_for(char *key,
+ int numval,
+ char *stringval,
+ int opt_flags,
+ int opt_type,
+ void *from,
+ Error *err);
+
+static void set_option_value_err(char *key,
+ int numval,
+ char *stringval,
+ int opt_flags,
+ Error *err);
+
void try_start()
{
++trylevel;
@@ -134,6 +151,110 @@ Object dict_set_value(dict_T *dict, String key, Object value, Error *err)
return rv;
}
+Object get_option_from(void *from, int type, String name, Error *err)
+{
+ Object rv = {.type = kObjectTypeNil};
+
+ if (name.size == 0) {
+ set_api_error("Empty option name", err);
+ return rv;
+ }
+
+ // Return values
+ long numval;
+ char *stringval = NULL;
+ //
+ char key[name.size + 1];
+ memcpy(key, name.data, name.size);
+ key[name.size] = NUL;
+ int flags = get_option_value_strict(key, &numval, &stringval, type, from);
+
+ if (!flags) {
+ set_api_error("invalid option name", err);
+ return rv;
+ }
+
+ if (flags & SOPT_BOOL) {
+ rv.type = kObjectTypeBool;
+ rv.data.boolean = numval ? true : false;
+ } else if (flags & SOPT_NUM) {
+ rv.type = kObjectTypeInt;
+ 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 {
+ set_api_error(N_("Unable to get option value"), err);
+ }
+ } else {
+ set_api_error(N_("internal error: unknown option type"), err);
+ }
+
+ return rv;
+}
+
+void set_option_to(void *to, int type, String name, Object value, Error *err)
+{
+ if (name.size == 0) {
+ set_api_error("Empty option name", err);
+ return;
+ }
+
+ char key[name.size + 1];
+ memcpy(key, name.data, name.size);
+ key[name.size] = NUL;
+ int flags = get_option_value_strict(key, NULL, NULL, type, to);
+
+ if (flags == 0) {
+ set_api_error("invalid option name", err);
+ return;
+ }
+
+ if (value.type == kObjectTypeNil) {
+ if (type == SREQ_GLOBAL) {
+ set_api_error("unable to unset option", err);
+ return;
+ } else if (!(flags & SOPT_GLOBAL)) {
+ set_api_error("cannot unset option that doesn't have a global value",
+ err);
+ return;
+ } else {
+ unset_global_local_option(key, to);
+ return;
+ }
+ }
+
+ int opt_flags = (type ? OPT_LOCAL : OPT_GLOBAL);
+
+ if (flags & SOPT_BOOL) {
+ if (value.type != kObjectTypeBool) {
+ set_api_error("option requires a boolean value", err);
+ return;
+ }
+ bool val = value.data.boolean;
+ set_option_value_for(key, val, NULL, opt_flags, type, to, err);
+
+ } else if (flags & SOPT_NUM) {
+ if (value.type != kObjectTypeInt) {
+ set_api_error("option requires an integer value", err);
+ return;
+ }
+
+ int val = value.data.integer;
+ set_option_value_for(key, val, NULL, opt_flags, type, to, err);
+ } else {
+ if (value.type != kObjectTypeString) {
+ set_api_error("option requires a string value", err);
+ return;
+ }
+
+ char *val = xstrndup(value.data.string.data, value.data.string.size);
+ set_option_value_for(key, 0, val, opt_flags, type, to, err);
+ }
+}
+
Object vim_to_object(typval_T *obj)
{
Object rv;
@@ -336,3 +457,71 @@ static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup)
return rv;
}
+
+
+static void set_option_value_for(char *key,
+ int numval,
+ char *stringval,
+ int opt_flags,
+ int opt_type,
+ void *from,
+ Error *err)
+{
+ win_T *save_curwin = NULL;
+ tabpage_T *save_curtab = NULL;
+ buf_T *save_curbuf = NULL;
+
+ try_start();
+ switch (opt_type)
+ {
+ case SREQ_WIN:
+ if (switch_win(&save_curwin, &save_curtab, (win_T *)from,
+ win_find_tabpage((win_T *)from), FALSE) == FAIL)
+ {
+ if (try_end(err)) {
+ return;
+ }
+ set_api_error("problem while switching windows", err);
+ return;
+ }
+ set_option_value_err(key, numval, stringval, opt_flags, err);
+ restore_win(save_curwin, save_curtab, TRUE);
+ break;
+ case SREQ_BUF:
+ switch_buffer(&save_curbuf, (buf_T *)from);
+ set_option_value_err(key, numval, stringval, opt_flags, err);
+ restore_buffer(save_curbuf);
+ break;
+ case SREQ_GLOBAL:
+ set_option_value_err(key, numval, stringval, opt_flags, err);
+ break;
+ }
+
+ if (err->set) {
+ return;
+ }
+
+ try_end(err);
+}
+
+
+static void set_option_value_err(char *key,
+ int numval,
+ char *stringval,
+ int opt_flags,
+ Error *err)
+{
+ char *errmsg;
+
+ if ((errmsg = (char *)set_option_value((uint8_t *)key,
+ numval,
+ (uint8_t *)stringval,
+ opt_flags)))
+ {
+ if (try_end(err)) {
+ return;
+ }
+
+ set_api_error(errmsg, err);
+ }
+}
diff --git a/src/api/helpers.h b/src/api/helpers.h
index d839fe30e7..d98ed3b22b 100644
--- a/src/api/helpers.h
+++ b/src/api/helpers.h
@@ -40,6 +40,25 @@ Object dict_get_value(dict_T *dict, String key, bool pop, Error *err);
/// @return the old value, if any
Object dict_set_value(dict_T *dict, String key, Object value, Error *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);
+
+/// 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(void *to, int type, String name, Object value, Error *err);
+
/// Convert a vim object to an `Object` instance, recursively expanding
/// Arrays/Dictionaries.
///
diff --git a/src/api/vim.c b/src/api/vim.c
index 93654da91f..7eaa27d580 100644
--- a/src/api/vim.c
+++ b/src/api/vim.c
@@ -139,19 +139,14 @@ Object vim_set_var(String name, Object value, Error *err)
return dict_set_value(&globvardict, name, value, err);
}
-String vim_get_option(String name, Error *err)
+Object vim_get_option(String name, Error *err)
{
- abort();
-}
-
-void vim_set_option(String name, String value, Error *err)
-{
- abort();
+ return get_option_from(NULL, SREQ_GLOBAL, name, err);
}
-void vim_del_option(String name, Error *err)
+void vim_set_option(String name, Object value, Error *err)
{
- abort();
+ set_option_to(NULL, SREQ_GLOBAL, name, value, err);
}
void vim_out_write(String str)
diff --git a/src/api/vim.h b/src/api/vim.h
index a18f9c69e9..81aadb2014 100644
--- a/src/api/vim.h
+++ b/src/api/vim.h
@@ -77,20 +77,14 @@ Object vim_set_var(String name, Object value, Error *err);
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
/// @return The option value
-String vim_get_option(String name, Error *err);
+Object vim_get_option(String name, Error *err);
/// Sets an option value
///
/// @param name The option name
/// @param value The new option value
/// @param[out] err Details of an error that may have occurred
-void vim_set_option(String name, String value, Error *err);
-
-/// Deletes an option, falling back to the default value
-///
-/// @param name The option name
-/// @param[out] err Details of an error that may have occurred
-void vim_del_option(String name, Error *err);
+void vim_set_option(String name, Object value, Error *err);
/// Write a message to vim output buffer
///
diff --git a/src/option.c b/src/option.c
index 56f86e34fd..89069d96ef 100644
--- a/src/option.c
+++ b/src/option.c
@@ -32,6 +32,7 @@
#define IN_OPTION_C
#include <string.h>
+#include <stdint.h>
#include <stdlib.h>
#include "vim.h"
@@ -5946,6 +5947,124 @@ get_option_value (
return 1;
}
+// Returns the option attributes and its value. Unlike the above function it
+// will return either global value or local value of the option depending on
+// what was requested, but it will never return global value if it was
+// requested to return local one and vice versa. Neither it will return
+// buffer-local value if it was requested to return window-local one.
+//
+// Pretends that option is absent if it is not present in the requested scope
+// (i.e. has no global, window-local or buffer-local value depending on
+// opt_type). Uses
+//
+// Returned flags:
+// 0 hidden or unknown option, also option that does not have requested
+// type (see SREQ_* in vim.h)
+// see SOPT_* in vim.h for other flags
+//
+// Possible opt_type values: see SREQ_* in vim.h
+int get_option_value_strict(char *name,
+ int64_t *numval,
+ char **stringval,
+ int opt_type,
+ void *from)
+{
+ char_u *varp = NULL;
+ struct vimoption *p;
+ int rv = 0;
+ int opt_idx = findoption((uint8_t *)name);
+ if (opt_idx < 0) {
+ return 0;
+ }
+
+ p = &(options[opt_idx]);
+
+ // Hidden option
+ if (p->var == NULL) {
+ return 0;
+ }
+
+ if (p->flags & P_BOOL) {
+ rv |= SOPT_BOOL;
+ } else if (p->flags & P_NUM) {
+ rv |= SOPT_NUM;
+ } else if (p->flags & P_STRING) {
+ rv |= SOPT_STRING;
+ }
+
+ if (p->indir == PV_NONE) {
+ if (opt_type == SREQ_GLOBAL)
+ rv |= SOPT_GLOBAL;
+ else
+ return 0; // Did not request global-only option
+ } else {
+ if (p->indir & PV_BOTH) {
+ rv |= SOPT_GLOBAL;
+ } else if (opt_type == SREQ_GLOBAL) {
+ return 0; // Requested global option
+ }
+
+ if (p->indir & PV_WIN) {
+ if (opt_type == SREQ_BUF) {
+ return 0; // Did not request window-local option
+ } else {
+ rv |= SOPT_WIN;
+ }
+ } else if (p->indir & PV_BUF) {
+ if (opt_type == SREQ_WIN) {
+ return 0; // Did not request buffer-local option
+ } else {
+ rv |= SOPT_BUF;
+ }
+ }
+ }
+
+ if (stringval == NULL) {
+ return rv;
+ }
+
+ if (opt_type == SREQ_GLOBAL) {
+ varp = p->var;
+ } else {
+ if (opt_type == SREQ_BUF) {
+ // Special case: 'modified' is b_changed, but we also want to
+ // consider it set when 'ff' or 'fenc' changed.
+ if (p->indir == PV_MOD) {
+ *numval = bufIsChanged((buf_T *) from);
+ varp = NULL;
+ } else {
+ aco_save_T aco;
+ aucmd_prepbuf(&aco, (buf_T *) from);
+ varp = get_varp(p);
+ aucmd_restbuf(&aco);
+ }
+ } else if (opt_type == SREQ_WIN) {
+ win_T *save_curwin;
+ save_curwin = curwin;
+ curwin = (win_T *) from;
+ curbuf = curwin->w_buffer;
+ varp = get_varp(p);
+ curwin = save_curwin;
+ curbuf = curwin->w_buffer;
+ }
+
+ if (varp == p->var) {
+ return (rv | SOPT_UNSET);
+ }
+ }
+
+ if (varp != NULL) {
+ if (p->flags & P_STRING) {
+ *stringval = xstrdup(*(char **)(varp));
+ } else if (p->flags & P_NUM) {
+ *numval = *(long *) varp;
+ } else {
+ *numval = *(int *)varp;
+ }
+ }
+
+ return rv;
+}
/*
* Set the value of option "name".
@@ -6554,6 +6673,64 @@ void comp_col(void)
ru_col = 1;
}
+// Unset local option value, similar to ":set opt<".
+void unset_global_local_option(char *name, void *from)
+{
+ struct vimoption *p;
+ int opt_idx;
+ buf_T *buf = (buf_T *)from;
+
+ opt_idx = findoption((uint8_t *)name);
+ p = &(options[opt_idx]);
+
+ switch ((int)p->indir)
+ {
+ // global option with local value: use local value if it's been set
+ case PV_EP:
+ clear_string_option(&buf->b_p_ep);
+ break;
+ case PV_KP:
+ clear_string_option(&buf->b_p_kp);
+ break;
+ case PV_PATH:
+ clear_string_option(&buf->b_p_path);
+ break;
+ case PV_AR:
+ buf->b_p_ar = -1;
+ break;
+ case PV_TAGS:
+ clear_string_option(&buf->b_p_tags);
+ break;
+ case PV_DEF:
+ clear_string_option(&buf->b_p_def);
+ break;
+ case PV_INC:
+ clear_string_option(&buf->b_p_inc);
+ break;
+ case PV_DICT:
+ clear_string_option(&buf->b_p_dict);
+ break;
+ case PV_TSR:
+ clear_string_option(&buf->b_p_tsr);
+ break;
+ case PV_EFM:
+ clear_string_option(&buf->b_p_efm);
+ break;
+ case PV_GP:
+ clear_string_option(&buf->b_p_gp);
+ break;
+ case PV_MP:
+ clear_string_option(&buf->b_p_mp);
+ break;
+ case PV_STL:
+ clear_string_option(&((win_T *)from)->w_p_stl);
+ break;
+ case PV_UL:
+ buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
+ break;
+ }
+}
+
/*
* Get pointer to option variable, depending on local or global scope.
*/
diff --git a/src/option.h b/src/option.h
index 31fd1e2025..ec27e1b493 100644
--- a/src/option.h
+++ b/src/option.h
@@ -1,5 +1,8 @@
#ifndef NEOVIM_OPTION_H
#define NEOVIM_OPTION_H
+
+#include <stdint.h>
+
/* option.c */
void set_init_1(void);
void set_string_default(char *name, char_u *val);
@@ -26,6 +29,11 @@ char_u *check_colorcolumn(win_T *wp);
char_u *check_stl_option(char_u *s);
int get_option_value(char_u *name, long *numval, char_u **stringval,
int opt_flags);
+int get_option_value_strict(char *name,
+ int64_t *numval,
+ char **stringval,
+ int opt_type,
+ void *from);
char_u *option_iter_next(void **option, int opt_type);
char_u *set_option_value(char_u *name, long number, char_u *string,
int opt_flags);
@@ -39,6 +47,7 @@ void free_termoptions(void);
void free_one_termoption(char_u *var);
void set_term_defaults(void);
void comp_col(void);
+void unset_global_local_option(char *name, void *from);
char_u *get_equalprg(void);
void win_copy_options(win_T *wp_from, win_T *wp_to);
void copy_winopt(winopt_T *from, winopt_T *to);
diff --git a/src/option_defs.h b/src/option_defs.h
index 72a5836b2d..cfd6a6d31f 100644
--- a/src/option_defs.h
+++ b/src/option_defs.h
@@ -3,9 +3,21 @@
#include "types.h"
-/*
- * option_defs.h: definition of global variables for settable options
- */
+// option_defs.h: definition of global variables for settable options
+
+// Return value from get_option_value_strict */
+#define SOPT_BOOL 0x01 // Boolean option
+#define SOPT_NUM 0x02 // Number option
+#define SOPT_STRING 0x04 // String option
+#define SOPT_GLOBAL 0x08 // Option has global value
+#define SOPT_WIN 0x10 // Option has window-local value
+#define SOPT_BUF 0x20 // Option has buffer-local value
+#define SOPT_UNSET 0x40 // Option does not have local value set
+
+// Option types for various functions in option.c
+#define SREQ_GLOBAL 0 // Request global option
+#define SREQ_WIN 1 // Request window-local option
+#define SREQ_BUF 2 // Request buffer-local option
/*
* Default values for 'errorformat'.
diff --git a/src/vim.h b/src/vim.h
index f48b7a6f4c..0032032fcf 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1382,11 +1382,6 @@ typedef int VimClipboard; /* This is required for the prototypes. */
#define FILEINFO_READ_FAIL 2 /* CreateFile() failed */
#define FILEINFO_INFO_FAIL 3 /* GetFileInformationByHandle() failed */
-/* Option types for various functions in option.c */
-#define SREQ_GLOBAL 0 /* Request global option */
-#define SREQ_WIN 1 /* Request window-local option */
-#define SREQ_BUF 2 /* Request buffer-local option */
-
/* Character used as separated in autoload function/variable names. */
#define AUTOLOAD_CHAR '#'