From af48547d8b33a0a9e7894057e5cb01636c984fbe Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 12 Aug 2022 09:40:58 +0530 Subject: [PATCH] Implement SingleKey._replace --- kitty/fast_data_types.pyi | 6 ++++-- kitty/keys.c | 35 ++++++++++++++++++++++++++++++++--- kitty_tests/datatypes.py | 4 +++- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index d67849998..f09e2e462 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -2,7 +2,7 @@ import termios from ctypes import Array, c_ubyte from typing import ( Any, AnyStr, Callable, Dict, List, NewType, Optional, Tuple, TypedDict, - Union + Union, Iterator ) from kitty.boss import Boss @@ -1470,7 +1470,7 @@ class AES256GCMDecrypt: class SingleKey: - def __init__(self, mods: int = 0, is_native: bool = False, key: int = -1): ... + def __init__(self, mods: int = 0, is_native: object = False, key: int = -1): ... def __hash__(self) -> int: ... def __len__(self) -> int: ... def __getitem__(self, x: int) -> int: ... @@ -1480,3 +1480,5 @@ class SingleKey: def is_native(self) -> bool: ... @property def key(self) -> int: ... + def __iter__(self) -> Iterator[int]: ... + def _replace(self, mods: int = 0, is_native: object = False, key: int = -1) -> 'SingleKey': ... diff --git a/kitty/keys.c b/kitty/keys.c index 19deb223d..90bd2a1ee 100644 --- a/kitty/keys.c +++ b/kitty/keys.c @@ -304,11 +304,12 @@ typedef struct { Key key; } SingleKey; + static PyObject * SingleKey_new(PyTypeObject *type, PyObject *args, PyObject *kw) { - static char *kwds[] = {"mods", "is_native", "key", NULL}; long key = -1; unsigned short mods = 0; int is_native = 0; - if (!PyArg_ParseTupleAndKeywords(args, kw, "|Hpl", kwds, &mods, &is_native, &key)) return NULL; + static char *SingleKey_kwds[] = {"mods", "is_native", "key", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kw, "|Hpl", SingleKey_kwds, &mods, &is_native, &key)) return NULL; SingleKey *self = (SingleKey *)type->tp_alloc(type, 0); if (self) { if (key > 0 && key <= 0x10FFFF) { @@ -408,6 +409,34 @@ static PySequenceMethods SingleKey_sequence_methods = { .sq_item = SingleKey_item, }; +static bool +dict_has_key(PyObject *dict, const char *key) { + PyObject *k = PyUnicode_FromString(key); + if (!k) { PyErr_Print(); return false; } + int ret = PyDict_Contains(dict, k); + Py_DECREF(k); + return ret != 0; +} + +static PyObject* +SingleKey_replace(SingleKey *self, PyObject *args, PyObject *kw) { + SingleKey *r = (SingleKey*)SingleKey_new(&SingleKey_Type, args, kw); + if (!r) return NULL; + SingleKey *ans = (SingleKey*)SingleKey_Type.tp_alloc(&SingleKey_Type, 0); + if (!ans) { Py_DECREF(r); return NULL; } + ans->key.val = self->key.val; + if (dict_has_key(kw, "mods")) ans->key.mods = r->key.mods; + if (dict_has_key(kw, "is_native")) ans->key.is_native = r->key.is_native; + if (dict_has_key(kw, "key")) ans->key.key = r->key.key; + Py_DECREF(r); + return (PyObject*)ans; +} + +static PyMethodDef SingleKey_methods[] = { + {"_replace", (PyCFunction)(void (*) (void))SingleKey_replace, METH_VARARGS | METH_KEYWORDS, ""}, + {NULL} /* Sentinel */ +}; + static PyTypeObject SingleKey_Type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -421,7 +450,7 @@ static PyTypeObject SingleKey_Type = { .tp_richcompare = SingleKey_richcompare, .tp_as_sequence = &SingleKey_sequence_methods, .tp_repr = SingleKey_repr, - /* .tp_methods = methods, */ + .tp_methods = SingleKey_methods, .tp_getset = SingleKey_getsetters, }; // }}} diff --git a/kitty_tests/datatypes.py b/kitty_tests/datatypes.py index 69129c652..202e840bc 100644 --- a/kitty_tests/datatypes.py +++ b/kitty_tests/datatypes.py @@ -538,9 +538,11 @@ class TestDataTypes(BaseTest): for m in (GLFW_MOD_NUM_LOCK, GLFW_MOD_SHIFT): s = SingleKey(mods=m) self.ae(s.mods, m) - self.ae(tuple(SingleKey()), (0, False, -1)) + self.ae(tuple(iter(SingleKey())), (0, False, -1)) self.ae(tuple(SingleKey(key=0x10ffff, mods=GLFW_MOD_SHIFT, is_native=True)), (GLFW_MOD_SHIFT, True, 0x10ffff)) self.ae(repr(SingleKey()), 'SingleKey()') self.ae(repr(SingleKey(key=23, mods=2, is_native=True)), 'SingleKey(mods=2, is_native=True, key=23)') self.ae(repr(SingleKey(key=23, mods=2)), 'SingleKey(mods=2, key=23)') self.ae(repr(SingleKey(key=23)), 'SingleKey(key=23)') + self.ae(repr(SingleKey(key=23)._replace(mods=2)), 'SingleKey(mods=2, key=23)') + self.ae(repr(SingleKey(key=23)._replace(key=-1, mods=2)), 'SingleKey(mods=2)')