]> granicus.if.org Git - vim/commitdiff
updated for version 7.3.1099 v7.3.1099
authorBram Moolenaar <Bram@vim.org>
Sun, 2 Jun 2013 16:20:17 +0000 (18:20 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 2 Jun 2013 16:20:17 +0000 (18:20 +0200)
Problem:    Python: Changing directory with os.chdir() causes problems for
            Vim's notion of directories.
Solution:   Add vim.chdir() and vim.fchdir(). (ZyX)

runtime/doc/if_pyth.txt
src/ex_docmd.c
src/if_py_both.h
src/if_python.c
src/if_python3.c
src/proto/ex_docmd.pro
src/testdir/test86.in
src/testdir/test86.ok
src/testdir/test87.in
src/testdir/test87.ok
src/version.c

index d37bd49f4f9fbf83fbd306ca0ca1b00eb5e0b622..7bd9b377e4c885e439810f18e22b626ddd0de348 100644 (file)
@@ -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*
index 056339e7eac5af4391f5e0a437895a189795dc1a..b6fc3766842e0400c7d621ac73e6cd9fa75edf64 100644 (file)
@@ -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)
index 21bf069c8c37d9f49bc6a9bff29e08d675d1bb0f..73fa56cbc911631fe9d2c6969a384cc9b476827e 100644 (file)
@@ -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;
 }
index a1291d7364344d0dae64caae72668706612aa5b4..254f01a75b478a4339aa6d35bee8ad8374587581 100644 (file)
@@ -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);
 }
 
 /*************************************************************************
index 66e153b6e21eb664b42a8da8030602f1648632d9..915d3f83d9ea7f3e98ea06a69ff3dfe4f9b51eba 100644 (file)
 # 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;
index f59c494a86d62813bc9e246e9f86feb525ca5e8d..55ae0de5e539b331db6b2e711e9eb70b4e16bba0 100644 (file)
@@ -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 : */
index dc21af493e33dc571464b970ce213e30251fce48..6929f67442cc22c7302c0944e25578a401cb59b8 100644 (file)
@@ -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
index 7d243904e2eb78abd4634232236f02fd4306f8ec..5ebf108d1f538dd897998b378a97f06a52d6d9cb 100644 (file)
@@ -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",))
index 45a4b8e40107320553f196e9edef75a82921e280..cf5d5e27f5f42a277e8eec4d71096a7a0dc2024b 100644 (file)
@@ -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
index 94a914ef85ac4566f7a83ed83fd75b27ccd219fe..49ad4e4cd85dd3f76160de1f272736a0418823ae 100644 (file)
@@ -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",))
index fad5ada8a6b52ef4d3c249b76e3bef5e2dceb916..9b13b2d5ddf3e84fa6c9a7b5b3d2501a80f4a633 100644 (file)
@@ -728,6 +728,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1099,
 /**/
     1098,
 /**/