This commit is contained in:
Florian Bruhin 2018-02-27 09:33:50 +01:00
parent f18b5aa782
commit 362f923f06
8 changed files with 51 additions and 34 deletions

View File

@ -26,7 +26,7 @@ from PyQt5.QtCore import QUrl
from qutebrowser.commands import cmdexc, cmdutils from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.completion.models import configmodel from qutebrowser.completion.models import configmodel
from qutebrowser.utils import objreg, utils, message, standarddir, urlmatch from qutebrowser.utils import objreg, message, standarddir, urlmatch
from qutebrowser.config import configtypes, configexc, configfiles, configdata from qutebrowser.config import configtypes, configexc, configfiles, configdata
from qutebrowser.misc import editor from qutebrowser.misc import editor
from qutebrowser.keyinput import keyutils from qutebrowser.keyinput import keyutils

View File

@ -20,8 +20,6 @@
"""Base class for vim-like key sequence parser.""" """Base class for vim-like key sequence parser."""
import enum import enum
import re
import unicodedata
from PyQt5.QtCore import pyqtSignal, QObject from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtGui import QKeySequence from PyQt5.QtGui import QKeySequence
@ -148,7 +146,8 @@ class BaseKeyParser(QObject):
sequence = self._sequence.append_event(e) 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:
mapped = config.val.bindings.key_mappings.get(sequence, None) mappings = config.val.bindings.key_mappings
mapped = mappings.get(sequence, None)
if mapped is not None: if mapped is not None:
match, binding = self._match_key(mapped) match, binding = self._match_key(mapped)
@ -241,13 +240,13 @@ class BaseKeyParser(QObject):
assert cmd assert cmd
self.bindings[key] = cmd self.bindings[key] = cmd
def _parse_key_command(self, modename, key, cmd): # FIXME
"""Parse the keys and their command and store them in the object.""" # def _parse_key_command(self, modename, key, cmd):
# FIXME # """Parse the keys and their command and store them in the object."""
# elif self._warn_on_keychains: # elif self._warn_on_keychains:
# log.keyboard.warning("Ignoring keychain '{}' in mode '{}' because " # log.keyboard.warning("Ignoring keychain '{}' in mode '{}' "
# "keychains are not supported there." # "because keychains are not supported there."
# .format(key, modename)) # .format(key, modename))
def execute(self, cmdstr, keytype, count=None): def execute(self, cmdstr, keytype, count=None):
"""Handle a completed keychain. """Handle a completed keychain.

View File

@ -27,7 +27,7 @@ import attr
from PyQt5.QtCore import Qt, QEvent from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtGui import QKeySequence, QKeyEvent from PyQt5.QtGui import QKeySequence, QKeyEvent
from qutebrowser.utils import utils, debug from qutebrowser.utils import utils
def key_to_string(key): def key_to_string(key):
@ -209,8 +209,8 @@ class KeyInfo:
an empty string if only modifiers are pressed. an empty string if only modifiers are pressed.
""" """
if utils.is_mac: if utils.is_mac:
# Qt swaps Ctrl/Meta on macOS, so we switch it back here so the user # Qt swaps Ctrl/Meta on macOS, so we switch it back here so the
# can use it in the config as expected. See: # user can use it in the config as expected. See:
# https://github.com/qutebrowser/qutebrowser/issues/110 # https://github.com/qutebrowser/qutebrowser/issues/110
# http://doc.qt.io/qt-5.4/osx-issues.html#special-keys # http://doc.qt.io/qt-5.4/osx-issues.html#special-keys
modmask2str = collections.OrderedDict([ modmask2str = collections.OrderedDict([
@ -228,9 +228,9 @@ class KeyInfo:
]) ])
modifier_keys = (Qt.Key_Control, Qt.Key_Alt, Qt.Key_Shift, Qt.Key_Meta, modifier_keys = (Qt.Key_Control, Qt.Key_Alt, Qt.Key_Shift, Qt.Key_Meta,
Qt.Key_AltGr, Qt.Key_Super_L, Qt.Key_Super_R, Qt.Key_AltGr, Qt.Key_Super_L, Qt.Key_Super_R,
Qt.Key_Hyper_L, Qt.Key_Hyper_R, Qt.Key_Direction_L, Qt.Key_Hyper_L, Qt.Key_Hyper_R, Qt.Key_Direction_L,
Qt.Key_Direction_R) Qt.Key_Direction_R)
if self.key in modifier_keys: if self.key in modifier_keys:
# Only modifier pressed # Only modifier pressed
return '' return ''
@ -285,6 +285,18 @@ class KeyInfo:
class KeySequence: class KeySequence:
"""A sequence of key presses.
This internally uses chained QKeySequence objects and exposes a nicer
interface over it.
Attributes:
_sequences: A list of QKeySequence
Class attributes:
_MAX_LEN: The maximum amount of keys in a QKeySequence.
"""
_MAX_LEN = 4 _MAX_LEN = 4
def __init__(self, *keys): def __init__(self, *keys):
@ -293,7 +305,7 @@ class KeySequence:
sequence = QKeySequence(*sub) sequence = QKeySequence(*sub)
self._sequences.append(sequence) self._sequences.append(sequence)
if keys: if keys:
assert len(self) > 0 assert self
self._validate() self._validate()
def __str__(self): def __str__(self):
@ -316,15 +328,19 @@ class KeySequence:
return utils.get_repr(self, keys=str(self)) return utils.get_repr(self, keys=str(self))
def __lt__(self, other): def __lt__(self, other):
# pylint: disable=protected-access
return self._sequences < other._sequences return self._sequences < other._sequences
def __gt__(self, other): def __gt__(self, other):
# pylint: disable=protected-access
return self._sequences > other._sequences return self._sequences > other._sequences
def __eq__(self, other): def __eq__(self, other):
# pylint: disable=protected-access
return self._sequences == other._sequences return self._sequences == other._sequences
def __ne__(self, other): def __ne__(self, other):
# pylint: disable=protected-access
return self._sequences != other._sequences return self._sequences != other._sequences
def __hash__(self): def __hash__(self):
@ -334,6 +350,9 @@ class KeySequence:
def __len__(self): def __len__(self):
return sum(len(seq) for seq in self._sequences) return sum(len(seq) for seq in self._sequences)
def __bool__(self):
return bool(self._sequences)
def __getitem__(self, item): def __getitem__(self, item):
if isinstance(item, slice): if isinstance(item, slice):
keys = list(self._iter_keys()) keys = list(self._iter_keys())
@ -351,6 +370,7 @@ class KeySequence:
raise KeyParseError(keystr, "Got unknown key!") raise KeyParseError(keystr, "Got unknown key!")
def matches(self, other): def matches(self, other):
"""Check whether the given KeySequence matches with this one."""
# FIXME test this # FIXME test this
# pylint: disable=protected-access # pylint: disable=protected-access
assert self._sequences assert self._sequences
@ -369,16 +389,16 @@ class KeySequence:
We don't care about a shift modifier with symbols (Shift-: should match We don't care about a shift modifier with symbols (Shift-: should match
a : binding even though we typed it with a shift on an US-keyboard) a : binding even though we typed it with a shift on an US-keyboard)
However, we *do* care about Shift being involved if we got an upper-case However, we *do* care about Shift being involved if we got an
letter, as Shift-A should match a Shift-A binding, but not an "a" upper-case letter, as Shift-A should match a Shift-A binding, but not
binding. an "a" binding.
In addition, Shift also *is* relevant when other modifiers are involved. In addition, Shift also *is* relevant when other modifiers are
involved.
Shift-Ctrl-X should not be equivalent to Ctrl-X. Shift-Ctrl-X should not be equivalent to Ctrl-X.
FIXME: create test cases! FIXME: create test cases!
""" """
# pylint: disable=protected-access
modifiers = ev.modifiers() modifiers = ev.modifiers()
if (modifiers == Qt.ShiftModifier and if (modifiers == Qt.ShiftModifier and
@ -394,6 +414,7 @@ class KeySequence:
@classmethod @classmethod
def parse(cls, keystr): def parse(cls, keystr):
"""Parse a keystring like <Ctrl-x> or xyz and return a KeySequence.""" """Parse a keystring like <Ctrl-x> or xyz and return a KeySequence."""
# pylint: disable=protected-access
# FIXME: test stuff like <a, a> # FIXME: test stuff like <a, a>
new = cls() new = cls()
strings = list(_parse_keystring(keystr)) strings = list(_parse_keystring(keystr))
@ -402,7 +423,8 @@ class KeySequence:
new._sequences.append(sequence) new._sequences.append(sequence)
if keystr: if keystr:
assert len(new) > 0, keystr assert new, keystr
# pylint: disable=protected-access
new._validate(keystr) new._validate(keystr)
return new return new

View File

@ -30,7 +30,6 @@ import re
from PyQt5.QtWidgets import QLabel, QSizePolicy from PyQt5.QtWidgets import QLabel, QSizePolicy
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt
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

View File

@ -26,18 +26,15 @@ import re
import sys import sys
import enum import enum
import json import json
import collections
import datetime import datetime
import traceback import traceback
import functools import functools
import contextlib import contextlib
import socket import socket
import shlex import shlex
import unicodedata
import attr from PyQt5.QtCore import QUrl
from PyQt5.QtCore import Qt, QUrl from PyQt5.QtGui import QColor, QClipboard, QDesktopServices
from PyQt5.QtGui import QKeySequence, QColor, QClipboard, QDesktopServices
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
import pkg_resources import pkg_resources
import yaml import yaml
@ -49,7 +46,7 @@ except ImportError: # pragma: no cover
YAML_C_EXT = False YAML_C_EXT = False
import qutebrowser import qutebrowser
from qutebrowser.utils import qtutils, log, debug from qutebrowser.utils import qtutils, log
fake_clipboard = None fake_clipboard = None

View File

@ -18,7 +18,6 @@
"""Tests for qutebrowser.config.config.""" """Tests for qutebrowser.config.config."""
import copy
import types import types
import unittest.mock import unittest.mock

View File

@ -203,7 +203,8 @@ class TestSpecialKeys:
assert not keyparser.execute.called assert not keyparser.execute.called
def test_no_binding(self, monkeypatch, fake_keyevent_factory, keyparser): def test_no_binding(self, monkeypatch, fake_keyevent_factory, keyparser):
monkeypatch.setattr(keyutils, 'keyevent_to_string', lambda binding: None) monkeypatch.setattr(keyutils, 'keyevent_to_string',
lambda binding: None)
keyparser.handle(fake_keyevent_factory(Qt.Key_A, Qt.NoModifier)) keyparser.handle(fake_keyevent_factory(Qt.Key_A, Qt.NoModifier))
assert not keyparser.execute.called assert not keyparser.execute.called

View File

@ -30,7 +30,7 @@ import re
import shlex import shlex
import attr import attr
from PyQt5.QtCore import Qt, QUrl from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QColor, QClipboard from PyQt5.QtGui import QColor, QClipboard
import pytest import pytest