⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_python.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 4 页
字号:
/* 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 + -