summaryrefslogtreecommitdiff
path: root/src/if_py_both.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/if_py_both.h')
-rw-r--r--src/if_py_both.h267
1 files changed, 259 insertions, 8 deletions
diff --git a/src/if_py_both.h b/src/if_py_both.h
index 287191a4e..1e5a151e7 100644
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -24,6 +24,8 @@ typedef int Py_ssize_t; /* Python 2.4 and earlier don't have this type. */
#endif
#define DOPY_FUNC "_vim_pydo"
+static const char *vim_special_path = "_vim_path_";
+
#define PyErr_SetVim(str) PyErr_SetString(VimError, str)
#define RAISE_NO_EMPTY_KEYS PyErr_SetString(PyExc_ValueError, \
@@ -55,6 +57,8 @@ static PyObject *globals;
static PyObject *py_chdir;
static PyObject *py_fchdir;
static PyObject *py_getcwd;
+static PyObject *vim_module;
+static PyObject *vim_special_path_object;
/*
* obtain a lock on the Vim data structures
@@ -779,19 +783,168 @@ VimFchdir(PyObject *self UNUSED, PyObject *args, PyObject *kwargs)
return _VimChdir(py_fchdir, args, kwargs);
}
+typedef struct {
+ PyObject *callable;
+ PyObject *result;
+} map_rtp_data;
+
+ static void
+map_rtp_callback(char_u *path, void *_data)
+{
+ void **data = (void **) _data;
+ PyObject *pathObject;
+ map_rtp_data *mr_data = *((map_rtp_data **) data);
+
+ if (!(pathObject = PyString_FromString((char *) path)))
+ {
+ *data = NULL;
+ return;
+ }
+
+ mr_data->result = PyObject_CallFunctionObjArgs(mr_data->callable,
+ pathObject, NULL);
+
+ Py_DECREF(pathObject);
+
+ if (!mr_data->result || mr_data->result != Py_None)
+ *data = NULL;
+ else
+ {
+ Py_DECREF(mr_data->result);
+ mr_data->result = NULL;
+ }
+}
+
+ static PyObject *
+VimForeachRTP(PyObject *self UNUSED, PyObject *args)
+{
+ map_rtp_data data;
+
+ if (!PyArg_ParseTuple(args, "O", &data.callable))
+ return NULL;
+
+ data.result = NULL;
+
+ do_in_runtimepath(NULL, FALSE, &map_rtp_callback, &data);
+
+ if (data.result == NULL)
+ {
+ if (PyErr_Occurred())
+ return NULL;
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ }
+ return data.result;
+}
+
+/*
+ * _vim_runtimepath_ special path implementation.
+ */
+
+ static void
+map_finder_callback(char_u *path, void *_data)
+{
+ void **data = (void **) _data;
+ PyObject *list = *((PyObject **) data);
+ PyObject *pathObject1, *pathObject2;
+ char *pathbuf;
+ size_t pathlen;
+
+ pathlen = STRLEN(path);
+
+#if PY_MAJOR_VERSION < 3
+# define PY_MAIN_DIR_STRING "python2"
+#else
+# define PY_MAIN_DIR_STRING "python3"
+#endif
+#define PY_ALTERNATE_DIR_STRING "pythonx"
+
+#define PYTHONX_STRING_LENGTH 7 /* STRLEN("pythonx") */
+ if (!(pathbuf = PyMem_New(char,
+ pathlen + STRLEN(PATHSEPSTR) + PYTHONX_STRING_LENGTH + 1)))
+ {
+ PyErr_NoMemory();
+ *data = NULL;
+ return;
+ }
+
+ mch_memmove(pathbuf, path, pathlen + 1);
+ add_pathsep((char_u *) pathbuf);
+
+ pathlen = STRLEN(pathbuf);
+ mch_memmove(pathbuf + pathlen, PY_MAIN_DIR_STRING,
+ PYTHONX_STRING_LENGTH + 1);
+
+ if (!(pathObject1 = PyString_FromString(pathbuf)))
+ {
+ *data = NULL;
+ PyMem_Free(pathbuf);
+ return;
+ }
+
+ mch_memmove(pathbuf + pathlen, PY_ALTERNATE_DIR_STRING,
+ PYTHONX_STRING_LENGTH + 1);
+
+ if (!(pathObject2 = PyString_FromString(pathbuf)))
+ {
+ Py_DECREF(pathObject1);
+ PyMem_Free(pathbuf);
+ *data = NULL;
+ return;
+ }
+
+ PyMem_Free(pathbuf);
+
+ if (PyList_Append(list, pathObject1)
+ || PyList_Append(list, pathObject2))
+ *data = NULL;
+
+ Py_DECREF(pathObject1);
+ Py_DECREF(pathObject2);
+}
+
+ static PyObject *
+Vim_GetPaths(PyObject *self UNUSED)
+{
+ PyObject *r;
+
+ if (!(r = PyList_New(0)))
+ return NULL;
+
+ do_in_runtimepath(NULL, FALSE, &map_finder_callback, r);
+
+ if (PyErr_Occurred())
+ {
+ Py_DECREF(r);
+ return NULL;
+ }
+
+ return r;
+}
+
/*
* Vim module - Definitions
*/
static struct PyMethodDef VimMethods[] = {
- /* name, function, calling, documentation */
- {"command", VimCommand, METH_VARARGS, "Execute a Vim ex-mode command" },
- {"eval", VimEval, METH_VARARGS, "Evaluate an expression using Vim evaluator" },
- {"bindeval", VimEvalPy, METH_VARARGS, "Like eval(), but returns objects attached to vim ones"},
- {"strwidth", VimStrwidth, METH_VARARGS, "Screen string width, counts <Tab> as having width 1"},
- {"chdir", (PyCFunction)VimChdir, METH_VARARGS|METH_KEYWORDS, "Change directory"},
- {"fchdir", (PyCFunction)VimFchdir, METH_VARARGS|METH_KEYWORDS, "Change directory"},
- { NULL, NULL, 0, NULL }
+ /* name, function, calling, documentation */
+ {"command", VimCommand, METH_VARARGS, "Execute a Vim ex-mode command" },
+ {"eval", VimEval, METH_VARARGS, "Evaluate an expression using Vim evaluator" },
+ {"bindeval", VimEvalPy, METH_VARARGS, "Like eval(), but returns objects attached to vim ones"},
+ {"strwidth", VimStrwidth, METH_VARARGS, "Screen string width, counts <Tab> as having width 1"},
+ {"chdir", (PyCFunction)VimChdir, METH_VARARGS|METH_KEYWORDS, "Change directory"},
+ {"fchdir", (PyCFunction)VimFchdir, METH_VARARGS|METH_KEYWORDS, "Change directory"},
+ {"foreach_rtp", VimForeachRTP, METH_VARARGS, "Call given callable for each path in &rtp"},
+#if PY_MAJOR_VERSION < 3
+ {"find_module", FinderFindModule, METH_VARARGS, "Internal use only, returns loader object for any input it receives"},
+ {"load_module", LoaderLoadModule, METH_VARARGS, "Internal use only, tries importing the given module from &rtp by temporary mocking sys.path (to an rtp-based one) and unsetting sys.meta_path and sys.path_hooks"},
+#endif
+ {"path_hook", VimPathHook, METH_VARARGS, "Hook function to install in sys.path_hooks"},
+ {"_get_paths", (PyCFunction)Vim_GetPaths, METH_NOARGS, "Get &rtp-based additions to sys.path"},
+ { NULL, NULL, 0, NULL}
};
/*
@@ -5036,6 +5189,14 @@ typedef struct
} CurrentObject;
static PyTypeObject CurrentType;
+#if PY_MAJOR_VERSION >= 3
+typedef struct
+{
+ PyObject_HEAD
+} FinderObject;
+static PyTypeObject FinderType;
+#endif
+
static void
init_structs(void)
{
@@ -5281,6 +5442,81 @@ init_types()
PYTYPE_READY(FunctionType);
PYTYPE_READY(OptionsType);
PYTYPE_READY(OutputType);
+#if PY_MAJOR_VERSION >= 3
+ PYTYPE_READY(FinderType);
+#endif
+ return 0;
+}
+
+ static int
+init_sys_path()
+{
+ PyObject *path;
+ PyObject *path_hook;
+ PyObject *path_hooks;
+
+ if (!(path_hook = PyObject_GetAttrString(vim_module, "path_hook")))
+ return -1;
+
+ if (!(path_hooks = PySys_GetObject("path_hooks")))
+ {
+ PyErr_Clear();
+ path_hooks = PyList_New(1);
+ PyList_SET_ITEM(path_hooks, 0, path_hook);
+ if (PySys_SetObject("path_hooks", path_hooks))
+ {
+ Py_DECREF(path_hooks);
+ return -1;
+ }
+ Py_DECREF(path_hooks);
+ }
+ else if (PyList_Check(path_hooks))
+ {
+ if (PyList_Append(path_hooks, path_hook))
+ {
+ Py_DECREF(path_hook);
+ return -1;
+ }
+ Py_DECREF(path_hook);
+ }
+ else
+ {
+ VimTryStart();
+ EMSG(_("Failed to set path hook: sys.path_hooks is not a list\n"
+ "You should now do the following:\n"
+ "- append vim.path_hook to sys.path_hooks\n"
+ "- append vim.VIM_SPECIAL_PATH to sys.path\n"));
+ VimTryEnd(); /* Discard the error */
+ Py_DECREF(path_hook);
+ return 0;
+ }
+
+ if (!(path = PySys_GetObject("path")))
+ {
+ PyErr_Clear();
+ path = PyList_New(1);
+ Py_INCREF(vim_special_path_object);
+ PyList_SET_ITEM(path, 0, vim_special_path_object);
+ if (PySys_SetObject("path", path))
+ {
+ Py_DECREF(path);
+ return -1;
+ }
+ Py_DECREF(path);
+ }
+ else if (PyList_Check(path))
+ {
+ if (PyList_Append(path, vim_special_path_object))
+ return -1;
+ }
+ else
+ {
+ VimTryStart();
+ EMSG(_("Failed to set path: sys.path is not a list\n"
+ "You should now append vim.VIM_SPECIAL_PATH to sys.path"));
+ VimTryEnd(); /* Discard the error */
+ }
+
return 0;
}
@@ -5332,6 +5568,9 @@ static struct object_constant {
{"List", (PyObject *)&ListType},
{"Function", (PyObject *)&FunctionType},
{"Options", (PyObject *)&OptionsType},
+#if PY_MAJOR_VERSION >= 3
+ {"Finder", (PyObject *)&FinderType},
+#endif
};
typedef int (*object_adder)(PyObject *, const char *, PyObject *);
@@ -5417,5 +5656,17 @@ populate_module(PyObject *m, object_adder add_object, attr_getter get_attr)
else
PyErr_Clear();
+ if (!(vim_special_path_object = PyString_FromString(vim_special_path)))
+ return -1;
+
+ ADD_OBJECT(m, "VIM_SPECIAL_PATH", vim_special_path_object);
+
+#if PY_MAJOR_VERSION >= 3
+ ADD_OBJECT(m, "_PathFinder", path_finder);
+ ADD_CHECKED_OBJECT(m, "_find_module",
+ (py_find_module = PyObject_GetAttrString(path_finder,
+ "find_module")));
+#endif
+
return 0;
}