From 600919a23ad9a811eeb1d3aaa43f596ad832c543 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Fri, 29 Dec 2017 00:53:37 +0100 Subject: [PATCH] Add a custom KeySequence class --- qutebrowser/keyinput/basekeyparser.py | 21 +++++----- qutebrowser/keyinput/sequence.py | 58 +++++++++++++++++++++++++++ qutebrowser/misc/keyhintwidget.py | 3 +- qutebrowser/utils/utils.py | 5 ++- 4 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 qutebrowser/keyinput/sequence.py diff --git a/qutebrowser/keyinput/basekeyparser.py b/qutebrowser/keyinput/basekeyparser.py index 33a1f808a..14a7ccc6f 100644 --- a/qutebrowser/keyinput/basekeyparser.py +++ b/qutebrowser/keyinput/basekeyparser.py @@ -28,6 +28,7 @@ from PyQt5.QtGui import QKeySequence from qutebrowser.config import config from qutebrowser.utils import usertypes, log, utils +from qutebrowser.keyinput import sequence class BaseKeyParser(QObject): @@ -83,7 +84,7 @@ class BaseKeyParser(QObject): super().__init__(parent) self._win_id = win_id self._modename = None - self._sequence = QKeySequence() + self._sequence = sequence.KeySequence() self._count = '' if supports_count is None: supports_count = supports_chains @@ -142,7 +143,7 @@ class BaseKeyParser(QObject): self._count += txt return None - sequence = QKeySequence(*self._sequence, e.modifiers() | e.key()) + sequence = self._sequence.append_event(e) match, binding = self._match_key(sequence) if match == QKeySequence.NoMatch: mappings = config.val.bindings.key_mappings @@ -151,22 +152,22 @@ class BaseKeyParser(QObject): # FIXME raise Exception txt = mapped - sequence = QKeySequence(*self._sequence, e.modifiers() | e.key()) + sequence = self._sequence.append_event(e) match, binding = self._match_key(sequence) - self._sequence = QKeySequence(*self._sequence, e.modifiers() | e.key()) + self._sequence = self._sequence.append_event(e) if match == QKeySequence.ExactMatch: self._debug_log("Definitive match for '{}'.".format( - self._sequence.toString())) + self._sequence)) count = int(self._count) if self._count else None self.clear_keystring() self.execute(binding, self.Type.chain, count) elif match == QKeySequence.PartialMatch: self._debug_log("No match for '{}' (added {})".format( - self._sequence.toString(), txt)) + self._sequence, txt)) elif match == QKeySequence.NoMatch: self._debug_log("Giving up with '{}', no matches".format( - self._sequence.toString())) + self._sequence)) self.clear_keystring() else: raise utils.Unreachable("Invalid match value {!r}".format(match)) @@ -210,7 +211,7 @@ class BaseKeyParser(QObject): # don't emit twice if the keystring was cleared in self.clear_keystring if self._sequence: - self.keystring_updated.emit(self._count + self._sequence.toString()) + self.keystring_updated.emit(self._count + str(self._sequence)) return match != QKeySequence.NoMatch @@ -262,7 +263,7 @@ class BaseKeyParser(QObject): """Clear the currently entered key sequence.""" if self._sequence: self._debug_log("discarding keystring '{}'.".format( - self._sequence.toString())) - self._sequence = QKeySequence() + self._sequence)) + self._sequence = sequence.KeySequence() self._count = '' self.keystring_updated.emit('') diff --git a/qutebrowser/keyinput/sequence.py b/qutebrowser/keyinput/sequence.py new file mode 100644 index 000000000..7db4f76a7 --- /dev/null +++ b/qutebrowser/keyinput/sequence.py @@ -0,0 +1,58 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2014-2017 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + +"""Our own QKeySequence-like class and related utilities.""" + +from PyQt5.QtGui import QKeySequence + +from qutebrowser.utils import utils + + +class KeySequence: + + def __init__(self, *args): + self._sequence = QKeySequence(*args) + + def __str__(self): + return self._sequence.toString() + + def __repr__(self): + return utils.get_repr(self, keys=str(self)) + + def __lt__(self, other): + return self._sequence < other._sequence + + def __gt__(self, other): + return self._sequence > other._sequence + + def __eq__(self, other): + return self._sequence == other._sequence + + def __ne__(self, other): + return self._sequence != other._sequence + + def __hash__(self): + return hash(self._sequence) + + def matches(self, other): + # pylint: disable=protected-access + return self._sequence.matches(other._sequence) + + def append_event(self, ev): + return self.__class__(*self._sequence, ev.modifiers() | ev.key()) diff --git a/qutebrowser/misc/keyhintwidget.py b/qutebrowser/misc/keyhintwidget.py index d70ddf23d..d4ed43141 100644 --- a/qutebrowser/misc/keyhintwidget.py +++ b/qutebrowser/misc/keyhintwidget.py @@ -35,6 +35,7 @@ from PyQt5.QtGui import QKeySequence from qutebrowser.config import config from qutebrowser.utils import utils, usertypes from qutebrowser.commands import cmdutils +from qutebrowser.keyinput import sequence class KeyHintView(QLabel): @@ -106,7 +107,7 @@ class KeyHintView(QLabel): bindings_dict = config.key_instance.get_bindings_for(modename) bindings = [(k, v) for (k, v) in sorted(bindings_dict.items()) - if k.matches(QKeySequence(prefix)) and # FIXME + if k.matches(sequence.KeySequence(prefix)) and # FIXME not blacklisted(k) and (takes_count(v) or not countstr)] diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py index 29d9c6671..a11c67bc4 100644 --- a/qutebrowser/utils/utils.py +++ b/qutebrowser/utils/utils.py @@ -50,6 +50,7 @@ except ImportError: # pragma: no cover import qutebrowser from qutebrowser.utils import qtutils, log, debug +from qutebrowser.keyinput import sequence fake_clipboard = None @@ -491,7 +492,7 @@ def _parse_single_key(keystr): raise KeyParseError(keystr, "Expecting either a single key or a " " like keybinding.") - seq = QKeySequence(normalize_keystr(keystr), QKeySequence.PortableText) + seq = sequence.KeySequence(normalize_keystr(keystr), QKeySequence.PortableText) if len(seq) != 1: raise KeyParseError(keystr, "Got {} keys instead of 1.".format( len(seq))) @@ -545,7 +546,7 @@ def _parse_keystring(keystr): def parse_keystring(keystr): """Parse a keystring like or xyz and return a KeyInfo list.""" s = ', '.join(_parse_keystring(keystr)) - return QKeySequence(s) + return sequence.KeySequence(s) def normalize_keystr(keystr):