diff src/if_py_both.h @ 4350:7eaccdaa5304 v7.3.924

updated for version 7.3.924 Problem: Python interface can't easily access options. Solution: Add vim.options, vim.window.options and vim.buffer.options. (ZyX)
author Bram Moolenaar <bram@vim.org>
date Mon, 06 May 2013 03:52:55 +0200
parents f1eab4f77a6f
children 04736b4030ec
line wrap: on
line diff
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -1497,6 +1497,279 @@ static struct PyMethodDef FunctionMethod
     { NULL,	    NULL,		0,	    NULL }
 };
 
+/*
+ * Options object
+ */
+
+static PyTypeObject OptionsType;
+
+typedef int (*checkfun)(void *);
+
+typedef struct
+{
+    PyObject_HEAD
+    int opt_type;
+    void *from;
+    checkfun Check;
+    PyObject *fromObj;
+} OptionsObject;
+
+    static PyObject *
+OptionsItem(OptionsObject *this, PyObject *keyObject)
+{
+    char_u	*key;
+    int		flags;
+    long	numval;
+    char_u	*stringval;
+
+    if (this->Check(this->from))
+	return NULL;
+
+    DICTKEY_DECL
+
+    DICTKEY_GET_NOTEMPTY(NULL)
+
+    flags = get_option_value_strict(key, &numval, &stringval,
+				    this->opt_type, this->from);
+
+    DICTKEY_UNREF
+
+    if (flags == 0)
+    {
+	PyErr_SetString(PyExc_KeyError, "Option does not exist in given scope");
+	return NULL;
+    }
+
+    if (flags & SOPT_UNSET)
+    {
+	Py_INCREF(Py_None);
+	return Py_None;
+    }
+    else if (flags & SOPT_BOOL)
+    {
+	PyObject *r;
+	r = numval ? Py_True : Py_False;
+	Py_INCREF(r);
+	return r;
+    }
+    else if (flags & SOPT_NUM)
+	return PyInt_FromLong(numval);
+    else if (flags & SOPT_STRING)
+    {
+	if (stringval)
+	    return PyBytes_FromString((char *) stringval);
+	else
+	{
+	    PyErr_SetString(PyExc_ValueError, "Unable to get option value");
+	    return NULL;
+	}
+    }
+    else
+    {
+	PyErr_SetVim("Internal error: unknown option type. Should not happen");
+	return NULL;
+    }
+}
+
+    static int
+set_option_value_for(key, numval, stringval, opt_flags, opt_type, from)
+    char_u	*key;
+    int		numval;
+    char_u	*stringval;
+    int		opt_flags;
+    int		opt_type;
+    void	*from;
+{
+    win_T	*save_curwin;
+    tabpage_T	*save_curtab;
+    aco_save_T	aco;
+    int		r = 0;
+
+    switch (opt_type)
+    {
+	case SREQ_WIN:
+	    if (switch_win(&save_curwin, &save_curtab, (win_T *) from, curtab)
+								      == FAIL)
+	    {
+		PyErr_SetVim("Problem while switching windows.");
+		return -1;
+	    }
+	    set_option_value(key, numval, stringval, opt_flags);
+	    restore_win(save_curwin, save_curtab);
+	    break;
+	case SREQ_BUF:
+	    aucmd_prepbuf(&aco, (buf_T *) from);
+	    set_option_value(key, numval, stringval, opt_flags);
+	    aucmd_restbuf(&aco);
+	    break;
+	case SREQ_GLOBAL:
+	    set_option_value(key, numval, stringval, opt_flags);
+	    break;
+    }
+    return r;
+}
+
+    static int
+OptionsAssItem(OptionsObject *this, PyObject *keyObject, PyObject *valObject)
+{
+    char_u	*key;
+    int		flags;
+    int		opt_flags;
+    int		r = 0;
+
+    if (this->Check(this->from))
+	return -1;
+
+    DICTKEY_DECL
+
+    DICTKEY_GET_NOTEMPTY(-1)
+
+    flags = get_option_value_strict(key, NULL, NULL,
+				    this->opt_type, this->from);
+
+    DICTKEY_UNREF
+
+    if (flags == 0)
+    {
+	PyErr_SetString(PyExc_KeyError, "Option does not exist in given scope");
+	return -1;
+    }
+
+    if (valObject == NULL)
+    {
+	if (this->opt_type == SREQ_GLOBAL)
+	{
+	    PyErr_SetString(PyExc_ValueError, "Unable to unset global option");
+	    return -1;
+	}
+	else if (!(flags & SOPT_GLOBAL))
+	{
+	    PyErr_SetString(PyExc_ValueError, "Unable to unset option without "
+						"global value");
+	    return -1;
+	}
+	else
+	{
+	    unset_global_local_option(key, this->from);
+	    return 0;
+	}
+    }
+
+    opt_flags = (this->opt_type ? OPT_LOCAL : OPT_GLOBAL);
+
+    if (flags & SOPT_BOOL)
+    {
+	if (!PyBool_Check(valObject))
+	{
+	    PyErr_SetString(PyExc_ValueError, "Object must be boolean");
+	    return -1;
+	}
+
+	r = set_option_value_for(key, (valObject == Py_True), NULL, opt_flags,
+				this->opt_type, this->from);
+    }
+    else if (flags & SOPT_NUM)
+    {
+	int val;
+
+#if PY_MAJOR_VERSION < 3
+	if (PyInt_Check(valObject))
+	    val = PyInt_AsLong(valObject);
+	else
+#endif
+	if (PyLong_Check(valObject))
+	    val = PyLong_AsLong(valObject);
+	else
+	{
+	    PyErr_SetString(PyExc_ValueError, "Object must be integer");
+	    return -1;
+	}
+
+	r = set_option_value_for(key, val, NULL, opt_flags,
+				this->opt_type, this->from);
+    }
+    else
+    {
+	char_u	*val;
+	if (PyBytes_Check(valObject))
+	{
+
+	    if (PyString_AsStringAndSize(valObject, (char **) &val, NULL) == -1)
+		return -1;
+	    if (val == NULL)
+		return -1;
+
+	    val = vim_strsave(val);
+	}
+	else if (PyUnicode_Check(valObject))
+	{
+	    PyObject	*bytes;
+
+	    bytes = PyUnicode_AsEncodedString(valObject, (char *)ENC_OPT, NULL);
+	    if (bytes == NULL)
+		return -1;
+
+	    if(PyString_AsStringAndSize(bytes, (char **) &val, NULL) == -1)
+		return -1;
+	    if (val == NULL)
+		return -1;
+
+	    val = vim_strsave(val);
+	    Py_XDECREF(bytes);
+	}
+	else
+	{
+	    PyErr_SetString(PyExc_ValueError, "Object must be string");
+	    return -1;
+	}
+
+	r = set_option_value_for(key, 0, val, opt_flags,
+				this->opt_type, this->from);
+	vim_free(val);
+    }
+
+    return r;
+}
+
+    static int
+dummy_check(void *arg UNUSED)
+{
+    return 0;
+}
+
+    static PyObject *
+OptionsNew(int opt_type, void *from, checkfun Check, PyObject *fromObj)
+{
+    OptionsObject	*self;
+
+    self = PyObject_NEW(OptionsObject, &OptionsType);
+    if (self == NULL)
+	return NULL;
+
+    self->opt_type = opt_type;
+    self->from = from;
+    self->Check = Check;
+    self->fromObj = fromObj;
+    if (fromObj)
+	Py_INCREF(fromObj);
+
+    return (PyObject *)(self);
+}
+
+    static void
+OptionsDestructor(PyObject *self)
+{
+    if (((OptionsObject *)(self))->fromObj)
+	Py_DECREF(((OptionsObject *)(self))->fromObj);
+    DESTRUCTOR_FINISH(self);
+}
+
+static PyMappingMethods OptionsAsMapping = {
+    (lenfunc)       NULL,
+    (binaryfunc)    OptionsItem,
+    (objobjargproc) OptionsAssItem,
+};
+
 #define INVALID_WINDOW_VALUE ((win_T *)(-1))
 
     static int
