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

View File

@ -355,9 +355,11 @@ def data(readonly=False):
"Hide the window decoration when using wayland " "Hide the window decoration when using wayland "
"(requires restart)"), "(requires restart)"),
('show-keyhints', ('keyhint-blacklist',
SettingValue(typ.Bool(), 'true'), SettingValue(typ.List(none_ok=True), ''),
"Show possible keychains based on the current keystring"), "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 readonly=readonly
)), )),

View File

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

View File

@ -34,7 +34,6 @@ def expected_text(*args):
""" """
text = '<table>' text = '<table>'
for group in args: for group in args:
print("group = {}".format(group))
text += ("<tr>" text += ("<tr>"
"<td>{}</td>" "<td>{}</td>"
"<td style='color: {}'>{}</td>" "<td style='color: {}'>{}</td>"
@ -54,7 +53,7 @@ def keyhint(qtbot, config_stub, key_config_stub):
'keyhint.bg': 'black' 'keyhint.bg': 'black'
}, },
'fonts': {'keyhint': 'Comic Sans'}, 'fonts': {'keyhint': 'Comic Sans'},
'ui': {'show-keyhints': True}, 'ui': {'keyhint-blacklist': ''},
} }
keyhint = KeyHintView(0, None) keyhint = KeyHintView(0, None)
qtbot.add_widget(keyhint) qtbot.add_widget(keyhint)
@ -63,7 +62,7 @@ def keyhint(qtbot, config_stub, key_config_stub):
def test_suggestions(keyhint, 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 # we want the dict to return sorted items() for reliable testing
key_config_stub.set_bindings_for('normal', OrderedDict([ key_config_stub.set_bindings_for('normal', OrderedDict([
('aa', 'cmd-aa'), ('aa', 'cmd-aa'),
@ -95,14 +94,6 @@ def test_special_bindings(keyhint, key_config_stub):
('&lt;', 'yellow', 'b', 'cmd-&lt;b')) ('&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): def test_color_switch(keyhint, config_stub, key_config_stub):
"""Ensure the the keyhint suffix color can be updated at runtime.""" """Ensure the the keyhint suffix color can be updated at runtime."""
config_stub.set('colors', 'keyhint.fg.suffix', '#ABCDEF') config_stub.set('colors', 'keyhint.fg.suffix', '#ABCDEF')
@ -118,4 +109,37 @@ def test_no_matches(keyhint, key_config_stub):
('aa', 'cmd-aa'), ('aa', 'cmd-aa'),
('ab', 'cmd-ab')])) ('ab', 'cmd-ab')]))
keyhint.update_keyhint('normal', 'z') keyhint.update_keyhint('normal', 'z')
assert not keyhint.text()
assert not keyhint.isVisible() 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()