Merge branch 'better_keyhints' of https://github.com/rcorre/qutebrowser into rcorre-better_keyhints

This commit is contained in:
Florian Bruhin 2016-05-25 22:04:51 +02:00
commit c96722f169
4 changed files with 61 additions and 29 deletions

View File

@ -341,6 +341,7 @@ class ConfigManager(QObject):
('colors', 'tab.indicator.system'): 'tabs.indicator.system',
('completion', 'history-length'): 'cmd-history-max-items',
('colors', 'downloads.fg'): 'downloads.fg.start',
('ui', 'show-keyhints'): 'keyhint-blacklist',
}
DELETED_OPTIONS = [
('colors', 'tab.separator'),
@ -360,6 +361,8 @@ class ConfigManager(QObject):
_get_value_transformer({'false': '-1', 'true': '1000'}),
('general', 'log-javascript-console'):
_get_value_transformer({'false': 'none', 'true': 'debug'}),
('ui', 'keyhint-blacklist'):
_get_value_transformer({'false': '*', 'true': ''}),
}
changed = pyqtSignal(str, str)

View File

@ -355,9 +355,11 @@ def data(readonly=False):
"Hide the window decoration when using wayland "
"(requires restart)"),
('show-keyhints',
SettingValue(typ.Bool(), 'true'),
"Show possible keychains based on the current keystring"),
('keyhint-blacklist',
SettingValue(typ.List(none_ok=True), ''),
"Keychains that shouldn't be shown in the keyhint dialog\n\n"
"Globs are supported, so ';*' will blacklist all keychains"
"starting with ';'. Use '*' to disable keyhints"),
readonly=readonly
)),

View File

@ -25,12 +25,13 @@ It is intended to help discoverability of keybindings.
"""
import html
import fnmatch
from PyQt5.QtWidgets import QLabel, QSizePolicy
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt
from qutebrowser.config import config, style
from qutebrowser.utils import objreg, utils
from qutebrowser.utils import objreg, utils, usertypes
class KeyHintView(QLabel):
@ -39,7 +40,6 @@ class KeyHintView(QLabel):
Attributes:
_win_id: Window ID of parent.
_enabled: If False, do not show the window at all
Signals:
reposition_keyhint: Emitted when this widget should be resized.
@ -61,23 +61,16 @@ class KeyHintView(QLabel):
super().__init__(parent)
self.setTextFormat(Qt.RichText)
self._win_id = win_id
self.set_enabled()
cfg = objreg.get('config')
cfg.changed.connect(self.set_enabled)
style.set_register_stylesheet(self)
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum)
self.hide()
self._show_timer = usertypes.Timer(self, 'keyhint_show')
self._show_timer.setInterval(500)
self._show_timer.timeout.connect(self.show)
def __repr__(self):
return utils.get_repr(self, win_id=self._win_id)
@config.change_filter('ui', 'show-keyhints')
def set_enabled(self):
"""Update self._enabled when the config changed."""
self._enabled = config.get('ui', 'show-keyhints')
if not self._enabled:
self.hide()
def showEvent(self, e):
"""Adjust the keyhint size when it's freshly shown."""
self.reposition_keyhint.emit()
@ -90,19 +83,29 @@ class KeyHintView(QLabel):
Args:
prefix: The current partial keystring.
"""
if not prefix or not self._enabled:
if not prefix:
self._show_timer.stop()
self.hide()
return
blacklist = config.get('ui', 'keyhint-blacklist') or []
keyconf = objreg.get('key-config')
def blacklisted(keychain):
return any(fnmatch.fnmatchcase(keychain, glob)
for glob in blacklist)
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 k.startswith(prefix) and not utils.is_special_key(k) and
not blacklisted(k)]
if not bindings:
self._show_timer.stop()
return
self.show()
# delay so a quickly typed keychain doesn't display hints
self._show_timer.start()
suffix_color = html.escape(config.get('colors', 'keyhint.fg.suffix'))
text = ''

View File

@ -34,7 +34,6 @@ def expected_text(*args):
"""
text = '<table>'
for group in args:
print("group = {}".format(group))
text += ("<tr>"
"<td>{}</td>"
"<td style='color: {}'>{}</td>"
@ -54,7 +53,7 @@ def keyhint(qtbot, config_stub, key_config_stub):
'keyhint.bg': 'black'
},
'fonts': {'keyhint': 'Comic Sans'},
'ui': {'show-keyhints': True},
'ui': {'keyhint-blacklist': ''},
}
keyhint = KeyHintView(0, None)
qtbot.add_widget(keyhint)
@ -63,7 +62,7 @@ def keyhint(qtbot, config_stub, key_config_stub):
def test_suggestions(keyhint, key_config_stub):
"""Test cursor position based on the prompt."""
"""Test that keyhints are shown based on a prefix."""
# we want the dict to return sorted items() for reliable testing
key_config_stub.set_bindings_for('normal', OrderedDict([
('aa', 'cmd-aa'),
@ -95,14 +94,6 @@ def test_special_bindings(keyhint, key_config_stub):
('&lt;', 'yellow', 'b', 'cmd-&lt;b'))
def test_disable(keyhint, config_stub):
"""Ensure the widget isn't visible if disabled."""
config_stub.set('ui', 'show-keyhints', False)
keyhint.update_keyhint('normal', 'a')
assert not keyhint.text()
assert not keyhint.isVisible()
def test_color_switch(keyhint, config_stub, key_config_stub):
"""Ensure the the keyhint suffix color can be updated at runtime."""
config_stub.set('colors', 'keyhint.fg.suffix', '#ABCDEF')
@ -118,4 +109,37 @@ def test_no_matches(keyhint, key_config_stub):
('aa', 'cmd-aa'),
('ab', 'cmd-ab')]))
keyhint.update_keyhint('normal', 'z')
assert not keyhint.text()
assert not keyhint.isVisible()
def test_blacklist(keyhint, config_stub, key_config_stub):
"""Test that blacklisted keychaints aren't hinted."""
config_stub.set('ui', 'keyhint-blacklist', ['ab*'])
# we want the dict to return sorted items() for reliable testing
key_config_stub.set_bindings_for('normal', OrderedDict([
('aa', 'cmd-aa'),
('ab', 'cmd-ab'),
('aba', 'cmd-aba'),
('abb', 'cmd-abb'),
('xd', 'cmd-xd'),
('xe', 'cmd-xe')]))
keyhint.update_keyhint('normal', 'a')
assert keyhint.text() == expected_text(('a', 'yellow', 'a', 'cmd-aa'))
def test_blacklist_all(keyhint, config_stub, key_config_stub):
"""Test that setting the blacklist to * disables keyhints."""
config_stub.set('ui', 'keyhint-blacklist', ['*'])
# we want the dict to return sorted items() for reliable testing
key_config_stub.set_bindings_for('normal', OrderedDict([
('aa', 'cmd-aa'),
('ab', 'cmd-ab'),
('aba', 'cmd-aba'),
('abb', 'cmd-abb'),
('xd', 'cmd-xd'),
('xe', 'cmd-xe')]))
keyhint.update_keyhint('normal', 'a')
assert not keyhint.text()