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 terminal
- New `:messages` command to show error messages - New `:messages` command to show error messages
- New pop-up showing possible keybinding when the first key of a keychain is - 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 Changed
~~~~~~~ ~~~~~~~

View File

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

View File

@ -49,7 +49,7 @@
|<<ui-hide-mouse-cursor,hide-mouse-cursor>>|Whether to hide the mouse cursor. |<<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-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-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'' .Quick reference for section ``network''
@ -671,16 +671,13 @@ Valid values:
Default: +pass:[false]+ Default: +pass:[false]+
[[ui-show-keyhints]] [[ui-keyhint-blacklist]]
=== show-keyhints === keyhint-blacklist
Show possible keychains based on the current keystring 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+ Default: empty
* +false+
Default: +pass:[true]+
== network == network
Settings related to the network. Settings related to the network.

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