Simplify userscript running.

This commit is contained in:
Florian Bruhin 2014-07-29 02:05:15 +02:00
parent b83dd59469
commit 425a7fd7c4
5 changed files with 52 additions and 26 deletions

View File

@ -45,6 +45,7 @@ import qutebrowser.utils.log as log
import qutebrowser.utils.version as version import qutebrowser.utils.version as version
import qutebrowser.utils.url as urlutils import qutebrowser.utils.url as urlutils
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
import qutebrowser.commands.userscripts as userscripts
from qutebrowser.config.config import ConfigManager from qutebrowser.config.config import ConfigManager
from qutebrowser.keyinput.modeman import ModeManager from qutebrowser.keyinput.modeman import ModeManager
from qutebrowser.widgets.mainwindow import MainWindow from qutebrowser.widgets.mainwindow import MainWindow
@ -136,6 +137,8 @@ class Application(QApplication):
quickmarks.init() quickmarks.init()
log.init.debug("Initializing proxy...") log.init.debug("Initializing proxy...")
proxy.init() proxy.init()
log.init.debug("Initializing userscripts...")
userscripts.init()
log.init.debug("Initializing cookies...") log.init.debug("Initializing cookies...")
self.cookiejar = CookieJar(self) self.cookiejar = CookieJar(self)
log.init.debug("Initializing commands...") log.init.debug("Initializing commands...")

View File

@ -37,10 +37,10 @@ import qutebrowser.utils.webelem as webelem
import qutebrowser.browser.quickmarks as quickmarks import qutebrowser.browser.quickmarks as quickmarks
import qutebrowser.utils.log as log import qutebrowser.utils.log as log
import qutebrowser.utils.url as urlutils import qutebrowser.utils.url as urlutils
import qutebrowser.commands.userscripts as userscripts
from qutebrowser.utils.qt import check_overflow, check_print_compat from qutebrowser.utils.qt import check_overflow, check_print_compat
from qutebrowser.utils.editor import ExternalEditor from qutebrowser.utils.editor import ExternalEditor
from qutebrowser.commands.exceptions import CommandError from qutebrowser.commands.exceptions import CommandError
from qutebrowser.commands.userscripts import UserscriptRunner
from qutebrowser.utils.usertypes import KeyMode from qutebrowser.utils.usertypes import KeyMode
@ -57,7 +57,6 @@ class CommandDispatcher:
Attributes: Attributes:
_tabs: The TabbedBrowser object. _tabs: The TabbedBrowser object.
_editor: The ExternalEditor object. _editor: The ExternalEditor object.
_userscript_runners: A list of userscript runners.
""" """
def __init__(self, parent): def __init__(self, parent):
@ -66,7 +65,6 @@ class CommandDispatcher:
Args: Args:
parent: The TabbedBrowser for this dispatcher. parent: The TabbedBrowser for this dispatcher.
""" """
self._userscript_runners = []
self._tabs = parent self._tabs = parent
self._editor = None self._editor = None
@ -603,7 +601,7 @@ class CommandDispatcher:
self.openurl(config.get('general', 'startpage')[0]) self.openurl(config.get('general', 'startpage')[0])
@cmdutils.register(instance='mainwindow.tabs.cmd') @cmdutils.register(instance='mainwindow.tabs.cmd')
def run_userscript(self, cmd, *args, url=None): def run_userscript(self, cmd, *args):
"""Run an userscript given as argument. """Run an userscript given as argument.
Args: Args:
@ -611,15 +609,8 @@ class CommandDispatcher:
args: Arguments to pass to the userscript. args: Arguments to pass to the userscript.
url: A custom QUrl to use instead of the current url. url: A custom QUrl to use instead of the current url.
""" """
if url is None:
url = self._tabs.current_url() url = self._tabs.current_url()
# We don't remove the password in the URL here, as it's probably safe userscripts.run(cmd, *args, url=url)
# to pass via env variable.
urlstr = url.toString(QUrl.FullyEncoded)
runner = UserscriptRunner(self._tabs)
runner.got_cmd.connect(self._tabs.got_cmd)
runner.run(cmd, *args, env={'QUTE_URL': urlstr})
self._userscript_runners.append(runner)
@cmdutils.register(instance='mainwindow.tabs.cmd') @cmdutils.register(instance='mainwindow.tabs.cmd')
def quickmark_save(self): def quickmark_save(self):

