📄 if_python.c
字号:
}
/* 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 *buf, int lo, int hi)
{
int i;
int 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;
}
/* 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 *buf, int n, PyObject *line, int *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 *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
{
mark_adjust((linenr_t)n, (linenr_t)n, (long)MAXLNUM, -1L);
changed();
}
curbuf = savebuf;
update_screen(NOT_VALID);
if (PyErr_Occurred() || VimErrorCheck())
return FAIL;
if (len_change)
*len_change = -1;
return OK;
}
else if (PyString_Check(line))
{
char *save = StringToLine(line);
BUF *savebuf = curbuf;
if (save == NULL)
return FAIL;
/* We do not need to free save, as we pass responsibility for
* it to vim, via the final parameter of ml_replace().
*/
PyErr_Clear();
curbuf = buf;
if (u_savesub((linenr_t)n) == FAIL)
PyErr_SetVim("cannot save undo information");
else if (ml_replace((linenr_t)n, (char_u *)save, TRUE) == FAIL)
PyErr_SetVim("cannot replace line");
else
{
changed();
#ifdef SYNTAX_HL
syn_changed((linenr_t)n); /* recompute syntax hl. for this line */
#endif
}
curbuf = savebuf;
update_screen(NOT_VALID);
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
* list 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
SetBufferLineList(BUF *buf, int lo, int hi, PyObject *list, int *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 list - this is a replacement.
* 3. Anything else - this is an error.
*/
if (list == Py_None || list == NULL)
{
int i;
int ok = 0;
int n = hi - lo;
BUF *savebuf = curbuf;
PyErr_Clear();
curbuf = buf;
if (u_savedel((linenr_t)lo, (long)n) == FAIL)
PyErr_SetVim("cannot save undo information");
else
{
ok = 1;
for (i = 0; i < n; ++i)
{
if (ml_delete((linenr_t)lo, FALSE) == FAIL)
{
PyErr_SetVim("cannot delete line");
ok = 0;
break;
}
changed();
}
}
if (ok)
mark_adjust((linenr_t)lo, (linenr_t)(hi-1), (long)MAXLNUM,
(long)-n);
curbuf = savebuf;
update_screen(NOT_VALID);
if (PyErr_Occurred() || VimErrorCheck())
return FAIL;
if (len_change)
*len_change = -n;
return OK;
}
else if (PyList_Check(list))
{
int i;
int n = PyList_Size(list);
int lines = hi - lo;
char **array;
BUF *savebuf;
array = (char **)alloc((unsigned)(n * sizeof(char *)));
if (array == NULL)
{
PyErr_NoMemory();
return FAIL;
}
for (i = 0; i < n; ++i)
{
PyObject *line = PyList_GetItem(list, 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)(lo-1), (linenr_t)hi) == FAIL)
PyErr_SetVim("cannot save undo information");
/* If the size of the range is reducing (ie, n < lines) we
* need to delete some lines. We do this at the start, by
* repeatedly deleting line "lo".
*/
if (!PyErr_Occurred())
{
for (i = 0; i < lines - n; ++i)
{
if (ml_delete((linenr_t)lo, FALSE) == FAIL)
{
PyErr_SetVim("cannot delete line");
break;
}
changed();
}
}
/* For as long as possible, replace the existing lines with the
* new lines. This is a more efficient operation, as it requires
* less memory allocation and freeing.
*/
if (!PyErr_Occurred())
{
for (i = 0; i < lines && i < n; ++i)
{
if (ml_replace((linenr_t)(lo+i), (char_u *)array[i], TRUE)
== FAIL)
{
PyErr_SetVim("cannot replace line");
break;
}
changed();
#ifdef SYNTAX_HL
/* recompute syntax hl. for this line */
syn_changed((linenr_t)(lo+i));
#endif
}
}
/* Now we may need to insert the remaining new lines. If we do, we
* must free the strings as we finish with them (we can't pass the
* responsibility to vim in this case).
*/
if (!PyErr_Occurred())
{
while (i < n)
{
if (ml_append((linenr_t)(lo+i-1), (char_u *)array[i], 0, FALSE) == FAIL)
{
PyErr_SetVim("cannot insert line");
break;
}
changed();
vim_free(array[i]);
++i;
}
}
/* Free any left-over lines, as a result of an error */
while (i < n)
{
vim_free(array[i]);
++i;
}
/* Adjust marks. Invalidate any which lie in the
* changed range, and move any in the remainder of the buffer.
*/
if (!PyErr_Occurred())
mark_adjust((linenr_t)lo, (linenr_t)(hi-1), (long)MAXLNUM, (long)(n - lines));
/* Free the array of lines. All of its contents have now
* been dealt with (either freed, or the responsibility passed
* to vim.
*/
vim_free(array);
curbuf = savebuf;
update_screen(NOT_VALID);
if (PyErr_Occurred() || VimErrorCheck())
return FAIL;
if (len_change)
*len_change = n - lines;
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 *buf, int n, PyObject *lines, int *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 *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
{
mark_adjust((linenr_t)(n+1), (linenr_t)MAXLNUM, 1L, 0L);
changed();
}
vim_free(str);
curbuf = savebuf;
update_screen(NOT_VALID);
if (PyErr_Occurred() || VimErrorCheck())
return FAIL;
if (len_change)
*len_change = 1;
return OK;
}
else if (PyList_Check(lines))
{
int i;
int ok = 0;
int size = PyList_Size(lines);
char **array;
BUF *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
{
ok = 1;
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");
ok = 0;
/* Free the rest of the lines */
while (i < size)
vim_free(array[i++]);
break;
}
changed();
vim_free(array[i]);
}
}
if (ok)
mark_adjust((linenr_t)(n+1), (linenr_t)MAXLNUM, (long)size, 0L);
/* Free the array of lines. All of its contents have now
* been freed.
*/
vim_free(array);
curbuf = savebuf;
update_screen(NOT_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.
*
* On errors, the Python exception data is set, and NULL is returned.
*/
static PyObject *
LineToString(const char *str)
{
PyObject *result;
int len = strlen(str);
char *p;
/* Allocate an Python string object, with uninitialised contents. We
* must do it this way, so that we can modify the string in place
* later. See the Python source, Objects/stringobject.c for details.
*/
result = PyString_FromStringAndSize(NULL, len);
if (result == NULL)
return NULL;
p = PyString_AsString(result);
while (*str)
{
if (*str == '\n')
*p = '\0';
else
*p = *str;
++p;
++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;
int len;
int i;
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.
*/
if (memchr(str, '\n', len))
{
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;
}
/* Check to see whether a Vim error has been reported, or a keyboard
* interrupt has been detected.
*/
static int
VimErrorCheck(void)
{
if (got_int)
{
PyErr_SetNone(PyExc_KeyboardInterrupt);
return 1;
}
else if (did_emsg && !PyErr_Occurred())
{
PyErr_SetNone(VimError);
return 1;
}
return 0;
}
#if PYTHON_API_VERSION < 1007 /* Python 1.4 */
char *
Py_GetProgramName(void)
{
return "vim";
}
#endif /* Python 1.4 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -