Move word selection code into C, avoiding the need for the python regex module

This commit is contained in:
Kovid Goyal
2017-09-10 10:42:23 +05:30
parent 9bea1001f9
commit 544c402c9f
2 changed files with 31 additions and 20 deletions

View File

@@ -3,12 +3,11 @@
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
import re
import sys
from collections import namedtuple
from ctypes import sizeof
from enum import Enum
from .config import build_ansi_color_table, defaults
from .config import build_ansi_color_table
from .constants import (
GLfloat, GLuint, ScreenGeometry, cell_size, viewport_size
)
@@ -22,7 +21,7 @@ from .fast_data_types import (
from .rgb import to_color
from .shaders import ShaderProgram, load_shaders
from .utils import (
color_as_int, color_from_int, get_logical_dpi, open_url, safe_print,
color_as_int, color_from_int, get_logical_dpi, open_url,
set_primary_selection
)
@@ -143,15 +142,6 @@ class CharGrid:
self.default_cursor = self.current_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0)
self.opts = opts
def escape(chars):
return ''.join(frozenset(chars)).replace('\\', r'\\').replace(']', r'\]').replace('-', r'\-')
try:
self.word_pat = re.compile(r'[\w{}]'.format(escape(self.opts.select_by_word_characters)), re.UNICODE)
except Exception:
safe_print('Invalid characters in select_by_word_characters, ignoring', file=sys.stderr)
self.word_pat = re.compile(r'[\w{}]'.format(escape(defaults.select_by_word_characters)), re.UNICODE)
def destroy(self, cell_program):
if self.vao_id is not None:
cell_program.remove_vertex_array(self.vao_id)
@@ -282,14 +272,8 @@ class CharGrid:
s.start_y = s.end_y = y
s.in_progress = False
if count == 2:
i = x
while i >= 0 and self.word_pat.match(line[i]) is not None:
i -= 1
s.start_x = i if i == x else i + 1
i = x
while i < self.screen.columns and self.word_pat.match(line[i]) is not None:
i += 1
s.end_x = i if i == x else i - 1
s.start_x, xlimit = self.screen.selection_range_for_word(x, y, self.scrolled_by, self.opts.select_by_word_characters)
s.end_x = max(s.start_x, xlimit - 1)
elif count == 3:
s.start_x, xlimit = self.screen.selection_range_for_line(y, self.scrolled_by)
s.end_x = max(s.start_x, xlimit - 1)

View File

@@ -1288,6 +1288,32 @@ selection_range_for_line(Screen *self, PyObject *args) {
return Py_BuildValue("II", (unsigned int)xstart, (unsigned int)xlimit);
}
static inline bool
has_char(int kind, void *data, Py_ssize_t sz, char_type ch) {
for (Py_ssize_t i = 0; i < sz; i++) {
if (PyUnicode_READ(kind, data, i) == ch) return true;
}
return false;
}
static PyObject*
selection_range_for_word(Screen *self, PyObject *args) {
unsigned int x, y, scrolled_by;
PyObject *extra_chars;
if (!PyArg_ParseTuple(args, "IIIU", &x, &y, &scrolled_by, &extra_chars)) return NULL;
if (PyUnicode_READY(extra_chars) != 0) return NULL;
if (y >= self->lines) { PyErr_SetString(PyExc_ValueError, "y larger than lines"); return NULL; }
if (x >= self->columns) { PyErr_SetString(PyExc_ValueError, "x larger than columns"); return NULL; }
Line *line = visual_line_(self, y, scrolled_by);
#define is_ok(x) (is_word_char((line->cells[x].ch) & CHAR_MASK) || has_char(PyUnicode_KIND(extra_chars), PyUnicode_DATA(extra_chars), PyUnicode_GET_LENGTH(extra_chars), (line->cells[x].ch) & CHAR_MASK))
if (!is_ok(x)) Py_BuildValue("II", x, x + 1);
unsigned int start = x, end = x;
while(start > 0 && is_ok(start - 1)) start--;
while(end < self->columns - 1 && is_ok(end + 1)) end++;
return Py_BuildValue("II", start, end + 1);
#undef is_ok
}
static
PyObject* mark_as_dirty(Screen *self) {
@@ -1375,6 +1401,7 @@ static PyMethodDef methods[] = {
MND(set_margins, METH_VARARGS)
MND(apply_selection, METH_VARARGS)
MND(selection_range_for_line, METH_VARARGS)
MND(selection_range_for_word, METH_VARARGS)
MND(text_for_selection, METH_VARARGS)
MND(toggle_alt_screen, METH_NOARGS)
MND(reset_callbacks, METH_NOARGS)