From bf4e968c6754bc4b185f6f469487b9ff92734a2a Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 18 Jun 2015 07:58:15 +0200 Subject: [PATCH] Add new completion -> auto-open option. Closes #557. --- qutebrowser/completion/completer.py | 82 +++++++++++++++++++++- qutebrowser/completion/completionwidget.py | 21 ++---- qutebrowser/config/configdata.py | 4 ++ 3 files changed, 89 insertions(+), 18 deletions(-) diff --git a/qutebrowser/completion/completer.py b/qutebrowser/completion/completer.py index ebcaed67d..945f3636f 100644 --- a/qutebrowser/completion/completer.py +++ b/qutebrowser/completion/completer.py @@ -19,7 +19,7 @@ """Completer attached to a CompletionView.""" -from PyQt5.QtCore import pyqtSlot, QObject, QTimer +from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QTimer from qutebrowser.config import config from qutebrowser.commands import cmdutils, runners @@ -40,14 +40,22 @@ class Completer(QObject): _last_cursor_pos: The old cursor position so we avoid double completion updates. _last_text: The old command text so we avoid double completion updates. + _signals_connected: Whether the signals are connected to update the + completion when the command widget requests that. + + Signals: + next_prev_item: Emitted to select the next/previous item in the + completion. + arg0: True for the previous item, False for the next. """ + next_prev_item = pyqtSignal(bool) + def __init__(self, cmd, win_id, parent=None): super().__init__(parent) self._win_id = win_id self._cmd = cmd - self._cmd.update_completion.connect(self.schedule_completion_update) - self._cmd.textEdited.connect(self.on_text_edited) + self._signals_connected = False self._ignore_change = False self._empty_item_idx = None self._timer = QTimer() @@ -58,9 +66,63 @@ class Completer(QObject): self._last_cursor_pos = None self._last_text = None + objreg.get('config').changed.connect(self.on_auto_open_changed) + self.handle_signal_connections() + self._cmd.clear_completion_selection.connect( + self.handle_signal_connections) + def __repr__(self): return utils.get_repr(self) + @config.change_filter('completion', 'auto-open') + def on_auto_open_changed(self): + self.handle_signal_connections() + + @pyqtSlot() + def handle_signal_connections(self): + self._connect_signals(config.get('completion', 'auto-open')) + + def _connect_signals(self, connect=True): + """Connect or disconnect the completion signals. + + Args: + connect: Whether to connect (True) or disconnect (False) the + signals. + + Return: + True if the signals were connected (connect=True and aren't + connected yet) - otherwise False. + """ + connections = [ + (self._cmd.update_completion, self.schedule_completion_update), + (self._cmd.textChanged, self.on_text_edited), + ] + + if connect and not self._signals_connected: + for sender, receiver in connections: + sender.connect(receiver) + self._signals_connected = True + return True + elif not connect: + for sender, receiver in connections: + try: + sender.disconnect(receiver) + except TypeError: + # Don't fail if not connected + pass + self._signals_connected = False + return False + + def _open_completion_if_needed(self): + """If auto-open is false, temporarily connect signals. + + Also opens the completion. + """ + if not config.get('completion', 'auto-open'): + connected = self._connect_signals(True) + if connected: + self.update_completion() + def _model(self): """Convienience method to get the current completion model.""" completion = objreg.get('completion', scope='window', @@ -405,3 +467,17 @@ class Completer(QObject): # We also want to update the cursor part and emit update_completion # here, but that's already done for us by cursorPositionChanged # anyways, so we don't need to do it twice. + + @cmdutils.register(instance='completer', hide=True, + modes=[usertypes.KeyMode.command], scope='window') + def completion_item_prev(self): + """Select the previous completion item.""" + self._open_completion_if_needed() + self.next_prev_item.emit(True) + + @cmdutils.register(instance='completer', hide=True, + modes=[usertypes.KeyMode.command], scope='window') + def completion_item_next(self): + """Select the next completion item.""" + self._open_completion_if_needed() + self.next_prev_item.emit(False) diff --git a/qutebrowser/completion/completionwidget.py b/qutebrowser/completion/completionwidget.py index 58532058d..a3bea931a 100644 --- a/qutebrowser/completion/completionwidget.py +++ b/qutebrowser/completion/completionwidget.py @@ -26,10 +26,9 @@ subclasses to provide completions. from PyQt5.QtWidgets import QStyle, QTreeView, QSizePolicy from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel -from qutebrowser.commands import cmdutils from qutebrowser.config import config, style from qutebrowser.completion import completiondelegate, completer -from qutebrowser.utils import usertypes, qtutils, objreg, utils +from qutebrowser.utils import qtutils, objreg, utils class CompletionView(QTreeView): @@ -96,6 +95,7 @@ class CompletionView(QTreeView): objreg.register('completion', self, scope='window', window=win_id) cmd = objreg.get('status-command', scope='window', window=win_id) completer_obj = completer.Completer(cmd, win_id, self) + completer_obj.next_prev_item.connect(self.on_next_prev_item) objreg.register('completer', completer_obj, scope='window', window=win_id) self.enabled = config.get('completion', 'show') @@ -168,12 +168,15 @@ class CompletionView(QTreeView): # Item is a real item, not a category header -> success return idx - def _next_prev_item(self, prev): + @pyqtSlot(bool) + def on_next_prev_item(self, prev): """Handle a tab press for the CompletionView. Select the previous/next item and write the new text to the statusbar. + Called from the Completer's next_prev_item signal. + Args: prev: True for prev item, False for next one. """ @@ -233,18 +236,6 @@ class CompletionView(QTreeView): selmod.clearSelection() selmod.clearCurrentIndex() - @cmdutils.register(instance='completion', hide=True, - modes=[usertypes.KeyMode.command], scope='window') - def completion_item_prev(self): - """Select the previous completion item.""" - self._next_prev_item(prev=True) - - @cmdutils.register(instance='completion', hide=True, - modes=[usertypes.KeyMode.command], scope='window') - def completion_item_next(self): - """Select the next completion item.""" - self._next_prev_item(prev=False) - def selectionChanged(self, selected, deselected): """Extend selectionChanged to call completers selection_changed.""" super().selectionChanged(selected, deselected) diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py index 3c57ae43d..15c41d5ef 100644 --- a/qutebrowser/config/configdata.py +++ b/qutebrowser/config/configdata.py @@ -352,6 +352,10 @@ def data(readonly=False): )), ('completion', sect.KeyValue( + ('auto-open', + SettingValue(typ.Bool(), 'true'), + "Automatically open completion when typing."), + ('download-path-suggestion', SettingValue(typ.DownloadPathSuggestion(), 'path'), "What to display in the download filename input."),