Merge branch 'rcorre-better_keyhints'

This commit is contained in:
Florian Bruhin 2016-05-25 22:07:23 +02:00
commit a6abc86456
7 changed files with 69 additions and 40 deletions

View File

@ -31,7 +31,7 @@ Added
terminal
- New `:messages` command to show error messages
- New pop-up showing possible keybinding when the first key of a keychain is
pressed. This can be turned off using `:set ui show-keyhints false`.
pressed. This can be turned off using `:set ui keyhint-blacklist *`.
Changed
~~~~~~~

View File

@ -141,8 +141,8 @@ Contributors, sorted by the number of commits in descending order:
* Daniel Schadt
* Antoni Boucher
* Lamar Pavel
* Bruno Oliveira
* Ryan Roden-Corrent
* Bruno Oliveira
* Alexander Cogneau
* Felix Van der Jeugt
* Martin Tournoij

View File

@ -49,7 +49,7 @@
|<<ui-hide-mouse-cursor,hide-mouse-cursor>>|Whether to hide the mouse cursor.
|<<ui-modal-js-dialog,modal-js-dialog>>|Use standard JavaScript modal dialog for alert() and confirm()
|<<ui-hide-wayland-decoration,hide-wayland-decoration>>|Hide the window decoration when using wayland (requires restart)
|<<ui-show-keyhints,show-keyhints>>|Show possible keychains based on the current keystring
|<<ui-keyhint-blacklist,keyhint-blacklist>>|Keychains that shouldn't be shown in the keyhint dialog
|==============
.Quick reference for section ``network''
@ -671,16 +671,13 @@ Valid values:
Default: +pass:[false]+
[[ui-show-keyhints]]
=== show-keyhints
Show possible keychains based on the current keystring
[[ui-keyhint-blacklist]]
=== keyhint-blacklist
Keychains that shouldn't be shown in the keyhint dialog
Valid values:
Globs are supported, so ';*' will blacklist all keychainsstarting with ';'. Use '*' to disable keyhints
* +true+
* +false+
Default: +pass:[true]+
Default: empty
== network
Settings related to the network.

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()