0
0
mirror of https://github.com/vim/vim.git synced 2025-09-25 03:54:15 -04:00

updated for version 7.3.1163

Problem:    Not easy to load Python modules.
Solution:   Search "python2", "python3" and "pythonx" directories in
            'runtimepath' for Python modules. (ZyX)
This commit is contained in:
Bram Moolenaar
2013-06-10 21:27:29 +02:00
parent f9c9b32bd1
commit c09a6d6c0c
10 changed files with 627 additions and 32 deletions

View File

@@ -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;
}