From c35ff2e8431dfdc02323ddcb09c7762fc127ccdc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 25 Jun 2026 10:35:11 +0000 Subject: [PATCH] Replace ctypes in marks.py with C-level set_uint_at_address function --- kitty/data-types.c | 12 +++++++++++ kitty/marks.py | 33 +++++++++-------------------- kitty_tests/datatypes.py | 45 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 23 deletions(-) diff --git a/kitty/data-types.c b/kitty/data-types.c index a31fe667b..06fd2a362 100644 --- a/kitty/data-types.c +++ b/kitty/data-types.c @@ -683,6 +683,17 @@ py_get_config_dir(PyObject *self UNUSED, PyObject *args UNUSED) { #include "launcher/cli-parser.h" +static PyObject* +set_uint_at_address(PyObject *self UNUSED, PyObject *args) { + PyObject *address_obj; + unsigned int value; + if (!PyArg_ParseTuple(args, "OI", &address_obj, &value)) return NULL; + void *ptr = PyLong_AsVoidPtr(address_obj); + if (ptr == NULL && PyErr_Occurred()) return NULL; + *((unsigned int*)ptr) = value; + Py_RETURN_NONE; +} + static PyMethodDef module_methods[] = { METHODB(replace_c0_codes_except_nl_space_tab, METH_O), METHODB(read_file, METH_O), @@ -716,6 +727,7 @@ static PyMethodDef module_methods[] = { {"timed_debug_print", (PyCFunction)py_timed_debug_print, METH_VARARGS, ""}, {"find_in_memoryview", (PyCFunction)find_in_memoryview, METH_VARARGS, ""}, {"run_at_exit_cleanup_functions", (PyCFunction)py_run_atexit_cleanup_functions, METH_NOARGS, ""}, + {"set_uint_at_address", (PyCFunction)set_uint_at_address, METH_VARARGS, ""}, #ifdef __APPLE__ METHODB(user_cache_dir, METH_NOARGS), METHODB(process_group_map, METH_NOARGS), diff --git a/kitty/marks.py b/kitty/marks.py index a35461213..90cf23f3f 100644 --- a/kitty/marks.py +++ b/kitty/marks.py @@ -3,26 +3,16 @@ import re from collections.abc import Callable, Generator, Iterable, Sequence -from ctypes import POINTER, c_uint, c_void_p, cast from re import Pattern from typing import Union +from .fast_data_types import set_uint_at_address from .utils import resolve_custom_file -pointer_to_uint = POINTER(c_uint) - MarkerFunc = Callable[[str, int, int, int], Generator[None, None, None]] -def get_output_variables(left_address: int, right_address: int, color_address: int) -> tuple[c_uint, c_uint, c_uint]: - return ( - cast(c_void_p(left_address), pointer_to_uint).contents, - cast(c_void_p(right_address), pointer_to_uint).contents, - cast(c_void_p(color_address), pointer_to_uint).contents, - ) - - def marker_from_regex(expression: Union[str, 'Pattern[str]'], color: int, flags: int = re.UNICODE) -> MarkerFunc: color = max(1, min(color, 3)) if isinstance(expression, str): @@ -31,11 +21,10 @@ def marker_from_regex(expression: Union[str, 'Pattern[str]'], color: int, flags: pat = expression def marker(text: str, left_address: int, right_address: int, color_address: int) -> Generator[None, None, None]: - left, right, colorv = get_output_variables(left_address, right_address, color_address) - colorv.value = color + set_uint_at_address(color_address, color) for match in pat.finditer(text): - left.value = match.start() - right.value = match.end() - 1 + set_uint_at_address(left_address, match.start()) + set_uint_at_address(right_address, match.end() - 1) yield return marker @@ -52,12 +41,11 @@ def marker_from_multiple_regex(regexes: Iterable[tuple[int, str]], flags: int = pat = re.compile(expr, flags=flags) def marker(text: str, left_address: int, right_address: int, color_address: int) -> Generator[None, None, None]: - left, right, color = get_output_variables(left_address, right_address, color_address) for match in pat.finditer(text): - left.value = match.start() - right.value = match.end() - 1 + set_uint_at_address(left_address, match.start()) + set_uint_at_address(right_address, match.end() - 1) grp = match.lastgroup - color.value = color_map[grp] if grp is not None else 0 + set_uint_at_address(color_address, color_map[grp] if grp is not None else 0) yield return marker @@ -69,11 +57,10 @@ def marker_from_text(expression: str, color: int) -> MarkerFunc: def marker_from_function(func: Callable[[str], Iterable[tuple[int, int, int]]]) -> MarkerFunc: def marker(text: str, left_address: int, right_address: int, color_address: int) -> Generator[None, None, None]: - left, right, colorv = get_output_variables(left_address, right_address, color_address) for (ll, r, c) in func(text): - left.value = ll - right.value = r - colorv.value = c + set_uint_at_address(left_address, ll) + set_uint_at_address(right_address, r) + set_uint_at_address(color_address, c) yield return marker diff --git a/kitty_tests/datatypes.py b/kitty_tests/datatypes.py index 716df74f0..959063fe0 100644 --- a/kitty_tests/datatypes.py +++ b/kitty_tests/datatypes.py @@ -940,3 +940,48 @@ class TestDataTypes(BaseTest): s.reset() s.draw('\0') self.ae(str(s.line(0)), '') + + def test_set_uint_at_address(self): + from ctypes import addressof, c_uint + + from kitty.fast_data_types import set_uint_at_address + from kitty.marks import marker_from_function, marker_from_multiple_regex, marker_from_regex, marker_from_text + + # Test set_uint_at_address directly + val = c_uint(0) + addr = addressof(val) + set_uint_at_address(addr, 42) + self.ae(val.value, 42) + set_uint_at_address(addr, 0) + self.ae(val.value, 0) + set_uint_at_address(addr, 0xFFFF) + self.ae(val.value, 0xFFFF) + + # Test marker functions using set_uint_at_address via Screen + s = self.create_screen() + s.draw('abaa') + s.set_marker(marker_from_regex('a', 3)) + self.ae(s.marked_cells(), [(0, 0, 3), (2, 0, 3), (3, 0, 3)]) + s.set_marker() + self.ae(s.marked_cells(), []) + + s = self.create_screen() + s.draw('aXbX') + s.set_marker(marker_from_multiple_regex([(1, 'a'), (2, 'X')])) + self.ae(s.marked_cells(), [(0, 0, 1), (1, 0, 2), (3, 0, 2)]) + + s = self.create_screen(cols=20) + s.draw('hello world') + s.set_marker(marker_from_text('world', 2)) + self.ae(s.marked_cells(), [(6, 0, 2), (7, 0, 2), (8, 0, 2), (9, 0, 2), (10, 0, 2)]) + + def mark_func(text): + for i, ch in enumerate(text): + if ch == 'x': + yield i, i, 1 + + s = self.create_screen() + s.draw('axbxc') + s.set_marker(marker_from_function(mark_func)) + self.ae(s.marked_cells(), [(1, 0, 1), (3, 0, 1)]) +