summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2019-12-14 22:35:00 +0100
committerFlorian Bruhin <me@the-compiler.org>2019-12-14 22:35:00 +0100
commit0aff95bede61709918d120c63111d8122031cfee (patch)
treeafed879c74673dd0db0b3f8b3c38c71f3b3a92e7
parent02c3f02edc2152b2d41c5c004f9f047cadc3a244 (diff)
downloadqutebrowser-0aff95bede61709918d120c63111d8122031cfee.tar.gz
qutebrowser-0aff95bede61709918d120c63111d8122031cfee.zip
Add :spawn --output-messages
-rw-r--r--doc/changelog.asciidoc2
-rw-r--r--qutebrowser/browser/commands.py7
-rw-r--r--qutebrowser/misc/guiprocess.py10
-rw-r--r--tests/unit/misc/test_guiprocess.py47
4 files changed, 63 insertions, 3 deletions
diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc
index 70a66e5a5..753d29ced 100644
--- a/doc/changelog.asciidoc
+++ b/doc/changelog.asciidoc
@@ -50,6 +50,8 @@ Changed
- qutebrowser now enables the new PyQt exit scheme, which should result in
things being cleaned up more properly (e.g. cookies being saved even without
a timeout) on PyQt 5.13.1 and newer.
+- The `:spawn` command has a new `-m` / `--output-messages` argument which
+ shows qutebrowser messages based on a command's standard output/error.
- Performance improvements for the following areas:
* Adding settings with URL patterns
* Matching of settings using URL patterns
diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py
index c4b8e86f8..871d0f673 100644
--- a/qutebrowser/browser/commands.py
+++ b/qutebrowser/browser/commands.py
@@ -994,8 +994,9 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0, no_replace_variables=True)
@cmdutils.argument('count', value=cmdutils.Value.count)
+ @cmdutils.argument('output_messages', flag='m')
def spawn(self, cmdline, userscript=False, verbose=False,
- output=False, detach=False, count=None):
+ output=False, output_messages=False, detach=False, count=None):
"""Spawn a command in a shell.
Args:
@@ -1006,7 +1007,8 @@ class CommandDispatcher:
(or `$XDG_DATA_HOME`)
- `/usr/share/qutebrowser/userscripts`
verbose: Show notifications when the command started/exited.
- output: Whether the output should be shown in a new tab.
+ output: Show the output in a new tab.
+ output_messages: Show the output as messages.
detach: Whether the command should be detached from qutebrowser.
cmdline: The commandline to execute.
count: Given to userscripts as $QUTE_COUNT.
@@ -1048,6 +1050,7 @@ class CommandDispatcher:
else:
cmd = os.path.expanduser(cmd)
proc = guiprocess.GUIProcess(what='command', verbose=verbose,
+ output_messages=output_messages,
parent=self._tabbed_browser)
if detach:
ok = proc.start_detached(cmd, args)
diff --git a/qutebrowser/misc/guiprocess.py b/qutebrowser/misc/guiprocess.py
index 13c270944..aedb07bd1 100644
--- a/qutebrowser/misc/guiprocess.py
+++ b/qutebrowser/misc/guiprocess.py
@@ -37,6 +37,7 @@ class GUIProcess(QObject):
cmd: The command which was started.
args: A list of arguments which gets passed.
verbose: Whether to show more messages.
+ _output_messages: Show output as messages.
_started: Whether the underlying process is started.
_proc: The underlying QProcess.
_what: What kind of thing is spawned (process/editor/userscript/...).
@@ -51,10 +52,11 @@ class GUIProcess(QObject):
started = pyqtSignal()
def __init__(self, what, *, verbose=False, additional_env=None,
- parent=None):
+ output_messages=False, parent=None):
super().__init__(parent)
self._what = what
self.verbose = verbose
+ self._output_messages = output_messages
self._started = False
self.cmd = None
self.args = None
@@ -92,6 +94,12 @@ class GUIProcess(QObject):
stdout = bytes(self._proc.readAllStandardOutput()).decode(
encoding, 'replace')
+ if self._output_messages:
+ if stdout:
+ message.info(stdout.strip())
+ if stderr:
+ message.error(stderr.strip())
+
if status == QProcess.CrashExit:
exitinfo = "{} crashed!".format(self._what.capitalize())
message.error(exitinfo)
diff --git a/tests/unit/misc/test_guiprocess.py b/tests/unit/misc/test_guiprocess.py
index bb14a0cf2..32320ff5c 100644
--- a/tests/unit/misc/test_guiprocess.py
+++ b/tests/unit/misc/test_guiprocess.py
@@ -84,6 +84,53 @@ def test_start_verbose(proc, qtbot, message_mock, py_proc):
assert qutescheme.spawn_output == expected
+@pytest.mark.parametrize('stdout', [True, False])
+@pytest.mark.parametrize('stderr', [True, False])
+def test_start_output_message(proc, qtbot, caplog, message_mock, py_proc,
+ stdout, stderr):
+ proc._output_messages = True
+
+ code = ['import sys']
+ if stdout:
+ code.append('print("stdout text")')
+ if stderr:
+ code.append(r'sys.stderr.write("stderr text\n")')
+ code.append("sys.exit(0)")
+
+ with caplog.at_level(logging.ERROR, 'message'):
+ with qtbot.waitSignals([proc.started, proc.finished],
+ timeout=10000,
+ order='strict'):
+ argv = py_proc(';'.join(code))
+ proc.start(*argv)
+
+ if stdout and stderr:
+ stdout_msg = message_mock.messages[0]
+ stderr_msg = message_mock.messages[1]
+ msg_count = 2
+ elif stdout:
+ stdout_msg = message_mock.messages[0]
+ stderr_msg = None
+ msg_count = 1
+ elif stderr:
+ stdout_msg = None
+ stderr_msg = message_mock.messages[0]
+ msg_count = 1
+ else:
+ stdout_msg = None
+ stderr_msg = None
+ msg_count = 0
+
+ assert len(message_mock.messages) == msg_count
+
+ if stdout_msg is not None:
+ assert stdout_msg.level == usertypes.MessageLevel.info
+ assert stdout_msg.text == 'stdout text'
+ if stderr_msg is not None:
+ assert stderr_msg.level == usertypes.MessageLevel.error
+ assert stderr_msg.text == 'stderr text'
+
+
def test_start_env(monkeypatch, qtbot, py_proc):
monkeypatch.setenv('QUTEBROWSER_TEST_1', '1')
env = {'QUTEBROWSER_TEST_2': '2'}