Implement modes and hint input.
This commit is contained in:
parent
5a3966ca82
commit
d7b87e09c9
@ -57,6 +57,7 @@ from qutebrowser.widgets.mainwindow import MainWindow
|
||||
from qutebrowser.widgets.crash import CrashDialog
|
||||
from qutebrowser.commands.keys import CommandKeyParser
|
||||
from qutebrowser.commands.parsers import CommandParser, SearchParser
|
||||
from qutebrowser.browser.hints import HintKeyParser
|
||||
from qutebrowser.utils.appdirs import AppDirs
|
||||
from qutebrowser.utils.misc import dotted_getattr
|
||||
from qutebrowser.utils.debug import set_trace # pylint: disable=unused-import
|
||||
@ -74,13 +75,14 @@ class QuteBrowser(QApplication):
|
||||
Attributes:
|
||||
mainwindow: The MainWindow QWidget.
|
||||
commandparser: The main CommandParser instance.
|
||||
keyparser: The main CommandKeyParser instance.
|
||||
searchparser: The main SearchParser instance.
|
||||
_keyparsers: A mapping from modes to keyparsers.
|
||||
_dirs: AppDirs instance for config/cache directories.
|
||||
_args: ArgumentParser instance.
|
||||
_timers: List of used QTimers so they don't get GCed.
|
||||
_shutting_down: True if we're currently shutting down.
|
||||
_quit_status: The current quitting status.
|
||||
_mode: The mode we're currently in.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
@ -88,6 +90,7 @@ class QuteBrowser(QApplication):
|
||||
self._quit_status = {}
|
||||
self._timers = []
|
||||
self._shutting_down = False
|
||||
self._mode = None
|
||||
|
||||
sys.excepthook = self._exception_hook
|
||||
|
||||
@ -108,40 +111,16 @@ class QuteBrowser(QApplication):
|
||||
|
||||
self.commandparser = CommandParser()
|
||||
self.searchparser = SearchParser()
|
||||
self.keyparser = CommandKeyParser(self)
|
||||
self._keyparsers = {
|
||||
"normal": CommandKeyParser(self),
|
||||
"hint": HintKeyParser(self),
|
||||
}
|
||||
self._init_cmds()
|
||||
self.mainwindow = MainWindow()
|
||||
|
||||
self.setQuitOnLastWindowClosed(False)
|
||||
self.lastWindowClosed.connect(self.shutdown)
|
||||
self.mainwindow.tabs.keypress.connect(
|
||||
self.mainwindow.status.keypress)
|
||||
self.mainwindow.tabs.keypress.connect(self.keyparser.handle)
|
||||
self.keyparser.set_cmd_text.connect(
|
||||
self.mainwindow.status.cmd.set_cmd_text)
|
||||
self.mainwindow.tabs.set_cmd_text.connect(
|
||||
self.mainwindow.status.cmd.set_cmd_text)
|
||||
self.mainwindow.tabs.quit.connect(self.shutdown)
|
||||
self.mainwindow.status.cmd.got_cmd.connect(self.commandparser.run)
|
||||
self.mainwindow.status.cmd.got_search.connect(self.searchparser.search)
|
||||
self.mainwindow.status.cmd.got_search_rev.connect(
|
||||
self.searchparser.search_rev)
|
||||
self.mainwindow.status.cmd.returnPressed.connect(
|
||||
self.mainwindow.tabs.setFocus)
|
||||
self.searchparser.do_search.connect(
|
||||
self.mainwindow.tabs.cur.search)
|
||||
self.keyparser.keystring_updated.connect(
|
||||
self.mainwindow.status.keystring.setText)
|
||||
message.bridge.error.connect(self.mainwindow.status.disp_error)
|
||||
message.bridge.info.connect(self.mainwindow.status.disp_tmp_text)
|
||||
self.config.style_changed.connect(style.invalidate_caches)
|
||||
self.config.changed.connect(self.mainwindow.tabs.on_config_changed)
|
||||
self.config.changed.connect(
|
||||
self.mainwindow.completion.on_config_changed)
|
||||
self.config.changed.connect(self.mainwindow.on_config_changed)
|
||||
self.config.changed.connect(config.cmd_history.on_config_changed)
|
||||
self.config.changed.connect(websettings.on_config_changed)
|
||||
self.config.changed.connect(self.keyparser.on_config_changed)
|
||||
|
||||
self._connect_signals()
|
||||
self.set_mode("normal")
|
||||
|
||||
self.mainwindow.show()
|
||||
self._python_hacks()
|
||||
@ -241,6 +220,45 @@ class QuteBrowser(QApplication):
|
||||
timer.timeout.connect(lambda: None)
|
||||
self._timers.append(timer)
|
||||
|
||||
def _connect_signals(self):
|
||||
"""Connect all signals to their slots."""
|
||||
self.lastWindowClosed.connect(self.shutdown)
|
||||
self.mainwindow.tabs.keypress.connect(
|
||||
self.mainwindow.status.keypress)
|
||||
self._keyparsers["normal"].set_cmd_text.connect(
|
||||
self.mainwindow.status.cmd.set_cmd_text)
|
||||
self.mainwindow.tabs.set_cmd_text.connect(
|
||||
self.mainwindow.status.cmd.set_cmd_text)
|
||||
self.mainwindow.tabs.quit.connect(self.shutdown)
|
||||
self.mainwindow.status.cmd.got_cmd.connect(self.commandparser.run)
|
||||
self.mainwindow.status.cmd.got_search.connect(self.searchparser.search)
|
||||
self.mainwindow.status.cmd.got_search_rev.connect(
|
||||
self.searchparser.search_rev)
|
||||
self.mainwindow.status.cmd.returnPressed.connect(
|
||||
self.mainwindow.tabs.setFocus)
|
||||
self.searchparser.do_search.connect(
|
||||
self.mainwindow.tabs.cur.search)
|
||||
self._keyparsers["normal"].keystring_updated.connect(
|
||||
self.mainwindow.status.keystring.setText)
|
||||
self._keyparsers["hint"].fire_hint.connect(
|
||||
self.mainwindow.tabs.cur.fire_hint)
|
||||
self._keyparsers["hint"].keystring_updated.connect(
|
||||
self.mainwindow.tabs.cur.handle_hint_key)
|
||||
self.mainwindow.tabs.hint_strings_updated.connect(
|
||||
self._keyparsers["hint"].on_hint_strings_updated)
|
||||
self.mainwindow.tabs.set_mode.connect(self.set_mode)
|
||||
message.bridge.error.connect(self.mainwindow.status.disp_error)
|
||||
message.bridge.info.connect(self.mainwindow.status.disp_tmp_text)
|
||||
self.config.style_changed.connect(style.invalidate_caches)
|
||||
self.config.changed.connect(self.mainwindow.tabs.on_config_changed)
|
||||
self.config.changed.connect(
|
||||
self.mainwindow.completion.on_config_changed)
|
||||
self.config.changed.connect(self.mainwindow.on_config_changed)
|
||||
self.config.changed.connect(config.cmd_history.on_config_changed)
|
||||
self.config.changed.connect(websettings.on_config_changed)
|
||||
self.config.changed.connect(
|
||||
self._keyparsers["normal"].on_config_changed)
|
||||
|
||||
def _recover_pages(self):
|
||||
"""Try to recover all open pages.
|
||||
|
||||
@ -340,6 +358,20 @@ class QuteBrowser(QApplication):
|
||||
logging.debug("maybe_quit quitting.")
|
||||
self.quit()
|
||||
|
||||
@pyqtSlot(str)
|
||||
def set_mode(self, mode):
|
||||
"""Set a key input mode.
|
||||
|
||||
Args:
|
||||
mode: The new mode to set, as an index for self._keyparsers.
|
||||
"""
|
||||
if self._mode is not None:
|
||||
oldhandler = self._keyparsers[self._mode]
|
||||
self.mainwindow.tabs.keypress.disconnect(oldhandler.handle)
|
||||
handler = self._keyparsers[mode]
|
||||
self.mainwindow.tabs.keypress.connect(handler.handle)
|
||||
self._mode = mode
|
||||
|
||||
@cmdutils.register(instance='', maxsplit=0)
|
||||
def pyeval(self, s):
|
||||
"""Evaluate a python string and display the results as a webpage.
|
||||
|
@ -175,6 +175,16 @@ class CurCommandDispatcher(QObject):
|
||||
"""
|
||||
self._tabs.currentWidget().hintmanager.start(mode)
|
||||
|
||||
@pyqtSlot(str)
|
||||
def handle_hint_key(self, keystr):
|
||||
"""Handle a new hint keypress."""
|
||||
self._tabs.currentWidget().hintmanager.handle_partial_key(keystr)
|
||||
|
||||
@pyqtSlot(str)
|
||||
def fire_hint(self, keystr):
|
||||
"""Fire a completed hint."""
|
||||
self._tabs.currentWidget().hintmanager.fire(keystr)
|
||||
|
||||
@pyqtSlot(str, int)
|
||||
def search(self, text, flags):
|
||||
"""Search for text in the current page.
|
||||
|
@ -19,10 +19,41 @@
|
||||
|
||||
import math
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, QObject
|
||||
|
||||
import qutebrowser.config.config as config
|
||||
from qutebrowser.utils.keyparser import KeyParser
|
||||
|
||||
|
||||
class HintManager:
|
||||
class HintKeyParser(KeyParser):
|
||||
|
||||
"""KeyParser for hints.
|
||||
|
||||
Class attributes:
|
||||
supports_count: If the keyparser should support counts.
|
||||
|
||||
Signals:
|
||||
fire_hint: When a hint keybinding was completed.
|
||||
Arg: the keystring/hint string pressed.
|
||||
"""
|
||||
|
||||
supports_count = False
|
||||
fire_hint = pyqtSignal(str)
|
||||
|
||||
def execute(self, cmdstr, count=None):
|
||||
"""Handle a completed keychain."""
|
||||
self.fire_hint.emit(cmdstr)
|
||||
|
||||
def on_hint_strings_updated(self, strings):
|
||||
"""Handler for HintManager's hint_strings_updated.
|
||||
|
||||
Args:
|
||||
strings: A list of hint strings.
|
||||
"""
|
||||
self.bindings = {s: s for s in strings}
|
||||
|
||||
|
||||
class HintManager(QObject):
|
||||
|
||||
"""Manage drawing hints over links or other elements.
|
||||
|
||||
@ -34,6 +65,10 @@ class HintManager:
|
||||
_frame: The QWebFrame to use.
|
||||
_elems: The elements we're hinting currently.
|
||||
_labels: The label elements.
|
||||
|
||||
Signals:
|
||||
hint_strings_updated: Emitted when the possible hint strings changed.
|
||||
set_mode: Emitted when the input mode should be changed.
|
||||
"""
|
||||
|
||||
SELECTORS = {
|
||||
@ -60,12 +95,16 @@ class HintManager:
|
||||
top: {top}px;
|
||||
"""
|
||||
|
||||
hint_strings_updated = pyqtSignal(list)
|
||||
set_mode = pyqtSignal(str)
|
||||
|
||||
def __init__(self, frame):
|
||||
"""Constructor.
|
||||
|
||||
Args:
|
||||
frame: The QWebFrame to use for finding elements and drawing.
|
||||
"""
|
||||
super().__init__(frame)
|
||||
self._frame = frame
|
||||
self._elems = []
|
||||
self._labels = []
|
||||
@ -196,6 +235,8 @@ class HintManager:
|
||||
strings = self._hint_strings(self._elems)
|
||||
for e, string in zip(self._elems, strings):
|
||||
self._draw_label(e, string)
|
||||
self.hint_strings_updated.emit(strings)
|
||||
self.set_mode.emit("hint")
|
||||
|
||||
def stop(self):
|
||||
"""Stop hinting."""
|
||||
@ -203,3 +244,12 @@ class HintManager:
|
||||
e.removeFromDocument()
|
||||
self._elems = None
|
||||
self._labels = []
|
||||
self.set_mode.emit("normal")
|
||||
|
||||
def handle_partial_key(self, keystr):
|
||||
"""Handle a new partial keypress."""
|
||||
raise NotImplementedError
|
||||
|
||||
def fire(self, keystr):
|
||||
"""Fire a completed hint."""
|
||||
raise NotImplementedError
|
||||
|
@ -37,9 +37,11 @@ class CommandKeyParser(KeyParser):
|
||||
|
||||
"""Keyparser for command bindings.
|
||||
|
||||
Class attributes:
|
||||
supports_count: If the keyparser should support counts.
|
||||
|
||||
Attributes:
|
||||
commandparser: Commandparser instance.
|
||||
supports_count: If the keyparser should support counts.
|
||||
|
||||
Signals:
|
||||
set_cmd_text: Emitted when the statusbar should set a partial command.
|
||||
|
@ -67,6 +67,10 @@ class TabbedBrowser(TabWidget):
|
||||
cur_scroll_perc_changed: Scroll percentage of current tab changed.
|
||||
arg 1: x-position in %.
|
||||
arg 2: y-position in %.
|
||||
hint_strings_updated: Hint strings were updated.
|
||||
arg: A list of hint strings.
|
||||
set_mode: The input mode should be changed.
|
||||
arg: The new mode as a string.
|
||||
keypress: A key was pressed.
|
||||
arg: The QKeyEvent leading to the keypress.
|
||||
shutdown_complete: The shuttdown is completed.
|
||||
@ -84,7 +88,9 @@ class TabbedBrowser(TabWidget):
|
||||
cur_url_changed = pyqtSignal('QUrl')
|
||||
cur_link_hovered = pyqtSignal(str, str, str)
|
||||
cur_scroll_perc_changed = pyqtSignal(int, int)
|
||||
hint_strings_updated = pyqtSignal(list)
|
||||
set_cmd_text = pyqtSignal(str)
|
||||
set_mode = pyqtSignal(str)
|
||||
keypress = pyqtSignal('QKeyEvent')
|
||||
shutdown_complete = pyqtSignal()
|
||||
quit = pyqtSignal()
|
||||
@ -238,6 +244,8 @@ class TabbedBrowser(TabWidget):
|
||||
tab.temp_message.connect(self._filter.create(self.cur_temp_message))
|
||||
tab.urlChanged.connect(self._filter.create(self.cur_url_changed))
|
||||
tab.titleChanged.connect(self._titleChanged_handler)
|
||||
tab.hintmanager.hint_strings_updated.connect(self.hint_strings_updated)
|
||||
tab.hintmanager.set_mode.connect(self.set_mode)
|
||||
# FIXME sometimes this doesn't load
|
||||
tab.show()
|
||||
tab.open_tab.connect(self.tabopen)
|
||||
|
Loading…
Reference in New Issue
Block a user