Implement numeric hints

This commit is contained in:
Florian Bruhin 2014-05-02 17:53:16 +02:00
parent e5c7d467ae
commit efc613811f
7 changed files with 97 additions and 3 deletions

2
TODO
View File

@ -50,8 +50,8 @@ hints
bindings for prev/next hint bindings for prev/next hint
more intelligent clicking (end of textfields) more intelligent clicking (end of textfields)
filtering when typing part of name
filter close hints when it's the same link filter close hints when it's the same link
ignore keypresses shortly after link following
Qt Bugs Qt Bugs
======== ========

View File

@ -284,6 +284,7 @@ class QuteBrowser(QApplication):
# hints # hints
kp['hint'].fire_hint.connect(tabs.cur.fire_hint) kp['hint'].fire_hint.connect(tabs.cur.fire_hint)
kp['hint'].filter_hints.connect(tabs.cur.filter_hints)
kp['hint'].keystring_updated.connect(tabs.cur.handle_hint_key) kp['hint'].keystring_updated.connect(tabs.cur.handle_hint_key)
tabs.hint_strings_updated.connect(kp['hint'].on_hint_strings_updated) tabs.hint_strings_updated.connect(kp['hint'].on_hint_strings_updated)

View File

@ -245,6 +245,11 @@ class CurCommandDispatcher(QObject):
"""Fire a completed hint.""" """Fire a completed hint."""
self._tabs.currentWidget().hintmanager.fire(keystr) self._tabs.currentWidget().hintmanager.fire(keystr)
@pyqtSlot(str)
def filter_hints(self, filterstr):
"""Filter displayed hints."""
self._tabs.currentWidget().hintmanager.filter_hints(filterstr)
@cmdutils.register(instance='mainwindow.tabs.cur') @cmdutils.register(instance='mainwindow.tabs.cur')
def prevpage(self): def prevpage(self):
"""Open a "previous" link.""" """Open a "previous" link."""

View File

@ -107,7 +107,10 @@ class HintManager(QObject):
Return: Return:
A list of hint strings, in the same order as the elements. A list of hint strings, in the same order as the elements.
""" """
chars = config.get("hints", "chars") if config.get('hints', 'mode') == 'number':
chars = '0123456789'
else:
chars = config.get('hints', 'chars')
# Determine how many digits the link hints will require in the worst # Determine how many digits the link hints will require in the worst
# case. Usually we do not need all of these digits for every link # case. Usually we do not need all of these digits for every link
# single hint, so we can show shorter hints for a few of the links. # single hint, so we can show shorter hints for a few of the links.
@ -389,6 +392,22 @@ class HintManager(QObject):
for key in delete: for key in delete:
del self._elems[key] del self._elems[key]
def filter_hints(self, filterstr):
"""Filter displayed hints according to a text."""
delete = []
for (string, elems) in self._elems.items():
if not elems.elem.toPlainText().lower().startswith(filterstr):
elems.label.removeFromDocument()
delete.append(string)
for key in delete:
del self._elems[key]
if not self._elems:
# Whoops, filtered all hints
modeman.leave('hint')
elif len(self._elems) == 1 and config.get('hints', 'auto-follow'):
# unpacking gets us the first (and only) key in the dict.
self.fire(*self._elems)
def fire(self, keystr, force=False): def fire(self, keystr, force=False):
"""Fire a completed hint. """Fire a completed hint.

View File

@ -200,6 +200,16 @@ class ShellCommand(String):
return shlex.split(value) return shlex.split(value)
class HintMode(BaseType):
"""Base class for the hints -> mode setting."""
typestr = 'hint-mode'
valid_values = ValidValues(('number', "Use numeric hints."),
('letter', "Use the chars in hints -> chars."))
class Bool(BaseType): class Bool(BaseType):
"""Base class for a boolean setting. """Base class for a boolean setting.

View File

@ -410,6 +410,10 @@ DATA = OrderedDict([
SettingValue(types.Float(minval=0.0, maxval=1.0), '0.7'), SettingValue(types.Float(minval=0.0, maxval=1.0), '0.7'),
"Opacity for hints."), "Opacity for hints."),
('mode',
SettingValue(types.HintMode(), 'letter'),
"Mode to use for hints, 'number' or 'letter'."),
('chars', ('chars',
SettingValue(types.String(minlen=2), 'asdfghjkl'), SettingValue(types.String(minlen=2), 'asdfghjkl'),
"Chars used for hint strings."), "Chars used for hint strings."),

View File

@ -21,9 +21,12 @@ Module attributes:
STARTCHARS: Possible chars for starting a commandline input. STARTCHARS: Possible chars for starting a commandline input.
""" """
from PyQt5.QtCore import pyqtSignal import logging
from PyQt5.QtCore import pyqtSignal, Qt
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
import qutebrowser.config.config as config
from qutebrowser.keyinput.keyparser import CommandKeyParser from qutebrowser.keyinput.keyparser import CommandKeyParser
@ -61,14 +64,65 @@ class HintKeyParser(CommandKeyParser):
Signals: Signals:
fire_hint: When a hint keybinding was completed. fire_hint: When a hint keybinding was completed.
Arg: the keystring/hint string pressed. Arg: the keystring/hint string pressed.
filter_hints: When the filter text changed.
Arg: the text to filter hints with.
Attributes:
_filtertext: The text to filter with.
""" """
fire_hint = pyqtSignal(str) fire_hint = pyqtSignal(str)
filter_hints = pyqtSignal(str)
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent, supports_count=False, supports_chains=True) super().__init__(parent, supports_count=False, supports_chains=True)
self._filtertext = ''
self.read_config('keybind.hint') self.read_config('keybind.hint')
def _handle_special_key(self, e):
"""Override _handle_special_key to handle string filtering.
Return True if the keypress has been handled, and False if not.
Args:
e: the KeyPressEvent from Qt.
Return:
True if event has been handled, False otherwise.
Emit:
filter_hints: Emitted when filter string has changed.
"""
logging.debug("Got special key {} text {}".format(e.key(), e.text()))
if config.get('hints', 'mode') != 'number':
return super()._handle_special_key(e)
elif e.key() == Qt.Key_Backspace:
if self._filtertext:
self._filtertext = self._filtertext[:-1]
self.filter_hints.emit(self._filtertext)
return True
elif not e.text():
return super()._handle_special_key(e)
else:
self._filtertext += e.text()
self.filter_hints.emit(self._filtertext)
return True
def handle(self, e):
"""Handle a new keypress and call the respective handlers.
Args:
e: the KeyPressEvent from Qt
Emit:
keystring_updated: If a new keystring should be set.
"""
handled = self._handle_single_key(e)
if handled:
self.keystring_updated.emit(self._keystring)
return handled
return self._handle_special_key(e)
def execute(self, cmdstr, keytype, count=None): def execute(self, cmdstr, keytype, count=None):
"""Handle a completed keychain. """Handle a completed keychain.
@ -88,3 +142,4 @@ class HintKeyParser(CommandKeyParser):
strings: A list of hint strings. strings: A list of hint strings.
""" """
self.bindings = {s: s for s in strings} self.bindings = {s: s for s in strings}
self._filtertext = ''