Add a custom KeySequence class

This commit is contained in:
Florian Bruhin 2017-12-29 00:53:37 +01:00
parent a565b77bf0
commit 600919a23a
4 changed files with 74 additions and 13 deletions

View File

@ -28,6 +28,7 @@ from PyQt5.QtGui import QKeySequence
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.utils import usertypes, log, utils from qutebrowser.utils import usertypes, log, utils
from qutebrowser.keyinput import sequence
class BaseKeyParser(QObject): class BaseKeyParser(QObject):
@ -83,7 +84,7 @@ class BaseKeyParser(QObject):
super().__init__(parent) super().__init__(parent)
self._win_id = win_id self._win_id = win_id
self._modename = None self._modename = None
self._sequence = QKeySequence() self._sequence = sequence.KeySequence()
self._count = '' self._count = ''
if supports_count is None: if supports_count is None:
supports_count = supports_chains supports_count = supports_chains
@ -142,7 +143,7 @@ class BaseKeyParser(QObject):
self._count += txt self._count += txt
return None return None
sequence = QKeySequence(*self._sequence, e.modifiers() | e.key()) sequence = self._sequence.append_event(e)
match, binding = self._match_key(sequence) match, binding = self._match_key(sequence)
if match == QKeySequence.NoMatch: if match == QKeySequence.NoMatch:
mappings = config.val.bindings.key_mappings mappings = config.val.bindings.key_mappings
@ -151,22 +152,22 @@ class BaseKeyParser(QObject):
# FIXME # FIXME
raise Exception raise Exception
txt = mapped txt = mapped
sequence = QKeySequence(*self._sequence, e.modifiers() | e.key()) sequence = self._sequence.append_event(e)
match, binding = self._match_key(sequence) 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: if match == QKeySequence.ExactMatch:
self._debug_log("Definitive match for '{}'.".format( self._debug_log("Definitive match for '{}'.".format(
self._sequence.toString())) self._sequence))
count = int(self._count) if self._count else None count = int(self._count) if self._count else None
self.clear_keystring() self.clear_keystring()
self.execute(binding, self.Type.chain, count) self.execute(binding, self.Type.chain, count)
elif match == QKeySequence.PartialMatch: elif match == QKeySequence.PartialMatch:
self._debug_log("No match for '{}' (added {})".format( self._debug_log("No match for '{}' (added {})".format(
self._sequence.toString(), txt)) self._sequence, txt))
elif match == QKeySequence.NoMatch: elif match == QKeySequence.NoMatch:
self._debug_log("Giving up with '{}', no matches".format( self._debug_log("Giving up with '{}', no matches".format(
self._sequence.toString())) self._sequence))
self.clear_keystring() self.clear_keystring()
else: else:
raise utils.Unreachable("Invalid match value {!r}".format(match)) 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 # don't emit twice if the keystring was cleared in self.clear_keystring
if self._sequence: 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 return match != QKeySequence.NoMatch
@ -262,7 +263,7 @@ class BaseKeyParser(QObject):
"""Clear the currently entered key sequence.""" """Clear the currently entered key sequence."""
if self._sequence: if self._sequence:
self._debug_log("discarding keystring '{}'.".format( self._debug_log("discarding keystring '{}'.".format(
self._sequence.toString())) self._sequence))
self._sequence = QKeySequence() self._sequence = sequence.KeySequence()
self._count = '' self._count = ''
self.keystring_updated.emit('') self.keystring_updated.emit('')

View File

@ -0,0 +1,58 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# 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 <http://www.gnu.org/licenses/>.
"""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())

View File

@ -35,6 +35,7 @@ from PyQt5.QtGui import QKeySequence
from qutebrowser.config import config from qutebrowser.config import config
from qutebrowser.utils import utils, usertypes from qutebrowser.utils import utils, usertypes
from qutebrowser.commands import cmdutils from qutebrowser.commands import cmdutils
from qutebrowser.keyinput import sequence
class KeyHintView(QLabel): class KeyHintView(QLabel):
@ -106,7 +107,7 @@ class KeyHintView(QLabel):
bindings_dict = config.key_instance.get_bindings_for(modename) bindings_dict = config.key_instance.get_bindings_for(modename)
bindings = [(k, v) for (k, v) in sorted(bindings_dict.items()) 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 not blacklisted(k) and
(takes_count(v) or not countstr)] (takes_count(v) or not countstr)]

View File

@ -50,6 +50,7 @@ except ImportError: # pragma: no cover
import qutebrowser import qutebrowser
from qutebrowser.utils import qtutils, log, debug from qutebrowser.utils import qtutils, log, debug
from qutebrowser.keyinput import sequence
fake_clipboard = None fake_clipboard = None
@ -491,7 +492,7 @@ def _parse_single_key(keystr):
raise KeyParseError(keystr, "Expecting either a single key or a " raise KeyParseError(keystr, "Expecting either a single key or a "
"<Ctrl-x> like keybinding.") "<Ctrl-x> like keybinding.")
seq = QKeySequence(normalize_keystr(keystr), QKeySequence.PortableText) seq = sequence.KeySequence(normalize_keystr(keystr), QKeySequence.PortableText)
if len(seq) != 1: if len(seq) != 1:
raise KeyParseError(keystr, "Got {} keys instead of 1.".format( raise KeyParseError(keystr, "Got {} keys instead of 1.".format(
len(seq))) len(seq)))
@ -545,7 +546,7 @@ def _parse_keystring(keystr):
def parse_keystring(keystr): def parse_keystring(keystr):
"""Parse a keystring like <Ctrl-x> or xyz and return a KeyInfo list.""" """Parse a keystring like <Ctrl-x> or xyz and return a KeyInfo list."""
s = ', '.join(_parse_keystring(keystr)) s = ', '.join(_parse_keystring(keystr))
return QKeySequence(s) return sequence.KeySequence(s)
def normalize_keystr(keystr): def normalize_keystr(keystr):