📄 if_python.c
字号:
/* vi:set ts=8 sts=4 sw=4:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*/
/*
* Python extensions by Paul Moore.
* Changes for Unix by David Leonard.
*
* This consists of four parts:
* 1. Python interpreter main program
* 2. Python output stream: writes output via [e]msg().
* 3. Implementation of the Vim module for Python
* 4. Utility functions for handling the interface between Vim and Python.
*/
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#include <Python.h>
#ifdef macintosh
# include "macglue.h"
#endif
#undef main /* Defined in python.h - aargh */
#undef HAVE_FCNTL_H /* Clash with os_win32.h */
/* Parser flags */
#define single_input 256
#define file_input 257
#define eval_input 258
#include "vim.h"
/******************************************************
* Internal function prototypes.
*/
static int DoPythonCommand(EXARG *, const char *);
static int RangeStart;
static int RangeEnd;
static void PythonIO_Flush(void);
static int PythonIO_Init(void);
static int PythonMod_Init(void);
/* Utility functions for the vim/python interface
* ----------------------------------------------
*/
static PyObject *GetBufferLine(BUF *, int);
static PyObject *GetBufferLineList(BUF *, int, int);
static int SetBufferLine(BUF *, int, PyObject *, int *);
static int SetBufferLineList(BUF *, int, int, PyObject *, int *);
static int InsertBufferLines(BUF *, int, PyObject *, int *);
static PyObject *LineToString(const char *);
static char *StringToLine(PyObject *);
static int VimErrorCheck(void);
#define PyErr_SetVim(str) PyErr_SetString(VimError, str)
/******************************************************
* 1. Python interpreter main program.
*/
static int initialised = 0;
#if PYTHON_API_VERSION < 1007 /* Python 1.4 */
typedef PyObject PyThreadState;
#endif /* Python 1.4 */
static PyThreadState* saved_python_thread = NULL;
/* suspend a thread of the python interpreter
- other threads are allowed to run */
static void Python_SaveThread() {
saved_python_thread = PyEval_SaveThread();
}
/* restore a thread of the python interpreter
- waits for other threads to block */
static void Python_RestoreThread() {
PyEval_RestoreThread( saved_python_thread );
saved_python_thread = NULL;
}
/* obtain a lock on the Vim data structures */
static void Python_Lock_Vim() {
}
/* release a lock on the Vim data structures */
static void Python_Release_Vim() {
}
static int
Python_Init(void)
{
if (!initialised)
{
#ifndef macintosh
Py_Initialize();
#else
PyMac_Initialize();
#endif
if (PythonIO_Init())
goto fail;
if (PythonMod_Init())
goto fail;
/* the first python thread is vim's */
Python_SaveThread();
initialised = 1;
}
return 0;
fail:
/* We call PythonIO_Flush() here to print any Python errors.
* This is OK, as it is possible to call this function even
* if PythonIO_Init() has not completed successfully (it will
* not do anything in this case).
*/
PythonIO_Flush();
return -1;
}
/* External interface
*/
static int
DoPythonCommand(EXARG *eap, const char *cmd)
{
#ifdef macintosh
GrafPtr oldPort;
GetPort (&oldPort);
#endif
if (Python_Init())
return FAIL;
RangeStart = eap->line1;
RangeEnd = eap->line2;
Python_Release_Vim(); /* leave vim */
Python_RestoreThread(); /* enter python */
PyRun_SimpleString((char *)(cmd));
Python_SaveThread(); /* leave python */
Python_Lock_Vim(); /* enter vim */
PythonIO_Flush();
#ifdef macintosh
SetPort (oldPort);
#endif
return OK;
}
int
do_python(EXARG *eap)
{
return DoPythonCommand(eap, (char *)eap->arg);
}
#define BUFFER_SIZE 1024
int
do_pyfile(EXARG *eap)
{
static char buffer[BUFFER_SIZE];
const char *file = (char *)eap->arg;
char *p;
/* Have to do it like this. PyRun_SimpleFile requires you to pass a
* stdio file pointer, but Vim and the Python DLL are compiled with
* different options under Windows, meaning that stdio pointers aren't
* compatible between the two. Yuk.
*
* Put the string "execfile('file')" into buffer. But, we need to
* escape any backslashes or single quotes in the file name, so that
* Python won't mangle the file name.
*/
strcpy(buffer, "execfile('");
p = buffer + 10; /* size of "execfile('" */
while (*file && p < buffer + (BUFFER_SIZE - 3))
{
if (*file == '\\' || *file == '\'')
*p++ = '\\';
*p++ = *file++;
}
/* If we didn't finish the file name, we hit a buffer overflow */
if (*file != '\0')
return FAIL;
/* Put in the terminating "')" and a null */
*p++ = '\'';
*p++ = ')';
*p++ = '\0';
/* Execute the file */
return DoPythonCommand(eap, buffer);
}
/******************************************************
* 2. Python output stream: writes output via [e]msg().
*/
/* Implementation functions
*/
static PyObject *OutputGetattr(PyObject *, char *);
static int OutputSetattr(PyObject *, char *, PyObject *);
static PyObject *OutputWrite(PyObject *, PyObject *);
static PyObject *OutputWritelines(PyObject *, PyObject *);
typedef void (*writefn)(char_u *);
static void writer(writefn fn, char_u *str, int n);
/* Output object definition
*/
typedef struct
{
PyObject_HEAD
long softspace;
long error;
} OutputObject;
static struct PyMethodDef OutputMethods[] = {
/* name, function, calling, documentation */
{"write", OutputWrite, 1, "" },
{"writelines", OutputWritelines, 1, "" },
{ NULL, NULL, 0, NULL }
};
static PyTypeObject OutputType = {
PyObject_HEAD_INIT(0)
0,
"message",
sizeof(OutputObject),
0,
(destructor) 0,
(printfunc) 0,
(getattrfunc) OutputGetattr,
(setattrfunc) OutputSetattr,
(cmpfunc) 0,
(reprfunc) 0,
0, /* as number */
0, /* as sequence */
0, /* as mapping */
(hashfunc) 0,
(ternaryfunc) 0,
(reprfunc) 0
};
/*************/
static PyObject *
OutputGetattr(PyObject *self, char *name)
{
if (strcmp(name, "softspace") == 0)
return PyInt_FromLong(((OutputObject *)(self))->softspace);
return Py_FindMethod(OutputMethods, self, name);
}
static int
OutputSetattr(PyObject *self, char *name, PyObject *val)
{
if (val == NULL) {
PyErr_SetString(PyExc_AttributeError, "can't delete OutputObject attributes");
return -1;
}
if (strcmp(name, "softspace") == 0)
{
if (!PyInt_Check(val)) {
PyErr_SetString(PyExc_TypeError, "softspace must be an integer");
return -1;
}
((OutputObject *)(self))->softspace = PyInt_AsLong(val);
return 0;
}
PyErr_SetString(PyExc_AttributeError, "invalid attribute");
return -1;
}
/*************/
static PyObject *
OutputWrite(PyObject *self, PyObject *args)
{
int len;
char *str;
int error = ((OutputObject *)(self))->error;
if (!PyArg_ParseTuple(args, "s#", &str, &len))
return NULL;
Py_BEGIN_ALLOW_THREADS
Python_Lock_Vim();
writer((writefn)(error ? emsg : msg), (char_u *)str, len);
Python_Release_Vim();
Py_END_ALLOW_THREADS
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
OutputWritelines(PyObject *self, PyObject *args)
{
int n;
int i;
PyObject *list;
int error = ((OutputObject *)(self))->error;
if (!PyArg_ParseTuple(args, "O", &list))
return NULL;
Py_INCREF(list);
if (!PyList_Check(list)) {
PyErr_SetString(PyExc_TypeError, "writelines() requires list of strings");
Py_DECREF(list);
return NULL;
}
n = PyList_Size(list);
for (i = 0; i < n; ++i)
{
PyObject *line = PyList_GetItem(list, i);
char *str;
int len;
if (!PyArg_Parse(line, "s#", &str, &len)) {
PyErr_SetString(PyExc_TypeError, "writelines() requires list of strings");
Py_DECREF(list);
return NULL;
}
Py_BEGIN_ALLOW_THREADS
Python_Lock_Vim();
writer((writefn)(error ? emsg : msg), (char_u *)str, len);
Python_Release_Vim();
Py_END_ALLOW_THREADS
}
Py_DECREF(list);
Py_INCREF(Py_None);
return Py_None;
}
/* Output buffer management
*/
static char_u *buffer = NULL;
static int buffer_len = 0;
static int buffer_size = 0;
static writefn old_fn = NULL;
static void
buffer_ensure(int n)
{
int new_size;
char_u *new_buffer;
if (n < buffer_size)
return;
new_size = buffer_size;
while (new_size < n)
new_size += 80;
if (new_size != buffer_size)
{
new_buffer = alloc((unsigned)new_size);
if (new_buffer == NULL)
{
EMSG("Out of memory!");
return;
}
if (buffer)
{
memcpy(new_buffer, buffer, buffer_len);
vim_free(buffer);
}
buffer = new_buffer;
buffer_size = new_size;
}
}
static void
PythonIO_Flush(void)
{
if (old_fn && buffer_len)
{
buffer[buffer_len] = 0;
old_fn(buffer);
}
buffer_len = 0;
}
static void
writer(writefn fn, char_u *str, int n)
{
char_u *ptr;
if (fn != old_fn && old_fn != NULL)
PythonIO_Flush();
old_fn = fn;
while (n > 0 && (ptr = memchr(str, '\n', n)) != NULL)
{
int len = ptr - str;
buffer_ensure(buffer_len + len + 1);
memcpy(buffer + buffer_len, str, len);
buffer_len += len;
buffer[buffer_len] = 0;
fn(buffer);
str = ptr + 1;
n -= len + 1;
buffer_len = 0;
}
/* Put the remaining text into the buffer for later printing */
buffer_ensure(buffer_len + n + 1);
memcpy(buffer + buffer_len, str, n);
buffer_len += n;
}
/***************/
static OutputObject Output =
{
PyObject_HEAD_INIT(&OutputType)
0,
0
};
static OutputObject Error =
{
PyObject_HEAD_INIT(&OutputType)
0,
1
};
static int
PythonIO_Init(void)
{
/* Fixups... */
OutputType.ob_type = &PyType_Type;
PySys_SetObject("stdout", (PyObject *)(&Output));
PySys_SetObject("stderr", (PyObject *)(&Error));
if (PyErr_Occurred())
{
EMSG("Python: Error initialising I/O objects");
return -1;
}
return 0;
}
/******************************************************
* 3. Implementation of the Vim module for Python
*/
/* Vim module - Implementation functions
* -------------------------------------
*/
static PyObject *VimError;
static PyObject *VimCommand(PyObject *, PyObject *);
static PyObject *VimEval(PyObject *, PyObject *);
/* Window type - Implementation functions
* --------------------------------------
*/
typedef struct
{
PyObject_HEAD
WIN *win;
}
WindowObject;
#define INVALID_WINDOW_VALUE ((WIN*)(-1))
#define WindowType_Check(obj) ((obj)->ob_type == &WindowType)
static PyObject *WindowNew(WIN *);
static void WindowDestructor(PyObject *);
static PyObject *WindowGetattr(PyObject *, char *);
static int WindowSetattr(PyObject *, char *, PyObject *);
static PyObject *WindowRepr(PyObject *);
/* Buffer type - Implementation functions
* --------------------------------------
*/
typedef struct
{
PyObject_HEAD
BUF *buf;
}
BufferObject;
#define INVALID_BUFFER_VALUE ((BUF*)(-1))
#define BufferType_Check(obj) ((obj)->ob_type == &BufferType)
static PyObject *BufferNew (BUF *);
static void BufferDestructor(PyObject *);
static PyObject *BufferGetattr(PyObject *, char *);
static PyObject *BufferRepr(PyObject *);
static int BufferLength(PyObject *);
static PyObject *BufferItem(PyObject *, int);
static PyObject *BufferSlice(PyObject *, int, int);
static int BufferAssItem(PyObject *, int, PyObject *);
static int BufferAssSlice(PyObject *, int, int, PyObject *);
static PyObject *BufferAppend(PyObject *, PyObject *);
static PyObject *BufferMark(PyObject *, PyObject *);
static PyObject *BufferRange(PyObject *, PyObject *);
/* Line range type - Implementation functions
* --------------------------------------
*/
typedef struct
{
PyObject_HEAD
BufferObject *buf;
int start;
int end;
}
RangeObject;
#define RangeType_Check(obj) ((obj)->ob_type == &RangeType)
static PyObject *RangeNew(BUF *, int, int);
static void RangeDestructor(PyObject *);
static PyObject *RangeGetattr(PyObject *, char *);
static PyObject *RangeRepr(PyObject *);
static int RangeLength(PyObject *);
static PyObject *RangeItem(PyObject *, int);
static PyObject *RangeSlice(PyObject *, int, int);
static int RangeAssItem(PyObject *, int, PyObject *);
static int RangeAssSlice(PyObject *, int, int, PyObject *);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -