Merge branch 'rcorre-keyhint_fix'
This commit is contained in:
commit
d67bfc8c45
@ -24,7 +24,7 @@ from PyQt5.QtCore import Qt, QTimer, pyqtSlot
|
|||||||
|
|
||||||
from qutebrowser.browser import webview
|
from qutebrowser.browser import webview
|
||||||
from qutebrowser.config import config, configdata
|
from qutebrowser.config import config, configdata
|
||||||
from qutebrowser.utils import objreg, log, qtutils
|
from qutebrowser.utils import objreg, log, qtutils, utils
|
||||||
from qutebrowser.commands import cmdutils
|
from qutebrowser.commands import cmdutils
|
||||||
from qutebrowser.completion.models import base
|
from qutebrowser.completion.models import base
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ class CommandCompletionModel(base.BaseCompletionModel):
|
|||||||
cmd_to_keys = defaultdict(list)
|
cmd_to_keys = defaultdict(list)
|
||||||
for key, cmd in keyconf.get_bindings_for('normal').items():
|
for key, cmd in keyconf.get_bindings_for('normal').items():
|
||||||
# put special bindings last
|
# put special bindings last
|
||||||
if key.startswith('<') and key.endswith('>'):
|
if utils.is_special_key(key):
|
||||||
cmd_to_keys[cmd].append(key)
|
cmd_to_keys[cmd].append(key)
|
||||||
else:
|
else:
|
||||||
cmd_to_keys[cmd].insert(0, key)
|
cmd_to_keys[cmd].insert(0, key)
|
||||||
|
@ -335,7 +335,7 @@ class BaseKeyParser(QObject):
|
|||||||
|
|
||||||
def _parse_key_command(self, modename, key, cmd):
|
def _parse_key_command(self, modename, key, cmd):
|
||||||
"""Parse the keys and their command and store them in the object."""
|
"""Parse the keys and their command and store them in the object."""
|
||||||
if key.startswith('<') and key.endswith('>'):
|
if utils.is_special_key(key):
|
||||||
keystr = utils.normalize_keystr(key[1:-1])
|
keystr = utils.normalize_keystr(key[1:-1])
|
||||||
self.special_bindings[keystr] = cmd
|
self.special_bindings[keystr] = cmd
|
||||||
elif self._supports_chains:
|
elif self._supports_chains:
|
||||||
|
@ -94,28 +94,31 @@ class KeyHintView(QLabel):
|
|||||||
self.hide()
|
self.hide()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
keyconf = objreg.get('key-config')
|
||||||
|
bindings = [(k, v) for (k, v)
|
||||||
|
in keyconf.get_bindings_for(modename).items()
|
||||||
|
if k.startswith(prefix) and not utils.is_special_key(k)]
|
||||||
|
|
||||||
|
if not bindings:
|
||||||
|
return
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
suffix_color = html.escape(config.get('colors', 'keyhint.fg.suffix'))
|
suffix_color = html.escape(config.get('colors', 'keyhint.fg.suffix'))
|
||||||
|
|
||||||
text = ''
|
text = ''
|
||||||
keyconf = objreg.get('key-config')
|
for key, cmd in bindings:
|
||||||
# this is only fired in normal mode
|
text += (
|
||||||
for key, cmd in keyconf.get_bindings_for(modename).items():
|
"<tr>"
|
||||||
# for now, special keys can't be part of keychains, so ignore them
|
"<td>{}</td>"
|
||||||
is_special_binding = key.startswith('<') and key.endswith('>')
|
"<td style='color: {}'>{}</td>"
|
||||||
if key.startswith(prefix) and not is_special_binding:
|
"<td style='padding-left: 2ex'>{}</td>"
|
||||||
text += (
|
"</tr>"
|
||||||
"<tr>"
|
).format(
|
||||||
"<td>{}</td>"
|
html.escape(prefix),
|
||||||
"<td style='color: {}'>{}</td>"
|
suffix_color,
|
||||||
"<td style='padding-left: 2ex'>{}</td>"
|
html.escape(key[len(prefix):]),
|
||||||
"</tr>"
|
html.escape(cmd)
|
||||||
).format(
|
)
|
||||||
html.escape(prefix),
|
|
||||||
suffix_color,
|
|
||||||
html.escape(key[len(prefix):]),
|
|
||||||
html.escape(cmd)
|
|
||||||
)
|
|
||||||
text = '<table>{}</table>'.format(text)
|
text = '<table>{}</table>'.format(text)
|
||||||
|
|
||||||
self.setText(text)
|
self.setText(text)
|
||||||
|
@ -440,9 +440,14 @@ class KeyParseError(Exception):
|
|||||||
super().__init__("Could not parse {!r}: {}".format(keystr, error))
|
super().__init__("Could not parse {!r}: {}".format(keystr, error))
|
||||||
|
|
||||||
|
|
||||||
|
def is_special_key(keystr):
|
||||||
|
"""True if keystr is a 'special' keystring (e.g. <ctrl-x> or <space>)."""
|
||||||
|
return keystr.startswith('<') and keystr.endswith('>')
|
||||||
|
|
||||||
|
|
||||||
def _parse_single_key(keystr):
|
def _parse_single_key(keystr):
|
||||||
"""Convert a single key string to a (Qt.Key, Qt.Modifiers, text) tuple."""
|
"""Convert a single key string to a (Qt.Key, Qt.Modifiers, text) tuple."""
|
||||||
if keystr.startswith('<') and keystr.endswith('>'):
|
if is_special_key(keystr):
|
||||||
# Special key
|
# Special key
|
||||||
keystr = keystr[1:-1]
|
keystr = keystr[1:-1]
|
||||||
elif len(keystr) == 1:
|
elif len(keystr) == 1:
|
||||||
@ -489,7 +494,7 @@ def _parse_single_key(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."""
|
||||||
if keystr.startswith('<') and keystr.endswith('>'):
|
if is_special_key(keystr):
|
||||||
return [_parse_single_key(keystr)]
|
return [_parse_single_key(keystr)]
|
||||||
else:
|
else:
|
||||||
return [_parse_single_key(char) for char in keystr]
|
return [_parse_single_key(char) for char in keystr]
|
||||||
|
@ -110,3 +110,12 @@ def test_color_switch(keyhint, config_stub, key_config_stub):
|
|||||||
('aa', 'cmd-aa')]))
|
('aa', 'cmd-aa')]))
|
||||||
keyhint.update_keyhint('normal', 'a')
|
keyhint.update_keyhint('normal', 'a')
|
||||||
assert keyhint.text() == expected_text(('a', '#ABCDEF', 'a', 'cmd-aa'))
|
assert keyhint.text() == expected_text(('a', '#ABCDEF', 'a', 'cmd-aa'))
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_matches(keyhint, key_config_stub):
|
||||||
|
"""Ensure the widget isn't visible if there are no keystrings to show."""
|
||||||
|
key_config_stub.set_bindings_for('normal', OrderedDict([
|
||||||
|
('aa', 'cmd-aa'),
|
||||||
|
('ab', 'cmd-ab')]))
|
||||||
|
keyhint.update_keyhint('normal', 'z')
|
||||||
|
assert not keyhint.isVisible()
|
||||||
|
@ -984,3 +984,19 @@ class TestGetSetClipboard:
|
|||||||
def test_supports_selection(self, clipboard_mock, selection):
|
def test_supports_selection(self, clipboard_mock, selection):
|
||||||
clipboard_mock.supportsSelection.return_value = selection
|
clipboard_mock.supportsSelection.return_value = selection
|
||||||
assert utils.supports_selection() == selection
|
assert utils.supports_selection() == selection
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('keystr, expected', [
|
||||||
|
('<Control-x>', True),
|
||||||
|
('<Meta-x>', True),
|
||||||
|
('<Ctrl-Alt-y>', True),
|
||||||
|
('x', False),
|
||||||
|
('X', False),
|
||||||
|
('<Escape>', True),
|
||||||
|
('foobar', False),
|
||||||
|
('foo>', False),
|
||||||
|
('<foo', False),
|
||||||
|
('<<', False),
|
||||||
|
])
|
||||||
|
def test_is_special_key(keystr, expected):
|
||||||
|
assert utils.is_special_key(keystr) == expected
|
||||||
|
Loading…
Reference in New Issue
Block a user