@@ -1534,8 +1807,12 @@ WindowAttr(WindowObject *this, char *nam
 #endif
     else if (strcmp(name, "vars") == 0)
 	return DictionaryNew(this->win->w_vars);
+    else if (strcmp(name, "options") == 0)
+	return OptionsNew(SREQ_WIN, this->win, (checkfun) CheckWindow,
+			(PyObject *) this);
     else if (strcmp(name,"__members__") == 0)
-	return Py_BuildValue("[ssss]", "buffer", "cursor", "height", "vars");
+	return Py_BuildValue("[sssss]", "buffer", "cursor", "height", "vars",
+		"options");
     else
 	return NULL;
 }
@@ -2499,8 +2776,11 @@ BufferAttr(BufferObject *this, char *nam
 	return Py_BuildValue(Py_ssize_t_fmt, this->buf->b_fnum);
     else if (strcmp(name, "vars") == 0)
 	return DictionaryNew(this->buf->b_vars);
+    else if (strcmp(name, "options") == 0)
+	return OptionsNew(SREQ_BUF, this->buf, (checkfun) CheckBuffer,
+			(PyObject *) this);
     else if (strcmp(name,"__members__") == 0)
-	return Py_BuildValue("[sss]", "name", "number", "vars");
+	return Py_BuildValue("[ssss]", "name", "number", "vars", "options");
     else
 	return NULL;
 }
@@ -3121,6 +3401,14 @@ init_structs(void)
     FunctionType.tp_getattr = FunctionGetattr;
 #endif
 
+    vim_memset(&OptionsType, 0, sizeof(OptionsType));
+    OptionsType.tp_name = "vim.options";
+    OptionsType.tp_basicsize = sizeof(OptionsObject);
+    OptionsType.tp_flags = Py_TPFLAGS_DEFAULT;
+    OptionsType.tp_doc = "object for manipulating options";
+    OptionsType.tp_as_mapping = &OptionsAsMapping;
+    OptionsType.tp_dealloc = OptionsDestructor;
+
 #if PY_MAJOR_VERSION >= 3
     vim_memset(&vimmodule, 0, sizeof(vimmodule));
     vimmodule.m_name = "vim";