# HG changeset patch # User Bram Moolenaar # Date 1280598854 -7200 # Node ID 84d3537628453b280102e16df75eae39f5a4c055 # Parent 348f64c129dfa24ac357098c911224c30de38130 Move many more common Python items to if_py_both.c. diff --git a/src/if_py_both.h b/src/if_py_both.h --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -51,6 +51,8 @@ static struct PyMethodDef OutputMethods[ { NULL, NULL, 0, NULL } }; +#define PyErr_SetVim(str) PyErr_SetString(VimError, str) + /*************/ /* Output buffer management @@ -254,3 +256,1094 @@ VimErrorCheck(void) return 0; } + +/* Vim module - Implementation + */ + static PyObject * +VimCommand(PyObject *self UNUSED, PyObject *args) +{ + char *cmd; + PyObject *result; + + if (!PyArg_ParseTuple(args, "s", &cmd)) + return NULL; + + PyErr_Clear(); + + Py_BEGIN_ALLOW_THREADS + Python_Lock_Vim(); + + do_cmdline_cmd((char_u *)cmd); + update_screen(VALID); + + Python_Release_Vim(); + Py_END_ALLOW_THREADS + + if (VimErrorCheck()) + result = NULL; + else + result = Py_None; + + Py_XINCREF(result); + return result; +} + +#ifdef FEAT_EVAL +/* + * Function to translate a typval_T into a PyObject; this will recursively + * translate lists/dictionaries into their Python equivalents. + * + * The depth parameter is to avoid infinite recursion, set it to 1 when + * you call VimToPython. + */ + static PyObject * +VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict) +{ + PyObject *result; + PyObject *newObj; + char ptrBuf[NUMBUFLEN]; + + /* Avoid infinite recursion */ + if (depth > 100) + { + Py_INCREF(Py_None); + result = Py_None; + return result; + } + + /* Check if we run into a recursive loop. The item must be in lookupDict + * then and we can use it again. */ + if ((our_tv->v_type == VAR_LIST && our_tv->vval.v_list != NULL) + || (our_tv->v_type == VAR_DICT && our_tv->vval.v_dict != NULL)) + { + sprintf(ptrBuf, PRINTF_DECIMAL_LONG_U, + our_tv->v_type == VAR_LIST ? (long_u)our_tv->vval.v_list + : (long_u)our_tv->vval.v_dict); + result = PyDict_GetItemString(lookupDict, ptrBuf); + if (result != NULL) + { + Py_INCREF(result); + return result; + } + } + + if (our_tv->v_type == VAR_STRING) + { + result = Py_BuildValue("s", our_tv->vval.v_string); + } + else if (our_tv->v_type == VAR_NUMBER) + { + char buf[NUMBUFLEN]; + + /* For backwards compatibility numbers are stored as strings. */ + sprintf(buf, "%ld", (long)our_tv->vval.v_number); + result = Py_BuildValue("s", buf); + } +# ifdef FEAT_FLOAT + else if (our_tv->v_type == VAR_FLOAT) + { + char buf[NUMBUFLEN]; + + sprintf(buf, "%f", our_tv->vval.v_float); + result = Py_BuildValue("s", buf); + } +# endif + else if (our_tv->v_type == VAR_LIST) + { + list_T *list = our_tv->vval.v_list; + listitem_T *curr; + + result = PyList_New(0); + + if (list != NULL) + { + PyDict_SetItemString(lookupDict, ptrBuf, result); + + for (curr = list->lv_first; curr != NULL; curr = curr->li_next) + { + newObj = VimToPython(&curr->li_tv, depth + 1, lookupDict); + PyList_Append(result, newObj); + Py_DECREF(newObj); + } + } + } + else if (our_tv->v_type == VAR_DICT) + { + result = PyDict_New(); + + if (our_tv->vval.v_dict != NULL) + { + hashtab_T *ht = &our_tv->vval.v_dict->dv_hashtab; + long_u todo = ht->ht_used; + hashitem_T *hi; + dictitem_T *di; + + PyDict_SetItemString(lookupDict, ptrBuf, result); + + for (hi = ht->ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + + di = dict_lookup(hi); + newObj = VimToPython(&di->di_tv, depth + 1, lookupDict); + PyDict_SetItemString(result, (char *)hi->hi_key, newObj); + Py_DECREF(newObj); + } + } + } + } + else + { + Py_INCREF(Py_None); + result = Py_None; + } + + return result; +} +#endif + + static PyObject * +VimEval(PyObject *self UNUSED, PyObject *args) +{ +#ifdef FEAT_EVAL + char *expr; + typval_T *our_tv; + PyObject *result; + PyObject *lookup_dict; + + if (!PyArg_ParseTuple(args, "s", &expr)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + Python_Lock_Vim(); + our_tv = eval_expr((char_u *)expr, NULL); + + Python_Release_Vim(); + Py_END_ALLOW_THREADS + + if (our_tv == NULL) + { + PyErr_SetVim(_("invalid expression")); + return NULL; + } + + /* Convert the Vim type into a Python type. Create a dictionary that's + * used to check for recursive loops. */ + lookup_dict = PyDict_New(); + result = VimToPython(our_tv, 1, lookup_dict); + Py_DECREF(lookup_dict); + + + Py_BEGIN_ALLOW_THREADS + Python_Lock_Vim(); + free_tv(our_tv); + Python_Release_Vim(); + Py_END_ALLOW_THREADS + + return result; +#else + PyErr_SetVim(_("expressions disabled at compile time")); + return NULL; +#endif +} + +/* + * Vim module - Definitions + */ + +static struct PyMethodDef VimMethods[] = { + /* name, function, calling, documentation */ + {"command", VimCommand, 1, "Execute a Vim ex-mode command" }, + {"eval", VimEval, 1, "Evaluate an expression using Vim evaluator" }, + { NULL, NULL, 0, NULL } +}; + +typedef struct +{ + PyObject_HEAD + buf_T *buf; +} +BufferObject; + +#define INVALID_BUFFER_VALUE ((buf_T *)(-1)) + +/* + * Buffer list object - Implementation + */ + + static PyInt +BufListLength(PyObject *self UNUSED) +{ + buf_T *b = firstbuf; + PyInt n = 0; + + while (b) + { + ++n; + b = b->b_next; + } + + return n; +} + + static PyObject * +BufListItem(PyObject *self UNUSED, PyInt n) +{ + buf_T *b; + + for (b = firstbuf; b; b = b->b_next, --n) + { + if (n == 0) + return BufferNew(b); + } + + PyErr_SetString(PyExc_IndexError, _("no such buffer")); + return NULL; +} + +typedef struct +{ + PyObject_HEAD + win_T *win; +} WindowObject; + +#define INVALID_WINDOW_VALUE ((win_T *)(-1)) + + static int +CheckWindow(WindowObject *this) +{ + if (this->win == INVALID_WINDOW_VALUE) + { + PyErr_SetVim(_("attempt to refer to deleted window")); + return -1; + } + + return 0; +} + +static int WindowSetattr(PyObject *, char *, PyObject *); +static PyObject *WindowRepr(PyObject *); + + static int +WindowSetattr(PyObject *self, char *name, PyObject *val) +{ + WindowObject *this = (WindowObject *)(self); + + if (CheckWindow(this)) + return -1; + + if (strcmp(name, "buffer") == 0) + { + PyErr_SetString(PyExc_TypeError, _("readonly attribute")); + return -1; + } + else if (strcmp(name, "cursor") == 0) + { + long lnum; + long col; + long len; + + if (!PyArg_Parse(val, "(ll)", &lnum, &col)) + return -1; + + if (lnum <= 0 || lnum > this->win->w_buffer->b_ml.ml_line_count) + { + PyErr_SetVim(_("cursor position outside buffer")); + return -1; + } + + /* Check for keyboard interrupts */ + if (VimErrorCheck()) + return -1; + + /* When column is out of range silently correct it. */ + len = (long)STRLEN(ml_get_buf(this->win->w_buffer, lnum, FALSE)); + if (col > len) + col = len; + + this->win->w_cursor.lnum = lnum; + this->win->w_cursor.col = col; +#ifdef FEAT_VIRTUALEDIT + this->win->w_cursor.coladd = 0; +#endif + update_screen(VALID); + + return 0; + } + else if (strcmp(name, "height") == 0) + { + int height; + win_T *savewin; + + if (!PyArg_Parse(val, "i", &height)) + return -1; + +#ifdef FEAT_GUI + need_mouse_correct = TRUE; +#endif + savewin = curwin; + curwin = this->win; + win_setheight(height); + curwin = savewin; + + /* Check for keyboard interrupts */ + if (VimErrorCheck()) + return -1; + + return 0; + } +#ifdef FEAT_VERTSPLIT + else if (strcmp(name, "width") == 0) + { + int width; + win_T *savewin; + + if (!PyArg_Parse(val, "i", &width)) + return -1; + +#ifdef FEAT_GUI + need_mouse_correct = TRUE; +#endif + savewin = curwin; + curwin = this->win; + win_setwidth(width); + curwin = savewin; + + /* Check for keyboard interrupts */ + if (VimErrorCheck()) + return -1; + + return 0; + } +#endif + else + { + PyErr_SetString(PyExc_AttributeError, name); + return -1; + } +} + + static PyObject * +WindowRepr(PyObject *self) +{ + static char repr[100]; + WindowObject *this = (WindowObject *)(self); + + if (this->win == INVALID_WINDOW_VALUE) + { + vim_snprintf(repr, 100, _(""), (self)); + return PyString_FromString(repr); + } + else + { + int i = 0; + win_T *w; + + for (w = firstwin; w != NULL && w != this->win; w = W_NEXT(w)) + ++i; + + if (w == NULL) + vim_snprintf(repr, 100, _(""), + (self)); + else + vim_snprintf(repr, 100, _(""), i); + + return PyString_FromString(repr); + } +} + +/* + * Window list object - Implementation + */ + static PyInt +WinListLength(PyObject *self UNUSED) +{ + win_T *w = firstwin; + PyInt n = 0; + + while (w != NULL) + { + ++n; + w = W_NEXT(w); + } + + return n; +} + + static PyObject * +WinListItem(PyObject *self UNUSED, PyInt n) +{ + win_T *w; + + for (w = firstwin; w != NULL; w = W_NEXT(w), --n) + if (n == 0) + return WindowNew(w); + + PyErr_SetString(PyExc_IndexError, _("no such window")); + return NULL; +} + +/* Convert a Python string into a Vim line. + * + * The result is in allocated memory. All internal nulls are replaced by + * newline characters. It is an error for the string to contain newline + * characters. + * + * On errors, the Python exception data is set, and NULL is returned. + */ + static char * +StringToLine(PyObject *obj) +{ + const char *str; + char *save; + PyInt len; + PyInt i; + char *p; + + if (obj == NULL || !PyString_Check(obj)) + { + PyErr_BadArgument(); + return NULL; + } + + str = PyString_AsString(obj); + len = PyString_Size(obj); + + /* + * Error checking: String must not contain newlines, as we + * are replacing a single line, and we must replace it with + * a single line. + * A trailing newline is removed, so that append(f.readlines()) works. + */ + p = memchr(str, '\n', len); + if (p != NULL) + { + if (p == str + len - 1) + --len; + else + { + PyErr_SetVim(_("string cannot contain newlines")); + return NULL; + } + } + + /* Create a copy of the string, with internal nulls replaced by + * newline characters, as is the vim convention. + */ + save = (char *)alloc((unsigned)(len+1)); + if (save == NULL) + { + PyErr_NoMemory(); + return NULL; + } + + for (i = 0; i < len; ++i) + { + if (str[i] == '\0') + save[i] = '\n'; + else + save[i] = str[i]; + } + + save[i] = '\0'; + + return save; +} + +/* Get a line from the specified buffer. The line number is + * in Vim format (1-based). The line is returned as a Python + * string object. + */ + static PyObject * +GetBufferLine(buf_T *buf, PyInt n) +{ + return LineToString((char *)ml_get_buf(buf, (linenr_T)n, FALSE)); +} + + +/* Get a list of lines from the specified buffer. The line numbers + * are in Vim format (1-based). The range is from lo up to, but not + * including, hi. The list is returned as a Python list of string objects. + */ + static PyObject * +GetBufferLineList(buf_T *buf, PyInt lo, PyInt hi) +{ + PyInt i; + PyInt n = hi - lo; + PyObject *list = PyList_New(n); + + if (list == NULL) + return NULL; + + for (i = 0; i < n; ++i) + { + PyObject *str = LineToString((char *)ml_get_buf(buf, (linenr_T)(lo+i), FALSE)); + + /* Error check - was the Python string creation OK? */ + if (str == NULL) + { + Py_DECREF(list); + return NULL; + } + + /* Set the list item */ + if (PyList_SetItem(list, i, str)) + { + Py_DECREF(str); + Py_DECREF(list); + return NULL; + } + } + + /* The ownership of the Python list is passed to the caller (ie, + * the caller should Py_DECREF() the object when it is finished + * with it). + */ + + return list; +} + +/* + * Check if deleting lines made the cursor position invalid. + * Changed the lines from "lo" to "hi" and added "extra" lines (negative if + * deleted). + */ + static void +py_fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra) +{ + if (curwin->w_cursor.lnum >= lo) + { + /* Adjust the cursor position if it's in/after the changed + * lines. */ + if (curwin->w_cursor.lnum >= hi) + { + curwin->w_cursor.lnum += extra; + check_cursor_col(); + } + else if (extra < 0) + { + curwin->w_cursor.lnum = lo; + check_cursor(); + } + else + check_cursor_col(); + changed_cline_bef_curs(); + } + invalidate_botline(); +} + +/* Replace a line in the specified buffer. The line number is + * in Vim format (1-based). The replacement line is given as + * a Python string object. The object is checked for validity + * and correct format. Errors are returned as a value of FAIL. + * The return value is OK on success. + * If OK is returned and len_change is not NULL, *len_change + * is set to the change in the buffer length. + */ + static int +SetBufferLine(buf_T *buf, PyInt n, PyObject *line, PyInt *len_change) +{ + /* First of all, we check the thpe of the supplied Python object. + * There are three cases: + * 1. NULL, or None - this is a deletion. + * 2. A string - this is a replacement. + * 3. Anything else - this is an error. + */ + if (line == Py_None || line == NULL) + { + buf_T *savebuf = curbuf; + + PyErr_Clear(); + curbuf = buf; + + if (u_savedel((linenr_T)n, 1L) == FAIL) + PyErr_SetVim(_("cannot save undo information")); + else if (ml_delete((linenr_T)n, FALSE) == FAIL) + PyErr_SetVim(_("cannot delete line")); + else + { + if (buf == curwin->w_buffer) + py_fix_cursor((linenr_T)n, (linenr_T)n + 1, (linenr_T)-1); + deleted_lines_mark((linenr_T)n, 1L); + } + + curbuf = savebuf; + + if (PyErr_Occurred() || VimErrorCheck()) + return FAIL; + + if (len_change) + *len_change = -1; + + return OK; + } + else if (PyString_Check(line)) + { + char *save = StringToLine(line); + buf_T *savebuf = curbuf; + + if (save == NULL) + return FAIL; + + /* We do not need to free "save" if ml_replace() consumes it. */ + PyErr_Clear(); + curbuf = buf; + + if (u_savesub((linenr_T)n) == FAIL) + { + PyErr_SetVim(_("cannot save undo information")); + vim_free(save); + } + else if (ml_replace((linenr_T)n, (char_u *)save, FALSE) == FAIL) + { + PyErr_SetVim(_("cannot replace line")); + vim_free(save); + } + else + changed_bytes((linenr_T)n, 0); + + curbuf = savebuf; + + /* Check that the cursor is not beyond the end of the line now. */ + if (buf == curwin->w_buffer) + check_cursor_col(); + + if (PyErr_Occurred() || VimErrorCheck()) + return FAIL; + + if (len_change) + *len_change = 0; + + return OK; + } + else + { + PyErr_BadArgument(); + return FAIL; + } +} + + +/* Insert a number of lines into the specified buffer after the specifed line. + * The line number is in Vim format (1-based). The lines to be inserted are + * given as a Python list of string objects or as a single string. The lines + * to be added are checked for validity and correct format. Errors are + * returned as a value of FAIL. The return value is OK on success. + * If OK is returned and len_change is not NULL, *len_change + * is set to the change in the buffer length. + */ + static int +InsertBufferLines(buf_T *buf, PyInt n, PyObject *lines, PyInt *len_change) +{ + /* First of all, we check the type of the supplied Python object. + * It must be a string or a list, or the call is in error. + */ + if (PyString_Check(lines)) + { + char *str = StringToLine(lines); + buf_T *savebuf; + + if (str == NULL) + return FAIL; + + savebuf = curbuf; + + PyErr_Clear(); + curbuf = buf; + + if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL) + PyErr_SetVim(_("cannot save undo information")); + else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL) + PyErr_SetVim(_("cannot insert line")); + else + appended_lines_mark((linenr_T)n, 1L); + + vim_free(str); + curbuf = savebuf; + update_screen(VALID); + + if (PyErr_Occurred() || VimErrorCheck()) + return FAIL; + + if (len_change) + *len_change = 1; + + return OK; + } + else if (PyList_Check(lines)) + { + PyInt i; + PyInt size = PyList_Size(lines); + char **array; + buf_T *savebuf; + + array = (char **)alloc((unsigned)(size * sizeof(char *))); + if (array == NULL) + { + PyErr_NoMemory(); + return FAIL; + } + + for (i = 0; i < size; ++i) + { + PyObject *line = PyList_GetItem(lines, i); + array[i] = StringToLine(line); + + if (array[i] == NULL) + { + while (i) + vim_free(array[--i]); + vim_free(array); + return FAIL; + } + } + + savebuf = curbuf; + + PyErr_Clear(); + curbuf = buf; + + if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL) + PyErr_SetVim(_("cannot save undo information")); + else + { + for (i = 0; i < size; ++i) + { + if (ml_append((linenr_T)(n + i), + (char_u *)array[i], 0, FALSE) == FAIL) + { + PyErr_SetVim(_("cannot insert line")); + + /* Free the rest of the lines */ + while (i < size) + vim_free(array[i++]); + + break; + } + vim_free(array[i]); + } + if (i > 0) + appended_lines_mark((linenr_T)n, (long)i); + } + + /* Free the array of lines. All of its contents have now + * been freed. + */ + vim_free(array); + + curbuf = savebuf; + update_screen(VALID); + + if (PyErr_Occurred() || VimErrorCheck()) + return FAIL; + + if (len_change) + *len_change = size; + + return OK; + } + else + { + PyErr_BadArgument(); + return FAIL; + } +} + +/* + * Common routines for buffers and line ranges + * ------------------------------------------- + */ + + static int +CheckBuffer(BufferObject *this) +{ + if (this->buf == INVALID_BUFFER_VALUE) + { + PyErr_SetVim(_("attempt to refer to deleted buffer")); + return -1; + } + + return 0; +} + + static PyObject * +RBItem(BufferObject *self, PyInt n, PyInt start, PyInt end) +{ + if (CheckBuffer(self)) + return NULL; + + if (n < 0 || n > end - start) + { + PyErr_SetString(PyExc_IndexError, _("line number out of range")); + return NULL; + } + + return GetBufferLine(self->buf, n+start); +} + + static PyObject * +RBSlice(BufferObject *self, PyInt lo, PyInt hi, PyInt start, PyInt end) +{ + PyInt size; + + if (CheckBuffer(self)) + return NULL; + + size = end - start + 1; + + if (lo < 0) + lo = 0; + else if (lo > size) + lo = size; + if (hi < 0) + hi = 0; + if (hi < lo) + hi = lo; + else if (hi > size) + hi = size; + + return GetBufferLineList(self->buf, lo+start, hi+start); +} + + static PyInt +RBAsItem(BufferObject *self, PyInt n, PyObject *val, PyInt start, PyInt end, PyInt *new_end) +{ + PyInt len_change; + + if (CheckBuffer(self)) + return -1; + + if (n < 0 || n > end - start) + { + PyErr_SetString(PyExc_IndexError, _("line number out of range")); + return -1; + } + + if (SetBufferLine(self->buf, n+start, val, &len_change) == FAIL) + return -1; + + if (new_end) + *new_end = end + len_change; + + return 0; +} + + + static PyObject * +RBAppend(BufferObject *self, PyObject *args, PyInt start, PyInt end, PyInt *new_end) +{ + PyObject *lines; + PyInt len_change; + PyInt max; + PyInt n; + + if (CheckBuffer(self)) + return NULL; + + max = n = end - start + 1; + + if (!PyArg_ParseTuple(args, "O|n", &lines, &n)) + return NULL; + + if (n < 0 || n > max) + { + PyErr_SetString(PyExc_ValueError, _("line number out of range")); + return NULL; + } + + if (InsertBufferLines(self->buf, n + start - 1, lines, &len_change) == FAIL) + return NULL; + + if (new_end) + *new_end = end + len_change; + + Py_INCREF(Py_None); + return Py_None; +} + + +/* Buffer object - Definitions + */ + +typedef struct +{ + PyObject_HEAD + BufferObject *buf; + PyInt start; + PyInt end; +} RangeObject; + + static PyObject * +RangeNew(buf_T *buf, PyInt start, PyInt end) +{ + BufferObject *bufr; + RangeObject *self; + self = PyObject_NEW(RangeObject, &RangeType); + if (self == NULL) + return NULL; + + bufr = (BufferObject *)BufferNew(buf); + if (bufr == NULL) + { + Py_DECREF(self); + return NULL; + } + Py_INCREF(bufr); + + self->buf = bufr; + self->start = start; + self->end = end; + + return (PyObject *)(self); +} + + static PyObject * +BufferAppend(PyObject *self, PyObject *args) +{ + return RBAppend((BufferObject *)(self), args, 1, + (PyInt)((BufferObject *)(self))->buf->b_ml.ml_line_count, + NULL); +} + + static PyObject * +BufferMark(PyObject *self, PyObject *args) +{ + pos_T *posp; + char *pmark; + char mark; + buf_T *curbuf_save; + + if (CheckBuffer((BufferObject *)(self))) + return NULL; + + if (!PyArg_ParseTuple(args, "s", &pmark)) + return NULL; + mark = *pmark; + + curbuf_save = curbuf; + curbuf = ((BufferObject *)(self))->buf; + posp = getmark(mark, FALSE); + curbuf = curbuf_save; + + if (posp == NULL) + { + PyErr_SetVim(_("invalid mark name")); + return NULL; + } + + /* Ckeck for keyboard interrupt */ + if (VimErrorCheck()) + return NULL; + + if (posp->lnum <= 0) + { + /* Or raise an error? */ + Py_INCREF(Py_None); + return Py_None; + } + + return Py_BuildValue("(ll)", (long)(posp->lnum), (long)(posp->col)); +} + + static PyObject * +BufferRange(PyObject *self, PyObject *args) +{ + PyInt start; + PyInt end; + + if (CheckBuffer((BufferObject *)(self))) + return NULL; + + if (!PyArg_ParseTuple(args, "nn", &start, &end)) + return NULL; + + return RangeNew(((BufferObject *)(self))->buf, start, end); +} + +static struct PyMethodDef BufferMethods[] = { + /* name, function, calling, documentation */ + {"append", BufferAppend, 1, "Append data to Vim buffer" }, + {"mark", BufferMark, 1, "Return (row,col) representing position of named mark" }, + {"range", BufferRange, 1, "Return a range object which represents the part of the given buffer between line numbers s and e" }, + { NULL, NULL, 0, NULL } +}; + + static PyObject * +RangeAppend(PyObject *self, PyObject *args) +{ + return RBAppend(((RangeObject *)(self))->buf, args, + ((RangeObject *)(self))->start, + ((RangeObject *)(self))->end, + &((RangeObject *)(self))->end); +} + + static PyInt +RangeLength(PyObject *self) +{ + /* HOW DO WE SIGNAL AN ERROR FROM THIS FUNCTION? */ + if (CheckBuffer(((RangeObject *)(self))->buf)) + return -1; /* ??? */ + + return (((RangeObject *)(self))->end - ((RangeObject *)(self))->start + 1); +} + + static PyObject * +RangeItem(PyObject *self, PyInt n) +{ + return RBItem(((RangeObject *)(self))->buf, n, + ((RangeObject *)(self))->start, + ((RangeObject *)(self))->end); +} + + static PyObject * +RangeRepr(PyObject *self) +{ + static char repr[100]; + RangeObject *this = (RangeObject *)(self); + + if (this->buf->buf == INVALID_BUFFER_VALUE) + { + vim_snprintf(repr, 100, "", + (self)); + return PyString_FromString(repr); + } + else + { + char *name = (char *)this->buf->buf->b_fname; + int len; + + if (name == NULL) + name = ""; + len = (int)strlen(name); + + if (len > 45) + name = name + (45 - len); + + vim_snprintf(repr, 100, "", + len > 45 ? "..." : "", name, + this->start, this->end); + + return PyString_FromString(repr); + } +} + + static PyObject * +RangeSlice(PyObject *self, PyInt lo, PyInt hi) +{ + return RBSlice(((RangeObject *)(self))->buf, lo, hi, + ((RangeObject *)(self))->start, + ((RangeObject *)(self))->end); +} + +/* + * Line range object - Definitions + */ + +static struct PyMethodDef RangeMethods[] = { + /* name, function, calling, documentation */ + {"append", RangeAppend, 1, "Append data to the Vim range" }, + { NULL, NULL, 0, NULL } +}; + diff --git a/src/if_python.c b/src/if_python.c --- a/src/if_python.c +++ b/src/if_python.c @@ -390,13 +390,12 @@ python_enabled(int verbose) return python_runtime_link_init(DYNAMIC_PYTHON_DLL, verbose) == OK; } -/* Load the standard Python exceptions - don't import the symbols from the +/* + * Load the standard Python exceptions - don't import the symbols from the * DLL, as this can cause errors (importing data symbols is not reliable). */ -static void get_exceptions __ARGS((void)); - static void -get_exceptions() +get_exceptions(void) { PyObject *exmod = PyImport_ImportModule("exceptions"); PyObject *exdict = PyModule_GetDict(exmod); @@ -414,6 +413,12 @@ get_exceptions() } #endif /* DYNAMIC_PYTHON */ +static PyObject *BufferNew (buf_T *); +static PyObject *WindowNew(win_T *); +static PyObject *LineToString(const char *); + +static PyTypeObject RangeType; + /* * Include the code shared with if_python3.c */ @@ -424,7 +429,6 @@ get_exceptions() * Internal function prototypes. */ -static void DoPythonCommand(exarg_T *, const char *); static PyInt RangeStart; static PyInt RangeEnd; @@ -435,17 +439,9 @@ static int PythonMod_Init(void); /* Utility functions for the vim/python interface * ---------------------------------------------- */ -static PyObject *GetBufferLine(buf_T *, PyInt); -static PyObject *GetBufferLineList(buf_T *, PyInt, PyInt); -static int SetBufferLine(buf_T *, PyInt, PyObject *, PyInt *); static int SetBufferLineList(buf_T *, PyInt, PyInt, PyObject *, PyInt *); -static int InsertBufferLines(buf_T *, PyInt, PyObject *, PyInt *); -static PyObject *LineToString(const char *); -static char *StringToLine(PyObject *); - -#define PyErr_SetVim(str) PyErr_SetString(VimError, str) /****************************************************** * 1. Python interpreter main program. @@ -734,11 +730,6 @@ ex_pyfile(exarg_T *eap) /* Implementation functions */ -static PyObject *OutputGetattr(PyObject *, char *); -static int OutputSetattr(PyObject *, char *, PyObject *); - -/*************/ - static PyObject * OutputGetattr(PyObject *self, char *name) { @@ -786,52 +777,21 @@ PythonIO_Init(void) * 3. Implementation of the Vim module for Python */ -/* Vim module - Implementation functions - * ------------------------------------- - */ - -static PyObject *VimCommand(PyObject *, PyObject *); -static PyObject *VimEval(PyObject *, PyObject *); - /* Window type - Implementation functions * -------------------------------------- */ -typedef struct -{ - PyObject_HEAD - win_T *win; -} -WindowObject; - -#define INVALID_WINDOW_VALUE ((win_T *)(-1)) - #define WindowType_Check(obj) ((obj)->ob_type == &WindowType) -static PyObject *WindowNew(win_T *); - 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_T *buf; -} -BufferObject; - -#define INVALID_BUFFER_VALUE ((buf_T *)(-1)) - #define BufferType_Check(obj) ((obj)->ob_type == &BufferType) -static PyObject *BufferNew (buf_T *); - static void BufferDestructor(PyObject *); static PyObject *BufferGetattr(PyObject *, char *); static PyObject *BufferRepr(PyObject *); @@ -842,53 +802,15 @@ static PyObject *BufferSlice(PyObject *, static PyInt BufferAssItem(PyObject *, PyInt, PyObject *); static PyInt BufferAssSlice(PyObject *, PyInt, PyInt, 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; - PyInt start; - PyInt end; -} -RangeObject; - #define RangeType_Check(obj) ((obj)->ob_type == &RangeType) -static PyObject *RangeNew(buf_T *, PyInt, PyInt); - -static void RangeDestructor(PyObject *); -static PyObject *RangeGetattr(PyObject *, char *); -static PyObject *RangeRepr(PyObject *); - -static PyInt RangeLength(PyObject *); -static PyObject *RangeItem(PyObject *, PyInt); -static PyObject *RangeSlice(PyObject *, PyInt, PyInt); static PyInt RangeAssItem(PyObject *, PyInt, PyObject *); static PyInt RangeAssSlice(PyObject *, PyInt, PyInt, PyObject *); -static PyObject *RangeAppend(PyObject *, PyObject *); - -/* Window list type - Implementation functions - * ------------------------------------------- - */ - -static PyInt WinListLength(PyObject *); -static PyObject *WinListItem(PyObject *, PyInt); - -/* Buffer list type - Implementation functions - * ------------------------------------------- - */ - -static PyInt BufListLength(PyObject *); -static PyObject *BufListItem(PyObject *, PyInt); - /* Current objects type - Implementation functions * ----------------------------------------------- */ @@ -896,286 +818,10 @@ static PyObject *BufListItem(PyObject *, static PyObject *CurrentGetattr(PyObject *, char *); static int CurrentSetattr(PyObject *, char *, PyObject *); -/* Vim module - Definitions - */ - -static struct PyMethodDef VimMethods[] = { - /* name, function, calling, documentation */ - {"command", VimCommand, 1, "Execute a Vim ex-mode command" }, - {"eval", VimEval, 1, "Evaluate an expression using Vim evaluator" }, - { NULL, NULL, 0, NULL } -}; - -/* Vim module - Implementation - */ - static PyObject * -VimCommand(PyObject *self UNUSED, PyObject *args) -{ - char *cmd; - PyObject *result; - - if (!PyArg_ParseTuple(args, "s", &cmd)) - return NULL; - - PyErr_Clear(); - - Py_BEGIN_ALLOW_THREADS - Python_Lock_Vim(); - - do_cmdline_cmd((char_u *)cmd); - update_screen(VALID); - - Python_Release_Vim(); - Py_END_ALLOW_THREADS - - if (VimErrorCheck()) - result = NULL; - else - result = Py_None; - - Py_XINCREF(result); - return result; -} - -#ifdef FEAT_EVAL -/* - * Function to translate a typval_T into a PyObject; this will recursively - * translate lists/dictionaries into their Python equivalents. - * - * The depth parameter is to avoid infinite recursion, set it to 1 when - * you call VimToPython. - */ - static PyObject * -VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict) -{ - PyObject *result; - PyObject *newObj; - char ptrBuf[NUMBUFLEN]; - - /* Avoid infinite recursion */ - if (depth > 100) - { - Py_INCREF(Py_None); - result = Py_None; - return result; - } - - /* Check if we run into a recursive loop. The item must be in lookupDict - * then and we can use it again. */ - if ((our_tv->v_type == VAR_LIST && our_tv->vval.v_list != NULL) - || (our_tv->v_type == VAR_DICT && our_tv->vval.v_dict != NULL)) - { - sprintf(ptrBuf, PRINTF_DECIMAL_LONG_U, - our_tv->v_type == VAR_LIST ? (long_u)our_tv->vval.v_list - : (long_u)our_tv->vval.v_dict); - result = PyDict_GetItemString(lookupDict, ptrBuf); - if (result != NULL) - { - Py_INCREF(result); - return result; - } - } - - if (our_tv->v_type == VAR_STRING) - { - result = Py_BuildValue("s", our_tv->vval.v_string); - } - else if (our_tv->v_type == VAR_NUMBER) - { - char buf[NUMBUFLEN]; - - /* For backwards compatibility numbers are stored as strings. */ - sprintf(buf, "%ld", (long)our_tv->vval.v_number); - result = Py_BuildValue("s", buf); - } -# ifdef FEAT_FLOAT - else if (our_tv->v_type == VAR_FLOAT) - { - char buf[NUMBUFLEN]; - - sprintf(buf, "%f", our_tv->vval.v_float); - result = Py_BuildValue("s", buf); - } -# endif - else if (our_tv->v_type == VAR_LIST) - { - list_T *list = our_tv->vval.v_list; - listitem_T *curr; - - result = PyList_New(0); - - if (list != NULL) - { - PyDict_SetItemString(lookupDict, ptrBuf, result); - - for (curr = list->lv_first; curr != NULL; curr = curr->li_next) - { - newObj = VimToPython(&curr->li_tv, depth + 1, lookupDict); - PyList_Append(result, newObj); - Py_DECREF(newObj); - } - } - } - else if (our_tv->v_type == VAR_DICT) - { - result = PyDict_New(); - - if (our_tv->vval.v_dict != NULL) - { - hashtab_T *ht = &our_tv->vval.v_dict->dv_hashtab; - long_u todo = ht->ht_used; - hashitem_T *hi; - dictitem_T *di; - - PyDict_SetItemString(lookupDict, ptrBuf, result); - - for (hi = ht->ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - --todo; - - di = dict_lookup(hi); - newObj = VimToPython(&di->di_tv, depth + 1, lookupDict); - PyDict_SetItemString(result, (char *)hi->hi_key, newObj); - Py_DECREF(newObj); - } - } - } - } - else - { - Py_INCREF(Py_None); - result = Py_None; - } - - return result; -} -#endif - - static PyObject * -VimEval(PyObject *self UNUSED, PyObject *args) -{ -#ifdef FEAT_EVAL - char *expr; - typval_T *our_tv; - PyObject *result; - PyObject *lookup_dict; - - if (!PyArg_ParseTuple(args, "s", &expr)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - Python_Lock_Vim(); - our_tv = eval_expr((char_u *)expr, NULL); - - Python_Release_Vim(); - Py_END_ALLOW_THREADS - - if (our_tv == NULL) - { - PyErr_SetVim(_("invalid expression")); - return NULL; - } - - /* Convert the Vim type into a Python type. Create a dictionary that's - * used to check for recursive loops. */ - lookup_dict = PyDict_New(); - result = VimToPython(our_tv, 1, lookup_dict); - Py_DECREF(lookup_dict); - - - Py_BEGIN_ALLOW_THREADS - Python_Lock_Vim(); - free_tv(our_tv); - Python_Release_Vim(); - Py_END_ALLOW_THREADS - - return result; -#else - PyErr_SetVim(_("expressions disabled at compile time")); - return NULL; -#endif -} - /* Common routines for buffers and line ranges * ------------------------------------------- */ - static int -CheckBuffer(BufferObject *this) -{ - if (this->buf == INVALID_BUFFER_VALUE) - { - PyErr_SetVim(_("attempt to refer to deleted buffer")); - return -1; - } - - return 0; -} - - static PyObject * -RBItem(BufferObject *self, PyInt n, PyInt start, PyInt end) -{ - if (CheckBuffer(self)) - return NULL; - - if (n < 0 || n > end - start) - { - PyErr_SetString(PyExc_IndexError, _("line number out of range")); - return NULL; - } - - return GetBufferLine(self->buf, n+start); -} - - static PyObject * -RBSlice(BufferObject *self, PyInt lo, PyInt hi, PyInt start, PyInt end) -{ - PyInt size; - - if (CheckBuffer(self)) - return NULL; - - size = end - start + 1; - - if (lo < 0) - lo = 0; - else if (lo > size) - lo = size; - if (hi < 0) - hi = 0; - if (hi < lo) - hi = lo; - else if (hi > size) - hi = size; - - return GetBufferLineList(self->buf, lo+start, hi+start); -} - - static PyInt -RBAssItem(BufferObject *self, PyInt n, PyObject *val, PyInt start, PyInt end, PyInt *new_end) -{ - PyInt len_change; - - if (CheckBuffer(self)) - return -1; - - if (n < 0 || n > end - start) - { - PyErr_SetString(PyExc_IndexError, _("line number out of range")); - return -1; - } - - if (SetBufferLine(self->buf, n+start, val, &len_change) == FAIL) - return -1; - - if (new_end) - *new_end = end + len_change; - - return 0; -} - static PyInt RBAssSlice(BufferObject *self, PyInt lo, PyInt hi, PyObject *val, PyInt start, PyInt end, PyInt *new_end) { @@ -1200,7 +846,8 @@ RBAssSlice(BufferObject *self, PyInt lo, else if (hi > size) hi = size; - if (SetBufferLineList(self->buf, lo+start, hi+start, val, &len_change) == FAIL) + if (SetBufferLineList(self->buf, lo + start, hi + start, + val, &len_change) == FAIL) return -1; if (new_end) @@ -1209,50 +856,6 @@ RBAssSlice(BufferObject *self, PyInt lo, return 0; } - static PyObject * -RBAppend(BufferObject *self, PyObject *args, PyInt start, PyInt end, PyInt *new_end) -{ - PyObject *lines; - PyInt len_change; - PyInt max; - PyInt n; - - if (CheckBuffer(self)) - return NULL; - - max = n = end - start + 1; - - if (!PyArg_ParseTuple(args, "O|" Py_ssize_t_fmt, &lines, &n)) - return NULL; - - if (n < 0 || n > max) - { - PyErr_SetString(PyExc_ValueError, _("line number out of range")); - return NULL; - } - - if (InsertBufferLines(self->buf, n + start - 1, lines, &len_change) == FAIL) - return NULL; - - if (new_end) - *new_end = end + len_change; - - Py_INCREF(Py_None); - return Py_None; -} - - -/* Buffer object - Definitions - */ - -static struct PyMethodDef BufferMethods[] = { - /* name, function, calling, documentation */ - {"append", BufferAppend, 1, "Append data to Vim buffer" }, - {"mark", BufferMark, 1, "Return (row,col) representing position of named mark" }, - {"range", BufferRange, 1, "Return a range object which represents the part of the given buffer between line numbers s and e" }, - { NULL, NULL, 0, NULL } -}; - static PySequenceMethods BufferAsSeq = { (PyInquiry) BufferLength, /* sq_length, len(x) */ (binaryfunc) 0, /* BufferConcat, */ /* sq_concat, x+y */ @@ -1412,7 +1015,7 @@ BufferSlice(PyObject *self, PyInt lo, Py static PyInt BufferAssItem(PyObject *self, PyInt n, PyObject *val) { - return RBAssItem((BufferObject *)(self), n, val, 1, + return RBAsItem((BufferObject *)(self), n, val, 1, (PyInt)((BufferObject *)(self))->buf->b_ml.ml_line_count, NULL); } @@ -1425,76 +1028,6 @@ BufferAssSlice(PyObject *self, PyInt lo, NULL); } - static PyObject * -BufferAppend(PyObject *self, PyObject *args) -{ - return RBAppend((BufferObject *)(self), args, 1, - (PyInt)((BufferObject *)(self))->buf->b_ml.ml_line_count, - NULL); -} - - static PyObject * -BufferMark(PyObject *self, PyObject *args) -{ - pos_T *posp; - char mark; - buf_T *curbuf_save; - - if (CheckBuffer((BufferObject *)(self))) - return NULL; - - if (!PyArg_ParseTuple(args, "c", &mark)) - return NULL; - - curbuf_save = curbuf; - curbuf = ((BufferObject *)(self))->buf; - posp = getmark(mark, FALSE); - curbuf = curbuf_save; - - if (posp == NULL) - { - PyErr_SetVim(_("invalid mark name")); - return NULL; - } - - /* Ckeck for keyboard interrupt */ - if (VimErrorCheck()) - return NULL; - - if (posp->lnum <= 0) - { - /* Or raise an error? */ - Py_INCREF(Py_None); - return Py_None; - } - - return Py_BuildValue("(ll)", (long)(posp->lnum), (long)(posp->col)); -} - - static PyObject * -BufferRange(PyObject *self, PyObject *args) -{ - PyInt start; - PyInt end; - - if (CheckBuffer((BufferObject *)(self))) - return NULL; - - if (!PyArg_ParseTuple(args, Py_ssize_t_fmt Py_ssize_t_fmt, &start, &end)) - return NULL; - - return RangeNew(((BufferObject *)(self))->buf, start, end); -} - -/* Line range object - Definitions - */ - -static struct PyMethodDef RangeMethods[] = { - /* name, function, calling, documentation */ - {"append", RangeAppend, 1, "Append data to the Vim range" }, - { NULL, NULL, 0, NULL } -}; - static PySequenceMethods RangeAsSeq = { (PyInquiry) RangeLength, /* sq_length, len(x) */ (binaryfunc) 0, /* RangeConcat, */ /* sq_concat, x+y */ @@ -1505,56 +1038,9 @@ static PySequenceMethods RangeAsSeq = { (PyIntIntObjArgProc) RangeAssSlice, /* sq_ass_slice, x[i:j]=v */ }; -static PyTypeObject RangeType = { - PyObject_HEAD_INIT(0) - 0, - "range", - sizeof(RangeObject), - 0, - - (destructor) RangeDestructor, /* tp_dealloc, refcount==0 */ - (printfunc) 0, /* tp_print, print x */ - (getattrfunc) RangeGetattr, /* tp_getattr, x.attr */ - (setattrfunc) 0, /* tp_setattr, x.attr=v */ - (cmpfunc) 0, /* tp_compare, x>y */ - (reprfunc) RangeRepr, /* tp_repr, `x`, print x */ - - 0, /* as number */ - &RangeAsSeq, /* as sequence */ - 0, /* as mapping */ - - (hashfunc) 0, /* tp_hash, dict(x) */ - (ternaryfunc) 0, /* tp_call, x() */ - (reprfunc) 0, /* tp_str, str(x) */ -}; - /* Line range object - Implementation */ - static PyObject * -RangeNew(buf_T *buf, PyInt start, PyInt end) -{ - BufferObject *bufr; - RangeObject *self; - self = PyObject_NEW(RangeObject, &RangeType); - if (self == NULL) - return NULL; - - bufr = (BufferObject *)BufferNew(buf); - if (bufr == NULL) - { - Py_DECREF(self); - return NULL; - } - Py_INCREF(bufr); - - self->buf = bufr; - self->start = start; - self->end = end; - - return (PyObject *)(self); -} - static void RangeDestructor(PyObject *self) { @@ -1573,70 +1059,12 @@ RangeGetattr(PyObject *self, char *name) return Py_FindMethod(RangeMethods, self, name); } - static PyObject * -RangeRepr(PyObject *self) -{ - static char repr[100]; - RangeObject *this = (RangeObject *)(self); - - if (this->buf->buf == INVALID_BUFFER_VALUE) - { - vim_snprintf(repr, 100, "", - (self)); - return PyString_FromString(repr); - } - else - { - char *name = (char *)this->buf->buf->b_fname; - int len; - - if (name == NULL) - name = ""; - len = (int)strlen(name); - - if (len > 45) - name = name + (45 - len); - - vim_snprintf(repr, 100, "", - len > 45 ? "..." : "", name, - this->start, this->end); - - return PyString_FromString(repr); - } -} - /****************/ static PyInt -RangeLength(PyObject *self) -{ - /* HOW DO WE SIGNAL AN ERROR FROM THIS FUNCTION? */ - if (CheckBuffer(((RangeObject *)(self))->buf)) - return -1; /* ??? */ - - return (((RangeObject *)(self))->end - ((RangeObject *)(self))->start + 1); -} - - static PyObject * -RangeItem(PyObject *self, PyInt n) -{ - return RBItem(((RangeObject *)(self))->buf, n, - ((RangeObject *)(self))->start, - ((RangeObject *)(self))->end); -} - - static PyObject * -RangeSlice(PyObject *self, PyInt lo, PyInt hi) -{ - return RBSlice(((RangeObject *)(self))->buf, lo, hi, - ((RangeObject *)(self))->start, - ((RangeObject *)(self))->end); -} - - static PyInt RangeAssItem(PyObject *self, PyInt n, PyObject *val) { - return RBAssItem(((RangeObject *)(self))->buf, n, val, + return RBAsItem(((RangeObject *)(self))->buf, n, val, ((RangeObject *)(self))->start, ((RangeObject *)(self))->end, &((RangeObject *)(self))->end); @@ -1651,23 +1079,13 @@ RangeAssSlice(PyObject *self, PyInt lo, &((RangeObject *)(self))->end); } - static PyObject * -RangeAppend(PyObject *self, PyObject *args) -{ - return RBAppend(((RangeObject *)(self))->buf, args, - ((RangeObject *)(self))->start, - ((RangeObject *)(self))->end, - &((RangeObject *)(self))->end); -} - /* Buffer list object - Definitions */ typedef struct { PyObject_HEAD -} -BufListObject; +} BufListObject; static PySequenceMethods BufListAsSeq = { (PyInquiry) BufListLength, /* sq_length, len(x) */ @@ -1702,39 +1120,6 @@ static PyTypeObject BufListType = { (reprfunc) 0, /* tp_str, str(x) */ }; -/* Buffer list object - Implementation - */ - - static PyInt -BufListLength(PyObject *self UNUSED) -{ - buf_T *b = firstbuf; - PyInt n = 0; - - while (b) - { - ++n; - b = b->b_next; - } - - return n; -} - - static PyObject * -BufListItem(PyObject *self UNUSED, PyInt n) -{ - buf_T *b; - - for (b = firstbuf; b; b = b->b_next, --n) - { - if (n == 0) - return BufferNew(b); - } - - PyErr_SetString(PyExc_IndexError, _("no such buffer")); - return NULL; -} - /* Window object - Definitions */ @@ -1814,18 +1199,6 @@ WindowDestructor(PyObject *self) Py_DECREF(self); } - static int -CheckWindow(WindowObject *this) -{ - if (this->win == INVALID_WINDOW_VALUE) - { - PyErr_SetVim(_("attempt to refer to deleted window")); - return -1; - } - - return 0; -} - static PyObject * WindowGetattr(PyObject *self, char *name) { @@ -1854,134 +1227,6 @@ WindowGetattr(PyObject *self, char *name return Py_FindMethod(WindowMethods, self, name); } - static int -WindowSetattr(PyObject *self, char *name, PyObject *val) -{ - WindowObject *this = (WindowObject *)(self); - - if (CheckWindow(this)) - return -1; - - if (strcmp(name, "buffer") == 0) - { - PyErr_SetString(PyExc_TypeError, _("readonly attribute")); - return -1; - } - else if (strcmp(name, "cursor") == 0) - { - long lnum; - long col; - long len; - - if (!PyArg_Parse(val, "(ll)", &lnum, &col)) - return -1; - - if (lnum <= 0 || lnum > this->win->w_buffer->b_ml.ml_line_count) - { - PyErr_SetVim(_("cursor position outside buffer")); - return -1; - } - - /* Check for keyboard interrupts */ - if (VimErrorCheck()) - return -1; - - /* When column is out of range silently correct it. */ - len = (long)STRLEN(ml_get_buf(this->win->w_buffer, lnum, FALSE)); - if (col > len) - col = len; - - this->win->w_cursor.lnum = lnum; - this->win->w_cursor.col = col; -#ifdef FEAT_VIRTUALEDIT - this->win->w_cursor.coladd = 0; -#endif - update_screen(VALID); - - return 0; - } - else if (strcmp(name, "height") == 0) - { - int height; - win_T *savewin; - - if (!PyArg_Parse(val, "i", &height)) - return -1; - -#ifdef FEAT_GUI - need_mouse_correct = TRUE; -#endif - savewin = curwin; - curwin = this->win; - win_setheight(height); - curwin = savewin; - - /* Check for keyboard interrupts */ - if (VimErrorCheck()) - return -1; - - return 0; - } -#ifdef FEAT_VERTSPLIT - else if (strcmp(name, "width") == 0) - { - int width; - win_T *savewin; - - if (!PyArg_Parse(val, "i", &width)) - return -1; - -#ifdef FEAT_GUI - need_mouse_correct = TRUE; -#endif - savewin = curwin; - curwin = this->win; - win_setwidth(width); - curwin = savewin; - - /* Check for keyboard interrupts */ - if (VimErrorCheck()) - return -1; - - return 0; - } -#endif - else - { - PyErr_SetString(PyExc_AttributeError, name); - return -1; - } -} - - static PyObject * -WindowRepr(PyObject *self) -{ - static char repr[100]; - WindowObject *this = (WindowObject *)(self); - - if (this->win == INVALID_WINDOW_VALUE) - { - vim_snprintf(repr, 100, _(""), (self)); - return PyString_FromString(repr); - } - else - { - int i = 0; - win_T *w; - - for (w = firstwin; w != NULL && w != this->win; w = W_NEXT(w)) - ++i; - - if (w == NULL) - vim_snprintf(repr, 100, _(""), - (self)); - else - vim_snprintf(repr, 100, _(""), i); - - return PyString_FromString(repr); - } -} - /* Window list object - Definitions */ @@ -2024,44 +1269,13 @@ static PyTypeObject WinListType = { (reprfunc) 0, /* tp_str, str(x) */ }; -/* Window list object - Implementation - */ - static PyInt -WinListLength(PyObject *self UNUSED) -{ - win_T *w = firstwin; - PyInt n = 0; - - while (w != NULL) - { - ++n; - w = W_NEXT(w); - } - - return n; -} - - static PyObject * -WinListItem(PyObject *self UNUSED, PyInt n) -{ - win_T *w; - - for (w = firstwin; w != NULL; w = W_NEXT(w), --n) - if (n == 0) - return WindowNew(w); - - PyErr_SetString(PyExc_IndexError, _("no such window")); - return NULL; -} - /* Current items object - Definitions */ typedef struct { PyObject_HEAD -} -CurrentObject; +} CurrentObject; static PyTypeObject CurrentType = { PyObject_HEAD_INIT(0) @@ -2206,178 +1420,6 @@ PythonMod_Init(void) * 4. Utility functions for handling the interface between Vim and Python. */ -/* Get a line from the specified buffer. The line number is - * in Vim format (1-based). The line is returned as a Python - * string object. - */ - static PyObject * -GetBufferLine(buf_T *buf, PyInt n) -{ - return LineToString((char *)ml_get_buf(buf, (linenr_T)n, FALSE)); -} - -/* Get a list of lines from the specified buffer. The line numbers - * are in Vim format (1-based). The range is from lo up to, but not - * including, hi. The list is returned as a Python list of string objects. - */ - static PyObject * -GetBufferLineList(buf_T *buf, PyInt lo, PyInt hi) -{ - PyInt i; - PyInt n = hi - lo; - PyObject *list = PyList_New(n); - - if (list == NULL) - return NULL; - - for (i = 0; i < n; ++i) - { - PyObject *str = LineToString((char *)ml_get_buf(buf, (linenr_T)(lo+i), FALSE)); - - /* Error check - was the Python string creation OK? */ - if (str == NULL) - { - Py_DECREF(list); - return NULL; - } - - /* Set the list item */ - if (PyList_SetItem(list, i, str)) - { - Py_DECREF(str); - Py_DECREF(list); - return NULL; - } - } - - /* The ownership of the Python list is passed to the caller (ie, - * the caller should Py_DECREF() the object when it is finished - * with it). - */ - - return list; -} - -/* - * Check if deleting lines made the cursor position invalid. - * Changed the lines from "lo" to "hi" and added "extra" lines (negative if - * deleted). - */ - static void -py_fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra) -{ - if (curwin->w_cursor.lnum >= lo) - { - /* Adjust the cursor position if it's in/after the changed - * lines. */ - if (curwin->w_cursor.lnum >= hi) - { - curwin->w_cursor.lnum += extra; - check_cursor_col(); - } - else if (extra < 0) - { - curwin->w_cursor.lnum = lo; - check_cursor(); - } - else - check_cursor_col(); - changed_cline_bef_curs(); - } - invalidate_botline(); -} - -/* Replace a line in the specified buffer. The line number is - * in Vim format (1-based). The replacement line is given as - * a Python string object. The object is checked for validity - * and correct format. Errors are returned as a value of FAIL. - * The return value is OK on success. - * If OK is returned and len_change is not NULL, *len_change - * is set to the change in the buffer length. - */ - static int -SetBufferLine(buf_T *buf, PyInt n, PyObject *line, PyInt *len_change) -{ - /* First of all, we check the thpe of the supplied Python object. - * There are three cases: - * 1. NULL, or None - this is a deletion. - * 2. A string - this is a replacement. - * 3. Anything else - this is an error. - */ - if (line == Py_None || line == NULL) - { - buf_T *savebuf = curbuf; - - PyErr_Clear(); - curbuf = buf; - - if (u_savedel((linenr_T)n, 1L) == FAIL) - PyErr_SetVim(_("cannot save undo information")); - else if (ml_delete((linenr_T)n, FALSE) == FAIL) - PyErr_SetVim(_("cannot delete line")); - else - { - if (buf == curwin->w_buffer) - py_fix_cursor((linenr_T)n, (linenr_T)n + 1, (linenr_T)-1); - deleted_lines_mark((linenr_T)n, 1L); - } - - curbuf = savebuf; - - if (PyErr_Occurred() || VimErrorCheck()) - return FAIL; - - if (len_change) - *len_change = -1; - - return OK; - } - else if (PyString_Check(line)) - { - char *save = StringToLine(line); - buf_T *savebuf = curbuf; - - if (save == NULL) - return FAIL; - - /* We do not need to free "save" if ml_replace() consumes it. */ - PyErr_Clear(); - curbuf = buf; - - if (u_savesub((linenr_T)n) == FAIL) - { - PyErr_SetVim(_("cannot save undo information")); - vim_free(save); - } - else if (ml_replace((linenr_T)n, (char_u *)save, FALSE) == FAIL) - { - PyErr_SetVim(_("cannot replace line")); - vim_free(save); - } - else - changed_bytes((linenr_T)n, 0); - - curbuf = savebuf; - - /* Check that the cursor is not beyond the end of the line now. */ - if (buf == curwin->w_buffer) - check_cursor_col(); - - if (PyErr_Occurred() || VimErrorCheck()) - return FAIL; - - if (len_change) - *len_change = 0; - - return OK; - } - else - { - PyErr_BadArgument(); - return FAIL; - } -} - /* Replace a range of lines in the specified buffer. The line numbers are in * Vim format (1-based). The range is from lo up to, but not including, hi. * The replacement lines are given as a Python list of string objects. The @@ -2566,131 +1608,6 @@ SetBufferLineList(buf_T *buf, PyInt lo, } } -/* Insert a number of lines into the specified buffer after the specifed line. - * The line number is in Vim format (1-based). The lines to be inserted are - * given as a Python list of string objects or as a single string. The lines - * to be added are checked for validity and correct format. Errors are - * returned as a value of FAIL. The return value is OK on success. - * If OK is returned and len_change is not NULL, *len_change - * is set to the change in the buffer length. - */ - static int -InsertBufferLines(buf_T *buf, PyInt n, PyObject *lines, PyInt *len_change) -{ - /* First of all, we check the type of the supplied Python object. - * It must be a string or a list, or the call is in error. - */ - if (PyString_Check(lines)) - { - char *str = StringToLine(lines); - buf_T *savebuf; - - if (str == NULL) - return FAIL; - - savebuf = curbuf; - - PyErr_Clear(); - curbuf = buf; - - if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL) - PyErr_SetVim(_("cannot save undo information")); - else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL) - PyErr_SetVim(_("cannot insert line")); - else - appended_lines_mark((linenr_T)n, 1L); - - vim_free(str); - curbuf = savebuf; - update_screen(VALID); - - if (PyErr_Occurred() || VimErrorCheck()) - return FAIL; - - if (len_change) - *len_change = 1; - - return OK; - } - else if (PyList_Check(lines)) - { - PyInt i; - PyInt size = PyList_Size(lines); - char **array; - buf_T *savebuf; - - array = (char **)alloc((unsigned)(size * sizeof(char *))); - if (array == NULL) - { - PyErr_NoMemory(); - return FAIL; - } - - for (i = 0; i < size; ++i) - { - PyObject *line = PyList_GetItem(lines, i); - array[i] = StringToLine(line); - - if (array[i] == NULL) - { - while (i) - vim_free(array[--i]); - vim_free(array); - return FAIL; - } - } - - savebuf = curbuf; - - PyErr_Clear(); - curbuf = buf; - - if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL) - PyErr_SetVim(_("cannot save undo information")); - else - { - for (i = 0; i < size; ++i) - { - if (ml_append((linenr_T)(n + i), - (char_u *)array[i], 0, FALSE) == FAIL) - { - PyErr_SetVim(_("cannot insert line")); - - /* Free the rest of the lines */ - while (i < size) - vim_free(array[i++]); - - break; - } - vim_free(array[i]); - } - if (i > 0) - appended_lines_mark((linenr_T)n, (long)i); - } - - /* Free the array of lines. All of its contents have now - * been freed. - */ - vim_free(array); - - curbuf = savebuf; - update_screen(VALID); - - if (PyErr_Occurred() || VimErrorCheck()) - return FAIL; - - if (len_change) - *len_change = size; - - return OK; - } - else - { - PyErr_BadArgument(); - return FAIL; - } -} - /* Convert a Vim line into a Python string. * All internal newlines are replaced by null characters. * @@ -2727,73 +1644,6 @@ LineToString(const char *str) return result; } -/* Convert a Python string into a Vim line. - * - * The result is in allocated memory. All internal nulls are replaced by - * newline characters. It is an error for the string to contain newline - * characters. - * - * On errors, the Python exception data is set, and NULL is returned. - */ - static char * -StringToLine(PyObject *obj) -{ - const char *str; - char *save; - PyInt len; - PyInt i; - char *p; - - if (obj == NULL || !PyString_Check(obj)) - { - PyErr_BadArgument(); - return NULL; - } - - str = PyString_AsString(obj); - len = PyString_Size(obj); - - /* - * Error checking: String must not contain newlines, as we - * are replacing a single line, and we must replace it with - * a single line. - * A trailing newline is removed, so that append(f.readlines()) works. - */ - p = memchr(str, '\n', len); - if (p != NULL) - { - if (p == str + len - 1) - --len; - else - { - PyErr_SetVim(_("string cannot contain newlines")); - return NULL; - } - } - - /* Create a copy of the string, with internal nulls replaced by - * newline characters, as is the vim convention. - */ - save = (char *)alloc((unsigned)(len+1)); - if (save == NULL) - { - PyErr_NoMemory(); - return NULL; - } - - for (i = 0; i < len; ++i) - { - if (str[i] == '\0') - save[i] = '\n'; - else - save[i] = str[i]; - } - - save[i] = '\0'; - - return save; -} - /* Don't generate a prototype for the next function, it generates an error on * newer Python versions. */ @@ -2814,4 +1664,12 @@ init_structs(void) OutputType.tp_basicsize = sizeof(OutputObject); OutputType.tp_getattr = OutputGetattr; OutputType.tp_setattr = OutputSetattr; + + vim_memset(&RangeType, 0, sizeof(RangeType)); + RangeType.tp_name = "range"; + RangeType.tp_basicsize = sizeof(RangeObject); + RangeType.tp_dealloc = RangeDestructor; + RangeType.tp_getattr = RangeGetattr; + RangeType.tp_repr = RangeRepr; + RangeType.tp_as_sequence = &RangeAsSeq; } diff --git a/src/if_python3.c b/src/if_python3.c --- a/src/if_python3.c +++ b/src/if_python3.c @@ -69,6 +69,10 @@ static void init_structs(void); #define PyInt Py_ssize_t +#define PyString_Check(obj) PyUnicode_Check(obj) +#define PyString_AsString(obj) _PyUnicode_AsString(obj) +#define PyString_Size(obj) PyUnicode_GET_SIZE(obj) +#define PyString_FromString(repr) PyUnicode_FromString(repr) #if defined(DYNAMIC_PYTHON3) @@ -424,6 +428,12 @@ get_py3_exceptions() } #endif /* DYNAMIC_PYTHON3 */ +static PyObject *BufferNew (buf_T *); +static PyObject *WindowNew(win_T *); +static PyObject *LineToString(const char *); + +static PyTypeObject RangeType; + /* * Include the code shared with if_python.c */ @@ -455,36 +465,19 @@ call_PyType_GenericAlloc(PyTypeObject *t * Internal function prototypes. */ -static void DoPy3Command(exarg_T *, const char *); static Py_ssize_t RangeStart; static Py_ssize_t RangeEnd; -static void PythonIO_Flush(void); static int PythonIO_Init(void); static void PythonIO_Fini(void); PyMODINIT_FUNC Py3Init_vim(void); -/* Utility functions for the vim/python interface - * ---------------------------------------------- - */ -static PyObject *GetBufferLine(buf_T *, Py_ssize_t); - -static int SetBufferLine(buf_T *, Py_ssize_t, PyObject *, Py_ssize_t*); -static int InsertBufferLines(buf_T *, Py_ssize_t, PyObject *, Py_ssize_t*); -static PyObject *GetBufferLineList(buf_T *buf, Py_ssize_t lo, Py_ssize_t hi); - -static PyObject *LineToString(const char *); -static char *StringToLine(PyObject *); - -#define PyErr_SetVim(str) PyErr_SetString(VimError, str) - /****************************************************** * 1. Python interpreter main program. */ static int py3initialised = 0; - static PyGILState_STATE pygilstate = PyGILState_UNLOCKED; void @@ -732,11 +725,6 @@ ex_py3file(exarg_T *eap) /* Implementation functions */ -static PyObject *OutputGetattro(PyObject *, PyObject *); -static int OutputSetattro(PyObject *, PyObject *, PyObject *); - -/*************/ - static PyObject * OutputGetattro(PyObject *self, PyObject *nameobj) { @@ -797,439 +785,37 @@ PythonIO_Fini(void) * 3. Implementation of the Vim module for Python */ -/* Vim module - Implementation functions - * ------------------------------------- - */ - -static PyObject *VimCommand(PyObject *, PyObject *); -static PyObject *VimEval(PyObject *, PyObject *); - /* Window type - Implementation functions * -------------------------------------- */ -typedef struct -{ - PyObject_HEAD - win_T *win; -} -WindowObject; - -#define INVALID_WINDOW_VALUE ((win_T *)(-1)) - #define WindowType_Check(obj) ((obj)->ob_base.ob_type == &WindowType) -static PyObject *WindowNew(win_T *); - -static void WindowDestructor(PyObject *); -static PyObject *WindowGetattro(PyObject *, PyObject *); -static int WindowSetattro(PyObject *, PyObject *, PyObject *); -static PyObject *WindowRepr(PyObject *); - /* Buffer type - Implementation functions * -------------------------------------- */ -typedef struct -{ - PyObject_HEAD - buf_T *buf; -} -BufferObject; - -#define INVALID_BUFFER_VALUE ((buf_T *)(-1)) - #define BufferType_Check(obj) ((obj)->ob_base.ob_type == &BufferType) -static PyObject *BufferNew (buf_T *); - -static void BufferDestructor(PyObject *); - -static PyObject *BufferGetattro(PyObject *, PyObject*); -static PyObject *BufferRepr(PyObject *); - static Py_ssize_t BufferLength(PyObject *); static PyObject *BufferItem(PyObject *, Py_ssize_t); static Py_ssize_t BufferAsItem(PyObject *, Py_ssize_t, PyObject *); static PyObject* BufferSubscript(PyObject *self, PyObject* idx); -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; - Py_ssize_t start; - Py_ssize_t end; -} -RangeObject; - #define RangeType_Check(obj) ((obj)->ob_base.ob_type == &RangeType) -static PyObject *RangeNew(buf_T *, Py_ssize_t, Py_ssize_t); - -static void RangeDestructor(PyObject *); -static PyObject *RangeGetattro(PyObject *, PyObject *); -static PyObject *RangeRepr(PyObject *); static PyObject* RangeSubscript(PyObject *self, PyObject* idx); - -static Py_ssize_t RangeLength(PyObject *); -static PyObject *RangeItem(PyObject *, Py_ssize_t); static Py_ssize_t RangeAsItem(PyObject *, Py_ssize_t, PyObject *); -static PyObject *RangeAppend(PyObject *, PyObject *); - -/* Window list type - Implementation functions - * ------------------------------------------- - */ - -static Py_ssize_t WinListLength(PyObject *); -static PyObject *WinListItem(PyObject *, Py_ssize_t); - -/* Buffer list type - Implementation functions - * ------------------------------------------- - */ - -static Py_ssize_t BufListLength(PyObject *); -static PyObject *BufListItem(PyObject *, Py_ssize_t); - /* Current objects type - Implementation functions * ----------------------------------------------- */ -static PyObject *CurrentGetattro(PyObject *, PyObject *); -static int CurrentSetattro(PyObject *, PyObject *, PyObject *); - -/* Vim module - Definitions - */ - -static struct PyMethodDef VimMethods[] = { - /* name, function, calling, documentation */ - {"command", VimCommand, 1, "Execute a Vim ex-mode command" }, - {"eval", VimEval, 1, "Evaluate an expression using Vim evaluator" }, - { NULL, NULL, 0, NULL } -}; - -/* Vim module - Implementation - */ - static PyObject * -VimCommand(PyObject *self UNUSED, PyObject *args) -{ - char *cmd; - PyObject *result; - - if (!PyArg_ParseTuple(args, "s", &cmd)) - return NULL; - - PyErr_Clear(); - - Py_BEGIN_ALLOW_THREADS - Python_Lock_Vim(); - - do_cmdline_cmd((char_u *)cmd); - update_screen(VALID); - - Python_Release_Vim(); - Py_END_ALLOW_THREADS - - if (VimErrorCheck()) - result = NULL; - else - result = Py_None; - - Py_XINCREF(result); - return result; -} - -#ifdef FEAT_EVAL -/* - * Function to translate a typval_T into a PyObject; this will recursively - * translate lists/dictionaries into their Python equivalents. - * - * The depth parameter is to avoid infinite recursion, set it to 1 when - * you call VimToPython. - */ - static PyObject * -VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict) -{ - PyObject *result; - PyObject *newObj; - char ptrBuf[NUMBUFLEN]; - - /* Avoid infinite recursion */ - if (depth > 100) - { - Py_INCREF(Py_None); - result = Py_None; - return result; - } - - /* Check if we run into a recursive loop. The item must be in lookupDict - * then and we can use it again. */ - if ((our_tv->v_type == VAR_LIST && our_tv->vval.v_list != NULL) - || (our_tv->v_type == VAR_DICT && our_tv->vval.v_dict != NULL)) - { - sprintf(ptrBuf, PRINTF_DECIMAL_LONG_U, - our_tv->v_type == VAR_LIST ? (long_u)our_tv->vval.v_list - : (long_u)our_tv->vval.v_dict); - result = PyDict_GetItemString(lookupDict, ptrBuf); - if (result != NULL) - { - Py_INCREF(result); - return result; - } - } - - if (our_tv->v_type == VAR_STRING) - { - result = Py_BuildValue("s", our_tv->vval.v_string); - } - else if (our_tv->v_type == VAR_NUMBER) - { - char buf[NUMBUFLEN]; - - /* For backwards compatibility numbers are stored as strings. */ - sprintf(buf, "%ld", (long)our_tv->vval.v_number); - result = Py_BuildValue("s", buf); - } -# ifdef FEAT_FLOAT - else if (our_tv->v_type == VAR_FLOAT) - { - char buf[NUMBUFLEN]; - - sprintf(buf, "%f", our_tv->vval.v_float); - result = Py_BuildValue("s", buf); - } -# endif - else if (our_tv->v_type == VAR_LIST) - { - list_T *list = our_tv->vval.v_list; - listitem_T *curr; - - result = PyList_New(0); - - if (list != NULL) - { - PyDict_SetItemString(lookupDict, ptrBuf, result); - - for (curr = list->lv_first; curr != NULL; curr = curr->li_next) - { - newObj = VimToPython(&curr->li_tv, depth + 1, lookupDict); - PyList_Append(result, newObj); - Py_DECREF(newObj); - } - } - } - else if (our_tv->v_type == VAR_DICT) - { - result = PyDict_New(); - - if (our_tv->vval.v_dict != NULL) - { - hashtab_T *ht = &our_tv->vval.v_dict->dv_hashtab; - long_u todo = ht->ht_used; - hashitem_T *hi; - dictitem_T *di; - - PyDict_SetItemString(lookupDict, ptrBuf, result); - - for (hi = ht->ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - --todo; - - di = dict_lookup(hi); - newObj = VimToPython(&di->di_tv, depth + 1, lookupDict); - PyDict_SetItemString(result, (char *)hi->hi_key, newObj); - Py_DECREF(newObj); - } - } - } - } - else - { - Py_INCREF(Py_None); - result = Py_None; - } - - return result; -} -#endif - - static PyObject * -VimEval(PyObject *self UNUSED, PyObject *args) -{ -#ifdef FEAT_EVAL - char *expr; - typval_T *our_tv; - PyObject *result; - PyObject *lookup_dict; - - if (!PyArg_ParseTuple(args, "s", &expr)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - Python_Lock_Vim(); - our_tv = eval_expr((char_u *)expr, NULL); - - Python_Release_Vim(); - Py_END_ALLOW_THREADS - - if (our_tv == NULL) - { - PyErr_SetVim(_("invalid expression")); - return NULL; - } - - /* Convert the Vim type into a Python type. Create a dictionary that's - * used to check for recursive loops. */ - lookup_dict = PyDict_New(); - result = VimToPython(our_tv, 1, lookup_dict); - Py_DECREF(lookup_dict); - - - Py_BEGIN_ALLOW_THREADS - Python_Lock_Vim(); - free_tv(our_tv); - Python_Release_Vim(); - Py_END_ALLOW_THREADS - - return result; -#else - PyErr_SetVim(_("expressions disabled at compile time")); - return NULL; -#endif -} - -/* Common routines for buffers and line ranges - * ------------------------------------------- - */ - - static int -CheckBuffer(BufferObject *this) -{ - if (this->buf == INVALID_BUFFER_VALUE) - { - PyErr_SetVim(_("attempt to refer to deleted buffer")); - return -1; - } - - return 0; -} - - static PyObject * -RBItem(BufferObject *self, Py_ssize_t n, Py_ssize_t start, Py_ssize_t end) -{ - if (CheckBuffer(self)) - return NULL; - - if (n < 0 || n > end - start) - { - PyErr_SetString(PyExc_IndexError, _("line number out of range")); - return NULL; - } - - return GetBufferLine(self->buf, n+start); -} - - static PyObject * -RBSlice(BufferObject *self, Py_ssize_t lo, Py_ssize_t hi, Py_ssize_t start, Py_ssize_t end) -{ - Py_ssize_t size; - - if (CheckBuffer(self)) - return NULL; - - size = end - start + 1; - - if (lo < 0) - lo = 0; - else if (lo > size) - lo = size; - if (hi < 0) - hi = 0; - if (hi < lo) - hi = lo; - else if (hi > size) - hi = size; - - return GetBufferLineList(self->buf, lo+start, hi+start); -} - - static Py_ssize_t -RBAsItem(BufferObject *self, Py_ssize_t n, PyObject *val, Py_ssize_t start, Py_ssize_t end, Py_ssize_t *new_end) -{ - Py_ssize_t len_change; - - if (CheckBuffer(self)) - return -1; - - if (n < 0 || n > end - start) - { - PyErr_SetString(PyExc_IndexError, _("line number out of range")); - return -1; - } - - if (SetBufferLine(self->buf, n+start, val, &len_change) == FAIL) - return -1; - - if (new_end) - *new_end = end + len_change; - - return 0; -} - - static PyObject * -RBAppend(BufferObject *self, PyObject *args, Py_ssize_t start, Py_ssize_t end, Py_ssize_t *new_end) -{ - PyObject *lines; - Py_ssize_t len_change; - Py_ssize_t max; - Py_ssize_t n; - - if (CheckBuffer(self)) - return NULL; - - max = n = end - start + 1; - - if (!PyArg_ParseTuple(args, "O|n" , &lines, &n)) - return NULL; - - if (n < 0 || n > max) - { - PyErr_SetString(PyExc_ValueError, _("line number out of range")); - return NULL; - } - - if (InsertBufferLines(self->buf, n + start - 1, lines, &len_change) == FAIL) - return NULL; - - if (new_end) - *new_end = end + len_change; - - Py_INCREF(Py_None); - return Py_None; -} - - -/* Buffer object - Definitions - */ - -static struct PyMethodDef BufferMethods[] = { - /* name, function, calling, documentation */ - {"append", BufferAppend, 1, "Append data to Vim buffer" }, - {"mark", BufferMark, 1, "Return (row,col) representing position of named mark" }, - {"range", BufferRange, 1, "Return a range object which represents the part of the given buffer between line numbers s and e" }, - { NULL, NULL, 0, NULL } -}; - static PySequenceMethods BufferAsSeq = { (lenfunc) BufferLength, /* sq_length, len(x) */ (binaryfunc) 0, /* sq_concat, x+y */ @@ -1407,78 +993,6 @@ BufferSubscript(PyObject *self, PyObject } } - static PyObject * -BufferAppend(PyObject *self, PyObject *args) -{ - return RBAppend((BufferObject *)(self), args, 1, - (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count, - NULL); -} - - static PyObject * -BufferMark(PyObject *self, PyObject *args) -{ - pos_T *posp; - char *pmark;//test - char mark; - buf_T *curbuf_save; - - if (CheckBuffer((BufferObject *)(self))) - return NULL; - - if (!PyArg_ParseTuple(args, "s", &pmark))//test: "c"->"s" - return NULL; - mark = *pmark;//test - - curbuf_save = curbuf; - curbuf = ((BufferObject *)(self))->buf; - posp = getmark(mark, FALSE); - curbuf = curbuf_save; - - if (posp == NULL) - { - PyErr_SetVim(_("invalid mark name")); - return NULL; - } - - /* Ckeck for keyboard interrupt */ - if (VimErrorCheck()) - return NULL; - - if (posp->lnum <= 0) - { - /* Or raise an error? */ - Py_INCREF(Py_None); - return Py_None; - } - - return Py_BuildValue("(ll)", (long)(posp->lnum), (long)(posp->col)); -} - - static PyObject * -BufferRange(PyObject *self, PyObject *args) -{ - Py_ssize_t start; - Py_ssize_t end; - - if (CheckBuffer((BufferObject *)(self))) - return NULL; - - if (!PyArg_ParseTuple(args, "nn", &start, &end)) - return NULL; - - return RangeNew(((BufferObject *)(self))->buf, start, end); -} - -/* Line range object - Definitions - */ - -static struct PyMethodDef RangeMethods[] = { - /* name, function, calling, documentation */ - {"append", RangeAppend, 1, "Append data to the Vim range" }, - { NULL, NULL, 0, NULL } -}; - static PySequenceMethods RangeAsSeq = { (lenfunc) RangeLength, /* sq_length, len(x) */ (binaryfunc) 0, /* RangeConcat, sq_concat, x+y */ @@ -1498,35 +1012,9 @@ PyMappingMethods RangeAsMapping = { /* mp_ass_subscript */ (objobjargproc)0, }; -static PyTypeObject RangeType; - /* Line range object - Implementation */ - static PyObject * -RangeNew(buf_T *buf, Py_ssize_t start, Py_ssize_t end) -{ - BufferObject *bufr; - RangeObject *self; - self = PyObject_NEW(RangeObject, &RangeType); - if (self == NULL) - return NULL; - - bufr = (BufferObject *)BufferNew(buf); - if (bufr == NULL) - { - Py_DECREF(self); - return NULL; - } - Py_INCREF(bufr); - - self->buf = bufr; - self->start = start; - self->end = end; - - return (PyObject *)(self); -} - static void RangeDestructor(PyObject *self) { @@ -1548,59 +1036,9 @@ RangeGetattro(PyObject *self, PyObject * return PyObject_GenericGetAttr(self, nameobj); } - static PyObject * -RangeRepr(PyObject *self) -{ - static char repr[100]; - RangeObject *this = (RangeObject *)(self); - - if (this->buf->buf == INVALID_BUFFER_VALUE) - { - vim_snprintf(repr, 100, "", - (self)); - return PyUnicode_FromString(repr); - } - else - { - char *name = (char *)this->buf->buf->b_fname; - int len; - - if (name == NULL) - name = ""; - len = (int)strlen(name); - - if (len > 45) - name = name + (45 - len); - - vim_snprintf(repr, 100, "", - len > 45 ? "..." : "", name, - this->start, this->end); - - return PyUnicode_FromString(repr); - } -} - /****************/ static Py_ssize_t -RangeLength(PyObject *self) -{ - /* HOW DO WE SIGNAL AN ERROR FROM THIS FUNCTION? */ - if (CheckBuffer(((RangeObject *)(self))->buf)) - return -1; /* ??? */ - - return (((RangeObject *)(self))->end - ((RangeObject *)(self))->start + 1); -} - - static PyObject * -RangeItem(PyObject *self, Py_ssize_t n) -{ - return RBItem(((RangeObject *)(self))->buf, n, - ((RangeObject *)(self))->start, - ((RangeObject *)(self))->end); -} - - static Py_ssize_t RangeAsItem(PyObject *self, Py_ssize_t n, PyObject *val) { return RBAsItem(((RangeObject *)(self))->buf, n, val, @@ -1610,14 +1048,6 @@ RangeAsItem(PyObject *self, Py_ssize_t n } static PyObject * -RangeSlice(PyObject *self, Py_ssize_t lo, Py_ssize_t hi) -{ - return RBSlice(((RangeObject *)(self))->buf, lo, hi, - ((RangeObject *)(self))->start, - ((RangeObject *)(self))->end); -} - - static PyObject * RangeSubscript(PyObject *self, PyObject* idx) { if (PyLong_Check(idx)) { @@ -1639,23 +1069,13 @@ RangeSubscript(PyObject *self, PyObject* } } - static PyObject * -RangeAppend(PyObject *self, PyObject *args) -{ - return RBAppend(((RangeObject *)(self))->buf, args, - ((RangeObject *)(self))->start, - ((RangeObject *)(self))->end, - &((RangeObject *)(self))->end); -} - /* Buffer list object - Definitions */ typedef struct { PyObject_HEAD -} -BufListObject; +} BufListObject; static PySequenceMethods BufListAsSeq = { (lenfunc) BufListLength, /* sq_length, len(x) */ @@ -1672,39 +1092,6 @@ static PySequenceMethods BufListAsSeq = static PyTypeObject BufListType; -/* Buffer list object - Implementation - */ - - static Py_ssize_t -BufListLength(PyObject *self UNUSED) -{ - buf_T *b = firstbuf; - Py_ssize_t n = 0; - - while (b) - { - ++n; - b = b->b_next; - } - - return n; -} - - static PyObject * -BufListItem(PyObject *self UNUSED, Py_ssize_t n) -{ - buf_T *b; - - for (b = firstbuf; b; b = b->b_next, --n) - { - if (n == 0) - return BufferNew(b); - } - - PyErr_SetString(PyExc_IndexError, _("no such buffer")); - return NULL; -} - /* Window object - Definitions */ @@ -1761,18 +1148,6 @@ WindowDestructor(PyObject *self) this->win->w_python3_ref = NULL; } - static int -CheckWindow(WindowObject *this) -{ - if (this->win == INVALID_WINDOW_VALUE) - { - PyErr_SetVim(_("attempt to refer to deleted window")); - return -1; - } - - return 0; -} - static PyObject * WindowGetattro(PyObject *self, PyObject *nameobj) { @@ -1809,134 +1184,12 @@ WindowGetattro(PyObject *self, PyObject static int WindowSetattro(PyObject *self, PyObject *nameobj, PyObject *val) { - WindowObject *this = (WindowObject *)(self); + char *name = ""; - char *name = ""; if (PyUnicode_Check(nameobj)) name = _PyUnicode_AsString(nameobj); - - if (CheckWindow(this)) - return -1; - - if (strcmp(name, "buffer") == 0) - { - PyErr_SetString(PyExc_TypeError, _("readonly attribute")); - return -1; - } - else if (strcmp(name, "cursor") == 0) - { - long lnum; - long col; - long len; - - if (!PyArg_Parse(val, "(ll)", &lnum, &col)) - return -1; - - if (lnum <= 0 || lnum > this->win->w_buffer->b_ml.ml_line_count) - { - PyErr_SetVim(_("cursor position outside buffer")); - return -1; - } - - /* Check for keyboard interrupts */ - if (VimErrorCheck()) - return -1; - - /* When column is out of range silently correct it. */ - len = (long)STRLEN(ml_get_buf(this->win->w_buffer, lnum, FALSE)); - if (col > len) - col = len; - - this->win->w_cursor.lnum = lnum; - this->win->w_cursor.col = col; -#ifdef FEAT_VIRTUALEDIT - this->win->w_cursor.coladd = 0; -#endif - update_screen(VALID); - - return 0; - } - else if (strcmp(name, "height") == 0) - { - int height; - win_T *savewin; - - if (!PyArg_Parse(val, "i", &height)) - return -1; - -#ifdef FEAT_GUI - need_mouse_correct = TRUE; -#endif - savewin = curwin; - curwin = this->win; - win_setheight(height); - curwin = savewin; - - /* Check for keyboard interrupts */ - if (VimErrorCheck()) - return -1; - - return 0; - } -#ifdef FEAT_VERTSPLIT - else if (strcmp(name, "width") == 0) - { - int width; - win_T *savewin; - - if (!PyArg_Parse(val, "i", &width)) - return -1; - -#ifdef FEAT_GUI - need_mouse_correct = TRUE; -#endif - savewin = curwin; - curwin = this->win; - win_setwidth(width); - curwin = savewin; - - /* Check for keyboard interrupts */ - if (VimErrorCheck()) - return -1; - - return 0; - } -#endif - else - { - PyErr_SetString(PyExc_AttributeError, name); - return -1; - } -} - - static PyObject * -WindowRepr(PyObject *self) -{ - static char repr[100]; - WindowObject *this = (WindowObject *)(self); - - if (this->win == INVALID_WINDOW_VALUE) - { - vim_snprintf(repr, 100, _(""), (self)); - return PyUnicode_FromString(repr); - } - else - { - int i = 0; - win_T *w; - - for (w = firstwin; w != NULL && w != this->win; w = W_NEXT(w)) - ++i; - - if (w == NULL) - vim_snprintf(repr, 100, _(""), - (self)); - else - vim_snprintf(repr, 100, _(""), i); - - return PyUnicode_FromString(repr); - } + return WindowSetattr(self, name, val); } /* Window list object - Definitions @@ -1963,44 +1216,13 @@ static PySequenceMethods WinListAsSeq = static PyTypeObject WinListType; -/* Window list object - Implementation - */ - static Py_ssize_t -WinListLength(PyObject *self UNUSED) -{ - win_T *w = firstwin; - Py_ssize_t n = 0; - - while (w != NULL) - { - ++n; - w = W_NEXT(w); - } - - return n; -} - - static PyObject * -WinListItem(PyObject *self UNUSED, Py_ssize_t n) -{ - win_T *w; - - for (w = firstwin; w != NULL; w = W_NEXT(w), --n) - if (n == 0) - return WindowNew(w); - - PyErr_SetString(PyExc_IndexError, _("no such window")); - return NULL; -} - /* Current items object - Definitions */ typedef struct { PyObject_HEAD -} -CurrentObject; +} CurrentObject; static PyTypeObject CurrentType; @@ -2137,304 +1359,6 @@ PyMODINIT_FUNC Py3Init_vim(void) * 4. Utility functions for handling the interface between Vim and Python. */ -/* Get a line from the specified buffer. The line number is - * in Vim format (1-based). The line is returned as a Python - * string object. - */ - static PyObject * -GetBufferLine(buf_T *buf, Py_ssize_t n) -{ - return LineToString((char *)ml_get_buf(buf, (linenr_T)n, FALSE)); -} - - -/* Get a list of lines from the specified buffer. The line numbers - * are in Vim format (1-based). The range is from lo up to, but not - * including, hi. The list is returned as a Python list of string objects. - */ - static PyObject * -GetBufferLineList(buf_T *buf, Py_ssize_t lo, Py_ssize_t hi) -{ - Py_ssize_t i; - Py_ssize_t n = hi - lo; - PyObject *list = PyList_New(n); - - if (list == NULL) - return NULL; - - for (i = 0; i < n; ++i) - { - PyObject *str = LineToString((char *)ml_get_buf(buf, (linenr_T)(lo+i), FALSE)); - - /* Error check - was the Python string creation OK? */ - if (str == NULL) - { - Py_DECREF(list); - return NULL; - } - - /* Set the list item */ - if (PyList_SetItem(list, i, str)) - { - Py_DECREF(str); - Py_DECREF(list); - return NULL; - } - } - - /* The ownership of the Python list is passed to the caller (ie, - * the caller should Py_DECREF() the object when it is finished - * with it). - */ - - return list; -} - -/* - * Check if deleting lines made the cursor position invalid. - * Changed the lines from "lo" to "hi" and added "extra" lines (negative if - * deleted). - */ - static void -py_fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra) -{ - if (curwin->w_cursor.lnum >= lo) - { - /* Adjust the cursor position if it's in/after the changed - * lines. */ - if (curwin->w_cursor.lnum >= hi) - { - curwin->w_cursor.lnum += extra; - check_cursor_col(); - } - else if (extra < 0) - { - curwin->w_cursor.lnum = lo; - check_cursor(); - } - else - check_cursor_col(); - changed_cline_bef_curs(); - } - invalidate_botline(); -} - -/* Replace a line in the specified buffer. The line number is - * in Vim format (1-based). The replacement line is given as - * a Python string object. The object is checked for validity - * and correct format. Errors are returned as a value of FAIL. - * The return value is OK on success. - * If OK is returned and len_change is not NULL, *len_change - * is set to the change in the buffer length. - */ - static int -SetBufferLine(buf_T *buf, Py_ssize_t n, PyObject *line, Py_ssize_t *len_change) -{ - /* First of all, we check the thpe of the supplied Python object. - * There are three cases: - * 1. NULL, or None - this is a deletion. - * 2. A string - this is a replacement. - * 3. Anything else - this is an error. - */ - if (line == Py_None || line == NULL) - { - buf_T *savebuf = curbuf; - - PyErr_Clear(); - curbuf = buf; - - if (u_savedel((linenr_T)n, 1L) == FAIL) - PyErr_SetVim(_("cannot save undo information")); - else if (ml_delete((linenr_T)n, FALSE) == FAIL) - PyErr_SetVim(_("cannot delete line")); - else - { - if (buf == curwin->w_buffer) - py_fix_cursor((linenr_T)n, (linenr_T)n + 1, (linenr_T)-1); - deleted_lines_mark((linenr_T)n, 1L); - } - - curbuf = savebuf; - - if (PyErr_Occurred() || VimErrorCheck()) - return FAIL; - - if (len_change) - *len_change = -1; - - return OK; - } - else if (PyUnicode_Check(line)) - { - char *save = StringToLine(line); - buf_T *savebuf = curbuf; - - if (save == NULL) - return FAIL; - - /* We do not need to free "save" if ml_replace() consumes it. */ - PyErr_Clear(); - curbuf = buf; - - if (u_savesub((linenr_T)n) == FAIL) - { - PyErr_SetVim(_("cannot save undo information")); - vim_free(save); - } - else if (ml_replace((linenr_T)n, (char_u *)save, FALSE) == FAIL) - { - PyErr_SetVim(_("cannot replace line")); - vim_free(save); - } - else - changed_bytes((linenr_T)n, 0); - - curbuf = savebuf; - - /* Check that the cursor is not beyond the end of the line now. */ - if (buf == curwin->w_buffer) - check_cursor_col(); - - if (PyErr_Occurred() || VimErrorCheck()) - return FAIL; - - if (len_change) - *len_change = 0; - - return OK; - } - else - { - PyErr_BadArgument(); - return FAIL; - } -} - -/* Insert a number of lines into the specified buffer after the specifed line. - * The line number is in Vim format (1-based). The lines to be inserted are - * given as a Python list of string objects or as a single string. The lines - * to be added are checked for validity and correct format. Errors are - * returned as a value of FAIL. The return value is OK on success. - * If OK is returned and len_change is not NULL, *len_change - * is set to the change in the buffer length. - */ - static int -InsertBufferLines(buf_T *buf, Py_ssize_t n, PyObject *lines, Py_ssize_t *len_change) -{ - /* First of all, we check the type of the supplied Python object. - * It must be a string or a list, or the call is in error. - */ - if (PyUnicode_Check(lines)) - { - char *str = StringToLine(lines); - buf_T *savebuf; - - if (str == NULL) - return FAIL; - - savebuf = curbuf; - - PyErr_Clear(); - curbuf = buf; - - if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL) - PyErr_SetVim(_("cannot save undo information")); - else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL) - PyErr_SetVim(_("cannot insert line")); - else - appended_lines_mark((linenr_T)n, 1L); - - vim_free(str); - curbuf = savebuf; - update_screen(VALID); - - if (PyErr_Occurred() || VimErrorCheck()) - return FAIL; - - if (len_change) - *len_change = 1; - - return OK; - } - else if (PyList_Check(lines)) - { - Py_ssize_t i; - Py_ssize_t size = PyList_Size(lines); - char **array; - buf_T *savebuf; - - array = (char **)alloc((unsigned)(size * sizeof(char *))); - if (array == NULL) - { - PyErr_NoMemory(); - return FAIL; - } - - for (i = 0; i < size; ++i) - { - PyObject *line = PyList_GetItem(lines, i); - array[i] = StringToLine(line); - - if (array[i] == NULL) - { - while (i) - vim_free(array[--i]); - vim_free(array); - return FAIL; - } - } - - savebuf = curbuf; - - PyErr_Clear(); - curbuf = buf; - - if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL) - PyErr_SetVim(_("cannot save undo information")); - else - { - for (i = 0; i < size; ++i) - { - if (ml_append((linenr_T)(n + i), - (char_u *)array[i], 0, FALSE) == FAIL) - { - PyErr_SetVim(_("cannot insert line")); - - /* Free the rest of the lines */ - while (i < size) - vim_free(array[i++]); - - break; - } - vim_free(array[i]); - } - if (i > 0) - appended_lines_mark((linenr_T)n, (long)i); - } - - /* Free the array of lines. All of its contents have now - * been freed. - */ - vim_free(array); - - curbuf = savebuf; - update_screen(VALID); - - if (PyErr_Occurred() || VimErrorCheck()) - return FAIL; - - if (len_change) - *len_change = size; - - return OK; - } - else - { - PyErr_BadArgument(); - return FAIL; - } -} - /* Convert a Vim line into a Python string. * All internal newlines are replaced by null characters. * @@ -2473,73 +1397,6 @@ LineToString(const char *str) return result; } -/* Convert a Python string into a Vim line. - * - * The result is in allocated memory. All internal nulls are replaced by - * newline characters. It is an error for the string to contain newline - * characters. - * - * On errors, the Python exception data is set, and NULL is returned. - */ - static char * -StringToLine(PyObject *obj) -{ - const char *str; - char *save; - Py_ssize_t len; - Py_ssize_t i; - char *p; - - if (obj == NULL || !PyUnicode_Check(obj)) - { - PyErr_BadArgument(); - return NULL; - } - - str = _PyUnicode_AsString(obj); - len = PyUnicode_GET_SIZE(obj); - - /* - * Error checking: String must not contain newlines, as we - * are replacing a single line, and we must replace it with - * a single line. - * A trailing newline is removed, so that append(f.readlines()) works. - */ - p = memchr(str, '\n', len); - if (p != NULL) - { - if (p == str + len - 1) - --len; - else - { - PyErr_SetVim(_("string cannot contain newlines")); - return NULL; - } - } - - /* Create a copy of the string, with internal nulls replaced by - * newline characters, as is the vim convention. - */ - save = (char *)alloc((unsigned)(len+1)); - if (save == NULL) - { - PyErr_NoMemory(); - return NULL; - } - - for (i = 0; i < len; ++i) - { - if (str[i] == '\0') - save[i] = '\n'; - else - save[i] = str[i]; - } - - save[i] = '\0'; - - return save; -} - static void init_structs(void) {