xref: /vim-8.2.3635/src/if_python.c (revision 170bf1ae)
1071d4279SBram Moolenaar /* vi:set ts=8 sts=4 sw=4:
2071d4279SBram Moolenaar  *
3071d4279SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
4071d4279SBram Moolenaar  *
5071d4279SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar  * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar  */
9071d4279SBram Moolenaar /*
10071d4279SBram Moolenaar  * Python extensions by Paul Moore.
11071d4279SBram Moolenaar  * Changes for Unix by David Leonard.
12071d4279SBram Moolenaar  *
13071d4279SBram Moolenaar  * This consists of four parts:
14071d4279SBram Moolenaar  * 1. Python interpreter main program
15071d4279SBram Moolenaar  * 2. Python output stream: writes output via [e]msg().
16071d4279SBram Moolenaar  * 3. Implementation of the Vim module for Python
17071d4279SBram Moolenaar  * 4. Utility functions for handling the interface between Vim and Python.
18071d4279SBram Moolenaar  */
19071d4279SBram Moolenaar 
20071d4279SBram Moolenaar #include "vim.h"
21071d4279SBram Moolenaar 
22071d4279SBram Moolenaar #include <limits.h>
23071d4279SBram Moolenaar 
24071d4279SBram Moolenaar /* Python.h defines _POSIX_THREADS itself (if needed) */
25071d4279SBram Moolenaar #ifdef _POSIX_THREADS
26071d4279SBram Moolenaar # undef _POSIX_THREADS
27071d4279SBram Moolenaar #endif
28071d4279SBram Moolenaar 
29071d4279SBram Moolenaar #if defined(_WIN32) && defined(HAVE_FCNTL_H)
30071d4279SBram Moolenaar # undef HAVE_FCNTL_H
31071d4279SBram Moolenaar #endif
32071d4279SBram Moolenaar 
33071d4279SBram Moolenaar #ifdef _DEBUG
34071d4279SBram Moolenaar # undef _DEBUG
35071d4279SBram Moolenaar #endif
36071d4279SBram Moolenaar 
37071d4279SBram Moolenaar #ifdef HAVE_STDARG_H
38071d4279SBram Moolenaar # undef HAVE_STDARG_H	/* Python's config.h defines it as well. */
39071d4279SBram Moolenaar #endif
40be2c9ae9SBram Moolenaar #ifdef _POSIX_C_SOURCE
41be2c9ae9SBram Moolenaar # undef _POSIX_C_SOURCE	/* pyconfig.h defines it as well. */
42be2c9ae9SBram Moolenaar #endif
43be2c9ae9SBram Moolenaar #ifdef _XOPEN_SOURCE
44be2c9ae9SBram Moolenaar # undef _XOPEN_SOURCE	/* pyconfig.h defines it as well. */
45be2c9ae9SBram Moolenaar #endif
46071d4279SBram Moolenaar 
472c45e945SBram Moolenaar #define PY_SSIZE_T_CLEAN
482c45e945SBram Moolenaar 
49071d4279SBram Moolenaar #include <Python.h>
50071d4279SBram Moolenaar #if defined(MACOS) && !defined(MACOS_X_UNIX)
51071d4279SBram Moolenaar # include "macglue.h"
52071d4279SBram Moolenaar # include <CodeFragments.h>
53071d4279SBram Moolenaar #endif
54071d4279SBram Moolenaar #undef main /* Defined in python.h - aargh */
55071d4279SBram Moolenaar #undef HAVE_FCNTL_H /* Clash with os_win32.h */
56071d4279SBram Moolenaar 
57*170bf1aeSBram Moolenaar static void init_structs(void);
58*170bf1aeSBram Moolenaar 
59071d4279SBram Moolenaar #if !defined(FEAT_PYTHON) && defined(PROTO)
60071d4279SBram Moolenaar /* Use this to be able to generate prototypes without python being used. */
61e7cb9cf6SBram Moolenaar # define PyObject Py_ssize_t
62e7cb9cf6SBram Moolenaar # define PyThreadState Py_ssize_t
63e7cb9cf6SBram Moolenaar # define PyTypeObject Py_ssize_t
64e7cb9cf6SBram Moolenaar struct PyMethodDef { Py_ssize_t a; };
65e7cb9cf6SBram Moolenaar # define PySequenceMethods Py_ssize_t
66071d4279SBram Moolenaar #endif
67071d4279SBram Moolenaar 
682c45e945SBram Moolenaar #if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02050000
692c45e945SBram Moolenaar # define PyInt Py_ssize_t
702c45e945SBram Moolenaar # define PyInquiry lenfunc
712c45e945SBram Moolenaar # define PyIntArgFunc ssizeargfunc
722c45e945SBram Moolenaar # define PyIntIntArgFunc ssizessizeargfunc
732c45e945SBram Moolenaar # define PyIntObjArgProc ssizeobjargproc
742c45e945SBram Moolenaar # define PyIntIntObjArgProc ssizessizeobjargproc
75e7cb9cf6SBram Moolenaar # define Py_ssize_t_fmt "n"
762c45e945SBram Moolenaar #else
772c45e945SBram Moolenaar # define PyInt int
782c45e945SBram Moolenaar # define PyInquiry inquiry
792c45e945SBram Moolenaar # define PyIntArgFunc intargfunc
802c45e945SBram Moolenaar # define PyIntIntArgFunc intintargfunc
812c45e945SBram Moolenaar # define PyIntObjArgProc intobjargproc
822c45e945SBram Moolenaar # define PyIntIntObjArgProc intintobjargproc
83e7cb9cf6SBram Moolenaar # define Py_ssize_t_fmt "i"
842c45e945SBram Moolenaar #endif
852c45e945SBram Moolenaar 
86071d4279SBram Moolenaar /* Parser flags */
87071d4279SBram Moolenaar #define single_input	256
88071d4279SBram Moolenaar #define file_input	257
89071d4279SBram Moolenaar #define eval_input	258
90071d4279SBram Moolenaar 
91071d4279SBram Moolenaar #if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x020300F0
92071d4279SBram Moolenaar   /* Python 2.3: can invoke ":python" recursively. */
93071d4279SBram Moolenaar # define PY_CAN_RECURSE
94071d4279SBram Moolenaar #endif
95071d4279SBram Moolenaar 
96071d4279SBram Moolenaar #if defined(DYNAMIC_PYTHON) || defined(PROTO)
97071d4279SBram Moolenaar # ifndef DYNAMIC_PYTHON
98e7cb9cf6SBram Moolenaar #  define HINSTANCE long_u		/* for generating prototypes */
99071d4279SBram Moolenaar # endif
100071d4279SBram Moolenaar 
101fa5d1e63SBram Moolenaar #ifndef WIN3264
102bd5e15fdSBram Moolenaar # include <dlfcn.h>
103bd5e15fdSBram Moolenaar # define FARPROC void*
104bd5e15fdSBram Moolenaar # define HINSTANCE void*
105fa5d1e63SBram Moolenaar # define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
106bd5e15fdSBram Moolenaar # define close_dll dlclose
107bd5e15fdSBram Moolenaar # define symbol_from_dll dlsym
108bd5e15fdSBram Moolenaar #else
109bd5e15fdSBram Moolenaar # define load_dll LoadLibrary
110bd5e15fdSBram Moolenaar # define close_dll FreeLibrary
111bd5e15fdSBram Moolenaar # define symbol_from_dll GetProcAddress
112bd5e15fdSBram Moolenaar #endif
113bd5e15fdSBram Moolenaar 
114e7cb9cf6SBram Moolenaar /* This makes if_python.c compile without warnings against Python 2.5
115e7cb9cf6SBram Moolenaar  * on Win32 and Win64. */
116e7cb9cf6SBram Moolenaar #undef PyRun_SimpleString
117e7cb9cf6SBram Moolenaar #undef PyArg_Parse
118e7cb9cf6SBram Moolenaar #undef PyArg_ParseTuple
119e7cb9cf6SBram Moolenaar #undef Py_BuildValue
120e7cb9cf6SBram Moolenaar #undef Py_InitModule4
121e7cb9cf6SBram Moolenaar #undef Py_InitModule4_64
122e7cb9cf6SBram Moolenaar 
123071d4279SBram Moolenaar /*
124071d4279SBram Moolenaar  * Wrapper defines
125071d4279SBram Moolenaar  */
126071d4279SBram Moolenaar # define PyArg_Parse dll_PyArg_Parse
127071d4279SBram Moolenaar # define PyArg_ParseTuple dll_PyArg_ParseTuple
128071d4279SBram Moolenaar # define PyDict_SetItemString dll_PyDict_SetItemString
129071d4279SBram Moolenaar # define PyErr_BadArgument dll_PyErr_BadArgument
130071d4279SBram Moolenaar # define PyErr_Clear dll_PyErr_Clear
131071d4279SBram Moolenaar # define PyErr_NoMemory dll_PyErr_NoMemory
132071d4279SBram Moolenaar # define PyErr_Occurred dll_PyErr_Occurred
133071d4279SBram Moolenaar # define PyErr_SetNone dll_PyErr_SetNone
134071d4279SBram Moolenaar # define PyErr_SetString dll_PyErr_SetString
135071d4279SBram Moolenaar # define PyEval_InitThreads dll_PyEval_InitThreads
136071d4279SBram Moolenaar # define PyEval_RestoreThread dll_PyEval_RestoreThread
137071d4279SBram Moolenaar # define PyEval_SaveThread dll_PyEval_SaveThread
138071d4279SBram Moolenaar # ifdef PY_CAN_RECURSE
139071d4279SBram Moolenaar #  define PyGILState_Ensure dll_PyGILState_Ensure
140071d4279SBram Moolenaar #  define PyGILState_Release dll_PyGILState_Release
141071d4279SBram Moolenaar # endif
142071d4279SBram Moolenaar # define PyInt_AsLong dll_PyInt_AsLong
143071d4279SBram Moolenaar # define PyInt_FromLong dll_PyInt_FromLong
144071d4279SBram Moolenaar # define PyInt_Type (*dll_PyInt_Type)
145071d4279SBram Moolenaar # define PyList_GetItem dll_PyList_GetItem
1460ac9379aSBram Moolenaar # define PyList_Append dll_PyList_Append
147071d4279SBram Moolenaar # define PyList_New dll_PyList_New
148071d4279SBram Moolenaar # define PyList_SetItem dll_PyList_SetItem
149071d4279SBram Moolenaar # define PyList_Size dll_PyList_Size
150071d4279SBram Moolenaar # define PyList_Type (*dll_PyList_Type)
151071d4279SBram Moolenaar # define PyImport_ImportModule dll_PyImport_ImportModule
1520ac9379aSBram Moolenaar # define PyDict_New dll_PyDict_New
153071d4279SBram Moolenaar # define PyDict_GetItemString dll_PyDict_GetItemString
154071d4279SBram Moolenaar # define PyModule_GetDict dll_PyModule_GetDict
155071d4279SBram Moolenaar # define PyRun_SimpleString dll_PyRun_SimpleString
156071d4279SBram Moolenaar # define PyString_AsString dll_PyString_AsString
157071d4279SBram Moolenaar # define PyString_FromString dll_PyString_FromString
158071d4279SBram Moolenaar # define PyString_FromStringAndSize dll_PyString_FromStringAndSize
159071d4279SBram Moolenaar # define PyString_Size dll_PyString_Size
160071d4279SBram Moolenaar # define PyString_Type (*dll_PyString_Type)
161071d4279SBram Moolenaar # define PySys_SetObject dll_PySys_SetObject
162071d4279SBram Moolenaar # define PySys_SetArgv dll_PySys_SetArgv
163071d4279SBram Moolenaar # define PyType_Type (*dll_PyType_Type)
164071d4279SBram Moolenaar # define Py_BuildValue dll_Py_BuildValue
165071d4279SBram Moolenaar # define Py_FindMethod dll_Py_FindMethod
166071d4279SBram Moolenaar # define Py_InitModule4 dll_Py_InitModule4
167071d4279SBram Moolenaar # define Py_Initialize dll_Py_Initialize
1680e21a3f6SBram Moolenaar # define Py_Finalize dll_Py_Finalize
1690e21a3f6SBram Moolenaar # define Py_IsInitialized dll_Py_IsInitialized
170071d4279SBram Moolenaar # define _PyObject_New dll__PyObject_New
171071d4279SBram Moolenaar # define _Py_NoneStruct (*dll__Py_NoneStruct)
172071d4279SBram Moolenaar # define PyObject_Init dll__PyObject_Init
173071d4279SBram Moolenaar # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02020000
174071d4279SBram Moolenaar #  define PyType_IsSubtype dll_PyType_IsSubtype
175071d4279SBram Moolenaar # endif
176071d4279SBram Moolenaar # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02030000
177071d4279SBram Moolenaar #  define PyObject_Malloc dll_PyObject_Malloc
178071d4279SBram Moolenaar #  define PyObject_Free dll_PyObject_Free
179071d4279SBram Moolenaar # endif
180071d4279SBram Moolenaar 
181071d4279SBram Moolenaar /*
182071d4279SBram Moolenaar  * Pointers for dynamic link
183071d4279SBram Moolenaar  */
184071d4279SBram Moolenaar static int(*dll_PyArg_Parse)(PyObject *, char *, ...);
185071d4279SBram Moolenaar static int(*dll_PyArg_ParseTuple)(PyObject *, char *, ...);
186071d4279SBram Moolenaar static int(*dll_PyDict_SetItemString)(PyObject *dp, char *key, PyObject *item);
187071d4279SBram Moolenaar static int(*dll_PyErr_BadArgument)(void);
188071d4279SBram Moolenaar static void(*dll_PyErr_Clear)(void);
189071d4279SBram Moolenaar static PyObject*(*dll_PyErr_NoMemory)(void);
190071d4279SBram Moolenaar static PyObject*(*dll_PyErr_Occurred)(void);
191071d4279SBram Moolenaar static void(*dll_PyErr_SetNone)(PyObject *);
192071d4279SBram Moolenaar static void(*dll_PyErr_SetString)(PyObject *, const char *);
193071d4279SBram Moolenaar static void(*dll_PyEval_InitThreads)(void);
194071d4279SBram Moolenaar static void(*dll_PyEval_RestoreThread)(PyThreadState *);
195071d4279SBram Moolenaar static PyThreadState*(*dll_PyEval_SaveThread)(void);
196071d4279SBram Moolenaar # ifdef PY_CAN_RECURSE
197071d4279SBram Moolenaar static PyGILState_STATE	(*dll_PyGILState_Ensure)(void);
198071d4279SBram Moolenaar static void (*dll_PyGILState_Release)(PyGILState_STATE);
199071d4279SBram Moolenaar #endif
200071d4279SBram Moolenaar static long(*dll_PyInt_AsLong)(PyObject *);
201071d4279SBram Moolenaar static PyObject*(*dll_PyInt_FromLong)(long);
202071d4279SBram Moolenaar static PyTypeObject* dll_PyInt_Type;
2032c45e945SBram Moolenaar static PyObject*(*dll_PyList_GetItem)(PyObject *, PyInt);
2040ac9379aSBram Moolenaar static PyObject*(*dll_PyList_Append)(PyObject *, PyObject *);
2052c45e945SBram Moolenaar static PyObject*(*dll_PyList_New)(PyInt size);
2062c45e945SBram Moolenaar static int(*dll_PyList_SetItem)(PyObject *, PyInt, PyObject *);
2072c45e945SBram Moolenaar static PyInt(*dll_PyList_Size)(PyObject *);
208071d4279SBram Moolenaar static PyTypeObject* dll_PyList_Type;
209071d4279SBram Moolenaar static PyObject*(*dll_PyImport_ImportModule)(const char *);
2100ac9379aSBram Moolenaar static PyObject*(*dll_PyDict_New)(void);
211071d4279SBram Moolenaar static PyObject*(*dll_PyDict_GetItemString)(PyObject *, const char *);
212071d4279SBram Moolenaar static PyObject*(*dll_PyModule_GetDict)(PyObject *);
213071d4279SBram Moolenaar static int(*dll_PyRun_SimpleString)(char *);
214071d4279SBram Moolenaar static char*(*dll_PyString_AsString)(PyObject *);
215071d4279SBram Moolenaar static PyObject*(*dll_PyString_FromString)(const char *);
2162c45e945SBram Moolenaar static PyObject*(*dll_PyString_FromStringAndSize)(const char *, PyInt);
2172c45e945SBram Moolenaar static PyInt(*dll_PyString_Size)(PyObject *);
218071d4279SBram Moolenaar static PyTypeObject* dll_PyString_Type;
219071d4279SBram Moolenaar static int(*dll_PySys_SetObject)(char *, PyObject *);
220071d4279SBram Moolenaar static int(*dll_PySys_SetArgv)(int, char **);
221071d4279SBram Moolenaar static PyTypeObject* dll_PyType_Type;
222071d4279SBram Moolenaar static PyObject*(*dll_Py_BuildValue)(char *, ...);
223071d4279SBram Moolenaar static PyObject*(*dll_Py_FindMethod)(struct PyMethodDef[], PyObject *, char *);
224071d4279SBram Moolenaar static PyObject*(*dll_Py_InitModule4)(char *, struct PyMethodDef *, char *, PyObject *, int);
225071d4279SBram Moolenaar static void(*dll_Py_Initialize)(void);
2260e21a3f6SBram Moolenaar static void(*dll_Py_Finalize)(void);
2270e21a3f6SBram Moolenaar static int(*dll_Py_IsInitialized)(void);
228071d4279SBram Moolenaar static PyObject*(*dll__PyObject_New)(PyTypeObject *, PyObject *);
229071d4279SBram Moolenaar static PyObject*(*dll__PyObject_Init)(PyObject *, PyTypeObject *);
230071d4279SBram Moolenaar static PyObject* dll__Py_NoneStruct;
231071d4279SBram Moolenaar # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02020000
232071d4279SBram Moolenaar static int (*dll_PyType_IsSubtype)(PyTypeObject *, PyTypeObject *);
233071d4279SBram Moolenaar # endif
234071d4279SBram Moolenaar # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02030000
235071d4279SBram Moolenaar static void* (*dll_PyObject_Malloc)(size_t);
236071d4279SBram Moolenaar static void (*dll_PyObject_Free)(void*);
237071d4279SBram Moolenaar # endif
238071d4279SBram Moolenaar 
239071d4279SBram Moolenaar static HINSTANCE hinstPython = 0; /* Instance of python.dll */
240071d4279SBram Moolenaar 
241071d4279SBram Moolenaar /* Imported exception objects */
242071d4279SBram Moolenaar static PyObject *imp_PyExc_AttributeError;
243071d4279SBram Moolenaar static PyObject *imp_PyExc_IndexError;
244071d4279SBram Moolenaar static PyObject *imp_PyExc_KeyboardInterrupt;
245071d4279SBram Moolenaar static PyObject *imp_PyExc_TypeError;
246071d4279SBram Moolenaar static PyObject *imp_PyExc_ValueError;
247071d4279SBram Moolenaar 
248071d4279SBram Moolenaar # define PyExc_AttributeError imp_PyExc_AttributeError
249071d4279SBram Moolenaar # define PyExc_IndexError imp_PyExc_IndexError
250071d4279SBram Moolenaar # define PyExc_KeyboardInterrupt imp_PyExc_KeyboardInterrupt
251071d4279SBram Moolenaar # define PyExc_TypeError imp_PyExc_TypeError
252071d4279SBram Moolenaar # define PyExc_ValueError imp_PyExc_ValueError
253071d4279SBram Moolenaar 
254071d4279SBram Moolenaar /*
255071d4279SBram Moolenaar  * Table of name to function pointer of python.
256071d4279SBram Moolenaar  */
257071d4279SBram Moolenaar # define PYTHON_PROC FARPROC
258071d4279SBram Moolenaar static struct
259071d4279SBram Moolenaar {
260071d4279SBram Moolenaar     char *name;
261071d4279SBram Moolenaar     PYTHON_PROC *ptr;
262071d4279SBram Moolenaar } python_funcname_table[] =
263071d4279SBram Moolenaar {
264071d4279SBram Moolenaar     {"PyArg_Parse", (PYTHON_PROC*)&dll_PyArg_Parse},
265071d4279SBram Moolenaar     {"PyArg_ParseTuple", (PYTHON_PROC*)&dll_PyArg_ParseTuple},
266071d4279SBram Moolenaar     {"PyDict_SetItemString", (PYTHON_PROC*)&dll_PyDict_SetItemString},
267071d4279SBram Moolenaar     {"PyErr_BadArgument", (PYTHON_PROC*)&dll_PyErr_BadArgument},
268071d4279SBram Moolenaar     {"PyErr_Clear", (PYTHON_PROC*)&dll_PyErr_Clear},
269071d4279SBram Moolenaar     {"PyErr_NoMemory", (PYTHON_PROC*)&dll_PyErr_NoMemory},
270071d4279SBram Moolenaar     {"PyErr_Occurred", (PYTHON_PROC*)&dll_PyErr_Occurred},
271071d4279SBram Moolenaar     {"PyErr_SetNone", (PYTHON_PROC*)&dll_PyErr_SetNone},
272071d4279SBram Moolenaar     {"PyErr_SetString", (PYTHON_PROC*)&dll_PyErr_SetString},
273071d4279SBram Moolenaar     {"PyEval_InitThreads", (PYTHON_PROC*)&dll_PyEval_InitThreads},
274071d4279SBram Moolenaar     {"PyEval_RestoreThread", (PYTHON_PROC*)&dll_PyEval_RestoreThread},
275071d4279SBram Moolenaar     {"PyEval_SaveThread", (PYTHON_PROC*)&dll_PyEval_SaveThread},
276071d4279SBram Moolenaar # ifdef PY_CAN_RECURSE
277071d4279SBram Moolenaar     {"PyGILState_Ensure", (PYTHON_PROC*)&dll_PyGILState_Ensure},
278071d4279SBram Moolenaar     {"PyGILState_Release", (PYTHON_PROC*)&dll_PyGILState_Release},
279071d4279SBram Moolenaar # endif
280071d4279SBram Moolenaar     {"PyInt_AsLong", (PYTHON_PROC*)&dll_PyInt_AsLong},
281071d4279SBram Moolenaar     {"PyInt_FromLong", (PYTHON_PROC*)&dll_PyInt_FromLong},
282071d4279SBram Moolenaar     {"PyInt_Type", (PYTHON_PROC*)&dll_PyInt_Type},
283071d4279SBram Moolenaar     {"PyList_GetItem", (PYTHON_PROC*)&dll_PyList_GetItem},
2840ac9379aSBram Moolenaar     {"PyList_Append", (PYTHON_PROC*)&dll_PyList_Append},
285071d4279SBram Moolenaar     {"PyList_New", (PYTHON_PROC*)&dll_PyList_New},
286071d4279SBram Moolenaar     {"PyList_SetItem", (PYTHON_PROC*)&dll_PyList_SetItem},
287071d4279SBram Moolenaar     {"PyList_Size", (PYTHON_PROC*)&dll_PyList_Size},
288071d4279SBram Moolenaar     {"PyList_Type", (PYTHON_PROC*)&dll_PyList_Type},
289071d4279SBram Moolenaar     {"PyImport_ImportModule", (PYTHON_PROC*)&dll_PyImport_ImportModule},
290071d4279SBram Moolenaar     {"PyDict_GetItemString", (PYTHON_PROC*)&dll_PyDict_GetItemString},
2910ac9379aSBram Moolenaar     {"PyDict_New", (PYTHON_PROC*)&dll_PyDict_New},
292071d4279SBram Moolenaar     {"PyModule_GetDict", (PYTHON_PROC*)&dll_PyModule_GetDict},
293071d4279SBram Moolenaar     {"PyRun_SimpleString", (PYTHON_PROC*)&dll_PyRun_SimpleString},
294071d4279SBram Moolenaar     {"PyString_AsString", (PYTHON_PROC*)&dll_PyString_AsString},
295071d4279SBram Moolenaar     {"PyString_FromString", (PYTHON_PROC*)&dll_PyString_FromString},
296071d4279SBram Moolenaar     {"PyString_FromStringAndSize", (PYTHON_PROC*)&dll_PyString_FromStringAndSize},
297071d4279SBram Moolenaar     {"PyString_Size", (PYTHON_PROC*)&dll_PyString_Size},
298071d4279SBram Moolenaar     {"PyString_Type", (PYTHON_PROC*)&dll_PyString_Type},
299071d4279SBram Moolenaar     {"PySys_SetObject", (PYTHON_PROC*)&dll_PySys_SetObject},
300071d4279SBram Moolenaar     {"PySys_SetArgv", (PYTHON_PROC*)&dll_PySys_SetArgv},
301071d4279SBram Moolenaar     {"PyType_Type", (PYTHON_PROC*)&dll_PyType_Type},
302071d4279SBram Moolenaar     {"Py_BuildValue", (PYTHON_PROC*)&dll_Py_BuildValue},
303071d4279SBram Moolenaar     {"Py_FindMethod", (PYTHON_PROC*)&dll_Py_FindMethod},
304e7cb9cf6SBram Moolenaar # if (PY_VERSION_HEX >= 0x02050000) && SIZEOF_SIZE_T != SIZEOF_INT
305e7cb9cf6SBram Moolenaar     {"Py_InitModule4_64", (PYTHON_PROC*)&dll_Py_InitModule4},
306e7cb9cf6SBram Moolenaar # else
307071d4279SBram Moolenaar     {"Py_InitModule4", (PYTHON_PROC*)&dll_Py_InitModule4},
308e7cb9cf6SBram Moolenaar # endif
309071d4279SBram Moolenaar     {"Py_Initialize", (PYTHON_PROC*)&dll_Py_Initialize},
3100e21a3f6SBram Moolenaar     {"Py_Finalize", (PYTHON_PROC*)&dll_Py_Finalize},
3110e21a3f6SBram Moolenaar     {"Py_IsInitialized", (PYTHON_PROC*)&dll_Py_IsInitialized},
312071d4279SBram Moolenaar     {"_PyObject_New", (PYTHON_PROC*)&dll__PyObject_New},
313071d4279SBram Moolenaar     {"PyObject_Init", (PYTHON_PROC*)&dll__PyObject_Init},
314071d4279SBram Moolenaar     {"_Py_NoneStruct", (PYTHON_PROC*)&dll__Py_NoneStruct},
315071d4279SBram Moolenaar # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02020000
316071d4279SBram Moolenaar     {"PyType_IsSubtype", (PYTHON_PROC*)&dll_PyType_IsSubtype},
317071d4279SBram Moolenaar # endif
318071d4279SBram Moolenaar # if defined(PY_VERSION_HEX) && PY_VERSION_HEX >= 0x02030000
319071d4279SBram Moolenaar     {"PyObject_Malloc", (PYTHON_PROC*)&dll_PyObject_Malloc},
320071d4279SBram Moolenaar     {"PyObject_Free", (PYTHON_PROC*)&dll_PyObject_Free},
321071d4279SBram Moolenaar # endif
322071d4279SBram Moolenaar     {"", NULL},
323071d4279SBram Moolenaar };
324071d4279SBram Moolenaar 
325071d4279SBram Moolenaar /*
326071d4279SBram Moolenaar  * Free python.dll
327071d4279SBram Moolenaar  */
328071d4279SBram Moolenaar     static void
329071d4279SBram Moolenaar end_dynamic_python(void)
330071d4279SBram Moolenaar {
331071d4279SBram Moolenaar     if (hinstPython)
332071d4279SBram Moolenaar     {
333bd5e15fdSBram Moolenaar 	close_dll(hinstPython);
334071d4279SBram Moolenaar 	hinstPython = 0;
335071d4279SBram Moolenaar     }
336071d4279SBram Moolenaar }
337071d4279SBram Moolenaar 
338071d4279SBram Moolenaar /*
339071d4279SBram Moolenaar  * Load library and get all pointers.
340071d4279SBram Moolenaar  * Parameter 'libname' provides name of DLL.
341071d4279SBram Moolenaar  * Return OK or FAIL.
342071d4279SBram Moolenaar  */
343071d4279SBram Moolenaar     static int
344071d4279SBram Moolenaar python_runtime_link_init(char *libname, int verbose)
345071d4279SBram Moolenaar {
346071d4279SBram Moolenaar     int i;
347071d4279SBram Moolenaar 
3484c3a326cSBram Moolenaar #if defined(UNIX) && defined(FEAT_PYTHON3)
3494c3a326cSBram Moolenaar     /* Can't have Python and Python3 loaded at the same time, it may cause a
3504c3a326cSBram Moolenaar      * crash. */
3514c3a326cSBram Moolenaar     if (python3_loaded())
3524c3a326cSBram Moolenaar     {
3534c3a326cSBram Moolenaar 	EMSG(_("E999: Python: Cannot use :py and :py3 in one session"));
3544c3a326cSBram Moolenaar 	return FAIL;
3554c3a326cSBram Moolenaar     }
3564c3a326cSBram Moolenaar #endif
3574c3a326cSBram Moolenaar 
358071d4279SBram Moolenaar     if (hinstPython)
359071d4279SBram Moolenaar 	return OK;
360bd5e15fdSBram Moolenaar     hinstPython = load_dll(libname);
361071d4279SBram Moolenaar     if (!hinstPython)
362071d4279SBram Moolenaar     {
363071d4279SBram Moolenaar 	if (verbose)
364071d4279SBram Moolenaar 	    EMSG2(_(e_loadlib), libname);
365071d4279SBram Moolenaar 	return FAIL;
366071d4279SBram Moolenaar     }
367071d4279SBram Moolenaar 
368071d4279SBram Moolenaar     for (i = 0; python_funcname_table[i].ptr; ++i)
369071d4279SBram Moolenaar     {
370bd5e15fdSBram Moolenaar 	if ((*python_funcname_table[i].ptr = symbol_from_dll(hinstPython,
371071d4279SBram Moolenaar 			python_funcname_table[i].name)) == NULL)
372071d4279SBram Moolenaar 	{
373bd5e15fdSBram Moolenaar 	    close_dll(hinstPython);
374071d4279SBram Moolenaar 	    hinstPython = 0;
375071d4279SBram Moolenaar 	    if (verbose)
376071d4279SBram Moolenaar 		EMSG2(_(e_loadfunc), python_funcname_table[i].name);
377071d4279SBram Moolenaar 	    return FAIL;
378071d4279SBram Moolenaar 	}
379071d4279SBram Moolenaar     }
380071d4279SBram Moolenaar     return OK;
381071d4279SBram Moolenaar }
382071d4279SBram Moolenaar 
383071d4279SBram Moolenaar /*
384071d4279SBram Moolenaar  * If python is enabled (there is installed python on Windows system) return
385071d4279SBram Moolenaar  * TRUE, else FALSE.
386071d4279SBram Moolenaar  */
387071d4279SBram Moolenaar     int
388e7cb9cf6SBram Moolenaar python_enabled(int verbose)
389071d4279SBram Moolenaar {
390071d4279SBram Moolenaar     return python_runtime_link_init(DYNAMIC_PYTHON_DLL, verbose) == OK;
391071d4279SBram Moolenaar }
392071d4279SBram Moolenaar 
393071d4279SBram Moolenaar /* Load the standard Python exceptions - don't import the symbols from the
394071d4279SBram Moolenaar  * DLL, as this can cause errors (importing data symbols is not reliable).
395071d4279SBram Moolenaar  */
396071d4279SBram Moolenaar static void get_exceptions __ARGS((void));
397071d4279SBram Moolenaar 
398071d4279SBram Moolenaar     static void
399071d4279SBram Moolenaar get_exceptions()
400071d4279SBram Moolenaar {
401071d4279SBram Moolenaar     PyObject *exmod = PyImport_ImportModule("exceptions");
402071d4279SBram Moolenaar     PyObject *exdict = PyModule_GetDict(exmod);
403071d4279SBram Moolenaar     imp_PyExc_AttributeError = PyDict_GetItemString(exdict, "AttributeError");
404071d4279SBram Moolenaar     imp_PyExc_IndexError = PyDict_GetItemString(exdict, "IndexError");
405071d4279SBram Moolenaar     imp_PyExc_KeyboardInterrupt = PyDict_GetItemString(exdict, "KeyboardInterrupt");
406071d4279SBram Moolenaar     imp_PyExc_TypeError = PyDict_GetItemString(exdict, "TypeError");
407071d4279SBram Moolenaar     imp_PyExc_ValueError = PyDict_GetItemString(exdict, "ValueError");
408071d4279SBram Moolenaar     Py_XINCREF(imp_PyExc_AttributeError);
409071d4279SBram Moolenaar     Py_XINCREF(imp_PyExc_IndexError);
410071d4279SBram Moolenaar     Py_XINCREF(imp_PyExc_KeyboardInterrupt);
411071d4279SBram Moolenaar     Py_XINCREF(imp_PyExc_TypeError);
412071d4279SBram Moolenaar     Py_XINCREF(imp_PyExc_ValueError);
413071d4279SBram Moolenaar     Py_XDECREF(exmod);
414071d4279SBram Moolenaar }
415071d4279SBram Moolenaar #endif /* DYNAMIC_PYTHON */
416071d4279SBram Moolenaar 
417*170bf1aeSBram Moolenaar /*
418*170bf1aeSBram Moolenaar  * Include the code shared with if_python3.c
419*170bf1aeSBram Moolenaar  */
420*170bf1aeSBram Moolenaar #include "if_py_both.h"
421*170bf1aeSBram Moolenaar 
422*170bf1aeSBram Moolenaar 
423071d4279SBram Moolenaar /******************************************************
424071d4279SBram Moolenaar  * Internal function prototypes.
425071d4279SBram Moolenaar  */
426071d4279SBram Moolenaar 
427071d4279SBram Moolenaar static void DoPythonCommand(exarg_T *, const char *);
428e7cb9cf6SBram Moolenaar static PyInt RangeStart;
429e7cb9cf6SBram Moolenaar static PyInt RangeEnd;
430071d4279SBram Moolenaar 
431071d4279SBram Moolenaar static void PythonIO_Flush(void);
432071d4279SBram Moolenaar static int PythonIO_Init(void);
433071d4279SBram Moolenaar static int PythonMod_Init(void);
434071d4279SBram Moolenaar 
435071d4279SBram Moolenaar /* Utility functions for the vim/python interface
436071d4279SBram Moolenaar  * ----------------------------------------------
437071d4279SBram Moolenaar  */
438e7cb9cf6SBram Moolenaar static PyObject *GetBufferLine(buf_T *, PyInt);
4392c45e945SBram Moolenaar static PyObject *GetBufferLineList(buf_T *, PyInt, PyInt);
440071d4279SBram Moolenaar 
441e7cb9cf6SBram Moolenaar static int SetBufferLine(buf_T *, PyInt, PyObject *, PyInt *);
442e7cb9cf6SBram Moolenaar static int SetBufferLineList(buf_T *, PyInt, PyInt, PyObject *, PyInt *);
443e7cb9cf6SBram Moolenaar static int InsertBufferLines(buf_T *, PyInt, PyObject *, PyInt *);
444071d4279SBram Moolenaar 
445071d4279SBram Moolenaar static PyObject *LineToString(const char *);
446071d4279SBram Moolenaar static char *StringToLine(PyObject *);
447071d4279SBram Moolenaar 
448071d4279SBram Moolenaar #define PyErr_SetVim(str) PyErr_SetString(VimError, str)
449071d4279SBram Moolenaar 
450071d4279SBram Moolenaar /******************************************************
451071d4279SBram Moolenaar  * 1. Python interpreter main program.
452071d4279SBram Moolenaar  */
453071d4279SBram Moolenaar 
454071d4279SBram Moolenaar static int initialised = 0;
455071d4279SBram Moolenaar 
456071d4279SBram Moolenaar #if PYTHON_API_VERSION < 1007 /* Python 1.4 */
457071d4279SBram Moolenaar typedef PyObject PyThreadState;
4589ba0eb85SBram Moolenaar #endif
459071d4279SBram Moolenaar 
4609ba0eb85SBram Moolenaar #ifdef PY_CAN_RECURSE
4619ba0eb85SBram Moolenaar static PyGILState_STATE pygilstate = PyGILState_UNLOCKED;
4629ba0eb85SBram Moolenaar #else
463071d4279SBram Moolenaar static PyThreadState *saved_python_thread = NULL;
4649ba0eb85SBram Moolenaar #endif
465071d4279SBram Moolenaar 
466071d4279SBram Moolenaar /*
467071d4279SBram Moolenaar  * Suspend a thread of the Python interpreter, other threads are allowed to
468071d4279SBram Moolenaar  * run.
469071d4279SBram Moolenaar  */
470293ee4d4SBram Moolenaar     static void
471293ee4d4SBram Moolenaar Python_SaveThread(void)
472071d4279SBram Moolenaar {
4739ba0eb85SBram Moolenaar #ifdef PY_CAN_RECURSE
4749ba0eb85SBram Moolenaar     PyGILState_Release(pygilstate);
4759ba0eb85SBram Moolenaar #else
476071d4279SBram Moolenaar     saved_python_thread = PyEval_SaveThread();
4779ba0eb85SBram Moolenaar #endif
478071d4279SBram Moolenaar }
479071d4279SBram Moolenaar 
480071d4279SBram Moolenaar /*
481071d4279SBram Moolenaar  * Restore a thread of the Python interpreter, waits for other threads to
482071d4279SBram Moolenaar  * block.
483071d4279SBram Moolenaar  */
484293ee4d4SBram Moolenaar     static void
485293ee4d4SBram Moolenaar Python_RestoreThread(void)
486071d4279SBram Moolenaar {
4879ba0eb85SBram Moolenaar #ifdef PY_CAN_RECURSE
4889ba0eb85SBram Moolenaar     pygilstate = PyGILState_Ensure();
4899ba0eb85SBram Moolenaar #else
490071d4279SBram Moolenaar     PyEval_RestoreThread(saved_python_thread);
491071d4279SBram Moolenaar     saved_python_thread = NULL;
492071d4279SBram Moolenaar #endif
4939ba0eb85SBram Moolenaar }
494071d4279SBram Moolenaar 
495071d4279SBram Moolenaar     void
496071d4279SBram Moolenaar python_end()
497071d4279SBram Moolenaar {
498a5792f58SBram Moolenaar     static int recurse = 0;
499a5792f58SBram Moolenaar 
500a5792f58SBram Moolenaar     /* If a crash occurs while doing this, don't try again. */
501a5792f58SBram Moolenaar     if (recurse != 0)
502a5792f58SBram Moolenaar 	return;
503a5792f58SBram Moolenaar 
504a5792f58SBram Moolenaar     ++recurse;
505a5792f58SBram Moolenaar 
506071d4279SBram Moolenaar #ifdef DYNAMIC_PYTHON
5070e21a3f6SBram Moolenaar     if (hinstPython && Py_IsInitialized())
5089ba0eb85SBram Moolenaar     {
5099ba0eb85SBram Moolenaar 	Python_RestoreThread();	    /* enter python */
5100e21a3f6SBram Moolenaar 	Py_Finalize();
5119ba0eb85SBram Moolenaar     }
512071d4279SBram Moolenaar     end_dynamic_python();
5130e21a3f6SBram Moolenaar #else
5140e21a3f6SBram Moolenaar     if (Py_IsInitialized())
5159ba0eb85SBram Moolenaar     {
5169ba0eb85SBram Moolenaar 	Python_RestoreThread();	    /* enter python */
5170e21a3f6SBram Moolenaar 	Py_Finalize();
5189ba0eb85SBram Moolenaar     }
519071d4279SBram Moolenaar #endif
520a5792f58SBram Moolenaar 
521a5792f58SBram Moolenaar     --recurse;
522071d4279SBram Moolenaar }
523071d4279SBram Moolenaar 
5244c3a326cSBram Moolenaar #if (defined(DYNAMIC_PYTHON) && defined(FEAT_PYTHON3)) || defined(PROTO)
5254c3a326cSBram Moolenaar     int
5264c3a326cSBram Moolenaar python_loaded()
5274c3a326cSBram Moolenaar {
5284c3a326cSBram Moolenaar     return (hinstPython != 0);
5294c3a326cSBram Moolenaar }
5304c3a326cSBram Moolenaar #endif
5314c3a326cSBram Moolenaar 
532071d4279SBram Moolenaar     static int
533071d4279SBram Moolenaar Python_Init(void)
534071d4279SBram Moolenaar {
535071d4279SBram Moolenaar     if (!initialised)
536071d4279SBram Moolenaar     {
537071d4279SBram Moolenaar #ifdef DYNAMIC_PYTHON
538071d4279SBram Moolenaar 	if (!python_enabled(TRUE))
539071d4279SBram Moolenaar 	{
540071d4279SBram Moolenaar 	    EMSG(_("E263: Sorry, this command is disabled, the Python library could not be loaded."));
541071d4279SBram Moolenaar 	    goto fail;
542071d4279SBram Moolenaar 	}
543071d4279SBram Moolenaar #endif
544071d4279SBram Moolenaar 
545*170bf1aeSBram Moolenaar 	init_structs();
546*170bf1aeSBram Moolenaar 
547071d4279SBram Moolenaar #if !defined(MACOS) || defined(MACOS_X_UNIX)
548071d4279SBram Moolenaar 	Py_Initialize();
549071d4279SBram Moolenaar #else
550071d4279SBram Moolenaar 	PyMac_Initialize();
551071d4279SBram Moolenaar #endif
552071d4279SBram Moolenaar 	/* initialise threads */
553071d4279SBram Moolenaar 	PyEval_InitThreads();
554071d4279SBram Moolenaar 
555071d4279SBram Moolenaar #ifdef DYNAMIC_PYTHON
556071d4279SBram Moolenaar 	get_exceptions();
557071d4279SBram Moolenaar #endif
558071d4279SBram Moolenaar 
559071d4279SBram Moolenaar 	if (PythonIO_Init())
560071d4279SBram Moolenaar 	    goto fail;
561071d4279SBram Moolenaar 
562071d4279SBram Moolenaar 	if (PythonMod_Init())
563071d4279SBram Moolenaar 	    goto fail;
564071d4279SBram Moolenaar 
5659774ecc8SBram Moolenaar 	/* Remove the element from sys.path that was added because of our
5669774ecc8SBram Moolenaar 	 * argv[0] value in PythonMod_Init().  Previously we used an empty
5679774ecc8SBram Moolenaar 	 * string, but dependinding on the OS we then get an empty entry or
5689774ecc8SBram Moolenaar 	 * the current directory in sys.path. */
5699774ecc8SBram Moolenaar 	PyRun_SimpleString("import sys; sys.path = filter(lambda x: x != '/must>not&exist', sys.path)");
5709774ecc8SBram Moolenaar 
571293ee4d4SBram Moolenaar 	/* the first python thread is vim's, release the lock */
572071d4279SBram Moolenaar 	Python_SaveThread();
573071d4279SBram Moolenaar 
574071d4279SBram Moolenaar 	initialised = 1;
575071d4279SBram Moolenaar     }
576071d4279SBram Moolenaar 
577071d4279SBram Moolenaar     return 0;
578071d4279SBram Moolenaar 
579071d4279SBram Moolenaar fail:
580071d4279SBram Moolenaar     /* We call PythonIO_Flush() here to print any Python errors.
581071d4279SBram Moolenaar      * This is OK, as it is possible to call this function even
582071d4279SBram Moolenaar      * if PythonIO_Init() has not completed successfully (it will
583071d4279SBram Moolenaar      * not do anything in this case).
584071d4279SBram Moolenaar      */
585071d4279SBram Moolenaar     PythonIO_Flush();
586071d4279SBram Moolenaar     return -1;
587071d4279SBram Moolenaar }
588071d4279SBram Moolenaar 
589071d4279SBram Moolenaar /*
590071d4279SBram Moolenaar  * External interface
591071d4279SBram Moolenaar  */
592071d4279SBram Moolenaar     static void
593071d4279SBram Moolenaar DoPythonCommand(exarg_T *eap, const char *cmd)
594071d4279SBram Moolenaar {
5959ba0eb85SBram Moolenaar #ifndef PY_CAN_RECURSE
596071d4279SBram Moolenaar     static int		recursive = 0;
597071d4279SBram Moolenaar #endif
598071d4279SBram Moolenaar #if defined(MACOS) && !defined(MACOS_X_UNIX)
599071d4279SBram Moolenaar     GrafPtr		oldPort;
600071d4279SBram Moolenaar #endif
601071d4279SBram Moolenaar #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
602071d4279SBram Moolenaar     char		*saved_locale;
603071d4279SBram Moolenaar #endif
604071d4279SBram Moolenaar 
605071d4279SBram Moolenaar #ifndef PY_CAN_RECURSE
606071d4279SBram Moolenaar     if (recursive)
607071d4279SBram Moolenaar     {
608071d4279SBram Moolenaar 	EMSG(_("E659: Cannot invoke Python recursively"));
609071d4279SBram Moolenaar 	return;
610071d4279SBram Moolenaar     }
611071d4279SBram Moolenaar     ++recursive;
612071d4279SBram Moolenaar #endif
613071d4279SBram Moolenaar 
614071d4279SBram Moolenaar #if defined(MACOS) && !defined(MACOS_X_UNIX)
615071d4279SBram Moolenaar     GetPort(&oldPort);
616071d4279SBram Moolenaar     /* Check if the Python library is available */
617071d4279SBram Moolenaar     if ((Ptr)PyMac_Initialize == (Ptr)kUnresolvedCFragSymbolAddress)
618071d4279SBram Moolenaar 	goto theend;
619071d4279SBram Moolenaar #endif
620071d4279SBram Moolenaar     if (Python_Init())
621071d4279SBram Moolenaar 	goto theend;
622071d4279SBram Moolenaar 
623071d4279SBram Moolenaar     RangeStart = eap->line1;
624071d4279SBram Moolenaar     RangeEnd = eap->line2;
625071d4279SBram Moolenaar     Python_Release_Vim();	    /* leave vim */
626071d4279SBram Moolenaar 
627071d4279SBram Moolenaar #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
628071d4279SBram Moolenaar     /* Python only works properly when the LC_NUMERIC locale is "C". */
629071d4279SBram Moolenaar     saved_locale = setlocale(LC_NUMERIC, NULL);
630071d4279SBram Moolenaar     if (saved_locale == NULL || STRCMP(saved_locale, "C") == 0)
631071d4279SBram Moolenaar 	saved_locale = NULL;
632071d4279SBram Moolenaar     else
633071d4279SBram Moolenaar     {
634071d4279SBram Moolenaar 	/* Need to make a copy, value may change when setting new locale. */
635071d4279SBram Moolenaar 	saved_locale = (char *)vim_strsave((char_u *)saved_locale);
636071d4279SBram Moolenaar 	(void)setlocale(LC_NUMERIC, "C");
637071d4279SBram Moolenaar     }
638071d4279SBram Moolenaar #endif
639071d4279SBram Moolenaar 
640071d4279SBram Moolenaar     Python_RestoreThread();	    /* enter python */
641071d4279SBram Moolenaar 
642071d4279SBram Moolenaar     PyRun_SimpleString((char *)(cmd));
643071d4279SBram Moolenaar 
644071d4279SBram Moolenaar     Python_SaveThread();	    /* leave python */
645071d4279SBram Moolenaar 
646071d4279SBram Moolenaar #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
647071d4279SBram Moolenaar     if (saved_locale != NULL)
648071d4279SBram Moolenaar     {
649071d4279SBram Moolenaar 	(void)setlocale(LC_NUMERIC, saved_locale);
650071d4279SBram Moolenaar 	vim_free(saved_locale);
651071d4279SBram Moolenaar     }
652071d4279SBram Moolenaar #endif
653071d4279SBram Moolenaar 
654071d4279SBram Moolenaar     Python_Lock_Vim();		    /* enter vim */
655071d4279SBram Moolenaar     PythonIO_Flush();
656071d4279SBram Moolenaar #if defined(MACOS) && !defined(MACOS_X_UNIX)
657071d4279SBram Moolenaar     SetPort(oldPort);
658071d4279SBram Moolenaar #endif
659071d4279SBram Moolenaar 
660071d4279SBram Moolenaar theend:
661071d4279SBram Moolenaar #ifndef PY_CAN_RECURSE
662071d4279SBram Moolenaar     --recursive;
663071d4279SBram Moolenaar #endif
664071d4279SBram Moolenaar     return;	    /* keeps lint happy */
665071d4279SBram Moolenaar }
666071d4279SBram Moolenaar 
667071d4279SBram Moolenaar /*
668071d4279SBram Moolenaar  * ":python"
669071d4279SBram Moolenaar  */
670071d4279SBram Moolenaar     void
671071d4279SBram Moolenaar ex_python(exarg_T *eap)
672071d4279SBram Moolenaar {
673071d4279SBram Moolenaar     char_u *script;
674071d4279SBram Moolenaar 
675071d4279SBram Moolenaar     script = script_get(eap, eap->arg);
676071d4279SBram Moolenaar     if (!eap->skip)
677071d4279SBram Moolenaar     {
678071d4279SBram Moolenaar 	if (script == NULL)
679071d4279SBram Moolenaar 	    DoPythonCommand(eap, (char *)eap->arg);
680071d4279SBram Moolenaar 	else
681071d4279SBram Moolenaar 	    DoPythonCommand(eap, (char *)script);
682071d4279SBram Moolenaar     }
683071d4279SBram Moolenaar     vim_free(script);
684071d4279SBram Moolenaar }
685071d4279SBram Moolenaar 
686071d4279SBram Moolenaar #define BUFFER_SIZE 1024
687071d4279SBram Moolenaar 
688071d4279SBram Moolenaar /*
689071d4279SBram Moolenaar  * ":pyfile"
690071d4279SBram Moolenaar  */
691071d4279SBram Moolenaar     void
692071d4279SBram Moolenaar ex_pyfile(exarg_T *eap)
693071d4279SBram Moolenaar {
694071d4279SBram Moolenaar     static char buffer[BUFFER_SIZE];
695071d4279SBram Moolenaar     const char *file = (char *)eap->arg;
696071d4279SBram Moolenaar     char *p;
697071d4279SBram Moolenaar 
698071d4279SBram Moolenaar     /* Have to do it like this. PyRun_SimpleFile requires you to pass a
699071d4279SBram Moolenaar      * stdio file pointer, but Vim and the Python DLL are compiled with
700071d4279SBram Moolenaar      * different options under Windows, meaning that stdio pointers aren't
701071d4279SBram Moolenaar      * compatible between the two. Yuk.
702071d4279SBram Moolenaar      *
703071d4279SBram Moolenaar      * Put the string "execfile('file')" into buffer. But, we need to
704071d4279SBram Moolenaar      * escape any backslashes or single quotes in the file name, so that
705071d4279SBram Moolenaar      * Python won't mangle the file name.
706071d4279SBram Moolenaar      */
707071d4279SBram Moolenaar     strcpy(buffer, "execfile('");
708071d4279SBram Moolenaar     p = buffer + 10; /* size of "execfile('" */
709071d4279SBram Moolenaar 
710071d4279SBram Moolenaar     while (*file && p < buffer + (BUFFER_SIZE - 3))
711071d4279SBram Moolenaar     {
712071d4279SBram Moolenaar 	if (*file == '\\' || *file == '\'')
713071d4279SBram Moolenaar 	    *p++ = '\\';
714071d4279SBram Moolenaar 	*p++ = *file++;
715071d4279SBram Moolenaar     }
716071d4279SBram Moolenaar 
717071d4279SBram Moolenaar     /* If we didn't finish the file name, we hit a buffer overflow */
718071d4279SBram Moolenaar     if (*file != '\0')
719071d4279SBram Moolenaar 	return;
720071d4279SBram Moolenaar 
721071d4279SBram Moolenaar     /* Put in the terminating "')" and a null */
722071d4279SBram Moolenaar     *p++ = '\'';
723071d4279SBram Moolenaar     *p++ = ')';
724071d4279SBram Moolenaar     *p++ = '\0';
725071d4279SBram Moolenaar 
726071d4279SBram Moolenaar     /* Execute the file */
727071d4279SBram Moolenaar     DoPythonCommand(eap, buffer);
728071d4279SBram Moolenaar }
729071d4279SBram Moolenaar 
730071d4279SBram Moolenaar /******************************************************
731071d4279SBram Moolenaar  * 2. Python output stream: writes output via [e]msg().
732071d4279SBram Moolenaar  */
733071d4279SBram Moolenaar 
734071d4279SBram Moolenaar /* Implementation functions
735071d4279SBram Moolenaar  */
736071d4279SBram Moolenaar 
737071d4279SBram Moolenaar static PyObject *OutputGetattr(PyObject *, char *);
738071d4279SBram Moolenaar static int OutputSetattr(PyObject *, char *, PyObject *);
739071d4279SBram Moolenaar 
740071d4279SBram Moolenaar /*************/
741071d4279SBram Moolenaar 
742071d4279SBram Moolenaar     static PyObject *
743071d4279SBram Moolenaar OutputGetattr(PyObject *self, char *name)
744071d4279SBram Moolenaar {
745071d4279SBram Moolenaar     if (strcmp(name, "softspace") == 0)
746071d4279SBram Moolenaar 	return PyInt_FromLong(((OutputObject *)(self))->softspace);
747071d4279SBram Moolenaar 
748071d4279SBram Moolenaar     return Py_FindMethod(OutputMethods, self, name);
749071d4279SBram Moolenaar }
750071d4279SBram Moolenaar 
751071d4279SBram Moolenaar     static int
752071d4279SBram Moolenaar OutputSetattr(PyObject *self, char *name, PyObject *val)
753071d4279SBram Moolenaar {
754071d4279SBram Moolenaar     if (val == NULL) {
755071d4279SBram Moolenaar 	PyErr_SetString(PyExc_AttributeError, _("can't delete OutputObject attributes"));
756071d4279SBram Moolenaar 	return -1;
757071d4279SBram Moolenaar     }
758071d4279SBram Moolenaar 
759071d4279SBram Moolenaar     if (strcmp(name, "softspace") == 0)
760071d4279SBram Moolenaar     {
761071d4279SBram Moolenaar 	if (!PyInt_Check(val)) {
762071d4279SBram Moolenaar 	    PyErr_SetString(PyExc_TypeError, _("softspace must be an integer"));
763071d4279SBram Moolenaar 	    return -1;
764071d4279SBram Moolenaar 	}
765071d4279SBram Moolenaar 
766071d4279SBram Moolenaar 	((OutputObject *)(self))->softspace = PyInt_AsLong(val);
767071d4279SBram Moolenaar 	return 0;
768071d4279SBram Moolenaar     }
769071d4279SBram Moolenaar 
770071d4279SBram Moolenaar     PyErr_SetString(PyExc_AttributeError, _("invalid attribute"));
771071d4279SBram Moolenaar     return -1;
772071d4279SBram Moolenaar }
773071d4279SBram Moolenaar 
774071d4279SBram Moolenaar /***************/
775071d4279SBram Moolenaar 
776071d4279SBram Moolenaar     static int
777071d4279SBram Moolenaar PythonIO_Init(void)
778071d4279SBram Moolenaar {
779071d4279SBram Moolenaar     /* Fixups... */
780071d4279SBram Moolenaar     OutputType.ob_type = &PyType_Type;
781071d4279SBram Moolenaar 
782*170bf1aeSBram Moolenaar     return PythonIO_Init_io();
783071d4279SBram Moolenaar }
784071d4279SBram Moolenaar 
785071d4279SBram Moolenaar /******************************************************
786071d4279SBram Moolenaar  * 3. Implementation of the Vim module for Python
787071d4279SBram Moolenaar  */
788071d4279SBram Moolenaar 
789071d4279SBram Moolenaar /* Vim module - Implementation functions
790071d4279SBram Moolenaar  * -------------------------------------
791071d4279SBram Moolenaar  */
792071d4279SBram Moolenaar 
793071d4279SBram Moolenaar static PyObject *VimCommand(PyObject *, PyObject *);
794071d4279SBram Moolenaar static PyObject *VimEval(PyObject *, PyObject *);
795071d4279SBram Moolenaar 
796071d4279SBram Moolenaar /* Window type - Implementation functions
797071d4279SBram Moolenaar  * --------------------------------------
798071d4279SBram Moolenaar  */
799071d4279SBram Moolenaar 
800071d4279SBram Moolenaar typedef struct
801071d4279SBram Moolenaar {
802071d4279SBram Moolenaar     PyObject_HEAD
803071d4279SBram Moolenaar     win_T	*win;
804071d4279SBram Moolenaar }
805071d4279SBram Moolenaar WindowObject;
806071d4279SBram Moolenaar 
807071d4279SBram Moolenaar #define INVALID_WINDOW_VALUE ((win_T *)(-1))
808071d4279SBram Moolenaar 
809071d4279SBram Moolenaar #define WindowType_Check(obj) ((obj)->ob_type == &WindowType)
810071d4279SBram Moolenaar 
811071d4279SBram Moolenaar static PyObject *WindowNew(win_T *);
812071d4279SBram Moolenaar 
813071d4279SBram Moolenaar static void WindowDestructor(PyObject *);
814071d4279SBram Moolenaar static PyObject *WindowGetattr(PyObject *, char *);
815071d4279SBram Moolenaar static int WindowSetattr(PyObject *, char *, PyObject *);
816071d4279SBram Moolenaar static PyObject *WindowRepr(PyObject *);
817071d4279SBram Moolenaar 
818071d4279SBram Moolenaar /* Buffer type - Implementation functions
819071d4279SBram Moolenaar  * --------------------------------------
820071d4279SBram Moolenaar  */
821071d4279SBram Moolenaar 
822071d4279SBram Moolenaar typedef struct
823071d4279SBram Moolenaar {
824071d4279SBram Moolenaar     PyObject_HEAD
825071d4279SBram Moolenaar     buf_T *buf;
826071d4279SBram Moolenaar }
827071d4279SBram Moolenaar BufferObject;
828071d4279SBram Moolenaar 
829071d4279SBram Moolenaar #define INVALID_BUFFER_VALUE ((buf_T *)(-1))
830071d4279SBram Moolenaar 
831071d4279SBram Moolenaar #define BufferType_Check(obj) ((obj)->ob_type == &BufferType)
832071d4279SBram Moolenaar 
833071d4279SBram Moolenaar static PyObject *BufferNew (buf_T *);
834071d4279SBram Moolenaar 
835071d4279SBram Moolenaar static void BufferDestructor(PyObject *);
836071d4279SBram Moolenaar static PyObject *BufferGetattr(PyObject *, char *);
837071d4279SBram Moolenaar static PyObject *BufferRepr(PyObject *);
838071d4279SBram Moolenaar 
8392c45e945SBram Moolenaar static PyInt BufferLength(PyObject *);
8402c45e945SBram Moolenaar static PyObject *BufferItem(PyObject *, PyInt);
8412c45e945SBram Moolenaar static PyObject *BufferSlice(PyObject *, PyInt, PyInt);
8422c45e945SBram Moolenaar static PyInt BufferAssItem(PyObject *, PyInt, PyObject *);
8432c45e945SBram Moolenaar static PyInt BufferAssSlice(PyObject *, PyInt, PyInt, PyObject *);
844071d4279SBram Moolenaar 
845071d4279SBram Moolenaar static PyObject *BufferAppend(PyObject *, PyObject *);
846071d4279SBram Moolenaar static PyObject *BufferMark(PyObject *, PyObject *);
847071d4279SBram Moolenaar static PyObject *BufferRange(PyObject *, PyObject *);
848071d4279SBram Moolenaar 
849071d4279SBram Moolenaar /* Line range type - Implementation functions
850071d4279SBram Moolenaar  * --------------------------------------
851071d4279SBram Moolenaar  */
852071d4279SBram Moolenaar 
853071d4279SBram Moolenaar typedef struct
854071d4279SBram Moolenaar {
855071d4279SBram Moolenaar     PyObject_HEAD
856071d4279SBram Moolenaar     BufferObject *buf;
857e7cb9cf6SBram Moolenaar     PyInt start;
858e7cb9cf6SBram Moolenaar     PyInt end;
859071d4279SBram Moolenaar }
860071d4279SBram Moolenaar RangeObject;
861071d4279SBram Moolenaar 
862071d4279SBram Moolenaar #define RangeType_Check(obj) ((obj)->ob_type == &RangeType)
863071d4279SBram Moolenaar 
864e7cb9cf6SBram Moolenaar static PyObject *RangeNew(buf_T *, PyInt, PyInt);
865071d4279SBram Moolenaar 
866071d4279SBram Moolenaar static void RangeDestructor(PyObject *);
867071d4279SBram Moolenaar static PyObject *RangeGetattr(PyObject *, char *);
868071d4279SBram Moolenaar static PyObject *RangeRepr(PyObject *);
869071d4279SBram Moolenaar 
8702c45e945SBram Moolenaar static PyInt RangeLength(PyObject *);
8712c45e945SBram Moolenaar static PyObject *RangeItem(PyObject *, PyInt);
8722c45e945SBram Moolenaar static PyObject *RangeSlice(PyObject *, PyInt, PyInt);
8732c45e945SBram Moolenaar static PyInt RangeAssItem(PyObject *, PyInt, PyObject *);
8742c45e945SBram Moolenaar static PyInt RangeAssSlice(PyObject *, PyInt, PyInt, PyObject *);
875071d4279SBram Moolenaar 
876071d4279SBram Moolenaar static PyObject *RangeAppend(PyObject *, PyObject *);
877071d4279SBram Moolenaar 
878071d4279SBram Moolenaar /* Window list type - Implementation functions
879071d4279SBram Moolenaar  * -------------------------------------------
880071d4279SBram Moolenaar  */
881071d4279SBram Moolenaar 
8822c45e945SBram Moolenaar static PyInt WinListLength(PyObject *);
8832c45e945SBram Moolenaar static PyObject *WinListItem(PyObject *, PyInt);
884071d4279SBram Moolenaar 
885071d4279SBram Moolenaar /* Buffer list type - Implementation functions
886071d4279SBram Moolenaar  * -------------------------------------------
887071d4279SBram Moolenaar  */
888071d4279SBram Moolenaar 
8892c45e945SBram Moolenaar static PyInt BufListLength(PyObject *);
8902c45e945SBram Moolenaar static PyObject *BufListItem(PyObject *, PyInt);
891071d4279SBram Moolenaar 
892071d4279SBram Moolenaar /* Current objects type - Implementation functions
893071d4279SBram Moolenaar  * -----------------------------------------------
894071d4279SBram Moolenaar  */
895071d4279SBram Moolenaar 
896071d4279SBram Moolenaar static PyObject *CurrentGetattr(PyObject *, char *);
897071d4279SBram Moolenaar static int CurrentSetattr(PyObject *, char *, PyObject *);
898071d4279SBram Moolenaar 
899071d4279SBram Moolenaar /* Vim module - Definitions
900071d4279SBram Moolenaar  */
901071d4279SBram Moolenaar 
902071d4279SBram Moolenaar static struct PyMethodDef VimMethods[] = {
903071d4279SBram Moolenaar     /* name,	     function,		calling,    documentation */
904e7cb9cf6SBram Moolenaar     {"command",	     VimCommand,	1,	    "Execute a Vim ex-mode command" },
905e7cb9cf6SBram Moolenaar     {"eval",	     VimEval,		1,	    "Evaluate an expression using Vim evaluator" },
906071d4279SBram Moolenaar     { NULL,	     NULL,		0,	    NULL }
907071d4279SBram Moolenaar };
908071d4279SBram Moolenaar 
909071d4279SBram Moolenaar /* Vim module - Implementation
910071d4279SBram Moolenaar  */
911071d4279SBram Moolenaar     static PyObject *
9124bdbbf70SBram Moolenaar VimCommand(PyObject *self UNUSED, PyObject *args)
913071d4279SBram Moolenaar {
914071d4279SBram Moolenaar     char *cmd;
915071d4279SBram Moolenaar     PyObject *result;
916071d4279SBram Moolenaar 
917071d4279SBram Moolenaar     if (!PyArg_ParseTuple(args, "s", &cmd))
918071d4279SBram Moolenaar 	return NULL;
919071d4279SBram Moolenaar 
920071d4279SBram Moolenaar     PyErr_Clear();
921071d4279SBram Moolenaar 
922071d4279SBram Moolenaar     Py_BEGIN_ALLOW_THREADS
923071d4279SBram Moolenaar     Python_Lock_Vim();
924071d4279SBram Moolenaar 
925071d4279SBram Moolenaar     do_cmdline_cmd((char_u *)cmd);
926071d4279SBram Moolenaar     update_screen(VALID);
927071d4279SBram Moolenaar 
928071d4279SBram Moolenaar     Python_Release_Vim();
929071d4279SBram Moolenaar     Py_END_ALLOW_THREADS
930071d4279SBram Moolenaar 
931071d4279SBram Moolenaar     if (VimErrorCheck())
932071d4279SBram Moolenaar 	result = NULL;
933071d4279SBram Moolenaar     else
934071d4279SBram Moolenaar 	result = Py_None;
935071d4279SBram Moolenaar 
936071d4279SBram Moolenaar     Py_XINCREF(result);
937071d4279SBram Moolenaar     return result;
938071d4279SBram Moolenaar }
939071d4279SBram Moolenaar 
94001dd60cbSBram Moolenaar #ifdef FEAT_EVAL
941b71eaaeaSBram Moolenaar /*
942b71eaaeaSBram Moolenaar  * Function to translate a typval_T into a PyObject; this will recursively
943b71eaaeaSBram Moolenaar  * translate lists/dictionaries into their Python equivalents.
944b71eaaeaSBram Moolenaar  *
945e7cb9cf6SBram Moolenaar  * The depth parameter is to avoid infinite recursion, set it to 1 when
946b71eaaeaSBram Moolenaar  * you call VimToPython.
947b71eaaeaSBram Moolenaar  */
948b71eaaeaSBram Moolenaar     static PyObject *
949b71eaaeaSBram Moolenaar VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
950b71eaaeaSBram Moolenaar {
951b71eaaeaSBram Moolenaar     PyObject	*result;
952b71eaaeaSBram Moolenaar     PyObject	*newObj;
953b71eaaeaSBram Moolenaar     char	ptrBuf[NUMBUFLEN];
954b71eaaeaSBram Moolenaar 
955b71eaaeaSBram Moolenaar     /* Avoid infinite recursion */
956b71eaaeaSBram Moolenaar     if (depth > 100)
957b71eaaeaSBram Moolenaar     {
958b71eaaeaSBram Moolenaar 	Py_INCREF(Py_None);
959b71eaaeaSBram Moolenaar 	result = Py_None;
960b71eaaeaSBram Moolenaar 	return result;
961b71eaaeaSBram Moolenaar     }
962b71eaaeaSBram Moolenaar 
963b71eaaeaSBram Moolenaar     /* Check if we run into a recursive loop.  The item must be in lookupDict
964b71eaaeaSBram Moolenaar      * then and we can use it again. */
965d72b386aSBram Moolenaar     if ((our_tv->v_type == VAR_LIST && our_tv->vval.v_list != NULL)
966d72b386aSBram Moolenaar 	    || (our_tv->v_type == VAR_DICT && our_tv->vval.v_dict != NULL))
967d72b386aSBram Moolenaar     {
968d72b386aSBram Moolenaar 	sprintf(ptrBuf, PRINTF_DECIMAL_LONG_U,
969d72b386aSBram Moolenaar 		our_tv->v_type == VAR_LIST ? (long_u)our_tv->vval.v_list
970d72b386aSBram Moolenaar 					   : (long_u)our_tv->vval.v_dict);
971b71eaaeaSBram Moolenaar 	result = PyDict_GetItemString(lookupDict, ptrBuf);
972b71eaaeaSBram Moolenaar 	if (result != NULL)
973d72b386aSBram Moolenaar 	{
974b71eaaeaSBram Moolenaar 	    Py_INCREF(result);
975d72b386aSBram Moolenaar 	    return result;
976d72b386aSBram Moolenaar 	}
977d72b386aSBram Moolenaar     }
978d72b386aSBram Moolenaar 
979d72b386aSBram Moolenaar     if (our_tv->v_type == VAR_STRING)
980b71eaaeaSBram Moolenaar     {
981b71eaaeaSBram Moolenaar 	result = Py_BuildValue("s", our_tv->vval.v_string);
982b71eaaeaSBram Moolenaar     }
983b71eaaeaSBram Moolenaar     else if (our_tv->v_type == VAR_NUMBER)
984b71eaaeaSBram Moolenaar     {
985b71eaaeaSBram Moolenaar 	char buf[NUMBUFLEN];
986b71eaaeaSBram Moolenaar 
987b71eaaeaSBram Moolenaar 	/* For backwards compatibility numbers are stored as strings. */
988b71eaaeaSBram Moolenaar 	sprintf(buf, "%ld", (long)our_tv->vval.v_number);
989b71eaaeaSBram Moolenaar 	result = Py_BuildValue("s", buf);
990b71eaaeaSBram Moolenaar     }
9912c45e945SBram Moolenaar # ifdef FEAT_FLOAT
9922c45e945SBram Moolenaar     else if (our_tv->v_type == VAR_FLOAT)
9932c45e945SBram Moolenaar     {
9942c45e945SBram Moolenaar 	char buf[NUMBUFLEN];
9952c45e945SBram Moolenaar 
9962c45e945SBram Moolenaar 	sprintf(buf, "%f", our_tv->vval.v_float);
9972c45e945SBram Moolenaar 	result = Py_BuildValue("s", buf);
9982c45e945SBram Moolenaar     }
9992c45e945SBram Moolenaar # endif
1000b71eaaeaSBram Moolenaar     else if (our_tv->v_type == VAR_LIST)
1001b71eaaeaSBram Moolenaar     {
1002b71eaaeaSBram Moolenaar 	list_T		*list = our_tv->vval.v_list;
1003b71eaaeaSBram Moolenaar 	listitem_T	*curr;
1004b71eaaeaSBram Moolenaar 
1005b71eaaeaSBram Moolenaar 	result = PyList_New(0);
1006b71eaaeaSBram Moolenaar 
1007b71eaaeaSBram Moolenaar 	if (list != NULL)
1008b71eaaeaSBram Moolenaar 	{
1009d72b386aSBram Moolenaar 	    PyDict_SetItemString(lookupDict, ptrBuf, result);
1010d72b386aSBram Moolenaar 
1011b71eaaeaSBram Moolenaar 	    for (curr = list->lv_first; curr != NULL; curr = curr->li_next)
1012b71eaaeaSBram Moolenaar 	    {
1013b71eaaeaSBram Moolenaar 		newObj = VimToPython(&curr->li_tv, depth + 1, lookupDict);
1014b71eaaeaSBram Moolenaar 		PyList_Append(result, newObj);
1015b71eaaeaSBram Moolenaar 		Py_DECREF(newObj);
1016b71eaaeaSBram Moolenaar 	    }
1017b71eaaeaSBram Moolenaar 	}
1018b71eaaeaSBram Moolenaar     }
1019b71eaaeaSBram Moolenaar     else if (our_tv->v_type == VAR_DICT)
1020b71eaaeaSBram Moolenaar     {
1021b71eaaeaSBram Moolenaar 	result = PyDict_New();
1022b71eaaeaSBram Moolenaar 
1023b71eaaeaSBram Moolenaar 	if (our_tv->vval.v_dict != NULL)
1024b71eaaeaSBram Moolenaar 	{
1025b71eaaeaSBram Moolenaar 	    hashtab_T	*ht = &our_tv->vval.v_dict->dv_hashtab;
1026e7cb9cf6SBram Moolenaar 	    long_u	todo = ht->ht_used;
1027b71eaaeaSBram Moolenaar 	    hashitem_T	*hi;
1028b71eaaeaSBram Moolenaar 	    dictitem_T	*di;
1029b71eaaeaSBram Moolenaar 
1030d72b386aSBram Moolenaar 	    PyDict_SetItemString(lookupDict, ptrBuf, result);
1031d72b386aSBram Moolenaar 
1032b71eaaeaSBram Moolenaar 	    for (hi = ht->ht_array; todo > 0; ++hi)
1033b71eaaeaSBram Moolenaar 	    {
1034b71eaaeaSBram Moolenaar 		if (!HASHITEM_EMPTY(hi))
1035b71eaaeaSBram Moolenaar 		{
1036b71eaaeaSBram Moolenaar 		    --todo;
1037b71eaaeaSBram Moolenaar 
1038b71eaaeaSBram Moolenaar 		    di = dict_lookup(hi);
1039b71eaaeaSBram Moolenaar 		    newObj = VimToPython(&di->di_tv, depth + 1, lookupDict);
1040b71eaaeaSBram Moolenaar 		    PyDict_SetItemString(result, (char *)hi->hi_key, newObj);
1041b71eaaeaSBram Moolenaar 		    Py_DECREF(newObj);
1042b71eaaeaSBram Moolenaar 		}
1043b71eaaeaSBram Moolenaar 	    }
1044b71eaaeaSBram Moolenaar 	}
1045b71eaaeaSBram Moolenaar     }
1046b71eaaeaSBram Moolenaar     else
1047b71eaaeaSBram Moolenaar     {
1048b71eaaeaSBram Moolenaar 	Py_INCREF(Py_None);
1049b71eaaeaSBram Moolenaar 	result = Py_None;
1050b71eaaeaSBram Moolenaar     }
1051b71eaaeaSBram Moolenaar 
1052b71eaaeaSBram Moolenaar     return result;
1053b71eaaeaSBram Moolenaar }
105401dd60cbSBram Moolenaar #endif
1055b71eaaeaSBram Moolenaar 
1056071d4279SBram Moolenaar     static PyObject *
10574bdbbf70SBram Moolenaar VimEval(PyObject *self UNUSED, PyObject *args)
1058071d4279SBram Moolenaar {
1059071d4279SBram Moolenaar #ifdef FEAT_EVAL
1060071d4279SBram Moolenaar     char	*expr;
1061b71eaaeaSBram Moolenaar     typval_T	*our_tv;
1062071d4279SBram Moolenaar     PyObject	*result;
1063b71eaaeaSBram Moolenaar     PyObject    *lookup_dict;
1064071d4279SBram Moolenaar 
1065071d4279SBram Moolenaar     if (!PyArg_ParseTuple(args, "s", &expr))
1066071d4279SBram Moolenaar 	return NULL;
1067071d4279SBram Moolenaar 
1068071d4279SBram Moolenaar     Py_BEGIN_ALLOW_THREADS
1069071d4279SBram Moolenaar     Python_Lock_Vim();
1070b71eaaeaSBram Moolenaar     our_tv = eval_expr((char_u *)expr, NULL);
1071b71eaaeaSBram Moolenaar 
1072071d4279SBram Moolenaar     Python_Release_Vim();
1073071d4279SBram Moolenaar     Py_END_ALLOW_THREADS
1074071d4279SBram Moolenaar 
1075b71eaaeaSBram Moolenaar     if (our_tv == NULL)
1076071d4279SBram Moolenaar     {
1077071d4279SBram Moolenaar 	PyErr_SetVim(_("invalid expression"));
1078071d4279SBram Moolenaar 	return NULL;
1079071d4279SBram Moolenaar     }
1080071d4279SBram Moolenaar 
1081b71eaaeaSBram Moolenaar     /* Convert the Vim type into a Python type.  Create a dictionary that's
1082b71eaaeaSBram Moolenaar      * used to check for recursive loops. */
1083b71eaaeaSBram Moolenaar     lookup_dict = PyDict_New();
1084b71eaaeaSBram Moolenaar     result = VimToPython(our_tv, 1, lookup_dict);
1085b71eaaeaSBram Moolenaar     Py_DECREF(lookup_dict);
1086b71eaaeaSBram Moolenaar 
1087071d4279SBram Moolenaar 
1088071d4279SBram Moolenaar     Py_BEGIN_ALLOW_THREADS
1089071d4279SBram Moolenaar     Python_Lock_Vim();
1090b71eaaeaSBram Moolenaar     free_tv(our_tv);
1091071d4279SBram Moolenaar     Python_Release_Vim();
1092071d4279SBram Moolenaar     Py_END_ALLOW_THREADS
1093071d4279SBram Moolenaar 
1094071d4279SBram Moolenaar     return result;
1095071d4279SBram Moolenaar #else
1096071d4279SBram Moolenaar     PyErr_SetVim(_("expressions disabled at compile time"));
1097071d4279SBram Moolenaar     return NULL;
1098071d4279SBram Moolenaar #endif
1099071d4279SBram Moolenaar }
1100071d4279SBram Moolenaar 
1101071d4279SBram Moolenaar /* Common routines for buffers and line ranges
1102071d4279SBram Moolenaar  * -------------------------------------------
1103071d4279SBram Moolenaar  */
1104*170bf1aeSBram Moolenaar 
1105071d4279SBram Moolenaar     static int
1106071d4279SBram Moolenaar CheckBuffer(BufferObject *this)
1107071d4279SBram Moolenaar {
1108071d4279SBram Moolenaar     if (this->buf == INVALID_BUFFER_VALUE)
1109071d4279SBram Moolenaar     {
1110071d4279SBram Moolenaar 	PyErr_SetVim(_("attempt to refer to deleted buffer"));
1111071d4279SBram Moolenaar 	return -1;
1112071d4279SBram Moolenaar     }
1113071d4279SBram Moolenaar 
1114071d4279SBram Moolenaar     return 0;
1115071d4279SBram Moolenaar }
1116071d4279SBram Moolenaar 
1117071d4279SBram Moolenaar     static PyObject *
1118e7cb9cf6SBram Moolenaar RBItem(BufferObject *self, PyInt n, PyInt start, PyInt end)
1119071d4279SBram Moolenaar {
1120071d4279SBram Moolenaar     if (CheckBuffer(self))
1121071d4279SBram Moolenaar 	return NULL;
1122071d4279SBram Moolenaar 
1123071d4279SBram Moolenaar     if (n < 0 || n > end - start)
1124071d4279SBram Moolenaar     {
1125071d4279SBram Moolenaar 	PyErr_SetString(PyExc_IndexError, _("line number out of range"));
1126071d4279SBram Moolenaar 	return NULL;
1127071d4279SBram Moolenaar     }
1128071d4279SBram Moolenaar 
1129071d4279SBram Moolenaar     return GetBufferLine(self->buf, n+start);
1130071d4279SBram Moolenaar }
1131071d4279SBram Moolenaar 
1132071d4279SBram Moolenaar     static PyObject *
1133e7cb9cf6SBram Moolenaar RBSlice(BufferObject *self, PyInt lo, PyInt hi, PyInt start, PyInt end)
1134071d4279SBram Moolenaar {
11352c45e945SBram Moolenaar     PyInt size;
1136071d4279SBram Moolenaar 
1137071d4279SBram Moolenaar     if (CheckBuffer(self))
1138071d4279SBram Moolenaar 	return NULL;
1139071d4279SBram Moolenaar 
1140071d4279SBram Moolenaar     size = end - start + 1;
1141071d4279SBram Moolenaar 
1142071d4279SBram Moolenaar     if (lo < 0)
1143071d4279SBram Moolenaar 	lo = 0;
1144071d4279SBram Moolenaar     else if (lo > size)
1145071d4279SBram Moolenaar 	lo = size;
1146071d4279SBram Moolenaar     if (hi < 0)
1147071d4279SBram Moolenaar 	hi = 0;
1148071d4279SBram Moolenaar     if (hi < lo)
1149071d4279SBram Moolenaar 	hi = lo;
1150071d4279SBram Moolenaar     else if (hi > size)
1151071d4279SBram Moolenaar 	hi = size;
1152071d4279SBram Moolenaar 
1153071d4279SBram Moolenaar     return GetBufferLineList(self->buf, lo+start, hi+start);
1154071d4279SBram Moolenaar }
1155071d4279SBram Moolenaar 
11562c45e945SBram Moolenaar     static PyInt
1157e7cb9cf6SBram Moolenaar RBAssItem(BufferObject *self, PyInt n, PyObject *val, PyInt start, PyInt end, PyInt *new_end)
1158071d4279SBram Moolenaar {
1159e7cb9cf6SBram Moolenaar     PyInt len_change;
1160071d4279SBram Moolenaar 
1161071d4279SBram Moolenaar     if (CheckBuffer(self))
1162071d4279SBram Moolenaar 	return -1;
1163071d4279SBram Moolenaar 
1164071d4279SBram Moolenaar     if (n < 0 || n > end - start)
1165071d4279SBram Moolenaar     {
1166071d4279SBram Moolenaar 	PyErr_SetString(PyExc_IndexError, _("line number out of range"));
1167071d4279SBram Moolenaar 	return -1;
1168071d4279SBram Moolenaar     }
1169071d4279SBram Moolenaar 
1170071d4279SBram Moolenaar     if (SetBufferLine(self->buf, n+start, val, &len_change) == FAIL)
1171071d4279SBram Moolenaar 	return -1;
1172071d4279SBram Moolenaar 
1173071d4279SBram Moolenaar     if (new_end)
1174071d4279SBram Moolenaar 	*new_end = end + len_change;
1175071d4279SBram Moolenaar 
1176071d4279SBram Moolenaar     return 0;
1177071d4279SBram Moolenaar }
1178071d4279SBram Moolenaar 
11792c45e945SBram Moolenaar     static PyInt
1180e7cb9cf6SBram Moolenaar RBAssSlice(BufferObject *self, PyInt lo, PyInt hi, PyObject *val, PyInt start, PyInt end, PyInt *new_end)
1181071d4279SBram Moolenaar {
1182e7cb9cf6SBram Moolenaar     PyInt size;
1183e7cb9cf6SBram Moolenaar     PyInt len_change;
1184071d4279SBram Moolenaar 
1185071d4279SBram Moolenaar     /* Self must be a valid buffer */
1186071d4279SBram Moolenaar     if (CheckBuffer(self))
1187071d4279SBram Moolenaar 	return -1;
1188071d4279SBram Moolenaar 
1189071d4279SBram Moolenaar     /* Sort out the slice range */
1190071d4279SBram Moolenaar     size = end - start + 1;
1191071d4279SBram Moolenaar 
1192071d4279SBram Moolenaar     if (lo < 0)
1193071d4279SBram Moolenaar 	lo = 0;
1194071d4279SBram Moolenaar     else if (lo > size)
1195071d4279SBram Moolenaar 	lo = size;
1196071d4279SBram Moolenaar     if (hi < 0)
1197071d4279SBram Moolenaar 	hi = 0;
1198071d4279SBram Moolenaar     if (hi < lo)
1199071d4279SBram Moolenaar 	hi = lo;
1200071d4279SBram Moolenaar     else if (hi > size)
1201071d4279SBram Moolenaar 	hi = size;
1202071d4279SBram Moolenaar 
1203071d4279SBram Moolenaar     if (SetBufferLineList(self->buf, lo+start, hi+start, val, &len_change) == FAIL)
1204071d4279SBram Moolenaar 	return -1;
1205071d4279SBram Moolenaar 
1206071d4279SBram Moolenaar     if (new_end)
1207071d4279SBram Moolenaar 	*new_end = end + len_change;
1208071d4279SBram Moolenaar 
1209071d4279SBram Moolenaar     return 0;
1210071d4279SBram Moolenaar }
1211071d4279SBram Moolenaar 
1212071d4279SBram Moolenaar     static PyObject *
1213e7cb9cf6SBram Moolenaar RBAppend(BufferObject *self, PyObject *args, PyInt start, PyInt end, PyInt *new_end)
1214071d4279SBram Moolenaar {
1215071d4279SBram Moolenaar     PyObject *lines;
1216e7cb9cf6SBram Moolenaar     PyInt len_change;
1217e7cb9cf6SBram Moolenaar     PyInt max;
1218e7cb9cf6SBram Moolenaar     PyInt n;
1219071d4279SBram Moolenaar 
1220071d4279SBram Moolenaar     if (CheckBuffer(self))
1221071d4279SBram Moolenaar 	return NULL;
1222071d4279SBram Moolenaar 
1223071d4279SBram Moolenaar     max = n = end - start + 1;
1224071d4279SBram Moolenaar 
1225e7cb9cf6SBram Moolenaar     if (!PyArg_ParseTuple(args, "O|" Py_ssize_t_fmt, &lines, &n))
1226071d4279SBram Moolenaar 	return NULL;
1227071d4279SBram Moolenaar 
1228071d4279SBram Moolenaar     if (n < 0 || n > max)
1229071d4279SBram Moolenaar     {
1230071d4279SBram Moolenaar 	PyErr_SetString(PyExc_ValueError, _("line number out of range"));
1231071d4279SBram Moolenaar 	return NULL;
1232071d4279SBram Moolenaar     }
1233071d4279SBram Moolenaar 
1234071d4279SBram Moolenaar     if (InsertBufferLines(self->buf, n + start - 1, lines, &len_change) == FAIL)
1235071d4279SBram Moolenaar 	return NULL;
1236071d4279SBram Moolenaar 
1237071d4279SBram Moolenaar     if (new_end)
1238071d4279SBram Moolenaar 	*new_end = end + len_change;
1239071d4279SBram Moolenaar 
1240071d4279SBram Moolenaar     Py_INCREF(Py_None);
1241071d4279SBram Moolenaar     return Py_None;
1242071d4279SBram Moolenaar }
1243071d4279SBram Moolenaar 
1244071d4279SBram Moolenaar 
1245071d4279SBram Moolenaar /* Buffer object - Definitions
1246071d4279SBram Moolenaar  */
1247071d4279SBram Moolenaar 
1248071d4279SBram Moolenaar static struct PyMethodDef BufferMethods[] = {
1249071d4279SBram Moolenaar     /* name,	    function,		calling,    documentation */
1250e7cb9cf6SBram Moolenaar     {"append",	    BufferAppend,	1,	    "Append data to Vim buffer" },
1251e7cb9cf6SBram Moolenaar     {"mark",	    BufferMark,		1,	    "Return (row,col) representing position of named mark" },
1252e7cb9cf6SBram Moolenaar     {"range",	    BufferRange,	1,	    "Return a range object which represents the part of the given buffer between line numbers s and e" },
1253071d4279SBram Moolenaar     { NULL,	    NULL,		0,	    NULL }
1254071d4279SBram Moolenaar };
1255071d4279SBram Moolenaar 
1256071d4279SBram Moolenaar static PySequenceMethods BufferAsSeq = {
12572c45e945SBram Moolenaar     (PyInquiry)		BufferLength,	    /* sq_length,    len(x)   */
1258071d4279SBram Moolenaar     (binaryfunc)	0, /* BufferConcat, */	     /* sq_concat,    x+y      */
12592c45e945SBram Moolenaar     (PyIntArgFunc)	0, /* BufferRepeat, */	     /* sq_repeat,    x*n      */
12602c45e945SBram Moolenaar     (PyIntArgFunc)	BufferItem,	    /* sq_item,      x[i]     */
12612c45e945SBram Moolenaar     (PyIntIntArgFunc)	BufferSlice,	    /* sq_slice,     x[i:j]   */
12622c45e945SBram Moolenaar     (PyIntObjArgProc)	BufferAssItem,	    /* sq_ass_item,  x[i]=v   */
12632c45e945SBram Moolenaar     (PyIntIntObjArgProc)	BufferAssSlice,     /* sq_ass_slice, x[i:j]=v */
1264071d4279SBram Moolenaar };
1265071d4279SBram Moolenaar 
1266071d4279SBram Moolenaar static PyTypeObject BufferType = {
1267071d4279SBram Moolenaar     PyObject_HEAD_INIT(0)
1268071d4279SBram Moolenaar     0,
1269071d4279SBram Moolenaar     "buffer",
1270071d4279SBram Moolenaar     sizeof(BufferObject),
1271071d4279SBram Moolenaar     0,
1272071d4279SBram Moolenaar 
1273071d4279SBram Moolenaar     (destructor)    BufferDestructor,	/* tp_dealloc,	refcount==0  */
1274071d4279SBram Moolenaar     (printfunc)     0,			/* tp_print,	print x      */
1275071d4279SBram Moolenaar     (getattrfunc)   BufferGetattr,	/* tp_getattr,	x.attr	     */
1276071d4279SBram Moolenaar     (setattrfunc)   0,			/* tp_setattr,	x.attr=v     */
1277071d4279SBram Moolenaar     (cmpfunc)	    0,			/* tp_compare,	x>y	     */
1278071d4279SBram Moolenaar     (reprfunc)	    BufferRepr,		/* tp_repr,	`x`, print x */
1279071d4279SBram Moolenaar 
1280071d4279SBram Moolenaar     0,		    /* as number */
1281071d4279SBram Moolenaar     &BufferAsSeq,   /* as sequence */
1282071d4279SBram Moolenaar     0,		    /* as mapping */
1283071d4279SBram Moolenaar 
1284071d4279SBram Moolenaar     (hashfunc) 0,			/* tp_hash, dict(x) */
1285071d4279SBram Moolenaar     (ternaryfunc) 0,			/* tp_call, x()     */
1286071d4279SBram Moolenaar     (reprfunc) 0,			/* tp_str,  str(x)  */
1287071d4279SBram Moolenaar };
1288071d4279SBram Moolenaar 
1289071d4279SBram Moolenaar /* Buffer object - Implementation
1290071d4279SBram Moolenaar  */
1291071d4279SBram Moolenaar 
1292071d4279SBram Moolenaar     static PyObject *
1293071d4279SBram Moolenaar BufferNew(buf_T *buf)
1294071d4279SBram Moolenaar {
1295071d4279SBram Moolenaar     /* We need to handle deletion of buffers underneath us.
1296e344beadSBram Moolenaar      * If we add a "b_python_ref" field to the buf_T structure,
1297071d4279SBram Moolenaar      * then we can get at it in buf_freeall() in vim. We then
1298071d4279SBram Moolenaar      * need to create only ONE Python object per buffer - if
1299071d4279SBram Moolenaar      * we try to create a second, just INCREF the existing one
1300071d4279SBram Moolenaar      * and return it. The (single) Python object referring to
1301e344beadSBram Moolenaar      * the buffer is stored in "b_python_ref".
1302071d4279SBram Moolenaar      * Question: what to do on a buf_freeall(). We'll probably
1303071d4279SBram Moolenaar      * have to either delete the Python object (DECREF it to
1304071d4279SBram Moolenaar      * zero - a bad idea, as it leaves dangling refs!) or
1305071d4279SBram Moolenaar      * set the buf_T * value to an invalid value (-1?), which
1306071d4279SBram Moolenaar      * means we need checks in all access functions... Bah.
1307071d4279SBram Moolenaar      */
1308071d4279SBram Moolenaar 
1309071d4279SBram Moolenaar     BufferObject *self;
1310071d4279SBram Moolenaar 
1311e344beadSBram Moolenaar     if (buf->b_python_ref != NULL)
1312071d4279SBram Moolenaar     {
1313e344beadSBram Moolenaar 	self = buf->b_python_ref;
1314071d4279SBram Moolenaar 	Py_INCREF(self);
1315071d4279SBram Moolenaar     }
1316071d4279SBram Moolenaar     else
1317071d4279SBram Moolenaar     {
1318071d4279SBram Moolenaar 	self = PyObject_NEW(BufferObject, &BufferType);
1319071d4279SBram Moolenaar 	if (self == NULL)
1320071d4279SBram Moolenaar 	    return NULL;
1321071d4279SBram Moolenaar 	self->buf = buf;
1322e344beadSBram Moolenaar 	buf->b_python_ref = self;
1323071d4279SBram Moolenaar     }
1324071d4279SBram Moolenaar 
1325071d4279SBram Moolenaar     return (PyObject *)(self);
1326071d4279SBram Moolenaar }
1327071d4279SBram Moolenaar 
1328071d4279SBram Moolenaar     static void
1329071d4279SBram Moolenaar BufferDestructor(PyObject *self)
1330071d4279SBram Moolenaar {
1331071d4279SBram Moolenaar     BufferObject *this = (BufferObject *)(self);
1332071d4279SBram Moolenaar 
1333071d4279SBram Moolenaar     if (this->buf && this->buf != INVALID_BUFFER_VALUE)
1334e344beadSBram Moolenaar 	this->buf->b_python_ref = NULL;
1335071d4279SBram Moolenaar 
1336658ada69SBram Moolenaar     Py_DECREF(self);
1337071d4279SBram Moolenaar }
1338071d4279SBram Moolenaar 
1339071d4279SBram Moolenaar     static PyObject *
1340071d4279SBram Moolenaar BufferGetattr(PyObject *self, char *name)
1341071d4279SBram Moolenaar {
1342071d4279SBram Moolenaar     BufferObject *this = (BufferObject *)(self);
1343071d4279SBram Moolenaar 
1344071d4279SBram Moolenaar     if (CheckBuffer(this))
1345071d4279SBram Moolenaar 	return NULL;
1346071d4279SBram Moolenaar 
1347071d4279SBram Moolenaar     if (strcmp(name, "name") == 0)
1348071d4279SBram Moolenaar 	return Py_BuildValue("s", this->buf->b_ffname);
1349071d4279SBram Moolenaar     else if (strcmp(name, "number") == 0)
1350e7cb9cf6SBram Moolenaar 	return Py_BuildValue(Py_ssize_t_fmt, this->buf->b_fnum);
1351071d4279SBram Moolenaar     else if (strcmp(name,"__members__") == 0)
1352071d4279SBram Moolenaar 	return Py_BuildValue("[ss]", "name", "number");
1353071d4279SBram Moolenaar     else
1354071d4279SBram Moolenaar 	return Py_FindMethod(BufferMethods, self, name);
1355071d4279SBram Moolenaar }
1356071d4279SBram Moolenaar 
1357071d4279SBram Moolenaar     static PyObject *
1358071d4279SBram Moolenaar BufferRepr(PyObject *self)
1359071d4279SBram Moolenaar {
1360555b280fSBram Moolenaar     static char repr[100];
1361071d4279SBram Moolenaar     BufferObject *this = (BufferObject *)(self);
1362071d4279SBram Moolenaar 
1363071d4279SBram Moolenaar     if (this->buf == INVALID_BUFFER_VALUE)
1364071d4279SBram Moolenaar     {
1365e7cb9cf6SBram Moolenaar 	vim_snprintf(repr, 100, _("<buffer object (deleted) at %p>"), (self));
1366071d4279SBram Moolenaar 	return PyString_FromString(repr);
1367071d4279SBram Moolenaar     }
1368071d4279SBram Moolenaar     else
1369071d4279SBram Moolenaar     {
1370071d4279SBram Moolenaar 	char *name = (char *)this->buf->b_fname;
1371e7cb9cf6SBram Moolenaar 	PyInt len;
1372071d4279SBram Moolenaar 
1373071d4279SBram Moolenaar 	if (name == NULL)
1374071d4279SBram Moolenaar 	    name = "";
1375071d4279SBram Moolenaar 	len = strlen(name);
1376071d4279SBram Moolenaar 
1377071d4279SBram Moolenaar 	if (len > 35)
1378071d4279SBram Moolenaar 	    name = name + (35 - len);
1379071d4279SBram Moolenaar 
1380555b280fSBram Moolenaar 	vim_snprintf(repr, 100, "<buffer %s%s>", len > 35 ? "..." : "", name);
1381071d4279SBram Moolenaar 
1382071d4279SBram Moolenaar 	return PyString_FromString(repr);
1383071d4279SBram Moolenaar     }
1384071d4279SBram Moolenaar }
1385071d4279SBram Moolenaar 
1386071d4279SBram Moolenaar /******************/
1387071d4279SBram Moolenaar 
13882c45e945SBram Moolenaar     static PyInt
1389071d4279SBram Moolenaar BufferLength(PyObject *self)
1390071d4279SBram Moolenaar {
1391071d4279SBram Moolenaar     /* HOW DO WE SIGNAL AN ERROR FROM THIS FUNCTION? */
1392071d4279SBram Moolenaar     if (CheckBuffer((BufferObject *)(self)))
1393071d4279SBram Moolenaar 	return -1; /* ??? */
1394071d4279SBram Moolenaar 
1395071d4279SBram Moolenaar     return (((BufferObject *)(self))->buf->b_ml.ml_line_count);
1396071d4279SBram Moolenaar }
1397071d4279SBram Moolenaar 
1398071d4279SBram Moolenaar     static PyObject *
13992c45e945SBram Moolenaar BufferItem(PyObject *self, PyInt n)
1400071d4279SBram Moolenaar {
1401071d4279SBram Moolenaar     return RBItem((BufferObject *)(self), n, 1,
1402071d4279SBram Moolenaar 		  (int)((BufferObject *)(self))->buf->b_ml.ml_line_count);
1403071d4279SBram Moolenaar }
1404071d4279SBram Moolenaar 
1405071d4279SBram Moolenaar     static PyObject *
14062c45e945SBram Moolenaar BufferSlice(PyObject *self, PyInt lo, PyInt hi)
1407071d4279SBram Moolenaar {
1408071d4279SBram Moolenaar     return RBSlice((BufferObject *)(self), lo, hi, 1,
1409071d4279SBram Moolenaar 		   (int)((BufferObject *)(self))->buf->b_ml.ml_line_count);
1410071d4279SBram Moolenaar }
1411071d4279SBram Moolenaar 
14122c45e945SBram Moolenaar     static PyInt
14132c45e945SBram Moolenaar BufferAssItem(PyObject *self, PyInt n, PyObject *val)
1414071d4279SBram Moolenaar {
1415071d4279SBram Moolenaar     return RBAssItem((BufferObject *)(self), n, val, 1,
1416e7cb9cf6SBram Moolenaar 		     (PyInt)((BufferObject *)(self))->buf->b_ml.ml_line_count,
1417071d4279SBram Moolenaar 		     NULL);
1418071d4279SBram Moolenaar }
1419071d4279SBram Moolenaar 
14202c45e945SBram Moolenaar     static PyInt
14212c45e945SBram Moolenaar BufferAssSlice(PyObject *self, PyInt lo, PyInt hi, PyObject *val)
1422071d4279SBram Moolenaar {
1423071d4279SBram Moolenaar     return RBAssSlice((BufferObject *)(self), lo, hi, val, 1,
1424e7cb9cf6SBram Moolenaar 		      (PyInt)((BufferObject *)(self))->buf->b_ml.ml_line_count,
1425071d4279SBram Moolenaar 		      NULL);
1426071d4279SBram Moolenaar }
1427071d4279SBram Moolenaar 
1428071d4279SBram Moolenaar     static PyObject *
1429071d4279SBram Moolenaar BufferAppend(PyObject *self, PyObject *args)
1430071d4279SBram Moolenaar {
1431071d4279SBram Moolenaar     return RBAppend((BufferObject *)(self), args, 1,
1432e7cb9cf6SBram Moolenaar 		    (PyInt)((BufferObject *)(self))->buf->b_ml.ml_line_count,
1433071d4279SBram Moolenaar 		    NULL);
1434071d4279SBram Moolenaar }
1435071d4279SBram Moolenaar 
1436071d4279SBram Moolenaar     static PyObject *
1437071d4279SBram Moolenaar BufferMark(PyObject *self, PyObject *args)
1438071d4279SBram Moolenaar {
1439071d4279SBram Moolenaar     pos_T	*posp;
1440071d4279SBram Moolenaar     char	mark;
1441071d4279SBram Moolenaar     buf_T	*curbuf_save;
1442071d4279SBram Moolenaar 
1443071d4279SBram Moolenaar     if (CheckBuffer((BufferObject *)(self)))
1444071d4279SBram Moolenaar 	return NULL;
1445071d4279SBram Moolenaar 
1446071d4279SBram Moolenaar     if (!PyArg_ParseTuple(args, "c", &mark))
1447071d4279SBram Moolenaar 	return NULL;
1448071d4279SBram Moolenaar 
1449071d4279SBram Moolenaar     curbuf_save = curbuf;
1450071d4279SBram Moolenaar     curbuf = ((BufferObject *)(self))->buf;
1451071d4279SBram Moolenaar     posp = getmark(mark, FALSE);
1452071d4279SBram Moolenaar     curbuf = curbuf_save;
1453071d4279SBram Moolenaar 
1454071d4279SBram Moolenaar     if (posp == NULL)
1455071d4279SBram Moolenaar     {
1456071d4279SBram Moolenaar 	PyErr_SetVim(_("invalid mark name"));
1457071d4279SBram Moolenaar 	return NULL;
1458071d4279SBram Moolenaar     }
1459071d4279SBram Moolenaar 
1460071d4279SBram Moolenaar     /* Ckeck for keyboard interrupt */
1461071d4279SBram Moolenaar     if (VimErrorCheck())
1462071d4279SBram Moolenaar 	return NULL;
1463071d4279SBram Moolenaar 
1464071d4279SBram Moolenaar     if (posp->lnum <= 0)
1465071d4279SBram Moolenaar     {
1466071d4279SBram Moolenaar 	/* Or raise an error? */
1467071d4279SBram Moolenaar 	Py_INCREF(Py_None);
1468071d4279SBram Moolenaar 	return Py_None;
1469071d4279SBram Moolenaar     }
1470071d4279SBram Moolenaar 
1471071d4279SBram Moolenaar     return Py_BuildValue("(ll)", (long)(posp->lnum), (long)(posp->col));
1472071d4279SBram Moolenaar }
1473071d4279SBram Moolenaar 
1474071d4279SBram Moolenaar     static PyObject *
1475071d4279SBram Moolenaar BufferRange(PyObject *self, PyObject *args)
1476071d4279SBram Moolenaar {
1477e7cb9cf6SBram Moolenaar     PyInt start;
1478e7cb9cf6SBram Moolenaar     PyInt end;
1479071d4279SBram Moolenaar 
1480071d4279SBram Moolenaar     if (CheckBuffer((BufferObject *)(self)))
1481071d4279SBram Moolenaar 	return NULL;
1482071d4279SBram Moolenaar 
1483e7cb9cf6SBram Moolenaar     if (!PyArg_ParseTuple(args, Py_ssize_t_fmt Py_ssize_t_fmt, &start, &end))
1484071d4279SBram Moolenaar 	return NULL;
1485071d4279SBram Moolenaar 
1486071d4279SBram Moolenaar     return RangeNew(((BufferObject *)(self))->buf, start, end);
1487071d4279SBram Moolenaar }
1488071d4279SBram Moolenaar 
1489071d4279SBram Moolenaar /* Line range object - Definitions
1490071d4279SBram Moolenaar  */
1491071d4279SBram Moolenaar 
1492071d4279SBram Moolenaar static struct PyMethodDef RangeMethods[] = {
1493071d4279SBram Moolenaar     /* name,	    function,		calling,    documentation */
1494e7cb9cf6SBram Moolenaar     {"append",	    RangeAppend,	1,	    "Append data to the Vim range" },
1495071d4279SBram Moolenaar     { NULL,	    NULL,		0,	    NULL }
1496071d4279SBram Moolenaar };
1497071d4279SBram Moolenaar 
1498071d4279SBram Moolenaar static PySequenceMethods RangeAsSeq = {
14992c45e945SBram Moolenaar     (PyInquiry)		RangeLength,	    /* sq_length,    len(x)   */
1500071d4279SBram Moolenaar     (binaryfunc)	0, /* RangeConcat, */	     /* sq_concat,    x+y      */
15012c45e945SBram Moolenaar     (PyIntArgFunc)	0, /* RangeRepeat, */	     /* sq_repeat,    x*n      */
15022c45e945SBram Moolenaar     (PyIntArgFunc)	RangeItem,	    /* sq_item,      x[i]     */
15032c45e945SBram Moolenaar     (PyIntIntArgFunc)	RangeSlice,	    /* sq_slice,     x[i:j]   */
15042c45e945SBram Moolenaar     (PyIntObjArgProc)	RangeAssItem,	    /* sq_ass_item,  x[i]=v   */
15052c45e945SBram Moolenaar     (PyIntIntObjArgProc)	RangeAssSlice,	    /* sq_ass_slice, x[i:j]=v */
1506071d4279SBram Moolenaar };
1507071d4279SBram Moolenaar 
1508071d4279SBram Moolenaar static PyTypeObject RangeType = {
1509071d4279SBram Moolenaar     PyObject_HEAD_INIT(0)
1510071d4279SBram Moolenaar     0,
1511071d4279SBram Moolenaar     "range",
1512071d4279SBram Moolenaar     sizeof(RangeObject),
1513071d4279SBram Moolenaar     0,
1514071d4279SBram Moolenaar 
1515071d4279SBram Moolenaar     (destructor)    RangeDestructor,	/* tp_dealloc,	refcount==0  */
1516071d4279SBram Moolenaar     (printfunc)     0,			/* tp_print,	print x      */
1517071d4279SBram Moolenaar     (getattrfunc)   RangeGetattr,	/* tp_getattr,	x.attr	     */
1518071d4279SBram Moolenaar     (setattrfunc)   0,			/* tp_setattr,	x.attr=v     */
1519071d4279SBram Moolenaar     (cmpfunc)	    0,			/* tp_compare,	x>y	     */
1520071d4279SBram Moolenaar     (reprfunc)	    RangeRepr,		/* tp_repr,	`x`, print x */
1521071d4279SBram Moolenaar 
1522071d4279SBram Moolenaar     0,		    /* as number */
1523071d4279SBram Moolenaar     &RangeAsSeq,    /* as sequence */
1524071d4279SBram Moolenaar     0,		    /* as mapping */
1525071d4279SBram Moolenaar 
1526071d4279SBram Moolenaar     (hashfunc) 0,			/* tp_hash, dict(x) */
1527071d4279SBram Moolenaar     (ternaryfunc) 0,			/* tp_call, x()     */
1528071d4279SBram Moolenaar     (reprfunc) 0,			/* tp_str,  str(x)  */
1529071d4279SBram Moolenaar };
1530071d4279SBram Moolenaar 
1531071d4279SBram Moolenaar /* Line range object - Implementation
1532071d4279SBram Moolenaar  */
1533071d4279SBram Moolenaar 
1534071d4279SBram Moolenaar     static PyObject *
1535e7cb9cf6SBram Moolenaar RangeNew(buf_T *buf, PyInt start, PyInt end)
1536071d4279SBram Moolenaar {
1537071d4279SBram Moolenaar     BufferObject *bufr;
1538071d4279SBram Moolenaar     RangeObject *self;
1539071d4279SBram Moolenaar     self = PyObject_NEW(RangeObject, &RangeType);
1540071d4279SBram Moolenaar     if (self == NULL)
1541071d4279SBram Moolenaar 	return NULL;
1542071d4279SBram Moolenaar 
1543071d4279SBram Moolenaar     bufr = (BufferObject *)BufferNew(buf);
1544071d4279SBram Moolenaar     if (bufr == NULL)
1545071d4279SBram Moolenaar     {
1546658ada69SBram Moolenaar 	Py_DECREF(self);
1547071d4279SBram Moolenaar 	return NULL;
1548071d4279SBram Moolenaar     }
1549071d4279SBram Moolenaar     Py_INCREF(bufr);
1550071d4279SBram Moolenaar 
1551071d4279SBram Moolenaar     self->buf = bufr;
1552071d4279SBram Moolenaar     self->start = start;
1553071d4279SBram Moolenaar     self->end = end;
1554071d4279SBram Moolenaar 
1555071d4279SBram Moolenaar     return (PyObject *)(self);
1556071d4279SBram Moolenaar }
1557071d4279SBram Moolenaar 
1558071d4279SBram Moolenaar     static void
1559071d4279SBram Moolenaar RangeDestructor(PyObject *self)
1560071d4279SBram Moolenaar {
1561071d4279SBram Moolenaar     Py_DECREF(((RangeObject *)(self))->buf);
1562658ada69SBram Moolenaar     Py_DECREF(self);
1563071d4279SBram Moolenaar }
1564071d4279SBram Moolenaar 
1565071d4279SBram Moolenaar     static PyObject *
1566071d4279SBram Moolenaar RangeGetattr(PyObject *self, char *name)
1567071d4279SBram Moolenaar {
1568071d4279SBram Moolenaar     if (strcmp(name, "start") == 0)
1569e7cb9cf6SBram Moolenaar 	return Py_BuildValue(Py_ssize_t_fmt, ((RangeObject *)(self))->start - 1);
1570071d4279SBram Moolenaar     else if (strcmp(name, "end") == 0)
1571e7cb9cf6SBram Moolenaar 	return Py_BuildValue(Py_ssize_t_fmt, ((RangeObject *)(self))->end - 1);
1572071d4279SBram Moolenaar     else
1573071d4279SBram Moolenaar 	return Py_FindMethod(RangeMethods, self, name);
1574071d4279SBram Moolenaar }
1575071d4279SBram Moolenaar 
1576071d4279SBram Moolenaar     static PyObject *
1577071d4279SBram Moolenaar RangeRepr(PyObject *self)
1578071d4279SBram Moolenaar {
1579555b280fSBram Moolenaar     static char repr[100];
1580071d4279SBram Moolenaar     RangeObject *this = (RangeObject *)(self);
1581071d4279SBram Moolenaar 
1582071d4279SBram Moolenaar     if (this->buf->buf == INVALID_BUFFER_VALUE)
1583071d4279SBram Moolenaar     {
1584e7cb9cf6SBram Moolenaar 	vim_snprintf(repr, 100, "<range object (for deleted buffer) at %p>",
1585e7cb9cf6SBram Moolenaar 								      (self));
1586071d4279SBram Moolenaar 	return PyString_FromString(repr);
1587071d4279SBram Moolenaar     }
1588071d4279SBram Moolenaar     else
1589071d4279SBram Moolenaar     {
1590071d4279SBram Moolenaar 	char *name = (char *)this->buf->buf->b_fname;
1591071d4279SBram Moolenaar 	int len;
1592071d4279SBram Moolenaar 
1593071d4279SBram Moolenaar 	if (name == NULL)
1594071d4279SBram Moolenaar 	    name = "";
1595c236c16dSBram Moolenaar 	len = (int)strlen(name);
1596071d4279SBram Moolenaar 
1597071d4279SBram Moolenaar 	if (len > 45)
1598071d4279SBram Moolenaar 	    name = name + (45 - len);
1599071d4279SBram Moolenaar 
1600555b280fSBram Moolenaar 	vim_snprintf(repr, 100, "<range %s%s (%d:%d)>",
1601071d4279SBram Moolenaar 		len > 45 ? "..." : "", name,
1602071d4279SBram Moolenaar 		this->start, this->end);
1603071d4279SBram Moolenaar 
1604071d4279SBram Moolenaar 	return PyString_FromString(repr);
1605071d4279SBram Moolenaar     }
1606071d4279SBram Moolenaar }
1607071d4279SBram Moolenaar 
1608071d4279SBram Moolenaar /****************/
1609071d4279SBram Moolenaar 
16102c45e945SBram Moolenaar     static PyInt
1611071d4279SBram Moolenaar RangeLength(PyObject *self)
1612071d4279SBram Moolenaar {
1613071d4279SBram Moolenaar     /* HOW DO WE SIGNAL AN ERROR FROM THIS FUNCTION? */
1614071d4279SBram Moolenaar     if (CheckBuffer(((RangeObject *)(self))->buf))
1615071d4279SBram Moolenaar 	return -1; /* ??? */
1616071d4279SBram Moolenaar 
1617071d4279SBram Moolenaar     return (((RangeObject *)(self))->end - ((RangeObject *)(self))->start + 1);
1618071d4279SBram Moolenaar }
1619071d4279SBram Moolenaar 
1620071d4279SBram Moolenaar     static PyObject *
16212c45e945SBram Moolenaar RangeItem(PyObject *self, PyInt n)
1622071d4279SBram Moolenaar {
1623071d4279SBram Moolenaar     return RBItem(((RangeObject *)(self))->buf, n,
1624071d4279SBram Moolenaar 		  ((RangeObject *)(self))->start,
1625071d4279SBram Moolenaar 		  ((RangeObject *)(self))->end);
1626071d4279SBram Moolenaar }
1627071d4279SBram Moolenaar 
1628071d4279SBram Moolenaar     static PyObject *
16292c45e945SBram Moolenaar RangeSlice(PyObject *self, PyInt lo, PyInt hi)
1630071d4279SBram Moolenaar {
1631071d4279SBram Moolenaar     return RBSlice(((RangeObject *)(self))->buf, lo, hi,
1632071d4279SBram Moolenaar 		   ((RangeObject *)(self))->start,
1633071d4279SBram Moolenaar 		   ((RangeObject *)(self))->end);
1634071d4279SBram Moolenaar }
1635071d4279SBram Moolenaar 
16362c45e945SBram Moolenaar     static PyInt
16372c45e945SBram Moolenaar RangeAssItem(PyObject *self, PyInt n, PyObject *val)
1638071d4279SBram Moolenaar {
1639071d4279SBram Moolenaar     return RBAssItem(((RangeObject *)(self))->buf, n, val,
1640071d4279SBram Moolenaar 		     ((RangeObject *)(self))->start,
1641071d4279SBram Moolenaar 		     ((RangeObject *)(self))->end,
1642071d4279SBram Moolenaar 		     &((RangeObject *)(self))->end);
1643071d4279SBram Moolenaar }
1644071d4279SBram Moolenaar 
16452c45e945SBram Moolenaar     static PyInt
16462c45e945SBram Moolenaar RangeAssSlice(PyObject *self, PyInt lo, PyInt hi, PyObject *val)
1647071d4279SBram Moolenaar {
1648071d4279SBram Moolenaar     return RBAssSlice(((RangeObject *)(self))->buf, lo, hi, val,
1649071d4279SBram Moolenaar 		      ((RangeObject *)(self))->start,
1650071d4279SBram Moolenaar 		      ((RangeObject *)(self))->end,
1651071d4279SBram Moolenaar 		      &((RangeObject *)(self))->end);
1652071d4279SBram Moolenaar }
1653071d4279SBram Moolenaar 
1654071d4279SBram Moolenaar     static PyObject *
1655071d4279SBram Moolenaar RangeAppend(PyObject *self, PyObject *args)
1656071d4279SBram Moolenaar {
1657071d4279SBram Moolenaar     return RBAppend(((RangeObject *)(self))->buf, args,
1658071d4279SBram Moolenaar 		    ((RangeObject *)(self))->start,
1659071d4279SBram Moolenaar 		    ((RangeObject *)(self))->end,
1660071d4279SBram Moolenaar 		    &((RangeObject *)(self))->end);
1661071d4279SBram Moolenaar }
1662071d4279SBram Moolenaar 
1663071d4279SBram Moolenaar /* Buffer list object - Definitions
1664071d4279SBram Moolenaar  */
1665071d4279SBram Moolenaar 
1666071d4279SBram Moolenaar typedef struct
1667071d4279SBram Moolenaar {
1668071d4279SBram Moolenaar     PyObject_HEAD
1669071d4279SBram Moolenaar }
1670071d4279SBram Moolenaar BufListObject;
1671071d4279SBram Moolenaar 
1672071d4279SBram Moolenaar static PySequenceMethods BufListAsSeq = {
16732c45e945SBram Moolenaar     (PyInquiry)		BufListLength,	    /* sq_length,    len(x)   */
1674071d4279SBram Moolenaar     (binaryfunc)	0,		    /* sq_concat,    x+y      */
16752c45e945SBram Moolenaar     (PyIntArgFunc)	0,		    /* sq_repeat,    x*n      */
16762c45e945SBram Moolenaar     (PyIntArgFunc)	BufListItem,	    /* sq_item,      x[i]     */
16772c45e945SBram Moolenaar     (PyIntIntArgFunc)	0,		    /* sq_slice,     x[i:j]   */
16782c45e945SBram Moolenaar     (PyIntObjArgProc)	0,		    /* sq_ass_item,  x[i]=v   */
16792c45e945SBram Moolenaar     (PyIntIntObjArgProc)	0,		    /* sq_ass_slice, x[i:j]=v */
1680071d4279SBram Moolenaar };
1681071d4279SBram Moolenaar 
1682071d4279SBram Moolenaar static PyTypeObject BufListType = {
1683071d4279SBram Moolenaar     PyObject_HEAD_INIT(0)
1684071d4279SBram Moolenaar     0,
1685071d4279SBram Moolenaar     "buffer list",
1686071d4279SBram Moolenaar     sizeof(BufListObject),
1687071d4279SBram Moolenaar     0,
1688071d4279SBram Moolenaar 
1689071d4279SBram Moolenaar     (destructor)    0,			/* tp_dealloc,	refcount==0  */
1690071d4279SBram Moolenaar     (printfunc)     0,			/* tp_print,	print x      */
1691071d4279SBram Moolenaar     (getattrfunc)   0,			/* tp_getattr,	x.attr	     */
1692071d4279SBram Moolenaar     (setattrfunc)   0,			/* tp_setattr,	x.attr=v     */
1693071d4279SBram Moolenaar     (cmpfunc)	    0,			/* tp_compare,	x>y	     */
1694071d4279SBram Moolenaar     (reprfunc)	    0,			/* tp_repr,	`x`, print x */
1695071d4279SBram Moolenaar 
1696071d4279SBram Moolenaar     0,		    /* as number */
1697071d4279SBram Moolenaar     &BufListAsSeq,  /* as sequence */
1698071d4279SBram Moolenaar     0,		    /* as mapping */
1699071d4279SBram Moolenaar 
1700071d4279SBram Moolenaar     (hashfunc) 0,			/* tp_hash, dict(x) */
1701071d4279SBram Moolenaar     (ternaryfunc) 0,			/* tp_call, x()     */
1702071d4279SBram Moolenaar     (reprfunc) 0,			/* tp_str,  str(x)  */
1703071d4279SBram Moolenaar };
1704071d4279SBram Moolenaar 
1705071d4279SBram Moolenaar /* Buffer list object - Implementation
1706071d4279SBram Moolenaar  */
1707071d4279SBram Moolenaar 
17082c45e945SBram Moolenaar     static PyInt
17094bdbbf70SBram Moolenaar BufListLength(PyObject *self UNUSED)
1710071d4279SBram Moolenaar {
1711071d4279SBram Moolenaar     buf_T	*b = firstbuf;
1712e7cb9cf6SBram Moolenaar     PyInt	n = 0;
1713071d4279SBram Moolenaar 
1714071d4279SBram Moolenaar     while (b)
1715071d4279SBram Moolenaar     {
1716071d4279SBram Moolenaar 	++n;
1717071d4279SBram Moolenaar 	b = b->b_next;
1718071d4279SBram Moolenaar     }
1719071d4279SBram Moolenaar 
1720071d4279SBram Moolenaar     return n;
1721071d4279SBram Moolenaar }
1722071d4279SBram Moolenaar 
1723071d4279SBram Moolenaar     static PyObject *
17244bdbbf70SBram Moolenaar BufListItem(PyObject *self UNUSED, PyInt n)
1725071d4279SBram Moolenaar {
1726071d4279SBram Moolenaar     buf_T *b;
1727071d4279SBram Moolenaar 
1728071d4279SBram Moolenaar     for (b = firstbuf; b; b = b->b_next, --n)
1729071d4279SBram Moolenaar     {
1730071d4279SBram Moolenaar 	if (n == 0)
1731071d4279SBram Moolenaar 	    return BufferNew(b);
1732071d4279SBram Moolenaar     }
1733071d4279SBram Moolenaar 
1734071d4279SBram Moolenaar     PyErr_SetString(PyExc_IndexError, _("no such buffer"));
1735071d4279SBram Moolenaar     return NULL;
1736071d4279SBram Moolenaar }
1737071d4279SBram Moolenaar 
1738071d4279SBram Moolenaar /* Window object - Definitions
1739071d4279SBram Moolenaar  */
1740071d4279SBram Moolenaar 
1741071d4279SBram Moolenaar static struct PyMethodDef WindowMethods[] = {
1742071d4279SBram Moolenaar     /* name,	    function,		calling,    documentation */
1743071d4279SBram Moolenaar     { NULL,	    NULL,		0,	    NULL }
1744071d4279SBram Moolenaar };
1745071d4279SBram Moolenaar 
1746071d4279SBram Moolenaar static PyTypeObject WindowType = {
1747071d4279SBram Moolenaar     PyObject_HEAD_INIT(0)
1748071d4279SBram Moolenaar     0,
1749071d4279SBram Moolenaar     "window",
1750071d4279SBram Moolenaar     sizeof(WindowObject),
1751071d4279SBram Moolenaar     0,
1752071d4279SBram Moolenaar 
1753071d4279SBram Moolenaar     (destructor)    WindowDestructor,	/* tp_dealloc,	refcount==0  */
1754071d4279SBram Moolenaar     (printfunc)     0,			/* tp_print,	print x      */
1755071d4279SBram Moolenaar     (getattrfunc)   WindowGetattr,	/* tp_getattr,	x.attr	     */
1756071d4279SBram Moolenaar     (setattrfunc)   WindowSetattr,	/* tp_setattr,	x.attr=v     */
1757071d4279SBram Moolenaar     (cmpfunc)	    0,			/* tp_compare,	x>y	     */
1758071d4279SBram Moolenaar     (reprfunc)	    WindowRepr,		/* tp_repr,	`x`, print x */
1759071d4279SBram Moolenaar 
1760071d4279SBram Moolenaar     0,		    /* as number */
1761071d4279SBram Moolenaar     0,		    /* as sequence */
1762071d4279SBram Moolenaar     0,		    /* as mapping */
1763071d4279SBram Moolenaar 
1764071d4279SBram Moolenaar     (hashfunc) 0,			/* tp_hash, dict(x) */
1765071d4279SBram Moolenaar     (ternaryfunc) 0,			/* tp_call, x()     */
1766071d4279SBram Moolenaar     (reprfunc) 0,			/* tp_str,  str(x)  */
1767071d4279SBram Moolenaar };
1768071d4279SBram Moolenaar 
1769071d4279SBram Moolenaar /* Window object - Implementation
1770071d4279SBram Moolenaar  */
1771071d4279SBram Moolenaar 
1772071d4279SBram Moolenaar     static PyObject *
1773071d4279SBram Moolenaar WindowNew(win_T *win)
1774071d4279SBram Moolenaar {
1775071d4279SBram Moolenaar     /* We need to handle deletion of windows underneath us.
1776e344beadSBram Moolenaar      * If we add a "w_python_ref" field to the win_T structure,
1777071d4279SBram Moolenaar      * then we can get at it in win_free() in vim. We then
1778071d4279SBram Moolenaar      * need to create only ONE Python object per window - if
1779071d4279SBram Moolenaar      * we try to create a second, just INCREF the existing one
1780071d4279SBram Moolenaar      * and return it. The (single) Python object referring to
1781e344beadSBram Moolenaar      * the window is stored in "w_python_ref".
1782071d4279SBram Moolenaar      * On a win_free() we set the Python object's win_T* field
1783071d4279SBram Moolenaar      * to an invalid value. We trap all uses of a window
1784071d4279SBram Moolenaar      * object, and reject them if the win_T* field is invalid.
1785071d4279SBram Moolenaar      */
1786071d4279SBram Moolenaar 
1787071d4279SBram Moolenaar     WindowObject *self;
1788071d4279SBram Moolenaar 
1789e344beadSBram Moolenaar     if (win->w_python_ref)
1790071d4279SBram Moolenaar     {
1791e344beadSBram Moolenaar 	self = win->w_python_ref;
1792071d4279SBram Moolenaar 	Py_INCREF(self);
1793071d4279SBram Moolenaar     }
1794071d4279SBram Moolenaar     else
1795071d4279SBram Moolenaar     {
1796071d4279SBram Moolenaar 	self = PyObject_NEW(WindowObject, &WindowType);
1797071d4279SBram Moolenaar 	if (self == NULL)
1798071d4279SBram Moolenaar 	    return NULL;
1799071d4279SBram Moolenaar 	self->win = win;
1800e344beadSBram Moolenaar 	win->w_python_ref = self;
1801071d4279SBram Moolenaar     }
1802071d4279SBram Moolenaar 
1803071d4279SBram Moolenaar     return (PyObject *)(self);
1804071d4279SBram Moolenaar }
1805071d4279SBram Moolenaar 
1806071d4279SBram Moolenaar     static void
1807071d4279SBram Moolenaar WindowDestructor(PyObject *self)
1808071d4279SBram Moolenaar {
1809071d4279SBram Moolenaar     WindowObject *this = (WindowObject *)(self);
1810071d4279SBram Moolenaar 
1811071d4279SBram Moolenaar     if (this->win && this->win != INVALID_WINDOW_VALUE)
1812e344beadSBram Moolenaar 	this->win->w_python_ref = NULL;
1813071d4279SBram Moolenaar 
1814658ada69SBram Moolenaar     Py_DECREF(self);
1815071d4279SBram Moolenaar }
1816071d4279SBram Moolenaar 
1817071d4279SBram Moolenaar     static int
1818071d4279SBram Moolenaar CheckWindow(WindowObject *this)
1819071d4279SBram Moolenaar {
1820071d4279SBram Moolenaar     if (this->win == INVALID_WINDOW_VALUE)
1821071d4279SBram Moolenaar     {
1822071d4279SBram Moolenaar 	PyErr_SetVim(_("attempt to refer to deleted window"));
1823071d4279SBram Moolenaar 	return -1;
1824071d4279SBram Moolenaar     }
1825071d4279SBram Moolenaar 
1826071d4279SBram Moolenaar     return 0;
1827071d4279SBram Moolenaar }
1828071d4279SBram Moolenaar 
1829071d4279SBram Moolenaar     static PyObject *
1830071d4279SBram Moolenaar WindowGetattr(PyObject *self, char *name)
1831071d4279SBram Moolenaar {
1832071d4279SBram Moolenaar     WindowObject *this = (WindowObject *)(self);
1833071d4279SBram Moolenaar 
1834071d4279SBram Moolenaar     if (CheckWindow(this))
1835071d4279SBram Moolenaar 	return NULL;
1836071d4279SBram Moolenaar 
1837071d4279SBram Moolenaar     if (strcmp(name, "buffer") == 0)
1838071d4279SBram Moolenaar 	return (PyObject *)BufferNew(this->win->w_buffer);
1839071d4279SBram Moolenaar     else if (strcmp(name, "cursor") == 0)
1840071d4279SBram Moolenaar     {
1841071d4279SBram Moolenaar 	pos_T *pos = &this->win->w_cursor;
1842071d4279SBram Moolenaar 
1843071d4279SBram Moolenaar 	return Py_BuildValue("(ll)", (long)(pos->lnum), (long)(pos->col));
1844071d4279SBram Moolenaar     }
1845071d4279SBram Moolenaar     else if (strcmp(name, "height") == 0)
1846071d4279SBram Moolenaar 	return Py_BuildValue("l", (long)(this->win->w_height));
1847071d4279SBram Moolenaar #ifdef FEAT_VERTSPLIT
1848071d4279SBram Moolenaar     else if (strcmp(name, "width") == 0)
1849071d4279SBram Moolenaar 	return Py_BuildValue("l", (long)(W_WIDTH(this->win)));
1850071d4279SBram Moolenaar #endif
1851071d4279SBram Moolenaar     else if (strcmp(name,"__members__") == 0)
1852071d4279SBram Moolenaar 	return Py_BuildValue("[sss]", "buffer", "cursor", "height");
1853071d4279SBram Moolenaar     else
1854071d4279SBram Moolenaar 	return Py_FindMethod(WindowMethods, self, name);
1855071d4279SBram Moolenaar }
1856071d4279SBram Moolenaar 
1857071d4279SBram Moolenaar     static int
1858071d4279SBram Moolenaar WindowSetattr(PyObject *self, char *name, PyObject *val)
1859071d4279SBram Moolenaar {
1860071d4279SBram Moolenaar     WindowObject *this = (WindowObject *)(self);
1861071d4279SBram Moolenaar 
1862071d4279SBram Moolenaar     if (CheckWindow(this))
1863071d4279SBram Moolenaar 	return -1;
1864071d4279SBram Moolenaar 
1865071d4279SBram Moolenaar     if (strcmp(name, "buffer") == 0)
1866071d4279SBram Moolenaar     {
1867071d4279SBram Moolenaar 	PyErr_SetString(PyExc_TypeError, _("readonly attribute"));
1868071d4279SBram Moolenaar 	return -1;
1869071d4279SBram Moolenaar     }
1870071d4279SBram Moolenaar     else if (strcmp(name, "cursor") == 0)
1871071d4279SBram Moolenaar     {
1872071d4279SBram Moolenaar 	long lnum;
1873071d4279SBram Moolenaar 	long col;
1874badfde1bSBram Moolenaar 	long len;
1875071d4279SBram Moolenaar 
1876071d4279SBram Moolenaar 	if (!PyArg_Parse(val, "(ll)", &lnum, &col))
1877071d4279SBram Moolenaar 	    return -1;
1878071d4279SBram Moolenaar 
1879071d4279SBram Moolenaar 	if (lnum <= 0 || lnum > this->win->w_buffer->b_ml.ml_line_count)
1880071d4279SBram Moolenaar 	{
1881071d4279SBram Moolenaar 	    PyErr_SetVim(_("cursor position outside buffer"));
1882071d4279SBram Moolenaar 	    return -1;
1883071d4279SBram Moolenaar 	}
1884071d4279SBram Moolenaar 
1885071d4279SBram Moolenaar 	/* Check for keyboard interrupts */
1886071d4279SBram Moolenaar 	if (VimErrorCheck())
1887071d4279SBram Moolenaar 	    return -1;
1888071d4279SBram Moolenaar 
1889badfde1bSBram Moolenaar 	/* When column is out of range silently correct it. */
18908b9c05faSBram Moolenaar 	len = (long)STRLEN(ml_get_buf(this->win->w_buffer, lnum, FALSE));
1891badfde1bSBram Moolenaar 	if (col > len)
1892badfde1bSBram Moolenaar 	    col = len;
1893071d4279SBram Moolenaar 
1894071d4279SBram Moolenaar 	this->win->w_cursor.lnum = lnum;
1895071d4279SBram Moolenaar 	this->win->w_cursor.col = col;
1896badfde1bSBram Moolenaar #ifdef FEAT_VIRTUALEDIT
1897badfde1bSBram Moolenaar 	this->win->w_cursor.coladd = 0;
1898badfde1bSBram Moolenaar #endif
1899071d4279SBram Moolenaar 	update_screen(VALID);
1900071d4279SBram Moolenaar 
1901071d4279SBram Moolenaar 	return 0;
1902071d4279SBram Moolenaar     }
1903071d4279SBram Moolenaar     else if (strcmp(name, "height") == 0)
1904071d4279SBram Moolenaar     {
1905071d4279SBram Moolenaar 	int	height;
1906071d4279SBram Moolenaar 	win_T	*savewin;
1907071d4279SBram Moolenaar 
1908071d4279SBram Moolenaar 	if (!PyArg_Parse(val, "i", &height))
1909071d4279SBram Moolenaar 	    return -1;
1910071d4279SBram Moolenaar 
1911071d4279SBram Moolenaar #ifdef FEAT_GUI
1912071d4279SBram Moolenaar 	need_mouse_correct = TRUE;
1913071d4279SBram Moolenaar #endif
1914071d4279SBram Moolenaar 	savewin = curwin;
1915071d4279SBram Moolenaar 	curwin = this->win;
1916071d4279SBram Moolenaar 	win_setheight(height);
1917071d4279SBram Moolenaar 	curwin = savewin;
1918071d4279SBram Moolenaar 
1919071d4279SBram Moolenaar 	/* Check for keyboard interrupts */
1920071d4279SBram Moolenaar 	if (VimErrorCheck())
1921071d4279SBram Moolenaar 	    return -1;
1922071d4279SBram Moolenaar 
1923071d4279SBram Moolenaar 	return 0;
1924071d4279SBram Moolenaar     }
1925071d4279SBram Moolenaar #ifdef FEAT_VERTSPLIT
1926071d4279SBram Moolenaar     else if (strcmp(name, "width") == 0)
1927071d4279SBram Moolenaar     {
1928071d4279SBram Moolenaar 	int	width;
1929071d4279SBram Moolenaar 	win_T	*savewin;
1930071d4279SBram Moolenaar 
1931071d4279SBram Moolenaar 	if (!PyArg_Parse(val, "i", &width))
1932071d4279SBram Moolenaar 	    return -1;
1933071d4279SBram Moolenaar 
1934071d4279SBram Moolenaar #ifdef FEAT_GUI
1935071d4279SBram Moolenaar 	need_mouse_correct = TRUE;
1936071d4279SBram Moolenaar #endif
1937071d4279SBram Moolenaar 	savewin = curwin;
1938071d4279SBram Moolenaar 	curwin = this->win;
1939071d4279SBram Moolenaar 	win_setwidth(width);
1940071d4279SBram Moolenaar 	curwin = savewin;
1941071d4279SBram Moolenaar 
1942071d4279SBram Moolenaar 	/* Check for keyboard interrupts */
1943071d4279SBram Moolenaar 	if (VimErrorCheck())
1944071d4279SBram Moolenaar 	    return -1;
1945071d4279SBram Moolenaar 
1946071d4279SBram Moolenaar 	return 0;
1947071d4279SBram Moolenaar     }
1948071d4279SBram Moolenaar #endif
1949071d4279SBram Moolenaar     else
1950071d4279SBram Moolenaar     {
1951071d4279SBram Moolenaar 	PyErr_SetString(PyExc_AttributeError, name);
1952071d4279SBram Moolenaar 	return -1;
1953071d4279SBram Moolenaar     }
1954071d4279SBram Moolenaar }
1955071d4279SBram Moolenaar 
1956071d4279SBram Moolenaar     static PyObject *
1957071d4279SBram Moolenaar WindowRepr(PyObject *self)
1958071d4279SBram Moolenaar {
1959555b280fSBram Moolenaar     static char repr[100];
1960071d4279SBram Moolenaar     WindowObject *this = (WindowObject *)(self);
1961071d4279SBram Moolenaar 
1962071d4279SBram Moolenaar     if (this->win == INVALID_WINDOW_VALUE)
1963071d4279SBram Moolenaar     {
1964e7cb9cf6SBram Moolenaar 	vim_snprintf(repr, 100, _("<window object (deleted) at %p>"), (self));
1965071d4279SBram Moolenaar 	return PyString_FromString(repr);
1966071d4279SBram Moolenaar     }
1967071d4279SBram Moolenaar     else
1968071d4279SBram Moolenaar     {
1969071d4279SBram Moolenaar 	int	i = 0;
1970071d4279SBram Moolenaar 	win_T	*w;
1971071d4279SBram Moolenaar 
1972071d4279SBram Moolenaar 	for (w = firstwin; w != NULL && w != this->win; w = W_NEXT(w))
1973071d4279SBram Moolenaar 	    ++i;
1974071d4279SBram Moolenaar 
1975071d4279SBram Moolenaar 	if (w == NULL)
1976e7cb9cf6SBram Moolenaar 	    vim_snprintf(repr, 100, _("<window object (unknown) at %p>"),
1977e7cb9cf6SBram Moolenaar 								      (self));
1978071d4279SBram Moolenaar 	else
1979555b280fSBram Moolenaar 	    vim_snprintf(repr, 100, _("<window %d>"), i);
1980071d4279SBram Moolenaar 
1981071d4279SBram Moolenaar 	return PyString_FromString(repr);
1982071d4279SBram Moolenaar     }
1983071d4279SBram Moolenaar }
1984071d4279SBram Moolenaar 
1985071d4279SBram Moolenaar /* Window list object - Definitions
1986071d4279SBram Moolenaar  */
1987071d4279SBram Moolenaar 
1988071d4279SBram Moolenaar typedef struct
1989071d4279SBram Moolenaar {
1990071d4279SBram Moolenaar     PyObject_HEAD
1991071d4279SBram Moolenaar }
1992071d4279SBram Moolenaar WinListObject;
1993071d4279SBram Moolenaar 
1994071d4279SBram Moolenaar static PySequenceMethods WinListAsSeq = {
19952c45e945SBram Moolenaar     (PyInquiry)		WinListLength,	    /* sq_length,    len(x)   */
1996071d4279SBram Moolenaar     (binaryfunc)	0,		    /* sq_concat,    x+y      */
19972c45e945SBram Moolenaar     (PyIntArgFunc)	0,		    /* sq_repeat,    x*n      */
19982c45e945SBram Moolenaar     (PyIntArgFunc)	WinListItem,	    /* sq_item,      x[i]     */
19992c45e945SBram Moolenaar     (PyIntIntArgFunc)	0,		    /* sq_slice,     x[i:j]   */
20002c45e945SBram Moolenaar     (PyIntObjArgProc)	0,		    /* sq_ass_item,  x[i]=v   */
20012c45e945SBram Moolenaar     (PyIntIntObjArgProc)	0,		    /* sq_ass_slice, x[i:j]=v */
2002071d4279SBram Moolenaar };
2003071d4279SBram Moolenaar 
2004071d4279SBram Moolenaar static PyTypeObject WinListType = {
2005071d4279SBram Moolenaar     PyObject_HEAD_INIT(0)
2006071d4279SBram Moolenaar     0,
2007071d4279SBram Moolenaar     "window list",
2008071d4279SBram Moolenaar     sizeof(WinListObject),
2009071d4279SBram Moolenaar     0,
2010071d4279SBram Moolenaar 
2011071d4279SBram Moolenaar     (destructor)    0,			/* tp_dealloc,	refcount==0  */
2012071d4279SBram Moolenaar     (printfunc)     0,			/* tp_print,	print x      */
2013071d4279SBram Moolenaar     (getattrfunc)   0,			/* tp_getattr,	x.attr	     */
2014071d4279SBram Moolenaar     (setattrfunc)   0,			/* tp_setattr,	x.attr=v     */
2015071d4279SBram Moolenaar     (cmpfunc)	    0,			/* tp_compare,	x>y	     */
2016071d4279SBram Moolenaar     (reprfunc)	    0,			/* tp_repr,	`x`, print x */
2017071d4279SBram Moolenaar 
2018071d4279SBram Moolenaar     0,		    /* as number */
2019071d4279SBram Moolenaar     &WinListAsSeq,  /* as sequence */
2020071d4279SBram Moolenaar     0,		    /* as mapping */
2021071d4279SBram Moolenaar 
2022071d4279SBram Moolenaar     (hashfunc) 0,			/* tp_hash, dict(x) */
2023071d4279SBram Moolenaar     (ternaryfunc) 0,			/* tp_call, x()     */
2024071d4279SBram Moolenaar     (reprfunc) 0,			/* tp_str,  str(x)  */
2025071d4279SBram Moolenaar };
2026071d4279SBram Moolenaar 
2027071d4279SBram Moolenaar /* Window list object - Implementation
2028071d4279SBram Moolenaar  */
20292c45e945SBram Moolenaar     static PyInt
20304bdbbf70SBram Moolenaar WinListLength(PyObject *self UNUSED)
2031071d4279SBram Moolenaar {
2032071d4279SBram Moolenaar     win_T	*w = firstwin;
2033e7cb9cf6SBram Moolenaar     PyInt	n = 0;
2034071d4279SBram Moolenaar 
2035f740b29aSBram Moolenaar     while (w != NULL)
2036071d4279SBram Moolenaar     {
2037071d4279SBram Moolenaar 	++n;
2038071d4279SBram Moolenaar 	w = W_NEXT(w);
2039071d4279SBram Moolenaar     }
2040071d4279SBram Moolenaar 
2041071d4279SBram Moolenaar     return n;
2042071d4279SBram Moolenaar }
2043071d4279SBram Moolenaar 
2044071d4279SBram Moolenaar     static PyObject *
20454bdbbf70SBram Moolenaar WinListItem(PyObject *self UNUSED, PyInt n)
2046071d4279SBram Moolenaar {
2047071d4279SBram Moolenaar     win_T *w;
2048071d4279SBram Moolenaar 
2049f740b29aSBram Moolenaar     for (w = firstwin; w != NULL; w = W_NEXT(w), --n)
2050071d4279SBram Moolenaar 	if (n == 0)
2051071d4279SBram Moolenaar 	    return WindowNew(w);
2052071d4279SBram Moolenaar 
2053071d4279SBram Moolenaar     PyErr_SetString(PyExc_IndexError, _("no such window"));
2054071d4279SBram Moolenaar     return NULL;
2055071d4279SBram Moolenaar }
2056071d4279SBram Moolenaar 
2057071d4279SBram Moolenaar /* Current items object - Definitions
2058071d4279SBram Moolenaar  */
2059071d4279SBram Moolenaar 
2060071d4279SBram Moolenaar typedef struct
2061071d4279SBram Moolenaar {
2062071d4279SBram Moolenaar     PyObject_HEAD
2063071d4279SBram Moolenaar }
2064071d4279SBram Moolenaar CurrentObject;
2065071d4279SBram Moolenaar 
2066071d4279SBram Moolenaar static PyTypeObject CurrentType = {
2067071d4279SBram Moolenaar     PyObject_HEAD_INIT(0)
2068071d4279SBram Moolenaar     0,
2069071d4279SBram Moolenaar     "current data",
2070071d4279SBram Moolenaar     sizeof(CurrentObject),
2071071d4279SBram Moolenaar     0,
2072071d4279SBram Moolenaar 
2073071d4279SBram Moolenaar     (destructor)    0,			/* tp_dealloc,	refcount==0  */
2074071d4279SBram Moolenaar     (printfunc)     0,			/* tp_print,	print x      */
2075071d4279SBram Moolenaar     (getattrfunc)   CurrentGetattr,	/* tp_getattr,	x.attr	     */
2076071d4279SBram Moolenaar     (setattrfunc)   CurrentSetattr,	/* tp_setattr,	x.attr=v     */
2077071d4279SBram Moolenaar     (cmpfunc)	    0,			/* tp_compare,	x>y	     */
2078071d4279SBram Moolenaar     (reprfunc)	    0,			/* tp_repr,	`x`, print x */
2079071d4279SBram Moolenaar 
2080071d4279SBram Moolenaar     0,		    /* as number */
2081071d4279SBram Moolenaar     0,		    /* as sequence */
2082071d4279SBram Moolenaar     0,		    /* as mapping */
2083071d4279SBram Moolenaar 
2084071d4279SBram Moolenaar     (hashfunc) 0,			/* tp_hash, dict(x) */
2085071d4279SBram Moolenaar     (ternaryfunc) 0,			/* tp_call, x()     */
2086071d4279SBram Moolenaar     (reprfunc) 0,			/* tp_str,  str(x)  */
2087071d4279SBram Moolenaar };
2088071d4279SBram Moolenaar 
2089071d4279SBram Moolenaar /* Current items object - Implementation
2090071d4279SBram Moolenaar  */
2091071d4279SBram Moolenaar     static PyObject *
20924bdbbf70SBram Moolenaar CurrentGetattr(PyObject *self UNUSED, char *name)
2093071d4279SBram Moolenaar {
2094071d4279SBram Moolenaar     if (strcmp(name, "buffer") == 0)
2095071d4279SBram Moolenaar 	return (PyObject *)BufferNew(curbuf);
2096071d4279SBram Moolenaar     else if (strcmp(name, "window") == 0)
2097071d4279SBram Moolenaar 	return (PyObject *)WindowNew(curwin);
2098071d4279SBram Moolenaar     else if (strcmp(name, "line") == 0)
2099e7cb9cf6SBram Moolenaar 	return GetBufferLine(curbuf, (PyInt)curwin->w_cursor.lnum);
2100071d4279SBram Moolenaar     else if (strcmp(name, "range") == 0)
2101071d4279SBram Moolenaar 	return RangeNew(curbuf, RangeStart, RangeEnd);
2102071d4279SBram Moolenaar     else if (strcmp(name,"__members__") == 0)
2103071d4279SBram Moolenaar 	return Py_BuildValue("[ssss]", "buffer", "window", "line", "range");
2104071d4279SBram Moolenaar     else
2105071d4279SBram Moolenaar     {
2106071d4279SBram Moolenaar 	PyErr_SetString(PyExc_AttributeError, name);
2107071d4279SBram Moolenaar 	return NULL;
2108071d4279SBram Moolenaar     }
2109071d4279SBram Moolenaar }
2110071d4279SBram Moolenaar 
2111071d4279SBram Moolenaar     static int
21124bdbbf70SBram Moolenaar CurrentSetattr(PyObject *self UNUSED, char *name, PyObject *value)
2113071d4279SBram Moolenaar {
2114071d4279SBram Moolenaar     if (strcmp(name, "line") == 0)
2115071d4279SBram Moolenaar     {
2116e7cb9cf6SBram Moolenaar 	if (SetBufferLine(curbuf, (PyInt)curwin->w_cursor.lnum, value, NULL) == FAIL)
2117071d4279SBram Moolenaar 	    return -1;
2118071d4279SBram Moolenaar 
2119071d4279SBram Moolenaar 	return 0;
2120071d4279SBram Moolenaar     }
2121071d4279SBram Moolenaar     else
2122071d4279SBram Moolenaar     {
2123071d4279SBram Moolenaar 	PyErr_SetString(PyExc_AttributeError, name);
2124071d4279SBram Moolenaar 	return -1;
2125071d4279SBram Moolenaar     }
2126071d4279SBram Moolenaar }
2127071d4279SBram Moolenaar 
2128071d4279SBram Moolenaar /* External interface
2129071d4279SBram Moolenaar  */
2130071d4279SBram Moolenaar 
2131071d4279SBram Moolenaar     void
2132071d4279SBram Moolenaar python_buffer_free(buf_T *buf)
2133071d4279SBram Moolenaar {
2134e344beadSBram Moolenaar     if (buf->b_python_ref != NULL)
2135071d4279SBram Moolenaar     {
2136e344beadSBram Moolenaar 	BufferObject *bp = buf->b_python_ref;
2137071d4279SBram Moolenaar 	bp->buf = INVALID_BUFFER_VALUE;
2138e344beadSBram Moolenaar 	buf->b_python_ref = NULL;
2139071d4279SBram Moolenaar     }
2140071d4279SBram Moolenaar }
2141071d4279SBram Moolenaar 
2142071d4279SBram Moolenaar #if defined(FEAT_WINDOWS) || defined(PROTO)
2143071d4279SBram Moolenaar     void
2144071d4279SBram Moolenaar python_window_free(win_T *win)
2145071d4279SBram Moolenaar {
2146e344beadSBram Moolenaar     if (win->w_python_ref != NULL)
2147071d4279SBram Moolenaar     {
2148e344beadSBram Moolenaar 	WindowObject *wp = win->w_python_ref;
2149071d4279SBram Moolenaar 	wp->win = INVALID_WINDOW_VALUE;
2150e344beadSBram Moolenaar 	win->w_python_ref = NULL;
2151071d4279SBram Moolenaar     }
2152071d4279SBram Moolenaar }
2153071d4279SBram Moolenaar #endif
2154071d4279SBram Moolenaar 
2155071d4279SBram Moolenaar static BufListObject TheBufferList =
2156071d4279SBram Moolenaar {
2157071d4279SBram Moolenaar     PyObject_HEAD_INIT(&BufListType)
2158071d4279SBram Moolenaar };
2159071d4279SBram Moolenaar 
2160071d4279SBram Moolenaar static WinListObject TheWindowList =
2161071d4279SBram Moolenaar {
2162071d4279SBram Moolenaar     PyObject_HEAD_INIT(&WinListType)
2163071d4279SBram Moolenaar };
2164071d4279SBram Moolenaar 
2165071d4279SBram Moolenaar static CurrentObject TheCurrent =
2166071d4279SBram Moolenaar {
2167071d4279SBram Moolenaar     PyObject_HEAD_INIT(&CurrentType)
2168071d4279SBram Moolenaar };
2169071d4279SBram Moolenaar 
2170071d4279SBram Moolenaar     static int
2171071d4279SBram Moolenaar PythonMod_Init(void)
2172071d4279SBram Moolenaar {
2173071d4279SBram Moolenaar     PyObject *mod;
2174071d4279SBram Moolenaar     PyObject *dict;
21759774ecc8SBram Moolenaar     /* The special value is removed from sys.path in Python_Init(). */
21769774ecc8SBram Moolenaar     static char *(argv[2]) = {"/must>not&exist/foo", NULL};
2177071d4279SBram Moolenaar 
2178071d4279SBram Moolenaar     /* Fixups... */
2179071d4279SBram Moolenaar     BufferType.ob_type = &PyType_Type;
2180071d4279SBram Moolenaar     RangeType.ob_type = &PyType_Type;
2181071d4279SBram Moolenaar     WindowType.ob_type = &PyType_Type;
2182071d4279SBram Moolenaar     BufListType.ob_type = &PyType_Type;
2183071d4279SBram Moolenaar     WinListType.ob_type = &PyType_Type;
2184071d4279SBram Moolenaar     CurrentType.ob_type = &PyType_Type;
2185071d4279SBram Moolenaar 
2186071d4279SBram Moolenaar     /* Set sys.argv[] to avoid a crash in warn(). */
2187071d4279SBram Moolenaar     PySys_SetArgv(1, argv);
2188071d4279SBram Moolenaar 
2189e7cb9cf6SBram Moolenaar     mod = Py_InitModule4("vim", VimMethods, (char *)NULL, (PyObject *)NULL, PYTHON_API_VERSION);
2190071d4279SBram Moolenaar     dict = PyModule_GetDict(mod);
2191071d4279SBram Moolenaar 
2192071d4279SBram Moolenaar     VimError = Py_BuildValue("s", "vim.error");
2193071d4279SBram Moolenaar 
2194071d4279SBram Moolenaar     PyDict_SetItemString(dict, "error", VimError);
21957df2d662SBram Moolenaar     PyDict_SetItemString(dict, "buffers", (PyObject *)(void *)&TheBufferList);
21967df2d662SBram Moolenaar     PyDict_SetItemString(dict, "current", (PyObject *)(void *)&TheCurrent);
21977df2d662SBram Moolenaar     PyDict_SetItemString(dict, "windows", (PyObject *)(void *)&TheWindowList);
2198071d4279SBram Moolenaar 
2199071d4279SBram Moolenaar     if (PyErr_Occurred())
2200071d4279SBram Moolenaar 	return -1;
2201071d4279SBram Moolenaar 
2202071d4279SBram Moolenaar     return 0;
2203071d4279SBram Moolenaar }
2204071d4279SBram Moolenaar 
2205071d4279SBram Moolenaar /*************************************************************************
2206071d4279SBram Moolenaar  * 4. Utility functions for handling the interface between Vim and Python.
2207071d4279SBram Moolenaar  */
2208071d4279SBram Moolenaar 
2209071d4279SBram Moolenaar /* Get a line from the specified buffer. The line number is
2210071d4279SBram Moolenaar  * in Vim format (1-based). The line is returned as a Python
2211071d4279SBram Moolenaar  * string object.
2212071d4279SBram Moolenaar  */
2213071d4279SBram Moolenaar     static PyObject *
2214e7cb9cf6SBram Moolenaar GetBufferLine(buf_T *buf, PyInt n)
2215071d4279SBram Moolenaar {
2216071d4279SBram Moolenaar     return LineToString((char *)ml_get_buf(buf, (linenr_T)n, FALSE));
2217071d4279SBram Moolenaar }
2218071d4279SBram Moolenaar 
2219071d4279SBram Moolenaar /* Get a list of lines from the specified buffer. The line numbers
2220071d4279SBram Moolenaar  * are in Vim format (1-based). The range is from lo up to, but not
2221071d4279SBram Moolenaar  * including, hi. The list is returned as a Python list of string objects.
2222071d4279SBram Moolenaar  */
2223071d4279SBram Moolenaar     static PyObject *
22242c45e945SBram Moolenaar GetBufferLineList(buf_T *buf, PyInt lo, PyInt hi)
2225071d4279SBram Moolenaar {
22262c45e945SBram Moolenaar     PyInt i;
22272c45e945SBram Moolenaar     PyInt n = hi - lo;
2228071d4279SBram Moolenaar     PyObject *list = PyList_New(n);
2229071d4279SBram Moolenaar 
2230071d4279SBram Moolenaar     if (list == NULL)
2231071d4279SBram Moolenaar 	return NULL;
2232071d4279SBram Moolenaar 
2233071d4279SBram Moolenaar     for (i = 0; i < n; ++i)
2234071d4279SBram Moolenaar     {
2235071d4279SBram Moolenaar 	PyObject *str = LineToString((char *)ml_get_buf(buf, (linenr_T)(lo+i), FALSE));
2236071d4279SBram Moolenaar 
2237071d4279SBram Moolenaar 	/* Error check - was the Python string creation OK? */
2238071d4279SBram Moolenaar 	if (str == NULL)
2239071d4279SBram Moolenaar 	{
2240071d4279SBram Moolenaar 	    Py_DECREF(list);
2241071d4279SBram Moolenaar 	    return NULL;
2242071d4279SBram Moolenaar 	}
2243071d4279SBram Moolenaar 
2244071d4279SBram Moolenaar 	/* Set the list item */
2245071d4279SBram Moolenaar 	if (PyList_SetItem(list, i, str))
2246071d4279SBram Moolenaar 	{
2247071d4279SBram Moolenaar 	    Py_DECREF(str);
2248071d4279SBram Moolenaar 	    Py_DECREF(list);
2249071d4279SBram Moolenaar 	    return NULL;
2250071d4279SBram Moolenaar 	}
2251071d4279SBram Moolenaar     }
2252071d4279SBram Moolenaar 
2253071d4279SBram Moolenaar     /* The ownership of the Python list is passed to the caller (ie,
2254071d4279SBram Moolenaar      * the caller should Py_DECREF() the object when it is finished
2255071d4279SBram Moolenaar      * with it).
2256071d4279SBram Moolenaar      */
2257071d4279SBram Moolenaar 
2258071d4279SBram Moolenaar     return list;
2259071d4279SBram Moolenaar }
2260071d4279SBram Moolenaar 
2261071d4279SBram Moolenaar /*
2262071d4279SBram Moolenaar  * Check if deleting lines made the cursor position invalid.
2263071d4279SBram Moolenaar  * Changed the lines from "lo" to "hi" and added "extra" lines (negative if
2264071d4279SBram Moolenaar  * deleted).
2265071d4279SBram Moolenaar  */
2266071d4279SBram Moolenaar     static void
2267e7cb9cf6SBram Moolenaar py_fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
2268071d4279SBram Moolenaar {
2269071d4279SBram Moolenaar     if (curwin->w_cursor.lnum >= lo)
2270071d4279SBram Moolenaar     {
2271071d4279SBram Moolenaar 	/* Adjust the cursor position if it's in/after the changed
2272071d4279SBram Moolenaar 	 * lines. */
2273071d4279SBram Moolenaar 	if (curwin->w_cursor.lnum >= hi)
2274071d4279SBram Moolenaar 	{
2275071d4279SBram Moolenaar 	    curwin->w_cursor.lnum += extra;
2276071d4279SBram Moolenaar 	    check_cursor_col();
2277071d4279SBram Moolenaar 	}
2278071d4279SBram Moolenaar 	else if (extra < 0)
2279071d4279SBram Moolenaar 	{
2280071d4279SBram Moolenaar 	    curwin->w_cursor.lnum = lo;
2281071d4279SBram Moolenaar 	    check_cursor();
2282071d4279SBram Moolenaar 	}
2283454ec05aSBram Moolenaar 	else
2284454ec05aSBram Moolenaar 	    check_cursor_col();
2285071d4279SBram Moolenaar 	changed_cline_bef_curs();
2286071d4279SBram Moolenaar     }
2287071d4279SBram Moolenaar     invalidate_botline();
2288071d4279SBram Moolenaar }
2289071d4279SBram Moolenaar 
2290071d4279SBram Moolenaar /* Replace a line in the specified buffer. The line number is
2291071d4279SBram Moolenaar  * in Vim format (1-based). The replacement line is given as
2292071d4279SBram Moolenaar  * a Python string object. The object is checked for validity
2293071d4279SBram Moolenaar  * and correct format. Errors are returned as a value of FAIL.
2294071d4279SBram Moolenaar  * The return value is OK on success.
2295071d4279SBram Moolenaar  * If OK is returned and len_change is not NULL, *len_change
2296071d4279SBram Moolenaar  * is set to the change in the buffer length.
2297071d4279SBram Moolenaar  */
2298071d4279SBram Moolenaar     static int
2299e7cb9cf6SBram Moolenaar SetBufferLine(buf_T *buf, PyInt n, PyObject *line, PyInt *len_change)
2300071d4279SBram Moolenaar {
2301071d4279SBram Moolenaar     /* First of all, we check the thpe of the supplied Python object.
2302071d4279SBram Moolenaar      * There are three cases:
2303071d4279SBram Moolenaar      *	  1. NULL, or None - this is a deletion.
2304071d4279SBram Moolenaar      *	  2. A string	   - this is a replacement.
2305071d4279SBram Moolenaar      *	  3. Anything else - this is an error.
2306071d4279SBram Moolenaar      */
2307071d4279SBram Moolenaar     if (line == Py_None || line == NULL)
2308071d4279SBram Moolenaar     {
2309071d4279SBram Moolenaar 	buf_T *savebuf = curbuf;
2310071d4279SBram Moolenaar 
2311071d4279SBram Moolenaar 	PyErr_Clear();
2312071d4279SBram Moolenaar 	curbuf = buf;
2313071d4279SBram Moolenaar 
2314071d4279SBram Moolenaar 	if (u_savedel((linenr_T)n, 1L) == FAIL)
2315071d4279SBram Moolenaar 	    PyErr_SetVim(_("cannot save undo information"));
2316071d4279SBram Moolenaar 	else if (ml_delete((linenr_T)n, FALSE) == FAIL)
2317071d4279SBram Moolenaar 	    PyErr_SetVim(_("cannot delete line"));
2318071d4279SBram Moolenaar 	else
2319071d4279SBram Moolenaar 	{
2320071d4279SBram Moolenaar 	    if (buf == curwin->w_buffer)
2321e7cb9cf6SBram Moolenaar 		py_fix_cursor((linenr_T)n, (linenr_T)n + 1, (linenr_T)-1);
2322cdcaa589SBram Moolenaar 	    deleted_lines_mark((linenr_T)n, 1L);
2323071d4279SBram Moolenaar 	}
2324071d4279SBram Moolenaar 
2325071d4279SBram Moolenaar 	curbuf = savebuf;
2326071d4279SBram Moolenaar 
2327071d4279SBram Moolenaar 	if (PyErr_Occurred() || VimErrorCheck())
2328071d4279SBram Moolenaar 	    return FAIL;
2329071d4279SBram Moolenaar 
2330071d4279SBram Moolenaar 	if (len_change)
2331071d4279SBram Moolenaar 	    *len_change = -1;
2332071d4279SBram Moolenaar 
2333071d4279SBram Moolenaar 	return OK;
2334071d4279SBram Moolenaar     }
2335071d4279SBram Moolenaar     else if (PyString_Check(line))
2336071d4279SBram Moolenaar     {
2337071d4279SBram Moolenaar 	char *save = StringToLine(line);
2338071d4279SBram Moolenaar 	buf_T *savebuf = curbuf;
2339071d4279SBram Moolenaar 
2340071d4279SBram Moolenaar 	if (save == NULL)
2341071d4279SBram Moolenaar 	    return FAIL;
2342071d4279SBram Moolenaar 
2343071d4279SBram Moolenaar 	/* We do not need to free "save" if ml_replace() consumes it. */
2344071d4279SBram Moolenaar 	PyErr_Clear();
2345071d4279SBram Moolenaar 	curbuf = buf;
2346071d4279SBram Moolenaar 
2347071d4279SBram Moolenaar 	if (u_savesub((linenr_T)n) == FAIL)
2348071d4279SBram Moolenaar 	{
2349071d4279SBram Moolenaar 	    PyErr_SetVim(_("cannot save undo information"));
2350071d4279SBram Moolenaar 	    vim_free(save);
2351071d4279SBram Moolenaar 	}
2352071d4279SBram Moolenaar 	else if (ml_replace((linenr_T)n, (char_u *)save, FALSE) == FAIL)
2353071d4279SBram Moolenaar 	{
2354071d4279SBram Moolenaar 	    PyErr_SetVim(_("cannot replace line"));
2355071d4279SBram Moolenaar 	    vim_free(save);
2356071d4279SBram Moolenaar 	}
2357071d4279SBram Moolenaar 	else
2358071d4279SBram Moolenaar 	    changed_bytes((linenr_T)n, 0);
2359071d4279SBram Moolenaar 
2360071d4279SBram Moolenaar 	curbuf = savebuf;
2361071d4279SBram Moolenaar 
2362454ec05aSBram Moolenaar 	/* Check that the cursor is not beyond the end of the line now. */
2363454ec05aSBram Moolenaar 	if (buf == curwin->w_buffer)
2364454ec05aSBram Moolenaar 	    check_cursor_col();
2365454ec05aSBram Moolenaar 
2366071d4279SBram Moolenaar 	if (PyErr_Occurred() || VimErrorCheck())
2367071d4279SBram Moolenaar 	    return FAIL;
2368071d4279SBram Moolenaar 
2369071d4279SBram Moolenaar 	if (len_change)
2370071d4279SBram Moolenaar 	    *len_change = 0;
2371071d4279SBram Moolenaar 
2372071d4279SBram Moolenaar 	return OK;
2373071d4279SBram Moolenaar     }
2374071d4279SBram Moolenaar     else
2375071d4279SBram Moolenaar     {
2376071d4279SBram Moolenaar 	PyErr_BadArgument();
2377071d4279SBram Moolenaar 	return FAIL;
2378071d4279SBram Moolenaar     }
2379071d4279SBram Moolenaar }
2380071d4279SBram Moolenaar 
2381071d4279SBram Moolenaar /* Replace a range of lines in the specified buffer. The line numbers are in
2382071d4279SBram Moolenaar  * Vim format (1-based). The range is from lo up to, but not including, hi.
2383071d4279SBram Moolenaar  * The replacement lines are given as a Python list of string objects. The
2384071d4279SBram Moolenaar  * list is checked for validity and correct format. Errors are returned as a
2385071d4279SBram Moolenaar  * value of FAIL.  The return value is OK on success.
2386071d4279SBram Moolenaar  * If OK is returned and len_change is not NULL, *len_change
2387071d4279SBram Moolenaar  * is set to the change in the buffer length.
2388071d4279SBram Moolenaar  */
2389071d4279SBram Moolenaar     static int
2390e7cb9cf6SBram Moolenaar SetBufferLineList(buf_T *buf, PyInt lo, PyInt hi, PyObject *list, PyInt *len_change)
2391071d4279SBram Moolenaar {
2392071d4279SBram Moolenaar     /* First of all, we check the thpe of the supplied Python object.
2393071d4279SBram Moolenaar      * There are three cases:
2394071d4279SBram Moolenaar      *	  1. NULL, or None - this is a deletion.
2395071d4279SBram Moolenaar      *	  2. A list	   - this is a replacement.
2396071d4279SBram Moolenaar      *	  3. Anything else - this is an error.
2397071d4279SBram Moolenaar      */
2398071d4279SBram Moolenaar     if (list == Py_None || list == NULL)
2399071d4279SBram Moolenaar     {
24002c45e945SBram Moolenaar 	PyInt	i;
2401e7cb9cf6SBram Moolenaar 	PyInt	n = (int)(hi - lo);
2402071d4279SBram Moolenaar 	buf_T	*savebuf = curbuf;
2403071d4279SBram Moolenaar 
2404071d4279SBram Moolenaar 	PyErr_Clear();
2405071d4279SBram Moolenaar 	curbuf = buf;
2406071d4279SBram Moolenaar 
2407071d4279SBram Moolenaar 	if (u_savedel((linenr_T)lo, (long)n) == FAIL)
2408071d4279SBram Moolenaar 	    PyErr_SetVim(_("cannot save undo information"));
2409071d4279SBram Moolenaar 	else
2410071d4279SBram Moolenaar 	{
2411071d4279SBram Moolenaar 	    for (i = 0; i < n; ++i)
2412071d4279SBram Moolenaar 	    {
2413071d4279SBram Moolenaar 		if (ml_delete((linenr_T)lo, FALSE) == FAIL)
2414071d4279SBram Moolenaar 		{
2415071d4279SBram Moolenaar 		    PyErr_SetVim(_("cannot delete line"));
2416071d4279SBram Moolenaar 		    break;
2417071d4279SBram Moolenaar 		}
2418071d4279SBram Moolenaar 	    }
2419071d4279SBram Moolenaar 	    if (buf == curwin->w_buffer)
2420e7cb9cf6SBram Moolenaar 		py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)-n);
2421cdcaa589SBram Moolenaar 	    deleted_lines_mark((linenr_T)lo, (long)i);
2422071d4279SBram Moolenaar 	}
2423071d4279SBram Moolenaar 
2424071d4279SBram Moolenaar 	curbuf = savebuf;
2425071d4279SBram Moolenaar 
2426071d4279SBram Moolenaar 	if (PyErr_Occurred() || VimErrorCheck())
2427071d4279SBram Moolenaar 	    return FAIL;
2428071d4279SBram Moolenaar 
2429071d4279SBram Moolenaar 	if (len_change)
2430071d4279SBram Moolenaar 	    *len_change = -n;
2431071d4279SBram Moolenaar 
2432071d4279SBram Moolenaar 	return OK;
2433071d4279SBram Moolenaar     }
2434071d4279SBram Moolenaar     else if (PyList_Check(list))
2435071d4279SBram Moolenaar     {
24362c45e945SBram Moolenaar 	PyInt	i;
24372c45e945SBram Moolenaar 	PyInt	new_len = PyList_Size(list);
24382c45e945SBram Moolenaar 	PyInt	old_len = hi - lo;
2439e7cb9cf6SBram Moolenaar 	PyInt	extra = 0;	/* lines added to text, can be negative */
2440071d4279SBram Moolenaar 	char	**array;
2441071d4279SBram Moolenaar 	buf_T	*savebuf;
2442071d4279SBram Moolenaar 
2443071d4279SBram Moolenaar 	if (new_len == 0)	/* avoid allocating zero bytes */
2444071d4279SBram Moolenaar 	    array = NULL;
2445071d4279SBram Moolenaar 	else
2446071d4279SBram Moolenaar 	{
2447071d4279SBram Moolenaar 	    array = (char **)alloc((unsigned)(new_len * sizeof(char *)));
2448071d4279SBram Moolenaar 	    if (array == NULL)
2449071d4279SBram Moolenaar 	    {
2450071d4279SBram Moolenaar 		PyErr_NoMemory();
2451071d4279SBram Moolenaar 		return FAIL;
2452071d4279SBram Moolenaar 	    }
2453071d4279SBram Moolenaar 	}
2454071d4279SBram Moolenaar 
2455071d4279SBram Moolenaar 	for (i = 0; i < new_len; ++i)
2456071d4279SBram Moolenaar 	{
2457071d4279SBram Moolenaar 	    PyObject *line = PyList_GetItem(list, i);
2458071d4279SBram Moolenaar 
2459071d4279SBram Moolenaar 	    array[i] = StringToLine(line);
2460071d4279SBram Moolenaar 	    if (array[i] == NULL)
2461071d4279SBram Moolenaar 	    {
2462071d4279SBram Moolenaar 		while (i)
2463071d4279SBram Moolenaar 		    vim_free(array[--i]);
2464071d4279SBram Moolenaar 		vim_free(array);
2465071d4279SBram Moolenaar 		return FAIL;
2466071d4279SBram Moolenaar 	    }
2467071d4279SBram Moolenaar 	}
2468071d4279SBram Moolenaar 
2469071d4279SBram Moolenaar 	savebuf = curbuf;
2470071d4279SBram Moolenaar 
2471071d4279SBram Moolenaar 	PyErr_Clear();
2472071d4279SBram Moolenaar 	curbuf = buf;
2473071d4279SBram Moolenaar 
2474071d4279SBram Moolenaar 	if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL)
2475071d4279SBram Moolenaar 	    PyErr_SetVim(_("cannot save undo information"));
2476071d4279SBram Moolenaar 
2477071d4279SBram Moolenaar 	/* If the size of the range is reducing (ie, new_len < old_len) we
2478071d4279SBram Moolenaar 	 * need to delete some old_len. We do this at the start, by
2479071d4279SBram Moolenaar 	 * repeatedly deleting line "lo".
2480071d4279SBram Moolenaar 	 */
2481071d4279SBram Moolenaar 	if (!PyErr_Occurred())
2482071d4279SBram Moolenaar 	{
2483071d4279SBram Moolenaar 	    for (i = 0; i < old_len - new_len; ++i)
2484071d4279SBram Moolenaar 		if (ml_delete((linenr_T)lo, FALSE) == FAIL)
2485071d4279SBram Moolenaar 		{
2486071d4279SBram Moolenaar 		    PyErr_SetVim(_("cannot delete line"));
2487071d4279SBram Moolenaar 		    break;
2488071d4279SBram Moolenaar 		}
2489071d4279SBram Moolenaar 	    extra -= i;
2490071d4279SBram Moolenaar 	}
2491071d4279SBram Moolenaar 
2492071d4279SBram Moolenaar 	/* For as long as possible, replace the existing old_len with the
2493071d4279SBram Moolenaar 	 * new old_len. This is a more efficient operation, as it requires
2494071d4279SBram Moolenaar 	 * less memory allocation and freeing.
2495071d4279SBram Moolenaar 	 */
2496071d4279SBram Moolenaar 	if (!PyErr_Occurred())
2497071d4279SBram Moolenaar 	{
2498071d4279SBram Moolenaar 	    for (i = 0; i < old_len && i < new_len; ++i)
2499071d4279SBram Moolenaar 		if (ml_replace((linenr_T)(lo+i), (char_u *)array[i], FALSE)
2500071d4279SBram Moolenaar 								      == FAIL)
2501071d4279SBram Moolenaar 		{
2502071d4279SBram Moolenaar 		    PyErr_SetVim(_("cannot replace line"));
2503071d4279SBram Moolenaar 		    break;
2504071d4279SBram Moolenaar 		}
2505071d4279SBram Moolenaar 	}
2506071d4279SBram Moolenaar 	else
2507071d4279SBram Moolenaar 	    i = 0;
2508071d4279SBram Moolenaar 
2509071d4279SBram Moolenaar 	/* Now we may need to insert the remaining new old_len. If we do, we
2510071d4279SBram Moolenaar 	 * must free the strings as we finish with them (we can't pass the
2511071d4279SBram Moolenaar 	 * responsibility to vim in this case).
2512071d4279SBram Moolenaar 	 */
2513071d4279SBram Moolenaar 	if (!PyErr_Occurred())
2514071d4279SBram Moolenaar 	{
2515071d4279SBram Moolenaar 	    while (i < new_len)
2516071d4279SBram Moolenaar 	    {
2517071d4279SBram Moolenaar 		if (ml_append((linenr_T)(lo + i - 1),
2518071d4279SBram Moolenaar 					(char_u *)array[i], 0, FALSE) == FAIL)
2519071d4279SBram Moolenaar 		{
2520071d4279SBram Moolenaar 		    PyErr_SetVim(_("cannot insert line"));
2521071d4279SBram Moolenaar 		    break;
2522071d4279SBram Moolenaar 		}
2523071d4279SBram Moolenaar 		vim_free(array[i]);
2524071d4279SBram Moolenaar 		++i;
2525071d4279SBram Moolenaar 		++extra;
2526071d4279SBram Moolenaar 	    }
2527071d4279SBram Moolenaar 	}
2528071d4279SBram Moolenaar 
2529071d4279SBram Moolenaar 	/* Free any left-over old_len, as a result of an error */
2530071d4279SBram Moolenaar 	while (i < new_len)
2531071d4279SBram Moolenaar 	{
2532071d4279SBram Moolenaar 	    vim_free(array[i]);
2533071d4279SBram Moolenaar 	    ++i;
2534071d4279SBram Moolenaar 	}
2535071d4279SBram Moolenaar 
2536071d4279SBram Moolenaar 	/* Free the array of old_len. All of its contents have now
2537071d4279SBram Moolenaar 	 * been dealt with (either freed, or the responsibility passed
2538071d4279SBram Moolenaar 	 * to vim.
2539071d4279SBram Moolenaar 	 */
2540071d4279SBram Moolenaar 	vim_free(array);
2541071d4279SBram Moolenaar 
2542071d4279SBram Moolenaar 	/* Adjust marks. Invalidate any which lie in the
2543071d4279SBram Moolenaar 	 * changed range, and move any in the remainder of the buffer.
2544071d4279SBram Moolenaar 	 */
2545071d4279SBram Moolenaar 	mark_adjust((linenr_T)lo, (linenr_T)(hi - 1),
2546071d4279SBram Moolenaar 						  (long)MAXLNUM, (long)extra);
2547071d4279SBram Moolenaar 	changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra);
2548071d4279SBram Moolenaar 
2549071d4279SBram Moolenaar 	if (buf == curwin->w_buffer)
2550e7cb9cf6SBram Moolenaar 	    py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)extra);
2551071d4279SBram Moolenaar 
2552071d4279SBram Moolenaar 	curbuf = savebuf;
2553071d4279SBram Moolenaar 
2554071d4279SBram Moolenaar 	if (PyErr_Occurred() || VimErrorCheck())
2555071d4279SBram Moolenaar 	    return FAIL;
2556071d4279SBram Moolenaar 
2557071d4279SBram Moolenaar 	if (len_change)
2558071d4279SBram Moolenaar 	    *len_change = new_len - old_len;
2559071d4279SBram Moolenaar 
2560071d4279SBram Moolenaar 	return OK;
2561071d4279SBram Moolenaar     }
2562071d4279SBram Moolenaar     else
2563071d4279SBram Moolenaar     {
2564071d4279SBram Moolenaar 	PyErr_BadArgument();
2565071d4279SBram Moolenaar 	return FAIL;
2566071d4279SBram Moolenaar     }
2567071d4279SBram Moolenaar }
2568071d4279SBram Moolenaar 
2569071d4279SBram Moolenaar /* Insert a number of lines into the specified buffer after the specifed line.
2570071d4279SBram Moolenaar  * The line number is in Vim format (1-based). The lines to be inserted are
2571071d4279SBram Moolenaar  * given as a Python list of string objects or as a single string. The lines
2572071d4279SBram Moolenaar  * to be added are checked for validity and correct format. Errors are
2573071d4279SBram Moolenaar  * returned as a value of FAIL.  The return value is OK on success.
2574071d4279SBram Moolenaar  * If OK is returned and len_change is not NULL, *len_change
2575071d4279SBram Moolenaar  * is set to the change in the buffer length.
2576071d4279SBram Moolenaar  */
2577071d4279SBram Moolenaar     static int
2578e7cb9cf6SBram Moolenaar InsertBufferLines(buf_T *buf, PyInt n, PyObject *lines, PyInt *len_change)
2579071d4279SBram Moolenaar {
2580071d4279SBram Moolenaar     /* First of all, we check the type of the supplied Python object.
2581071d4279SBram Moolenaar      * It must be a string or a list, or the call is in error.
2582071d4279SBram Moolenaar      */
2583071d4279SBram Moolenaar     if (PyString_Check(lines))
2584071d4279SBram Moolenaar     {
2585071d4279SBram Moolenaar 	char	*str = StringToLine(lines);
2586071d4279SBram Moolenaar 	buf_T	*savebuf;
2587071d4279SBram Moolenaar 
2588071d4279SBram Moolenaar 	if (str == NULL)
2589071d4279SBram Moolenaar 	    return FAIL;
2590071d4279SBram Moolenaar 
2591071d4279SBram Moolenaar 	savebuf = curbuf;
2592071d4279SBram Moolenaar 
2593071d4279SBram Moolenaar 	PyErr_Clear();
2594071d4279SBram Moolenaar 	curbuf = buf;
2595071d4279SBram Moolenaar 
2596071d4279SBram Moolenaar 	if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL)
2597071d4279SBram Moolenaar 	    PyErr_SetVim(_("cannot save undo information"));
2598071d4279SBram Moolenaar 	else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL)
2599071d4279SBram Moolenaar 	    PyErr_SetVim(_("cannot insert line"));
2600071d4279SBram Moolenaar 	else
2601071d4279SBram Moolenaar 	    appended_lines_mark((linenr_T)n, 1L);
2602071d4279SBram Moolenaar 
2603071d4279SBram Moolenaar 	vim_free(str);
2604071d4279SBram Moolenaar 	curbuf = savebuf;
2605071d4279SBram Moolenaar 	update_screen(VALID);
2606071d4279SBram Moolenaar 
2607071d4279SBram Moolenaar 	if (PyErr_Occurred() || VimErrorCheck())
2608071d4279SBram Moolenaar 	    return FAIL;
2609071d4279SBram Moolenaar 
2610071d4279SBram Moolenaar 	if (len_change)
2611071d4279SBram Moolenaar 	    *len_change = 1;
2612071d4279SBram Moolenaar 
2613071d4279SBram Moolenaar 	return OK;
2614071d4279SBram Moolenaar     }
2615071d4279SBram Moolenaar     else if (PyList_Check(lines))
2616071d4279SBram Moolenaar     {
26172c45e945SBram Moolenaar 	PyInt	i;
26182c45e945SBram Moolenaar 	PyInt	size = PyList_Size(lines);
2619071d4279SBram Moolenaar 	char	**array;
2620071d4279SBram Moolenaar 	buf_T	*savebuf;
2621071d4279SBram Moolenaar 
2622071d4279SBram Moolenaar 	array = (char **)alloc((unsigned)(size * sizeof(char *)));
2623071d4279SBram Moolenaar 	if (array == NULL)
2624071d4279SBram Moolenaar 	{
2625071d4279SBram Moolenaar 	    PyErr_NoMemory();
2626071d4279SBram Moolenaar 	    return FAIL;
2627071d4279SBram Moolenaar 	}
2628071d4279SBram Moolenaar 
2629071d4279SBram Moolenaar 	for (i = 0; i < size; ++i)
2630071d4279SBram Moolenaar 	{
2631071d4279SBram Moolenaar 	    PyObject *line = PyList_GetItem(lines, i);
2632071d4279SBram Moolenaar 	    array[i] = StringToLine(line);
2633071d4279SBram Moolenaar 
2634071d4279SBram Moolenaar 	    if (array[i] == NULL)
2635071d4279SBram Moolenaar 	    {
2636071d4279SBram Moolenaar 		while (i)
2637071d4279SBram Moolenaar 		    vim_free(array[--i]);
2638071d4279SBram Moolenaar 		vim_free(array);
2639071d4279SBram Moolenaar 		return FAIL;
2640071d4279SBram Moolenaar 	    }
2641071d4279SBram Moolenaar 	}
2642071d4279SBram Moolenaar 
2643071d4279SBram Moolenaar 	savebuf = curbuf;
2644071d4279SBram Moolenaar 
2645071d4279SBram Moolenaar 	PyErr_Clear();
2646071d4279SBram Moolenaar 	curbuf = buf;
2647071d4279SBram Moolenaar 
2648071d4279SBram Moolenaar 	if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL)
2649071d4279SBram Moolenaar 	    PyErr_SetVim(_("cannot save undo information"));
2650071d4279SBram Moolenaar 	else
2651071d4279SBram Moolenaar 	{
2652071d4279SBram Moolenaar 	    for (i = 0; i < size; ++i)
2653071d4279SBram Moolenaar 	    {
2654071d4279SBram Moolenaar 		if (ml_append((linenr_T)(n + i),
2655071d4279SBram Moolenaar 					(char_u *)array[i], 0, FALSE) == FAIL)
2656071d4279SBram Moolenaar 		{
2657071d4279SBram Moolenaar 		    PyErr_SetVim(_("cannot insert line"));
2658071d4279SBram Moolenaar 
2659071d4279SBram Moolenaar 		    /* Free the rest of the lines */
2660071d4279SBram Moolenaar 		    while (i < size)
2661071d4279SBram Moolenaar 			vim_free(array[i++]);
2662071d4279SBram Moolenaar 
2663071d4279SBram Moolenaar 		    break;
2664071d4279SBram Moolenaar 		}
2665071d4279SBram Moolenaar 		vim_free(array[i]);
2666071d4279SBram Moolenaar 	    }
2667071d4279SBram Moolenaar 	    if (i > 0)
2668071d4279SBram Moolenaar 		appended_lines_mark((linenr_T)n, (long)i);
2669071d4279SBram Moolenaar 	}
2670071d4279SBram Moolenaar 
2671071d4279SBram Moolenaar 	/* Free the array of lines. All of its contents have now
2672071d4279SBram Moolenaar 	 * been freed.
2673071d4279SBram Moolenaar 	 */
2674071d4279SBram Moolenaar 	vim_free(array);
2675071d4279SBram Moolenaar 
2676071d4279SBram Moolenaar 	curbuf = savebuf;
2677071d4279SBram Moolenaar 	update_screen(VALID);
2678071d4279SBram Moolenaar 
2679071d4279SBram Moolenaar 	if (PyErr_Occurred() || VimErrorCheck())
2680071d4279SBram Moolenaar 	    return FAIL;
2681071d4279SBram Moolenaar 
2682071d4279SBram Moolenaar 	if (len_change)
2683071d4279SBram Moolenaar 	    *len_change = size;
2684071d4279SBram Moolenaar 
2685071d4279SBram Moolenaar 	return OK;
2686071d4279SBram Moolenaar     }
2687071d4279SBram Moolenaar     else
2688071d4279SBram Moolenaar     {
2689071d4279SBram Moolenaar 	PyErr_BadArgument();
2690071d4279SBram Moolenaar 	return FAIL;
2691071d4279SBram Moolenaar     }
2692071d4279SBram Moolenaar }
2693071d4279SBram Moolenaar 
2694071d4279SBram Moolenaar /* Convert a Vim line into a Python string.
2695071d4279SBram Moolenaar  * All internal newlines are replaced by null characters.
2696071d4279SBram Moolenaar  *
2697071d4279SBram Moolenaar  * On errors, the Python exception data is set, and NULL is returned.
2698071d4279SBram Moolenaar  */
2699071d4279SBram Moolenaar     static PyObject *
2700071d4279SBram Moolenaar LineToString(const char *str)
2701071d4279SBram Moolenaar {
2702071d4279SBram Moolenaar     PyObject *result;
27032c45e945SBram Moolenaar     PyInt len = strlen(str);
2704071d4279SBram Moolenaar     char *p;
2705071d4279SBram Moolenaar 
2706071d4279SBram Moolenaar     /* Allocate an Python string object, with uninitialised contents. We
2707071d4279SBram Moolenaar      * must do it this way, so that we can modify the string in place
2708071d4279SBram Moolenaar      * later. See the Python source, Objects/stringobject.c for details.
2709071d4279SBram Moolenaar      */
2710071d4279SBram Moolenaar     result = PyString_FromStringAndSize(NULL, len);
2711071d4279SBram Moolenaar     if (result == NULL)
2712071d4279SBram Moolenaar 	return NULL;
2713071d4279SBram Moolenaar 
2714071d4279SBram Moolenaar     p = PyString_AsString(result);
2715071d4279SBram Moolenaar 
2716071d4279SBram Moolenaar     while (*str)
2717071d4279SBram Moolenaar     {
2718071d4279SBram Moolenaar 	if (*str == '\n')
2719071d4279SBram Moolenaar 	    *p = '\0';
2720071d4279SBram Moolenaar 	else
2721071d4279SBram Moolenaar 	    *p = *str;
2722071d4279SBram Moolenaar 
2723071d4279SBram Moolenaar 	++p;
2724071d4279SBram Moolenaar 	++str;
2725071d4279SBram Moolenaar     }
2726071d4279SBram Moolenaar 
2727071d4279SBram Moolenaar     return result;
2728071d4279SBram Moolenaar }
2729071d4279SBram Moolenaar 
2730071d4279SBram Moolenaar /* Convert a Python string into a Vim line.
2731071d4279SBram Moolenaar  *
2732071d4279SBram Moolenaar  * The result is in allocated memory. All internal nulls are replaced by
2733071d4279SBram Moolenaar  * newline characters. It is an error for the string to contain newline
2734071d4279SBram Moolenaar  * characters.
2735071d4279SBram Moolenaar  *
2736071d4279SBram Moolenaar  * On errors, the Python exception data is set, and NULL is returned.
2737071d4279SBram Moolenaar  */
2738071d4279SBram Moolenaar     static char *
2739071d4279SBram Moolenaar StringToLine(PyObject *obj)
2740071d4279SBram Moolenaar {
2741071d4279SBram Moolenaar     const char *str;
2742071d4279SBram Moolenaar     char *save;
27432c45e945SBram Moolenaar     PyInt len;
27442c45e945SBram Moolenaar     PyInt i;
27455eb86f91SBram Moolenaar     char *p;
2746071d4279SBram Moolenaar 
2747071d4279SBram Moolenaar     if (obj == NULL || !PyString_Check(obj))
2748071d4279SBram Moolenaar     {
2749071d4279SBram Moolenaar 	PyErr_BadArgument();
2750071d4279SBram Moolenaar 	return NULL;
2751071d4279SBram Moolenaar     }
2752071d4279SBram Moolenaar 
2753071d4279SBram Moolenaar     str = PyString_AsString(obj);
2754071d4279SBram Moolenaar     len = PyString_Size(obj);
2755071d4279SBram Moolenaar 
27565eb86f91SBram Moolenaar     /*
27575eb86f91SBram Moolenaar      * Error checking: String must not contain newlines, as we
2758071d4279SBram Moolenaar      * are replacing a single line, and we must replace it with
2759071d4279SBram Moolenaar      * a single line.
27605eb86f91SBram Moolenaar      * A trailing newline is removed, so that append(f.readlines()) works.
2761071d4279SBram Moolenaar      */
27625eb86f91SBram Moolenaar     p = memchr(str, '\n', len);
27635eb86f91SBram Moolenaar     if (p != NULL)
27645eb86f91SBram Moolenaar     {
27655eb86f91SBram Moolenaar 	if (p == str + len - 1)
27665eb86f91SBram Moolenaar 	    --len;
27675eb86f91SBram Moolenaar 	else
2768071d4279SBram Moolenaar 	{
2769071d4279SBram Moolenaar 	    PyErr_SetVim(_("string cannot contain newlines"));
2770071d4279SBram Moolenaar 	    return NULL;
2771071d4279SBram Moolenaar 	}
27725eb86f91SBram Moolenaar     }
2773071d4279SBram Moolenaar 
2774071d4279SBram Moolenaar     /* Create a copy of the string, with internal nulls replaced by
2775071d4279SBram Moolenaar      * newline characters, as is the vim convention.
2776071d4279SBram Moolenaar      */
2777071d4279SBram Moolenaar     save = (char *)alloc((unsigned)(len+1));
2778071d4279SBram Moolenaar     if (save == NULL)
2779071d4279SBram Moolenaar     {
2780071d4279SBram Moolenaar 	PyErr_NoMemory();
2781071d4279SBram Moolenaar 	return NULL;
2782071d4279SBram Moolenaar     }
2783071d4279SBram Moolenaar 
2784071d4279SBram Moolenaar     for (i = 0; i < len; ++i)
2785071d4279SBram Moolenaar     {
2786071d4279SBram Moolenaar 	if (str[i] == '\0')
2787071d4279SBram Moolenaar 	    save[i] = '\n';
2788071d4279SBram Moolenaar 	else
2789071d4279SBram Moolenaar 	    save[i] = str[i];
2790071d4279SBram Moolenaar     }
2791071d4279SBram Moolenaar 
2792071d4279SBram Moolenaar     save[i] = '\0';
2793071d4279SBram Moolenaar 
2794071d4279SBram Moolenaar     return save;
2795071d4279SBram Moolenaar }
2796071d4279SBram Moolenaar 
2797071d4279SBram Moolenaar 
2798071d4279SBram Moolenaar /* Don't generate a prototype for the next function, it generates an error on
2799071d4279SBram Moolenaar  * newer Python versions. */
2800071d4279SBram Moolenaar #if PYTHON_API_VERSION < 1007 /* Python 1.4 */ && !defined(PROTO)
2801071d4279SBram Moolenaar 
2802071d4279SBram Moolenaar     char *
2803071d4279SBram Moolenaar Py_GetProgramName(void)
2804071d4279SBram Moolenaar {
2805071d4279SBram Moolenaar     return "vim";
2806071d4279SBram Moolenaar }
2807071d4279SBram Moolenaar #endif /* Python 1.4 */
2808*170bf1aeSBram Moolenaar 
2809*170bf1aeSBram Moolenaar     static void
2810*170bf1aeSBram Moolenaar init_structs(void)
2811*170bf1aeSBram Moolenaar {
2812*170bf1aeSBram Moolenaar     vim_memset(&OutputType, 0, sizeof(OutputType));
2813*170bf1aeSBram Moolenaar     OutputType.tp_name = "message";
2814*170bf1aeSBram Moolenaar     OutputType.tp_basicsize = sizeof(OutputObject);
2815*170bf1aeSBram Moolenaar     OutputType.tp_getattr = OutputGetattr;
2816*170bf1aeSBram Moolenaar     OutputType.tp_setattr = OutputSetattr;
2817*170bf1aeSBram Moolenaar }
2818