1
0
forked from aniani/vim

updated for version 7.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)
This commit is contained in:
Bram Moolenaar 2013-06-02 18:20:17 +02:00
parent 4f2109d782
commit f4258308e2
11 changed files with 194 additions and 31 deletions

View File

@ -180,6 +180,13 @@ vim.strwidth(str) *python-strwidth*
Like |strwidth()|: returns number of display cells str occupies, tab Like |strwidth()|: returns number of display cells str occupies, tab
is counted as one cell. 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 Error object of the "vim" module
vim.error *python-error* vim.error *python-error*

View File

@ -8182,6 +8182,37 @@ free_cd_dir()
} }
#endif #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". * ":cd", ":lcd", ":chdir" and ":lchdir".
@ -8253,27 +8284,7 @@ ex_cd(eap)
EMSG(_(e_failed)); EMSG(_(e_failed));
else else
{ {
vim_free(curwin->w_localdir); post_chdir(eap->cmdidx == CMD_lcd || eap->cmdidx == CMD_lchdir);
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);
/* Echo the new current directory if the command was typed. */ /* Echo the new current directory if the command was typed. */
if (KeyTyped || p_verbose >= 5) if (KeyTyped || p_verbose >= 5)

View File

@ -52,6 +52,10 @@ static PyInt RangeEnd;
static PyObject *globals; static PyObject *globals;
static PyObject *py_chdir;
static PyObject *py_fchdir;
static PyObject *py_getcwd;
/* /*
* obtain a lock on the Vim data structures * 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 * Vim module - Definitions
*/ */
static struct PyMethodDef VimMethods[] = { static struct PyMethodDef VimMethods[] = {
/* name, function, calling, documentation */ /* name, function, calling, documentation */
{"command", VimCommand, METH_VARARGS, "Execute a Vim ex-mode command" }, {"command", VimCommand, METH_VARARGS, "Execute a Vim ex-mode command" },
{"eval", VimEval, METH_VARARGS, "Evaluate an expression using Vim evaluator" }, {"eval", VimEval, METH_VARARGS, "Evaluate an expression using Vim evaluator" },
{"bindeval", VimEvalPy, METH_VARARGS, "Like eval(), but returns objects attached to vim ones"}, {"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"}, {"strwidth", VimStrwidth, METH_VARARGS, "Screen string width, counts <Tab> as having width 1"},
{ NULL, NULL, 0, NULL } {"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 int (*object_adder)(PyObject *, const char *, PyObject *);
typedef PyObject *(*attr_getter)(PyObject *, const char *);
#define ADD_OBJECT(m, name, obj) \ #define ADD_OBJECT(m, name, obj) \
if (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 static int
populate_module(PyObject *m, object_adder add_object) populate_module(PyObject *m, object_adder add_object, attr_getter get_attr)
{ {
int i; int i;
PyObject *os;
for (i = 0; i < (int)(sizeof(numeric_constants) for (i = 0; i < (int)(sizeof(numeric_constants)
/ sizeof(struct numeric_constant)); / 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, "vvars", NEW_DICTIONARY(&vimvardict));
ADD_CHECKED_OBJECT(m, "options", ADD_CHECKED_OBJECT(m, "options",
OptionsNew(SREQ_GLOBAL, NULL, dummy_check, NULL)); 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; return 0;
} }

View File

@ -213,6 +213,7 @@ struct PyMethodDef { Py_ssize_t a; };
# define PyObject_HasAttrString dll_PyObject_HasAttrString # define PyObject_HasAttrString dll_PyObject_HasAttrString
# define PyObject_SetAttrString dll_PyObject_SetAttrString # define PyObject_SetAttrString dll_PyObject_SetAttrString
# define PyObject_CallFunctionObjArgs dll_PyObject_CallFunctionObjArgs # define PyObject_CallFunctionObjArgs dll_PyObject_CallFunctionObjArgs
# define PyObject_Call dll_PyObject_Call
# define PyString_AsString dll_PyString_AsString # define PyString_AsString dll_PyString_AsString
# define PyString_AsStringAndSize dll_PyString_AsStringAndSize # define PyString_AsStringAndSize dll_PyString_AsStringAndSize
# define PyString_FromString dll_PyString_FromString # 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 int (*dll_PyObject_HasAttrString)(PyObject *, const char *);
static PyObject* (*dll_PyObject_SetAttrString)(PyObject *, const char *, PyObject *); static PyObject* (*dll_PyObject_SetAttrString)(PyObject *, const char *, PyObject *);
static PyObject* (*dll_PyObject_CallFunctionObjArgs)(PyObject *, ...); static PyObject* (*dll_PyObject_CallFunctionObjArgs)(PyObject *, ...);
static PyObject* (*dll_PyObject_Call)(PyObject *, PyObject *, PyObject *);
static char*(*dll_PyString_AsString)(PyObject *); static char*(*dll_PyString_AsString)(PyObject *);
static int(*dll_PyString_AsStringAndSize)(PyObject *, char **, int *); static int(*dll_PyString_AsStringAndSize)(PyObject *, char **, int *);
static PyObject*(*dll_PyString_FromString)(const char *); static PyObject*(*dll_PyString_FromString)(const char *);
@ -510,6 +512,7 @@ static struct
{"PyObject_HasAttrString", (PYTHON_PROC*)&dll_PyObject_HasAttrString}, {"PyObject_HasAttrString", (PYTHON_PROC*)&dll_PyObject_HasAttrString},
{"PyObject_SetAttrString", (PYTHON_PROC*)&dll_PyObject_SetAttrString}, {"PyObject_SetAttrString", (PYTHON_PROC*)&dll_PyObject_SetAttrString},
{"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&dll_PyObject_CallFunctionObjArgs}, {"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&dll_PyObject_CallFunctionObjArgs},
{"PyObject_Call", (PYTHON_PROC*)&dll_PyObject_Call},
{"PyString_AsString", (PYTHON_PROC*)&dll_PyString_AsString}, {"PyString_AsString", (PYTHON_PROC*)&dll_PyString_AsString},
{"PyString_AsStringAndSize", (PYTHON_PROC*)&dll_PyString_AsStringAndSize}, {"PyString_AsStringAndSize", (PYTHON_PROC*)&dll_PyString_AsStringAndSize},
{"PyString_FromString", (PYTHON_PROC*)&dll_PyString_FromString}, {"PyString_FromString", (PYTHON_PROC*)&dll_PyString_FromString},
@ -1374,10 +1377,11 @@ PythonMod_Init(void)
/* Set sys.argv[] to avoid a crash in warn(). */ /* Set sys.argv[] to avoid a crash in warn(). */
PySys_SetArgv(1, argv); 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); dict = PyModule_GetDict(mod);
return populate_module(dict, add_object); return populate_module(dict, add_object, PyDict_GetItemString);
} }
/************************************************************************* /*************************************************************************

View File

@ -174,6 +174,7 @@
# define PyObject_HasAttrString py3_PyObject_HasAttrString # define PyObject_HasAttrString py3_PyObject_HasAttrString
# define PyObject_SetAttrString py3_PyObject_SetAttrString # define PyObject_SetAttrString py3_PyObject_SetAttrString
# define PyObject_CallFunctionObjArgs py3_PyObject_CallFunctionObjArgs # define PyObject_CallFunctionObjArgs py3_PyObject_CallFunctionObjArgs
# define PyObject_Call py3_PyObject_Call
# define PyEval_GetLocals py3_PyEval_GetLocals # define PyEval_GetLocals py3_PyEval_GetLocals
# define PyEval_GetGlobals py3_PyEval_GetGlobals # define PyEval_GetGlobals py3_PyEval_GetGlobals
# define PySys_SetObject py3_PySys_SetObject # 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 int (*py3_PyObject_HasAttrString)(PyObject *, const char *);
static PyObject* (*py3_PyObject_SetAttrString)(PyObject *, const char *, PyObject *); static PyObject* (*py3_PyObject_SetAttrString)(PyObject *, const char *, PyObject *);
static PyObject* (*py3_PyObject_CallFunctionObjArgs)(PyObject *, ...); static PyObject* (*py3_PyObject_CallFunctionObjArgs)(PyObject *, ...);
static PyObject* (*py3_PyObject_Call)(PyObject *, PyObject *, PyObject *);
static PyObject* (*py3_PyEval_GetGlobals)(); static PyObject* (*py3_PyEval_GetGlobals)();
static PyObject* (*py3_PyEval_GetLocals)(); static PyObject* (*py3_PyEval_GetLocals)();
static PyObject* (*py3_PyList_GetItem)(PyObject *, Py_ssize_t); static PyObject* (*py3_PyList_GetItem)(PyObject *, Py_ssize_t);
@ -446,6 +448,7 @@ static struct
{"PyObject_HasAttrString", (PYTHON_PROC*)&py3_PyObject_HasAttrString}, {"PyObject_HasAttrString", (PYTHON_PROC*)&py3_PyObject_HasAttrString},
{"PyObject_SetAttrString", (PYTHON_PROC*)&py3_PyObject_SetAttrString}, {"PyObject_SetAttrString", (PYTHON_PROC*)&py3_PyObject_SetAttrString},
{"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&py3_PyObject_CallFunctionObjArgs}, {"PyObject_CallFunctionObjArgs", (PYTHON_PROC*)&py3_PyObject_CallFunctionObjArgs},
{"PyObject_Call", (PYTHON_PROC*)&py3_PyObject_Call},
{"PyEval_GetGlobals", (PYTHON_PROC*)&py3_PyEval_GetGlobals}, {"PyEval_GetGlobals", (PYTHON_PROC*)&py3_PyEval_GetGlobals},
{"PyEval_GetLocals", (PYTHON_PROC*)&py3_PyEval_GetLocals}, {"PyEval_GetLocals", (PYTHON_PROC*)&py3_PyEval_GetLocals},
{"PyList_GetItem", (PYTHON_PROC*)&py3_PyList_GetItem}, {"PyList_GetItem", (PYTHON_PROC*)&py3_PyList_GetItem},
@ -1600,7 +1603,7 @@ Py3Init_vim(void)
if (mod == NULL) if (mod == NULL)
return NULL; return NULL;
if (populate_module(mod, PyModule_AddObject)) if (populate_module(mod, PyModule_AddObject, PyObject_GetAttrString))
return NULL; return NULL;
return mod; return mod;

View File

@ -53,4 +53,5 @@ int put_eol __ARGS((FILE *fd));
int put_line __ARGS((FILE *fd, char *s)); int put_line __ARGS((FILE *fd, char *s));
void dialog_msg __ARGS((char_u *buff, char *format, char_u *fname)); void dialog_msg __ARGS((char_u *buff, char *format, char_u *fname));
char_u *get_behave_arg __ARGS((expand_T *xp, int idx)); char_u *get_behave_arg __ARGS((expand_T *xp, int idx));
void post_chdir __ARGS((int local));
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -788,6 +788,20 @@ EOF
:$put =string(pyeval('dl2')) :$put =string(pyeval('dl2'))
:$put =string(pyeval('df(2)')) :$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 :" Test errors
:fun F() dict :fun F() dict
:endfun :endfun

View File

@ -429,6 +429,12 @@ abc'
['a', 'b', 'c'] ['a', 'b', 'c']
[2, 2] [2, 2]
[2, 2] [2, 2]
testdir
test86.in
src
testdir/test86.in
testdir
test86.in
> Output > Output
>> OutputSetattr >> OutputSetattr
del sys.stdout.softspace:(<type 'exceptions.AttributeError'>, AttributeError("can't delete OutputObject attributes",)) del sys.stdout.softspace:(<type 'exceptions.AttributeError'>, AttributeError("can't delete OutputObject attributes",))

View File

@ -748,6 +748,20 @@ EOF
:$put =string(py3eval('dl2')) :$put =string(py3eval('dl2'))
:$put =string(py3eval('df(2)')) :$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 :" Test errors
:fun F() dict :fun F() dict
:endfun :endfun

View File

@ -418,6 +418,12 @@ abc'
['a', 'b', 'c'] ['a', 'b', 'c']
[2, 2] [2, 2]
[2, 2] [2, 2]
b'testdir'
test87.in
b'src'
testdir/test87.in
b'testdir'
test87.in
> Output > Output
>> OutputSetattr >> OutputSetattr
del sys.stdout.softspace:(<class 'AttributeError'>, AttributeError("can't delete OutputObject attributes",)) del sys.stdout.softspace:(<class 'AttributeError'>, AttributeError("can't delete OutputObject attributes",))

View File

@ -728,6 +728,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1099,
/**/ /**/
1098, 1098,
/**/ /**/