From 544c402c9f5d6d1cd275f9eae6638d704e84246b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 10 Sep 2017 10:42:23 +0530 Subject: [PATCH] Move word selection code into C, avoiding the need for the python regex module --- kitty/char_grid.py | 24 ++++-------------------- kitty/screen.c | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/kitty/char_grid.py b/kitty/char_grid.py index d8721bc77..4969537c5 100644 --- a/kitty/char_grid.py +++ b/kitty/char_grid.py @@ -3,12 +3,11 @@ # License: GPL v3 Copyright: 2016, Kovid Goyal 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) diff --git a/kitty/screen.c b/kitty/screen.c index 9b83834a0..695fb9a99 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -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)