diff --git a/qutebrowser/browser/curcommand.py b/qutebrowser/browser/curcommand.py index 8e5cd5fed..4ae3a9341 100644 --- a/qutebrowser/browser/curcommand.py +++ b/qutebrowser/browser/curcommand.py @@ -200,6 +200,11 @@ class CurCommandDispatcher(QObject): else: widget.hintmanager.start(frame, widget.url(), mode, target) + @cmdutils.register(instance='mainwindow.tabs.cur', hide=True) + def follow_hint(self): + """Follow the currently selected hint.""" + self._tabs.currentWidget().hintmanager.follow_hint() + @pyqtSlot(str) def handle_hint_key(self, keystr): """Handle a new hint keypress.""" diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 5b4e13103..49c64b22e 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -51,6 +51,7 @@ class HintManager(QObject): 'yank'/'yank_primary': Yank to clipboard/primary selection 'cmd'/'cmd_tab'/'cmd_bgtab': Enter link to commandline 'rapid': Rapid mode with background tabs + _to_follow: The link to follow when enter is pressed. Signals: hint_strings_updated: Emitted when the possible hint strings changed. @@ -91,6 +92,7 @@ class HintManager(QObject): self._frame = None self._target = None self._baseurl = None + self._to_follow = None modeman.manager.left.connect(self.on_mode_left) def _hint_strings(self, elems): @@ -318,9 +320,18 @@ class HintManager(QObject): for key in delete: del self._elems[key] - def fire(self, keystr): - """Fire a completed hint.""" + def fire(self, keystr, force=False): + """Fire a completed hint. + + Args: + keystr: The keychain string to follow. + force: When True, follow even when auto-follow is false. + """ # Targets which require a valid link + if not (force or config.get('hints', 'auto-follow')): + self.handle_partial_key(keystr) + self._to_follow = keystr + return require_link = ['yank', 'yank_primary', 'cmd', 'cmd_tab', 'cmd_bgtab'] elem = self._elems[keystr].elem if self._target in require_link: @@ -346,6 +357,11 @@ class HintManager(QObject): if self._target != 'rapid': modeman.leave('hint') + def follow_hint(self): + if not self._to_follow: + message.error("No hint to follow") + self.fire(self._to_follow, force=True) + @pyqtSlot('QSize') def on_contents_size_changed(self, _size): """Reposition hints if contents size changed.""" @@ -365,6 +381,7 @@ class HintManager(QObject): self._frame.contentsSizeChanged.disconnect( self.on_contents_size_changed) self._elems = {} + self._to_follow = None self._target = None self._frame = None message.clear() diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index b96168758..48ccdaf21 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -89,7 +89,9 @@ SECTION_DESC = { "Keybindings for hint mode.\n" "Since normal keypresses are passed through, only special keys are " "supported in this mode.\n" - "An useful command to map here is the hidden command leave_mode."), + "Useful hidden commands to map in this section:\n" + " follow_hint: Follow the currently selected hint.\n" + " leave_mode: Leave the command mode."), 'keybind.passthrough': ( "Keybindings for hint mode.\n" "Since normal keypresses are passed through, only special keys are " @@ -384,6 +386,10 @@ DATA = OrderedDict([ ('chars', SettingValue(types.String(minlen=2), 'asdfghjkl'), "Chars used for hint strings."), + + ('auto-follow', + SettingValue(types.Bool(), 'true'), + "Whether to auto-follow a hint if there's only one left."), )), ('searchengines', sect.ValueList( @@ -466,6 +472,7 @@ DATA = OrderedDict([ ('keybind.hint', sect.ValueList( types.KeyBindingName(), types.KeyBinding(), + ('', 'follow_hint'), ('', 'leave_mode'), ('', 'leave_mode'), )),