View File

@ -31,6 +31,7 @@ import qutebrowser.config.config as config
import qutebrowser.keyinput.modeman as modeman import qutebrowser.keyinput.modeman as modeman
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
import qutebrowser.utils.webelem as webelem import qutebrowser.utils.webelem as webelem
import qutebrowser.commands.userscripts as userscripts
from qutebrowser.commands.exceptions import CommandError from qutebrowser.commands.exceptions import CommandError
from qutebrowser.utils.usertypes import enum, KeyMode from qutebrowser.utils.usertypes import enum, KeyMode
from qutebrowser.utils.log import hints as logger from qutebrowser.utils.log import hints as logger
@ -111,9 +112,6 @@ class HintManager(QObject):
download_get: Download an URL. download_get: Download an URL.
arg 0: The URL to download, as QUrl. arg 0: The URL to download, as QUrl.
arg 1: The QWebPage to download the URL in. arg 1: The QWebPage to download the URL in.
run_userscript: Emitted when a custom userscript should be run.
arg 0: The URL which was selected.
arg 1: The userscript/args to run.
""" """
HINT_CSS = """ HINT_CSS = """
@ -150,7 +148,6 @@ class HintManager(QObject):
openurl = pyqtSignal('QUrl', bool) openurl = pyqtSignal('QUrl', bool)
set_open_target = pyqtSignal(str) set_open_target = pyqtSignal(str)
download_get = pyqtSignal('QUrl', 'QWebPage') download_get = pyqtSignal('QUrl', 'QWebPage')
run_userscript = pyqtSignal('QUrl', list)
def __init__(self, parent=None): def __init__(self, parent=None):
"""Constructor. """Constructor.
@ -369,7 +366,9 @@ class HintManager(QObject):
def _call_userscript(self, url): def _call_userscript(self, url):
"""Call an userscript from a hint.""" """Call an userscript from a hint."""
qt_ensure_valid(url) qt_ensure_valid(url)
self.run_userscript.emit(url, list(self._context.args)) cmd = self._context.args[0]
args = self._context.args[1:]
userscripts.run(cmd, *args, url=url)
def _spawn(self, url): def _spawn(self, url):
"""Spawn a simple command from a hint.""" """Spawn a simple command from a hint."""

View File

