summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <bram@vim.org>2013-06-02 18:20:17 +0200
committerBram Moolenaar <bram@vim.org>2013-06-02 18:20:17 +0200
commit3990b4c70424c4502af50978a6d907588d5ea8c6 (patch)
tree412ec35a5987e614cf53727bc29f07d2dab5d40a
parentd11edd90062e1b99f41d9e4ba13700152efcb216 (diff)
downloadvim-3990b4c70424c4502af50978a6d907588d5ea8c6.tar.gz
updated for version 7.3.1099v7.3.1099v7-3-1099
Problem: Python: Changing directory with os.chdir() causes problems for Vim's notion of directories. Solution: Add vim.chdir() and vim.fchdir(). (ZyX)
-rw-r--r--runtime/doc/if_pyth.txt7
-rw-r--r--src/ex_docmd.c53
-rw-r--r--src/if_py_both.h109
-rw-r--r--src/if_python.c8
-rw-r--r--src/if_python3.c5
-rw-r--r--src/proto/ex_docmd.pro1
-rw-r--r--src/testdir/test86.in14
-rw-r--r--src/testdir/test86.ok6
-rw-r--r--src/testdir/test87.in14
-rw-r--r--src/testdir/test87.ok6
-rw-r--r--src/version.c2
11 files changed, 194 insertions, 31 deletions
diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt
index d37bd49f..7bd9b377 100644
--- a/runtime/doc/if_pyth.txt
+++ b/runtime/doc/if_pyth.txt
@@ -180,6 +180,13 @@ vim.strwidth(str) *python-strwidth*
Like |strwidth()|: returns number of display cells str occupies, tab
is counted as one cell.
+vim.chdir(*args, **kwargs) *python-chdir*
+vim.fchdir(*args, **kwargs) *python-fchdir*
+ Run os.chdir or os.fchdir, then all appropriate vim stuff.
+ Note: you should not use these functions directly, use os.chdir and
+ os.fchdir instead. Behavior of vim.fchdir is undefined in case
+ os.fchdir does not exist.
+
Error object of the "vim" module
vim.error *python-error*
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 056339e7..b6fc3766 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -8182,6 +8182,37 @@ free_cd_dir()
}
#endif
+/*
+ * Deal with the side effects of changing the current directory.
+ * When "local" is TRUE then this was after an ":lcd" command.
+ */
+ void
+post_chdir(local)
+ int local;
+{
+ vim_free(curwin->w_localdir);
+ if (local)
+ {
+ /* If still in global directory, need to remember current
+ * directory as global directory. */
+ if (globaldir == NULL && prev_dir != NULL)
+ globaldir = vim_strsave(prev_dir);
+ /* Remember this local directory for the window. */
+ if (mch_dirname(NameBuff, MAXPATHL) == OK)
+ curwin->w_localdir = vim_strsave(NameBuff);
+ }
+ else
+ {
+ /* We are now in the global directory, no need to remember its
+ * name. */
+ vim_free(globaldir);
+ globaldir = NULL;
+ curwin->w_localdir = NULL;
+ }
+
+ shorten_fnames(TRUE);
+}
+
/*
* ":cd", ":lcd", ":chdir" and ":lchdir".
@@ -8253,27 +8284,7 @@ ex_cd(eap)
EMSG(_(e_failed));
else
{
- vim_free(curwin->w_localdir);
- if (eap->cmdidx == CMD_lcd || eap->cmdidx == CMD_lchdir)
- {
- /* If still in global directory, need to remember current
- * directory as global directory. */
- if (globaldir == NULL && prev_dir != NULL)
- globaldir = vim_strsave(prev_dir);
- /* Remember this local directory for the window. */
- if (mch_dirname(NameBuff, MAXPATHL) == OK)
- curwin->w_localdir = vim_strsave(NameBuff);
- }
- else
- {
- /* We are now in the global directory, no need to remember its
- * name. */
- vim_free(globaldir);
- globaldir = NULL;
- curwin->w_localdir = NULL;
- }
-
- shorten_fnames(TRUE);
+ post_chdir(eap->cmdidx == CMD_lcd || eap->cmdidx == CMD_lchdir);
/* Echo the new current directory if the command was typed. */
if (KeyTyped || p_verbose >= 5)
diff --git a/src/if_py_both.h b/src/if_py_both.h
index 21bf069c..73fa56cb 100644
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -52,6 +52,10 @@ static PyInt RangeEnd;
static PyObject *globals;
+static PyObject *py_chdir;
+static PyObject *py_fchdir;
+static PyObject *py_getcwd;
+
/*
* obtain a lock on the Vim data structures
*/
@@ -706,17 +710,84 @@ VimStrwidth(PyObject *self UNUSED, PyObject *args)
);
}
+ static PyObject *
+_VimChdir(PyObject *_chdir, PyObject *args, PyObject *kwargs)
+{
+ PyObject *r;
+ PyObject *newwd;
+ PyObject *todecref;
+ char_u *new_dir;
+
+ if (!(r = PyObject_Call(_chdir, args, kwargs)))
+ return NULL;
+
+ if (!(newwd = PyObject_CallFunctionObjArgs(py_getcwd, NULL)))
+ {
+ Py_DECREF(r);
+ return NULL;
+ }
+
+ if (!(new_dir = StringToChars(newwd, &todecref)))
+ {
+ Py_DECREF(r);
+ Py_DECREF(newwd);
+ return NULL;
+ }
+
+ VimTryStart();
+
+ if (vim_chdir(new_dir))
+ {
+ Py_DECREF(r);
+ Py_DECREF(newwd);
+ Py_XDECREF(todecref);
+
+ if (VimTryEnd())
+ return NULL;
+
+ PyErr_SetVim(_("failed to change directory"));
+ return NULL;
+ }
+
+ Py_DECREF(newwd);
+ Py_XDECREF(todecref);
+
+ post_chdir(FALSE);
+
+ if (VimTryEnd())
+ {
+ Py_DECREF(r);
+ return NULL;
+ }
+
+ return r;
+}
+
+ static PyObject *
+VimChdir(PyObject *self UNUSED, PyObject *args, PyObject *kwargs)
+{
+ return _VimChdir(py_chdir, args, kwargs);
+}
+
+ static PyObject *
+VimFchdir(PyObject *self UNUSED, PyObject *args, PyObject *kwargs)
+{
+ return _VimChdir(py_fchdir, args, kwargs);
+}
+
/*
* 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"},
- { 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"},
+ { NULL, NULL, 0, NULL }
};
/*
@@ -5274,6 +5345,7 @@ static struct object_constant {
};
typedef int (*object_adder)(PyObject *, const char *, PyObject *);
+typedef PyObject *(*attr_getter)(PyObject *, const char *);
#define ADD_OBJECT(m, name, obj) \
if (add_object(m, name, obj)) \
@@ -5288,9 +5360,10 @@ typedef int (*object_adder)(PyObject *, const char *, PyObject *);
}
static int
-populate_module(PyObject *m, object_adder add_object)
+populate_module(PyObject *m, object_adder add_object, attr_getter get_attr)
{
int i;
+ PyObject *os;
for (i = 0; i < (int)(sizeof(numeric_constants)
/ sizeof(struct numeric_constant));
@@ -5317,5 +5390,27 @@ populate_module(PyObject *m, object_adder add_object)
ADD_CHECKED_OBJECT(m, "vvars", NEW_DICTIONARY(&vimvardict));
ADD_CHECKED_OBJECT(m, "options",
OptionsNew(SREQ_GLOBAL, NULL, dummy_check, NULL));
+
+ if (!(os = PyImport_ImportModule("os")))
+ return -1;
+ ADD_OBJECT(m, "os", os);
+
+ if (!(py_getcwd = PyObject_GetAttrString(os, "getcwd")))
+ return -1;
+ ADD_OBJECT(m, "_getcwd", py_getcwd)
+
+ if (!(py_chdir = PyObject_GetAttrString(os, "chdir")))
+ return -1;
+ ADD_OBJECT(m, "_chdir", py_chdir);
+ if (PyObject_SetAttrString(os, "chdir", get_attr(m, "chdir")))
+ return -1;
+
+ if ((py_fchdir = PyObject_GetAttrString(os, "fchdir")))
+ {
+ ADD_OBJECT(m, "_fchdir", py_fchdir);
+ if (PyObject_SetAttrString(os, "fchdir", get_attr(m, "fchdir")))
+ return -1;
+ }
+
return 0;
}
diff --git a/src/if_python.c b/src/if_python.c
index a1291d73..254f01a7 100644
--- a/src/if_python.c
+++ b/src/if_python.c
@@ -213,6 +213,7 @@ struct PyMethodDef { Py_ssize_t a; };
# define PyObject_HasAttrString dll_PyObject_HasAttrString
# define PyObject_SetAttrString dll_PyObject_SetAttrString
# define PyObject_CallFunctionObjArgs dll_PyObject_CallFunctionObjArgs
+# define PyObject_Call dll_PyObject_Call
# define PyString_AsString dll_PyString_AsString
# define PyString_AsStringAndSize dll_PyString_AsStringAndSize
# define PyString_FromString dll_PyString_FromString
@@ -346,6 +347,7 @@ static PyObject* (*dll_PyObject_GetAttrString)(PyObject *, const char *);
static int (*dll_PyObject_HasAttrString)(PyObject *, const char *);
static PyObject* (*dll_PyObject_SetAttrString)(PyObject *, const char *, PyObject *);
static PyObject* (*dll_PyObject_CallFunctionObjArgs)(PyObject *, ...);
+static PyObject* (*dll_PyObject_Call)(PyObject *, PyObject *, PyObject *);
static char*(*dll_PyString_AsString)(PyObject *);
static int(*dll_PyString_AsStringAndSize)(PyObject *, char **, int *);
static PyObject*(*dll_PyString_FromString)(const char *);
@@ -510,6 +512,7 @@ static struct
{"PyObject_HasAttrString", (PYTHON_PROC*)&dll_PyObject_HasAttrString},
{"PyObject_SetAttrString", (PYTHON_PROC*)&dll_PyObject_SetAttrString},
{"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&dll_PyObject_CallFunctionObjArgs},
+ {"PyObject_Call", (PYTHON_PROC*)&dll_PyObject_Call},
{"PyString_AsString", (PYTHON_PROC*)&dll_PyString_AsString},
{"PyString_AsStringAndSize", (PYTHON_PROC*)&dll_PyString_AsStringAndSize},
{"PyString_FromString", (PYTHON_PROC*)&dll_PyString_FromString},
@@ -1374,10 +1377,11 @@ PythonMod_Init(void)
/* Set sys.argv[] to avoid a crash in warn(). */
PySys_SetArgv(1, argv);
- mod = Py_InitModule4("vim", VimMethods, (char *)NULL, (PyObject *)NULL, PYTHON_API_VERSION);
+ mod = Py_InitModule4("vim", VimMethods, (char *)NULL, (PyObject *)NULL,
+ PYTHON_API_VERSION);
dict = PyModule_GetDict(mod);
- return populate_module(dict, add_object);
+ return populate_module(dict, add_object, PyDict_GetItemString);
}
/*************************************************************************
diff --git a/src/if_python3.c b/src/if_python3.c
index 66e153b6..915d3f83 100644
--- a/src/if_python3.c
+++ b/src/if_python3.c
@@ -174,6 +174,7 @@
# define PyObject_HasAttrString py3_PyObject_HasAttrString
# define PyObject_SetAttrString py3_PyObject_SetAttrString
# define PyObject_CallFunctionObjArgs py3_PyObject_CallFunctionObjArgs
+# define PyObject_Call py3_PyObject_Call
# define PyEval_GetLocals py3_PyEval_GetLocals
# define PyEval_GetGlobals py3_PyEval_GetGlobals
# define PySys_SetObject py3_PySys_SetObject
@@ -290,6 +291,7 @@ static PyObject* (*py3_PyObject_GetAttrString)(PyObject *, const char *);
static int (*py3_PyObject_HasAttrString)(PyObject *, const char *);
static PyObject* (*py3_PyObject_SetAttrString)(PyObject *, const char *, PyObject *);
static PyObject* (*py3_PyObject_CallFunctionObjArgs)(PyObject *, ...);
+static PyObject* (*py3_PyObject_Call)(PyObject *, PyObject *, PyObject *);
static PyObject* (*py3_PyEval_GetGlobals)();
static PyObject* (*py3_PyEval_GetLocals)();
static PyObject* (*py3_PyList_GetItem)(PyObject *, Py_ssize_t);
@@ -446,6 +448,7 @@ static struct
{"PyObject_HasAttrString", (PYTHON_PROC*)&py3_PyObject_HasAttrString},
{"PyObject_SetAttrString", (PYTHON_PROC*)&py3_PyObject_SetAttrString},
{"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&py3_PyObject_CallFunctionObjArgs},
+ {"PyObject_Call", (PYTHON_PROC*)&py3_PyObject_Call},
{"PyEval_GetGlobals", (PYTHON_PROC*)&py3_PyEval_GetGlobals},
{"PyEval_GetLocals", (PYTHON_PROC*)&py3_PyEval_GetLocals},
{"PyList_GetItem", (PYTHON_PROC*)&py3_PyList_GetItem},
@@ -1600,7 +1603,7 @@ Py3Init_vim(void)
if (mod == NULL)
return NULL;
- if (populate_module(mod, PyModule_AddObject))
+ if (populate_module(mod, PyModule_AddObject, PyObject_GetAttrString))
return NULL;
return mod;
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
index f59c494a..55ae0de5 100644
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -53,4 +53,5 @@ int put_eol __ARGS((FILE *fd));
int put_line __ARGS((FILE *fd, char *s));
void dialog_msg __ARGS((char_u *buff, char *format, char_u *fname));
char_u *get_behave_arg __ARGS((expand_T *xp, int idx));
+void post_chdir __ARGS((int local));
/* vim: set ft=c : */
diff --git a/src/testdir/test86.in b/src/testdir/test86.in
index dc21af49..6929f674 100644
--- a/src/testdir/test86.in
+++ b/src/testdir/test86.in
@@ -788,6 +788,20 @@ EOF
:$put =string(pyeval('dl2'))
:$put =string(pyeval('df(2)'))
:"
+:" Test chdir
+py << EOF
+import os
+fnamemodify = vim.Function('fnamemodify')
+cb.append(fnamemodify('.', ':p:h:t'))
+cb.append(vim.eval('@%'))
+os.chdir('..')
+cb.append(fnamemodify('.', ':p:h:t'))
+cb.append(vim.eval('@%').replace(os.path.sep, '/'))
+os.chdir('testdir')
+cb.append(fnamemodify('.', ':p:h:t'))
+cb.append(vim.eval('@%'))
+EOF
+:"
:" Test errors
:fun F() dict
:endfun
diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok
index 7d243904..5ebf108d 100644
--- a/src/testdir/test86.ok
+++ b/src/testdir/test86.ok
@@ -429,6 +429,12 @@ abc'
['a', 'b', 'c']
[2, 2]
[2, 2]
+testdir
+test86.in
+src
+testdir/test86.in
+testdir
+test86.in
> Output
>> OutputSetattr
del sys.stdout.softspace:(<type 'exceptions.AttributeError'>, AttributeError("can't delete OutputObject attributes",))
diff --git a/src/testdir/test87.in b/src/testdir/test87.in
index 45a4b8e4..cf5d5e27 100644
--- a/src/testdir/test87.in
+++ b/src/testdir/test87.in
@@ -748,6 +748,20 @@ EOF
:$put =string(py3eval('dl2'))
:$put =string(py3eval('df(2)'))
:"
+:" Test chdir
+py3 << EOF
+import os
+fnamemodify = vim.Function('fnamemodify')
+cb.append(str(fnamemodify('.', ':p:h:t')))
+cb.append(vim.eval('@%'))
+os.chdir('..')
+cb.append(str(fnamemodify('.', ':p:h:t')))
+cb.append(vim.eval('@%').replace(os.path.sep, '/'))
+os.chdir('testdir')
+cb.append(str(fnamemodify('.', ':p:h:t')))
+cb.append(vim.eval('@%'))
+EOF
+:"
:" Test errors
:fun F() dict
:endfun
diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok
index 94a914ef..49ad4e4c 100644
--- a/src/testdir/test87.ok
+++ b/src/testdir/test87.ok
@@ -418,6 +418,12 @@ abc'
['a', 'b', 'c']
[2, 2]
[2, 2]
+b'testdir'
+test87.in
+b'src'
+testdir/test87.in
+b'testdir'
+test87.in
> Output
>> OutputSetattr
del sys.stdout.softspace:(<class 'AttributeError'>, AttributeError("can't delete OutputObject attributes",))
diff --git a/src/version.c b/src/version.c
index fad5ada8..9b13b2d5 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1099,
+/**/
1098,
/**/
1097,