diff --git a/README.asciidoc b/README.asciidoc index ab2c8b250..3efc88905 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -228,6 +228,7 @@ Contributors, sorted by the number of commits in descending order: * Matthias Lisin * Marcel Schilling * Johannes Martinsson +* Jeremy Kaplan * Jean-Christophe Petkovich * Jay Kamat * Helen Sherwood-Taylor diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index 7652277ba..c46805325 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -495,12 +495,13 @@ If the pasted text contains newlines, each line gets opened in its own tab. [[print]] === print -Syntax: +:print [*--preview*]+ +Syntax: +:print [*--preview*] [*--pdf* 'file']+ Print the current/[count]th tab. ==== optional arguments * +*-p*+, +*--preview*+: Show preview instead of printing. +* +*-f*+, +*--pdf*+: The file path to write the PDF to. ==== count The tab index to print. diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 748267178..74d857de7 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -28,7 +28,7 @@ import functools from PyQt5.QtWidgets import QApplication, QTabBar from PyQt5.QtCore import Qt, QUrl, QEvent from PyQt5.QtGui import QKeyEvent -from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog +from PyQt5.QtPrintSupport import QPrintDialog, QPrinter, QPrintPreviewDialog from PyQt5.QtWebKitWidgets import QWebPage try: from PyQt5.QtWebEngineWidgets import QWebEnginePage @@ -299,12 +299,14 @@ class CommandDispatcher: @cmdutils.register(instance='command-dispatcher', name='print', scope='window') @cmdutils.argument('count', count=True) - def printpage(self, preview=False, count=None): + @cmdutils.argument('pdf', flag='f', metavar='file') + def printpage(self, preview=False, count=None, *, pdf=None): """Print the current/[count]th tab. Args: preview: Show preview instead of printing. count: The tab index to print, or None. + pdf: The file path to write the PDF to. """ if not qtutils.check_print_compat(): # WORKAROUND (remove this when we bump the requirements to 5.3.0) @@ -320,6 +322,15 @@ class CommandDispatcher: Qt.WindowMinimizeButtonHint) diag.paintRequested.connect(tab.print) diag.exec_() + elif pdf: + pdf = os.path.expanduser(pdf) + directory = os.path.dirname(pdf) + if directory and not os.path.exists(directory): + os.mkdir(directory) + printer = QPrinter() + printer.setOutputFileName(pdf) + tab.print(printer) + log.misc.debug("Print to file: {}".format(pdf)) else: diag = QPrintDialog() diag.setAttribute(Qt.WA_DeleteOnClose) diff --git a/tests/end2end/features/misc.feature b/tests/end2end/features/misc.feature index ed415958d..5842a12a5 100644 --- a/tests/end2end/features/misc.feature +++ b/tests/end2end/features/misc.feature @@ -339,6 +339,13 @@ Feature: Various utility commands. And I run :debug-pyeval QApplication.instance().activeModalWidget().close() Then no crash should happen + Scenario: print pdf + Given a new tmpdir + When I open data/hello.txt + And I run :print --pdf (tmpdir)/hello.pdf + And I wait for "Print to file: *" in the log or skip the test + Then the file hello.pdf should exist in the tmpdir + # :pyeval Scenario: Running :pyeval diff --git a/tests/end2end/features/test_misc_bdd.py b/tests/end2end/features/test_misc_bdd.py index 443583166..7a28d059c 100644 --- a/tests/end2end/features/test_misc_bdd.py +++ b/tests/end2end/features/test_misc_bdd.py @@ -73,3 +73,14 @@ def check_cookie(quteproc, name, value): data = json.loads(content) print(data) assert data['cookies'][name] == value + + +@bdd.given(bdd.parsers.parse('a new tmpdir')) +def tmpdir(tmpdir_factory): + return tmpdir_factory.mktemp('tmpdir') + + +@bdd.then(bdd.parsers.parse('the file {filename} should exist in the tmpdir')) +def file_exists(quteproc, tmpdir, filename): + path = tmpdir / filename + assert os.path.exists(str(path))