@ -17,20 +17,30 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>. # along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Functions to execute an userscript.""" """Functions to execute an userscript.
Module attributes:
_runners: Active userscript runners from run_userscript.
"""
import os import os
import os.path import os.path
import tempfile import tempfile
from select import select from select import select
from functools import partial
from PyQt5.QtCore import (pyqtSignal, QObject, QThread, QStandardPaths, from PyQt5.QtCore import (pyqtSignal, QObject, QThread, QStandardPaths,
QProcessEnvironment, QProcess) QProcessEnvironment, QProcess, QUrl)
import qutebrowser.utils.message as message import qutebrowser.utils.message as message
from qutebrowser.utils.misc import get_standard_dir from qutebrowser.utils.misc import get_standard_dir
from qutebrowser.utils.log import procs as logger from qutebrowser.utils.log import procs as logger
from qutebrowser.commands.exceptions import CommandError from qutebrowser.commands.exceptions import CommandError
from qutebrowser.commands.managers import CommandManager
_runners = []
_commandmanager = None
class _BlockingFIFOReader(QObject): class _BlockingFIFOReader(QObject):
@ -97,9 +107,11 @@ class _BaseUserscriptRunner(QObject):
Signals: Signals:
got_cmd: Emitted when a new command arrived and should be executed. got_cmd: Emitted when a new command arrived and should be executed.
finished: Emitted when the userscript finished running.
""" """
got_cmd = pyqtSignal(str) got_cmd = pyqtSignal(str)
finished = pyqtSignal()
PROCESS_MESSAGES = { PROCESS_MESSAGES = {
QProcess.FailedToStart: "The process failed to start.", QProcess.FailedToStart: "The process failed to start.",
@ -229,6 +241,7 @@ class _POSIXUserscriptRunner(_BaseUserscriptRunner):
self.reader.fifo.close() self.reader.fifo.close()
self.reader.deleteLater() self.reader.deleteLater()
super()._cleanup() super()._cleanup()
self.finished.emit()
def on_thread_finished(self): def on_thread_finished(self):
"""Clean up the QThread object when the thread finished.""" """Clean up the QThread object when the thread finished."""
@ -270,11 +283,13 @@ class _WindowsUserscriptRunner(_BaseUserscriptRunner):
for line in f: for line in f:
self.got_cmd.emit(line.rstrip()) self.got_cmd.emit(line.rstrip())
self._cleanup() self._cleanup()
self.finished.emit()
def on_proc_error(self, error): def on_proc_error(self, error):
"""Clean up when the process had an error.""" """Clean up when the process had an error."""
super().on_proc_error(error) super().on_proc_error(error)
self._cleanup() self._cleanup()
self.finished.emit()
def run(self, cmd, *args, env=None): def run(self, cmd, *args, env=None):
self.oshandle, self.filepath = tempfile.mkstemp(text=True) self.oshandle, self.filepath = tempfile.mkstemp(text=True)
@ -287,10 +302,16 @@ class _DummyUserscriptRunner:
Used on unknown systems since we don't know what (or if any) approach will Used on unknown systems since we don't know what (or if any) approach will
work there. work there.
Signals:
finished: Always emitted.
""" """
finished = pyqtSignal()
def run(self, _cmd, *_args, _env=None): def run(self, _cmd, *_args, _env=None):
"""Print an error as userscripts are not supported.""" """Print an error as userscripts are not supported."""
self.finished.emit()
raise CommandError("Userscripts are not supported on this platform!") raise CommandError("Userscripts are not supported on this platform!")
@ -302,3 +323,21 @@ elif os.name == 'nt':
UserscriptRunner = _WindowsUserscriptRunner UserscriptRunner = _WindowsUserscriptRunner
else: else:
UserscriptRunner = _DummyUserscriptRunner UserscriptRunner = _DummyUserscriptRunner
def init():
"""Initialize the global _commandmanager."""
global _commandmanager
_commandmanager = CommandManager()
def run(cmd, *args, url):
"""Convenience method to run an userscript."""
# We don't remove the password in the URL here, as it's probably safe to
# pass via env variable..
urlstr = url.toString(QUrl.FullyEncoded)
runner = UserscriptRunner()
runner.got_cmd.connect(_commandmanager.run_safely)
runner.run(cmd, *args, env={'QUTE_URL': urlstr})
_runners.append(runner)
runner.finished.connect(partial(_runners.remove, runner))

View File

@ -112,7 +112,6 @@ class WebView(QWebView):
self.setPage(self._page) self.setPage(self._page)
self.hintmanager = HintManager(self) self.hintmanager = HintManager(self)
self.hintmanager.mouse_event.connect(self.on_mouse_event) self.hintmanager.mouse_event.connect(self.on_mouse_event)
self.hintmanager.run_userscript.connect(self.run_hint_userscript)
self.hintmanager.set_open_target.connect(self.set_force_open_target) self.hintmanager.set_open_target.connect(self.set_force_open_target)
self._page.linkHovered.connect(self.linkHovered) self._page.linkHovered.connect(self.linkHovered)
self._page.mainFrame().loadStarted.connect(self.on_load_started) self._page.mainFrame().loadStarted.connect(self.on_load_started)
@ -344,11 +343,6 @@ class WebView(QWebView):
""" """
self._tabs.currentWidget().findText(text, flags) self._tabs.currentWidget().findText(text, flags)
@pyqtSlot('QUrl', list)
def run_hint_userscript(self, url, args):
"""Glue slot to run an userscript via HintManager."""
self.tabbedbrowser.cmd.run_userscript(args[0], *args[1:], url=url)
def go_back(self): def go_back(self):
"""Go back a page in the history.""" """Go back a page in the history."""
if self.page().history().canGoBack(): if self.page().history().canGoBack():