summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Kamat <jaygkamat@gmail.com>2019-07-03 17:37:37 -0700
committerJay Kamat <jaygkamat@gmail.com>2019-07-03 17:37:37 -0700
commit76c3de4b8479e309f0d899ba163eb2d09df2b15a (patch)
tree558104d2bb66833f78b54bbb4958c11df323db5e
parentf35eba0d60b0150c3a1fdf6352a958d0882b3286 (diff)
parent012f11ab31146f4fce9a5d9fc67c5ef86986d90a (diff)
downloadqutebrowser-76c3de4b8479e309f0d899ba163eb2d09df2b15a.tar.gz
qutebrowser-76c3de4b8479e309f0d899ba163eb2d09df2b15a.zip
Merge branch 'master' of https://github.com/qutebrowser/qutebrowser into config-cli-option
-rw-r--r--.appveyor.yml8
-rw-r--r--.flake811
-rw-r--r--.github/CONTRIBUTING.asciidoc10
-rw-r--r--.github/ISSUE_TEMPLATE/1_Bug_report.md2
-rw-r--r--.github/ISSUE_TEMPLATE/3_Support_question.md4
-rw-r--r--.pylintrc3
-rw-r--r--.travis.yml50
-rw-r--r--MANIFEST.in4
-rw-r--r--README.asciidoc7
-rw-r--r--doc/changelog.asciidoc208
-rw-r--r--doc/contributing.asciidoc17
-rw-r--r--doc/extapi/conf.py2
-rw-r--r--doc/faq.asciidoc22
-rw-r--r--doc/help/commands.asciidoc43
-rw-r--r--doc/help/configuring.asciidoc6
-rw-r--r--doc/help/settings.asciidoc142
-rw-r--r--doc/install.asciidoc4
-rw-r--r--doc/stacktrace.asciidoc3
-rw-r--r--icons/qutebrowser.svg18
-rw-r--r--misc/Makefile8
-rw-r--r--misc/org.qutebrowser.qutebrowser.appdata.xml (renamed from misc/qutebrowser.appdata.xml)25
-rw-r--r--misc/org.qutebrowser.qutebrowser.desktop (renamed from misc/qutebrowser.desktop)1
-rw-r--r--misc/qutebrowser.spec6
-rw-r--r--misc/requirements/requirements-check-manifest.txt3
-rw-r--r--misc/requirements/requirements-codecov.txt8
-rw-r--r--misc/requirements/requirements-flake8.txt24
-rw-r--r--misc/requirements/requirements-flake8.txt-raw1
-rw-r--r--misc/requirements/requirements-mypy.txt8
-rw-r--r--misc/requirements/requirements-mypy.txt-raw1
-rw-r--r--misc/requirements/requirements-optional.txt6
-rw-r--r--misc/requirements/requirements-pip.txt8
-rw-r--r--misc/requirements/requirements-pyinstaller.txt3
-rw-r--r--misc/requirements/requirements-pylint.txt25
-rw-r--r--misc/requirements/requirements-pyqt.txt5
-rw-r--r--misc/requirements/requirements-pyqt.txt-raw3
-rw-r--r--misc/requirements/requirements-pyroma.txt2
-rw-r--r--misc/requirements/requirements-sphinx.txt31
-rw-r--r--misc/requirements/requirements-tests-git.txt1
-rw-r--r--misc/requirements/requirements-tests.txt66
-rw-r--r--misc/requirements/requirements-tests.txt-raw1
-rw-r--r--misc/requirements/requirements-tox.txt14
-rw-r--r--misc/userscripts/README.md2
-rwxr-xr-xmisc/userscripts/dmenu_qutebrowser2
-rwxr-xr-xmisc/userscripts/format_json9
-rwxr-xr-xmisc/userscripts/open_download2
-rwxr-xr-xmisc/userscripts/openfeeds2
-rwxr-xr-xmisc/userscripts/qute-keepass4
-rwxr-xr-xmisc/userscripts/qute-pass19
-rw-r--r--mypy.ini3
-rw-r--r--pytest.ini13
-rwxr-xr-xqutebrowser.py2
-rw-r--r--qutebrowser/__init__.py6
-rw-r--r--qutebrowser/__main__.py2
-rw-r--r--qutebrowser/api/__init__.py2
-rw-r--r--qutebrowser/api/apitypes.py2
-rw-r--r--qutebrowser/api/cmdutils.py2
-rw-r--r--qutebrowser/api/config.py2
-rw-r--r--qutebrowser/api/downloads.py2
-rw-r--r--qutebrowser/api/hook.py2
-rw-r--r--qutebrowser/api/interceptor.py5
-rw-r--r--qutebrowser/api/message.py2
-rw-r--r--qutebrowser/app.py87
-rw-r--r--qutebrowser/browser/__init__.py2
-rw-r--r--qutebrowser/browser/browsertab.py25
-rw-r--r--qutebrowser/browser/commands.py40
-rw-r--r--qutebrowser/browser/downloads.py22
-rw-r--r--qutebrowser/browser/downloadview.py2
-rw-r--r--qutebrowser/browser/greasemonkey.py39
-rw-r--r--qutebrowser/browser/hints.py49
-rw-r--r--qutebrowser/browser/history.py13
-rw-r--r--qutebrowser/browser/inspector.py2
-rw-r--r--qutebrowser/browser/mouse.py2
-rw-r--r--qutebrowser/browser/navigate.py2
-rw-r--r--qutebrowser/browser/network/pac.py9
-rw-r--r--qutebrowser/browser/network/proxy.py24
-rw-r--r--qutebrowser/browser/pdfjs.py7
-rw-r--r--qutebrowser/browser/qtnetworkdownloads.py2
-rw-r--r--qutebrowser/browser/qutescheme.py20
-rw-r--r--qutebrowser/browser/shared.py3
-rw-r--r--qutebrowser/browser/signalfilter.py2
-rw-r--r--qutebrowser/browser/urlmarks.py2
-rw-r--r--qutebrowser/browser/webelem.py6
-rw-r--r--qutebrowser/browser/webengine/__init__.py2
-rw-r--r--qutebrowser/browser/webengine/certificateerror.py2
-rw-r--r--qutebrowser/browser/webengine/cookies.py2
-rw-r--r--qutebrowser/browser/webengine/interceptor.py98
-rw-r--r--qutebrowser/browser/webengine/spell.py1
-rw-r--r--qutebrowser/browser/webengine/tabhistory.py4
-rw-r--r--qutebrowser/browser/webengine/webenginedownloads.py18
-rw-r--r--qutebrowser/browser/webengine/webengineelem.py5
-rw-r--r--qutebrowser/browser/webengine/webengineinspector.py2
-rw-r--r--qutebrowser/browser/webengine/webenginequtescheme.py22
-rw-r--r--qutebrowser/browser/webengine/webenginesettings.py38
-rw-r--r--qutebrowser/browser/webengine/webenginetab.py201
-rw-r--r--qutebrowser/browser/webengine/webview.py20
-rw-r--r--qutebrowser/browser/webkit/__init__.py2
-rw-r--r--qutebrowser/browser/webkit/cache.py2
-rw-r--r--qutebrowser/browser/webkit/certificateerror.py2
-rw-r--r--qutebrowser/browser/webkit/cookies.py2
-rw-r--r--qutebrowser/browser/webkit/http.py2
-rw-r--r--qutebrowser/browser/webkit/mhtml.py1
-rw-r--r--qutebrowser/browser/webkit/network/filescheme.py2
-rw-r--r--qutebrowser/browser/webkit/network/networkmanager.py2
-rw-r--r--qutebrowser/browser/webkit/network/networkreply.py5
-rw-r--r--qutebrowser/browser/webkit/network/webkitqutescheme.py2
-rw-r--r--qutebrowser/browser/webkit/rfc6266.py2
-rw-r--r--qutebrowser/browser/webkit/tabhistory.py7
-rw-r--r--qutebrowser/browser/webkit/webkitelem.py5
-rw-r--r--qutebrowser/browser/webkit/webkithistory.py2
-rw-r--r--qutebrowser/browser/webkit/webkitinspector.py2
-rw-r--r--qutebrowser/browser/webkit/webkitsettings.py2
-rw-r--r--qutebrowser/browser/webkit/webkittab.py16
-rw-r--r--qutebrowser/browser/webkit/webpage.py2
-rw-r--r--qutebrowser/browser/webkit/webview.py22
-rw-r--r--qutebrowser/commands/__init__.py10
-rw-r--r--qutebrowser/commands/argparser.py2
-rw-r--r--qutebrowser/commands/cmdexc.py2
-rw-r--r--qutebrowser/commands/command.py5
-rw-r--r--qutebrowser/commands/runners.py112
-rw-r--r--qutebrowser/commands/userscripts.py2
-rw-r--r--qutebrowser/completion/__init__.py2
-rw-r--r--qutebrowser/completion/completer.py2
-rw-r--r--qutebrowser/completion/completiondelegate.py9
-rw-r--r--qutebrowser/completion/completionwidget.py4
-rw-r--r--qutebrowser/completion/models/__init__.py2
-rw-r--r--qutebrowser/completion/models/completionmodel.py2
-rw-r--r--qutebrowser/completion/models/configmodel.py2
-rw-r--r--qutebrowser/completion/models/histcategory.py59
-rw-r--r--qutebrowser/completion/models/listcategory.py2
-rw-r--r--qutebrowser/completion/models/miscmodels.py2
-rw-r--r--qutebrowser/completion/models/urlmodel.py2
-rw-r--r--qutebrowser/completion/models/util.py2
-rw-r--r--qutebrowser/components/__init__.py2
-rw-r--r--qutebrowser/components/adblock.py2
-rw-r--r--qutebrowser/components/caretcommands.py9
-rw-r--r--qutebrowser/components/misccommands.py5
-rw-r--r--qutebrowser/components/scrollcommands.py2
-rw-r--r--qutebrowser/components/zoomcommands.py2
-rw-r--r--qutebrowser/config/__init__.py2
-rw-r--r--qutebrowser/config/config.py2
-rw-r--r--qutebrowser/config/configcache.py12
-rw-r--r--qutebrowser/config/configcommands.py21
-rw-r--r--qutebrowser/config/configdata.py12
-rw-r--r--qutebrowser/config/configdata.yml151
-rw-r--r--qutebrowser/config/configdiff.py2
-rw-r--r--qutebrowser/config/configexc.py2
-rw-r--r--qutebrowser/config/configfiles.py36
-rw-r--r--qutebrowser/config/configinit.py23
-rw-r--r--qutebrowser/config/configtypes.py140
-rw-r--r--qutebrowser/config/configutils.py2
-rw-r--r--qutebrowser/config/websettings.py8
-rw-r--r--qutebrowser/extensions/interceptors.py66
-rw-r--r--qutebrowser/extensions/loader.py2
-rw-r--r--qutebrowser/html/warning-webkit.html9
-rw-r--r--qutebrowser/javascript/.eslintrc.yaml1
-rw-r--r--qutebrowser/javascript/caret.js10
-rw-r--r--qutebrowser/javascript/global_wrapper.js2
-rw-r--r--qutebrowser/javascript/history.js1
-rw-r--r--qutebrowser/javascript/position_caret.js2
-rw-r--r--qutebrowser/javascript/print.js2
-rw-r--r--qutebrowser/javascript/scroll.js2
-rw-r--r--qutebrowser/javascript/stylesheet.js9
-rw-r--r--qutebrowser/javascript/webelem.js7
-rw-r--r--qutebrowser/keyinput/__init__.py2
-rw-r--r--qutebrowser/keyinput/basekeyparser.py2
-rw-r--r--qutebrowser/keyinput/keyutils.py2
-rw-r--r--qutebrowser/keyinput/macros.py1
-rw-r--r--qutebrowser/keyinput/modeman.py6
-rw-r--r--qutebrowser/keyinput/modeparsers.py2
-rw-r--r--qutebrowser/mainwindow/__init__.py2
-rw-r--r--qutebrowser/mainwindow/mainwindow.py21
-rw-r--r--qutebrowser/mainwindow/messageview.py15
-rw-r--r--qutebrowser/mainwindow/prompt.py25
-rw-r--r--qutebrowser/mainwindow/statusbar/__init__.py2
-rw-r--r--qutebrowser/mainwindow/statusbar/backforward.py2
-rw-r--r--qutebrowser/mainwindow/statusbar/bar.py12
-rw-r--r--qutebrowser/mainwindow/statusbar/command.py2
-rw-r--r--qutebrowser/mainwindow/statusbar/keystring.py2
-rw-r--r--qutebrowser/mainwindow/statusbar/percentage.py2
-rw-r--r--qutebrowser/mainwindow/statusbar/progress.py15
-rw-r--r--qutebrowser/mainwindow/statusbar/tabindex.py2
-rw-r--r--qutebrowser/mainwindow/statusbar/text.py2
-rw-r--r--qutebrowser/mainwindow/statusbar/textbase.py2
-rw-r--r--qutebrowser/mainwindow/statusbar/url.py2
-rw-r--r--qutebrowser/mainwindow/tabbedbrowser.py52
-rw-r--r--qutebrowser/mainwindow/tabwidget.py62
-rw-r--r--qutebrowser/misc/__init__.py2
-rw-r--r--qutebrowser/misc/autoupdate.py2
-rw-r--r--qutebrowser/misc/backendproblem.py36
-rw-r--r--qutebrowser/misc/checkpyver.py6
-rw-r--r--qutebrowser/misc/cmdhistory.py2
-rw-r--r--qutebrowser/misc/consolewidget.py4
-rw-r--r--qutebrowser/misc/crashdialog.py7
-rw-r--r--qutebrowser/misc/crashsignal.py28
-rw-r--r--qutebrowser/misc/earlyinit.py22
-rw-r--r--qutebrowser/misc/editor.py2
-rw-r--r--qutebrowser/misc/guiprocess.py81
-rw-r--r--qutebrowser/misc/httpclient.py2
-rw-r--r--qutebrowser/misc/ipc.py31
-rw-r--r--qutebrowser/misc/keyhintwidget.py3
-rw-r--r--qutebrowser/misc/lineparser.py2
-rw-r--r--qutebrowser/misc/miscwidgets.py2
-rw-r--r--qutebrowser/misc/msgbox.py2
-rw-r--r--qutebrowser/misc/objects.py3
-rw-r--r--qutebrowser/misc/pastebin.py2
-rw-r--r--qutebrowser/misc/readline.py2
-rw-r--r--qutebrowser/misc/savemanager.py2
-rw-r--r--qutebrowser/misc/sessions.py50
-rw-r--r--qutebrowser/misc/split.py2
-rw-r--r--qutebrowser/misc/sql.py51
-rw-r--r--qutebrowser/misc/utilcmds.py15
-rw-r--r--qutebrowser/qt.py2
-rw-r--r--qutebrowser/qutebrowser.py9
-rw-r--r--qutebrowser/utils/__init__.py2
-rw-r--r--qutebrowser/utils/debug.py2
-rw-r--r--qutebrowser/utils/docutils.py2
-rw-r--r--qutebrowser/utils/error.py2
-rw-r--r--qutebrowser/utils/javascript.py2
-rw-r--r--qutebrowser/utils/jinja.py5
-rw-r--r--qutebrowser/utils/log.py11
-rw-r--r--qutebrowser/utils/message.py2
-rw-r--r--qutebrowser/utils/objreg.py7
-rw-r--r--qutebrowser/utils/qtutils.py33
-rw-r--r--qutebrowser/utils/standarddir.py8
-rw-r--r--qutebrowser/utils/urlmatch.py4
-rw-r--r--qutebrowser/utils/urlutils.py56
-rw-r--r--qutebrowser/utils/usertypes.py8
-rw-r--r--qutebrowser/utils/utils.py18
-rw-r--r--qutebrowser/utils/version.py39
-rw-r--r--requirements.txt10
-rwxr-xr-xscripts/asciidoc2html.py2
-rwxr-xr-xscripts/dev/build_release.py36
-rw-r--r--scripts/dev/check_coverage.py8
-rwxr-xr-xscripts/dev/check_doc_changes.py2
-rw-r--r--scripts/dev/ci/travis_install.sh32
-rw-r--r--scripts/dev/ci/travis_run.sh3
-rwxr-xr-xscripts/dev/cleanup.py2
-rw-r--r--scripts/dev/gen_resources.py2
-rw-r--r--scripts/dev/gen_versioninfo.py2
-rw-r--r--scripts/dev/get_coredumpctl_traces.py2
-rw-r--r--scripts/dev/misc_checks.py2
-rw-r--r--scripts/dev/pylint_checkers/qute_pylint/config.py4
-rw-r--r--scripts/dev/pylint_checkers/qute_pylint/modeline.py2
-rw-r--r--scripts/dev/pylint_checkers/qute_pylint/openencoding.py2
-rw-r--r--scripts/dev/pylint_checkers/qute_pylint/settrace.py2
-rw-r--r--scripts/dev/pylint_checkers/setup.py2
-rw-r--r--scripts/dev/recompile_requirements.py2
-rwxr-xr-xscripts/dev/run_profile.py2
-rw-r--r--scripts/dev/run_pylint_on_tests.py2
-rwxr-xr-xscripts/dev/run_vulture.py2
-rwxr-xr-xscripts/dev/segfault_test.py2
-rwxr-xr-xscripts/dev/src2asciidoc.py4
-rw-r--r--scripts/dev/standardpaths_tester.py2
-rwxr-xr-xscripts/dev/ua_fetch.py33
-rwxr-xr-xscripts/dev/update_3rdparty.py2
-rwxr-xr-xscripts/dictcli.py1
-rwxr-xr-xscripts/hist_importer.py10
-rw-r--r--scripts/hostblock_blame.py2
-rwxr-xr-xscripts/importer.py2
-rw-r--r--scripts/keytester.py2
-rw-r--r--scripts/link_pyqt.py5
-rw-r--r--scripts/setupcommon.py2
-rwxr-xr-xscripts/testbrowser/testbrowser_webengine.py2
-rwxr-xr-xscripts/testbrowser/testbrowser_webkit.py2
-rw-r--r--scripts/utils.py2
-rwxr-xr-xsetup.py2
-rw-r--r--tests/conftest.py2
-rw-r--r--tests/end2end/conftest.py2
-rw-r--r--tests/end2end/data/misc/pyeval_file.py2
-rwxr-xr-xtests/end2end/data/userscripts/stdinclose.py2
-rw-r--r--tests/end2end/features/conftest.py33
-rw-r--r--tests/end2end/features/downloads.feature36
-rw-r--r--tests/end2end/features/hints.feature32
-rw-r--r--tests/end2end/features/history.feature2
-rw-r--r--tests/end2end/features/misc.feature35
-rw-r--r--tests/end2end/features/navigate.feature3
-rw-r--r--tests/end2end/features/qutescheme.feature52
-rw-r--r--tests/end2end/features/search.feature9
-rw-r--r--tests/end2end/features/sessions.feature2
-rw-r--r--tests/end2end/features/spawn.feature2
-rw-r--r--tests/end2end/features/tabs.feature8
-rw-r--r--tests/end2end/features/test_backforward_bdd.py2
-rw-r--r--tests/end2end/features/test_caret_bdd.py2
-rw-r--r--tests/end2end/features/test_completion_bdd.py2
-rw-r--r--tests/end2end/features/test_downloads_bdd.py2
-rw-r--r--tests/end2end/features/test_editor_bdd.py2
-rw-r--r--tests/end2end/features/test_hints_bdd.py2
-rw-r--r--tests/end2end/features/test_history_bdd.py2
-rw-r--r--tests/end2end/features/test_invoke_bdd.py2
-rw-r--r--tests/end2end/features/test_javascript_bdd.py2
-rw-r--r--tests/end2end/features/test_keyinput_bdd.py2
-rw-r--r--tests/end2end/features/test_marks_bdd.py2
-rw-r--r--tests/end2end/features/test_misc_bdd.py2
-rw-r--r--tests/end2end/features/test_navigate_bdd.py2
-rw-r--r--tests/end2end/features/test_open_bdd.py2
-rw-r--r--tests/end2end/features/test_private_bdd.py2
-rw-r--r--tests/end2end/features/test_prompts_bdd.py2
-rw-r--r--tests/end2end/features/test_qutescheme_bdd.py76
-rw-r--r--tests/end2end/features/test_scroll_bdd.py2
-rw-r--r--tests/end2end/features/test_search_bdd.py2
-rw-r--r--tests/end2end/features/test_sessions_bdd.py2
-rw-r--r--tests/end2end/features/test_spawn_bdd.py2
-rw-r--r--tests/end2end/features/test_tabs_bdd.py2
-rw-r--r--tests/end2end/features/test_urlmarks_bdd.py2
-rw-r--r--tests/end2end/features/test_utilcmds_bdd.py2
-rw-r--r--tests/end2end/features/test_yankpaste_bdd.py2
-rw-r--r--tests/end2end/features/test_zoom_bdd.py2
-rw-r--r--tests/end2end/features/utilcmds.feature2
-rw-r--r--tests/end2end/features/yankpaste.feature9
-rw-r--r--tests/end2end/fixtures/quteprocess.py53
-rw-r--r--tests/end2end/fixtures/test_quteprocess.py2
-rw-r--r--tests/end2end/fixtures/test_testprocess.py2
-rw-r--r--tests/end2end/fixtures/test_webserver.py2
-rw-r--r--tests/end2end/fixtures/testprocess.py2
-rw-r--r--tests/end2end/fixtures/webserver.py2
-rw-r--r--tests/end2end/fixtures/webserver_sub.py2
-rw-r--r--tests/end2end/fixtures/webserver_sub_ssl.py2
-rw-r--r--tests/end2end/misc/test_runners_e2e.py85
-rw-r--r--tests/end2end/test_dirbrowser.py1
-rw-r--r--tests/end2end/test_hints_html.py2
-rw-r--r--tests/end2end/test_insert_mode.py19
-rw-r--r--tests/end2end/test_invocations.py2
-rw-r--r--tests/end2end/test_mhtml_e2e.py6
-rw-r--r--tests/helpers/fixtures.py15
-rw-r--r--tests/helpers/logfail.py2
-rw-r--r--tests/helpers/messagemock.py2
-rw-r--r--tests/helpers/stubs.py13
-rw-r--r--tests/helpers/test_helper_utils.py2
-rw-r--r--tests/helpers/test_logfail.py2
-rw-r--r--tests/helpers/test_stubs.py2
-rw-r--r--tests/helpers/utils.py2
-rw-r--r--tests/manual/mouse.html2
-rw-r--r--tests/test_conftest.py2
-rw-r--r--tests/unit/api/test_cmdutils.py2
-rw-r--r--tests/unit/browser/test_caret.py42
-rw-r--r--tests/unit/browser/test_hints.py19
-rw-r--r--tests/unit/browser/test_history.py48
-rw-r--r--tests/unit/browser/test_pdfjs.py13
-rw-r--r--tests/unit/browser/test_qutescheme.py1
-rw-r--r--tests/unit/browser/test_shared.py13
-rw-r--r--tests/unit/browser/test_signalfilter.py2
-rw-r--r--tests/unit/browser/urlmarks.py2
-rw-r--r--tests/unit/browser/webengine/test_spell.py1
-rw-r--r--tests/unit/browser/webengine/test_webenginedownloads.py4
-rw-r--r--tests/unit/browser/webengine/test_webengineinterceptor.py39
-rw-r--r--tests/unit/browser/webengine/test_webenginesettings.py10
-rw-r--r--tests/unit/browser/webengine/test_webenginetab.py27
-rw-r--r--tests/unit/browser/webkit/http/test_content_disposition.py2
-rw-r--r--tests/unit/browser/webkit/http/test_http.py2
-rw-r--r--tests/unit/browser/webkit/http/test_http_hypothesis.py2
-rw-r--r--tests/unit/browser/webkit/network/test_filescheme.py1
-rw-r--r--tests/unit/browser/webkit/network/test_networkmanager.py2
-rw-r--r--tests/unit/browser/webkit/network/test_networkreply.py2
-rw-r--r--tests/unit/browser/webkit/network/test_pac.py16
-rw-r--r--tests/unit/browser/webkit/test_cache.py1
-rw-r--r--tests/unit/browser/webkit/test_cookies.py1
-rw-r--r--tests/unit/browser/webkit/test_downloads.py2
-rw-r--r--tests/unit/browser/webkit/test_mhtml.py1
-rw-r--r--tests/unit/browser/webkit/test_tabhistory.py2
-rw-r--r--tests/unit/browser/webkit/test_webkitelem.py4
-rw-r--r--tests/unit/commands/test_argparser.py2
-rw-r--r--tests/unit/commands/test_runners.py2
-rw-r--r--tests/unit/commands/test_userscripts.py5
-rw-r--r--tests/unit/completion/test_completer.py2
-rw-r--r--tests/unit/completion/test_completiondelegate.py2
-rw-r--r--tests/unit/completion/test_completionmodel.py4
-rw-r--r--tests/unit/completion/test_completionwidget.py2
-rw-r--r--tests/unit/completion/test_histcategory.py13
-rw-r--r--tests/unit/completion/test_listcategory.py2
-rw-r--r--tests/unit/completion/test_models.py2
-rw-r--r--tests/unit/components/test_adblock.py2
-rw-r--r--tests/unit/components/test_misccommands.py2
-rw-r--r--tests/unit/config/test_config.py16
-rw-r--r--tests/unit/config/test_configcache.py2
-rw-r--r--tests/unit/config/test_configcommands.py26
-rw-r--r--tests/unit/config/test_configdata.py6
-rw-r--r--tests/unit/config/test_configexc.py2
-rw-r--r--tests/unit/config/test_configfiles.py107
-rw-r--r--tests/unit/config/test_configinit.py49
-rw-r--r--tests/unit/config/test_configtypes.py67
-rw-r--r--tests/unit/config/test_configutils.py2
-rw-r--r--tests/unit/extensions/test_loader.py2
-rw-r--r--tests/unit/javascript/conftest.py13
-rw-r--r--tests/unit/javascript/position_caret/test_position_caret.py4
-rw-r--r--tests/unit/javascript/stylesheet/test_stylesheet.py8
-rw-r--r--tests/unit/javascript/test_greasemonkey.py53
-rw-r--r--tests/unit/javascript/test_js_execution.py2
-rw-r--r--tests/unit/keyinput/conftest.py2
-rw-r--r--tests/unit/keyinput/key_data.py2
-rw-r--r--tests/unit/keyinput/test_basekeyparser.py2
-rw-r--r--tests/unit/keyinput/test_keyutils.py4
-rw-r--r--tests/unit/keyinput/test_modeman.py2
-rw-r--r--tests/unit/keyinput/test_modeparsers.py2
-rw-r--r--tests/unit/mainwindow/statusbar/test_backforward.py2
-rw-r--r--tests/unit/mainwindow/statusbar/test_percentage.py2
-rw-r--r--tests/unit/mainwindow/statusbar/test_progress.py2
-rw-r--r--tests/unit/mainwindow/statusbar/test_tabindex.py2
-rw-r--r--tests/unit/mainwindow/statusbar/test_textbase.py4
-rw-r--r--tests/unit/mainwindow/statusbar/test_url.py2
-rw-r--r--tests/unit/mainwindow/test_messageview.py2
-rw-r--r--tests/unit/mainwindow/test_prompt.py2
-rw-r--r--tests/unit/mainwindow/test_tabwidget.py3
-rw-r--r--tests/unit/misc/test_autoupdate.py1
-rw-r--r--tests/unit/misc/test_checkpyver.py2
-rw-r--r--tests/unit/misc/test_cmdhistory.py2
-rw-r--r--tests/unit/misc/test_crashdialog.py2
-rw-r--r--tests/unit/misc/test_earlyinit.py2
-rw-r--r--tests/unit/misc/test_editor.py2
-rw-r--r--tests/unit/misc/test_guiprocess.py36
-rw-r--r--tests/unit/misc/test_ipc.py23
-rw-r--r--tests/unit/misc/test_keyhints.py3
-rw-r--r--tests/unit/misc/test_lineparser.py2
-rw-r--r--tests/unit/misc/test_miscwidgets.py2
-rw-r--r--tests/unit/misc/test_msgbox.py2
-rw-r--r--tests/unit/misc/test_objects.py2
-rw-r--r--tests/unit/misc/test_pastebin.py1
-rw-r--r--tests/unit/misc/test_readline.py2
-rw-r--r--tests/unit/misc/test_sessions.py2
-rw-r--r--tests/unit/misc/test_split.py2
-rw-r--r--tests/unit/misc/test_split_hypothesis.py2
-rw-r--r--tests/unit/misc/test_sql.py31
-rw-r--r--tests/unit/misc/test_utilcmds.py4
-rw-r--r--tests/unit/scripts/test_check_coverage.py2
-rw-r--r--tests/unit/scripts/test_dictcli.py1
-rw-r--r--tests/unit/scripts/test_importer.py2
-rw-r--r--tests/unit/scripts/test_run_vulture.py2
-rw-r--r--tests/unit/test_app.py4
-rw-r--r--tests/unit/utils/overflow_test_cases.py2
-rw-r--r--tests/unit/utils/test_debug.py2
-rw-r--r--tests/unit/utils/test_error.py2
-rw-r--r--tests/unit/utils/test_javascript.py2
-rw-r--r--tests/unit/utils/test_jinja.py2
-rw-r--r--tests/unit/utils/test_log.py2
-rw-r--r--tests/unit/utils/test_qtutils.py34
-rw-r--r--tests/unit/utils/test_standarddir.py2
-rw-r--r--tests/unit/utils/test_urlmatch.py2
-rw-r--r--tests/unit/utils/test_urlutils.py25
-rw-r--r--tests/unit/utils/test_utils.py2
-rw-r--r--tests/unit/utils/test_version.py62
-rw-r--r--tests/unit/utils/usertypes/test_misc.py2
-rw-r--r--tests/unit/utils/usertypes/test_neighborlist.py2
-rw-r--r--tests/unit/utils/usertypes/test_question.py2
-rw-r--r--tests/unit/utils/usertypes/test_timer.py2
-rw-r--r--tox.ini8
-rw-r--r--www/qute.css1
445 files changed, 3461 insertions, 1646 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
index 92a20c0bd..c42726fbe 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -5,15 +5,15 @@ cache:
build: off
environment:
PYTHONUNBUFFERED: 1
- PYTHON: C:\Python36-x64\python.exe
+ PYTHON: C:\Python37-x64\python.exe
matrix:
- - TESTENV: py36-pyqt511
- - TESTENV: pylint
+ - TESTENV: py37-pyqt512
+ # - TESTENV: pylint
install:
- '%PYTHON% -m pip install -U pip'
- '%PYTHON% -m pip install -r misc\requirements\requirements-tox.txt'
- - 'set PATH=C:\Python36-x64;%PATH'
+ - 'set PATH=C:\Python37-x64;%PATH'
test_script:
- '%PYTHON% -m tox -e %TESTENV%'
diff --git a/.flake8 b/.flake8
index 7a783a4b0..04c491bf2 100644
--- a/.flake8
+++ b/.flake8
@@ -46,12 +46,11 @@ ignore =
min-version = 3.4.0
max-complexity = 12
per-file-ignores =
- /qutebrowser/api/hook.py : N801
- /tests/**/*.py : D100,D101,D401
- /tests/unit/browser/test_history.py : N806
- /tests/helpers/fixtures.py : N806
- /tests/unit/browser/webkit/http/test_content_disposition.py : D400
- /scripts/dev/ci/appveyor_install.py : FI53
+ qutebrowser/api/hook.py : N801
+ tests/* : D100,D101
+ tests/unit/browser/test_history.py : D100,D101,N806
+ tests/helpers/fixtures.py : D100,D101,N806
+ tests/unit/browser/webkit/http/test_content_disposition.py : D100,D101,D400
copyright-check = True
copyright-regexp = # Copyright [\d-]+ .*
copyright-min-file-size = 110
diff --git a/.github/CONTRIBUTING.asciidoc b/.github/CONTRIBUTING.asciidoc
index d0fa243e9..bf9f0e66b 100644
--- a/.github/CONTRIBUTING.asciidoc
+++ b/.github/CONTRIBUTING.asciidoc
@@ -1,10 +1,6 @@
-IMPORTANT: *Currently, bigger changes are going on in qutebrowser, as
-part of a
-https://lists.schokokeks.org/pipermail/qutebrowser-announce/2018-September/000051.html[student research project]
-about adding a plugin API to qutebrowser and moving a lot of code from the code
-into plugins.* Due to that, bandwidth for pull request review is currently
-very limited, and contributions might lead to merge conflicts due to
-ongoing refactorings.
+IMPORTANT: Bandwidth for pull request review is currently quite limited. If you
+want to contribute where it's most needed, please consider reviewing or testing
+open pull requests.
- Before you start to work on something, please leave a comment on the relevant
issue (or open one). This makes sure there is no duplicate work done.
diff --git a/.github/ISSUE_TEMPLATE/1_Bug_report.md b/.github/ISSUE_TEMPLATE/1_Bug_report.md
index 56566849d..5e86b9a76 100644
--- a/.github/ISSUE_TEMPLATE/1_Bug_report.md
+++ b/.github/ISSUE_TEMPLATE/1_Bug_report.md
@@ -6,7 +6,7 @@ about: Report errors and problems
**Version info (see `:version`)**:
-**Does the bug happen if you start with `--temp-basedir`?** (if applicable):
+**Does the bug happen if you start with `--temp-basedir`?**:
**Description**
diff --git a/.github/ISSUE_TEMPLATE/3_Support_question.md b/.github/ISSUE_TEMPLATE/3_Support_question.md
index 76d0cffca..9d67d716b 100644
--- a/.github/ISSUE_TEMPLATE/3_Support_question.md
+++ b/.github/ISSUE_TEMPLATE/3_Support_question.md
@@ -10,3 +10,7 @@ ways to get help:
https://github.com/qutebrowser/qutebrowser#getting-help
-->
+
+**Version info (see `:version`)**:
+
+**If applicable: Does the issue happen if you start with `--temp-basedir`?**:
diff --git a/.pylintrc b/.pylintrc
index 445d2adcc..f4543fa1c 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -39,7 +39,8 @@ disable=locally-disabled,
too-many-locals,
too-many-branches,
too-many-statements,
- too-few-public-methods
+ too-few-public-methods,
+ bad-builtin
[BASIC]
function-rgx=[a-z_][a-z0-9_]{2,50}$
diff --git a/.travis.yml b/.travis.yml
index dfa566671..f0959d2a6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,55 +1,87 @@
dist: xenial
language: python
group: edge
-python: 3.6
+python: 3.7
os: linux
matrix:
+ fast_finish: true
include:
+ ### Archlinux QtWebKit
- env: DOCKER=archlinux
services: docker
+
+ ### Archlinux QtWebEngine
- env: DOCKER=archlinux-webengine QUTE_BDD_WEBENGINE=true
services: docker
- - env: TESTENV=py36-pyqt571
+
+ ### PyQt 5.7.1 (Python 3.5)
- python: 3.5
env: TESTENV=py35-pyqt571
- - env: TESTENV=py36-pyqt59
- - env: TESTENV=py36-pyqt510
+ ### PyQt 5.7.1 (Python 3.6)
+ - python: 3.6
+ env: TESTENV=py36-pyqt571
+
+ ### PyQt 5.9
+ - env: TESTENV=py37-pyqt59
+
+ ### PyQt 5.10
+ - env: TESTENV=py37-pyqt510
addons:
apt:
packages:
- xfonts-base
- - env: TESTENV=py36-pyqt511-cov
- - python: 3.7
- env: TESTENV=py37-pyqt511
+
+ ### PyQt 5.11
+ - env: TESTENV=py37-pyqt511
+
+ ### PyQt 5.12 (Python 3.7, with coverage)
+ - env: TESTENV=py37-pyqt512-cov
+ # http://code.qt.io/cgit/qt/qtbase.git/commit/?id=c3a963da1f9e7b1d37e63eedded61da4fbdaaf9a
+ addons:
+ apt:
+ packages:
+ - libxkbcommon-x11-0
+
+ ### macOS sierra
- os: osx
- env: TESTENV=py37 OSX=sierra
+ env: TESTENV=py37-pyqt512 OSX=sierra
osx_image: xcode9.2
language: generic
+ ### macOS yosemite
# https://github.com/qutebrowser/qutebrowser/issues/2013
# - os: osx
# env: TESTENV=py35 OSX=yosemite
# osx_image: xcode6.4
+
+ ### pylint/flake8/mypy
- env: TESTENV=pylint
- env: TESTENV=flake8
- env: TESTENV=mypy
+
+ ### docs
- env: TESTENV=docs
addons:
apt:
packages:
- asciidoc
+
+ ### vulture/misc/pyroma/check-manifest
- env: TESTENV=vulture
- env: TESTENV=misc
- env: TESTENV=pyroma
- env: TESTENV=check-manifest
+
+ ### eslint
- env: TESTENV=eslint
language: node_js
python: null
node_js: "lts/*"
+
+ ### shellcheck
- language: generic
env: TESTENV=shellcheck
services: docker
- fast_finish: true
cache:
directories:
diff --git a/MANIFEST.in b/MANIFEST.in
index cd9e50cf9..49b1a383b 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -12,8 +12,8 @@ recursive-include scripts *.py *.sh *.js
include qutebrowser/utils/testfile
include qutebrowser/git-commit-id
include LICENSE doc/* README.asciidoc
-include misc/qutebrowser.desktop
-include misc/qutebrowser.appdata.xml
+include misc/org.qutebrowser.qutebrowser.desktop
+include misc/org.qutebrowser.qutebrowser.appdata.xml
include misc/Makefile
include requirements.txt
include tox.ini
diff --git a/README.asciidoc b/README.asciidoc
index b2d882eae..d05f0b55c 100644
--- a/README.asciidoc
+++ b/README.asciidoc
@@ -97,7 +97,7 @@ Requirements
The following software and libraries are required to run qutebrowser:
* https://www.python.org/[Python] 3.5 or newer (3.6 recommended)
-* https://www.qt.io/[Qt] 5.7.1 or newer (5.11 recommended, support for < 5.9
+* https://www.qt.io/[Qt] 5.7.1 or newer (5.12 recommended, support for < 5.9
will be dropped soon) with the following modules:
- QtCore / qtbase
- QtQuick (part of qtbase in some distributions)
@@ -108,7 +108,7 @@ The following software and libraries are required to run qutebrowser:
only the link:https://github.com/annulen/webkit/wiki[updated fork] (5.212)
is supported
* https://www.riverbankcomputing.com/software/pyqt/intro[PyQt] 5.7.0 or newer
- (5.11 recommended, support for < 5.9 will be dropped soon) for Python 3
+ (5.12 recommended, support for < 5.9 will be dropped soon) for Python 3
* https://pypi.python.org/pypi/setuptools/[pkg_resources/setuptools]
* https://fdik.org/pyPEG/[pyPEG2]
* http://jinja.pocoo.org/[jinja2]
@@ -141,7 +141,8 @@ If you want to give me a beer or a pizza back, I'm trying to make it as easy as
possible for you to do so. If some other way would be easier for you, please
get in touch!
-* PayPal: me@the-compiler.org
+* SEPA bank transfer inside Europe (no fee): Contact me for details
+* PayPal: https://www.paypal.me/thecompiler[thecompiler] / me@the-compiler.org
* Bitcoin: link:bitcoin:1PMzbcetAHfpxoXww8Bj5XqquHtVvMjJtE[1PMzbcetAHfpxoXww8Bj5XqquHtVvMjJtE]
Sponsors
diff --git a/doc/changelog.asciidoc b/doc/changelog.asciidoc
index ceab9d043..81dbcda23 100644
--- a/doc/changelog.asciidoc
+++ b/doc/changelog.asciidoc
@@ -15,31 +15,181 @@ breaking changes (such as renamed commands) can happen in minor releases.
// `Fixed` for any bug fixes.
// `Security` to invite users to upgrade in case of vulnerabilities.
-v1.6.0 (unreleased)
+v1.7.0 (unreleased)
-------------------
Added
~~~~~
-- New `tabs.new_position.stacking` setting which controls whether new tabs
- opened from a page should stack on each other or not.
-- New `completion.open_categories` setting which allows to configure which
- categories are shown in the `:open` completion, and how they are ordered.
-- New `tabs.pinned.frozen` setting to allow/deny navigating in pinned tabs.
+- New settings:
+ * `colors.tabs.pinned.*` to control colors of pinned tabs.
+ * `hints.leave_on_load` which allows disabling leaving of hint mode when a
+ new page is loaded.
+ * `colors.completion.item.selected.match.fg` which allows configuring the
+ text color for the matching text in the currently selected completion item.
+ * `tabs.undo_stack_size` to limit how many undo entries are kept for closed tabs.
+- New commands:
+ * `:reverse-selection` (`o` in caret mode) to swap the stationary/moving ends
+ of a selection.
+- New commandline replacements:
+ * `{url:domain}`, `{url:auth}`, `{url:scheme}`, `{url:username}`,
+ `{url:password}`, `{url:host}`, `{url:port}`, `{url:path}`, `{url:query}`
+ for the respective parts of the current URL.
+ * `{title}` for the current page title.
+- The `{title}` field in `tabs.title.format`, `tabs.title.format_pinned` and
+ `window.title_format` got renamed to `{current_title}` (mirroring
+ `{current_url}`) in order to not conflict with the new `{title}` commandline
+ replacement.
+- New `delete` target for `:hint` which removes the hinted element from
+ the DOM.
+- Support for notifications (shown via system tray) with Qt 5.13.
+
+Changed
+~~~~~~~
+
+- The desktop file `qutebrowser.desktop` is now renamed to
+ `org.qutebrowser.qutebrowser.desktop`.
+- Pinned tabs now always show a favicon (even if the site doesn't provide one)
+ when shrinking.
+- Slight performance improvements for the `:open` completion.
+- Performance improvements for showing hints.
+- Setting `downloads.location.directory` now changes the directory displayed in
+ the download prompt even if `downloads.location.remember` is set.
+- The `yank` command gained a new `inline` argument, which allows to e.g. use
+ `:yank inline [{title}]({url})`.
+- Duplicate consecutive history entries with the same URL are now ignored.
+- More detailed error messages when spawning a process failed.
+- The `content.pdfjs` setting now supports domain patterns.
+- Improved process status output with `:spawn -o`.
+- Various performance improvements.
+- The `colors.tabs.bar.bg` setting is now of type `QssColor` and thus supports
+ gradients.
+- The `:fullscreen` command now understands a new `--enter` flag which
+ causes it to always enter fullscreen instead of toggling the current
+ state.
+- `--debug-flag stack` is now needed to show stack traces on renderer process
+ crashes.
+- For runtime data (such as the IPC socket), a proper runtime path is now used
+ on BSD; only macOS/Windows continue to use the temporary directory.
+- PDF.js is now also searched in `/app/share/pdf.js/` (for Flatpak)
+
+Deprecated
+~~~~~~~~~~
+
+- `:yank markdown` got deprecated, as `:yank inline [{title}]({url})` can now
+ be used instead.
+
+Fixed
+~~~~~
+
+- Various QtWebEngine load signals are now handled differently, which should
+ fix issues with insert mode being left while typing on sites like Google
+ Translate.
+- Race condition causing a colored statusbar in normal mode when
+ entering/exiting caret mode quickly.
+- Using `100%` for a hue in a `hsv(...)` config value now corresponds to 359
+ (rather than 255), matching the fixed behavior in Qt 5.13.
+- Chaining commands with ;; used to abort with some failing commands. It now
+ runs the second command no matter whether the first one succeeded or not.
+- Handling of profiles and private windows (and resulting crashes with Qt
+ 5.12.2).
+- Fixes for corner-cases when using :navigate increment/decrement.
+
+v1.6.3
+------
+
+Fixed
+~~~~~
+
+- Crash when hinting and changing/closing the tab before hints are displayed.
+- Crash on redirects with Qt 5.13.
+- Hide bogus `AA_ShareOpenGLContexts` warning with Qt 5.12.4.
+- Workaround for renderer process crashes with Qt 5.12.4.
+ If you're unable to update, you can remove `~/.cache/qutebrowser` for the
+ same result.
+
+v1.6.2
+------
+
+Changed
+~~~~~~~
+
+- Windows/macOS releases now ship with Qt 5.12.3, which includes security fixes
+ up to Chromium 73.0.3683.75.
+
+Fixed
+~~~~~
+
+- Crash when SQL errors occur while using the completion.
+- Crash when cancelling a download prompt started in an already closed window.
+- Crash when many prompts are opened at the same time.
+- Running without Qt installed now displays a proper error again.
+- High CPU usage when using the keyhint widget with a low delay.
+- Crash with Qt >= 5.14 on redirects.
+
+v1.6.1
+------
+
+Changed
+~~~~~~~
+
+- Windows/macOS releases now ship with Qt 5.12.2, which includes
+ security fixes up to Chromium 72.0.3626.121 (including CVE-2019-5786
+ which is known to be exploited in the wild).
+
+Fixed
+~~~~~
+
+- Crash when using `:config-{dict,list}-{add,remove}` with an invalid setting.
+- Functionality like hinting on pages with an element with ID `_qutebrowser` (such as qutebrowser.org) on Qt 5.12.
+- The .desktop file in v1.6.0 was missing the "Actions" key, which is now fixed.
+- The SVG icon now has a size of 256x256px set to comply with freedesktop standards.
+- Setting `colors.statusbar.*.bg` to a gradient now has the expected effect of
+ the gradient spanning the entire statusbar.
+
+v1.6.0
+------
+
+Added
+~~~~~
+
+- New settings:
+ * `tabs.new_position.stacking` which controls whether new tabs opened from a
+ page should stack on each other or not.
+ * `completion.open_categories` which allows to configure which categories are
+ shown in the `:open` completion, and how they are ordered.
+ * `tabs.pinned.frozen` to allow/deny navigating in pinned tabs.
+ * `hints.selectors` which allows to configure what CSS selectors are used for
+ hints, and also allows adding custom hint groups.
+ * `input.insert_mode.leave_on_load` to turn off leaving insert mode when a
+ new page is loaded.
- New config manipulation commands:
* `:config-dict-add` and `:config-list-add` to a new element to a dict/list
setting.
* `:config-dict-remove` and `:config-list-remove` to remove an element from a
dict/list setting.
-- New `hints.selectors` setting which allows to configure what CSS selectors
- are used for hints, and also allows adding custom hint groups.
- New `:yank markdown` feature which yanks the current URL and title in
markdown format.
+- Support for new QtWebEngine features in Qt 5.12:
+ * Basic support for client certificates. Selecting the certificate to use
+ when there are multiple matching certificates isn't implemented yet.
+ * Support for DNS prefetching (plus new `content.dns_prefetch` setting).
Changed
~~~~~~~
-- `:q` now closes current window instead of quitting qutebrowser completely
+- Various changes to the Windows and macOS builds:
+ * Bundling Qt 5.12.1, based on Chromium 69.0.3497.128 with security fixes up
+ to 71.0.3578.94.
+ * Windows: A 32-bit build is available again.
+ * Windows: The builds now bundle the Universal CRT DLLs, causing them to work
+ on earlier versions of Windows 10.
+ * macOS: Support for OS X 10.11 El Capitan was dropped, requiring macOS 10.12
+ Sierra or newer.
+ * macOS: The IPC socket path used to communicate with existing instances
+ changed due to changes in Qt 5.12. Please make sure to quit qutebrowser
+ before upgrading.
+- `:q` now closes the current window instead of quitting qutebrowser completely
(`:close`), while `:qa` quits (`:quit`). The behavior of `:wq` remains
unchanged (`:quit --save`), as closing a window while saving the session
doesn't make sense.
@@ -54,6 +204,18 @@ Changed
- Various small performance improvements for hints and the completion.
- The Wayland check for QtWebEngine is now disabled on Qt >= 5.11.2, as those
versions should work without any issues.
+- The JavaScript `console` object is now available in PAC files.
+- PAC proxies currently don't work properly on QtWebEngine (and never did), so
+ an error is now shown when trying to configure a PAC proxy.
+- The metainfo file `qutebrowser.appdata.xml` is now renamed to
+ `org.qutebrowser.qutebrowser.appdata.xml`.
+- The `qute-pass` userscript now understands domains in gpg filenames
+ in addition to directory names.
+- The autocompletion for `content.headers.user_agent` got updated to only
+ include the default and Chrome, as setting the UA to Firefox has various
+ bad side-effects.
+- Combining Qt 5.12 with an older PyQt can lead to issues, so a warning is
+ now shown when starting qutebrowser with that combination.
Fixed
~~~~~
@@ -68,12 +230,28 @@ Fixed
`content.cookies.accept = no-3rdparty` from working properly on some pages
like GMail. However, the default for `content.cookies.accept` is still `all`
to be in line with what other browsers do.
-- `:navigate` not incrementing in anchors or queries or anchors.
+- `:navigate` not incrementing in anchors or queries.
- Crash when trying to use a proxy requiring authentication with QtWebKit.
- Slashes in search terms are now percent-escaped.
- When `scrolling.bar = True` was set in versions before v1.5.0, this now
correctly gets migrated to `always` instead of `when-searching`.
- Completion highlighting now works again on Qt 5.11.3 and 5.12.1.
+- The non-standard header `X-Do-Not-Track` is no longer sent.
+- PAC proxies were never correctly supported with QtWebEngine, but are now
+ explicitly disallowed.
+- macOS: Context menus for download items now show in the correct macOS style.
+- Issues with fullscreen handling when exiting a video player.
+- Various fixes for Qt 5.12 issues:
+ * A javascript error on page load was fixed.
+ * `window.print()` works with Qt 5.12 now.
+ * Fixed handling of duplicate download filenames.
+ * Fixed broken `qute://history` page.
+ * Fixed PDF.js not working properly.
+ * The download button in PDF.js now works (it's not possible to make
+ it work with earlier Qt versions).
+ * Since Greasemonkey scripts modifying the DOM fail when being run at
+ document-start, some known-broken scripts (Iridium, userstyles.org) are now
+ forced to run at document-end.
v1.5.2
------
@@ -373,11 +551,11 @@ v1.3.3
Security
~~~~~~~~
-- An XSS vulnerability on the `qute://history` page allowed websites to inject
- HTML into the page via a crafted title tag. This could allow them to steal
- your browsing history. If you're currently unable to upgrade, avoid using
- `:history`. A CVE request for this issue is pending, see
- https://github.com/qutebrowser/qutebrowser/issues/4011[#4011] for updates.
+- CVE-2018-1000559: An XSS vulnerability on the `qute://history` page allowed
+ websites to inject HTML into the page via a crafted title tag. This could
+ allow them to steal your browsing history. If you're currently unable to
+ upgrade, avoid using `:history`. See the related GitHub issue for details:
+ https://github.com/qutebrowser/qutebrowser/issues/4011.
Fixed
~~~~~
diff --git a/doc/contributing.asciidoc b/doc/contributing.asciidoc
index dc52dd9a0..6fe6fb740 100644
--- a/doc/contributing.asciidoc
+++ b/doc/contributing.asciidoc
@@ -5,13 +5,9 @@ The Compiler <mail@qutebrowser.org>
:data-uri:
:toc:
-IMPORTANT: *Currently, bigger changes are going on in qutebrowser, as
-part of a
-https://lists.schokokeks.org/pipermail/qutebrowser-announce/2018-September/000051.html[student research project]
-about adding a plugin API to qutebrowser and moving a lot of code from the code
-into plugins.* Due to that, bandwidth for pull request review is currently
-very limited, and contributions might lead to merge conflicts due to
-ongoing refactorings.
+IMPORTANT: Bandwidth for pull request review is currently quite limited. If you
+want to contribute where it's most needed, please consider reviewing or testing
+open pull requests.
I `&lt;3` footnote:[Of course, that says `<3` in HTML.] contributors!
@@ -222,7 +218,7 @@ Some resources which might be handy:
* http://doc.qt.io/qt-5/classes.html[The Qt5 reference]
* https://docs.python.org/3/library/index.html[The Python reference]
* http://httpbin.org/[httpbin, a test service for HTTP requests/responses]
-* http://requestb.in/[RequestBin, a service to inspect HTTP requests]
+* https://requestbin.com/[RequestBin, a service to inspect HTTP requests]
Documentation of used Python libraries:
@@ -608,7 +604,7 @@ Style conventions
-----------------
qutebrowser's coding conventions are based on
-http://legacy.python.org/dev/peps/pep-0008/[PEP8] and the https://google-styleguide.googlecode.com/svn/trunk/pyguide.html[Google Python style guidelines] with some additions:
+http://legacy.python.org/dev/peps/pep-0008/[PEP8] and the https://google.github.io/styleguide/pyguide.html[Google Python style guidelines] with some additions:
* The _Raise:_ section is not added to the docstring.
* Methods overriding Qt methods (obviously!) don't follow the naming schemes.
@@ -710,6 +706,7 @@ qutebrowser release
* Update changelog (remove *(unreleased)*).
* Adjust `__version_info__` in `qutebrowser/__init__.py`.
+* Consider updating the completions for `content.headers.user_agent` in `configdata.yml`.
* Commit.
* Create annotated git tag (`git tag -s "v1.$x.$y" -m "Release v1.$x.$y"`).
@@ -723,7 +720,7 @@ as closed.
* Windows: Run `git checkout v1.X.Y; py -3 scripts\dev\build_release.py --asciidoc C:\Python27\python %userprofile%\bin\asciidoc-8.6.10\asciidoc.py --upload v1.X.Y` (replace X/Y by hand).
* macOS: Run `git checkout v1.X.Y && python3 scripts/dev/build_release.py --upload v1.X.Y` (replace X/Y by hand).
* On server:
- - Run `python3 scripts/dev/download_release.py v1.X.Y` (replace X/Y by hand).
+ - Run `bash download_release.sh 1.X.Y` (replace X/Y by hand).
- Run `git pull github master && sudo python3 scripts/asciidoc2html.py --website /srv/http/qutebrowser`
* Update `qutebrowser-git` PKGBUILD if dependencies/install changed.
* Announce to qutebrowser and qutebrowser-announce mailinglist.
diff --git a/doc/extapi/conf.py b/doc/extapi/conf.py
index 4cc5c6803..aba5e93af 100644
--- a/doc/extapi/conf.py
+++ b/doc/extapi/conf.py
@@ -20,7 +20,7 @@
# -- Project information -----------------------------------------------------
project = 'qutebrowser extensions'
-copyright = '2018, Florian Bruhin'
+copyright = '2018-2019, Florian Bruhin'
author = 'Florian Bruhin'
# The short X.Y version
diff --git a/doc/faq.asciidoc b/doc/faq.asciidoc
index 113a11f09..a044cdfb5 100644
--- a/doc/faq.asciidoc
+++ b/doc/faq.asciidoc
@@ -154,7 +154,7 @@ How do I use qutebrowser with mutt?::
extension:
+
----
- text/html; qutebrowser %s; nametemplate=%s.html
+ text/html; qutebrowser %s; needsterminal; nametemplate=%s.html
----
What is the difference between bookmarks and quickmarks?::
@@ -211,9 +211,10 @@ Why does J move to the next (right) tab, and K to the previous (left) one?::
What's the difference between insert and passthrough mode?::
They are quite similar, but insert mode has some bindings (like `Ctrl-e` to
- open an editor) while passthrough mode only has escape bound. It might also
- be useful to rebind escape to something else in passthrough mode only, to be
- able to send an escape keypress to the website.
+ open an editor) while passthrough mode only has shift+escape bound. This is
+ because shift+escape is unlikely to be a useful binding to be passed to a
+ webpage. However, any other keys may be assigned to leaving passthrough mode
+ instead of shift+escape should this be desired.
Why does it take longer to open a URL in qutebrowser than in chromium?::
When opening a URL in an existing instance, the normal qutebrowser
@@ -225,9 +226,7 @@ Why does it take longer to open a URL in qutebrowser than in chromium?::
and place it in your $PATH with the name "qutebrowser". This
script passes the URL via an unix socket to qutebrowser (if its
running already) using socat which is much faster and starts a new
- qutebrowser if it is not running already. Also check if you want
- to use webengine as backend in line 17 and change it to your
- needs.
+ qutebrowser if it is not running already.
How do I make qutebrowser use greasemonkey scripts?::
There is currently no UI elements to handle managing greasemonkey scripts.
@@ -298,15 +297,10 @@ Unable to view DRM content (Netflix, Spotify, etc.).::
You will need to install `widevine` and set `qt.args` to point to it.
Qt 5.9 currently only supports widevine up to Chrome version 61.
+
-On Arch, simply install `qt5-webengine-widevine` from the AUR and run:
-+
-----
-:set qt.args '["ppapi-widevine-path=/usr/lib/qt/plugins/ppapi/libwidevinecdmadapter.so"]'
-:restart
-----
+On Arch, simply install `chromium-widevine` from the AUR.
+
For other distributions, download the chromium tarball and widevine-cdm zip from
-https://aur.archlinux.org/packages/qt5-webengine-widevine/[the AUR page],
+https://aur.archlinux.org/packages/chromium-widevine/[the AUR page],
extract `libwidevinecdmadapter.so` and `libwidevinecdm.so` files, respectively,
and move them to the `ppapi` plugin directory in your Qt library directory (create it if it does not exist).
+
diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc
index 2d71a28c1..ae9ada9fd 100644
--- a/doc/help/commands.asciidoc
+++ b/doc/help/commands.asciidoc
@@ -14,11 +14,15 @@ For command arguments, there are also some variables you can use:
- `{url}` expands to the URL of the current page
- `{url:pretty}` expands to the URL in decoded format
-- `{url:host}` expands to the host part of the URL
+- `{url:host}`, `{url:domain}`, `{url:auth}`, `{url:scheme}`, `{url:username}`,
+ `{url:password}`, `{url:host}`, `{url:port}`, `{url:path}` and `{url:query}`
+ expand to the respective parts of the current URL
+- `{title}` expands to the current page's title
- `{clipboard}` expands to the clipboard contents
- `{primary}` expands to the primary selection contents
-It is possible to run or bind multiple commands by separating them with `;;`.
+Those variables can be escaped by doubling the braces, e.g. `{{url}}`. It is
+possible to run or bind multiple commands by separating them with `;;`.
== Normal commands
.Quick reference
@@ -126,7 +130,7 @@ It is possible to run or bind multiple commands by separating them with `;;`.
|<<version,version>>|Show version information.
|<<view-source,view-source>>|Show the source of the current page in a new tab.
|<<window-only,window-only>>|Close all windows except for the current one.
-|<<yank,yank>>|Yank something to the clipboard or primary selection.
+|<<yank,yank>>|Yank (copy) something to the clipboard or primary selection.
|<<zoom,zoom>>|Set the zoom level for the current tab.
|<<zoom-in,zoom-in>>|Increase the zoom level for the current tab.
|<<zoom-out,zoom-out>>|Decrease the zoom level for the current tab.
@@ -165,8 +169,7 @@ If no command is given, show the current binding for the given key. Using :bind
* +'command'+: The command to execute, with optional args.
==== optional arguments
-* +*-m*+, +*--mode*+: A comma-separated list of modes to bind the key in (default: `normal`). See `:help bindings.commands` for the
- available modes.
+* +*-m*+, +*--mode*+: The mode to bind the key in (default: `normal`). See `:help bindings.commands` for the available modes.
* +*-d*+, +*--default*+: If given, restore a default binding.
@@ -510,7 +513,9 @@ Syntax: +:enter-mode 'mode'+
Enter a key mode.
==== positional arguments
-* +'mode'+: The mode to enter.
+* +'mode'+: The mode to enter. See `:help bindings.commands` for the available modes, but note that hint/command/yesno/prompt mode
+ can't be entered manually.
+
[[fake-key]]
=== fake-key
@@ -551,12 +556,14 @@ How many pages to go forward.
[[fullscreen]]
=== fullscreen
-Syntax: +:fullscreen [*--leave*]+
+Syntax: +:fullscreen [*--leave*] [*--enter*]+
Toggle fullscreen mode.
==== optional arguments
* +*-l*+, +*--leave*+: Only leave fullscreen if it was entered by the page.
+* +*-e*+, +*--enter*+: Activate fullscreen and do not toggle if it is already active.
+
[[greasemonkey-reload]]
=== greasemonkey-reload
@@ -614,7 +621,7 @@ Start hinting.
- `normal`: Open the link.
- `current`: Open the link in the current tab.
- `tab`: Open the link in a new tab (honoring the
- `tabs.background_tabs` setting).
+ `tabs.background` setting).
- `tab-fg`: Open the link in a new foreground tab.
- `tab-bg`: Open the link in a new background tab.
- `window`: Open the link in a new window.
@@ -628,6 +635,7 @@ Start hinting.
- `userscript`: Call a userscript with `$QUTE_URL` set to the
link.
- `spawn`: Spawn a command.
+ - `delete`: Delete the selected element.
@@ -661,7 +669,7 @@ Start hinting.
* +*-r*+, +*--rapid*+: Whether to do rapid hinting. With rapid hinting, the hint mode isn't left after a hint is followed, so you can easily
open multiple links. This is only possible with targets
- `tab` (with `tabs.background_tabs=true`), `tab-bg`,
+ `tab` (with `tabs.background=true`), `tab-bg`,
`window`, `run`, `hover`, `userscript` and `spawn`.
* +*-f*+, +*--first*+: Click the first hinted element without prompting.
@@ -1425,7 +1433,7 @@ Unbind a keychain.
==== optional arguments
-* +*-m*+, +*--mode*+: A mode to unbind the key in (default: `normal`). See `:help bindings.commands` for the available modes.
+* +*-m*+, +*--mode*+: The mode to unbind the key in (default: `normal`). See `:help bindings.commands` for the available modes.
[[undo]]
@@ -1460,9 +1468,9 @@ Close all windows except for the current one.
[[yank]]
=== yank
-Syntax: +:yank [*--sel*] [*--keep*] [*--quiet*] ['what']+
+Syntax: +:yank [*--sel*] [*--keep*] [*--quiet*] ['what'] ['inline']+
-Yank something to the clipboard or primary selection.
+Yank (copy) something to the clipboard or primary selection.
==== positional arguments
* +'what'+: What to yank.
@@ -1472,10 +1480,14 @@ Yank something to the clipboard or primary selection.
- `title`: The current page's title.
- `domain`: The current scheme, domain, and port number.
- `selection`: The selection under the cursor.
- - `markdown`: Yank title and URL in markdown format.
+ - `markdown`: Yank title and URL in markdown format
+ (deprecated, use `:yank inline [{title}]({url})` instead).
+ - `inline`: Yank the text contained in the 'inline' argument.
+* +'inline'+: A block of text, to be yanked if 'what' is inline and ignored otherwise.
+
==== optional arguments
* +*-s*+, +*--sel*+: Use the primary selection instead of the clipboard.
@@ -1557,6 +1569,7 @@ How many steps to zoom out.
|<<prompt-item-focus,prompt-item-focus>>|Shift the focus of the prompt file completion menu to another item.
|<<prompt-open-download,prompt-open-download>>|Immediately open a download.
|<<prompt-yank,prompt-yank>>|Yank URL to clipboard or primary selection.
+|<<reverse-selection,reverse-selection>>|Swap the stationary and moving end of the current selection.
|<<rl-backward-char,rl-backward-char>>|Move back a character.
|<<rl-backward-delete-char,rl-backward-delete-char>>|Delete the character before the cursor.
|<<rl-backward-kill-word,rl-backward-kill-word>>|Remove chars from the cursor to the beginning of the word.
@@ -1777,6 +1790,10 @@ Yank URL to clipboard or primary selection.
==== optional arguments
* +*-s*+, +*--sel*+: Use the primary selection instead of the clipboard.
+[[reverse-selection]]
+=== reverse-selection
+Swap the stationary and moving end of the current selection.
+
[[rl-backward-char]]
=== rl-backward-char
Move back a character.
diff --git a/doc/help/configuring.asciidoc b/doc/help/configuring.asciidoc
index b04c9e9df..b95511245 100644
--- a/doc/help/configuring.asciidoc
+++ b/doc/help/configuring.asciidoc
@@ -89,7 +89,7 @@ You can run `:config-edit` inside qutebrowser to open the file in your editor,
The file should be located in the "config" location listed on
link:qute://version[], which is typically `~/.config/qutebrowser/config.py` on
Linux, `~/.qutebrowser/config.py` on macOS, and
-`%APPDATA%/qutebrowser/config.py` on Windows.
+`%APPDATA%/qutebrowser/config/config.py` on Windows.
Two global objects are pre-defined when running `config.py`: `c` and `config`.
@@ -309,7 +309,7 @@ You can use:
import yaml
with (config.configdir / 'config.yml').open() as f:
- yaml_data = yaml.load(f)
+ yaml_data = yaml.safe_load(f)
for k, v in yaml_data.items():
config.set(k, v)
@@ -339,7 +339,7 @@ You can use:
import yaml
with (config.configdir / 'colors.yml').open() as f:
- yaml_data = yaml.load(f)
+ yaml_data = yaml.safe_load(f)
def dict_attrs(obj, path=''):
if isinstance(obj, dict):
diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc
index eb3907cce..550e398b0 100644
--- a/doc/help/settings.asciidoc
+++ b/doc/help/settings.asciidoc
@@ -25,8 +25,9 @@
|<<colors.completion.fg,colors.completion.fg>>|Text color of the completion widget.
|<<colors.completion.item.selected.bg,colors.completion.item.selected.bg>>|Background color of the selected completion item.
|<<colors.completion.item.selected.border.bottom,colors.completion.item.selected.border.bottom>>|Bottom border color of the selected completion item.
-|<<colors.completion.item.selected.border.top,colors.completion.item.selected.border.top>>|Top border color of the completion widget category headers.
+|<<colors.completion.item.selected.border.top,colors.completion.item.selected.border.top>>|Top border color of the selected completion item.
|<<colors.completion.item.selected.fg,colors.completion.item.selected.fg>>|Foreground color of the selected completion item.
+|<<colors.completion.item.selected.match.fg,colors.completion.item.selected.match.fg>>|Foreground color of the matched text in the selected completion item.
|<<colors.completion.match.fg,colors.completion.match.fg>>|Foreground color of the matched text in the completion.
|<<colors.completion.odd.bg,colors.completion.odd.bg>>|Background color of the completion widget for odd rows.
|<<colors.completion.scrollbar.bg,colors.completion.scrollbar.bg>>|Color of the scrollbar in the completion view.
@@ -91,6 +92,14 @@
|<<colors.tabs.indicator.system,colors.tabs.indicator.system>>|Color gradient interpolation system for the tab indicator.
|<<colors.tabs.odd.bg,colors.tabs.odd.bg>>|Background color of unselected odd tabs.
|<<colors.tabs.odd.fg,colors.tabs.odd.fg>>|Foreground color of unselected odd tabs.
+|<<colors.tabs.pinned.even.bg,colors.tabs.pinned.even.bg>>|Background color of pinned unselected even tabs.
+|<<colors.tabs.pinned.even.fg,colors.tabs.pinned.even.fg>>|Foreground color of pinned unselected even tabs.
+|<<colors.tabs.pinned.odd.bg,colors.tabs.pinned.odd.bg>>|Background color of pinned unselected odd tabs.
+|<<colors.tabs.pinned.odd.fg,colors.tabs.pinned.odd.fg>>|Foreground color of pinned unselected odd tabs.
+|<<colors.tabs.pinned.selected.even.bg,colors.tabs.pinned.selected.even.bg>>|Background color of pinned selected even tabs.
+|<<colors.tabs.pinned.selected.even.fg,colors.tabs.pinned.selected.even.fg>>|Foreground color of pinned selected even tabs.
+|<<colors.tabs.pinned.selected.odd.bg,colors.tabs.pinned.selected.odd.bg>>|Background color of pinned selected odd tabs.
+|<<colors.tabs.pinned.selected.odd.fg,colors.tabs.pinned.selected.odd.fg>>|Foreground color of pinned selected odd tabs.
|<<colors.tabs.selected.even.bg,colors.tabs.selected.even.bg>>|Background color of selected even tabs.
|<<colors.tabs.selected.even.fg,colors.tabs.selected.even.fg>>|Foreground color of selected even tabs.
|<<colors.tabs.selected.odd.bg,colors.tabs.selected.odd.bg>>|Background color of selected odd tabs.
@@ -202,6 +211,7 @@
|<<hints.dictionary,hints.dictionary>>|Dictionary file to be used by the word hints.
|<<hints.find_implementation,hints.find_implementation>>|Which implementation to use to find elements to hint.
|<<hints.hide_unmatched_rapid_hints,hints.hide_unmatched_rapid_hints>>|Hide unmatched hints in rapid mode.
+|<<hints.leave_on_load,hints.leave_on_load>>|Leave hint mode when starting a new page load.
|<<hints.min_chars,hints.min_chars>>|Minimum number of characters used for hint strings.
|<<hints.mode,hints.mode>>|Mode to use for hints.
|<<hints.next_regexes,hints.next_regexes>>|Comma-separated list of regular expressions to use for 'next' links.
@@ -215,6 +225,7 @@
|<<input.insert_mode.auto_enter,input.insert_mode.auto_enter>>|Enter insert mode if an editable element is clicked.
|<<input.insert_mode.auto_leave,input.insert_mode.auto_leave>>|Leave insert mode if a non-editable element is clicked.
|<<input.insert_mode.auto_load,input.insert_mode.auto_load>>|Automatically enter insert mode if an editable element is focused after loading the page.
+|<<input.insert_mode.leave_on_load,input.insert_mode.leave_on_load>>|Leave insert mode when starting a new page load.
|<<input.insert_mode.plugins,input.insert_mode.plugins>>|Switch to insert mode when clicking flash and other plugins.
|<<input.links_included_in_focus_chain,input.links_included_in_focus_chain>>|Include hyperlinks in the keyboard focus chain when tabbing.
|<<input.partial_timeout,input.partial_timeout>>|Timeout (in milliseconds) for partially typed key bindings.
@@ -271,6 +282,7 @@
|<<tabs.title.alignment,tabs.title.alignment>>|Alignment of the text inside of tabs.
|<<tabs.title.format,tabs.title.format>>|Format to use for the tab title.
|<<tabs.title.format_pinned,tabs.title.format_pinned>>|Format to use for the tab title for pinned tabs. The same placeholders like for `tabs.title.format` are defined.
+|<<tabs.undo_stack_size,tabs.undo_stack_size>>|Number of close tab actions to remember, per window (-1 for no maximum).
|<<tabs.width,tabs.width>>|Width (in pixels or as percentage of the window) of the tab bar if it's vertical.
|<<tabs.wrap,tabs.wrap>>|Wrap when changing tabs.
|<<url.auto_search,url.auto_search>>|What search to start when something else than a URL is entered.
@@ -427,6 +439,7 @@ Default:
* +pass:[j]+: +pass:[move-to-next-line]+
* +pass:[k]+: +pass:[move-to-prev-line]+
* +pass:[l]+: +pass:[move-to-next-char]+
+* +pass:[o]+: +pass:[reverse-selection]+
* +pass:[v]+: +pass:[toggle-selection]+
* +pass:[w]+: +pass:[move-to-next-word]+
* +pass:[y]+: +pass:[yank selection]+
@@ -641,12 +654,12 @@ Default:
* +pass:[xO]+: +pass:[set-cmd-text :open -b -r {url:pretty}]+
* +pass:[xo]+: +pass:[set-cmd-text -s :open -b]+
* +pass:[yD]+: +pass:[yank domain -s]+
-* +pass:[yM]+: +pass:[yank markdown -s]+
+* +pass:[yM]+: +pass:[yank inline [{title}]({url}) -s]+
* +pass:[yP]+: +pass:[yank pretty-url -s]+
* +pass:[yT]+: +pass:[yank title -s]+
* +pass:[yY]+: +pass:[yank -s]+
* +pass:[yd]+: +pass:[yank domain]+
-* +pass:[ym]+: +pass:[yank markdown]+
+* +pass:[ym]+: +pass:[yank inline [{title}]({url})]+
* +pass:[yp]+: +pass:[yank pretty-url]+
* +pass:[yt]+: +pass:[yank title]+
* +pass:[yy]+: +pass:[yank]+
@@ -784,7 +797,7 @@ Default: +pass:[#bbbb00]+
[[colors.completion.item.selected.border.top]]
=== colors.completion.item.selected.border.top
-Top border color of the completion widget category headers.
+Top border color of the selected completion item.
Type: <<types,QssColor>>
@@ -798,6 +811,14 @@ Type: <<types,QtColor>>
Default: +pass:[black]+
+[[colors.completion.item.selected.match.fg]]
+=== colors.completion.item.selected.match.fg
+Foreground color of the matched text in the selected completion item.
+
+Type: <<types,QtColor>>
+
+Default: +pass:[#ff4444]+
+
[[colors.completion.match.fg]]
=== colors.completion.match.fg
Foreground color of the matched text in the completion.
@@ -1257,7 +1278,7 @@ Default: +pass:[yellow]+
=== colors.tabs.bar.bg
Background color of the tab bar.
-Type: <<types,QtColor>>
+Type: <<types,QssColor>>
Default: +pass:[#555555]+
@@ -1332,6 +1353,70 @@ Type: <<types,QtColor>>
Default: +pass:[white]+
+[[colors.tabs.pinned.even.bg]]
+=== colors.tabs.pinned.even.bg
+Background color of pinned unselected even tabs.
+
+Type: <<types,QtColor>>
+
+Default: +pass:[darkseagreen]+
+
+[[colors.tabs.pinned.even.fg]]
+=== colors.tabs.pinned.even.fg
+Foreground color of pinned unselected even tabs.
+
+Type: <<types,QtColor>>
+
+Default: +pass:[white]+
+
+[[colors.tabs.pinned.odd.bg]]
+=== colors.tabs.pinned.odd.bg
+Background color of pinned unselected odd tabs.
+
+Type: <<types,QtColor>>
+
+Default: +pass:[seagreen]+
+
+[[colors.tabs.pinned.odd.fg]]
+=== colors.tabs.pinned.odd.fg
+Foreground color of pinned unselected odd tabs.
+
+Type: <<types,QtColor>>
+
+Default: +pass:[white]+
+
+[[colors.tabs.pinned.selected.even.bg]]
+=== colors.tabs.pinned.selected.even.bg
+Background color of pinned selected even tabs.
+
+Type: <<types,QtColor>>
+
+Default: +pass:[black]+
+
+[[colors.tabs.pinned.selected.even.fg]]
+=== colors.tabs.pinned.selected.even.fg
+Foreground color of pinned selected even tabs.
+
+Type: <<types,QtColor>>
+
+Default: +pass:[white]+
+
+[[colors.tabs.pinned.selected.odd.bg]]
+=== colors.tabs.pinned.selected.odd.bg
+Background color of pinned selected odd tabs.
+
+Type: <<types,QtColor>>
+
+Default: +pass:[black]+
+
+[[colors.tabs.pinned.selected.odd.fg]]
+=== colors.tabs.pinned.selected.odd.fg
+Foreground color of pinned selected odd tabs.
+
+Type: <<types,QtColor>>
+
+Default: +pass:[white]+
+
[[colors.tabs.selected.even.bg]]
=== colors.tabs.selected.even.bg
Background color of selected even tabs.
@@ -1474,8 +1559,9 @@ Default: +pass:[false]+
[[completion.timestamp_format]]
=== completion.timestamp_format
Format of timestamps (e.g. for the history completion).
+See https://sqlite.org/lang_datefunc.html for allowed substitutions.
-Type: <<types,TimestampTemplate>>
+Type: <<types,String>>
Default: +pass:[%Y-%m-%d]+
@@ -1647,7 +1733,7 @@ Type: <<types,Bool>>
Default: +pass:[true]+
-This setting is only available with the QtWebKit backend.
+On QtWebEngine, this setting requires Qt 5.12 or newer.
[[content.frame_flattening]]
=== content.frame_flattening
@@ -1989,13 +2075,15 @@ Valid values:
Default: +pass:[ask]+
-This setting is only available with the QtWebKit backend.
+On QtWebEngine, this setting requires Qt 5.13 or newer.
[[content.pdfjs]]
=== content.pdfjs
Allow pdf.js to view PDF files in the browser.
Note that the files can still be downloaded by clicking the download button in the pdf.js viewer.
+This setting supports URL patterns.
+
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -2518,6 +2606,14 @@ Type: <<types,Bool>>
Default: +pass:[true]+
+[[hints.leave_on_load]]
+=== hints.leave_on_load
+Leave hint mode when starting a new page load.
+
+Type: <<types,Bool>>
+
+Default: +pass:[true]+
+
[[hints.min_chars]]
=== hints.min_chars
Minimum number of characters used for hint strings.
@@ -2711,6 +2807,17 @@ Type: <<types,Bool>>
Default: +pass:[false]+
+[[input.insert_mode.leave_on_load]]
+=== input.insert_mode.leave_on_load
+Leave insert mode when starting a new page load.
+Patterns may be unreliable on this setting, and they may match the url you are navigating to, or the URL you are navigating from.
+
+This setting supports URL patterns.
+
+Type: <<types,Bool>>
+
+Default: +pass:[true]+
+
[[input.insert_mode.plugins]]
=== input.insert_mode.plugins
Switch to insert mode when clicking flash and other plugins.
@@ -2813,7 +2920,7 @@ Default: +pass:[tab]+
[[new_instance_open_target_window]]
=== new_instance_open_target_window
Which window to choose when opening links as new tabs.
-When `new_instance_open_target` is not set to `window`, this is ignored.
+When `new_instance_open_target` is set to `window`, this is ignored.
Type: <<types,String>>
@@ -3405,7 +3512,7 @@ The following placeholders are defined:
* `{perc}`: Percentage as a string like `[10%]`.
* `{perc_raw}`: Raw percentage, e.g. `10`.
-* `{title}`: Title of the current web page.
+* `{current_title}`: Title of the current web page.
* `{title_sep}`: The string ` - ` if a title is set, empty otherwise.
* `{index}`: Index of this tab.
* `{id}`: Internal tab ID of this tab.
@@ -3420,7 +3527,7 @@ The following placeholders are defined:
Type: <<types,FormatString>>
-Default: +pass:[{audio}{index}: {title}]+
+Default: +pass:[{audio}{index}: {current_title}]+
[[tabs.title.format_pinned]]
=== tabs.title.format_pinned
@@ -3430,6 +3537,14 @@ Type: <<types,FormatString>>
Default: +pass:[{index}]+
+[[tabs.undo_stack_size]]
+=== tabs.undo_stack_size
+Number of close tab actions to remember, per window (-1 for no maximum).
+
+Type: <<types,Int>>
+
+Default: +pass:[100]+
+
[[tabs.width]]
=== tabs.width
Width (in pixels or as percentage of the window) of the tab bar if it's vertical.
@@ -3550,7 +3665,7 @@ Format to use for the window title. The same placeholders like for
Type: <<types,FormatString>>
-Default: +pass:[{perc}{title}{title_sep}qutebrowser]+
+Default: +pass:[{perc}{current_title}{title_sep}qutebrowser]+
[[zoom.default]]
=== zoom.default
@@ -3668,9 +3783,6 @@ See the documentation for `List`.
See the setting's valid values for more information on allowed values.
|TextAlignment|Alignment of text.
-|TimestampTemplate|An strftime-like template for timestamps.
-
-See https://sqlite.org/lang_datefunc.html for reference.
|UniqueCharString|A string which may not contain duplicate chars.
|Url|A URL as a string.
|UrlPattern|A match pattern for a URL.
diff --git a/doc/install.asciidoc b/doc/install.asciidoc
index c9ae54cd2..f4391b9f9 100644
--- a/doc/install.asciidoc
+++ b/doc/install.asciidoc
@@ -420,8 +420,8 @@ $ tox -e mkvenv-pypi
This installs all needed Python dependencies in a `.venv` subfolder.
-This comes with an up-to-date Qt/PyQt including QtWebEngine, but has a few
-caveats:
+This comes with an up-to-date Qt/PyQt including a pre-compiled QtWebEngine
+binary, but has a few caveats:
- Make sure your `python3` is Python 3.5 or newer, otherwise you'll get a "No
matching distribution found" error. Note that qutebrowser itself also requires
diff --git a/doc/stacktrace.asciidoc b/doc/stacktrace.asciidoc
index 00c89e884..fd41639b0 100644
--- a/doc/stacktrace.asciidoc
+++ b/doc/stacktrace.asciidoc
@@ -98,7 +98,8 @@ Then run qutebrowser directly inside gdb like this:
$ gdb $(readlink -f $(which python3)) -ex 'run -m qutebrowser --debug'
----
-After you reproduce the crash, you should now see something like:
+Note qutebrowser/gdb will take a long time to start. After you reproduce the
+crash, you should now see something like:
----
Program received signal SIGSEGV, Segmentation fault.
diff --git a/icons/qutebrowser.svg b/icons/qutebrowser.svg
index 47ef97b75..b26c80c2b 100644
--- a/icons/qutebrowser.svg
+++ b/icons/qutebrowser.svg
@@ -9,13 +9,13 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="650.00012"
- height="650.00018"
- viewBox="0 0 650.0001 650.00015"
+ width="256"
+ height="256"
+ viewBox="0 0 255.99999 255.99999"
id="svg4546"
version="1.1"
- inkscape:version="0.91 r13725"
- sodipodi:docname="qutebrowser-logo.svg">
+ inkscape:version="0.92.3 (2405546, 2018-03-11)"
+ sodipodi:docname="qutebrowser.svg">
<defs
id="defs4548" />
<sodipodi:namedview
@@ -57,12 +57,12 @@
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
- transform="translate(522.14287,-798.7907)">
+ transform="translate(522.14287,-1192.7909)">
<g
style="display:inline"
id="qutebrowser-logo"
inkscape:label="qutebrowser-logo"
- transform="translate(4742.4729,-1387.0639)">
+ transform="matrix(0.39384608,0,0,0.39384608,1551.3054,331.90062)">
<title
id="title4674">qutebrowser-logo</title>
<g
@@ -85,7 +85,7 @@
<path
inkscape:label="qutebrowser-planet-continents"
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccscccccccccccccccccccccccccccccccccccccccccccccscccccccccccscccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
- d="m -4950.1256,627.7519 c -41.0721,0 -80.1642,7.8197 -116.2898,21.5501 -2.6285,2.4104 -6.0419,4.2605 -8.7446,4.0308 -0.3622,-0.035 -0.7417,-0.2759 -1.1039,-0.4122 -17.8083,7.4364 -34.7008,16.5478 -50.7206,26.8822 2.0836,3.372 2.7009,7.1265 -1.5867,8.9502 -0.7245,0.3122 -9.2508,1.4737 -12.4142,1.396 -45.5513,33.0344 -81.4206,77.1046 -104.7757,128.9723 0.3794,-0.052 2.145,-0.2091 2.5243,-0.235 3.5446,-0.052 6.0115,1.0555 9.4162,1.7696 3.1408,0.6451 5.6744,2.7474 8.3945,2.9516 7.7149,0.5847 9.5725,-5.4041 15.8679,-8.7597 6.5042,0.9175 10.8196,-1.0988 16.6942,-0.4451 4.0032,0.4416 6.8956,4.7123 10.0157,4.9514 2.6252,0.2655 4.9329,-2.4512 7.4735,-2.0631 2.4681,0.3795 6.7215,5.7499 7.1233,8.7597 0.5002,3.7465 -2.7614,7.1204 -1.6903,11.2353 3.9308,3.997 11.0748,4.8067 16.6941,7.1093 3.6583,-3.009 0.483,-8.5931 0,-12.9491 0,-1.9169 0.2587,-3.6285 0,-5.3955 -0.3449,-2.9998 -1.6214,-5.748 -1.6558,-8.3153 0,-11.8579 9.5846,-17.4074 17.5532,-22.0899 3.4495,-2.0413 6.1661,-5.6155 9.1584,-7.1093 4.2275,-2.1158 7.3752,-2.6075 10.8748,-4.5703 6.3248,-3.5458 11.7493,-6.3922 16.6941,-10.41 2.2871,-5.3767 0.2243,-12.5866 0.414,-17.9005 2.2887,-1.3987 4.2516,0.602 6.6783,0.4123 3.817,-0.7917 4.1326,-6.1688 6.2955,-8.3153 1.259,-1.2298 4.7018,-2.1112 6.2645,-3.3326 3.8031,-2.9781 5.0415,-7.4763 8.3634,-8.7596 1.1902,-0.4812 3.9412,-0.3501 5.8195,-0.8572 2.4715,-0.6537 5.9901,-3.5737 10.0158,-4.9513 2.625,-0.9159 8.6342,-1.0918 9.6362,-2.0947 1.2247,-1.2574 0,-4.7832 0.414,-6.6648 2.0249,-9.407 16.2216,-11.4008 24.6126,-14.5679 5.8815,-2.2253 11.9182,-6.297 18.3792,-5.0465 -1.259,4.4706 -7.2837,2.8868 -6.2644,8.3155 1.4144,7.5338 11.518,-2.1589 14.1829,-3.269 5.095,-2.1433 13.8276,-3.4516 20.5111,-5.8718 5.859,-2.1431 16.3664,-5.402 10.8436,-12.0922 -4.6068,-0.2656 -6.8283,5.3958 -10.8436,7.1094 -2.7735,0.4415 -2.2457,-2.3165 -4.6104,-2.5391 -2.2509,-0.2655 -3.5099,2.0717 -5.8194,1.6817 -2.2974,-0.3777 -5.5244,-3.9842 -5.8831,-6.665 -0.9143,-6.9564 5.89,-9.8241 8.7756,-15.0122 -1.9076,-6.2923 -10.6281,-1.2816 -15.8991,-3.7451 0.5002,-3.7461 4.3931,-6.3297 8.7775,-7.046 3.5926,-0.6071 11.6594,-0.2967 13.7998,1.6179 1.242,1.0538 0,3.6801 2.0992,5.4273 2.1266,1.9171 4.743,1.7196 7.5044,1.2694 1.0004,-4.7481 -6.1867,-3.5571 -5.4054,-6.6967 5.6401,-3.6822 14.8141,-0.659 21.7184,-1.6817 3.974,-0.5847 8.1479,-3.3855 11.6698,-5.3638 3.3496,-1.9053 7.703,-5.2108 11.2578,-2.0948 0.9658,3.4033 -3.096,4.5293 -4.9934,6.2207 -6.3885,5.6721 -12.9685,12.1696 -17.9342,18.7573 3.0461,2.9656 8.5825,1.4798 13.7362,2.0947 2.0162,0.2656 4.5482,0.8624 6.6784,1.2384 2.4888,0.4415 5.1414,0.3173 7.0904,0.8245 3.5083,0.8572 4.4465,4.602 7.9185,4.602 5.7125,-0.011 5.7798,-6.177 2.5442,-10.0294 1.0175,-3.9329 2.6232,-5.9727 1.2418,-8.7279 -2.5734,-5.1363 -12.0114,-0.2656 -12.4979,-6.665 -0.3104,-4.1548 3.4841,-3.9692 4.9933,-7.0775 -0.6898,-8.0283 6.5973,-8.6099 5.8194,-15.8057 -0.345,-3.0099 -2.8804,-3.0515 -4.9932,-5.8716 -1.0521,-1.3868 -1.6041,-4.0437 -2.8287,-5.2368 -9.7432,-0.8676 -19.5969,-1.3971 -29.573,-1.3971 z m -168.0262,65.5708 0,0 c 1.9438,0.2812 4.2912,2.3608 6.6455,2.5392 2.2302,0.052 4.0653,-1.2263 5.4381,-0.8573 3.4911,0.9176 4.9623,6.1806 1.6904,8.7596 -2.7303,0.3415 -3.7945,-1.1815 -5.8504,-0.8244 -5.6711,0.9607 -7.8461,12.0465 -12.0838,11.6796 -3.9964,-0.3415 -6.1592,-10.0559 -2.0991,-12.9491 0.2588,-2.5259 -1.8473,-2.9313 -1.7247,-5.4273 1.2073,-1.5351 4.6291,-3.1868 7.9495,-2.9199 z m -18.7933,1.3006 c 1.1557,0.035 2.0352,0.319 2.4802,0.8261 -0.5518,4.4413 -4.0359,4.1503 -7.4734,6.2206 -5.935,3.5758 -9.3673,9.0244 -11.2559,16.6626 -0.5519,2.2252 -6.3972,8.1111 -9.2224,7.522 -6.6197,-1.3936 1.8265,-13.5736 3.3392,-15.4248 1.673,-2.052 3.9135,-3.8515 5.8832,-6.2207 1.9094,-2.2942 3.1529,-5.3917 4.9915,-6.6649 2.0163,-1.3937 7.7701,-3.0536 11.2576,-2.9201 z m 49.4149,14.9805 c 2.1216,0.035 4.0275,0.3811 4.8967,1.2383 -1.3624,5.5031 -13.2394,4.0501 -17.5842,2.0631 0.2761,-2.0751 3.5325,-2.6463 6.2644,-2.9199 1.9215,-0.052 4.3068,-0.445 6.4231,-0.3812 z m -27.0289,10.1561 c 1.4142,-0.035 2.8424,0.2725 4.3257,0.6658 -3.8429,3.2081 -7.9978,5.0254 -14.5968,7.1093 -3.1719,0.9969 -8.6515,2.2398 -9.1896,-1.3022 -0.6554,-4.3341 4.6396,-3.3255 7.5356,-3.7133 3.6479,-0.5053 7.6527,-2.6247 11.9251,-2.7611 z m 414.6595,24.6923 c -0.5003,1.1798 -0.8624,2.3483 -0.7934,3.4911 0.2586,2.011 2.4647,3.9451 2.9562,6.6651 0.2587,1.4402 -0.6726,4.5568 0,5.8716 2.0111,3.8912 7.2717,1.0918 11.0352,1.3005 -4.2758,-5.8758 -8.5447,-11.7617 -13.1963,-17.3292 z m 21.3372,28.6596 c -0.6037,2.871 -2.5545,6.6159 -4.1344,9.0136 -3.6392,5.5245 -8.5825,5.7821 -13.8017,8.728 -4.3515,2.4625 -6.2246,6.5714 -8.7756,10.8543 -2.7649,4.6264 -4.4776,7.4212 -3.3393,14.1237 -3.7306,7.3859 -9.3794,11.9111 -17.108,15.4246 -2.2854,1.0279 -5.4072,1.4075 -7.5045,2.9198 -1.6731,1.1971 -2.62,4.4166 -4.9916,7.0776 -2.9286,3.2523 -5.997,4.6247 -7.5372,7.1094 -1.1901,1.9172 -1.6041,5.7387 -2.9253,8.3155 -1.7817,3.4997 -5.5779,5.2139 -7.9184,8.7597 -1.0694,1.6402 -1.7765,4.962 -2.9563,7.1094 -2.6441,4.7974 -7.1629,8.2537 -6.6784,12.4729 0.483,4.0778 5.1209,4.7925 5.4382,8.3472 0,2.0094 -1.3279,3.2372 -1.2418,5.4273 0,3.1973 2.2267,5.4424 2.4804,7.9029 0.6208,6.1864 -2.1096,8.6552 -3.2755,12.8856 -0.5519,2.0199 -0.3105,4.2935 -0.8624,5.8716 -1.0176,3.097 -5.352,5.8917 -5.4364,9.5532 0,2.6018 2.6734,4.6945 2.8924,8.347 0,2.5181 -1.2419,5.2066 -0.7934,7.522 0.8969,4.5343 8.9981,9.8071 12.5288,13.3299 4.7241,4.7143 10.9075,8.3632 12.9428,13.3301 1.7074,4.218 1.7074,9.7066 4.9914,12.8857 2.4354,2.3474 6.4852,3.8108 9.6036,6.2523 2.9097,2.2793 6.0799,4.2466 9.1896,6.665 5.083,3.9677 12.7651,11.8768 20.8613,11.2672 4.2274,-0.3088 8.56,-3.7519 13.3549,-4.6021 4.9329,-0.8831 11.3353,-1.3367 16.3132,-0.8245 3.8117,0.3778 7.739,2.6575 11.7026,2.4756 4.1843,-0.2656 8.9826,-3.3542 13.7361,-5.4272 3.8256,-1.6627 8.5204,-3.5035 13.6741,-4.8559 2.3629,-15.8527 3.6254,-32.0934 3.6254,-48.6229 0,-66.5467 -19.9367,-128.2271 -54.0581,-179.6379 z m -538.5485,109.2108 c -6.9354,0.3794 -11.4802,0.6933 -15.4214,2.4756 -9.0343,4.1032 -7.2888,16.2872 -16.3129,19.17 -3.1218,0.9952 -7.4078,1.0435 -10.8436,1.6817 -2.9666,0.5416 -6.58,2.1592 -9.6364,2.0947 -0.8623,-0.012 -0.9086,-0.1949 -1.9727,-0.5329 -0.8094,5.1109 -1.7261,11.4288 -1.9674,17.1894 8.5859,1.6421 11.8706,12.6558 19.4597,16.4136 2.0783,1.0279 4.7949,1.0831 7.4717,1.6816 2.1612,0.4813 3.8015,1.3954 5.8833,2.0948 4.4154,1.4971 9.8243,1.316 13.3549,2.888 5.3226,2.3575 9.2242,12.3399 13.8017,15.0123 0.2587,2.6927 -0.5174,6.3076 0.414,8.3153 2.161,2.9264 5.2157,2.2813 8.7774,4.1895 4.2602,2.2942 5.564,8.2185 9.6036,10.0292 1.397,0.6173 4.8879,0.5381 7.0904,1.2055 5.5349,1.6714 7.3407,8.0618 12.0838,6.6651 3.1115,-0.9159 2.8665,-4.1093 3.3702,-7.0777 2.0559,-2.2251 4.2998,-5.7455 7.5045,-5.8079 5.1882,-0.2656 5.6486,5.3497 7.5373,10.3783 1.0693,2.8416 3.8514,5.3181 4.5793,8.3155 1.2936,5.1777 0.6554,20.6767 -0.4485,23.7718 -1.3108,3.7966 -6.4593,5.4072 -9.6346,9.6167 -1.5005,1.9737 -2.2112,4.8651 -3.3392,6.2524 -2.0438,2.4836 -5.0829,3.1344 -6.6128,5.4271 -0.8624,1.2919 -1.7075,4.0628 -2.544,5.8082 -2.5078,5.302 -5.8625,9.059 -3.753,15.4246 0.8795,2.6203 4.9828,4.3749 4.9931,7.4586 0.01,3.6279 -7.7321,6.8765 -8.3323,10.8543 -0.4484,2.9592 2.3991,8.2414 3.3392,12.0922 0.6899,2.9102 6.1987,4.7294 7.9183,6.6651 2.9304,3.284 5.2727,7.9361 7.9495,12.0606 5.2933,8.1125 9.4414,18.0066 14.5951,25.8666 2.7251,4.1168 6.549,7.8185 8.3634,12.0922 0.9315,2.1567 0.7934,4.7271 1.6558,6.665 2.9839,6.7213 16.1595,13.7388 22.9586,17.0751 3.1839,1.542 6.7145,2.0988 9.6345,3.7134 4.4242,2.4626 13.1895,9.0768 15.4231,12.949 1.9887,3.4807 3.2305,11.9529 4.198,17.4879 1.2938,7.3142 0.014,12.9303 0.4139,20.852 0.2589,4.2833 1.6388,8.5912 1.6905,12.8855 0.016,1.5023 -0.9177,1.4423 -0.9867,2.977 l 0.183,1.6086 c 40.8841,18.7713 86.3906,29.4377 134.4827,29.4377 8.6876,0 17.2623,-0.3073 25.7759,-0.9678 0.3794,-0.64 0.7374,-1.4468 1.1858,-2.0472 1.9594,-2.5675 3.6996,-4.8164 4.9933,-7.0776 1.2245,-7.6081 -3.0408,-12.9227 -1.242,-19.5825 1.9922,-7.4808 12.3565,-12.0496 19.6195,-15.4246 2.4991,-1.1591 5.0554,-3.0401 7.0906,-3.7453 5.0276,-1.7457 11.3041,-0.8019 15.8989,-2.4755 7.8237,-2.8571 8.6395,-11.2315 12.4979,-18.3446 1.8179,-3.3687 4.2223,-6.7415 4.5792,-9.1406 0.3105,-2.1569 -0.7934,-4.1855 -0.4485,-6.7285 0.3796,-2.5179 2.639,-4.6928 3.3393,-7.4585 0.9141,-3.6092 1.3108,-8.8969 1.3108,-12.9173 0,-3.3 -1.5523,-6.1955 -1.6903,-9.1723 -0.5347,-10.8083 3.9118,-12.0181 7.9185,-17.9004 2.0111,-2.9221 2.763,-6.253 4.1653,-8.3472 6.7267,-10.0161 18.3983,-14.8516 17.5531,-29.9926 -0.276,-5.0101 -3.4288,-16.3326 -7.1233,-17.9319 -2.1129,-0.9176 -6.9595,-0.052 -10.0159,-1.2383 -9.8674,-3.6742 -15.6592,-15.883 -25.8837,-16.6626 -2.1854,-0.2656 -4.1896,0.8952 -6.6473,0.8572 -4.0464,-0.2656 -10.1469,-2.8293 -14.6262,-3.3326 -2.8476,-0.3087 -6.6542,0.8469 -8.3634,0 -2.608,-1.2642 -2.8718,-6.0604 -4.9932,-7.4901 -1.6731,-1.1556 -4.9536,-1.5523 -7.5047,-2.539 -4.1118,-1.5765 -7.3716,-3.4153 -12.1147,-3.7452 -1.4661,-0.052 -3.2874,0.702 -4.9933,0.4449 -2.625,-0.4415 -4.7,-3.5433 -7.1216,-5.0146 -3.0338,-1.8429 -5.8383,-2.7346 -7.0923,-5.3636 2.7424,-8.9754 -4.8346,-11.477 -6.6782,-16.6626 -0.8798,-2.4301 -0.483,-5.3543 -1.242,-7.5219 -1.0866,-3.1051 -4.1636,-4.8998 -7.5355,-7.4903 -6.042,-4.6406 -11.3991,-8.9981 -20.0333,-10.0609 -3.7963,-0.4812 -7.5614,1.1349 -12.1477,0.8572 -4.8587,-0.3087 -10.9592,-4.5496 -14.595,-8.6963 -3.534,-4.0482 -5.2536,-7.6815 -8.3323,-9.6166 -2.915,-1.8712 -6.7836,-1.8175 -8.7758,-3.7134 -0.8795,-0.8244 -0.7416,-2.2428 -1.6903,-4.1895 -1.466,-3.031 -3.9273,-4.7156 -2.099,-8.347 -3.3271,-1.7058 -3.4185,3.1689 -7.0595,2.539 -3.2443,-4.5974 -5.9868,-6.7756 -13.355,-5.4274 -3.3754,0.6192 -5.2589,4.8772 -9.1896,4.9831 -3.2254,0.2656 -5.759,-3.5856 -10.0175,-4.1895 -3.215,-0.4415 -6.8699,0.871 -9.1586,0.445 -3.5634,-0.7123 -4.6622,-3.6717 -7.9167,-5.8081 -2.3873,-1.5662 -7.0252,-4.232 -8.3636,-4.1893 -4.1964,0.2656 -7.1872,8.9006 -12.9738,5.8397 -2.8131,-3.557 4.581,-5.4314 1.2419,-8.7598 -2.5304,-2.5256 -4.6552,1.1435 -6.6784,2.5391 -2.3181,1.5988 -4.4965,3.1795 -7.0595,4.1259 -5.7349,2.1431 -9.319,1.0211 -13.8,3.3326 -4.1498,2.1455 -4.3274,5.7349 -6.6783,9.9975 -1.9214,3.4922 -6.3006,8.5808 -9.1896,8.7916 -3.4996,0.2655 -6.8439,-4.8829 -10.0175,-6.2526 -9.5605,-4.1334 -14.1916,3.6709 -22.1323,3.777 -7.3666,0.2656 -17.8911,-11.8751 -17.5202,-18.7891 0,-4.2187 2.4301,-10.6185 2.9252,-15.8371 0.4484,-4.1509 3.2908,-6.653 3.3391,-10.442 0,-5.0612 -6.7266,-8.9528 -10.0174,-9.5532 -7.7995,-1.4315 -18.6294,3.1322 -27.569,-0.445 -1.7075,-2.8238 1.9991,-4.775 2.958,-7.5219 0.5347,-1.5627 0.2242,-3.6462 0.7935,-5.3637 0.983,-2.6538 3.779,-4.7101 5.0242,-7.522 0.9314,-2.1457 1.1728,-5.2407 2.0991,-7.9028 1.0866,-3.0313 3.1046,-4.9835 3.3392,-7.1094 0.3104,-2.8071 -0.759,-6.0516 -2.9581,-7.9027 z m 111.6154,88.2004 c 2.8287,0.2656 3.1839,6.1003 0.2933,6.5698 -3.1201,0.4829 -4.7069,-4.8866 -1.6903,-6.2843 0.5174,-0.2655 1.0004,-0.2828 1.397,-0.2535 l 0,-0.035 z"
+ d="m -4950.1256,627.7519 c -41.0721,0 -80.1642,7.8197 -116.2898,21.5501 -2.6285,2.4104 -6.0419,4.2605 -8.7446,4.0308 -0.3622,-0.035 -0.7417,-0.2759 -1.1039,-0.4122 -17.8083,7.4364 -34.7008,16.5478 -50.7206,26.8822 2.0836,3.372 2.7009,7.1265 -1.5867,8.9502 -0.7245,0.3122 -9.2508,1.4737 -12.4142,1.396 -45.5513,33.0344 -81.4206,77.1046 -104.7757,128.9723 0.3794,-0.052 2.145,-0.2091 2.5243,-0.235 3.5446,-0.052 6.0115,1.0555 9.4162,1.7696 3.1408,0.6451 5.6744,2.7474 8.3945,2.9516 7.7149,0.5847 9.5725,-5.4041 15.8679,-8.7597 6.5042,0.9175 10.8196,-1.0988 16.6942,-0.4451 4.0032,0.4416 6.8956,4.7123 10.0157,4.9514 2.6252,0.2655 4.9329,-2.4512 7.4735,-2.0631 2.4681,0.3795 6.7215,5.7499 7.1233,8.7597 0.5002,3.7465 -2.7614,7.1204 -1.6903,11.2353 3.9308,3.997 11.0748,4.8067 16.6941,7.1093 3.6583,-3.009 0.483,-8.5931 0,-12.9491 0,-1.9169 0.2587,-3.6285 0,-5.3955 -0.3449,-2.9998 -1.6214,-5.748 -1.6558,-8.3153 0,-11.8579 9.5846,-17.4074 17.5532,-22.0899 3.4495,-2.0413 6.1661,-5.6155 9.1584,-7.1093 4.2275,-2.1158 7.3752,-2.6075 10.8748,-4.5703 6.3248,-3.5458 11.7493,-6.3922 16.6941,-10.41 2.2871,-5.3767 0.2243,-12.5866 0.414,-17.9005 2.2887,-1.3987 4.2516,0.602 6.6783,0.4123 3.817,-0.7917 4.1326,-6.1688 6.2955,-8.3153 1.259,-1.2298 4.7018,-2.1112 6.2645,-3.3326 3.8031,-2.9781 5.0415,-7.4763 8.3634,-8.7596 1.1902,-0.4812 3.9412,-0.3501 5.8195,-0.8572 2.4715,-0.6537 5.9901,-3.5737 10.0158,-4.9513 2.625,-0.9159 8.6342,-1.0918 9.6362,-2.0947 1.2247,-1.2574 0,-4.7832 0.414,-6.6648 2.0249,-9.407 16.2216,-11.4008 24.6126,-14.5679 5.8815,-2.2253 11.9182,-6.297 18.3792,-5.0465 -1.259,4.4706 -7.2837,2.8868 -6.2644,8.3155 1.4144,7.5338 11.518,-2.1589 14.1829,-3.269 5.095,-2.1433 13.8276,-3.4516 20.5111,-5.8718 5.859,-2.1431 16.3664,-5.402 10.8436,-12.0922 -4.6068,-0.2656 -6.8283,5.3958 -10.8436,7.1094 -2.7735,0.4415 -2.2457,-2.3165 -4.6104,-2.5391 -2.2509,-0.2655 -3.5099,2.0717 -5.8194,1.6817 -2.2974,-0.3777 -5.5244,-3.9842 -5.8831,-6.665 -0.9143,-6.9564 5.89,-9.8241 8.7756,-15.0122 -1.9076,-6.2923 -10.6281,-1.2816 -15.8991,-3.7451 0.5002,-3.7461 4.3931,-6.3297 8.7775,-7.046 3.5926,-0.6071 11.6594,-0.2967 13.7998,1.6179 1.242,1.0538 0,3.6801 2.0992,5.4273 2.1266,1.9171 4.743,1.7196 7.5044,1.2694 1.0004,-4.7481 -6.1867,-3.5571 -5.4054,-6.6967 5.6401,-3.6822 14.8141,-0.659 21.7184,-1.6817 3.974,-0.5847 8.1479,-3.3855 11.6698,-5.3638 3.3496,-1.9053 7.703,-5.2108 11.2578,-2.0948 0.9658,3.4033 -3.096,4.5293 -4.9934,6.2207 -6.3885,5.6721 -12.9685,12.1696 -17.9342,18.7573 3.0461,2.9656 8.5825,1.4798 13.7362,2.0947 2.0162,0.2656 4.5482,0.8624 6.6784,1.2384 2.4888,0.4415 5.1414,0.3173 7.0904,0.8245 3.5083,0.8572 4.4465,4.602 7.9185,4.602 5.7125,-0.011 5.7798,-6.177 2.5442,-10.0294 1.0175,-3.9329 2.6232,-5.9727 1.2418,-8.7279 -2.5734,-5.1363 -12.0114,-0.2656 -12.4979,-6.665 -0.3104,-4.1548 3.4841,-3.9692 4.9933,-7.0775 -0.6898,-8.0283 6.5973,-8.6099 5.8194,-15.8057 -0.345,-3.0099 -2.8804,-3.0515 -4.9932,-5.8716 -1.0521,-1.3868 -1.6041,-4.0437 -2.8287,-5.2368 -9.7432,-0.8676 -19.5969,-1.3971 -29.573,-1.3971 z m -168.0262,65.5708 v 0 c 1.9438,0.2812 4.2912,2.3608 6.6455,2.5392 2.2302,0.052 4.0653,-1.2263 5.4381,-0.8573 3.4911,0.9176 4.9623,6.1806 1.6904,8.7596 -2.7303,0.3415 -3.7945,-1.1815 -5.8504,-0.8244 -5.6711,0.9607 -7.8461,12.0465 -12.0838,11.6796 -3.9964,-0.3415 -6.1592,-10.0559 -2.0991,-12.9491 0.2588,-2.5259 -1.8473,-2.9313 -1.7247,-5.4273 1.2073,-1.5351 4.6291,-3.1868 7.9495,-2.9199 z m -18.7933,1.3006 c 1.1557,0.035 2.0352,0.319 2.4802,0.8261 -0.5518,4.4413 -4.0359,4.1503 -7.4734,6.2206 -5.935,3.5758 -9.3673,9.0244 -11.2559,16.6626 -0.5519,2.2252 -6.3972,8.1111 -9.2224,7.522 -6.6197,-1.3936 1.8265,-13.5736 3.3392,-15.4248 1.673,-2.052 3.9135,-3.8515 5.8832,-6.2207 1.9094,-2.2942 3.1529,-5.3917 4.9915,-6.6649 2.0163,-1.3937 7.7701,-3.0536 11.2576,-2.9201 z m 49.4149,14.9805 c 2.1216,0.035 4.0275,0.3811 4.8967,1.2383 -1.3624,5.5031 -13.2394,4.0501 -17.5842,2.0631 0.2761,-2.0751 3.5325,-2.6463 6.2644,-2.9199 1.9215,-0.052 4.3068,-0.445 6.4231,-0.3812 z m -27.0289,10.1561 c 1.4142,-0.035 2.8424,0.2725 4.3257,0.6658 -3.8429,3.2081 -7.9978,5.0254 -14.5968,7.1093 -3.1719,0.9969 -8.6515,2.2398 -9.1896,-1.3022 -0.6554,-4.3341 4.6396,-3.3255 7.5356,-3.7133 3.6479,-0.5053 7.6527,-2.6247 11.9251,-2.7611 z m 414.6595,24.6923 c -0.5003,1.1798 -0.8624,2.3483 -0.7934,3.4911 0.2586,2.011 2.4647,3.9451 2.9562,6.6651 0.2587,1.4402 -0.6726,4.5568 0,5.8716 2.0111,3.8912 7.2717,1.0918 11.0352,1.3005 -4.2758,-5.8758 -8.5447,-11.7617 -13.1963,-17.3292 z m 21.3372,28.6596 c -0.6037,2.871 -2.5545,6.6159 -4.1344,9.0136 -3.6392,5.5245 -8.5825,5.7821 -13.8017,8.728 -4.3515,2.4625 -6.2246,6.5714 -8.7756,10.8543 -2.7649,4.6264 -4.4776,7.4212 -3.3393,14.1237 -3.7306,7.3859 -9.3794,11.9111 -17.108,15.4246 -2.2854,1.0279 -5.4072,1.4075 -7.5045,2.9198 -1.6731,1.1971 -2.62,4.4166 -4.9916,7.0776 -2.9286,3.2523 -5.997,4.6247 -7.5372,7.1094 -1.1901,1.9172 -1.6041,5.7387 -2.9253,8.3155 -1.7817,3.4997 -5.5779,5.2139 -7.9184,8.7597 -1.0694,1.6402 -1.7765,4.962 -2.9563,7.1094 -2.6441,4.7974 -7.1629,8.2537 -6.6784,12.4729 0.483,4.0778 5.1209,4.7925 5.4382,8.3472 0,2.0094 -1.3279,3.2372 -1.2418,5.4273 0,3.1973 2.2267,5.4424 2.4804,7.9029 0.6208,6.1864 -2.1096,8.6552 -3.2755,12.8856 -0.5519,2.0199 -0.3105,4.2935 -0.8624,5.8716 -1.0176,3.097 -5.352,5.8917 -5.4364,9.5532 0,2.6018 2.6734,4.6945 2.8924,8.347 0,2.5181 -1.2419,5.2066 -0.7934,7.522 0.8969,4.5343 8.9981,9.8071 12.5288,13.3299 4.7241,4.7143 10.9075,8.3632 12.9428,13.3301 1.7074,4.218 1.7074,9.7066 4.9914,12.8857 2.4354,2.3474 6.4852,3.8108 9.6036,6.2523 2.9097,2.2793 6.0799,4.2466 9.1896,6.665 5.083,3.9677 12.7651,11.8768 20.8613,11.2672 4.2274,-0.3088 8.56,-3.7519 13.3549,-4.6021 4.9329,-0.8831 11.3353,-1.3367 16.3132,-0.8245 3.8117,0.3778 7.739,2.6575 11.7026,2.4756 4.1843,-0.2656 8.9826,-3.3542 13.7361,-5.4272 3.8256,-1.6627 8.5204,-3.5035 13.6741,-4.8559 2.3629,-15.8527 3.6254,-32.0934 3.6254,-48.6229 0,-66.5467 -19.9367,-128.2271 -54.0581,-179.6379 z m -538.5485,109.2108 c -6.9354,0.3794 -11.4802,0.6933 -15.4214,2.4756 -9.0343,4.1032 -7.2888,16.2872 -16.3129,19.17 -3.1218,0.9952 -7.4078,1.0435 -10.8436,1.6817 -2.9666,0.5416 -6.58,2.1592 -9.6364,2.0947 -0.8623,-0.012 -0.9086,-0.1949 -1.9727,-0.5329 -0.8094,5.1109 -1.7261,11.4288 -1.9674,17.1894 8.5859,1.6421 11.8706,12.6558 19.4597,16.4136 2.0783,1.0279 4.7949,1.0831 7.4717,1.6816 2.1612,0.4813 3.8015,1.3954 5.8833,2.0948 4.4154,1.4971 9.8243,1.316 13.3549,2.888 5.3226,2.3575 9.2242,12.3399 13.8017,15.0123 0.2587,2.6927 -0.5174,6.3076 0.414,8.3153 2.161,2.9264 5.2157,2.2813 8.7774,4.1895 4.2602,2.2942 5.564,8.2185 9.6036,10.0292 1.397,0.6173 4.8879,0.5381 7.0904,1.2055 5.5349,1.6714 7.3407,8.0618 12.0838,6.6651 3.1115,-0.9159 2.8665,-4.1093 3.3702,-7.0777 2.0559,-2.2251 4.2998,-5.7455 7.5045,-5.8079 5.1882,-0.2656 5.6486,5.3497 7.5373,10.3783 1.0693,2.8416 3.8514,5.3181 4.5793,8.3155 1.2936,5.1777 0.6554,20.6767 -0.4485,23.7718 -1.3108,3.7966 -6.4593,5.4072 -9.6346,9.6167 -1.5005,1.9737 -2.2112,4.8651 -3.3392,6.2524 -2.0438,2.4836 -5.0829,3.1344 -6.6128,5.4271 -0.8624,1.2919 -1.7075,4.0628 -2.544,5.8082 -2.5078,5.302 -5.8625,9.059 -3.753,15.4246 0.8795,2.6203 4.9828,4.3749 4.9931,7.4586 0.01,3.6279 -7.7321,6.8765 -8.3323,10.8543 -0.4484,2.9592 2.3991,8.2414 3.3392,12.0922 0.6899,2.9102 6.1987,4.7294 7.9183,6.6651 2.9304,3.284 5.2727,7.9361 7.9495,12.0606 5.2933,8.1125 9.4414,18.0066 14.5951,25.8666 2.7251,4.1168 6.549,7.8185 8.3634,12.0922 0.9315,2.1567 0.7934,4.7271 1.6558,6.665 2.9839,6.7213 16.1595,13.7388 22.9586,17.0751 3.1839,1.542 6.7145,2.0988 9.6345,3.7134 4.4242,2.4626 13.1895,9.0768 15.4231,12.949 1.9887,3.4807 3.2305,11.9529 4.198,17.4879 1.2938,7.3142 0.014,12.9303 0.4139,20.852 0.2589,4.2833 1.6388,8.5912 1.6905,12.8855 0.016,1.5023 -0.9177,1.4423 -0.9867,2.977 l 0.183,1.6086 c 40.8841,18.7713 86.3906,29.4377 134.4827,29.4377 8.6876,0 17.2623,-0.3073 25.7759,-0.9678 0.3794,-0.64 0.7374,-1.4468 1.1858,-2.0472 1.9594,-2.5675 3.6996,-4.8164 4.9933,-7.0776 1.2245,-7.6081 -3.0408,-12.9227 -1.242,-19.5825 1.9922,-7.4808 12.3565,-12.0496 19.6195,-15.4246 2.4991,-1.1591 5.0554,-3.0401 7.0906,-3.7453 5.0276,-1.7457 11.3041,-0.8019 15.8989,-2.4755 7.8237,-2.8571 8.6395,-11.2315 12.4979,-18.3446 1.8179,-3.3687 4.2223,-6.7415 4.5792,-9.1406 0.3105,-2.1569 -0.7934,-4.1855 -0.4485,-6.7285 0.3796,-2.5179 2.639,-4.6928 3.3393,-7.4585 0.9141,-3.6092 1.3108,-8.8969 1.3108,-12.9173 0,-3.3 -1.5523,-6.1955 -1.6903,-9.1723 -0.5347,-10.8083 3.9118,-12.0181 7.9185,-17.9004 2.0111,-2.9221 2.763,-6.253 4.1653,-8.3472 6.7267,-10.0161 18.3983,-14.8516 17.5531,-29.9926 -0.276,-5.0101 -3.4288,-16.3326 -7.1233,-17.9319 -2.1129,-0.9176 -6.9595,-0.052 -10.0159,-1.2383 -9.8674,-3.6742 -15.6592,-15.883 -25.8837,-16.6626 -2.1854,-0.2656 -4.1896,0.8952 -6.6473,0.8572 -4.0464,-0.2656 -10.1469,-2.8293 -14.6262,-3.3326 -2.8476,-0.3087 -6.6542,0.8469 -8.3634,0 -2.608,-1.2642 -2.8718,-6.0604 -4.9932,-7.4901 -1.6731,-1.1556 -4.9536,-1.5523 -7.5047,-2.539 -4.1118,-1.5765 -7.3716,-3.4153 -12.1147,-3.7452 -1.4661,-0.052 -3.2874,0.702 -4.9933,0.4449 -2.625,-0.4415 -4.7,-3.5433 -7.1216,-5.0146 -3.0338,-1.8429 -5.8383,-2.7346 -7.0923,-5.3636 2.7424,-8.9754 -4.8346,-11.477 -6.6782,-16.6626 -0.8798,-2.4301 -0.483,-5.3543 -1.242,-7.5219 -1.0866,-3.1051 -4.1636,-4.8998 -7.5355,-7.4903 -6.042,-4.6406 -11.3991,-8.9981 -20.0333,-10.0609 -3.7963,-0.4812 -7.5614,1.1349 -12.1477,0.8572 -4.8587,-0.3087 -10.9592,-4.5496 -14.595,-8.6963 -3.534,-4.0482 -5.2536,-7.6815 -8.3323,-9.6166 -2.915,-1.8712 -6.7836,-1.8175 -8.7758,-3.7134 -0.8795,-0.8244 -0.7416,-2.2428 -1.6903,-4.1895 -1.466,-3.031 -3.9273,-4.7156 -2.099,-8.347 -3.3271,-1.7058 -3.4185,3.1689 -7.0595,2.539 -3.2443,-4.5974 -5.9868,-6.7756 -13.355,-5.4274 -3.3754,0.6192 -5.2589,4.8772 -9.1896,4.9831 -3.2254,0.2656 -5.759,-3.5856 -10.0175,-4.1895 -3.215,-0.4415 -6.8699,0.871 -9.1586,0.445 -3.5634,-0.7123 -4.6622,-3.6717 -7.9167,-5.8081 -2.3873,-1.5662 -7.0252,-4.232 -8.3636,-4.1893 -4.1964,0.2656 -7.1872,8.9006 -12.9738,5.8397 -2.8131,-3.557 4.581,-5.4314 1.2419,-8.7598 -2.5304,-2.5256 -4.6552,1.1435 -6.6784,2.5391 -2.3181,1.5988 -4.4965,3.1795 -7.0595,4.1259 -5.7349,2.1431 -9.319,1.0211 -13.8,3.3326 -4.1498,2.1455 -4.3274,5.7349 -6.6783,9.9975 -1.9214,3.4922 -6.3006,8.5808 -9.1896,8.7916 -3.4996,0.2655 -6.8439,-4.8829 -10.0175,-6.2526 -9.5605,-4.1334 -14.1916,3.6709 -22.1323,3.777 -7.3666,0.2656 -17.8911,-11.8751 -17.5202,-18.7891 0,-4.2187 2.4301,-10.6185 2.9252,-15.8371 0.4484,-4.1509 3.2908,-6.653 3.3391,-10.442 0,-5.0612 -6.7266,-8.9528 -10.0174,-9.5532 -7.7995,-1.4315 -18.6294,3.1322 -27.569,-0.445 -1.7075,-2.8238 1.9991,-4.775 2.958,-7.5219 0.5347,-1.5627 0.2242,-3.6462 0.7935,-5.3637 0.983,-2.6538 3.779,-4.7101 5.0242,-7.522 0.9314,-2.1457 1.1728,-5.2407 2.0991,-7.9028 1.0866,-3.0313 3.1046,-4.9835 3.3392,-7.1094 0.3104,-2.8071 -0.759,-6.0516 -2.9581,-7.9027 z m 111.6154,88.2004 c 2.8287,0.2656 3.1839,6.1003 0.2933,6.5698 -3.1201,0.4829 -4.7069,-4.8866 -1.6903,-6.2843 0.5174,-0.2655 1.0004,-0.2828 1.397,-0.2535 v -0.035 z"
id="use4632"
style="display:inline;fill:#7ebaff;fill-opacity:1;fill-rule:nonzero;stroke:none"
inkscape:connector-curvature="0">
@@ -98,7 +98,7 @@
sodipodi:nodetypes="cccccssccsccccssccsccccsccccc"
inkscape:connector-curvature="0"
id="qutebrowser-letterform-classical-clone"
- d="m -4845.3304,2264.927 -85.7148,51.123 0,130.7539 85.7148,-51.123 z m -149.0039,11.4375 c -78.5937,-0.4315 -227.4791,22.2666 -228.1386,190.8066 -0.8,204.4536 152.4167,157.7755 187.1425,137.1426 66.7691,-39.4285 135.559,-81.1427 198.5723,-118.0625 34.3158,-20.0731 98.5703,-33.1412 98.5703,61.1445 0,94.2857 -69.7669,123.5203 -107.1426,121.5 l 0,-159.2324 -85.7148,50.5879 0,181.7148 c 4.6167,0.947 22.0891,3.2468 46.1484,3.3789 78.5937,0.4315 227.4792,-22.2666 228.1387,-190.8066 0.8,-204.4536 -152.4167,-157.7755 -187.1426,-137.1426 -66.7691,39.4286 -135.5589,81.1428 -198.5722,118.0625 -34.3158,20.0731 -98.5703,33.1412 -98.5703,-61.1445 0,-94.2857 69.7669,-123.5203 107.1425,-121.5 l 0,159.2324 85.7149,-50.5879 0,-181.7148 c -4.6167,-0.947 -22.0892,-3.2468 -46.1485,-3.3789 z m 46.1485,298.541 -85.7149,51.123 0,130.7539 85.7149,-51.123 z"
+ d="m -4845.3304,2264.927 -85.7148,51.123 v 130.7539 l 85.7148,-51.123 z m -149.0039,11.4375 c -78.5937,-0.4315 -227.4791,22.2666 -228.1386,190.8066 -0.8,204.4536 152.4167,157.7755 187.1425,137.1426 66.7691,-39.4285 135.559,-81.1427 198.5723,-118.0625 34.3158,-20.0731 98.5703,-33.1412 98.5703,61.1445 0,94.2857 -69.7669,123.5203 -107.1426,121.5 v -159.2324 l -85.7148,50.5879 v 181.7148 c 4.6167,0.947 22.0891,3.2468 46.1484,3.3789 78.5937,0.4315 227.4792,-22.2666 228.1387,-190.8066 0.8,-204.4536 -152.4167,-157.7755 -187.1426,-137.1426 -66.7691,39.4286 -135.5589,81.1428 -198.5722,118.0625 -34.3158,20.0731 -98.5703,33.1412 -98.5703,-61.1445 0,-94.2857 69.7669,-123.5203 107.1425,-121.5 v 159.2324 l 85.7149,-50.5879 v -181.7148 c -4.6167,-0.947 -22.0892,-3.2468 -46.1485,-3.3789 z m 46.1485,298.541 -85.7149,51.123 v 130.7539 l 85.7149,-51.123 z"
style="fill:#0a396e;fill-opacity:1;fill-rule:evenodd">
<title
id="title4559">qutebrowser-letterform-classical</title>
diff --git a/misc/Makefile b/misc/Makefile
index 4625b288e..ff5a2cca2 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -17,12 +17,12 @@ doc/qutebrowser.1.html:
install: doc/qutebrowser.1.html
$(PYTHON) setup.py install --prefix="$(PREFIX)" --optimize=1 $(SETUPTOOLSOPTS)
- install -Dm644 misc/qutebrowser.appdata.xml \
- "$(DESTDIR)$(DATADIR)/metainfo/qutebrowser.appdata.xml"
+ install -Dm644 misc/org.qutebrowser.qutebrowser.appdata.xml \
+ "$(DESTDIR)$(DATADIR)/metainfo/org.qutebrowser.qutebrowser.appdata.xml"
install -Dm644 doc/qutebrowser.1 \
"$(DESTDIR)$(MANDIR)/man1/qutebrowser.1"
- install -Dm644 misc/qutebrowser.desktop \
- "$(DESTDIR)$(DATADIR)/applications/qutebrowser.desktop"
+ install -Dm644 misc/org.qutebrowser.qutebrowser.desktop \
+ "$(DESTDIR)$(DATADIR)/applications/org.qutebrowser.qutebrowser.desktop"
$(foreach i,$(ICONSIZES),install -Dm644 "icons/qutebrowser-$(i)x$(i).png" \
"$(DESTDIR)$(DATADIR)/icons/hicolor/$(i)x$(i)/apps/qutebrowser.png";)
install -Dm644 icons/qutebrowser.svg \
diff --git a/misc/qutebrowser.appdata.xml b/misc/org.qutebrowser.qutebrowser.appdata.xml
index bdab55f54..e44c68046 100644
--- a/misc/qutebrowser.appdata.xml
+++ b/misc/org.qutebrowser.qutebrowser.appdata.xml
@@ -20,7 +20,7 @@
<provides>
<binary>qutebrowser</binary>
</provides>
- <launchable type="desktop-id">qutebrowser.desktop</launchable>
+ <launchable type="desktop-id">org.qutebrowser.qutebrowser.desktop</launchable>
<screenshots>
<screenshot type="default">
<image>https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/main.png</image>
@@ -40,9 +40,32 @@
<url type="help">https://qutebrowser.org/doc/help/</url>
<url type="bugtracker">https://github.com/qutebrowser/qutebrowser/issues/</url>
<url type="donation">https://github.com/qutebrowser/qutebrowser#donating</url>
+ <content_rating type="oars-1.1">
+ </content_rating>
<releases>
+ <release version="1.6.3" date="2019-06-18"/>
+ <release version="1.6.2" date="2019-05-06"/>
+ <release version="1.6.1" date="2019-03-20"/>
+ <release version="1.6.0" date="2019-02-25"/>
+ <release version="1.5.2" date="2018-10-26"/>
+ <release version="1.5.1" date="2018-10-10"/>
+ <release version="1.5.0" date="2018-10-03"/>
+ <release version="1.4.2" date="2018-09-02"/>
+ <release version="1.4.1" date="2018-07-11"/>
+ <release version="1.4.0" date="2018-07-03"/>
+ <release version="1.3.3" date="2018-06-21"/>
+ <release version="1.3.2" date="2018-06-10"/>
+ <release version="1.3.1" date="2018-05-29"/>
<release version="1.3.0" date="2018-05-04"/>
<release version="1.2.1" date="2018-03-14"/>
<release version="1.2.0" date="2018-03-09"/>
+ <release version="1.1.2" date="2018-03-01"/>
+ <release version="1.1.1" date="2018-01-20"/>
+ <release version="1.1.0" date="2018-01-15"/>
+ <release version="1.0.4" date="2017-11-28"/>
+ <release version="1.0.3" date="2017-11-04"/>
+ <release version="1.0.2" date="2017-10-17"/>
+ <release version="1.0.1" date="2017-10-13"/>
+ <release version="1.0.0" date="2017-10-12"/>
</releases>
</component>
diff --git a/misc/qutebrowser.desktop b/misc/org.qutebrowser.qutebrowser.desktop
index 976803915..5836a5e48 100644
--- a/misc/qutebrowser.desktop
+++ b/misc/org.qutebrowser.qutebrowser.desktop
@@ -48,6 +48,7 @@ Terminal=false
StartupNotify=false
MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/qute;
Keywords=Browser
+Actions=new-window;preferences;
[Desktop Action new-window]
Name=New Window
diff --git a/misc/qutebrowser.spec b/misc/qutebrowser.spec
index 269668751..43a18b6b5 100644
--- a/misc/qutebrowser.spec
+++ b/misc/qutebrowser.spec
@@ -40,9 +40,9 @@ setupcommon.write_git_file()
if os.name == 'nt':
- icon = 'icons/qutebrowser.ico'
+ icon = '../icons/qutebrowser.ico'
elif sys.platform == 'darwin':
- icon = 'icons/qutebrowser.icns'
+ icon = '../icons/qutebrowser.icns'
else:
icon = None
@@ -69,7 +69,7 @@ exe = EXE(pyz,
strip=False,
upx=False,
console=False,
- version='misc/file_version_info.txt')
+ version='../misc/file_version_info.txt')
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
diff --git a/misc/requirements/requirements-check-manifest.txt b/misc/requirements/requirements-check-manifest.txt
index c11a3f76e..cb2102f8e 100644
--- a/misc/requirements/requirements-check-manifest.txt
+++ b/misc/requirements/requirements-check-manifest.txt
@@ -1,3 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-check-manifest==0.37
+check-manifest==0.39
+toml==0.10.0
diff --git a/misc/requirements/requirements-codecov.txt b/misc/requirements/requirements-codecov.txt
index 19ae758af..e72f881ad 100644
--- a/misc/requirements/requirements-codecov.txt
+++ b/misc/requirements/requirements-codecov.txt
@@ -1,9 +1,9 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-certifi==2018.11.29
+certifi==2019.6.16
chardet==3.0.4
codecov==2.0.15
-coverage==4.5.2
+coverage==4.5.3
idna==2.8
-requests==2.21.0
-urllib3==1.24.1
+requests==2.22.0
+urllib3==1.25.3
diff --git a/misc/requirements/requirements-flake8.txt b/misc/requirements/requirements-flake8.txt
index 42255f825..18928f659 100644
--- a/misc/requirements/requirements-flake8.txt
+++ b/misc/requirements/requirements-flake8.txt
@@ -1,27 +1,25 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-attrs==18.2.0
-flake8==3.6.0
-flake8-bugbear==18.8.0
+attrs==19.1.0
+entrypoints==0.3
+flake8==3.7.7
+flake8-bugbear==19.3.0
flake8-builtins==1.4.1
-flake8-comprehensions==1.4.1
+flake8-comprehensions==2.1.0
flake8-copyright==0.2.2
flake8-debugger==3.1.0
flake8-deprecated==1.3
flake8-docstrings==1.3.0
flake8-future-import==0.4.5
flake8-mock==0.3
-flake8-per-file-ignores==0.7
flake8-polyfill==1.0.2
flake8-string-format==0.2.3
-flake8-tidy-imports==1.1.0
-flake8-tuple==0.2.13
+flake8-tidy-imports==2.0.0
+flake8-tuple==0.3.1
mccabe==0.6.1
-pathmatch==0.2.1
-pep8-naming==0.7.0
-pycodestyle==2.4.0
+pep8-naming==0.8.2
+pycodestyle==2.5.0
pydocstyle==3.0.0
-pyflakes==2.0.0
+pyflakes==2.1.1
six==1.12.0
-snowballstemmer==1.2.1
-typing==3.6.6
+snowballstemmer==1.9.0
diff --git a/misc/requirements/requirements-flake8.txt-raw b/misc/requirements/requirements-flake8.txt-raw
index 1f30b83ae..1bdca6974 100644
--- a/misc/requirements/requirements-flake8.txt-raw
+++ b/misc/requirements/requirements-flake8.txt-raw
@@ -8,7 +8,6 @@ flake8-deprecated
flake8-docstrings
flake8-future-import
flake8-mock
-flake8-per-file-ignores
flake8-string-format
flake8-tidy-imports
flake8-tuple
diff --git a/misc/requirements/requirements-mypy.txt b/misc/requirements/requirements-mypy.txt
index 6b8c63e97..eac1123af 100644
--- a/misc/requirements/requirements-mypy.txt
+++ b/misc/requirements/requirements-mypy.txt
@@ -1,8 +1,8 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-mypy==0.650
+mypy==0.711
mypy-extensions==0.4.1
-PyQt5==5.11.3
-PyQt5-sip==4.19.13
+# PyQt5==5.11.3
+# PyQt5-sip==4.19.17
-e git+https://github.com/qutebrowser/PyQt5-stubs.git@wip#egg=PyQt5_stubs
-typed-ast==1.1.1
+typed-ast==1.4.0
diff --git a/misc/requirements/requirements-mypy.txt-raw b/misc/requirements/requirements-mypy.txt-raw
index 636ad43a4..92a35ab74 100644
--- a/misc/requirements/requirements-mypy.txt-raw
+++ b/misc/requirements/requirements-mypy.txt-raw
@@ -3,3 +3,4 @@ mypy
# remove @commit-id for scm installs
#@ replace: @.*# @wip#
+#@ ignore: PyQt5, PyQt5-sip
diff --git a/misc/requirements/requirements-optional.txt b/misc/requirements/requirements-optional.txt
index aafa38e46..03cc8c52a 100644
--- a/misc/requirements/requirements-optional.txt
+++ b/misc/requirements/requirements-optional.txt
@@ -2,6 +2,6 @@
colorama==0.4.1
cssutils==1.0.2
-hunter==2.1.0
-Pympler==0.6
-six==1.12.0
+hunter==3.0.1
+manhole==1.6.0
+Pympler==0.7
diff --git a/misc/requirements/requirements-pip.txt b/misc/requirements/requirements-pip.txt
index f15a3a3e1..e2336bba6 100644
--- a/misc/requirements/requirements-pip.txt
+++ b/misc/requirements/requirements-pip.txt
@@ -1,8 +1,8 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
appdirs==1.4.3
-packaging==18.0
-pyparsing==2.3.0
-setuptools==40.6.3
+packaging==19.0
+pyparsing==2.4.0
+setuptools==41.0.1
six==1.12.0
-wheel==0.32.3
+wheel==0.33.4
diff --git a/misc/requirements/requirements-pyinstaller.txt b/misc/requirements/requirements-pyinstaller.txt
index 4c7b57353..fe94cd13d 100644
--- a/misc/requirements/requirements-pyinstaller.txt
+++ b/misc/requirements/requirements-pyinstaller.txt
@@ -1,7 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
altgraph==0.16.1
-future==0.17.1
-macholib==1.11
-pefile==2018.8.8
-e git+https://github.com/pyinstaller/pyinstaller.git@develop#egg=PyInstaller
diff --git a/misc/requirements/requirements-pylint.txt b/misc/requirements/requirements-pylint.txt
index b3ecdaf70..f41585be8 100644
--- a/misc/requirements/requirements-pylint.txt
+++ b/misc/requirements/requirements-pylint.txt
@@ -1,23 +1,24 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
asn1crypto==0.24.0
-astroid==2.1.0
-certifi==2018.11.29
-cffi==1.11.5
+astroid==2.2.5
+certifi==2019.6.16
+cffi==1.12.3
chardet==3.0.4
-cryptography==2.4.2
-github3.py==1.2.0
+cryptography==2.7
+github3.py==1.3.0
idna==2.8
-isort==4.3.4
+isort==4.3.21
jwcrypto==0.6.0
-lazy-object-proxy==1.3.1
+lazy-object-proxy==1.4.1
mccabe==0.6.1
pycparser==2.19
-pylint==2.2.2
-python-dateutil==2.7.5
+pylint==2.3.1
+python-dateutil==2.8.0
./scripts/dev/pylint_checkers
-requests==2.21.0
+requests==2.22.0
six==1.12.0
+typed-ast==1.4.0
uritemplate==3.0.0
-urllib3==1.24.1
-wrapt==1.10.11
+urllib3==1.25.3
+wrapt==1.11.2
diff --git a/misc/requirements/requirements-pyqt.txt b/misc/requirements/requirements-pyqt.txt
index 32aee87a9..610d6c749 100644
--- a/misc/requirements/requirements-pyqt.txt
+++ b/misc/requirements/requirements-pyqt.txt
@@ -1,4 +1,5 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-PyQt5==5.11.3
-PyQt5-sip==4.19.13
+PyQt5==5.12.3
+PyQt5-sip==4.19.17
+PyQtWebEngine==5.12.1
diff --git a/misc/requirements/requirements-pyqt.txt-raw b/misc/requirements/requirements-pyqt.txt-raw
index 37a69c45a..9c6afbf16 100644
--- a/misc/requirements/requirements-pyqt.txt-raw
+++ b/misc/requirements/requirements-pyqt.txt-raw
@@ -1 +1,2 @@
-PyQt5 \ No newline at end of file
+PyQt5
+PyQtWebEngine
diff --git a/misc/requirements/requirements-pyroma.txt b/misc/requirements/requirements-pyroma.txt
index 513e8b269..608ff3944 100644
--- a/misc/requirements/requirements-pyroma.txt
+++ b/misc/requirements/requirements-pyroma.txt
@@ -1,4 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
docutils==0.14
-pyroma==2.4
+pyroma==2.5
diff --git a/misc/requirements/requirements-sphinx.txt b/misc/requirements/requirements-sphinx.txt
index c089895d1..97852e55e 100644
--- a/misc/requirements/requirements-sphinx.txt
+++ b/misc/requirements/requirements-sphinx.txt
@@ -1,21 +1,26 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
alabaster==0.7.12
-Babel==2.6.0
-certifi==2018.11.29
+Babel==2.7.0
+certifi==2019.6.16
chardet==3.0.4
docutils==0.14
idna==2.8
imagesize==1.1.0
-Jinja2==2.10
-MarkupSafe==1.1.0
-packaging==18.0
-Pygments==2.3.1
-pyparsing==2.3.0
-pytz==2018.7
-requests==2.21.0
+Jinja2==2.10.1
+MarkupSafe==1.1.1
+packaging==19.0
+Pygments==2.4.2
+pyparsing==2.4.0
+pytz==2019.1
+requests==2.22.0
six==1.12.0
-snowballstemmer==1.2.1
-Sphinx==1.8.3
-sphinxcontrib-websupport==1.1.0
-urllib3==1.24.1
+snowballstemmer==1.9.0
+Sphinx==2.1.2
+sphinxcontrib-applehelp==1.0.1
+sphinxcontrib-devhelp==1.0.1
+sphinxcontrib-htmlhelp==1.0.2
+sphinxcontrib-jsmath==1.0.1
+sphinxcontrib-qthelp==1.0.2
+sphinxcontrib-serializinghtml==1.1.3
+urllib3==1.25.3
diff --git a/misc/requirements/requirements-tests-git.txt b/misc/requirements/requirements-tests-git.txt
index ce00cd31c..5a32c6d68 100644
--- a/misc/requirements/requirements-tests-git.txt
+++ b/misc/requirements/requirements-tests-git.txt
@@ -13,7 +13,6 @@ hg+https://bitbucket.org/pytest-dev/py
git+https://github.com/pytest-dev/pytest.git@features
git+https://github.com/pytest-dev/pytest-bdd.git
git+https://github.com/pytest-dev/pytest-cov.git
-git+https://github.com/pytest-dev/pytest-faulthandler.git
git+https://github.com/pytest-dev/pytest-instafail.git
git+https://github.com/pytest-dev/pytest-mock.git
git+https://github.com/pytest-dev/pytest-qt.git
diff --git a/misc/requirements/requirements-tests.txt b/misc/requirements/requirements-tests.txt
index 228045f8c..f63b687ea 100644
--- a/misc/requirements/requirements-tests.txt
+++ b/misc/requirements/requirements-tests.txt
@@ -1,41 +1,47 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-atomicwrites==1.2.1
-attrs==18.2.0
+atomicwrites==1.3.0
+attrs==19.1.0
backports.functools-lru-cache==1.5
-beautifulsoup4==4.7.0
-cheroot==6.5.3
+beautifulsoup4==4.7.1
+cheroot==6.5.5
Click==7.0
# colorama==0.4.1
-coverage==4.5.2
-EasyProcess==0.2.5
-Flask==1.0.2
-glob2==0.6
-hunter==2.1.0
-hypothesis==3.85.2
+coverage==4.5.3
+EasyProcess==0.2.7
+Flask==1.0.3
+glob2==0.7
+hunter==3.0.1
+hypothesis==4.24.6
+importlib-metadata==0.18
itsdangerous==1.1.0
-# Jinja2==2.10
-Mako==1.0.7
-# MarkupSafe==1.1.0
-more-itertools==5.0.0
-parse==1.9.0
+# Jinja2==2.10.1
+Mako==1.0.13
+manhole==1.6.0
+# MarkupSafe==1.1.1
+more-itertools==7.1.0
+packaging==19.0
+parse==1.12.0
parse-type==0.4.2
-pluggy==0.8.0
-py==1.7.0
-py-cpuinfo==4.0.0
-pytest==4.0.2
-pytest-bdd==3.0.1
-pytest-benchmark==3.1.1
-pytest-cov==2.6.0
-pytest-faulthandler==1.5.0
-pytest-instafail==0.4.0
-pytest-mock==1.10.0
+pluggy==0.12.0
+py==1.8.0
+py-cpuinfo==5.0.0
+pyparsing==2.4.0
+pytest==5.0.0
+pytest-bdd==3.1.0
+pytest-benchmark==3.2.2
+pytest-cov==2.7.1
+pytest-instafail==0.4.1
+pytest-mock==1.10.4
pytest-qt==3.2.2
-pytest-repeat==0.7.0
-pytest-rerunfailures==5.0
+pytest-repeat==0.8.0
+pytest-rerunfailures==7.0
pytest-travis-fold==1.3.0
-pytest-xvfb==1.1.0
-PyVirtualDisplay==0.2.1
+pytest-xvfb==1.2.0
+PyVirtualDisplay==0.2.4
six==1.12.0
+soupsieve==1.9.2
vulture==1.0
-Werkzeug==0.14.1
+wcwidth==0.1.7
+Werkzeug==0.15.4
+zipp==0.5.1
diff --git a/misc/requirements/requirements-tests.txt-raw b/misc/requirements/requirements-tests.txt-raw
index 121689980..ea806e062 100644
--- a/misc/requirements/requirements-tests.txt-raw
+++ b/misc/requirements/requirements-tests.txt-raw
@@ -8,7 +8,6 @@ pytest
pytest-bdd
pytest-benchmark
pytest-cov
-pytest-faulthandler
pytest-instafail
pytest-mock
pytest-qt
diff --git a/misc/requirements/requirements-tox.txt b/misc/requirements/requirements-tox.txt
index ed0db2870..14ea6227e 100644
--- a/misc/requirements/requirements-tox.txt
+++ b/misc/requirements/requirements-tox.txt
@@ -1,9 +1,13 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-filelock==3.0.10
-pluggy==0.8.0
-py==1.7.0
+filelock==3.0.12
+importlib-metadata==0.18
+packaging==19.0
+pluggy==0.12.0
+py==1.8.0
+pyparsing==2.4.0
six==1.12.0
toml==0.10.0
-tox==3.6.1
-virtualenv==16.1.0
+tox==3.13.2
+virtualenv==16.6.1
+zipp==0.5.1
diff --git a/misc/userscripts/README.md b/misc/userscripts/README.md
index ceddb6c81..112c39904 100644
--- a/misc/userscripts/README.md
+++ b/misc/userscripts/README.md
@@ -43,7 +43,7 @@ The following userscripts can be found on their own repositories.
- [qutebrowser-zotero](https://github.com/parchd-1/qutebrowser-zotero): connects
qutebrowser to [Zotero][] standalone.
- [qute.match](https://github.com/bziur/qute.match): execute script based on
- visisted url.
+ visited url.
- [qutepocket](https://github.com/kepi/qutepocket): Add URL to your [Pocket][]
bookmark manager.
- [qb-scripts](https://github.com/peterjschroeder/qb-scripts): a small pack of
diff --git a/misc/userscripts/dmenu_qutebrowser b/misc/userscripts/dmenu_qutebrowser
index 82e6d2f18..044889b1d 100755
--- a/misc/userscripts/dmenu_qutebrowser
+++ b/misc/userscripts/dmenu_qutebrowser
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015 Zach-Button <zachrey.button@gmail.com>
-# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/misc/userscripts/format_json b/misc/userscripts/format_json
index 0d476b327..541408c70 100755
--- a/misc/userscripts/format_json
+++ b/misc/userscripts/format_json
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
set -euo pipefail
#
# Behavior:
@@ -9,10 +9,9 @@ set -euo pipefail
# syntax highlighting using pygments.
#
# In order to use this script, just start it using `spawn --userscript` from
-# qutebrowser. I recommend using an alias, e.g. put this in the
-# [alias]-section of qutebrowser.conf:
+# qutebrowser. I recommend using an alias, e.g.
#
-# json = spawn --userscript /path/to/json_format
+# :config-dict-add aliases json "spawn --userscript /path/to/json_format"
#
# Note that the color style defaults to monokai, but a different pygments style
# can be passed as the first parameter to the script. A full list of the pygments
@@ -25,7 +24,7 @@ MAX_SIZE_PRETTIFY=10485760 # 10 MB
# default style to monokai if none is provided
STYLE=${1:-monokai}
-TEMP_FILE="$(mktemp)"
+TEMP_FILE="$(mktemp --suffix .html)"
jq . "$QUTE_TEXT" >"$TEMP_FILE"
# try GNU stat first and then OSX stat if the former fails
diff --git a/misc/userscripts/open_download b/misc/userscripts/open_download
index 8dbb11384..e6de005c8 100755
--- a/misc/userscripts/open_download
+++ b/misc/userscripts/open_download
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Both standalone script and qutebrowser userscript that opens a rofi menu with
-# all files from the download director and opens the selected file. It works
+# all files from the download directory and opens the selected file. It works
# both as a userscript and a standalone script that is called from outside of
# qutebrowser.
#
diff --git a/misc/userscripts/openfeeds b/misc/userscripts/openfeeds
index 4a1a942e6..11feca966 100755
--- a/misc/userscripts/openfeeds
+++ b/misc/userscripts/openfeeds
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015 jnphilipp <me@jnphilipp.org>
-# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/misc/userscripts/qute-keepass b/misc/userscripts/qute-keepass
index a21ebc9b3..071a8e95e 100755
--- a/misc/userscripts/qute-keepass
+++ b/misc/userscripts/qute-keepass
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright 2018 Jay Kamat <jaygkamat@gmail.com>
+# Copyright 2018-2019 Jay Kamat <jaygkamat@gmail.com>
#
# This file is part of qutebrowser.
#
@@ -148,7 +148,7 @@ def dmenu(items, invocation, encoding):
def get_password():
"""Get a keepass db password from user."""
- _app = QApplication(sys.argv)
+ _app = QApplication(sys.argv) # don't remove this local variable
text, ok = QInputDialog.getText(
None, "KeePass DB Password",
"Please enter your KeePass Master Password",
diff --git a/misc/userscripts/qute-pass b/misc/userscripts/qute-pass
index ca9c4d4ca..838b91b4a 100755
--- a/misc/userscripts/qute-pass
+++ b/misc/userscripts/qute-pass
@@ -55,7 +55,8 @@ import tldextract
argument_parser = argparse.ArgumentParser(description=__doc__, usage=USAGE, epilog=EPILOG)
argument_parser.add_argument('url', nargs='?', default=os.getenv('QUTE_URL'))
-argument_parser.add_argument('--password-store', '-p', default=os.path.expanduser('~/.password-store'),
+argument_parser.add_argument('--password-store', '-p',
+ default=os.getenv('PASSWORD_STORE_DIR', default=os.path.expanduser('~/.password-store')),
help='Path to your pass password-store')
argument_parser.add_argument('--username-pattern', '-u', default=r'.*/(.+)',
help='Regular expression that matches the username')
@@ -97,13 +98,19 @@ def qute_command(command):
def find_pass_candidates(domain, password_store_path):
candidates = []
for path, directories, file_names in os.walk(password_store_path, followlinks=True):
- if directories or domain not in path.split(os.path.sep):
+ secrets = fnmatch.filter(file_names, '*.gpg')
+ if not secrets:
continue
# Strip password store path prefix to get the relative pass path
pass_path = path[len(password_store_path) + 1:]
- secrets = fnmatch.filter(file_names, '*.gpg')
- candidates.extend(os.path.join(pass_path, os.path.splitext(secret)[0]) for secret in secrets)
+ split_path = pass_path.split(os.path.sep)
+ for secret in secrets:
+ secret_base = os.path.splitext(secret)[0]
+ if domain not in (split_path + [secret_base]):
+ continue
+
+ candidates.append(os.path.join(pass_path, secret_base))
return candidates
@@ -146,7 +153,9 @@ def main(arguments):
# Try to find candidates using targets in the following order: fully-qualified domain name (includes subdomains),
# the registered domain name and finally: the IPv4 address if that's what the URL represents
candidates = set()
+ attempted_targets = []
for target in filter(None, [extract_result.fqdn, extract_result.registered_domain, extract_result.ipv4]):
+ attempted_targets.append(target)
target_candidates = find_pass_candidates(target, password_store_path)
if not target_candidates:
continue
@@ -156,7 +165,7 @@ def main(arguments):
break
else:
if not candidates:
- stderr('No pass candidates for URL {!r} found!'.format(arguments.url))
+ stderr('No pass candidates for URL {!r} found! (I tried {!r})'.format(arguments.url, attempted_targets))
return ExitCodes.NO_PASS_CANDIDATES
selection = candidates.pop() if len(candidates) == 1 else dmenu(sorted(candidates), arguments.dmenu_invocation,
diff --git a/mypy.ini b/mypy.ini
index d8c7221ad..0607ddfdf 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -18,6 +18,9 @@ disallow_untyped_decorators = True
# no_implicit_optional = True
# warn_return_any = True
+# Other strictness flags
+strict_equality = True
+
[mypy-colorama]
# https://github.com/tartley/colorama/issues/206
ignore_missing_imports = True
diff --git a/pytest.ini b/pytest.ini
index c278b0591..5f4211ab0 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,6 +1,6 @@
[pytest]
log_level = NOTSET
-addopts = --strict -rfEw --faulthandler-timeout=90 --instafail --benchmark-columns=Min,Max,Median
+addopts = --strict -rfEw --instafail --benchmark-columns=Min,Max,Median
testpaths = tests
markers =
gui: Tests using the GUI (e.g. spawning widgets)
@@ -65,10 +65,9 @@ qt_log_ignore =
^Icon theme ".*" not found
^Error receiving trust for a CA certificate
^QBackingStore::endPaint\(\) called with active painter on backingstore paint device
+ ^QPaintDevice: Cannot destroy paint device that is being painted
+ ^DirectWrite: CreateFontFaceFromHDC\(\) failed .*
+ ^Attribute Qt::AA_ShareOpenGLContexts must be set before QCoreApplication is created\.
xfail_strict = true
-filterwarnings =
- error
- # This happens in many qutebrowser dependencies...
- ignore:Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working:DeprecationWarning
- # WORKAROUND for https://github.com/ionelmc/pytest-benchmark/issues/124
- ignore:Node\.warn\(code, message\) form has been deprecated, use Node\.warn\(warning_instance\) instead:pytest.PytestDeprecationWarning
+filterwarnings = error
+faulthandler_timeout = 90
diff --git a/qutebrowser.py b/qutebrowser.py
index 8dd81b01a..392db932c 100755
--- a/qutebrowser.py
+++ b/qutebrowser.py
@@ -2,7 +2,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/__init__.py b/qutebrowser/__init__.py
index 8be3df172..f7b76b71f 100644
--- a/qutebrowser/__init__.py
+++ b/qutebrowser/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -22,11 +22,11 @@
import os.path
__author__ = "Florian Bruhin"
-__copyright__ = "Copyright 2014-2018 Florian Bruhin (The Compiler)"
+__copyright__ = "Copyright 2014-2019 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
-__version_info__ = (1, 5, 2)
+__version_info__ = (1, 6, 3)
__version__ = '.'.join(str(e) for e in __version_info__)
__description__ = "A keyboard-driven, vim-like browser based on PyQt5."
diff --git a/qutebrowser/__main__.py b/qutebrowser/__main__.py
index 533cf6e67..9bbe390e5 100644
--- a/qutebrowser/__main__.py
+++ b/qutebrowser/__main__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/api/__init__.py b/qutebrowser/api/__init__.py
index 648887005..c579e52bc 100644
--- a/qutebrowser/api/__init__.py
+++ b/qutebrowser/api/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/api/apitypes.py b/qutebrowser/api/apitypes.py
index 8fbc1a9a7..dc0e8fa11 100644
--- a/qutebrowser/api/apitypes.py
+++ b/qutebrowser/api/apitypes.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/api/cmdutils.py b/qutebrowser/api/cmdutils.py
index cd43079ad..0efc187a5 100644
--- a/qutebrowser/api/cmdutils.py
+++ b/qutebrowser/api/cmdutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/api/config.py b/qutebrowser/api/config.py
index 0c633e54d..da6c40179 100644
--- a/qutebrowser/api/config.py
+++ b/qutebrowser/api/config.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/api/downloads.py b/qutebrowser/api/downloads.py
index a2a37d931..70389bc51 100644
--- a/qutebrowser/api/downloads.py
+++ b/qutebrowser/api/downloads.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/api/hook.py b/qutebrowser/api/hook.py
index 84e103cbd..0a9be4595 100644
--- a/qutebrowser/api/hook.py
+++ b/qutebrowser/api/hook.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/api/interceptor.py b/qutebrowser/api/interceptor.py
index 78819dc46..f19d30897 100644
--- a/qutebrowser/api/interceptor.py
+++ b/qutebrowser/api/interceptor.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -27,6 +27,9 @@ from qutebrowser.extensions.interceptors import Request
#: Type annotation for an interceptor function.
InterceptorType = interceptors.InterceptorType
+#: Possible resource types for requests sent to interceptor.
+ResourceType = interceptors.ResourceType
+
def register(interceptor: InterceptorType) -> None:
"""Register a request interceptor.
diff --git a/qutebrowser/api/message.py b/qutebrowser/api/message.py
index fdb06354f..a225e12c0 100644
--- a/qutebrowser/api/message.py
+++ b/qutebrowser/api/message.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/app.py b/qutebrowser/app.py
index 2b6896b76..eb468d6d1 100644
--- a/qutebrowser/app.py
+++ b/qutebrowser/app.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -83,7 +83,7 @@ from qutebrowser.misc import utilcmds
# pylint: enable=unused-import
-qApp = None
+q_app = None
def run(args):
@@ -101,25 +101,25 @@ def run(args):
log.init.debug("Initializing config...")
configinit.early_init(args)
- global qApp
- qApp = Application(args)
- qApp.setOrganizationName("qutebrowser")
- qApp.setApplicationName("qutebrowser")
- qApp.setDesktopFileName("qutebrowser")
- qApp.setApplicationVersion(qutebrowser.__version__)
- qApp.lastWindowClosed.connect(quitter.on_last_window_closed)
+ global q_app
+ q_app = Application(args)
+ q_app.setOrganizationName("qutebrowser")
+ q_app.setApplicationName("qutebrowser")
+ q_app.setDesktopFileName("org.qutebrowser.qutebrowser")
+ q_app.setApplicationVersion(qutebrowser.__version__)
+ q_app.lastWindowClosed.connect(quitter.on_last_window_closed)
if args.version:
print(version.version())
sys.exit(usertypes.Exit.ok)
crash_handler = crashsignal.CrashHandler(
- app=qApp, quitter=quitter, args=args, parent=qApp)
+ app=q_app, quitter=quitter, args=args, parent=q_app)
crash_handler.activate()
objreg.register('crash-handler', crash_handler)
- signal_handler = crashsignal.SignalHandler(app=qApp, quitter=quitter,
- parent=qApp)
+ signal_handler = crashsignal.SignalHandler(app=q_app, quitter=quitter,
+ parent=q_app)
signal_handler.activate()
objreg.register('signal-handler', signal_handler)
@@ -151,7 +151,7 @@ def qt_mainloop():
WARNING: misc/crashdialog.py checks the stacktrace for this function
name, so if this is changed, it should be changed there as well!
"""
- return qApp.exec_()
+ return q_app.exec_()
def init(args, crash_handler):
@@ -162,7 +162,10 @@ def init(args, crash_handler):
crash_handler: The CrashHandler instance.
"""
log.init.debug("Starting init...")
- qApp.setQuitOnLastWindowClosed(False)
+
+ crash_handler.init_faulthandler()
+
+ q_app.setQuitOnLastWindowClosed(False)
_init_icon()
loader.init()
@@ -175,12 +178,12 @@ def init(args, crash_handler):
sys.exit(usertypes.Exit.err_init)
log.init.debug("Initializing eventfilter...")
- event_filter = EventFilter(qApp)
- qApp.installEventFilter(event_filter)
+ event_filter = EventFilter(q_app)
+ q_app.installEventFilter(event_filter)
objreg.register('event-filter', event_filter)
log.init.debug("Connecting signals...")
- qApp.focusChanged.connect(on_focus_changed)
+ q_app.focusChanged.connect(on_focus_changed)
_process_args(args)
@@ -207,7 +210,7 @@ def _init_icon():
if icon.isNull():
log.init.warning("Failed to load icon")
else:
- qApp.setWindowIcon(icon)
+ q_app.setWindowIcon(icon)
def _process_args(args):
@@ -217,10 +220,15 @@ def _process_args(args):
session_manager = objreg.get('session-manager')
if not session_manager.did_load:
log.init.debug("Initializing main window...")
+ if config.val.content.private_browsing and qtutils.is_single_process():
+ err = Exception("Private windows are unavailable with "
+ "the single-process process model.")
+ error.handle_fatal_exc(err, args, 'Cannot start in private mode')
+ sys.exit(usertypes.Exit.err_init)
window = mainwindow.MainWindow(private=None)
if not args.nowindow:
window.show()
- qApp.setActiveWindow(window)
+ q_app.setActiveWindow(window)
process_pos_args(args.command)
_open_startpage()
@@ -425,7 +433,7 @@ def _init_modules(args, crash_handler):
crash_handler: The CrashHandler instance.
"""
log.init.debug("Initializing save manager...")
- save_manager = savemanager.SaveManager(qApp)
+ save_manager = savemanager.SaveManager(q_app)
objreg.register('save-manager', save_manager)
configinit.late_init(save_manager)
@@ -441,54 +449,55 @@ def _init_modules(args, crash_handler):
log.init.debug("Initializing proxy...")
proxy.init()
+ log.init.debug("Initializing downloads...")
+ downloads.init()
+
log.init.debug("Initializing readline-bridge...")
readline_bridge = readline.ReadlineBridge()
objreg.register('readline-bridge', readline_bridge)
try:
- log.init.debug("Initializing sql...")
+ log.init.debug("Initializing SQL...")
sql.init(os.path.join(standarddir.data(), 'history.sqlite'))
log.init.debug("Initializing web history...")
- history.init(qApp)
- except sql.SqlEnvironmentError as e:
+ history.init(q_app)
+ except sql.KnownError as e:
error.handle_fatal_exc(e, args, 'Error initializing SQL',
pre_text='Error initializing SQL')
sys.exit(usertypes.Exit.err_init)
log.init.debug("Initializing command history...")
cmdhistory.init()
-
- log.init.debug("Initializing crashlog...")
- if not args.no_err_windows:
- crash_handler.handle_segfault()
-
log.init.debug("Initializing sessions...")
- sessions.init(qApp)
+ sessions.init(q_app)
log.init.debug("Initializing websettings...")
websettings.init(args)
+ if not args.no_err_windows:
+ crash_handler.display_faulthandler()
+
log.init.debug("Initializing quickmarks...")
- quickmark_manager = urlmarks.QuickmarkManager(qApp)
+ quickmark_manager = urlmarks.QuickmarkManager(q_app)
objreg.register('quickmark-manager', quickmark_manager)
log.init.debug("Initializing bookmarks...")
- bookmark_manager = urlmarks.BookmarkManager(qApp)
+ bookmark_manager = urlmarks.BookmarkManager(q_app)
objreg.register('bookmark-manager', bookmark_manager)
log.init.debug("Initializing cookies...")
- cookie_jar = cookies.CookieJar(qApp)
- ram_cookie_jar = cookies.RAMCookieJar(qApp)
+ cookie_jar = cookies.CookieJar(q_app)
+ ram_cookie_jar = cookies.RAMCookieJar(q_app)
objreg.register('cookie-jar', cookie_jar)
objreg.register('ram-cookie-jar', ram_cookie_jar)
log.init.debug("Initializing cache...")
- diskcache = cache.DiskCache(standarddir.cache(), parent=qApp)
+ diskcache = cache.DiskCache(standarddir.cache(), parent=q_app)
objreg.register('cache', diskcache)
log.init.debug("Initializing downloads...")
- download_manager = qtnetworkdownloads.DownloadManager(parent=qApp)
+ download_manager = qtnetworkdownloads.DownloadManager(parent=q_app)
objreg.register('qtnetwork-download-manager', download_manager)
log.init.debug("Initializing Greasemonkey...")
@@ -735,7 +744,7 @@ class Quitter:
def _shutdown(self, status, restart): # noqa
"""Second stage of shutdown."""
log.destroy.debug("Stage 2 of shutting down...")
- if qApp is None:
+ if q_app is None:
# No QApplication exists yet, so quit hard.
sys.exit(status)
# Remove eventfilter
@@ -743,7 +752,7 @@ class Quitter:
log.destroy.debug("Removing eventfilter...")
event_filter = objreg.get('event-filter', None)
if event_filter is not None:
- qApp.removeEventFilter(event_filter)
+ q_app.removeEventFilter(event_filter)
except AttributeError:
pass
# Close all windows
@@ -792,7 +801,7 @@ class Quitter:
session_manager.delete_autosave()
# We use a singleshot timer to exit here to minimize the likelihood of
# segfaults.
- QTimer.singleShot(0, functools.partial(qApp.exit, status))
+ QTimer.singleShot(0, functools.partial(q_app.exit, status))
class Application(QApplication):
@@ -893,7 +902,7 @@ class EventFilter(QObject):
Return:
True if the event should be filtered, False if it's passed through.
"""
- if qApp.activeWindow() not in objreg.window_registry.values():
+ if q_app.activeWindow() not in objreg.window_registry.values():
# Some other window (print dialog, etc.) is focused so we pass the
# event through.
return False
diff --git a/qutebrowser/browser/__init__.py b/qutebrowser/browser/__init__.py
index b565801d3..9b8251a75 100644
--- a/qutebrowser/browser/__init__.py
+++ b/qutebrowser/browser/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py
index 55ab89a20..67fad967c 100644
--- a/qutebrowser/browser/browsertab.py
+++ b/qutebrowser/browser/browsertab.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -437,6 +437,7 @@ class AbstractCaret(QObject):
self._tab = tab
self._widget = None
self.selection_enabled = False
+ self._mode_manager = mode_manager
mode_manager.entered.connect(self._on_mode_entered)
mode_manager.left.connect(self._on_mode_left)
@@ -500,6 +501,9 @@ class AbstractCaret(QObject):
def selection(self, callback: typing.Callable[[str], None]) -> None:
raise NotImplementedError
+ def reverse_selection(self) -> None:
+ raise NotImplementedError
+
def _follow_enter(self, tab: bool) -> None:
"""Follow a link by faking an enter press."""
if tab:
@@ -1012,7 +1016,19 @@ class AbstractTab(QWidget):
return
sess_manager.save_autosave()
+ self.load_finished.emit(ok)
+
+ if not self.title():
+ self.title_changed.emit(self.url().toDisplayString())
+
+ self.zoom.reapply()
+ def _update_load_status(self, ok: bool) -> None:
+ """Update the load status after a page finished loading.
+
+ Needs to be called by subclasses to trigger a load status update, e.g.
+ as a response to a loadFinished signal.
+ """
if ok and not self._has_ssl_errors:
if self.url().scheme() == 'https':
self._set_load_status(usertypes.LoadStatus.success_https)
@@ -1023,13 +1039,6 @@ class AbstractTab(QWidget):
else:
self._set_load_status(usertypes.LoadStatus.error)
- self.load_finished.emit(ok)
-
- if not self.title():
- self.title_changed.emit(self.url().toDisplayString())
-
- self.zoom.reapply()
-
@pyqtSlot()
def _on_history_trigger(self) -> None:
"""Emit history_item_triggered based on backend-specific signal."""
diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py
index 6ae47f9d9..0b6791100 100644
--- a/qutebrowser/browser/commands.py
+++ b/qutebrowser/browser/commands.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -479,7 +479,7 @@ class CommandDispatcher:
# Catch common cases before e.g. cloning tab
if not forward and not history.can_go_back():
raise cmdutils.CommandError("At beginning of history.")
- elif forward and not history.can_go_forward():
+ if forward and not history.can_go_forward():
raise cmdutils.CommandError("At end of history.")
if tab or bg or window:
@@ -646,9 +646,11 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('what', choices=['selection', 'url', 'pretty-url',
- 'title', 'domain', 'markdown'])
- def yank(self, what='url', sel=False, keep=False, quiet=False):
- """Yank something to the clipboard or primary selection.
+ 'title', 'domain', 'markdown',
+ 'inline'])
+ def yank(self, what='url', inline=None,
+ sel=False, keep=False, quiet=False):
+ """Yank (copy) something to the clipboard or primary selection.
Args:
what: What to yank.
@@ -658,13 +660,20 @@ class CommandDispatcher:
- `title`: The current page's title.
- `domain`: The current scheme, domain, and port number.
- `selection`: The selection under the cursor.
- - `markdown`: Yank title and URL in markdown format.
+ - `markdown`: Yank title and URL in markdown format
+ (deprecated, use `:yank inline [{title}]({url})` instead).
+ - `inline`: Yank the text contained in the 'inline' argument.
sel: Use the primary selection instead of the clipboard.
keep: Stay in visual mode after yanking the selection.
quiet: Don't show an information message.
+ inline: A block of text, to be yanked if 'what'
+ is inline and ignored otherwise.
"""
- if what == 'title':
+ if what == 'inline':
+ s = inline
+ what = 'inline block'
+ elif what == 'title':
s = self._tabbed_browser.widget.page_title(self._current_index())
elif what == 'domain':
port = self._current_url().port()
@@ -685,6 +694,8 @@ class CommandDispatcher:
caret.selection(callback=_selection_callback)
return
elif what == 'markdown':
+ message.warning(":yank markdown is deprecated, use `:yank inline "
+ "[{title}]({url})` instead.")
idx = self._current_index()
title = self._tabbed_browser.widget.page_title(idx)
url = self._yank_url(what)
@@ -1026,7 +1037,10 @@ class CommandDispatcher:
proc = guiprocess.GUIProcess(what='command', verbose=verbose,
parent=self._tabbed_browser)
if detach:
- proc.start_detached(cmd, args)
+ ok = proc.start_detached(cmd, args)
+ if not ok:
+ message.info("Hint: Try without --detach for a more "
+ "detailed error")
else:
proc.start(cmd, args)
proc.finished.connect(_on_proc_finished)
@@ -1196,6 +1210,7 @@ class CommandDispatcher:
objreg.get('bookmark-manager').delete(url)
except KeyError:
raise cmdutils.CommandError("Bookmark '{}' not found!".format(url))
+ message.info("Removed bookmark {}".format(url))
@cmdutils.register(instance='command-dispatcher', name='inspector',
scope='window')
@@ -1706,11 +1721,13 @@ class CommandDispatcher:
private=private, related=related)
@cmdutils.register(instance='command-dispatcher', scope='window')
- def fullscreen(self, leave=False):
+ def fullscreen(self, leave=False, enter=False):
"""Toggle fullscreen mode.
Args:
leave: Only leave fullscreen if it was entered by the page.
+ enter: Activate fullscreen and do not toggle if it is already
+ active.
"""
if leave:
tab = self._current_widget()
@@ -1724,7 +1741,10 @@ class CommandDispatcher:
if not window.isFullScreen():
window.state_before_fullscreen = window.windowState()
- window.setWindowState(window.windowState() ^ Qt.WindowFullScreen)
+ if enter:
+ window.setWindowState(window.windowState() | Qt.WindowFullScreen)
+ else:
+ window.setWindowState(window.windowState() ^ Qt.WindowFullScreen)
log.misc.debug('state before fullscreen: {}'.format(
debug.qflags_key(Qt, window.state_before_fullscreen)))
diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py
index b18e426d7..9dc143140 100644
--- a/qutebrowser/browser/downloads.py
+++ b/qutebrowser/browser/downloads.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -50,7 +50,6 @@ class ModelRole(enum.IntEnum):
# Remember the last used directory
last_used_directory = None
-
# All REFRESH_INTERVAL milliseconds, speeds will be recalculated and downloads
# redrawn.
_REFRESH_INTERVAL = 500
@@ -70,6 +69,20 @@ class UnsupportedOperationError(Exception):
"""Raised when an operation is not supported with the given backend."""
+def init():
+ """Set the application wide downloads variables."""
+ global last_used_directory
+ last_used_directory = None
+
+ config.instance.changed.connect(_clear_last_used)
+
+
+@config.change_filter('downloads.location.directory', function=True)
+def _clear_last_used():
+ global last_used_directory
+ last_used_directory = None
+
+
def download_dir():
"""Get the download directory to use."""
directory = config.val.downloads.location.directory
@@ -1105,8 +1118,7 @@ class DownloadModel(QAbstractListModel):
to_retry = [d for d in self if d.done and not d.successful]
if not to_retry:
raise cmdutils.CommandError("No failed downloads!")
- else:
- download = to_retry[0]
+ download = to_retry[0]
download.try_retry()
def can_clear(self):
@@ -1258,7 +1270,7 @@ class TempDownloadManager:
Args:
suggested_name: str of the "suggested"/original filename. Used as a
- suffix, so any file extenions are preserved.
+ suffix, so any file extensions are preserved.
Return:
A tempfile.NamedTemporaryFile that should be used to save the file.
diff --git a/qutebrowser/browser/downloadview.py b/qutebrowser/browser/downloadview.py
index 1ea2b6744..fc45fe26c 100644
--- a/qutebrowser/browser/downloadview.py
+++ b/qutebrowser/browser/downloadview.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/greasemonkey.py b/qutebrowser/browser/greasemonkey.py
index 9314f81c6..3a5b60544 100644
--- a/qutebrowser/browser/greasemonkey.py
+++ b/qutebrowser/browser/greasemonkey.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -31,7 +31,8 @@ import attr
from PyQt5.QtCore import pyqtSignal, QObject, QUrl
from qutebrowser.utils import (log, standarddir, jinja, objreg, utils,
- javascript, urlmatch, version, usertypes)
+ javascript, urlmatch, version, usertypes,
+ qtutils)
from qutebrowser.api import cmdutils
from qutebrowser.browser import downloads
from qutebrowser.misc import objects
@@ -116,6 +117,40 @@ class GreasemonkeyScript:
script.includes = ['*']
return script
+ def needs_document_end_workaround(self):
+ """Check whether to force @run-at document-end.
+
+ This needs to be done on QtWebEngine with Qt 5.12 for known-broken
+ scripts.
+
+ On Qt 5.12, accessing the DOM isn't possible with "@run-at
+ document-start". It was documented to be impossible before, but seems
+ to work fine.
+
+ However, some scripts do DOM access with "@run-at document-start". Fix
+ those by forcing them to use document-end instead.
+ """
+ if objects.backend != usertypes.Backend.QtWebEngine:
+ return False
+ elif not qtutils.version_check('5.12', compiled=False):
+ return False
+
+ broken_scripts = [
+ ('http://userstyles.org', None),
+ ('https://github.com/ParticleCore', 'Iridium'),
+ ]
+ return any(self._matches_id(namespace=namespace, name=name)
+ for namespace, name in broken_scripts)
+
+ def _matches_id(self, *, namespace, name):
+ """Check if this script matches the given namespace/name.
+
+ Both namespace and name can be None in order to match any script.
+ """
+ matches_namespace = namespace is None or self.namespace == namespace
+ matches_name = name is None or self.name == name
+ return matches_namespace and matches_name
+
def code(self):
"""Return the processed JavaScript code of this script.
diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py
index 43257d0a8..13c89ff6b 100644
--- a/qutebrowser/browser/hints.py
+++ b/qutebrowser/browser/hints.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -41,7 +41,8 @@ from qutebrowser.utils import usertypes, log, qtutils, message, objreg, utils
Target = enum.Enum('Target', ['normal', 'current', 'tab', 'tab_fg', 'tab_bg',
'window', 'yank', 'yank_primary', 'run', 'fill',
- 'hover', 'download', 'userscript', 'spawn'])
+ 'hover', 'download', 'userscript', 'spawn',
+ 'delete'])
class HintingError(Exception):
@@ -65,24 +66,16 @@ class HintLabel(QLabel):
_context: The current hinting context.
"""
- STYLESHEET = """
- QLabel {
- background-color: {{ conf.colors.hints.bg }};
- color: {{ conf.colors.hints.fg }};
- font: {{ conf.fonts.hints }};
- border: {{ conf.hints.border }};
- padding-left: -3px;
- padding-right: -3px;
- }
- """
-
def __init__(self, elem, context):
super().__init__(parent=context.tab)
self._context = context
self.elem = elem
+ # Make sure we can style the background via a style sheet, and we don't
+ # get any extra text indent from Qt.
+ # The real stylesheet lives in mainwindow.py for performance reasons..
self.setAttribute(Qt.WA_StyledBackground, True)
- config.set_register_stylesheet(self)
+ self.setIndent(0)
self._context.tab.contents_size_changed.connect(self._move_to_elem)
self._move_to_elem()
@@ -155,6 +148,7 @@ class HintContext:
download: Download the link.
userscript: Call a custom userscript.
spawn: Spawn a simple command.
+ delete: Delete the selected element.
to_follow: The link to follow when enter is pressed.
args: Custom arguments for userscript/spawn
rapid: Whether to do rapid hinting.
@@ -335,6 +329,9 @@ class HintActions:
except userscripts.Error as e:
raise HintingError(str(e))
+ def delete(self, elem, _context):
+ elem.delete()
+
def spawn(self, url, context):
"""Spawn a simple command from a hint.
@@ -379,6 +376,7 @@ class HintManager(QObject):
Target.download: "Download hint",
Target.userscript: "Call userscript via hint",
Target.spawn: "Spawn command via hint",
+ Target.delete: "Delete an element",
}
def __init__(self, win_id, tab_id, parent=None):
@@ -599,6 +597,18 @@ class HintManager(QObject):
message.error("No elements found.")
return
+ # Because _start_cb is called asynchronously, it's possible that the
+ # user switched to another tab or closed the tab/window. In that case
+ # we should not start hinting.
+ tabbed_browser = objreg.get('tabbed-browser', default=None,
+ scope='window', window=self._win_id)
+ tab = tabbed_browser.widget.currentWidget()
+ if tab.tab_id != self._tab_id:
+ log.hints.debug(
+ "Current tab changed ({} -> {}) before _start_cb is run."
+ .format(self._tab_id, tab.tab_id))
+ return
+
strings = self._hint_strings(elems)
log.hints.debug("hints: {}".format(', '.join(strings)))
@@ -636,7 +646,7 @@ class HintManager(QObject):
rapid: Whether to do rapid hinting. With rapid hinting, the hint
mode isn't left after a hint is followed, so you can easily
open multiple links. This is only possible with targets
- `tab` (with `tabs.background_tabs=true`), `tab-bg`,
+ `tab` (with `tabs.background=true`), `tab-bg`,
`window`, `run`, `hover`, `userscript` and `spawn`.
add_history: Whether to add the spawned or yanked link to the
browsing history.
@@ -656,7 +666,7 @@ class HintManager(QObject):
- `normal`: Open the link.
- `current`: Open the link in the current tab.
- `tab`: Open the link in a new tab (honoring the
- `tabs.background_tabs` setting).
+ `tabs.background` setting).
- `tab-fg`: Open the link in a new foreground tab.
- `tab-bg`: Open the link in a new background tab.
- `window`: Open the link in a new window.
@@ -670,6 +680,7 @@ class HintManager(QObject):
- `userscript`: Call a userscript with `$QUTE_URL` set to the
link.
- `spawn`: Spawn a command.
+ - `delete`: Delete the selected element.
mode: The hinting mode to use.
@@ -896,6 +907,7 @@ class HintManager(QObject):
# _download needs a QWebElement to get the frame.
Target.download: self._actions.download,
Target.userscript: self._actions.call_userscript,
+ Target.delete: self._actions.delete,
}
# Handlers which take a QUrl
url_handlers = {
@@ -956,10 +968,9 @@ class HintManager(QObject):
if keystring is None:
if self._context.to_follow is None:
raise cmdutils.CommandError("No hint to follow")
- elif select:
+ if select:
raise cmdutils.CommandError("Can't use --select without hint.")
- else:
- keystring = self._context.to_follow
+ keystring = self._context.to_follow
elif keystring not in self._context.labels:
raise cmdutils.CommandError("No hint {}!".format(keystring))
diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py
index 757a72e41..d49000d29 100644
--- a/qutebrowser/browser/history.py
+++ b/qutebrowser/browser/history.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -148,6 +148,8 @@ class WebHistory(sql.SqlTable):
'redirect': 'NOT NULL'},
parent=parent)
self._progress = progress
+ # Store the last saved url to avoid duplicate immedate saves.
+ self._last_url = None
self.completion = CompletionHistory(parent=self)
self.metainfo = CompletionMetaInfo(parent=self)
@@ -195,7 +197,7 @@ class WebHistory(sql.SqlTable):
def _handle_sql_errors(self):
try:
yield
- except sql.SqlEnvironmentError as e:
+ except sql.KnownError as e:
message.error("Failed to write history: {}".format(e.text()))
def _is_excluded(self, url):
@@ -276,6 +278,7 @@ class WebHistory(sql.SqlTable):
self.delete_all()
self.completion.delete_all()
self.history_cleared.emit()
+ self._last_url = None
def delete_url(self, url):
"""Remove all history entries with the given url.
@@ -287,6 +290,8 @@ class WebHistory(sql.SqlTable):
qtutils.ensure_valid(qurl)
self.delete('url', self._format_url(qurl))
self.completion.delete('url', self._format_completion_url(qurl))
+ if self._last_url == url:
+ self._last_url = None
self.url_cleared.emit(qurl)
@pyqtSlot(QUrl, QUrl, str)
@@ -306,7 +311,9 @@ class WebHistory(sql.SqlTable):
# If the url of the page is different than the url of the link
# originally clicked, save them both.
self.add_url(requested_url, title, redirect=True)
- self.add_url(url, title)
+ if url != self._last_url:
+ self.add_url(url, title)
+ self._last_url = url
def add_url(self, url, title="", *, redirect=False, atime=None):
"""Called via add_from_tab when a URL should be added to the history.
diff --git a/qutebrowser/browser/inspector.py b/qutebrowser/browser/inspector.py
index 3334cea4e..9b9e37504 100644
--- a/qutebrowser/browser/inspector.py
+++ b/qutebrowser/browser/inspector.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/mouse.py b/qutebrowser/browser/mouse.py
index a73f28203..c2e39663b 100644
--- a/qutebrowser/browser/mouse.py
+++ b/qutebrowser/browser/mouse.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/navigate.py b/qutebrowser/browser/navigate.py
index 240878ed6..a7bf50bb6 100644
--- a/qutebrowser/browser/navigate.py
+++ b/qutebrowser/browser/navigate.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/network/pac.py b/qutebrowser/browser/network/pac.py
index 1c6075945..cb3819bce 100644
--- a/qutebrowser/browser/network/pac.py
+++ b/qutebrowser/browser/network/pac.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -142,7 +142,8 @@ class PACResolver:
config = [c.strip() for c in proxy_str.split(' ') if c]
if not config:
raise ParseProxyError("Empty proxy entry")
- elif config[0] == "DIRECT":
+
+ if config[0] == "DIRECT":
if len(config) != 1:
raise ParseProxyError("Invalid number of parameters for " +
"DIRECT")
@@ -180,6 +181,8 @@ class PACResolver:
"""
self._engine = QJSEngine()
+ self._engine.installExtensions(QJSEngine.ConsoleExtension)
+
self._ctx = _PACContext(self._engine)
self._engine.globalObject().setProperty(
"PAC", self._engine.newQObject(self._ctx))
@@ -206,6 +209,8 @@ class PACResolver:
Return:
A list of QNetworkProxy objects in order of preference.
"""
+ qtutils.ensure_valid(query.url())
+
if from_file:
string_flags = QUrl.PrettyDecoded
else:
diff --git a/qutebrowser/browser/network/proxy.py b/qutebrowser/browser/network/proxy.py
index d3e25c23c..a14448512 100644
--- a/qutebrowser/browser/network/proxy.py
+++ b/qutebrowser/browser/network/proxy.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -20,10 +20,12 @@
"""Handling of proxies."""
+from PyQt5.QtCore import QUrl
from PyQt5.QtNetwork import QNetworkProxy, QNetworkProxyFactory
from qutebrowser.config import config, configtypes
-from qutebrowser.utils import objreg
+from qutebrowser.utils import objreg, message, usertypes, urlutils
+from qutebrowser.misc import objects
from qutebrowser.browser.network import pac
@@ -33,6 +35,18 @@ def init():
objreg.register('proxy-factory', proxy_factory)
QNetworkProxyFactory.setApplicationProxyFactory(proxy_factory)
+ config.instance.changed.connect(_warn_for_pac)
+ _warn_for_pac()
+
+
+@config.change_filter('content.proxy', function=True)
+def _warn_for_pac():
+ """Show a warning if PAC is used with QtWebEngine."""
+ proxy = config.val.content.proxy
+ if (isinstance(proxy, pac.PACFetcher) and
+ objects.backend == usertypes.Backend.QtWebEngine):
+ message.error("PAC support isn't implemented for QtWebEngine yet!")
+
def shutdown():
QNetworkProxyFactory.setApplicationProxyFactory(None)
@@ -70,7 +84,11 @@ class ProxyFactory(QNetworkProxyFactory):
# ref. http://doc.qt.io/qt-5/qnetworkproxyfactory.html#systemProxyForQuery
proxies = QNetworkProxyFactory.systemProxyForQuery(query)
elif isinstance(proxy, pac.PACFetcher):
- proxies = proxy.resolve(query)
+ if objects.backend == usertypes.Backend.QtWebEngine:
+ # Looks like query.url() is always invalid on QtWebEngine...
+ proxies = [urlutils.proxy_from_url(QUrl('direct://'))]
+ else:
+ proxies = proxy.resolve(query)
else:
proxies = [proxy]
for p in proxies:
diff --git a/qutebrowser/browser/pdfjs.py b/qutebrowser/browser/pdfjs.py
index 897f0407e..a5ae1b7f4 100644
--- a/qutebrowser/browser/pdfjs.py
+++ b/qutebrowser/browser/pdfjs.py
@@ -1,7 +1,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015 Daniel Schadt
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -131,6 +131,8 @@ def get_pdfjs_res_and_path(path):
# Debian pdf.js-common
# Arch Linux pdfjs (AUR)
'/usr/share/pdf.js/',
+ # Flatpak (Flathub)
+ '/app/share/pdf.js/',
# Arch Linux pdf.js (AUR)
'/usr/share/javascript/pdf.js/',
# Debian libjs-pdf
@@ -231,7 +233,8 @@ def should_use_pdfjs(mimetype, url):
is_download_url = (url.scheme() == 'blob' and
QUrl(url.path()).scheme() == 'qute')
is_pdf = mimetype in ['application/pdf', 'application/x-pdf']
- return is_pdf and not is_download_url and config.val.content.pdfjs
+ config_enabled = config.instance.get('content.pdfjs', url=url)
+ return is_pdf and not is_download_url and config_enabled
def get_main_url(filename):
diff --git a/qutebrowser/browser/qtnetworkdownloads.py b/qutebrowser/browser/qtnetworkdownloads.py
index bdd2b280a..5fb9ca95f 100644
--- a/qutebrowser/browser/qtnetworkdownloads.py
+++ b/qutebrowser/browser/qtnetworkdownloads.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py
index 14c43ad1e..606a05fc1 100644
--- a/qutebrowser/browser/qutescheme.py
+++ b/qutebrowser/browser/qutescheme.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -340,19 +340,11 @@ def qute_gpl(_url):
def _asciidoc_fallback_path(html_path):
"""Fall back to plaintext asciidoc if the HTML is unavailable."""
- asciidoc_path = html_path.replace('.html', '.asciidoc')
- asciidoc_paths = [asciidoc_path]
- if asciidoc_path.startswith('html/doc/'):
- asciidoc_paths += [asciidoc_path.replace('html/doc/', '../doc/help/'),
- asciidoc_path.replace('html/doc/', '../doc/')]
-
- for path in asciidoc_paths:
- try:
- return utils.read_file(path)
- except OSError:
- pass
-
- return None
+ path = html_path.replace('.html', '.asciidoc')
+ try:
+ return utils.read_file(path)
+ except OSError:
+ return None
@add_handler('help')
diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py
index 0bf3301f9..194dc5b36 100644
--- a/qutebrowser/browser/shared.py
+++ b/qutebrowser/browser/shared.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -42,7 +42,6 @@ def custom_headers(url):
if dnt_config is not None:
dnt = b'1' if dnt_config else b'0'
headers[b'DNT'] = dnt
- headers[b'X-Do-Not-Track'] = dnt
conf_headers = config.instance.get('content.headers.custom', url=url)
for header, value in conf_headers.items():
diff --git a/qutebrowser/browser/signalfilter.py b/qutebrowser/browser/signalfilter.py
index 7cc46abdb..356cd27a6 100644
--- a/qutebrowser/browser/signalfilter.py
+++ b/qutebrowser/browser/signalfilter.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/urlmarks.py b/qutebrowser/browser/urlmarks.py
index 4d25dde45..2ff71c2df 100644
--- a/qutebrowser/browser/urlmarks.py
+++ b/qutebrowser/browser/urlmarks.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Antoni Boucher <bouanto@zoho.com>
#
# This file is part of qutebrowser.
diff --git a/qutebrowser/browser/webelem.py b/qutebrowser/browser/webelem.py
index ac46fdcb9..4e5fd7bed 100644
--- a/qutebrowser/browser/webelem.py
+++ b/qutebrowser/browser/webelem.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -365,6 +365,10 @@ class AbstractWebElement(collections.abc.MutableMapping):
"""Fake a click by using the JS .click() method."""
raise NotImplementedError
+ def delete(self) -> None:
+ """Delete this element from the DOM."""
+ raise NotImplementedError
+
def _click_href(self, click_target: usertypes.ClickTarget) -> None:
"""Fake a click on an element with a href by opening the link."""
baseurl = self._tab.url()
diff --git a/qutebrowser/browser/webengine/__init__.py b/qutebrowser/browser/webengine/__init__.py
index 2649645d3..36a9a8b61 100644
--- a/qutebrowser/browser/webengine/__init__.py
+++ b/qutebrowser/browser/webengine/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webengine/certificateerror.py b/qutebrowser/browser/webengine/certificateerror.py
index 768f54ec6..c3d6c74ab 100644
--- a/qutebrowser/browser/webengine/certificateerror.py
+++ b/qutebrowser/browser/webengine/certificateerror.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webengine/cookies.py b/qutebrowser/browser/webengine/cookies.py
index e5abc20ea..7e5583152 100644
--- a/qutebrowser/browser/webengine/cookies.py
+++ b/qutebrowser/browser/webengine/cookies.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webengine/interceptor.py b/qutebrowser/browser/webengine/interceptor.py
index a5b7721b8..3f7618974 100644
--- a/qutebrowser/browser/webengine/interceptor.py
+++ b/qutebrowser/browser/webengine/interceptor.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -19,7 +19,9 @@
"""A request interceptor taking care of adblocking and custom headers."""
-from PyQt5.QtCore import QUrl
+import attr
+
+from PyQt5.QtCore import QUrl, QByteArray
from PyQt5.QtWebEngineCore import (QWebEngineUrlRequestInterceptor,
QWebEngineUrlRequestInfo)
@@ -29,10 +31,81 @@ from qutebrowser.utils import utils, log, debug
from qutebrowser.extensions import interceptors
-class RequestInterceptor(QWebEngineUrlRequestInterceptor):
+@attr.s
+class WebEngineRequest(interceptors.Request):
+
+ """QtWebEngine-specific request interceptor functionality."""
+
+ _WHITELISTED_REQUEST_METHODS = {QByteArray(b'GET'), QByteArray(b'HEAD')}
+
+ _webengine_info = attr.ib(default=None) # type: QWebEngineUrlRequestInfo
+ #: If this request has been redirected already
+ _redirected = attr.ib(init=False, default=False) # type: bool
+ def redirect(self, url: QUrl) -> None:
+ if self._redirected:
+ raise interceptors.RedirectFailedException(
+ "Request already redirected.")
+ if self._webengine_info is None:
+ raise interceptors.RedirectFailedException(
+ "Request improperly initialized.")
+ # Redirecting a request that contains payload data is not allowed.
+ # To be safe, abort on any request not in a whitelist.
+ if (self._webengine_info.requestMethod()
+ not in self._WHITELISTED_REQUEST_METHODS):
+ raise interceptors.RedirectFailedException(
+ "Request method does not support redirection.")
+ self._webengine_info.redirect(url)
+ self._redirected = True
+
+
+class RequestInterceptor(QWebEngineUrlRequestInterceptor):
"""Handle ad blocking and custom headers."""
+ # This dict should be from QWebEngine Resource Types to qutebrowser
+ # extension ResourceTypes. If a ResourceType is added to Qt, this table
+ # should be updated too.
+ RESOURCE_TYPES = {
+ QWebEngineUrlRequestInfo.ResourceTypeMainFrame:
+ interceptors.ResourceType.main_frame,
+ QWebEngineUrlRequestInfo.ResourceTypeSubFrame:
+ interceptors.ResourceType.sub_frame,
+ QWebEngineUrlRequestInfo.ResourceTypeStylesheet:
+ interceptors.ResourceType.stylesheet,
+ QWebEngineUrlRequestInfo.ResourceTypeScript:
+ interceptors.ResourceType.script,
+ QWebEngineUrlRequestInfo.ResourceTypeImage:
+ interceptors.ResourceType.image,
+ QWebEngineUrlRequestInfo.ResourceTypeFontResource:
+ interceptors.ResourceType.font_resource,
+ QWebEngineUrlRequestInfo.ResourceTypeSubResource:
+ interceptors.ResourceType.sub_resource,
+ QWebEngineUrlRequestInfo.ResourceTypeObject:
+ interceptors.ResourceType.object,
+ QWebEngineUrlRequestInfo.ResourceTypeMedia:
+ interceptors.ResourceType.media,
+ QWebEngineUrlRequestInfo.ResourceTypeWorker:
+ interceptors.ResourceType.worker,
+ QWebEngineUrlRequestInfo.ResourceTypeSharedWorker:
+ interceptors.ResourceType.shared_worker,
+ QWebEngineUrlRequestInfo.ResourceTypePrefetch:
+ interceptors.ResourceType.prefetch,
+ QWebEngineUrlRequestInfo.ResourceTypeFavicon:
+ interceptors.ResourceType.favicon,
+ QWebEngineUrlRequestInfo.ResourceTypeXhr:
+ interceptors.ResourceType.xhr,
+ QWebEngineUrlRequestInfo.ResourceTypePing:
+ interceptors.ResourceType.ping,
+ QWebEngineUrlRequestInfo.ResourceTypeServiceWorker:
+ interceptors.ResourceType.service_worker,
+ QWebEngineUrlRequestInfo.ResourceTypeCspReport:
+ interceptors.ResourceType.csp_report,
+ QWebEngineUrlRequestInfo.ResourceTypePluginResource:
+ interceptors.ResourceType.plugin_resource,
+ QWebEngineUrlRequestInfo.ResourceTypeUnknown:
+ interceptors.ResourceType.unknown,
+ }
+
def __init__(self, args, parent=None):
super().__init__(parent)
self._args = args
@@ -71,6 +144,17 @@ class RequestInterceptor(QWebEngineUrlRequestInterceptor):
url = info.requestUrl()
first_party = info.firstPartyUrl()
+ # Per QWebEngineUrlRequestInfo::ResourceType documentation, if we fail
+ # our lookup, we should fall back to ResourceTypeUnknown
+ try:
+ resource_type = RequestInterceptor.RESOURCE_TYPES[
+ info.resourceType()]
+ except KeyError:
+ log.webview.warning(
+ "Resource type {} not found in RequestInterceptor dict."
+ .format(debug.qenum_key(QWebEngineUrlRequestInfo,
+ info.resourceType())))
+ resource_type = interceptors.ResourceType.unknown
if ((url.scheme(), url.host(), url.path()) ==
('qute', 'settings', '/set')):
@@ -84,8 +168,12 @@ class RequestInterceptor(QWebEngineUrlRequestInterceptor):
return
# FIXME:qtwebengine only block ads for NavigationTypeOther?
- request = interceptors.Request(first_party_url=first_party,
- request_url=url)
+ request = WebEngineRequest(
+ first_party_url=first_party,
+ request_url=url,
+ resource_type=resource_type,
+ webengine_info=info)
+
interceptors.run(request)
if request.is_blocked:
info.block(True)
diff --git a/qutebrowser/browser/webengine/spell.py b/qutebrowser/browser/webengine/spell.py
index 55d8aea5b..6653acdd6 100644
--- a/qutebrowser/browser/webengine/spell.py
+++ b/qutebrowser/browser/webengine/spell.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2017-2018 Michal Siedlaczek <michal.siedlaczek@gmail.com>
# This file is part of qutebrowser.
diff --git a/qutebrowser/browser/webengine/tabhistory.py b/qutebrowser/browser/webengine/tabhistory.py
index 81f0a3afd..04e44fae5 100644
--- a/qutebrowser/browser/webengine/tabhistory.py
+++ b/qutebrowser/browser/webengine/tabhistory.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -66,7 +66,7 @@ def _serialize_item(item, stream):
def serialize(items):
- """Serialize a list of QWebHistoryItems to a data stream.
+ """Serialize a list of WebHistoryItems to a data stream.
Args:
items: An iterable of WebHistoryItems.
diff --git a/qutebrowser/browser/webengine/webenginedownloads.py b/qutebrowser/browser/webengine/webenginedownloads.py
index 6dde42070..a9e4046a1 100644
--- a/qutebrowser/browser/webengine/webenginedownloads.py
+++ b/qutebrowser/browser/webengine/webenginedownloads.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -180,7 +180,21 @@ def _get_suggested_filename(path):
See https://bugreports.qt.io/browse/QTBUG-56978
"""
filename = os.path.basename(path)
- filename = re.sub(r'\([0-9]+\)(?=\.|$)', '', filename)
+
+ suffix_re = re.compile(r"""
+ \ ? # Optional space between filename and suffix
+ (
+ # Numerical suffix
+ \([0-9]+\)
+ |
+ # ISO-8601 suffix
+ # https://cs.chromium.org/chromium/src/base/time/time_to_iso8601.cc
+ \ -\ \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z
+ )
+ (?=\.|$) # Begin of extension, or filename without extension
+ """, re.VERBOSE)
+
+ filename = suffix_re.sub('', filename)
if not qtutils.version_check('5.9', compiled=False):
# https://bugreports.qt.io/browse/QTBUG-58155
filename = urllib.parse.unquote(filename)
diff --git a/qutebrowser/browser/webengine/webengineelem.py b/qutebrowser/browser/webengine/webengineelem.py
index 13292b45b..eb9a9b1d8 100644
--- a/qutebrowser/browser/webengine/webengineelem.py
+++ b/qutebrowser/browser/webengine/webengineelem.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -209,6 +209,9 @@ class WebEngineElement(webelem.AbstractWebElement):
self._js_dict['attributes']['target'] = '_top'
self._js_call('remove_blank_target')
+ def delete(self) -> None:
+ self._js_call('delete')
+
def _move_text_cursor(self) -> None:
if self.is_text_input() and self.is_editable():
self._js_call('move_cursor_to_end')
diff --git a/qutebrowser/browser/webengine/webengineinspector.py b/qutebrowser/browser/webengine/webengineinspector.py
index 0b1ace3f3..4bf72502c 100644
--- a/qutebrowser/browser/webengine/webengineinspector.py
+++ b/qutebrowser/browser/webengine/webengineinspector.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webengine/webenginequtescheme.py b/qutebrowser/browser/webengine/webenginequtescheme.py
index 816589514..f622ee57b 100644
--- a/qutebrowser/browser/webengine/webenginequtescheme.py
+++ b/qutebrowser/browser/webengine/webenginequtescheme.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -62,18 +62,33 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler):
"""
try:
initiator = job.initiator()
+ request_url = job.requestUrl()
except AttributeError:
# Added in Qt 5.11
return True
- if initiator == QUrl('null') and not qtutils.version_check('5.12'):
+ # https://codereview.qt-project.org/#/c/234849/
+ is_opaque = initiator == QUrl('null')
+ target = request_url.scheme(), request_url.host()
+
+ if is_opaque and not qtutils.version_check('5.12'):
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-70421
+ # When we don't register the qute:// scheme, all requests are
+ # flagged as opaque.
+ return True
+
+ if (target == ('qute', 'testdata') and
+ is_opaque and
+ qtutils.version_check('5.12')):
+ # Allow requests to qute://testdata, as this is needed in Qt 5.12
+ # for all tests to work properly. No qute://testdata handler is
+ # installed outside of tests.
return True
if initiator.isValid() and initiator.scheme() != 'qute':
log.misc.warning("Blocking malicious request from {} to {}".format(
initiator.toDisplayString(),
- job.requestUrl().toDisplayString()))
+ request_url.toDisplayString()))
job.fail(QWebEngineUrlRequestJob.RequestDenied)
return False
@@ -148,6 +163,7 @@ def init():
classes.
"""
if QWebEngineUrlScheme is not None:
+ assert not QWebEngineUrlScheme.schemeByName(b'qute').name()
scheme = QWebEngineUrlScheme(b'qute')
scheme.setFlags(QWebEngineUrlScheme.LocalScheme |
QWebEngineUrlScheme.LocalAccessAllowed)
diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py
index 10c4d4e6b..32084d910 100644
--- a/qutebrowser/browser/webengine/webenginesettings.py
+++ b/qutebrowser/browser/webengine/webenginesettings.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -25,6 +25,7 @@ Module attributes:
"""
import os
+import operator
from PyQt5.QtGui import QFont
from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
@@ -42,6 +43,8 @@ private_profile = None
# The global WebEngineSettings object
global_settings = None
+default_user_agent = None
+
class _SettingsWrapper:
@@ -51,8 +54,9 @@ class _SettingsWrapper:
"""
def __init__(self):
- self._settings = [default_profile.settings(),
- private_profile.settings()]
+ self._settings = [default_profile.settings()]
+ if private_profile:
+ self._settings.append(private_profile.settings())
def setAttribute(self, *args, **kwargs):
for settings in self._settings:
@@ -163,9 +167,14 @@ class WebEngineSettings(websettings.AbstractSettings):
# Qt 5.8
'content.print_element_backgrounds':
('PrintElementBackgrounds', None),
+
# Qt 5.11
'content.autoplay':
- ('PlaybackRequiresUserGesture', lambda val: not val),
+ ('PlaybackRequiresUserGesture', operator.not_),
+
+ # Qt 5.12
+ 'content.dns_prefetch':
+ ('DnsPrefetchEnabled', None),
}
for name, (attribute, converter) in new_attributes.items():
try:
@@ -259,10 +268,12 @@ def _update_settings(option):
if option in ['content.headers.user_agent',
'content.headers.accept_language']:
default_profile.setter.set_http_headers()
- private_profile.setter.set_http_headers()
+ if private_profile:
+ private_profile.setter.set_http_headers()
elif option == 'content.cache.size':
default_profile.setter.set_http_cache_size()
- private_profile.setter.set_http_cache_size()
+ if private_profile:
+ private_profile.setter.set_http_cache_size()
elif (option == 'content.cookies.store' and
# https://bugreports.qt.io/browse/QTBUG-58650
qtutils.version_check('5.9', compiled=False)):
@@ -270,14 +281,16 @@ def _update_settings(option):
# We're not touching the private profile's cookie policy.
elif option == 'spellcheck.languages':
default_profile.setter.set_dictionary_language()
- private_profile.setter.set_dictionary_language(warn=False)
+ if private_profile:
+ private_profile.setter.set_dictionary_language(warn=False)
def _init_profiles():
"""Init the two used QWebEngineProfiles."""
- global default_profile, private_profile
+ global default_profile, private_profile, default_user_agent
default_profile = QWebEngineProfile.defaultProfile()
+ default_user_agent = default_profile.httpUserAgent()
default_profile.setter = ProfileSetter(default_profile)
default_profile.setCachePath(
os.path.join(standarddir.cache(), 'webengine'))
@@ -286,10 +299,11 @@ def _init_profiles():
default_profile.setter.init_profile()
default_profile.setter.set_persistent_cookie_policy()
- private_profile = QWebEngineProfile()
- private_profile.setter = ProfileSetter(private_profile)
- assert private_profile.isOffTheRecord()
- private_profile.setter.init_profile()
+ if not qtutils.is_single_process():
+ private_profile = QWebEngineProfile()
+ private_profile.setter = ProfileSetter(private_profile)
+ assert private_profile.isOffTheRecord()
+ private_profile.setter.init_profile()
def init(args):
diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py
index 22380cb1f..46d829bf1 100644
--- a/qutebrowser/browser/webengine/webenginetab.py
+++ b/qutebrowser/browser/webengine/webenginetab.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -26,7 +26,6 @@ import html as html_utils
from PyQt5.QtCore import (pyqtSignal, pyqtSlot, Qt, QPoint, QPointF, QUrl,
QTimer, QObject)
-from PyQt5.QtGui import QIcon
from PyQt5.QtNetwork import QAuthenticator
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineScript
@@ -57,28 +56,34 @@ def init():
log.init.debug("Initializing qute://* handler...")
_qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app)
_qute_scheme_handler.install(webenginesettings.default_profile)
- _qute_scheme_handler.install(webenginesettings.private_profile)
+ if webenginesettings.private_profile:
+ _qute_scheme_handler.install(webenginesettings.private_profile)
log.init.debug("Initializing request interceptor...")
args = objreg.get('args')
req_interceptor = interceptor.RequestInterceptor(args=args, parent=app)
req_interceptor.install(webenginesettings.default_profile)
- req_interceptor.install(webenginesettings.private_profile)
+ if webenginesettings.private_profile:
+ req_interceptor.install(webenginesettings.private_profile)
log.init.debug("Initializing QtWebEngine downloads...")
download_manager = webenginedownloads.DownloadManager(parent=app)
download_manager.install(webenginesettings.default_profile)
- download_manager.install(webenginesettings.private_profile)
+ if webenginesettings.private_profile:
+ download_manager.install(webenginesettings.private_profile)
objreg.register('webengine-download-manager', download_manager)
log.init.debug("Initializing cookie filter...")
cookies.install_filter(webenginesettings.default_profile)
- cookies.install_filter(webenginesettings.private_profile)
+ if webenginesettings.private_profile:
+ cookies.install_filter(webenginesettings.private_profile)
# Clear visited links on web history clear
hist = objreg.get('web-history')
for p in [webenginesettings.default_profile,
webenginesettings.private_profile]:
+ if not p:
+ continue
hist.history_cleared.connect(p.clearAllVisitedLinks)
hist.url_cleared.connect(lambda url, profile=p:
profile.clearVisitedLinks([url]))
@@ -270,6 +275,9 @@ class WebEngineCaret(browsertab.AbstractCaret):
def _selection_cb(self, enabled):
"""Emit selection_toggled based on setInitialCursor."""
+ if self._mode_manager.mode != usertypes.KeyMode.caret:
+ log.webview.debug("Ignoring selection cb due to mode change.")
+ return
if enabled is None:
log.webview.debug("Ignoring selection status None")
return
@@ -342,6 +350,9 @@ class WebEngineCaret(browsertab.AbstractCaret):
self._tab.run_js_async(javascript.assemble('caret', 'getSelection'),
callback)
+ def reverse_selection(self):
+ self._js_call('reverseSelection')
+
def _follow_selected_cb_wrapped(self, js_elem, tab):
try:
self._follow_selected_cb(js_elem, tab)
@@ -715,8 +726,6 @@ class _WebEnginePermissions(QObject):
"""Handling of various permission-related signals."""
- _abort_questions = pyqtSignal()
-
def __init__(self, tab, parent=None):
super().__init__(parent)
self._tab = tab
@@ -736,9 +745,6 @@ class _WebEnginePermissions(QObject):
page.registerProtocolHandlerRequested.connect(
self._on_register_protocol_handler_requested)
- self._tab.shutting_down.connect(self._abort_questions)
- self._tab.load_started.connect(self._abort_questions)
-
@pyqtSlot('QWebEngineFullScreenRequest')
def _on_fullscreen_requested(self, request):
request.accept()
@@ -794,6 +800,18 @@ class _WebEnginePermissions(QObject):
except AttributeError:
# Added in Qt 5.10
pass
+ try:
+ options.update({
+ QWebEnginePage.Notifications:
+ 'content.notifications',
+ })
+ messages.update({
+ QWebEnginePage.Notifications:
+ 'show notifications',
+ })
+ except AttributeError:
+ # Added in Qt 5.13
+ pass
assert options.keys() == messages.keys()
@@ -816,7 +834,7 @@ class _WebEnginePermissions(QObject):
question = shared.feature_permission(
url=url, option=options[feature], msg=messages[feature],
yes_action=yes_action, no_action=no_action,
- abort_on=[self._abort_questions])
+ abort_on=[self._tab.abort_questions])
if question is not None:
page.featurePermissionRequestCanceled.connect(
@@ -844,7 +862,7 @@ class _WebEnginePermissions(QObject):
option='content.persistent_storage',
msg='use {} of persistent storage'.format(size),
yes_action=request.accept, no_action=request.reject,
- abort_on=[self._abort_questions],
+ abort_on=[self._tab.abort_questions],
blocking=True)
def _on_register_protocol_handler_requested(self, request):
@@ -853,7 +871,7 @@ class _WebEnginePermissions(QObject):
option='content.register_protocol_handler',
msg='open all {} links'.format(request.scheme()),
yes_action=request.accept, no_action=request.reject,
- abort_on=[self._abort_questions],
+ abort_on=[self._tab.abort_questions],
blocking=True)
@@ -927,10 +945,14 @@ class _WebEngineScripts(QObject):
utils.read_file('javascript/webelem.js'),
utils.read_file('javascript/caret.js'),
)
- self._inject_early_js('js',
- utils.read_file('javascript/print.js'),
- subframes=True,
- world=QWebEngineScript.MainWorld)
+ if not qtutils.version_check('5.12'):
+ # WORKAROUND for Qt versions < 5.12 not exposing window.print().
+ # Qt 5.12 has a printRequested() signal so we don't need this hack
+ # anymore.
+ self._inject_early_js('js',
+ utils.read_file('javascript/print.js'),
+ subframes=True,
+ world=QWebEngineScript.MainWorld)
# FIXME:qtwebengine what about subframes=True?
self._inject_early_js('js', js_code, subframes=True)
self._init_stylesheet()
@@ -1039,9 +1061,15 @@ class _WebEngineScripts(QObject):
new_script.setSourceCode(script.code())
new_script.setName("GM-{}".format(script.name))
new_script.setRunsOnSubFrames(script.runs_on_sub_frames)
+
# Override the @run-at value parsed by QWebEngineScript if desired.
if injection_point:
new_script.setInjectionPoint(injection_point)
+ elif script.needs_document_end_workaround():
+ log.greasemonkey.debug("Forcing @run-at document-end for {}"
+ .format(script.name))
+ new_script.setInjectionPoint(QWebEngineScript.DocumentReady)
+
log.greasemonkey.debug('adding script: {}'
.format(new_script.name()))
page_scripts.insert(new_script)
@@ -1074,12 +1102,11 @@ class WebEngineTab(browsertab.AbstractTab):
"""A QtWebEngine tab in the browser.
Signals:
- _load_finished_fake:
- Used in place of unreliable loadFinished
+ abort_questions: Emitted when a new load started or we're shutting
+ down.
"""
- # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-65223
- _load_finished_fake = pyqtSignal(bool)
+ abort_questions = pyqtSignal()
def __init__(self, *, win_id, mode_manager, private, parent=None):
super().__init__(win_id=win_id, private=private, parent=parent)
@@ -1252,15 +1279,13 @@ class WebEngineTab(browsertab.AbstractTab):
answer = message.ask(
title="Proxy authentication required", text=msg,
mode=usertypes.PromptMode.user_pwd,
- abort_on=[self.shutting_down, self.load_started], url=urlstr)
+ abort_on=[self.abort_questions], url=urlstr)
if answer is not None:
authenticator.setUser(answer.user)
authenticator.setPassword(answer.password)
else:
try:
- # pylint: disable=no-member, useless-suppression
sip.assign(authenticator, QAuthenticator())
- # pylint: enable=no-member, useless-suppression
except AttributeError:
self._show_error_page(url, "Proxy authentication required")
@@ -1276,15 +1301,12 @@ class WebEngineTab(browsertab.AbstractTab):
if not netrc_success:
log.network.debug("Asking for credentials")
- abort_on = [self.shutting_down, self.load_started]
- answer = shared.authentication_required(url, authenticator,
- abort_on)
+ answer = shared.authentication_required(
+ url, authenticator, abort_on=[self.abort_questions])
if not netrc_success and answer is None:
log.network.debug("Aborting auth")
try:
- # pylint: disable=no-member, useless-suppression
sip.assign(authenticator, QAuthenticator())
- # pylint: enable=no-member, useless-suppression
except AttributeError:
# WORKAROUND for
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-December/038400.html
@@ -1322,24 +1344,6 @@ class WebEngineTab(browsertab.AbstractTab):
}
self.renderer_process_terminated.emit(status_map[status], exitcode)
- @pyqtSlot(int)
- def _on_load_progress_workaround(self, perc):
- """Use loadProgress(100) to emit loadFinished(True).
-
- See https://bugreports.qt.io/browse/QTBUG-65223
- """
- if perc == 100 and self.load_status() != usertypes.LoadStatus.error:
- self._load_finished_fake.emit(True)
-
- @pyqtSlot(bool)
- def _on_load_finished_workaround(self, ok):
- """Use only loadFinished(False).
-
- See https://bugreports.qt.io/browse/QTBUG-65223
- """
- if not ok:
- self._load_finished_fake.emit(False)
-
def _error_page_workaround(self, html):
"""Check if we're displaying a Chromium error page.
@@ -1355,10 +1359,30 @@ class WebEngineTab(browsertab.AbstractTab):
return
self._show_error_page(self.url(), error=match.group(1))
+ @pyqtSlot(int)
+ def _on_load_progress(self, perc: int) -> None:
+ """QtWebEngine-specific loadProgress workarounds.
+
+ WORKAROUND for https://bugreports.qt.io/browse/QTBUG-65223
+ """
+ super()._on_load_progress(perc)
+ if (perc == 100 and
+ qtutils.version_check('5.10', compiled=False) and
+ self.load_status() != usertypes.LoadStatus.error):
+ self._update_load_status(ok=True)
+
@pyqtSlot(bool)
- def _on_load_finished(self, ok):
- """Display a static error page if JavaScript is disabled."""
+ def _on_load_finished(self, ok: bool) -> None:
+ """QtWebEngine-specific loadFinished workarounds."""
super()._on_load_finished(ok)
+
+ # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-65223
+ if qtutils.version_check('5.10', compiled=False):
+ if not ok:
+ self._update_load_status(ok)
+ else:
+ self._update_load_status(ok)
+
js_enabled = self.settings.test_attribute('content.javascript.enabled')
if not ok and not js_enabled:
self.dump_async(self._error_page_workaround)
@@ -1373,13 +1397,6 @@ class WebEngineTab(browsertab.AbstractTab):
emit_before_load_started=False))
self._reload_url = None
- if not qtutils.version_check('5.10', compiled=False):
- # We can't do this when we have the loadFinished workaround as that
- # sometimes clears icons without loading a new page.
- # In general, this is handled by Qt, but when loading takes long,
- # the old icon is still displayed.
- self.icon_changed.emit(QIcon())
-
@pyqtSlot(certificateerror.CertificateErrorWrapper)
def _on_ssl_errors(self, error):
self._has_ssl_errors = True
@@ -1389,7 +1406,7 @@ class WebEngineTab(browsertab.AbstractTab):
if error.is_overridable():
error.ignore = shared.ignore_certificate_errors(
- url, [error], abort_on=[self.shutting_down, self.load_started])
+ url, [error], abort_on=[self.abort_questions])
else:
log.webview.error("Non-overridable certificate error: "
"{}".format(error))
@@ -1418,15 +1435,20 @@ class WebEngineTab(browsertab.AbstractTab):
if not qtutils.version_check('5.11.1', compiled=False):
self.settings.update_for_url(url)
+ @pyqtSlot()
+ def _on_print_requested(self):
+ """Slot for window.print() in JS."""
+ try:
+ self.printing.show_dialog()
+ except browsertab.WebTabError as e:
+ message.error(str(e))
+
@pyqtSlot(usertypes.NavigationRequest)
def _on_navigation_request(self, navigation):
super()._on_navigation_request(navigation)
if navigation.url == QUrl('qute://print'):
- try:
- self.printing.show_dialog()
- except browsertab.WebTabError as e:
- message.error(str(e))
+ self._on_print_requested()
navigation.accepted = False
if not navigation.accepted or not navigation.is_main_frame:
@@ -1458,6 +1480,37 @@ class WebEngineTab(browsertab.AbstractTab):
if reload_needed:
self._reload_url = navigation.url
+ def _on_select_client_certificate(self, selection):
+ """Handle client certificates.
+
+ Currently, we simply pick the first available certificate and show an
+ additional note if there are multiple matches.
+ """
+ certificate = selection.certificates()[0]
+ text = ('<b>Subject:</b> {subj}<br/>'
+ '<b>Issuer:</b> {issuer}<br/>'
+ '<b>Serial:</b> {serial}'.format(
+ subj=html_utils.escape(certificate.subjectDisplayName()),
+ issuer=html_utils.escape(certificate.issuerDisplayName()),
+ serial=bytes(certificate.serialNumber()).decode('ascii')))
+ if len(selection.certificates()) > 1:
+ text += ('<br/><br/><b>Note:</b> Multiple matching certificates '
+ 'were found, but certificate selection is not '
+ 'implemented yet!')
+ urlstr = selection.host().host()
+
+ present = message.ask(
+ title='Present client certificate to {}?'.format(urlstr),
+ text=text,
+ mode=usertypes.PromptMode.yesno,
+ abort_on=[self.abort_questions],
+ url=urlstr)
+
+ if present:
+ selection.select(certificate)
+ else:
+ selection.selectNone()
+
def _connect_signals(self):
view = self._widget
page = view.page()
@@ -1473,26 +1526,24 @@ class WebEngineTab(browsertab.AbstractTab):
page.contentsSizeChanged.connect(self.contents_size_changed)
page.navigation_request.connect(self._on_navigation_request)
+ if qtutils.version_check('5.12'):
+ page.printRequested.connect(self._on_print_requested)
+ page.selectClientCertificate.connect(
+ self._on_select_client_certificate)
+
view.titleChanged.connect(self.title_changed)
view.urlChanged.connect(self._on_url_changed)
view.renderProcessTerminated.connect(
self._on_render_process_terminated)
view.iconChanged.connect(self.icon_changed)
- # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-65223
- if qtutils.version_check('5.10', compiled=False):
- page.loadProgress.connect(self._on_load_progress_workaround)
- self._load_finished_fake.connect(self._on_history_trigger)
- self._load_finished_fake.connect(self._restore_zoom)
- self._load_finished_fake.connect(self._on_load_finished)
- page.loadFinished.connect(self._on_load_finished_workaround)
- else:
- # for older Qt versions which break with the above
- page.loadProgress.connect(self._on_load_progress)
- page.loadFinished.connect(self._on_history_trigger)
- page.loadFinished.connect(self._restore_zoom)
- page.loadFinished.connect(self._on_load_finished)
+
+ page.loadFinished.connect(self._on_history_trigger)
+ page.loadFinished.connect(self._restore_zoom)
+ page.loadFinished.connect(self._on_load_finished)
self.before_load_started.connect(self._on_before_load_started)
+ self.shutting_down.connect(self.abort_questions)
+ self.load_started.connect(self.abort_questions)
# pylint: disable=protected-access
self.audio._connect_signals()
diff --git a/qutebrowser/browser/webengine/webview.py b/qutebrowser/browser/webengine/webview.py
index e70226f30..f71f11087 100644
--- a/qutebrowser/browser/webengine/webview.py
+++ b/qutebrowser/browser/webengine/webview.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -43,6 +43,7 @@ class WebEngineView(QWebEngineView):
theme_color = self.style().standardPalette().color(QPalette.Base)
if private:
+ assert webenginesettings.private_profile is not None
profile = webenginesettings.private_profile
assert profile.isOffTheRecord()
else:
@@ -64,6 +65,8 @@ class WebEngineView(QWebEngineView):
Normally, this would always be the focusProxy().
However, it sometimes isn't, so we use this as a WORKAROUND for
https://bugreports.qt.io/browse/QTBUG-68727
+
+ This got introduced in Qt 5.11.0 and fixed in 5.12.0.
"""
if 'lost-focusproxy' not in objreg.get('args').debug_flags:
proxy = self.focusProxy()
@@ -256,8 +259,17 @@ class WebEnginePage(QWebEnginePage):
QWebEnginePage.NavigationTypeOther:
usertypes.NavigationRequest.Type.other,
}
- navigation = usertypes.NavigationRequest(url=url,
- navigation_type=type_map[typ],
- is_main_frame=is_main_frame)
+ try:
+ type_map[QWebEnginePage.NavigationTypeRedirect] = (
+ usertypes.NavigationRequest.Type.redirect)
+ except AttributeError:
+ # Added in Qt 5.14
+ pass
+
+ navigation = usertypes.NavigationRequest(
+ url=url,
+ navigation_type=type_map.get(
+ typ, usertypes.NavigationRequest.Type.other),
+ is_main_frame=is_main_frame)
self.navigation_request.emit(navigation)
return navigation.accepted
diff --git a/qutebrowser/browser/webkit/__init__.py b/qutebrowser/browser/webkit/__init__.py
index 5100b7a53..e276c8b2b 100644
--- a/qutebrowser/browser/webkit/__init__.py
+++ b/qutebrowser/browser/webkit/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/cache.py b/qutebrowser/browser/webkit/cache.py
index 163612ce9..4844ea0d3 100644
--- a/qutebrowser/browser/webkit/cache.py
+++ b/qutebrowser/browser/webkit/cache.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/certificateerror.py b/qutebrowser/browser/webkit/certificateerror.py
index cad17fba5..646de0bdc 100644
--- a/qutebrowser/browser/webkit/certificateerror.py
+++ b/qutebrowser/browser/webkit/certificateerror.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/cookies.py b/qutebrowser/browser/webkit/cookies.py
index 01b6842a0..9dce9bc11 100644
--- a/qutebrowser/browser/webkit/cookies.py
+++ b/qutebrowser/browser/webkit/cookies.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/http.py b/qutebrowser/browser/webkit/http.py
index 73e620015..d4d3802cd 100644
--- a/qutebrowser/browser/webkit/http.py
+++ b/qutebrowser/browser/webkit/http.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/mhtml.py b/qutebrowser/browser/webkit/mhtml.py
index 70a22351f..e0d714dce 100644
--- a/qutebrowser/browser/webkit/mhtml.py
+++ b/qutebrowser/browser/webkit/mhtml.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Daniel Schadt
#
# This file is part of qutebrowser.
diff --git a/qutebrowser/browser/webkit/network/filescheme.py b/qutebrowser/browser/webkit/network/filescheme.py
index a29674e25..c036bd6e6 100644
--- a/qutebrowser/browser/webkit/network/filescheme.py
+++ b/qutebrowser/browser/webkit/network/filescheme.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Antoni Boucher (antoyo) <bouanto@zoho.com>
#
# This file is part of qutebrowser.
diff --git a/qutebrowser/browser/webkit/network/networkmanager.py b/qutebrowser/browser/webkit/network/networkmanager.py
index dd3643c87..fd95f29fb 100644
--- a/qutebrowser/browser/webkit/network/networkmanager.py
+++ b/qutebrowser/browser/webkit/network/networkmanager.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/network/networkreply.py b/qutebrowser/browser/webkit/network/networkreply.py
index c56fe2a9b..99546c90d 100644
--- a/qutebrowser/browser/webkit/network/networkreply.py
+++ b/qutebrowser/browser/webkit/network/networkreply.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# Based on the Eric5 helpviewer,
# Copyright (c) 2009 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
@@ -34,8 +34,7 @@ class FixedDataNetworkReply(QNetworkReply):
"""QNetworkReply subclass for fixed data."""
- def __init__(self, request, fileData, mimeType, # noqa: N803
- parent=None):
+ def __init__(self, request, fileData, mimeType, parent=None): # noqa: N803
"""Constructor.
Args:
diff --git a/qutebrowser/browser/webkit/network/webkitqutescheme.py b/qutebrowser/browser/webkit/network/webkitqutescheme.py
index c05097b79..a90255323 100644
--- a/qutebrowser/browser/webkit/network/webkitqutescheme.py
+++ b/qutebrowser/browser/webkit/network/webkitqutescheme.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/rfc6266.py b/qutebrowser/browser/webkit/rfc6266.py
index 139b4f9df..2ffc39f88 100644
--- a/qutebrowser/browser/webkit/rfc6266.py
+++ b/qutebrowser/browser/webkit/rfc6266.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/tabhistory.py b/qutebrowser/browser/webkit/tabhistory.py
index 263bf6334..de22dbf31 100644
--- a/qutebrowser/browser/webkit/tabhistory.py
+++ b/qutebrowser/browser/webkit/tabhistory.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -63,7 +63,7 @@ def _serialize_item(item):
def serialize(items):
- """Serialize a list of QWebHistoryItems to a data stream.
+ """Serialize a list of WebHistoryItems to a data stream.
Args:
items: An iterable of WebHistoryItems.
@@ -89,8 +89,7 @@ def serialize(items):
if current_idx is not None:
raise ValueError("Multiple active items ({} and {}) "
"found!".format(current_idx, i))
- else:
- current_idx = i
+ current_idx = i
if items:
if current_idx is None:
diff --git a/qutebrowser/browser/webkit/webkitelem.py b/qutebrowser/browser/webkit/webkitelem.py
index af0db295d..983904eeb 100644
--- a/qutebrowser/browser/webkit/webkitelem.py
+++ b/qutebrowser/browser/webkit/webkitelem.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -324,6 +324,9 @@ class WebKitElement(webelem.AbstractWebElement):
break
elem = elem._parent() # pylint: disable=protected-access
+ def delete(self) -> None:
+ self._elem.evaluateJavaScript('this.remove();')
+
def _move_text_cursor(self) -> None:
if self.is_text_input() and self.is_editable():
self._tab.caret.move_to_end_of_document()
diff --git a/qutebrowser/browser/webkit/webkithistory.py b/qutebrowser/browser/webkit/webkithistory.py
index 65d9bbb01..a0d41088d 100644
--- a/qutebrowser/browser/webkit/webkithistory.py
+++ b/qutebrowser/browser/webkit/webkithistory.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/webkitinspector.py b/qutebrowser/browser/webkit/webkitinspector.py
index d590d4adf..e2652b9f4 100644
--- a/qutebrowser/browser/webkit/webkitinspector.py
+++ b/qutebrowser/browser/webkit/webkitinspector.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/webkitsettings.py b/qutebrowser/browser/webkit/webkitsettings.py
index cce1dcec0..fac86285e 100644
--- a/qutebrowser/browser/webkit/webkitsettings.py
+++ b/qutebrowser/browser/webkit/webkitsettings.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/webkittab.py b/qutebrowser/browser/webkit/webkittab.py
index c10c2aeec..05b6e22a6 100644
--- a/qutebrowser/browser/webkit/webkittab.py
+++ b/qutebrowser/browser/webkit/webkittab.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -351,6 +351,15 @@ class WebKitCaret(browsertab.AbstractCaret):
def selection(self, callback):
callback(self._widget.selectedText())
+ def reverse_selection(self):
+ self._tab.run_js_async("""{
+ const sel = window.getSelection();
+ sel.setBaseAndExtent(
+ sel.extentNode, sel.extentOffset, sel.baseNode,
+ sel.baseOffset
+ );
+ }""")
+
def _follow_selected(self, *, tab=False):
if QWebSettings.globalSettings().testAttribute(
QWebSettings.JavascriptEnabled):
@@ -782,6 +791,11 @@ class WebKitTab(browsertab.AbstractTab):
# Make sure the icon is cleared when navigating to a page without one.
self.icon_changed.emit(QIcon())
+ @pyqtSlot(bool)
+ def _on_load_finished(self, ok: bool) -> None:
+ super()._on_load_finished(ok)
+ self._update_load_status(ok)
+
@pyqtSlot()
def _on_frame_load_finished(self):
"""Make sure we emit an appropriate status when loading finished.
diff --git a/qutebrowser/browser/webkit/webpage.py b/qutebrowser/browser/webkit/webpage.py
index 0195ec17f..1b4b85c65 100644
--- a/qutebrowser/browser/webkit/webpage.py
+++ b/qutebrowser/browser/webkit/webpage.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/browser/webkit/webview.py b/qutebrowser/browser/webkit/webview.py
index 8921e211c..54258f1a8 100644
--- a/qutebrowser/browser/webkit/webview.py
+++ b/qutebrowser/browser/webkit/webview.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -20,7 +20,6 @@
"""The main browser widgets."""
from PyQt5.QtCore import pyqtSignal, Qt, QUrl
-from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import QStyleFactory
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWebKitWidgets import QWebView, QWebPage
@@ -50,6 +49,12 @@ class WebView(QWebView):
shutting_down: Emitted when the view is shutting down.
"""
+ STYLESHEET = """
+ WebView {
+ background-color: {{ qcolor_to_qsscolor(conf.colors.webpage.bg) }};
+ }
+ """
+
scroll_pos_changed = pyqtSignal(int, int)
shutting_down = pyqtSignal()
@@ -66,7 +71,6 @@ class WebView(QWebView):
self.win_id = win_id
self.scroll_pos = (-1, -1)
self._old_scroll_pos = (-1, -1)
- self._set_bg_color()
self._tab_id = tab_id
page = webpage.BrowserPage(win_id=self.win_id, tab_id=self._tab_id,
@@ -78,7 +82,7 @@ class WebView(QWebView):
self.setPage(page)
- config.instance.changed.connect(self._set_bg_color)
+ config.set_register_stylesheet(self)
def __repr__(self):
url = utils.elide(self.url().toDisplayString(QUrl.EncodeUnicode), 100)
@@ -97,16 +101,6 @@ class WebView(QWebView):
# deleted
pass
- @config.change_filter('colors.webpage.bg')
- def _set_bg_color(self):
- """Set the webpage background color as configured."""
- col = config.val.colors.webpage.bg
- palette = self.palette()
- if col is None:
- col = self.style().standardPalette().color(QPalette.Base)
- palette.setColor(QPalette.Base, col)
- self.setPalette(palette)
-
def shutdown(self):
"""Shut down the webview."""
self.shutting_down.emit()
diff --git a/qutebrowser/commands/__init__.py b/qutebrowser/commands/__init__.py
index 6ba8a9ae3..1cf55cae5 100644
--- a/qutebrowser/commands/__init__.py
+++ b/qutebrowser/commands/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -26,9 +26,13 @@ For command arguments, there are also some variables you can use:
- `{url}` expands to the URL of the current page
- `{url:pretty}` expands to the URL in decoded format
-- `{url:host}` expands to the host part of the URL
+- `{url:host}`, `{url:domain}`, `{url:auth}`, `{url:scheme}`, `{url:username}`,
+ `{url:password}`, `{url:host}`, `{url:port}`, `{url:path}` and `{url:query}`
+ expand to the respective parts of the current URL
+- `{title}` expands to the current page's title
- `{clipboard}` expands to the clipboard contents
- `{primary}` expands to the primary selection contents
-It is possible to run or bind multiple commands by separating them with `;;`.
+Those variables can be escaped by doubling the braces, e.g. `{{url}}`. It is
+possible to run or bind multiple commands by separating them with `;;`.
"""
diff --git a/qutebrowser/commands/argparser.py b/qutebrowser/commands/argparser.py
index 707324ede..289cdb54b 100644
--- a/qutebrowser/commands/argparser.py
+++ b/qutebrowser/commands/argparser.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/commands/cmdexc.py b/qutebrowser/commands/cmdexc.py
index f342f2436..5eb465a24 100644
--- a/qutebrowser/commands/cmdexc.py
+++ b/qutebrowser/commands/cmdexc.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/commands/command.py b/qutebrowser/commands/command.py
index 46f92772f..044816fdb 100644
--- a/qutebrowser/commands/command.py
+++ b/qutebrowser/commands/command.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -402,7 +402,8 @@ class Command:
if isinstance(typ, tuple):
raise TypeError("{}: Legacy tuple type annotation!".format(
self.name))
- elif getattr(typ, '__origin__', None) is typing.Union or (
+
+ if getattr(typ, '__origin__', None) is typing.Union or (
# Older Python 3.5 patch versions
# pylint: disable=no-member,useless-suppression
hasattr(typing, 'UnionMeta') and
diff --git a/qutebrowser/commands/runners.py b/qutebrowser/commands/runners.py
index 000689a75..217ef909d 100644
--- a/qutebrowser/commands/runners.py
+++ b/qutebrowser/commands/runners.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -21,6 +21,8 @@
import traceback
import re
+import typing
+import contextlib
import attr
from PyQt5.QtCore import pyqtSlot, QUrl, QObject
@@ -31,6 +33,12 @@ from qutebrowser.commands import cmdexc
from qutebrowser.utils import message, objreg, qtutils, usertypes, utils
from qutebrowser.misc import split, objects
+MYPY = False
+if MYPY:
+ # pylint: disable=unused-import
+ from qutebrowser.mainwindow import tabbedbrowser
+_ReplacementFunction = typing.Callable[['tabbedbrowser.TabbedBrowser'], str]
+
last_command = {}
@@ -45,7 +53,7 @@ class ParseResult:
cmdline = attr.ib()
-def _current_url(tabbed_browser):
+def _url(tabbed_browser):
"""Convenience method to get the current url."""
try:
return tabbed_browser.current_url()
@@ -57,25 +65,50 @@ def _current_url(tabbed_browser):
raise cmdutils.CommandError(msg)
-def replace_variables(win_id, arglist):
- """Utility function to replace variables like {url} in a list of args."""
- tabbed_browser = objreg.get('tabbed-browser', scope='window',
- window=win_id)
-
- variables = {
- 'url': lambda: _current_url(tabbed_browser).toString(
+def _init_variable_replacements() -> typing.Mapping[str, _ReplacementFunction]:
+ """Return a dict from variable replacements to fns processing them."""
+ replacements = {
+ 'url': lambda tb: _url(tb).toString(
QUrl.FullyEncoded | QUrl.RemovePassword),
- 'url:pretty': lambda: _current_url(tabbed_browser).toString(
+ 'url:pretty': lambda tb: _url(tb).toString(
QUrl.DecodeReserved | QUrl.RemovePassword),
- 'url:host': lambda: _current_url(tabbed_browser).host(),
- 'clipboard': utils.get_clipboard,
- 'primary': lambda: utils.get_clipboard(selection=True),
- }
-
- for key in list(variables):
+ 'url:domain': lambda tb: "{}://{}{}".format(
+ _url(tb).scheme(), _url(tb).host(),
+ ":" + str(_url(tb).port()) if _url(tb).port() != -1 else ""),
+ 'url:auth': lambda tb: "{}:{}@".format(
+ _url(tb).userName(),
+ _url(tb).password()) if _url(tb).userName() else "",
+ 'url:scheme': lambda tb: _url(tb).scheme(),
+ 'url:username': lambda tb: _url(tb).userName(),
+ 'url:password': lambda tb: _url(tb).password(),
+ 'url:host': lambda tb: _url(tb).host(),
+ 'url:port': lambda tb: str(
+ _url(tb).port()) if _url(tb).port() != -1 else "",
+ 'url:path': lambda tb: _url(tb).path(),
+ 'url:query': lambda tb: _url(tb).query(),
+ 'title': lambda tb: tb.widget.page_title(tb.widget.currentIndex()),
+ 'clipboard': lambda _: utils.get_clipboard(),
+ 'primary': lambda _: utils.get_clipboard(selection=True),
+ } # type: typing.Dict[str, _ReplacementFunction]
+
+ for key in list(replacements):
modified_key = '{' + key + '}'
- variables[modified_key] = lambda x=modified_key: x
+ # x = modified_key is to avoid binding x as a closure
+ replacements[modified_key] = (
+ lambda _, x=modified_key: x) # type: ignore
+ return replacements
+
+VARIABLE_REPLACEMENTS = _init_variable_replacements()
+# A regex matching all variable replacements
+VARIABLE_REPLACEMENT_PATTERN = re.compile(
+ "{(?P<var>" + "|".join(VARIABLE_REPLACEMENTS.keys()) + ")}")
+
+
+def replace_variables(win_id, arglist):
+ """Utility function to replace variables like {url} in a list of args."""
+ tabbed_browser = objreg.get('tabbed-browser', scope='window',
+ window=win_id)
values = {}
args = []
@@ -83,16 +116,15 @@ def replace_variables(win_id, arglist):
"""Return replacement for given match."""
var = matchobj.group("var")
if var not in values:
- values[var] = variables[var]()
+ values[var] = VARIABLE_REPLACEMENTS[var](tabbed_browser)
return values[var]
- repl_pattern = re.compile("{(?P<var>" + "|".join(variables.keys()) + ")}")
try:
for arg in arglist:
# using re.sub with callback function replaces all variables in a
# single pass and avoids expansion of nested variables (e.g.
# "{url}" from clipboard is not expanded)
- args.append(repl_pattern.sub(repl_cb, arg))
+ args.append(VARIABLE_REPLACEMENT_PATTERN.sub(repl_cb, arg))
except utils.ClipboardError as e:
raise cmdutils.CommandError(e)
return args
@@ -286,12 +318,24 @@ class CommandRunner(QObject):
self._parser = CommandParser(partial_match=partial_match)
self._win_id = win_id
- def run(self, text, count=None):
+ @contextlib.contextmanager
+ def _handle_error(self, safely) -> typing.Iterator[None]:
+ """Show exceptions as errors if safely=True is given."""
+ try:
+ yield
+ except cmdexc.Error as e:
+ if safely:
+ message.error(str(e), stack=traceback.format_exc())
+ else:
+ raise
+
+ def run(self, text, count=None, *, safely=False):
"""Parse a command from a line of text and run it.
Args:
text: The text to parse.
count: The count to pass to the command.
+ safely: Show CmdError exceptions as messages.
"""
record_last_command = True
record_macro = True
@@ -300,12 +344,21 @@ class CommandRunner(QObject):
window=self._win_id)
cur_mode = mode_manager.mode
- for result in self._parser.parse_all(text):
- if result.cmd.no_replace_variables:
- args = result.args
- else:
- args = replace_variables(self._win_id, result.args)
- result.cmd.run(self._win_id, args, count=count)
+ parsed = None
+ with self._handle_error(safely):
+ parsed = self._parser.parse_all(text)
+
+ if parsed is None:
+ return
+
+ for result in parsed:
+ with self._handle_error(safely):
+ if result.cmd.no_replace_variables:
+ args = result.args
+ else:
+ args = replace_variables(self._win_id, result.args)
+
+ result.cmd.run(self._win_id, args, count=count)
if result.cmdline[0] == 'repeat-command':
record_last_command = False
@@ -325,7 +378,4 @@ class CommandRunner(QObject):
@pyqtSlot(str)
def run_safely(self, text, count=None):
"""Run a command and display exceptions in the statusbar."""
- try:
- self.run(text, count)
- except cmdexc.Error as e:
- message.error(str(e), stack=traceback.format_exc())
+ self.run(text, count, safely=True)
diff --git a/qutebrowser/commands/userscripts.py b/qutebrowser/commands/userscripts.py
index 8d95db07d..6470a5365 100644
--- a/qutebrowser/commands/userscripts.py
+++ b/qutebrowser/commands/userscripts.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/completion/__init__.py b/qutebrowser/completion/__init__.py
index 2c9121699..ab188f92e 100644
--- a/qutebrowser/completion/__init__.py
+++ b/qutebrowser/completion/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/completion/completer.py b/qutebrowser/completion/completer.py
index ea64225d5..678a28af9 100644
--- a/qutebrowser/completion/completer.py
+++ b/qutebrowser/completion/completer.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/completion/completiondelegate.py b/qutebrowser/completion/completiondelegate.py
index b58f36372..4bdf1f3de 100644
--- a/qutebrowser/completion/completiondelegate.py
+++ b/qutebrowser/completion/completiondelegate.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -214,8 +214,11 @@ class CompletionItemDelegate(QStyledItemDelegate):
columns_to_filter = index.model().columns_to_filter(index)
if index.column() in columns_to_filter and pattern:
pat = re.escape(pattern).replace(r'\ ', r'|')
- _Highlighter(self._doc, pat,
- config.val.colors.completion.match.fg)
+ if self._opt.state & QStyle.State_Selected:
+ color = config.val.colors.completion.item.selected.match.fg
+ else:
+ color = config.val.colors.completion.match.fg
+ _Highlighter(self._doc, pat, color)
self._doc.setPlainText(self._opt.text)
else:
self._doc.setHtml(
diff --git a/qutebrowser/completion/completionwidget.py b/qutebrowser/completion/completionwidget.py
index 0af4ecbe1..64be8aa4f 100644
--- a/qutebrowser/completion/completionwidget.py
+++ b/qutebrowser/completion/completionwidget.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -359,8 +359,6 @@ class CompletionView(QTreeView):
self.horizontalScrollBar().sizeHint().height())
if contents_height <= height:
height = contents_height
- else:
- contents_height = -1
# The width isn't really relevant as we're expanding anyways.
return QSize(-1, height)
diff --git a/qutebrowser/completion/models/__init__.py b/qutebrowser/completion/models/__init__.py
index 7f62829ba..960e0766c 100644
--- a/qutebrowser/completion/models/__init__.py
+++ b/qutebrowser/completion/models/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/completion/models/completionmodel.py b/qutebrowser/completion/models/completionmodel.py
index 36a465fb7..d7cef71e2 100644
--- a/qutebrowser/completion/models/completionmodel.py
+++ b/qutebrowser/completion/models/completionmodel.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2017-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/completion/models/configmodel.py b/qutebrowser/completion/models/configmodel.py
index 19b252242..9c1093532 100644
--- a/qutebrowser/completion/models/configmodel.py
+++ b/qutebrowser/completion/models/configmodel.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/completion/models/histcategory.py b/qutebrowser/completion/models/histcategory.py
index 83eafef50..98589d287 100644
--- a/qutebrowser/completion/models/histcategory.py
+++ b/qutebrowser/completion/models/histcategory.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2017-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
@@ -17,18 +17,18 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
-"""A completion category that queries the SQL History store."""
+"""A completion category that queries the SQL history store."""
from PyQt5.QtSql import QSqlQueryModel
from qutebrowser.misc import sql
-from qutebrowser.utils import debug
+from qutebrowser.utils import debug, message
from qutebrowser.config import config
class HistoryCategory(QSqlQueryModel):
- """A completion category that queries the SQL History store."""
+ """A completion category that queries the SQL history store."""
def __init__(self, *, delete_func=None, parent=None):
"""Create a new History completion category."""
@@ -74,37 +74,46 @@ class HistoryCategory(QSqlQueryModel):
# build a where clause to match all of the words in any order
# given the search term "a b", the WHERE clause would be:
- # ((url || ' ' || title) LIKE '%a%') AND
- # ((url || ' ' || title) LIKE '%b%')
+ # (url LIKE '%a%' OR title LIKE '%a%') AND
+ # (url LIKE '%b%' OR title LIKE '%b%')
where_clause = ' AND '.join(
- "(url || ' ' || title) LIKE :{} escape '\\'".format(i)
- for i in range(len(words)))
+ "(url LIKE :{val} escape '\\' OR title LIKE :{val} escape '\\')"
+ .format(val=i) for i in range(len(words)))
# replace ' in timestamp-format to avoid breaking the query
timestamp_format = config.val.completion.timestamp_format or ''
timefmt = ("strftime('{}', last_atime, 'unixepoch', 'localtime')"
.format(timestamp_format.replace("'", "`")))
- if not self._query or len(words) != len(self._query.bound_values()):
- # if the number of words changed, we need to generate a new query
- # otherwise, we can reuse the prepared query for performance
- self._query = sql.Query(' '.join([
- "SELECT url, title, {}".format(timefmt),
- "FROM CompletionHistory",
- # the incoming pattern will have literal % and _ escaped
- # we need to tell sql to treat '\' as an escape character
- 'WHERE ({})'.format(where_clause),
- self._atime_expr(),
- "ORDER BY last_atime DESC",
- ]), forward_only=False)
-
- with debug.log_time('sql', 'Running completion query'):
- self._query.run(**{
- str(i): w for i, w in enumerate(words)})
+ try:
+ if (not self._query or
+ len(words) != len(self._query.bound_values())):
+ # if the number of words changed, we need to generate a new
+ # query otherwise, we can reuse the prepared query for
+ # performance
+ self._query = sql.Query(' '.join([
+ "SELECT url, title, {}".format(timefmt),
+ "FROM CompletionHistory",
+ # the incoming pattern will have literal % and _ escaped we
+ # need to tell SQL to treat '\' as an escape character
+ 'WHERE ({})'.format(where_clause),
+ self._atime_expr(),
+ "ORDER BY last_atime DESC",
+ ]), forward_only=False)
+
+ with debug.log_time('sql', 'Running completion query'):
+ self._query.run(**{
+ str(i): w for i, w in enumerate(words)})
+ except sql.KnownError as e:
+ # Sometimes, the query we built up was invalid, for example,
+ # due to a large amount of words.
+ # Also catches failures in the DB we can't solve.
+ message.error("Error with SQL query: {}".format(e.text()))
+ return
self.setQuery(self._query.query)
def removeRows(self, row, _count, _parent=None):
- """Override QAbstractItemModel::removeRows to re-run sql query."""
+ """Override QAbstractItemModel::removeRows to re-run SQL query."""
# re-run query to reload updated table
with debug.log_time('sql', 'Re-running completion query post-delete'):
self._query.run()
diff --git a/qutebrowser/completion/models/listcategory.py b/qutebrowser/completion/models/listcategory.py
index 78844f53f..1ff9dbab4 100644
--- a/qutebrowser/completion/models/listcategory.py
+++ b/qutebrowser/completion/models/listcategory.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2017-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/completion/models/miscmodels.py b/qutebrowser/completion/models/miscmodels.py
index 74b75aeb1..9c1cc20fc 100644
--- a/qutebrowser/completion/models/miscmodels.py
+++ b/qutebrowser/completion/models/miscmodels.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/completion/models/urlmodel.py b/qutebrowser/completion/models/urlmodel.py
index f2e6fe5f5..137afb00a 100644
--- a/qutebrowser/completion/models/urlmodel.py
+++ b/qutebrowser/completion/models/urlmodel.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/completion/models/util.py b/qutebrowser/completion/models/util.py
index 08f99eb6c..32f32f1c6 100644
--- a/qutebrowser/completion/models/util.py
+++ b/qutebrowser/completion/models/util.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2017-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/components/__init__.py b/qutebrowser/components/__init__.py
index 1a13763bf..63b8d8db3 100644
--- a/qutebrowser/components/__init__.py
+++ b/qutebrowser/components/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/components/adblock.py b/qutebrowser/components/adblock.py
index 9baa12d7c..8ceeccc1a 100644
--- a/qutebrowser/components/adblock.py
+++ b/qutebrowser/components/adblock.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/components/caretcommands.py b/qutebrowser/components/caretcommands.py
index 4bab6b6c6..e9d861d02 100644
--- a/qutebrowser/components/caretcommands.py
+++ b/qutebrowser/components/caretcommands.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -209,3 +209,10 @@ def follow_selected(tab_obj: apitypes.Tab, *, tab: bool = False) -> None:
tab_obj.caret.follow_selected(tab=tab)
except apitypes.WebTabError as e:
raise cmdutils.CommandError(str(e))
+
+
+@cmdutils.register(modes=[cmdutils.KeyMode.caret])
+@cmdutils.argument('tab', value=cmdutils.Value.cur_tab)
+def reverse_selection(tab: apitypes.Tab) -> None:
+ """Swap the stationary and moving end of the current selection."""
+ tab.caret.reverse_selection()
diff --git a/qutebrowser/components/misccommands.py b/qutebrowser/components/misccommands.py
index a65bdd235..fc5fce225 100644
--- a/qutebrowser/components/misccommands.py
+++ b/qutebrowser/components/misccommands.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -292,8 +292,7 @@ def debug_crash(typ: str = 'exception') -> None:
if typ == 'segfault':
os.kill(os.getpid(), signal.SIGSEGV)
raise Exception("Segfault failed (wat.)")
- else:
- raise Exception("Forced crash")
+ raise Exception("Forced crash")
@cmdutils.register(debug=True, maxsplit=0, no_cmd_split=True)
diff --git a/qutebrowser/components/scrollcommands.py b/qutebrowser/components/scrollcommands.py
index 0b8943f2d..15030ec3d 100644
--- a/qutebrowser/components/scrollcommands.py
+++ b/qutebrowser/components/scrollcommands.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/components/zoomcommands.py b/qutebrowser/components/zoomcommands.py
index 51d01cfea..f2796cfcc 100644
--- a/qutebrowser/components/zoomcommands.py
+++ b/qutebrowser/components/zoomcommands.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/config/__init__.py b/qutebrowser/config/__init__.py
index e2c25cce8..b124d26ae 100644
--- a/qutebrowser/config/__init__.py
+++ b/qutebrowser/config/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/config/config.py b/qutebrowser/config/config.py
index 201b87fde..a51126c1b 100644
--- a/qutebrowser/config/config.py
+++ b/qutebrowser/config/config.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/config/configcache.py b/qutebrowser/config/configcache.py
index 15f343478..0a62e503d 100644
--- a/qutebrowser/config/configcache.py
+++ b/qutebrowser/config/configcache.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Jay Kamat <jaygkamat@gmail.com>
+# Copyright 2018-2019 Jay Kamat <jaygkamat@gmail.com>
#
# This file is part of qutebrowser.
#
@@ -30,8 +30,8 @@ class ConfigCache:
"""A 'high-performance' cache for the config system.
Useful for areas which call out to the config system very frequently, DO
- NOT modify the value returned, DO NOT require per-url settings, do not
- change frequently, and do not require partially 'expanded' config paths.
+ NOT modify the value returned, DO NOT require per-url settings, and do not
+ require partially 'expanded' config paths.
If any of these requirements are broken, you will get incorrect or slow
behavior.
@@ -43,12 +43,12 @@ class ConfigCache:
def _on_config_changed(self, attr: str) -> None:
if attr in self._cache:
- self._cache[attr] = config.instance.get(attr)
+ del self._cache[attr]
def __getitem__(self, attr: str) -> typing.Any:
try:
return self._cache[attr]
except KeyError:
assert not config.instance.get_opt(attr).supports_pattern
- self._cache[attr] = config.instance.get(attr)
- return self._cache[attr]
+ result = self._cache[attr] = config.instance.get(attr)
+ return result
diff --git a/qutebrowser/config/configcommands.py b/qutebrowser/config/configcommands.py
index d667b043b..11990eaa7 100644
--- a/qutebrowser/config/configcommands.py
+++ b/qutebrowser/config/configcommands.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -152,9 +152,8 @@ class ConfigCommands:
key: The keychain to bind. Examples of valid keychains are `gC`,
`<Ctrl-X>` or `<Ctrl-C>a`.
command: The command to execute, with optional args.
- mode: A comma-separated list of modes to bind the key in
- (default: `normal`). See `:help bindings.commands` for the
- available modes.
+ mode: The mode to bind the key in (default: `normal`). See `:help
+ bindings.commands` for the available modes.
default: If given, restore a default binding.
"""
if key is None:
@@ -193,7 +192,7 @@ class ConfigCommands:
Args:
key: The keychain to unbind. See the help for `:bind` for the
correct syntax for keychains.
- mode: A mode to unbind the key in (default: `normal`).
+ mode: The mode to unbind the key in (default: `normal`).
See `:help bindings.commands` for the available modes.
"""
with self._handle_config_error():
@@ -275,7 +274,8 @@ class ConfigCommands:
value: The value to append to the end of the list.
temp: Add value temporarily until qutebrowser is closed.
"""
- opt = self._config.get_opt(option)
+ with self._handle_config_error():
+ opt = self._config.get_opt(option)
valid_list_types = (configtypes.List, configtypes.ListOrValue)
if not isinstance(opt.typ, valid_list_types):
raise cmdutils.CommandError(":config-list-add can only be used "
@@ -300,7 +300,8 @@ class ConfigCommands:
replace: Replace existing values. By default, existing values are
not overwritten.
"""
- opt = self._config.get_opt(option)
+ with self._handle_config_error():
+ opt = self._config.get_opt(option)
if not isinstance(opt.typ, configtypes.Dict):
raise cmdutils.CommandError(":config-dict-add can only be used "
"for dicts")
@@ -327,7 +328,8 @@ class ConfigCommands:
value: The value to remove from the list.
temp: Remove value temporarily until qutebrowser is closed.
"""
- opt = self._config.get_opt(option)
+ with self._handle_config_error():
+ opt = self._config.get_opt(option)
valid_list_types = (configtypes.List, configtypes.ListOrValue)
if not isinstance(opt.typ, valid_list_types):
raise cmdutils.CommandError(":config-list-remove can only be used "
@@ -355,7 +357,8 @@ class ConfigCommands:
key: The key to remove from the dict.
temp: Remove value temporarily until qutebrowser is closed.
"""
- opt = self._config.get_opt(option)
+ with self._handle_config_error():
+ opt = self._config.get_opt(option)
if not isinstance(opt.typ, configtypes.Dict):
raise cmdutils.CommandError(":config-dict-remove can only be used "
"for dicts")
diff --git a/qutebrowser/config/configdata.py b/qutebrowser/config/configdata.py
index 61e35fd53..71ce74a47 100644
--- a/qutebrowser/config/configdata.py
+++ b/qutebrowser/config/configdata.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -91,15 +91,15 @@ def _parse_yaml_type(
) -> configtypes.BaseType:
if isinstance(node, str):
# e.g:
- # type: Bool
+ # > type: Bool
# -> create the type object without any arguments
type_name = node
kwargs = {} # type: typing.MutableMapping[str, typing.Any]
elif isinstance(node, dict):
# e.g:
- # type:
- # name: String
- # none_ok: true
+ # > type:
+ # > name: String
+ # > none_ok: true
# -> create the type object and pass arguments
type_name = node.pop('name')
kwargs = node
@@ -164,6 +164,8 @@ def _parse_yaml_backends_dict(
'Qt 5.9.2': qtutils.version_check('5.9.2'),
'Qt 5.10': qtutils.version_check('5.10'),
'Qt 5.11': qtutils.version_check('5.11'),
+ 'Qt 5.12': qtutils.version_check('5.12'),
+ 'Qt 5.13': qtutils.version_check('5.13'),
}
for key in sorted(node.keys()):
if conditionals[node[key]]:
diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml
index b6d4736ae..d4f66126f 100644
--- a/qutebrowser/config/configdata.yml
+++ b/qutebrowser/config/configdata.yml
@@ -81,7 +81,7 @@ new_instance_open_target_window:
desc: >-
Which window to choose when opening links as new tabs.
- When `new_instance_open_target` is not set to `window`, this is ignored.
+ When `new_instance_open_target` is set to `window`, this is ignored.
session_default_name:
renamed: session.default_name
@@ -379,7 +379,9 @@ content.developer_extras:
content.dns_prefetch:
default: true
type: Bool
- backend: QtWebKit
+ backend:
+ QtWebKit: true
+ QtWebEngine: Qt 5.12
supports_pattern: true
desc: Try to pre-fetch DNS entries to speed up browsing.
@@ -476,46 +478,14 @@ content.headers.user_agent:
# 'ua_fetch.py'
# Vim-protip: Place your cursor below this comment and run
# :r!python scripts/dev/ua_fetch.py
- - - "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:53.0) Gecko/20100101
- Firefox/53.0"
- - Firefox 53.0 Win8.1
- - - "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:53.0) Gecko/20100101
- Firefox/53.0"
- - Firefox 53.0 Linux
- - - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0)
- Gecko/20100101 Firefox/53.0"
- - Firefox 53.0 MacOSX
-
- - - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4
- (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4"
- - Safari Generic MacOSX
- - - "Mozilla/5.0 (iPad; CPU OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30
- (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1"
- - Mobile Safari 10.0 iOS
-
- - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
- like Gecko) Chrome/58.0.3029.110 Safari/537.36"
- - Chrome Generic Win10
- - - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36
- (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
- - Chrome Generic MacOSX
+ like Gecko) Chrome/71.0.3578.98 Safari/537.36"
+ - Chrome 71.0 Win10
- - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like
- Gecko) Chrome/58.0.3029.110 Safari/537.36"
- - Chrome Generic Linux
-
- - - "Mozilla/5.0 (compatible; Googlebot/2.1;
- +http://www.google.com/bot.html"
- - Google Bot
- - - "Wget/1.16.1 (linux-gnu)"
- - wget 1.16.1
- - - "curl/7.40.0"
- - curl 7.40.0
- - - "Mozilla/5.0 (Linux; U; Android 7.1.2) AppleWebKit/534.30 (KHTML,
- like Gecko) Version/4.0 Mobile Safari/534.30"
- - Mobile Generic Android
- - - "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like
- Gecko"
- - IE 11.0 for Desktop Win7 64-bit
+ Gecko) Chrome/71.0.3578.98 Safari/537.36"
+ - Chrome 71.0 Linux
+ - - ""
+ - Use default QtWebKit/QtWebEngine User-Agent
supports_pattern: true
desc: >-
@@ -691,12 +661,15 @@ content.notifications:
default: ask
type: BoolAsk
supports_pattern: true
- backend: QtWebKit
+ backend:
+ QtWebEngine: Qt 5.13
+ QtWebKit: true
desc: Allow websites to show notifications.
content.pdfjs:
default: false
type: Bool
+ supports_pattern: true
desc: >-
Allow pdf.js to view PDF files in the browser.
@@ -888,10 +861,13 @@ completion.scrollbar.padding:
completion.timestamp_format:
type:
- name: TimestampTemplate
+ name: String
none_ok: true
default: '%Y-%m-%d'
- desc: Format of timestamps (e.g. for the history completion).
+ desc: >-
+ Format of timestamps (e.g. for the history completion).
+
+ See https://sqlite.org/lang_datefunc.html for allowed substitutions.
completion.web_history.exclude:
type:
@@ -1228,6 +1204,11 @@ hints.uppercase:
type: Bool
desc: Make characters in hint strings uppercase.
+hints.leave_on_load:
+ default: true
+ type: Bool
+ desc: Leave hint mode when starting a new page load.
+
## input
input.escape_quits_reporter:
@@ -1266,6 +1247,16 @@ input.insert_mode.plugins:
type: Bool
desc: Switch to insert mode when clicking flash and other plugins.
+input.insert_mode.leave_on_load:
+ default: true
+ type: Bool
+ supports_pattern: true
+ desc: >-
+ Leave insert mode when starting a new page load.
+
+ Patterns may be unreliable on this setting, and they may match the url you
+ are navigating to, or the URL you are navigating from.
+
input.links_included_in_focus_chain:
default: true
type: Bool
@@ -1639,13 +1630,13 @@ tabs.title.alignment:
desc: Alignment of the text inside of tabs.
tabs.title.format:
- default: '{audio}{index}: {title}'
+ default: '{audio}{index}: {current_title}'
type:
name: FormatString
fields:
- perc
- perc_raw
- - title
+ - current_title
- title_sep
- index
- id
@@ -1662,7 +1653,7 @@ tabs.title.format:
* `{perc}`: Percentage as a string like `[10%]`.
* `{perc_raw}`: Raw percentage, e.g. `10`.
- * `{title}`: Title of the current web page.
+ * `{current_title}`: Title of the current web page.
* `{title_sep}`: The string ` - ` if a title is set, empty otherwise.
* `{index}`: Index of this tab.
* `{id}`: Internal tab ID of this tab.
@@ -1681,7 +1672,7 @@ tabs.title.format_pinned:
fields:
- perc
- perc_raw
- - title
+ - current_title
- title_sep
- index
- id
@@ -1773,6 +1764,14 @@ tabs.pinned.frozen:
default: True
desc: Force pinned tabs to stay at fixed URL.
+tabs.undo_stack_size:
+ default: 100
+ type:
+ name: Int
+ minval: -1
+ maxval: maxint
+ desc: Number of close tab actions to remember, per window (-1 for no maximum).
+
tabs.wrap:
default: true
type: Bool
@@ -1873,7 +1872,7 @@ window.title_format:
fields:
- perc
- perc_raw
- - title
+ - current_title
- title_sep
- id
- scroll_pos
@@ -1883,7 +1882,7 @@ window.title_format:
- current_url
- protocol
- audio
- default: '{perc}{title}{title_sep}qutebrowser'
+ default: '{perc}{current_title}{title_sep}qutebrowser'
desc: |
Format to use for the window title. The same placeholders like for
`tabs.title.format` are defined.
@@ -1991,13 +1990,18 @@ colors.completion.item.selected.bg:
colors.completion.item.selected.border.top:
default: '#bbbb00'
type: QssColor
- desc: Top border color of the completion widget category headers.
+ desc: Top border color of the selected completion item.
colors.completion.item.selected.border.bottom:
default: '#bbbb00'
type: QssColor
desc: Bottom border color of the selected completion item.
+colors.completion.item.selected.match.fg:
+ default: '#ff4444'
+ type: QtColor
+ desc: Foreground color of the matched text in the selected completion item.
+
colors.completion.match.fg:
default: '#ff4444'
type: QtColor
@@ -2275,7 +2279,7 @@ colors.statusbar.url.warn.fg:
colors.tabs.bar.bg:
default: '#555555'
- type: QtColor
+ type: QssColor
desc: Background color of the tab bar.
colors.tabs.indicator.start:
@@ -2338,6 +2342,46 @@ colors.tabs.selected.even.bg:
type: QtColor
desc: Background color of selected even tabs.
+colors.tabs.pinned.odd.fg:
+ default: white
+ type: QtColor
+ desc: Foreground color of pinned unselected odd tabs.
+
+colors.tabs.pinned.odd.bg:
+ default: seagreen
+ type: QtColor
+ desc: Background color of pinned unselected odd tabs.
+
+colors.tabs.pinned.even.fg:
+ default: white
+ type: QtColor
+ desc: Foreground color of pinned unselected even tabs.
+
+colors.tabs.pinned.even.bg:
+ default: darkseagreen
+ type: QtColor
+ desc: Background color of pinned unselected even tabs.
+
+colors.tabs.pinned.selected.odd.fg:
+ default: white
+ type: QtColor
+ desc: Foreground color of pinned selected odd tabs.
+
+colors.tabs.pinned.selected.odd.bg:
+ default: black
+ type: QtColor
+ desc: Background color of pinned selected odd tabs.
+
+colors.tabs.pinned.selected.even.fg:
+ default: white
+ type: QtColor
+ desc: Foreground color of pinned selected even tabs.
+
+colors.tabs.pinned.selected.even.bg:
+ default: black
+ type: QtColor
+ desc: Background color of pinned selected even tabs.
+
colors.webpage.bg:
default: white
type:
@@ -2617,8 +2661,8 @@ bindings.default:
yD: yank domain -s
yp: yank pretty-url
yP: yank pretty-url -s
- ym: yank markdown
- yM: yank markdown -s
+ ym: yank inline [{title}]({url})
+ yM: yank inline [{title}]({url}) -s
pp: open -- {clipboard}
pP: open -- {primary}
Pp: open -t -- {clipboard}
@@ -2796,6 +2840,7 @@ bindings.default:
e: move-to-end-of-word
w: move-to-next-word
b: move-to-prev-word
+ o: reverse-selection
"]": move-to-start-of-next-block
"[": move-to-start-of-prev-block
"}": move-to-end-of-next-block
diff --git a/qutebrowser/config/configdiff.py b/qutebrowser/config/configdiff.py
index ba78f64b4..beefc3d8a 100644
--- a/qutebrowser/config/configdiff.py
+++ b/qutebrowser/config/configdiff.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/config/configexc.py b/qutebrowser/config/configexc.py
index 80a2cedb2..9f53847cb 100644
--- a/qutebrowser/config/configexc.py
+++ b/qutebrowser/config/configexc.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/config/configfiles.py b/qutebrowser/config/configfiles.py
index de50dfca9..edbfed0bb 100644
--- a/qutebrowser/config/configfiles.py
+++ b/qutebrowser/config/configfiles.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -28,9 +28,10 @@ import traceback
import configparser
import contextlib
import typing
+import re
import yaml
-from PyQt5.QtCore import pyqtSignal, QObject, QSettings
+from PyQt5.QtCore import pyqtSignal, QObject, QSettings, qVersion
import qutebrowser
from qutebrowser.config import configexc, config, configdata, configutils
@@ -55,6 +56,17 @@ class StateConfig(configparser.ConfigParser):
super().__init__()
self._filename = os.path.join(standarddir.data(), 'state')
self.read(self._filename, encoding='utf-8')
+
+ qt_version = qVersion()
+ # We handle this here, so we can avoid setting qt_version_changed if
+ # the config is brand new, but can still set it when qt_version wasn't
+ # there before...
+ if 'general' in self:
+ old_qt_version = self['general'].get('qt_version', None)
+ self.qt_version_changed = old_qt_version != qt_version
+ else:
+ self.qt_version_changed = False
+
for sect in ['general', 'geometry']:
try:
self.add_section(sect)
@@ -65,6 +77,9 @@ class StateConfig(configparser.ConfigParser):
for key in deleted_keys:
self['general'].pop(key, None)
+ self['general']['qt_version'] = qt_version
+ self['general']['version'] = qutebrowser.__version__
+
def init_save_manager(self,
save_manager: 'savemanager.SaveManager') -> None:
"""Make sure the config gets saved properly.
@@ -256,6 +271,16 @@ class YamlConfig(QObject):
settings[name][scope] = true_value if val else false_value
self._mark_changed()
+ def _migrate_string_value(self, settings: _SettingsType, name: str,
+ source: str, target: str) -> None:
+ if name in settings:
+ for scope, val in settings[name].items():
+ if isinstance(val, str):
+ new_val = re.sub(source, target, val)
+ if new_val != val:
+ settings[name][scope] = new_val
+ self._mark_changed()
+
def _handle_migrations(self, settings: _SettingsType) -> '_SettingsType':
"""Migrate older configs to the newest format."""
# Simple renamed/deleted options
@@ -312,6 +337,12 @@ class YamlConfig(QObject):
self._migrate_bool(settings, 'qt.force_software_rendering',
'software-opengl', 'none')
+ for s in ['tabs.title.format',
+ 'tabs.title.format_pinned',
+ 'window.title_format']:
+ self._migrate_string_value(
+ settings, s, r'(?<!{)\{title\}(?!})', r'{current_title}')
+
return settings
def _validate(self, settings: _SettingsType) -> None:
@@ -638,7 +669,6 @@ def init() -> None:
"""Initialize config storage not related to the main config."""
global state
state = StateConfig()
- state['general']['version'] = qutebrowser.__version__
# Set the QSettings path to something like
# ~/.config/qutebrowser/qsettings/qutebrowser/qutebrowser.conf so it
diff --git a/qutebrowser/config/configinit.py b/qutebrowser/config/configinit.py
index df772599a..9dc15d6e9 100644
--- a/qutebrowser/config/configinit.py
+++ b/qutebrowser/config/configinit.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -175,12 +175,12 @@ def qt_args(namespace: argparse.Namespace) -> typing.List[str]:
argv += ['--' + arg for arg in config.val.qt.args]
if objects.backend == usertypes.Backend.QtWebEngine:
- argv += list(_qtwebengine_args())
+ argv += list(_qtwebengine_args(namespace))
return argv
-def _qtwebengine_args() -> typing.Iterator[str]:
+def _qtwebengine_args(namespace: argparse.Namespace) -> typing.Iterator[str]:
"""Get the QtWebEngine arguments to use based on the config."""
if not qtutils.version_check('5.11', compiled=False):
# WORKAROUND equivalent to
@@ -188,6 +188,23 @@ def _qtwebengine_args() -> typing.Iterator[str]:
# Needed for Qt < 5.9.5 and < 5.10.1
yield '--disable-shared-workers'
+ # WORKAROUND equivalent to
+ # https://codereview.qt-project.org/c/qt/qtwebengine/+/256786
+ # also see:
+ # https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/265753
+ if qtutils.version_check('5.12.3', compiled=False):
+ if 'stack' in namespace.debug_flags:
+ # Only actually available in Qt 5.12.5, but let's save another
+ # check, as passing the option won't hurt.
+ yield '--enable-in-process-stack-traces'
+ else:
+ if 'stack' not in namespace.debug_flags:
+ yield '--disable-in-process-stack-traces'
+
+ if 'chromium' in namespace.debug_flags:
+ yield '--enable-logging'
+ yield '--v=1'
+
settings = {
'qt.force_software_rendering': {
'software-opengl': None,
diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py
index 3f134f770..0cb51f756 100644
--- a/qutebrowser/config/configtypes.py
+++ b/qutebrowser/config/configtypes.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -48,7 +48,6 @@ import codecs
import os.path
import itertools
import warnings
-import datetime
import functools
import operator
import json
@@ -176,8 +175,7 @@ class BaseType:
(pytype == dict and value == {})):
if not self.none_ok:
raise configexc.ValidationError(value, "may not be null!")
- else:
- return
+ return
if (not isinstance(value, pytype) or
pytype is int and isinstance(value, bool)):
@@ -204,6 +202,12 @@ class BaseType:
assert isinstance(value, str), value
if not value and not self.none_ok:
raise configexc.ValidationError(value, "may not be empty!")
+ BaseType._basic_str_validation_cache(value)
+
+ @staticmethod
+ @functools.lru_cache(maxsize=2**9)
+ def _basic_str_validation_cache(value: str) -> None:
+ """Cache validation result to prevent looping over strings."""
if any(ord(c) < 32 or ord(c) == 0x7f for c in value):
raise configexc.ValidationError(
value, "may not contain unprintable chars!")
@@ -316,6 +320,9 @@ class BaseType:
out.append((val, desc))
return out
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok)
+
class MappingType(BaseType):
@@ -341,6 +348,10 @@ class MappingType(BaseType):
self._validate_valid_values(value.lower())
return self.MAPPING[value.lower()]
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok,
+ valid_values=self.valid_values)
+
class String(BaseType):
@@ -365,9 +376,9 @@ class String(BaseType):
if minlen is not None and minlen < 1:
raise ValueError("minlen ({}) needs to be >= 1!".format(minlen))
- elif maxlen is not None and maxlen < 1:
+ if maxlen is not None and maxlen < 1:
raise ValueError("maxlen ({}) needs to be >= 1!".format(maxlen))
- elif maxlen is not None and minlen is not None and maxlen < minlen:
+ if maxlen is not None and minlen is not None and maxlen < minlen:
raise ValueError("minlen ({}) needs to be <= maxlen ({})!".format(
minlen, maxlen))
self.minlen = minlen
@@ -423,6 +434,14 @@ class String(BaseType):
else:
return super().complete()
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok,
+ valid_values=self.valid_values,
+ minlen=self.minlen,
+ maxlen=self.maxlen, forbidden=self.forbidden,
+ completions=self._completions,
+ encoding=self.encoding)
+
class UniqueCharString(String):
@@ -527,6 +546,10 @@ class List(BaseType):
self.valtype.to_doc(elem, indent=indent+1)))
return '\n'.join(lines)
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok, valtype=self.valtype,
+ length=self.length)
+
class ListOrValue(BaseType):
@@ -599,6 +622,9 @@ class ListOrValue(BaseType):
val, typ = self._val_and_type(value)
return typ.to_doc(val)
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok, valtype=self.valtype)
+
class FlagList(List):
@@ -652,6 +678,11 @@ class FlagList(List):
out.append((json.dumps(combination), ''))
return out
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok,
+ valid_values=self.valid_values,
+ length=self.length)
+
class Bool(BaseType):
@@ -772,6 +803,10 @@ class _Numeric(BaseType): # pylint: disable=abstract-method
return ''
return str(value)
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok, minval=self.minval,
+ maxval=self.maxval)
+
class Int(_Numeric):
@@ -924,6 +959,11 @@ class PercOrInt(_Numeric):
self._validate_bounds(value)
return value
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok, minint=self.minval,
+ maxint=self.maxval, minperc=self.minperc,
+ maxperc=self.maxperc)
+
class Command(BaseType):
@@ -1001,16 +1041,16 @@ class QtColor(BaseType):
* `hsv(h, s, v)` / `hsva(h, s, v, a)` (values 0-255, hue 0-359)
"""
- def _parse_value(self, val: str) -> int:
+ def _parse_value(self, kind: str, val: str) -> int:
try:
return int(val)
except ValueError:
pass
- mult = 255.0
+ mult = 359.0 if kind == 'h' else 255.0
if val.endswith('%'):
val = val[:-1]
- mult = 255.0 / 100
+ mult = mult / 100
try:
return int(float(val) * mult)
@@ -1029,17 +1069,28 @@ class QtColor(BaseType):
openparen = value.index('(')
kind = value[:openparen]
vals = value[openparen+1:-1].split(',')
- int_vals = [self._parse_value(v) for v in vals]
- if kind == 'rgba' and len(int_vals) == 4:
- return QColor.fromRgb(*int_vals)
- elif kind == 'rgb' and len(int_vals) == 3:
- return QColor.fromRgb(*int_vals)
- elif kind == 'hsva' and len(int_vals) == 4:
- return QColor.fromHsv(*int_vals)
- elif kind == 'hsv' and len(int_vals) == 3:
- return QColor.fromHsv(*int_vals)
- else:
- raise configexc.ValidationError(value, "must be a valid color")
+
+ converters = {
+ 'rgba': QColor.fromRgb,
+ 'rgb': QColor.fromRgb,
+ 'hsva': QColor.fromHsv,
+ 'hsv': QColor.fromHsv,
+ } # type: typing.Dict[str, typing.Callable[..., QColor]]
+
+ conv = converters.get(kind)
+ if not conv:
+ raise configexc.ValidationError(
+ value,
+ '{} not in {}'.format(kind, list(sorted(converters))))
+
+ if len(kind) != len(vals):
+ raise configexc.ValidationError(
+ value,
+ 'expected {} values for {}'.format(len(kind), kind))
+
+ int_vals = [self._parse_value(kind, val)
+ for kind, val in zip(kind, vals)]
+ return conv(*int_vals)
color = QColor(value)
if color.isValid():
@@ -1271,8 +1322,7 @@ class Regex(BaseType):
str(w.message).startswith('bad escape')):
raise configexc.ValidationError(
pattern, "must be a valid regex - " + str(w.message))
- else:
- warnings.warn(w.message)
+ warnings.warn(w.message)
return compiled
@@ -1301,6 +1351,9 @@ class Regex(BaseType):
assert isinstance(value, str)
return value
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok, flags=self.flags)
+
class Dict(BaseType):
@@ -1403,6 +1456,11 @@ class Dict(BaseType):
)).splitlines()
return '\n'.join(line.rstrip(' ') for line in lines)
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok, keytype=self.keytype,
+ valtype=self.valtype, fixed_keys=self.fixed_keys,
+ required_keys=self.required_keys)
+
class File(BaseType):
@@ -1435,6 +1493,10 @@ class File(BaseType):
return value
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok,
+ required=self.required)
+
class Directory(BaseType):
@@ -1487,6 +1549,9 @@ class FormatString(BaseType):
return value
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok, fields=self.fields)
+
class ShellCommand(List):
@@ -1523,6 +1588,10 @@ class ShellCommand(List):
"{file}-placeholder.")
return py_value
+ def __repr__(self) -> str:
+ return utils.get_repr(self, none_ok=self.none_ok,
+ placeholder=self.placeholder)
+
class Proxy(BaseType):
@@ -1803,7 +1872,7 @@ class ConfirmQuit(FlagList):
raise configexc.ValidationError(
values, "List cannot contain never!")
# Always can't be set with other options
- elif 'always' in values and len(values) > 1:
+ if 'always' in values and len(values) > 1:
raise configexc.ValidationError(
values, "List cannot contain always!")
@@ -1823,31 +1892,6 @@ class NewTabPosition(String):
('last', "At the end."))
-class TimestampTemplate(BaseType):
-
- """An strftime-like template for timestamps.
-
- See https://sqlite.org/lang_datefunc.html for reference.
- """
-
- def to_py(self, value: _StrUnset) -> _StrUnsetNone:
- self._basic_py_validation(value, str)
- if isinstance(value, configutils.Unset):
- return value
- elif not value:
- return None
-
- try:
- # Dummy check to see if the template is valid
- datetime.datetime.now().strftime(value)
- except ValueError as error:
- # thrown on invalid template string
- raise configexc.ValidationError(
- value, "Invalid format string: {}".format(error))
-
- return value
-
-
class Key(BaseType):
"""A name of a key."""
diff --git a/qutebrowser/config/configutils.py b/qutebrowser/config/configutils.py
index 47cac4bff..6392e4ca6 100644
--- a/qutebrowser/config/configutils.py
+++ b/qutebrowser/config/configutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/config/websettings.py b/qutebrowser/config/websettings.py
index 5a21af7e3..f228c2cde 100644
--- a/qutebrowser/config/websettings.py
+++ b/qutebrowser/config/websettings.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -93,7 +93,7 @@ class AbstractSettings:
Return:
True if there was a change, False otherwise.
"""
- assert value is not configutils.UNSET
+ assert value is not configutils.UNSET # type: ignore
family = self._FONT_SIZES[name]
old_value = self._settings.fontSize(family)
self._settings.setFontSize(family, value)
@@ -108,7 +108,7 @@ class AbstractSettings:
Return:
True if there was a change, False otherwise.
"""
- assert value is not configutils.UNSET
+ assert value is not configutils.UNSET # type: ignore
family = self._FONT_FAMILIES[name]
if value is None:
font = QFont()
@@ -126,7 +126,7 @@ class AbstractSettings:
Return:
True if there was a change, False otherwise.
"""
- assert encoding is not configutils.UNSET
+ assert encoding is not configutils.UNSET # type: ignore
old_value = self._settings.defaultTextEncoding()
self._settings.setDefaultTextEncoding(encoding)
return old_value != encoding
diff --git a/qutebrowser/extensions/interceptors.py b/qutebrowser/extensions/interceptors.py
index 7defcf213..82379b16b 100644
--- a/qutebrowser/extensions/interceptors.py
+++ b/qutebrowser/extensions/interceptors.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -20,13 +20,51 @@
"""Infrastructure for intercepting requests."""
import typing
+import enum
import attr
-MYPY = False
-if MYPY:
- # pylint: disable=unused-import,useless-suppression
- from PyQt5.QtCore import QUrl
+from PyQt5.QtCore import QUrl
+
+
+class ResourceType(enum.Enum):
+ """Possible request types that can be received.
+
+ Currently corresponds to the QWebEngineUrlRequestInfo Enum:
+ https://doc.qt.io/qt-5/qwebengineurlrequestinfo.html#ResourceType-enum
+ """
+
+ main_frame = 0
+ sub_frame = 1
+ stylesheet = 2
+ script = 3
+ image = 4
+ font_resource = 5
+ sub_resource = 6
+ object = 7
+ media = 8
+ worker = 9
+ shared_worker = 10
+ prefetch = 11
+ favicon = 12
+ xhr = 13
+ ping = 14
+ service_worker = 15
+ csp_report = 16
+ plugin_resource = 17
+ unknown = 255
+
+
+class RedirectException(Exception):
+ """Raised when there was an error with redirection."""
+
+
+class RedirectFailedException(RedirectException):
+ """Raised when the request was invalid, or a request was already made."""
+
+
+class RedirectUnsupportedException(RedirectException):
+ """Raised when redirection is currently unsupported."""
@attr.s
@@ -42,10 +80,28 @@ class Request:
is_blocked = attr.ib(False) # type: bool
+ #: The resource type of the request. None if not supported on this backend.
+ resource_type = attr.ib(None) # type: typing.Optional[ResourceType]
+
def block(self) -> None:
"""Block this request."""
self.is_blocked = True
+ def redirect(self, url: QUrl) -> None:
+ """Redirect this request.
+
+ Only some types of requests can be successfully redirected.
+ Improper use of this method can result in redirect loops.
+
+ This method will throw a RedirectFailedException if the request was not
+ possible.
+
+ Args:
+ url: The QUrl to try to redirect to.
+ """
+ # Will be overridden if the backend supports redirection
+ raise RedirectUnsupportedException("Unsupported backend.")
+
#: Type annotation for an interceptor function.
InterceptorType = typing.Callable[[Request], None]
diff --git a/qutebrowser/extensions/loader.py b/qutebrowser/extensions/loader.py
index 1383adfef..d10e0919f 100644
--- a/qutebrowser/extensions/loader.py
+++ b/qutebrowser/extensions/loader.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/html/warning-webkit.html b/qutebrowser/html/warning-webkit.html
index 2797ea228..e175a12ae 100644
--- a/qutebrowser/html/warning-webkit.html
+++ b/qutebrowser/html/warning-webkit.html
@@ -69,11 +69,10 @@ installed.</p>
<p><b>QtWebEngine being unavailable on Parabola</b>: Claims of Parabola
developers about QtWebEngine being "non-free" have repeatedly been disputed,
and so far nobody came up with solid evidence about that being the case. Also,
-note that their qutebrowser package is orphaned and was often outdated in the
-past (even qutebrowser security fixes took months to arrive there). You
-might be better off chosing an <a
-href="https://qutebrowser.org/doc/install.html">alternative install
-method</a>.</p>
+note that their qutebrowser package was often outdated in the past (even
+qutebrowser security fixes took months to arrive there). You might be better
+off chosing an <a href="https://qutebrowser.org/doc/install.html#tox">
+alternative install method</a>.</p>
<p><b>White flashing between loads with a custom stylesheet</b>: This doesn't
seem to happen with <span class="mono">qt.process_model = single-process</span>
diff --git a/qutebrowser/javascript/.eslintrc.yaml b/qutebrowser/javascript/.eslintrc.yaml
index cb1bb1fcb..f4af6914b 100644
--- a/qutebrowser/javascript/.eslintrc.yaml
+++ b/qutebrowser/javascript/.eslintrc.yaml
@@ -60,3 +60,4 @@ rules:
max-lines-per-function: "off"
require-unicode-regexp: "off"
max-params: "off"
+ prefer-named-capture-group: "off"
diff --git a/qutebrowser/javascript/caret.js b/qutebrowser/javascript/caret.js
index 5e6640311..d337e2e4a 100644
--- a/qutebrowser/javascript/caret.js
+++ b/qutebrowser/javascript/caret.js
@@ -30,7 +30,7 @@ default-case */
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
- * Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+ * Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
*
* This file is part of qutebrowser.
*
@@ -1404,5 +1404,13 @@ window._qutebrowser.caret = (function() {
return CaretBrowsing.selectionEnabled;
};
+ funcs.reverseSelection = () => {
+ const sel = window.getSelection();
+ sel.setBaseAndExtent(
+ sel.extentNode, sel.extentOffset, sel.baseNode,
+ sel.baseOffset
+ );
+ };
+
return funcs;
})();
diff --git a/qutebrowser/javascript/global_wrapper.js b/qutebrowser/javascript/global_wrapper.js
index a302bd5d1..0762fd85d 100644
--- a/qutebrowser/javascript/global_wrapper.js
+++ b/qutebrowser/javascript/global_wrapper.js
@@ -1,6 +1,6 @@
(function() {
"use strict";
- if (!("_qutebrowser" in window)) {
+ if (!window.hasOwnProperty("_qutebrowser")) {
window._qutebrowser = {"initialized": {}};
}
diff --git a/qutebrowser/javascript/history.js b/qutebrowser/javascript/history.js
index 093b95b4e..706db9c65 100644
--- a/qutebrowser/javascript/history.js
+++ b/qutebrowser/javascript/history.js
@@ -1,4 +1,5 @@
/**
+ * Copyright 2017-2019 Florian Bruhin (The-Compiler) <me@the-compiler.org>
* Copyright 2017 Imran Sobir
*
* This file is part of qutebrowser.
diff --git a/qutebrowser/javascript/position_caret.js b/qutebrowser/javascript/position_caret.js
index 0ead360fb..5aeff44fa 100644
--- a/qutebrowser/javascript/position_caret.js
+++ b/qutebrowser/javascript/position_caret.js
@@ -1,6 +1,6 @@
/**
+* Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
* Copyright 2015 Artur Shaik <ashaihullin@gmail.com>
-* Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
*
* This file is part of qutebrowser.
*
diff --git a/qutebrowser/javascript/print.js b/qutebrowser/javascript/print.js
index ceb34aa65..b91b45c97 100644
--- a/qutebrowser/javascript/print.js
+++ b/qutebrowser/javascript/print.js
@@ -1,5 +1,5 @@
/**
- * Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+ * Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
*
* This file is part of qutebrowser.
*
diff --git a/qutebrowser/javascript/scroll.js b/qutebrowser/javascript/scroll.js
index 7205cb151..1f74a9956 100644
--- a/qutebrowser/javascript/scroll.js
+++ b/qutebrowser/javascript/scroll.js
@@ -1,5 +1,5 @@
/**
- * Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+ * Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
*
* This file is part of qutebrowser.
*
diff --git a/qutebrowser/javascript/stylesheet.js b/qutebrowser/javascript/stylesheet.js
index b1cdeb26e..549d9b88b 100644
--- a/qutebrowser/javascript/stylesheet.js
+++ b/qutebrowser/javascript/stylesheet.js
@@ -1,4 +1,5 @@
/**
+ * Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
* Copyright 2017 Ulrik de Muelenaere <ulrikdem@gmail.com>
*
* This file is part of qutebrowser.
@@ -40,6 +41,11 @@ window._qutebrowser.stylesheet = (function() {
// then move the stylesheet to the end. Partially inspired by Stylus:
// https://github.com/openstyles/stylus/blob/1.1.4.2/content/apply.js#L235-L355
function watch_root() {
+ if (!document.documentElement) {
+ root_observer.observe(document, {"childList": true});
+ return;
+ }
+
if (root_elem !== document.documentElement) {
root_elem = document.documentElement;
root_observer.disconnect();
@@ -53,7 +59,8 @@ window._qutebrowser.stylesheet = (function() {
function create_style() {
let ns = xhtml_ns;
- if (document.documentElement.namespaceURI === svg_ns) {
+ if (document.documentElement &&
+ document.documentElement.namespaceURI === svg_ns) {
ns = svg_ns;
}
style_elem = document.createElementNS(ns, "style");
diff --git a/qutebrowser/javascript/webelem.js b/qutebrowser/javascript/webelem.js
index c9d2d09a6..0bf65907c 100644
--- a/qutebrowser/javascript/webelem.js
+++ b/qutebrowser/javascript/webelem.js
@@ -1,5 +1,5 @@
/**
- * Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+ * Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
*
* This file is part of qutebrowser.
*
@@ -412,5 +412,10 @@ window._qutebrowser.webelem = (function() {
elem.selectionEnd = elem.value.length;
};
+ funcs.delete = (id) => {
+ const elem = elements[id];
+ elem.remove();
+ };
+
return funcs;
})();
diff --git a/qutebrowser/keyinput/__init__.py b/qutebrowser/keyinput/__init__.py
index 1cff4943b..c292f2df3 100644
--- a/qutebrowser/keyinput/__init__.py
+++ b/qutebrowser/keyinput/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/keyinput/basekeyparser.py b/qutebrowser/keyinput/basekeyparser.py
index 8161293cc..a6d257617 100644
--- a/qutebrowser/keyinput/basekeyparser.py
+++ b/qutebrowser/keyinput/basekeyparser.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/keyinput/keyutils.py b/qutebrowser/keyinput/keyutils.py
index bef3c7cf0..03abf6d7a 100644
--- a/qutebrowser/keyinput/keyutils.py
+++ b/qutebrowser/keyinput/keyutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/keyinput/macros.py b/qutebrowser/keyinput/macros.py
index 5bf1ab18b..a0116c19f 100644
--- a/qutebrowser/keyinput/macros.py
+++ b/qutebrowser/keyinput/macros.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Jan Verbeek (blyxxyz) <ring@openmailbox.org>
#
# This file is part of qutebrowser.
diff --git a/qutebrowser/keyinput/modeman.py b/qutebrowser/keyinput/modeman.py
index edb443eec..0389c9ab9 100644
--- a/qutebrowser/keyinput/modeman.py
+++ b/qutebrowser/keyinput/modeman.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -277,7 +277,9 @@ class ModeManager(QObject):
"""Enter a key mode.
Args:
- mode: The mode to enter.
+ mode: The mode to enter. See `:help bindings.commands` for the
+ available modes, but note that hint/command/yesno/prompt mode
+ can't be entered manually.
"""
try:
m = usertypes.KeyMode[mode]
diff --git a/qutebrowser/keyinput/modeparsers.py b/qutebrowser/keyinput/modeparsers.py
index 209d7dea2..e40d89f58 100644
--- a/qutebrowser/keyinput/modeparsers.py
+++ b/qutebrowser/keyinput/modeparsers.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/__init__.py b/qutebrowser/mainwindow/__init__.py
index 1b76e9b5a..50bf30add 100644
--- a/qutebrowser/mainwindow/__init__.py
+++ b/qutebrowser/mainwindow/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/mainwindow.py b/qutebrowser/mainwindow/mainwindow.py
index 34dc5c507..38eb7cab6 100644
--- a/qutebrowser/mainwindow/mainwindow.py
+++ b/qutebrowser/mainwindow/mainwindow.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -145,6 +145,18 @@ class MainWindow(QWidget):
_private: Whether the window is in private browsing mode.
"""
+ # Application wide stylesheets
+ STYLESHEET = """
+ HintLabel {
+ background-color: {{ conf.colors.hints.bg }};
+ color: {{ conf.colors.hints.fg }};
+ font: {{ conf.fonts.hints }};
+ border: {{ conf.hints.border }};
+ padding-left: 3px;
+ padding-right: 3px;
+ }
+ """
+
def __init__(self, *, private, geometry=None, parent=None):
"""Create a new main window.
@@ -240,6 +252,7 @@ class MainWindow(QWidget):
self._set_decoration(config.val.window.hide_decoration)
self.state_before_fullscreen = self.windowState()
+ config.set_register_stylesheet(self)
def _init_geometry(self, geometry):
"""Initialize the window geometry or load it from disk."""
@@ -474,8 +487,7 @@ class MainWindow(QWidget):
# statusbar
self.tabbed_browser.current_tab_changed.connect(status.on_tab_changed)
- self.tabbed_browser.cur_progress.connect(status.prog.setValue)
- self.tabbed_browser.cur_load_finished.connect(status.prog.hide)
+ self.tabbed_browser.cur_progress.connect(status.prog.on_load_progress)
self.tabbed_browser.cur_load_started.connect(
status.prog.on_load_started)
@@ -584,8 +596,7 @@ class MainWindow(QWidget):
quit_texts = []
# Ask if multiple-tabs are open
if 'multiple-tabs' in config.val.confirm_quit and tab_count > 1:
- quit_texts.append("{} {} open.".format(
- tab_count, "tab is" if tab_count == 1 else "tabs are"))
+ quit_texts.append("{} tabs are open.".format(tab_count))
# Ask if multiple downloads running
if 'downloads' in config.val.confirm_quit and download_count > 0:
quit_texts.append("{} {} running.".format(
diff --git a/qutebrowser/mainwindow/messageview.py b/qutebrowser/mainwindow/messageview.py
index 43ddd5248..b00ae6202 100644
--- a/qutebrowser/mainwindow/messageview.py
+++ b/qutebrowser/mainwindow/messageview.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -103,13 +103,17 @@ class MessageView(QWidget):
interval *= min(5, len(self._messages))
self._clear_timer.setInterval(interval)
+ def _remove_message(self, widget):
+ """Fully remove and destroy widget from this object."""
+ self._vbox.removeWidget(widget)
+ widget.hide()
+ widget.deleteLater()
+
@pyqtSlot()
def clear_messages(self):
"""Hide and delete all messages."""
for widget in self._messages:
- self._vbox.removeWidget(widget)
- widget.hide()
- widget.deleteLater()
+ self._remove_message(widget)
self._messages = []
self._last_text = None
self.hide()
@@ -122,8 +126,7 @@ class MessageView(QWidget):
return
if replace and self._messages and self._messages[-1].replace:
- old = self._messages.pop()
- old.hide()
+ self._remove_message(self._messages.pop())
widget = Message(level, text, replace=replace, parent=self)
self._vbox.addWidget(widget)
diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py
index f666aa837..9fd3da8dd 100644
--- a/qutebrowser/mainwindow/prompt.py
+++ b/qutebrowser/mainwindow/prompt.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -22,6 +22,7 @@
import os.path
import html
import collections
+import functools
import attr
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QTimer, QDir, QModelIndex,
@@ -35,7 +36,6 @@ from qutebrowser.config import config
from qutebrowser.utils import usertypes, log, utils, qtutils, objreg, message
from qutebrowser.keyinput import modeman
from qutebrowser.api import cmdutils
-from qutebrowser.qt import sip
prompt_queue = None
@@ -117,10 +117,11 @@ class PromptQueue(QObject):
log.prompt.debug("Popping from queue {}".format(self._queue))
if self._queue:
question = self._queue.popleft()
- if not sip.isdeleted(question):
- # the question could already be deleted, e.g. by a cancelled
+ if not question.is_aborted:
+ # the question could already be aborted, e.g. by a cancelled
# download. See
- # https://github.com/qutebrowser/qutebrowser/issues/415
+ # https://github.com/qutebrowser/qutebrowser/issues/415 and
+ # https://github.com/qutebrowser/qutebrowser/issues/1249
self.ask_question(question, blocking=False)
def shutdown(self):
@@ -329,11 +330,10 @@ class PromptContainer(QWidget):
log.prompt.debug("Displaying prompt {}".format(prompt))
self._prompt = prompt
+ # If this question was interrupted, we already connected the signal
if not question.interrupted:
- # If this question was interrupted, we already connected the signal
question.aborted.connect(
- lambda: modeman.leave(self._win_id, prompt.KEY_MODE, 'aborted',
- maybe=True))
+ functools.partial(self._on_aborted, prompt.KEY_MODE))
modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked')
self.setSizePolicy(prompt.sizePolicy())
@@ -343,6 +343,15 @@ class PromptContainer(QWidget):
prompt.setFocus()
self.update_geometry.emit()
+ @pyqtSlot()
+ def _on_aborted(self, key_mode):
+ """Leave KEY_MODE whenever a prompt is aborted."""
+ try:
+ modeman.leave(self._win_id, key_mode, 'aborted', maybe=True)
+ except objreg.RegistryUnavailableError:
+ # window was deleted: ignore
+ pass
+
@pyqtSlot(usertypes.KeyMode)
def _on_prompt_done(self, key_mode):
"""Leave the prompt mode in this window if a question was answered."""
diff --git a/qutebrowser/mainwindow/statusbar/__init__.py b/qutebrowser/mainwindow/statusbar/__init__.py
index eee7cf990..a65da3461 100644
--- a/qutebrowser/mainwindow/statusbar/__init__.py
+++ b/qutebrowser/mainwindow/statusbar/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/statusbar/backforward.py b/qutebrowser/mainwindow/statusbar/backforward.py
index 5e244cf8c..63f502be7 100644
--- a/qutebrowser/mainwindow/statusbar/backforward.py
+++ b/qutebrowser/mainwindow/statusbar/backforward.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/statusbar/bar.py b/qutebrowser/mainwindow/statusbar/bar.py
index 13a368f05..5b1b17847 100644
--- a/qutebrowser/mainwindow/statusbar/bar.py
+++ b/qutebrowser/mainwindow/statusbar/bar.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -101,9 +101,12 @@ def _generate_stylesheet():
QWidget#StatusBar QLabel,
QWidget#StatusBar QLineEdit {
font: {{ conf.fonts.statusbar }};
- background-color: {{ conf.colors.statusbar.normal.bg }};
color: {{ conf.colors.statusbar.normal.fg }};
}
+
+ QWidget#StatusBar {
+ background-color: {{ conf.colors.statusbar.normal.bg }};
+ }
"""
for flag, option in flags:
stylesheet += """
@@ -111,10 +114,13 @@ def _generate_stylesheet():
QWidget#StatusBar[color_flags~="%s"] QLabel,
QWidget#StatusBar[color_flags~="%s"] QLineEdit {
color: {{ conf.colors.%s }};
+ }
+
+ QWidget#StatusBar[color_flags~="%s"] {
background-color: {{ conf.colors.%s }};
}
""" % (flag, flag, flag, # noqa: S001
- option + '.fg', option + '.bg')
+ option + '.fg', flag, option + '.bg')
return stylesheet
diff --git a/qutebrowser/mainwindow/statusbar/command.py b/qutebrowser/mainwindow/statusbar/command.py
index 1661d2362..bdac24d61 100644
--- a/qutebrowser/mainwindow/statusbar/command.py
+++ b/qutebrowser/mainwindow/statusbar/command.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/statusbar/keystring.py b/qutebrowser/mainwindow/statusbar/keystring.py
index 73b23a65d..6e4bf6520 100644
--- a/qutebrowser/mainwindow/statusbar/keystring.py
+++ b/qutebrowser/mainwindow/statusbar/keystring.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/statusbar/percentage.py b/qutebrowser/mainwindow/statusbar/percentage.py
index a362fd9d6..90aea7910 100644
--- a/qutebrowser/mainwindow/statusbar/percentage.py
+++ b/qutebrowser/mainwindow/statusbar/percentage.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/statusbar/progress.py b/qutebrowser/mainwindow/statusbar/progress.py
index 6c467150b..34c1954e8 100644
--- a/qutebrowser/mainwindow/statusbar/progress.py
+++ b/qutebrowser/mainwindow/statusbar/progress.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -60,6 +60,19 @@ class Progress(QProgressBar):
self.setValue(0)
self.setVisible(self.enabled)
+ @pyqtSlot(int)
+ def on_load_progress(self, value):
+ """Hide the statusbar when loading finished.
+
+ We use this instead of loadFinished because we sometimes get
+ loadStarted and loadProgress(100) without loadFinished from Qt.
+
+ WORKAROUND for https://bugreports.qt.io/browse/QTBUG-65223
+ """
+ self.setValue(value)
+ if value == 100:
+ self.hide()
+
def on_tab_changed(self, tab):
"""Set the correct value when the current tab changed."""
self.setValue(tab.progress())
diff --git a/qutebrowser/mainwindow/statusbar/tabindex.py b/qutebrowser/mainwindow/statusbar/tabindex.py
index 47a775f34..fca2a28a4 100644
--- a/qutebrowser/mainwindow/statusbar/tabindex.py
+++ b/qutebrowser/mainwindow/statusbar/tabindex.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/statusbar/text.py b/qutebrowser/mainwindow/statusbar/text.py
index 0a57446f1..f083889c5 100644
--- a/qutebrowser/mainwindow/statusbar/text.py
+++ b/qutebrowser/mainwindow/statusbar/text.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/statusbar/textbase.py b/qutebrowser/mainwindow/statusbar/textbase.py
index 399fafee7..f58c63402 100644
--- a/qutebrowser/mainwindow/statusbar/textbase.py
+++ b/qutebrowser/mainwindow/statusbar/textbase.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/statusbar/url.py b/qutebrowser/mainwindow/statusbar/url.py
index c6f436617..a99c23529 100644
--- a/qutebrowser/mainwindow/statusbar/url.py
+++ b/qutebrowser/mainwindow/statusbar/url.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py
index 9c14df3ae..15e2c7247 100644
--- a/qutebrowser/mainwindow/tabbedbrowser.py
+++ b/qutebrowser/mainwindow/tabbedbrowser.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -19,6 +19,7 @@
"""The main tabbed browser widget."""
+import collections
import functools
import attr
@@ -111,6 +112,8 @@ class TabbedBrowser(QWidget):
new_tab = pyqtSignal(browsertab.AbstractTab, int)
def __init__(self, *, win_id, private, parent=None):
+ if private:
+ assert not qtutils.is_single_process()
super().__init__(parent)
self.widget = tabwidget.TabWidget(win_id, parent=self)
self._win_id = win_id
@@ -120,10 +123,19 @@ class TabbedBrowser(QWidget):
self.widget.tabCloseRequested.connect(self.on_tab_close_requested)
self.widget.new_tab_requested.connect(self.tabopen)
self.widget.currentChanged.connect(self.on_current_changed)
- self.cur_load_started.connect(self.on_cur_load_started)
self.cur_fullscreen_requested.connect(self.widget.tabBar().maybe_hide)
self.widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
- self._undo_stack = []
+
+ # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-65223
+ if qtutils.version_check('5.10', compiled=False):
+ self.cur_load_finished.connect(self._leave_modes_on_load)
+ else:
+ self.cur_load_started.connect(self._leave_modes_on_load)
+
+ # This init is never used, it is immediately thrown away in the next
+ # line.
+ self._undo_stack = collections.deque()
+ self._update_stack_size()
self._filter = signalfilter.SignalFilter(win_id, self)
self._now_focused = None
self.search_text = None
@@ -134,6 +146,13 @@ class TabbedBrowser(QWidget):
self.is_private = private
config.instance.changed.connect(self._on_config_changed)
+ def _update_stack_size(self):
+ newsize = config.instance.get('tabs.undo_stack_size')
+ if newsize < 0:
+ newsize = None
+ # We can't resize a collections.deque so just recreate it >:(
+ self._undo_stack = collections.deque(self._undo_stack, maxlen=newsize)
+
def __repr__(self):
return utils.get_repr(self, count=self.widget.count())
@@ -143,6 +162,8 @@ class TabbedBrowser(QWidget):
self._update_favicons()
elif option == 'window.title_format':
self._update_window_title()
+ elif option == 'tabs.undo_stack_size':
+ self._update_stack_size()
elif option in ['tabs.title.format', 'tabs.title.format_pinned']:
self.widget.update_tab_titles()
@@ -442,7 +463,7 @@ class TabbedBrowser(QWidget):
Args:
url: The URL to open as QUrl or None for an empty tab.
background: Whether to open the tab in the background.
- if None, the `tabs.background_tabs`` setting decides.
+ if None, the `tabs.background` setting decides.
related: Whether the tab was opened from another existing tab.
If this is set, the new position might be different. With
the default settings we handle it like Chromium does:
@@ -584,12 +605,25 @@ class TabbedBrowser(QWidget):
self._update_window_title()
@pyqtSlot()
- def on_cur_load_started(self):
+ def _leave_modes_on_load(self):
"""Leave insert/hint mode when loading started."""
- modeman.leave(self._win_id, usertypes.KeyMode.insert, 'load started',
- maybe=True)
- modeman.leave(self._win_id, usertypes.KeyMode.hint, 'load started',
- maybe=True)
+ try:
+ url = self.current_url()
+ if not url.isValid():
+ url = None
+ except qtutils.QtValueError:
+ url = None
+ if config.instance.get('input.insert_mode.leave_on_load',
+ url=url):
+ modeman.leave(self._win_id, usertypes.KeyMode.insert,
+ 'load started', maybe=True)
+ else:
+ log.modes.debug("Ignoring leave_on_load request due to setting.")
+ if config.cache['hints.leave_on_load']:
+ modeman.leave(self._win_id, usertypes.KeyMode.hint,
+ 'load started', maybe=True)
+ else:
+ log.modes.debug("Ignoring leave_on_load request due to setting.")
@pyqtSlot(browsertab.AbstractTab, str)
def on_title_changed(self, tab, text):
diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py
index ca4be6d50..b90bc22ad 100644
--- a/qutebrowser/mainwindow/tabwidget.py
+++ b/qutebrowser/mainwindow/tabwidget.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -20,7 +20,6 @@
"""The tab widget used for TabbedBrowser from browser.py."""
import functools
-import enum
import contextlib
import attr
@@ -37,13 +36,6 @@ from qutebrowser.misc import objects
from qutebrowser.browser import browsertab
-class PixelMetrics(enum.IntEnum):
-
- """Custom PixelMetrics attributes."""
-
- icon_padding = QStyle.PM_CustomBase
-
-
class TabWidget(QTabWidget):
"""The tab widget used for TabbedBrowser.
@@ -149,7 +141,7 @@ class TabWidget(QTabWidget):
return
fields = self.get_tab_fields(idx)
- fields['title'] = fields['title'].replace('&', '&&')
+ fields['current_title'] = fields['current_title'].replace('&', '&&')
fields['index'] = idx + 1
title = '' if fmt is None else fmt.format(**fields)
@@ -161,7 +153,7 @@ class TabWidget(QTabWidget):
tabbar.setTabText(idx, title)
# always show only plain title in tooltips
- tabbar.setTabToolTip(idx, fields['title'])
+ tabbar.setTabToolTip(idx, fields['current_title'])
def get_tab_fields(self, idx):
"""Get the tab field data."""
@@ -173,7 +165,7 @@ class TabWidget(QTabWidget):
fields = {}
fields['id'] = tab.tab_id
- fields['title'] = page_title
+ fields['current_title'] = page_title
fields['title_sep'] = ' - ' if page_title else ''
fields['perc_raw'] = tab.progress()
fields['backend'] = objects.backend.name
@@ -276,7 +268,6 @@ class TabWidget(QTabWidget):
The index of the newly added tab.
"""
if text_or_empty is None:
- icon = None
text = icon_or_text
new_idx = super().addTab(page, '')
else:
@@ -306,7 +297,6 @@ class TabWidget(QTabWidget):
The index of the newly added tab.
"""
if text_or_empty is None:
- icon = None
text = icon_or_text
new_idx = super().insertTab(idx, page, '')
else:
@@ -355,6 +345,17 @@ class TabWidget(QTabWidget):
if config.val.tabs.tabs_are_windows:
self.window().setWindowIcon(self.window().windowIcon())
+ def setTabIcon(self, idx: int, icon: QIcon):
+ """Always show tab icons for pinned tabs in some circumstances."""
+ tab = self.widget(idx)
+ if (icon.isNull() and
+ config.cache['tabs.favicons.show'] != 'never' and
+ config.cache['tabs.pinned.shrink'] and
+ not self.tabBar().vertical and
+ tab is not None and tab.data.pinned):
+ icon = self.style().standardIcon(QStyle.SP_FileIcon)
+ super().setTabIcon(idx, icon)
+
class TabBar(QTabBar):
@@ -374,6 +375,12 @@ class TabBar(QTabBar):
new_tab_requested: Emitted when a new tab is requested.
"""
+ STYLESHEET = """
+ TabBar {
+ background-color: {{ conf.colors.tabs.bar.bg }};
+ }
+ """
+
new_tab_requested = pyqtSignal()
def __init__(self, win_id, parent=None):
@@ -388,8 +395,8 @@ class TabBar(QTabBar):
self._auto_hide_timer.timeout.connect(self.maybe_hide)
self._on_show_switching_delay_changed()
self.setAutoFillBackground(True)
- self._set_colors()
self.drag_in_progress = False
+ config.set_register_stylesheet(self)
QTimer.singleShot(0, self.maybe_hide)
def __repr__(self):
@@ -405,8 +412,6 @@ class TabBar(QTabBar):
self._set_font()
elif option == 'tabs.favicons.scale':
self._set_icon_size()
- elif option == 'colors.tabs.bar.bg':
- self._set_colors()
elif option == 'tabs.show_switching_delay':
self._on_show_switching_delay_changed()
elif option == 'tabs.show':
@@ -507,12 +512,6 @@ class TabBar(QTabBar):
size *= config.val.tabs.favicons.scale
self.setIconSize(QSize(size, size))
- def _set_colors(self):
- """Set the tab bar colors."""
- p = self.palette()
- p.setColor(QPalette.Window, config.val.colors.tabs.bar.bg)
- self.setPalette(p)
-
def mouseReleaseEvent(self, e):
"""Override mouseReleaseEvent to know when drags stop."""
self.drag_in_progress = False
@@ -555,13 +554,12 @@ class TabBar(QTabBar):
A QSize of the smallest tab size we can make.
"""
icon = self.tabIcon(index)
- icon_padding = self.style().pixelMetric(PixelMetrics.icon_padding,
- None, self)
if icon.isNull():
icon_width = 0
else:
- icon_width = min(icon.actualSize(self.iconSize()).width(),
- self.iconSize().width()) + icon_padding
+ icon_width = min(
+ icon.actualSize(self.iconSize()).width(),
+ self.iconSize().width()) + TabBarStyle.ICON_PADDING
pinned = self._tab_pinned(index)
if not self.vertical and pinned and config.val.tabs.pinned.shrink:
@@ -681,6 +679,8 @@ class TabBar(QTabBar):
self.initStyleOption(tab, idx)
setting = 'colors.tabs'
+ if self._tab_pinned(idx):
+ setting += '.pinned'
if idx == selected:
setting += '.selected'
setting += '.odd' if (idx + 1) % 2 else '.even'
@@ -749,6 +749,8 @@ class TabBarStyle(QCommonStyle):
https://code.google.com/p/makehuman/source/browse/trunk/makehuman/lib/qtgui.py
"""
+ ICON_PADDING = 4
+
def __init__(self):
"""Initialize all functions we're not overriding.
@@ -854,8 +856,6 @@ class TabBarStyle(QCommonStyle):
QStyle.PM_TabBarTabVSpace,
QStyle.PM_TabBarScrollButtonWidth]:
return 0
- elif metric == PixelMetrics.icon_padding:
- return 4
else:
return self._style.pixelMetric(metric, option, widget)
@@ -931,8 +931,8 @@ class TabBarStyle(QCommonStyle):
icon_rect = self._get_icon_rect(opt, text_rect)
if icon_rect.isValid():
- icon_padding = self.pixelMetric(PixelMetrics.icon_padding, opt)
- text_rect.adjust(icon_rect.width() + icon_padding, 0, 0, 0)
+ text_rect.adjust(
+ icon_rect.width() + TabBarStyle.ICON_PADDING, 0, 0, 0)
text_rect = self._style.visualRect(opt.direction, opt.rect, text_rect)
return Layouts(text=text_rect, icon=icon_rect,
diff --git a/qutebrowser/misc/__init__.py b/qutebrowser/misc/__init__.py
index 2be43490a..5164c0fde 100644
--- a/qutebrowser/misc/__init__.py
+++ b/qutebrowser/misc/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/autoupdate.py b/qutebrowser/misc/autoupdate.py
index d223bd366..51aa84112 100644
--- a/qutebrowser/misc/autoupdate.py
+++ b/qutebrowser/misc/autoupdate.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/backendproblem.py b/qutebrowser/misc/backendproblem.py
index 74a2ad372..796d97fea 100644
--- a/qutebrowser/misc/backendproblem.py
+++ b/qutebrowser/misc/backendproblem.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -26,6 +26,7 @@ import html
import ctypes
import ctypes.util
import enum
+import shutil
import attr
from PyQt5.QtCore import Qt
@@ -33,8 +34,9 @@ from PyQt5.QtWidgets import (QApplication, QDialog, QPushButton, QHBoxLayout,
QVBoxLayout, QLabel, QMessageBox)
from PyQt5.QtNetwork import QSslSocket
-from qutebrowser.config import config
-from qutebrowser.utils import usertypes, objreg, version, qtutils, log, utils
+from qutebrowser.config import config, configfiles
+from qutebrowser.utils import (usertypes, objreg, version, qtutils, log, utils,
+ standarddir)
from qutebrowser.misc import objects, msgbox
@@ -178,6 +180,10 @@ def _nvidia_shader_workaround():
See https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
"""
assert objects.backend == usertypes.Backend.QtWebEngine, objects.backend
+
+ if os.environ.get('QUTE_SKIP_LIBGL_WORKAROUND'):
+ return
+
libgl = ctypes.util.find_library("GL")
if libgl is not None:
ctypes.CDLL(libgl, mode=ctypes.RTLD_GLOBAL)
@@ -393,6 +399,29 @@ def _check_backend_modules():
raise utils.Unreachable
+def _handle_cache_nuking():
+ """Nuke the QtWebEngine cache if the Qt version changed.
+
+ WORKAROUND for https://bugreports.qt.io/browse/QTBUG-72532
+ """
+ if not configfiles.state.qt_version_changed:
+ return
+
+ # Only nuke the cache in cases where we know there are problems.
+ # It seems these issues started with Qt 5.12.
+ # They should be fixed with Qt 5.12.5:
+ # https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/265408
+ affected = (qtutils.version_check('5.12', compiled=False) and not
+ qtutils.version_check('5.12.5', compiled=False))
+ if not affected:
+ return
+
+ log.init.info("Qt version changed, nuking QtWebEngine cache")
+ cache_dir = os.path.join(standarddir.cache(), 'webengine')
+ if os.path.exists(cache_dir):
+ shutil.rmtree(cache_dir)
+
+
def init():
"""Check for various issues related to QtWebKit/QtWebEngine."""
_check_backend_modules()
@@ -401,6 +430,7 @@ def init():
_handle_wayland()
_nvidia_shader_workaround()
_handle_nouveau_graphics()
+ _handle_cache_nuking()
else:
assert objects.backend == usertypes.Backend.QtWebKit, objects.backend
_handle_ssl_support(fatal=True)
diff --git a/qutebrowser/misc/checkpyver.py b/qutebrowser/misc/checkpyver.py
index cf8e13810..aab373648 100644
--- a/qutebrowser/misc/checkpyver.py
+++ b/qutebrowser/misc/checkpyver.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The-Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The-Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -31,7 +31,7 @@ except ImportError: # pragma: no cover
try:
# Python2
from Tkinter import Tk # type: ignore
- import tkMessageBox as messagebox # type: ignore
+ import tkMessageBox as messagebox # type: ignore # noqa: N813
except ImportError:
# Some Python without Tk
Tk = None # type: ignore
@@ -46,9 +46,7 @@ def check_python_version():
if sys.hexversion < 0x03050000:
# We don't use .format() and print_function here just in case someone
# still has < 2.6 installed.
- # pylint: disable=bad-builtin
version_str = '.'.join(map(str, sys.version_info[:3]))
- # pylint: enable=bad-builtin
text = ("At least Python 3.5 is required to run qutebrowser, but " +
"it's running with " + version_str + ".\n")
if Tk and '--no-err-windows' not in sys.argv: # pragma: no cover
diff --git a/qutebrowser/misc/cmdhistory.py b/qutebrowser/misc/cmdhistory.py
index 0a3ac9fa9..ef51b60e1 100644
--- a/qutebrowser/misc/cmdhistory.py
+++ b/qutebrowser/misc/cmdhistory.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/consolewidget.py b/qutebrowser/misc/consolewidget.py
index 661c7b805..138ce76c8 100644
--- a/qutebrowser/misc/consolewidget.py
+++ b/qutebrowser/misc/consolewidget.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -162,7 +162,7 @@ class ConsoleWidget(QWidget):
namespace = {
'__name__': '__console__',
'__doc__': None,
- 'qApp': QApplication.instance(),
+ 'q_app': QApplication.instance(),
# We use parent as self here because the user "feels" the whole
# console, not just the line edit.
'self': parent,
diff --git a/qutebrowser/misc/crashdialog.py b/qutebrowser/misc/crashdialog.py
index 06a5aabc5..de89a2436 100644
--- a/qutebrowser/misc/crashdialog.py
+++ b/qutebrowser/misc/crashdialog.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -585,7 +585,10 @@ class ReportDialog(_CrashDialog):
("Objects", self._qobjects),
]
try:
- self._crash_info.append(("Debug log", log.ram_handler.dump_log()))
+ text = "Log output was disabled."
+ if log.ram_handler is not None:
+ text = log.ram_handler.dump_log()
+ self._crash_info.append(("Debug log", text))
except Exception:
self._crash_info.append(("Debug log", traceback.format_exc()))
diff --git a/qutebrowser/misc/crashsignal.py b/qutebrowser/misc/crashsignal.py
index 7890380e8..6bbd480f1 100644
--- a/qutebrowser/misc/crashsignal.py
+++ b/qutebrowser/misc/crashsignal.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -66,6 +66,7 @@ class CrashHandler(QObject):
_args: The argparse namespace.
_crash_dialog: The CrashDialog currently being shown.
_crash_log_file: The file handle for the faulthandler crash log.
+ _crash_log_data: Crash data read from the previous crash log.
"""
def __init__(self, *, app, quitter, args, parent=None):
@@ -74,28 +75,23 @@ class CrashHandler(QObject):
self._quitter = quitter
self._args = args
self._crash_log_file = None
+ self._crash_log_data = None
self._crash_dialog = None
def activate(self):
"""Activate the exception hook."""
sys.excepthook = self.exception_hook
- def handle_segfault(self):
- """Handle a segfault from a previous run."""
+ def init_faulthandler(self):
+ """Handle a segfault from a previous run and set up faulthandler."""
logname = os.path.join(standarddir.data(), 'crash.log')
try:
# First check if an old logfile exists.
if os.path.exists(logname):
with open(logname, 'r', encoding='ascii') as f:
- data = f.read()
+ self._crash_log_data = f.read()
os.remove(logname)
self._init_crashlogfile()
- if data:
- # Crashlog exists and has data in it, so something crashed
- # previously.
- self._crash_dialog = crashdialog.FatalCrashDialog(
- self._args.debug, data)
- self._crash_dialog.show()
else:
# There's no log file, so we can use this to display crashes to
# the user on the next start.
@@ -104,6 +100,17 @@ class CrashHandler(QObject):
log.init.exception("Error while handling crash log file!")
self._init_crashlogfile()
+ def display_faulthandler(self):
+ """If there was data in the crash log file, display a dialog."""
+ assert not self._args.no_err_windows
+ if self._crash_log_data:
+ # Crashlog exists and has data in it, so something crashed
+ # previously.
+ self._crash_dialog = crashdialog.FatalCrashDialog(
+ self._args.debug, self._crash_log_data)
+ self._crash_dialog.show()
+ self._crash_log_data = None
+
def _recover_pages(self, forgiving=False):
"""Try to recover all open pages.
@@ -137,7 +144,6 @@ class CrashHandler(QObject):
def _init_crashlogfile(self):
"""Start a new logfile and redirect faulthandler to it."""
- assert not self._args.no_err_windows
logname = os.path.join(standarddir.data(), 'crash.log')
try:
self._crash_log_file = open(logname, 'w', encoding='ascii')
diff --git a/qutebrowser/misc/earlyinit.py b/qutebrowser/misc/earlyinit.py
index 690ede60f..e8040c670 100644
--- a/qutebrowser/misc/earlyinit.py
+++ b/qutebrowser/misc/earlyinit.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The-Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The-Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -173,8 +173,10 @@ def check_qt_version():
PYQT_VERSION_STR)
from pkg_resources import parse_version
from qutebrowser.utils import log
+ parsed_qversion = parse_version(qVersion())
+
if (QT_VERSION < 0x050701 or PYQT_VERSION < 0x050700 or
- parse_version(qVersion()) < parse_version('5.7.1')):
+ parsed_qversion < parse_version('5.7.1')):
text = ("Fatal error: Qt >= 5.7.1 and PyQt >= 5.7 are required, "
"but Qt {} / PyQt {} is installed.".format(qt_version(),
PYQT_VERSION_STR))
@@ -184,6 +186,12 @@ def check_qt_version():
log.init.warning("Running qutebrowser with Qt 5.8 is untested and "
"unsupported!")
+ if (parsed_qversion >= parse_version('5.12') and
+ (PYQT_VERSION < 0x050c00 or QT_VERSION < 0x050c00)):
+ log.init.warning("Combining PyQt {} with Qt {} is unsupported! Ensure "
+ "all versions are newer than 5.12 to avoid potential "
+ "issues.".format(PYQT_VERSION_STR, qt_version()))
+
def check_ssl_support():
"""Check if SSL support is available."""
@@ -199,19 +207,11 @@ def _check_modules(modules):
for name, text in modules.items():
try:
- # https://github.com/pallets/jinja/pull/628
- # https://bitbucket.org/birkenfeld/pygments-main/issues/1314/
- # https://github.com/pallets/jinja/issues/646
# https://bitbucket.org/fdik/pypeg/commits/dd15ca462b532019c0a3be1d39b8ee2f3fa32f4e
- messages = ['invalid escape sequence',
- 'Flags not at the start of the expression']
# pylint: disable=bad-continuation
with log.ignore_py_warnings(
category=DeprecationWarning,
- message=r'({})'.format('|'.join(messages))
- ), log.ignore_py_warnings(
- category=PendingDeprecationWarning,
- module='imp'
+ message=r'invalid escape sequence'
), log.ignore_py_warnings(
category=ImportWarning,
message=r'Not importing directory .*: missing __init__'
diff --git a/qutebrowser/misc/editor.py b/qutebrowser/misc/editor.py
index 3c5b7471e..c5b423708 100644
--- a/qutebrowser/misc/editor.py
+++ b/qutebrowser/misc/editor.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/guiprocess.py b/qutebrowser/misc/guiprocess.py
index 52dc352a7..36b66c887 100644
--- a/qutebrowser/misc/guiprocess.py
+++ b/qutebrowser/misc/guiprocess.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -28,19 +28,6 @@ from PyQt5.QtCore import (pyqtSlot, pyqtSignal, QObject, QProcess,
from qutebrowser.utils import message, log
from qutebrowser.browser import qutescheme
-# A mapping of QProcess::ErrorCode's to human-readable strings.
-
-ERROR_STRINGS = {
- QProcess.FailedToStart: "The process failed to start.",
- QProcess.Crashed: "The process crashed.",
- QProcess.Timedout: "The last waitFor...() function timed out.",
- QProcess.WriteError: ("An error occurred when attempting to write to the "
- "process."),
- QProcess.ReadError: ("An error occurred when attempting to read from the "
- "process."),
- QProcess.UnknownError: "An unknown error occurred.",
-}
-
class GUIProcess(QObject):
@@ -73,11 +60,11 @@ class GUIProcess(QObject):
self.args = None
self._proc = QProcess(self)
- self._proc.error.connect(self.on_error)
- self._proc.error.connect(self.error)
- self._proc.finished.connect(self.on_finished)
+ self._proc.errorOccurred.connect(self._on_error)
+ self._proc.errorOccurred.connect(self.error)
+ self._proc.finished.connect(self._on_finished)
self._proc.finished.connect(self.finished)
- self._proc.started.connect(self.on_started)
+ self._proc.started.connect(self._on_started)
self._proc.started.connect(self.started)
if additional_env is not None:
@@ -86,14 +73,14 @@ class GUIProcess(QObject):
procenv.insert(k, v)
self._proc.setProcessEnvironment(procenv)
- @pyqtSlot(QProcess.ProcessError)
- def on_error(self, error):
+ @pyqtSlot()
+ def _on_error(self):
"""Show a message if there was an error while spawning."""
- msg = ERROR_STRINGS[error]
+ msg = self._proc.errorString()
message.error("Error while spawning {}: {}".format(self._what, msg))
@pyqtSlot(int, QProcess.ExitStatus)
- def on_finished(self, code, status):
+ def _on_finished(self, code, status):
"""Show a message when the process finished."""
self._started = False
log.procs.debug("Process finished with code {}, status {}.".format(
@@ -105,40 +92,42 @@ class GUIProcess(QObject):
stdout = bytes(self._proc.readAllStandardOutput()).decode(
encoding, 'replace')
- qutescheme.spawn_output = self._spawn_format(code, status,
- stdout, stderr)
-
if status == QProcess.CrashExit:
- message.error("{} crashed!".format(self._what.capitalize()))
+ exitinfo = "{} crashed!".format(self._what.capitalize())
+ message.error(exitinfo)
elif status == QProcess.NormalExit and code == 0:
+ exitinfo = "{} exited successfully.".format(
+ self._what.capitalize())
if self.verbose:
- message.info("{} exited successfully.".format(
- self._what.capitalize()))
+ message.info(exitinfo)
else:
assert status == QProcess.NormalExit
# We call this 'status' here as it makes more sense to the user -
# it's actually 'code'.
- message.error("{} exited with status {}, see :messages for "
- "details.".format(self._what.capitalize(), code))
+ exitinfo = ("{} exited with status {}, see :messages for "
+ "details.").format(self._what.capitalize(), code)
+ message.error(exitinfo)
if stdout:
log.procs.error("Process stdout:\n" + stdout.strip())
if stderr:
log.procs.error("Process stderr:\n" + stderr.strip())
- def _spawn_format(self, code=0, status=0, stdout="", stderr=""):
+ qutescheme.spawn_output = self._spawn_format(exitinfo, stdout, stderr)
+
+ def _spawn_format(self, exitinfo, stdout, stderr):
"""Produce a formatted string for spawn output."""
stdout = (stdout or "(No output)").strip()
stderr = (stderr or "(No output)").strip()
- spawn_string = ("Process finished with code {}, status {}\n"
+ spawn_string = ("{}\n"
"\nProcess stdout:\n {}"
- "\nProcess stderr:\n {}").format(code, status,
+ "\nProcess stderr:\n {}").format(exitinfo,
stdout, stderr)
return spawn_string
@pyqtSlot()
- def on_started(self):
+ def _on_started(self):
"""Called when the process started successfully."""
log.procs.debug("Process started.")
assert not self._started
@@ -155,28 +144,26 @@ class GUIProcess(QObject):
if self.verbose:
message.info('Executing: ' + fake_cmdline)
- def start(self, cmd, args, mode=None):
+ def start(self, cmd, args):
"""Convenience wrapper around QProcess::start."""
log.procs.debug("Starting process.")
self._pre_start(cmd, args)
- if mode is None:
- self._proc.start(cmd, args)
- else:
- self._proc.start(cmd, args, mode)
+ self._proc.start(cmd, args)
self._proc.closeWriteChannel()
- def start_detached(self, cmd, args, cwd=None):
+ def start_detached(self, cmd, args):
"""Convenience wrapper around QProcess::startDetached."""
log.procs.debug("Starting detached.")
self._pre_start(cmd, args)
- ok, _pid = self._proc.startDetached(cmd, args, cwd)
+ ok, _pid = self._proc.startDetached(cmd, args, None)
- if ok:
- log.procs.debug("Process started.")
- self._started = True
- else:
- message.error("Error while spawning {}: {}".format(
- self._what, ERROR_STRINGS[self._proc.error()]))
+ if not ok:
+ message.error("Error while spawning {}".format(self._what))
+ return False
+
+ log.procs.debug("Process started.")
+ self._started = True
+ return True
def exit_status(self):
return self._proc.exitStatus()
diff --git a/qutebrowser/misc/httpclient.py b/qutebrowser/misc/httpclient.py
index 0b162befd..3478884da 100644
--- a/qutebrowser/misc/httpclient.py
+++ b/qutebrowser/misc/httpclient.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/ipc.py b/qutebrowser/misc/ipc.py
index 3c718de7b..f7bf6e826 100644
--- a/qutebrowser/misc/ipc.py
+++ b/qutebrowser/misc/ipc.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -65,11 +65,9 @@ def _get_socketname(basedir):
data_to_hash = '-'.join(parts_to_hash).encode('utf-8')
md5 = hashlib.md5(data_to_hash).hexdigest()
- target_dir = standarddir.runtime()
-
- parts = ['ipc']
- parts.append(md5)
- return os.path.join(target_dir, '-'.join(parts))
+ prefix = 'i-' if utils.is_mac else 'ipc-'
+ filename = '{}{}'.format(prefix, md5)
+ return os.path.join(standarddir.runtime(), filename)
class Error(Exception):
@@ -209,8 +207,7 @@ class IPCServer(QObject):
if not ok:
if self._server.serverError() == QAbstractSocket.AddressInUseError:
raise AddressInUseError(self._server)
- else:
- raise ListenError(self._server)
+ raise ListenError(self._server)
if not utils.is_windows: # pragma: no cover
# If we use setSocketOptions on Unix with Qt < 5.4, we get a
# NameError while listening.
@@ -279,6 +276,8 @@ class IPCServer(QObject):
log.ipc.debug("Client disconnected from socket 0x{:x}.".format(
id(self._socket)))
self._timer.stop()
+ if self._old_socket is not None:
+ self._old_socket.deleteLater()
self._old_socket = self._socket
self._socket = None
# Maybe another connection is waiting.
@@ -454,19 +453,17 @@ def send_to_running_instance(socketname, command, target_arg, *, socket=None):
socket.waitForBytesWritten(WRITE_TIMEOUT)
if socket.error() != QLocalSocket.UnknownSocketError:
raise SocketError("writing to running instance", socket)
- else:
- socket.disconnectFromServer()
- if socket.state() != QLocalSocket.UnconnectedState:
- socket.waitForDisconnected(CONNECT_TIMEOUT)
- return True
+ socket.disconnectFromServer()
+ if socket.state() != QLocalSocket.UnconnectedState:
+ socket.waitForDisconnected(CONNECT_TIMEOUT)
+ return True
else:
if socket.error() not in [QLocalSocket.ConnectionRefusedError,
QLocalSocket.ServerNotFoundError]:
raise SocketError("connecting to running instance", socket)
- else:
- log.ipc.debug("No existing instance present (error {})".format(
- socket.error()))
- return False
+ log.ipc.debug("No existing instance present (error {})".format(
+ socket.error()))
+ return False
def display_error(exc, args):
diff --git a/qutebrowser/misc/keyhintwidget.py b/qutebrowser/misc/keyhintwidget.py
index 9d3f4c594..4b2c5d685 100644
--- a/qutebrowser/misc/keyhintwidget.py
+++ b/qutebrowser/misc/keyhintwidget.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2016-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
@@ -71,6 +71,7 @@ class KeyHintView(QLabel):
self.hide()
self._show_timer = usertypes.Timer(self, 'keyhint_show')
self._show_timer.timeout.connect(self.show)
+ self._show_timer.setSingleShot(True)
config.set_register_stylesheet(self)
def __repr__(self):
diff --git a/qutebrowser/misc/lineparser.py b/qutebrowser/misc/lineparser.py
index e9fc67e18..b40532eb2 100644
--- a/qutebrowser/misc/lineparser.py
+++ b/qutebrowser/misc/lineparser.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/miscwidgets.py b/qutebrowser/misc/miscwidgets.py
index 085b2fdd1..dd22c220f 100644
--- a/qutebrowser/misc/miscwidgets.py
+++ b/qutebrowser/misc/miscwidgets.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/msgbox.py b/qutebrowser/misc/msgbox.py
index 053534158..241951b84 100644
--- a/qutebrowser/misc/msgbox.py
+++ b/qutebrowser/misc/msgbox.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/objects.py b/qutebrowser/misc/objects.py
index 0bb26954c..d466a78c8 100644
--- a/qutebrowser/misc/objects.py
+++ b/qutebrowser/misc/objects.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -26,7 +26,6 @@ import typing
MYPY = False
if MYPY:
- # pylint: disable=unused-import,useless-suppression
from qutebrowser.utils import usertypes
from qutebrowser.commands import command
diff --git a/qutebrowser/misc/pastebin.py b/qutebrowser/misc/pastebin.py
index f317670ec..7fc0534c1 100644
--- a/qutebrowser/misc/pastebin.py
+++ b/qutebrowser/misc/pastebin.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/readline.py b/qutebrowser/misc/readline.py
index 14c25cd6d..9c42d5b02 100644
--- a/qutebrowser/misc/readline.py
+++ b/qutebrowser/misc/readline.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/savemanager.py b/qutebrowser/misc/savemanager.py
index 9985c5191..384522bf0 100644
--- a/qutebrowser/misc/savemanager.py
+++ b/qutebrowser/misc/savemanager.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/sessions.py b/qutebrowser/misc/sessions.py
index 2a557ef50..d061ed6e4 100644
--- a/qutebrowser/misc/sessions.py
+++ b/qutebrowser/misc/sessions.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -136,8 +136,7 @@ class SessionManager(QObject):
path = os.path.join(self._base_path, name + '.yml')
if check_exists and not os.path.exists(path):
raise SessionNotFoundError(path)
- else:
- return path
+ return path
def exists(self, name):
"""Check if a named session exists."""
@@ -405,6 +404,27 @@ class SessionManager(QObject):
except ValueError as e:
raise SessionError(e)
+ def _load_window(self, win):
+ """Turn yaml data into windows."""
+ window = mainwindow.MainWindow(geometry=win['geometry'],
+ private=win.get('private', None))
+ window.show()
+ tabbed_browser = objreg.get('tabbed-browser', scope='window',
+ window=window.win_id)
+ tab_to_focus = None
+ for i, tab in enumerate(win['tabs']):
+ new_tab = tabbed_browser.tabopen(background=False)
+ self._load_tab(new_tab, tab)
+ if tab.get('active', False):
+ tab_to_focus = i
+ if new_tab.data.pinned:
+ tabbed_browser.widget.set_tab_pinned(new_tab,
+ new_tab.data.pinned)
+ if tab_to_focus is not None:
+ tabbed_browser.widget.setCurrentIndex(tab_to_focus)
+ if win.get('active', False):
+ QTimer.singleShot(0, tabbed_browser.widget.activateWindow)
+
def load(self, name, temp=False):
"""Load a named session.
@@ -423,25 +443,13 @@ class SessionManager(QObject):
if data is None:
raise SessionError("Got empty session file")
+ if qtutils.is_single_process():
+ if any(win.get('private') for win in data['windows']):
+ raise SessionError("Can't load a session with private windows "
+ "in single process mode.")
+
for win in data['windows']:
- window = mainwindow.MainWindow(geometry=win['geometry'],
- private=win.get('private', None))
- window.show()
- tabbed_browser = objreg.get('tabbed-browser', scope='window',
- window=window.win_id)
- tab_to_focus = None
- for i, tab in enumerate(win['tabs']):
- new_tab = tabbed_browser.tabopen(background=False)
- self._load_tab(new_tab, tab)
- if tab.get('active', False):
- tab_to_focus = i
- if new_tab.data.pinned:
- tabbed_browser.widget.set_tab_pinned(new_tab,
- new_tab.data.pinned)
- if tab_to_focus is not None:
- tabbed_browser.widget.setCurrentIndex(tab_to_focus)
- if win.get('active', False):
- QTimer.singleShot(0, tabbed_browser.widget.activateWindow)
+ self._load_window(win)
if data['windows']:
self.did_load = True
diff --git a/qutebrowser/misc/split.py b/qutebrowser/misc/split.py
index 31738fbcc..cf3fe4829 100644
--- a/qutebrowser/misc/split.py
+++ b/qutebrowser/misc/split.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/misc/sql.py b/qutebrowser/misc/sql.py
index eda778194..c9b260502 100644
--- a/qutebrowser/misc/sql.py
+++ b/qutebrowser/misc/sql.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2016-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
@@ -36,6 +36,7 @@ class SqliteErrorCode:
"""
UNKNOWN = '-1'
+ ERROR = '1' # generic error code
BUSY = '5' # database is locked
READONLY = '8' # attempt to write a readonly database
IOERR = '10' # disk I/O error
@@ -45,7 +46,7 @@ class SqliteErrorCode:
CONSTRAINT = '19' # UNIQUE constraint failed
-class SqlError(Exception):
+class Error(Exception):
"""Base class for all SQL related errors."""
@@ -64,7 +65,7 @@ class SqlError(Exception):
return self.error.databaseText()
-class SqlEnvironmentError(SqlError):
+class KnownError(Error):
"""Raised on an error interacting with the SQL database.
@@ -73,7 +74,7 @@ class SqlEnvironmentError(SqlError):
"""
-class SqlBugError(SqlError):
+class BugError(Error):
"""Raised on an error interacting with the SQL database.
@@ -82,7 +83,7 @@ class SqlBugError(SqlError):
def raise_sqlite_error(msg, error):
- """Raise either a SqlBugError or SqlEnvironmentError."""
+ """Raise either a BugError or KnownError."""
error_code = error.nativeErrorCode()
database_text = error.databaseText()
driver_text = error.driverText()
@@ -94,7 +95,7 @@ def raise_sqlite_error(msg, error):
log.sql.debug("driver text: {}".format(driver_text))
log.sql.debug("error code: {}".format(error_code))
- environmental_errors = [
+ known_errors = [
SqliteErrorCode.BUSY,
SqliteErrorCode.READONLY,
SqliteErrorCode.IOERR,
@@ -110,18 +111,26 @@ def raise_sqlite_error(msg, error):
driver_text == "Error opening database" and
database_text == "out of memory")
- if error_code in environmental_errors or qtbug_70506:
- raise SqlEnvironmentError(msg, error)
- else:
- raise SqlBugError(msg, error)
+ # https://github.com/qutebrowser/qutebrowser/issues/4681
+ # If the query we built was too long
+ too_long_err = (
+ error_code == SqliteErrorCode.ERROR and
+ driver_text == "Unable to execute statement" and
+ (database_text.startswith("Expression tree is too large") or
+ database_text == "too many SQL variables"))
+
+ if error_code in known_errors or qtbug_70506 or too_long_err:
+ raise KnownError(msg, error)
+
+ raise BugError(msg, error)
def init(db_path):
"""Initialize the SQL database connection."""
database = QSqlDatabase.addDatabase('QSQLITE')
if not database.isValid():
- raise SqlEnvironmentError('Failed to add database. Are sqlite and Qt '
- 'sqlite support installed?')
+ raise KnownError('Failed to add database. Are sqlite and Qt sqlite '
+ 'support installed?')
database.setDatabaseName(db_path)
if not database.open():
error = database.lastError()
@@ -149,16 +158,16 @@ def version():
close()
return ver
return Query("select sqlite_version()").run().value()
- except SqlEnvironmentError as e:
+ except KnownError as e:
return 'UNAVAILABLE ({})'.format(e)
class Query:
- """A prepared SQL Query."""
+ """A prepared SQL query."""
def __init__(self, querystr, forward_only=True):
- """Prepare a new sql query.
+ """Prepare a new SQL query.
Args:
querystr: String to prepare query from.
@@ -174,7 +183,7 @@ class Query:
def __iter__(self):
if not self.query.isActive():
- raise SqlBugError("Cannot iterate inactive query")
+ raise BugError("Cannot iterate inactive query")
rec = self.query.record()
fields = [rec.fieldName(i) for i in range(rec.count())]
rowtype = collections.namedtuple('ResultRow', fields)
@@ -195,7 +204,7 @@ class Query:
for key, val in values.items():
self.query.bindValue(':{}'.format(key), val)
if any(val is None for val in self.bound_values().values()):
- raise SqlBugError("Missing bound values!")
+ raise BugError("Missing bound values!")
def run(self, **values):
"""Execute the prepared query."""
@@ -224,7 +233,7 @@ class Query:
ok = self.query.execBatch()
try:
self._check_ok('execBatch', ok)
- except SqlError:
+ except Error:
# Not checking the return value here, as we're failing anyways...
db.rollback()
raise
@@ -235,7 +244,7 @@ class Query:
def value(self):
"""Return the result of a single-value query (e.g. an EXISTS)."""
if not self.query.next():
- raise SqlBugError("No result for single-result query")
+ raise BugError("No result for single-result query")
return self.query.record().value(0)
def rows_affected(self):
@@ -247,7 +256,7 @@ class Query:
class SqlTable(QObject):
- """Interface to a sql table.
+ """Interface to a SQL table.
Attributes:
_name: Name of the SQL table this wraps.
@@ -259,7 +268,7 @@ class SqlTable(QObject):
changed = pyqtSignal()
def __init__(self, name, fields, constraints=None, parent=None):
- """Create a new table in the sql database.
+ """Create a new table in the SQL database.
Does nothing if the table already exists.
diff --git a/qutebrowser/misc/utilcmds.py b/qutebrowser/misc/utilcmds.py
index c2b2e6168..6f9bf5bd6 100644
--- a/qutebrowser/misc/utilcmds.py
+++ b/qutebrowser/misc/utilcmds.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -31,7 +31,7 @@ from qutebrowser.browser import qutescheme
from qutebrowser.utils import log, objreg, usertypes, message, debug, utils
from qutebrowser.commands import runners
from qutebrowser.api import cmdutils
-from qutebrowser.config import config, configdata
+from qutebrowser.config import config, configdata, configtypes
from qutebrowser.misc import consolewidget
from qutebrowser.utils.version import pastebin_version
from qutebrowser.qt import sip
@@ -140,12 +140,16 @@ def debug_cache_stats():
# pylint: disable=protected-access
tab_bar = tabbed_browser.widget.tabBar()
tabbed_browser_info = tab_bar._minimum_tab_size_hint_helper.cache_info()
+
+ str_validation_info = (configtypes.BaseType.
+ _basic_str_validation_cache.cache_info())
# pylint: enable=protected-access
log.misc.info('is_valid_prefix: {}'.format(prefix_info))
log.misc.info('_render_stylesheet: {}'.format(render_stylesheet_info))
log.misc.info('history: {}'.format(history_info))
log.misc.info('tab width cache: {}'.format(tabbed_browser_info))
+ log.misc.info('str validation cache: {}'.format(str_validation_info))
@cmdutils.register(debug=True)
@@ -243,9 +247,8 @@ def log_capacity(capacity: int) -> None:
"""
if capacity < 0:
raise cmdutils.CommandError("Can't set a negative log capacity!")
- else:
- assert log.ram_handler is not None
- log.ram_handler.change_log_capacity(capacity)
+ assert log.ram_handler is not None
+ log.ram_handler.change_log_capacity(capacity)
@cmdutils.register(debug=True)
@@ -311,7 +314,7 @@ def version(win_id, paste=False):
"""
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
- tabbed_browser.load_url(QUrl('qute://version'), newtab=True)
+ tabbed_browser.load_url(QUrl('qute://version/'), newtab=True)
if paste:
pastebin_version()
diff --git a/qutebrowser/qt.py b/qutebrowser/qt.py
index d9f1dc58d..823170b29 100644
--- a/qutebrowser/qt.py
+++ b/qutebrowser/qt.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/qutebrowser.py b/qutebrowser/qutebrowser.py
index a96a18121..fe846d489 100644
--- a/qutebrowser/qutebrowser.py
+++ b/qutebrowser/qutebrowser.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -51,7 +51,6 @@ except ImportError:
sys.stderr.flush()
sys.exit(100)
check_python_version()
-from qutebrowser.utils import log
import argparse # pylint: disable=wrong-import-order
from qutebrowser.misc import earlyinit
@@ -149,6 +148,7 @@ def logfilter_error(logfilter):
Args:
logfilter: A comma separated list of logger names.
"""
+ from qutebrowser.utils import log
if set(logfilter.lstrip('!').split(',')).issubset(log.LOGGER_NAMES):
return logfilter
else:
@@ -166,9 +166,12 @@ def debug_flag_error(flag):
no-sql-history: Don't store history items.
no-scroll-filtering: Process all scrolling updates.
log-requests: Log all network requests.
+ stack: Enable Chromium stack logging.
+ chromium: Enable Chromium logging.
"""
valid_flags = ['debug-exit', 'pdb-postmortem', 'no-sql-history',
- 'no-scroll-filtering', 'log-requests', 'lost-focusproxy']
+ 'no-scroll-filtering', 'log-requests', 'lost-focusproxy',
+ 'stack', 'chromium']
if flag in valid_flags:
return flag
diff --git a/qutebrowser/utils/__init__.py b/qutebrowser/utils/__init__.py
index 16069f3ae..7a062ad2c 100644
--- a/qutebrowser/utils/__init__.py
+++ b/qutebrowser/utils/__init__.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/utils/debug.py b/qutebrowser/utils/debug.py
index 2868d8390..7bb2d6992 100644
--- a/qutebrowser/utils/debug.py
+++ b/qutebrowser/utils/debug.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/utils/docutils.py b/qutebrowser/utils/docutils.py
index 9ae2039ac..cf346fb81 100644
--- a/qutebrowser/utils/docutils.py
+++ b/qutebrowser/utils/docutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/utils/error.py b/qutebrowser/utils/error.py
index b9abcdfe1..fe8077526 100644
--- a/qutebrowser/utils/error.py
+++ b/qutebrowser/utils/error.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/utils/javascript.py b/qutebrowser/utils/javascript.py
index 6127804a5..42da9759d 100644
--- a/qutebrowser/utils/javascript.py
+++ b/qutebrowser/utils/javascript.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/utils/jinja.py b/qutebrowser/utils/jinja.py
index d2ddfaeb7..5aad4a755 100644
--- a/qutebrowser/utils/jinja.py
+++ b/qutebrowser/utils/jinja.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -27,7 +27,7 @@ import html
import jinja2
from PyQt5.QtCore import QUrl
-from qutebrowser.utils import utils, urlutils, log
+from qutebrowser.utils import utils, urlutils, log, qtutils
html_fallback = """
@@ -85,6 +85,7 @@ class Environment(jinja2.Environment):
self.globals['resource_url'] = self._resource_url
self.globals['file_url'] = urlutils.file_url
self.globals['data_url'] = self._data_url
+ self.globals['qcolor_to_qsscolor'] = qtutils.qcolor_to_qsscolor
self._autoescape = True
@contextlib.contextmanager
diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py
index 115c53352..004ce16c0 100644
--- a/qutebrowser/utils/log.py
+++ b/qutebrowser/utils/log.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -199,6 +199,12 @@ def init_log(args):
root.addHandler(console)
if ram is not None:
root.addHandler(ram)
+ else:
+ # If we add no handler, we shouldn't process non visible logs at all
+ #
+ # disable blocks the current level (while setHandler shows the current
+ # level), so -1 to avoid blocking handled messages.
+ logging.disable(numeric_level - 1)
root.setLevel(logging.NOTSET)
logging.captureWarnings(True)
_init_py_warnings()
@@ -428,6 +434,9 @@ def qt_message_handler(msg_type, context, msg):
'QXcbWindow: Unhandled client message: ""',
# https://codereview.qt-project.org/176831
"QObject::disconnect: Unexpected null parameter",
+ # https://bugreports.qt.io/browse/QTBUG-76391
+ "Attribute Qt::AA_ShareOpenGLContexts must be set before "
+ "QCoreApplication is created.",
]
# not using utils.is_mac here, because we can't be sure we can successfully
# import the utils module here.
diff --git a/qutebrowser/utils/message.py b/qutebrowser/utils/message.py
index 6731721aa..b663cbfa4 100644
--- a/qutebrowser/utils/message.py
+++ b/qutebrowser/utils/message.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/qutebrowser/utils/objreg.py b/qutebrowser/utils/objreg.py
index b68ca133c..a00460a34 100644
--- a/qutebrowser/utils/objreg.py
+++ b/qutebrowser/utils/objreg.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -304,6 +304,5 @@ def window_by_index(idx):
"""Get the Nth opened window object."""
if not window_registry:
raise NoWindow()
- else:
- key = sorted(window_registry)[idx]
- return window_registry[key]
+ key = sorted(window_registry)[idx]
+ return window_registry[key]
diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py
index 5373e76aa..239e9a7eb 100644
--- a/qutebrowser/utils/qtutils.py
+++ b/qutebrowser/utils/qtutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -37,10 +37,15 @@ import pkg_resources
from PyQt5.QtCore import (qVersion, QEventLoop, QDataStream, QByteArray,
QIODevice, QSaveFile, QT_VERSION_STR,
PYQT_VERSION_STR, QFileDevice, QObject)
+from PyQt5.QtGui import QColor
+from PyQt5.QtWidgets import QApplication
try:
from PyQt5.QtWebKit import qWebKitVersion
except ImportError: # pragma: no cover
- qWebKitVersion = None # type: ignore
+ qWebKitVersion = None # type: ignore # noqa: N816
+
+from qutebrowser.misc import objects
+from qutebrowser.utils import usertypes
MAXVALS = {
@@ -85,9 +90,6 @@ def version_check(version: str,
exact: if given, check with == instead of >=
compiled: Set to False to not check the compiled version.
"""
- # Catch code using the old API for this
- assert exact not in [operator.gt, operator.lt, operator.ge, operator.le,
- operator.eq], exact
if compiled and exact:
raise ValueError("Can't use compiled=True with exact=True!")
@@ -114,6 +116,14 @@ def is_new_qtwebkit() -> bool:
pkg_resources.parse_version('538.1'))
+def is_single_process():
+ """Check whether QtWebEngine is running in single-process mode."""
+ if objects.backend == usertypes.Backend.QtWebKit:
+ return False
+ args = QApplication.instance().arguments()
+ return '--single-process' in args
+
+
def check_overflow(arg: int, ctype: str, fatal: bool = True) -> int:
"""Check if the given argument is in bounds for the given type.
@@ -131,13 +141,11 @@ def check_overflow(arg: int, ctype: str, fatal: bool = True) -> int:
if arg > maxval:
if fatal:
raise OverflowError(arg)
- else:
- return maxval
+ return maxval
elif arg < minval:
if fatal:
raise OverflowError(arg)
- else:
- return minval
+ return minval
else:
return arg
@@ -218,6 +226,13 @@ def savefile_open(filename, binary=False, encoding='utf-8'):
raise QtOSError(f, msg="Commit failed!")
+def qcolor_to_qsscolor(c: QColor) -> str:
+ """Convert a QColor to a string that can be used in a QStyleSheet."""
+ ensure_valid(c)
+ return "rgba({}, {}, {}, {})".format(
+ c.red(), c.green(), c.blue(), c.alpha())
+
+
class PyQIODevice(io.BufferedIOBase):
"""Wrapper for a QIODevice which provides a python interface.
diff --git a/qutebrowser/utils/standarddir.py b/qutebrowser/utils/standarddir.py
index f2715d2cd..0e5c7ea0a 100644
--- a/qutebrowser/utils/standarddir.py
+++ b/qutebrowser/utils/standarddir.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -200,11 +200,11 @@ def download():
def _init_runtime(args):
"""Initialize location for runtime data."""
- if utils.is_linux:
- typ = QStandardPaths.RuntimeLocation
- else:
+ if utils.is_mac or utils.is_windows:
# RuntimeLocation is a weird path on macOS and Windows.
typ = QStandardPaths.TempLocation
+ else:
+ typ = QStandardPaths.RuntimeLocation
overridden, path = _from_args(typ, args)
diff --git a/qutebrowser/utils/urlmatch.py b/qutebrowser/utils/urlmatch.py
index 79e02c37f..6096b3f2b 100644
--- a/qutebrowser/utils/urlmatch.py
+++ b/qutebrowser/utils/urlmatch.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -205,7 +205,7 @@ class UrlPattern:
if self._host.endswith('.*'):
# Special case to have a nicer error
raise ParseError("TLD wildcards are not implemented yet")
- elif '*' in self._host:
+ if '*' in self._host:
# Only * or *.foo is allowed as host.
raise ParseError("Invalid host wildcard")
diff --git a/qutebrowser/utils/urlutils.py b/qutebrowser/utils/urlutils.py
index 1acd9cd4e..a9b68852c 100644
--- a/qutebrowser/utils/urlutils.py
+++ b/qutebrowser/utils/urlutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -535,13 +535,14 @@ def _get_incdec_value(match, incdec, url, count):
# This should always succeed because we match \d+
val = int(number)
if incdec == 'decrement':
- if val <= 0:
- raise IncDecError("Can't decrement {}!".format(val), url)
+ if val < count:
+ raise IncDecError("Can't decrement {} by {}!".format(val, count),
+ url)
val -= count
elif incdec == 'increment':
val += count
else:
- raise ValueError("Invalid value {} for indec!".format(incdec))
+ raise ValueError("Invalid value {} for incdec!".format(incdec))
if zeroes:
if len(number) < len(str(val)):
zeroes = zeroes[1:]
@@ -551,6 +552,33 @@ def _get_incdec_value(match, incdec, url, count):
return ''.join([pre, zeroes, str(val), post])
+# Order of the segments in a URL.
+# Each list entry is a tuple of (path name (string), getter, setter).
+# Note that the getters must not use FullyDecoded decoded mode to prevent loss
+# of information. (host and path use FullyDecoded by default)
+_URL_SEGMENTS = [
+ ('host',
+ lambda url: url.host(QUrl.PrettyDecoded),
+ lambda url, host: url.setHost(host, QUrl.StrictMode)),
+
+ ('port',
+ lambda url: str(url.port()) if url.port() > 0 else '',
+ lambda url, x: url.setPort(int(x))),
+
+ ('path',
+ lambda url: url.path(QUrl.PrettyDecoded),
+ lambda url, path: url.setPath(path, QUrl.StrictMode)),
+
+ ('query',
+ lambda url: url.query(QUrl.PrettyDecoded),
+ lambda url, query: url.setQuery(query, QUrl.StrictMode)),
+
+ ('anchor',
+ lambda url: url.fragment(QUrl.PrettyDecoded),
+ lambda url, fragment: url.setFragment(fragment, QUrl.StrictMode)),
+]
+
+
def incdec_number(url, incdec, count=1, segments=None):
"""Find a number in the url and increment or decrement it.
@@ -580,26 +608,20 @@ def incdec_number(url, incdec, count=1, segments=None):
# Make a copy of the QUrl so we don't modify the original
url = QUrl(url)
- # Order as they appear in a URL
- segment_modifiers = [
- ('host', url.host, url.setHost),
- ('port', lambda: str(url.port()) if url.port() > 0 else '',
- lambda x: url.setPort(int(x))),
- ('path', url.path, url.setPath),
- ('query', url.query, url.setQuery),
- ('anchor', url.fragment, url.setFragment),
- ]
# We're searching the last number so we walk the url segments backwards
- for segment, getter, setter in reversed(segment_modifiers):
+ for segment, getter, setter in reversed(_URL_SEGMENTS):
if segment not in segments:
continue
- # Get the last number in a string
- match = re.fullmatch(r'(.*\D|^)(0*)(\d+)(.*)', getter())
+ # Get the last number in a string not preceded by regex '%' or '%.'
+ match = re.fullmatch(r'(.*\D|^)(?<!%)(?<!%.)(0*)(\d+)(.*)',
+ getter(url))
if not match:
continue
- setter(_get_incdec_value(match, incdec, url, count))
+ setter(url, _get_incdec_value(match, incdec, url, count))
+ qtutils.ensure_valid(url)
+
return url
raise IncDecError("No number found in URL!", url)
diff --git a/qutebrowser/utils/usertypes.py b/qutebrowser/utils/usertypes.py
index 84b7e7f9b..03bd44869 100644
--- a/qutebrowser/utils/usertypes.py
+++ b/qutebrowser/utils/usertypes.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -200,9 +200,8 @@ class NeighborList(collections.abc.Sequence):
"""Reset the position to the default."""
if self._default is _UNSET:
raise ValueError("No default set!")
- else:
- self._idx = self._items.index(self._default)
- return self.curitem()
+ self._idx = self._items.index(self._default)
+ return self.curitem()
# The mode of a Question.
@@ -451,6 +450,7 @@ class NavigationRequest:
'form_resubmitted', # QtWebKit only
'back_forward',
'reloaded',
+ 'redirect', # QtWebEngine >= 5.14 only
'other'
])
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
index 2d517043a..bd3d7822c 100644
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -30,6 +30,7 @@ import datetime
import traceback
import functools
import contextlib
+import posixpath
import socket
import shlex
import glob
@@ -41,7 +42,7 @@ from PyQt5.QtWidgets import QApplication
import pkg_resources
import yaml
try:
- from yaml import (CSafeLoader as YamlLoader, # type: ignore
+ from yaml import (CSafeLoader as YamlLoader,
CSafeDumper as YamlDumper)
YAML_C_EXT = True
except ImportError: # pragma: no cover
@@ -165,6 +166,9 @@ def read_file(filename, binary=False):
Return:
The file contents as string.
"""
+ assert not posixpath.isabs(filename), filename
+ assert os.path.pardir not in filename.split(posixpath.sep), filename
+
if not binary and filename in _resource_cache:
return _resource_cache[filename]
@@ -655,7 +659,15 @@ def expand_windows_drive(path):
def yaml_load(f):
"""Wrapper over yaml.load using the C loader if possible."""
start = datetime.datetime.now()
- data = yaml.load(f, Loader=YamlLoader)
+
+ # WORKAROUND for https://github.com/yaml/pyyaml/pull/181
+ with log.ignore_py_warnings(
+ category=DeprecationWarning,
+ message=r"Using or importing the ABCs from 'collections' instead "
+ r"of from 'collections\.abc' is deprecated, and in 3\.8 it will "
+ r"stop working"):
+ data = yaml.load(f, Loader=YamlLoader)
+
end = datetime.datetime.now()
delta = (end - start).total_seconds()
diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py
index a52e31ed8..437ba49a3 100644
--- a/qutebrowser/utils/version.py
+++ b/qutebrowser/utils/version.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -42,7 +42,7 @@ from PyQt5.QtWidgets import QApplication
try:
from PyQt5.QtWebKit import qWebKitVersion
except ImportError: # pragma: no cover
- qWebKitVersion = None # type: ignore
+ qWebKitVersion = None # type: ignore # noqa: N816
try:
from PyQt5.QtWebEngineWidgets import QWebEngineProfile
@@ -54,6 +54,11 @@ from qutebrowser.utils import log, utils, standarddir, usertypes, message
from qutebrowser.misc import objects, earlyinit, sql, httpclient, pastebin
from qutebrowser.browser import pdfjs
+try:
+ from qutebrowser.browser.webengine import webenginesettings
+except ImportError: # pragma: no cover
+ webenginesettings = None # type: ignore
+
@attr.s
class DistributionInfo:
@@ -69,7 +74,8 @@ class DistributionInfo:
pastebin_url = None
Distribution = enum.Enum(
'Distribution', ['unknown', 'ubuntu', 'debian', 'void', 'arch',
- 'gentoo', 'fedora', 'opensuse', 'linuxmint', 'manjaro'])
+ 'gentoo', 'fedora', 'opensuse', 'linuxmint', 'manjaro',
+ 'kde'])
def distribution():
@@ -94,9 +100,9 @@ def distribution():
except (OSError, UnicodeDecodeError):
return None
- pretty = info.get('PRETTY_NAME', 'Unknown')
- if pretty == 'Linux': # Thanks, Funtoo
- pretty = info.get('NAME', pretty)
+ pretty = info.get('PRETTY_NAME', None)
+ if pretty in ['Linux', None]: # Funtoo has PRETTY_NAME=Linux
+ pretty = info.get('NAME', 'Unknown')
if 'VERSION_ID' in info:
dist_version = pkg_resources.parse_version(info['VERSION_ID'])
@@ -106,6 +112,7 @@ def distribution():
dist_id = info.get('ID', None)
id_mappings = {
'funtoo': 'gentoo', # does not have ID_LIKE=gentoo
+ 'org.kde.Platform': 'kde',
}
try:
parsed = Distribution[id_mappings.get(dist_id, dist_id)]
@@ -324,7 +331,7 @@ def _chromium_version():
Qt 5.9: Chromium 56
(LTS) 56.0.2924.122 (2017-01-25)
- 5.9.6: Security fixes up to 66.0.3359.170 (2018-05-10)
+ 5.9.8: Security fixes up to 72.0.3626.121 (2019-03-01)
Qt 5.10: Chromium 61
61.0.3163.140 (2017-09-05)
@@ -332,20 +339,26 @@ def _chromium_version():
Qt 5.11: Chromium 65
65.0.3325.151 (.1: .230) (2018-03-06)
- 5.11.2: Security fixes up to 68.0.3440.75 (2018-07-24)
+ 5.11.3: Security fixes up to 70.0.3538.102 (2018-11-09)
Qt 5.12: Chromium 69
- 69.0.3497.128 (~2018-09-17)
- 5.12.0: Security fixes up to 70.0.3538.67 (2018-10-16)
+ (LTS) 69.0.3497.113 (2018-09-27)
+ 5.12.4: Security fixes up to 74.0.3729.157 (2019-05-14)
+
+ Qt 5.13: Chromium 73
+ 73.0.3683.105 (~2019-02-28)
+ 5.13.0: Security fixes up to 74.0.3729.131 (2019-04-30)
Also see https://www.chromium.org/developers/calendar
and https://chromereleases.googleblog.com/
"""
- if QWebEngineProfile is None:
+ if webenginesettings is None or QWebEngineProfile is None:
# This should never happen
return 'unavailable'
- profile = QWebEngineProfile()
- ua = profile.httpUserAgent()
+ ua = webenginesettings.default_user_agent
+ if ua is None:
+ profile = QWebEngineProfile.defaultProfile()
+ ua = profile.httpUserAgent()
match = re.search(r' Chrome/([^ ]*) ', ua)
if not match:
log.misc.error("Could not get Chromium version from: {}".format(ua))
diff --git a/requirements.txt b/requirements.txt
index 68bd341bb..975d22516 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,10 +1,10 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-attrs==18.2.0
+attrs==19.1.0
colorama==0.4.1
cssutils==1.0.2
-Jinja2==2.10
-MarkupSafe==1.1.0
-Pygments==2.3.1
+Jinja2==2.10.1
+MarkupSafe==1.1.1
+Pygments==2.4.2
pyPEG2==2.15.2
-PyYAML==3.13
+PyYAML==5.1.1
diff --git a/scripts/asciidoc2html.py b/scripts/asciidoc2html.py
index c4af174b2..2825c2ac4 100755
--- a/scripts/asciidoc2html.py
+++ b/scripts/asciidoc2html.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/build_release.py b/scripts/dev/build_release.py
index 8591f1c31..c400cf86d 100755
--- a/scripts/dev/build_release.py
+++ b/scripts/dev/build_release.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -112,7 +112,7 @@ def patch_mac_app():
plistlib.dump(plist_data, f)
# Replace some duplicate files by symlinks
- framework_path = os.path.join(app_path, 'Contents', 'Resources', 'PyQt5',
+ framework_path = os.path.join(app_path, 'Contents', 'MacOS', 'PyQt5',
'Qt', 'lib', 'QtWebEngineCore.framework')
core_lib = os.path.join(framework_path, 'Versions', '5', 'QtWebEngineCore')
@@ -218,7 +218,17 @@ def build_windows():
except FileNotFoundError:
python_x64 = r'C:\Python{}\python.exe'.format(ver)
+ try:
+ reg32_key = winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE,
+ r'SOFTWARE\WOW6432Node\Python\PythonCore'
+ r'\{}-32\InstallPath'.format(dot_ver))
+ python_x86 = winreg.QueryValueEx(reg32_key, 'ExecutablePath')[0]
+ except FileNotFoundError:
+ python_x86 = r'C:\Python{}-32\python.exe'.format(ver)
+
out_pyinstaller = os.path.join('dist', 'qutebrowser')
+ out_32 = os.path.join('dist',
+ 'qutebrowser-{}-x86'.format(qutebrowser.__version__))
out_64 = os.path.join('dist',
'qutebrowser-{}-x64'.format(qutebrowser.__version__))
@@ -228,28 +238,50 @@ def build_windows():
utils.print_title("Updating VersionInfo file")
gen_versioninfo.main()
+ utils.print_title("Running pyinstaller 32bit")
+ _maybe_remove(out_32)
+ call_tox('pyinstaller', '-r', python=python_x86)
+ shutil.move(out_pyinstaller, out_32)
+
utils.print_title("Running pyinstaller 64bit")
_maybe_remove(out_64)
call_tox('pyinstaller', '-r', python=python_x64)
shutil.move(out_pyinstaller, out_64)
+ utils.print_title("Running 32bit smoke test")
+ smoke_test(os.path.join(out_32, 'qutebrowser.exe'))
utils.print_title("Running 64bit smoke test")
smoke_test(os.path.join(out_64, 'qutebrowser.exe'))
utils.print_title("Building installers")
subprocess.run(['makensis.exe',
+ '/DVERSION={}'.format(qutebrowser.__version__),
+ 'misc/qutebrowser.nsi'], check=True)
+ subprocess.run(['makensis.exe',
'/DX64',
'/DVERSION={}'.format(qutebrowser.__version__),
'misc/qutebrowser.nsi'], check=True)
+ name_32 = 'qutebrowser-{}-win32.exe'.format(qutebrowser.__version__)
name_64 = 'qutebrowser-{}-amd64.exe'.format(qutebrowser.__version__)
artifacts += [
+ (os.path.join('dist', name_32),
+ 'application/vnd.microsoft.portable-executable',
+ 'Windows 32bit installer'),
(os.path.join('dist', name_64),
'application/vnd.microsoft.portable-executable',
'Windows 64bit installer'),
]
+ utils.print_title("Zipping 32bit standalone...")
+ name = 'qutebrowser-{}-windows-standalone-win32'.format(
+ qutebrowser.__version__)
+ shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_32))
+ artifacts.append(('{}.zip'.format(name),
+ 'application/zip',
+ 'Windows 32bit standalone'))
+
utils.print_title("Zipping 64bit standalone...")
name = 'qutebrowser-{}-windows-standalone-amd64'.format(
qutebrowser.__version__)
diff --git a/scripts/dev/check_coverage.py b/scripts/dev/check_coverage.py
index d42ce1d71..fdbbce71a 100644
--- a/scripts/dev/check_coverage.py
+++ b/scripts/dev/check_coverage.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -235,11 +235,11 @@ def check(fileobj, perfect_files):
"""Main entry point which parses/checks coverage.xml if applicable."""
if not utils.is_linux:
raise Skipped("on non-Linux system.")
- elif '-k' in sys.argv[1:]:
+ if '-k' in sys.argv[1:]:
raise Skipped("because -k is given.")
- elif '-m' in sys.argv[1:]:
+ if '-m' in sys.argv[1:]:
raise Skipped("because -m is given.")
- elif '--lf' in sys.argv[1:]:
+ if '--lf' in sys.argv[1:]:
raise Skipped("because --lf is given.")
perfect_src_files = [e[1] for e in perfect_files]
diff --git a/scripts/dev/check_doc_changes.py b/scripts/dev/check_doc_changes.py
index 3d90bea5e..37a061da6 100755
--- a/scripts/dev/check_doc_changes.py
+++ b/scripts/dev/check_doc_changes.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/ci/travis_install.sh b/scripts/dev/ci/travis_install.sh
index c736a01d3..064f4098a 100644
--- a/scripts/dev/ci/travis_install.sh
+++ b/scripts/dev/ci/travis_install.sh
@@ -53,43 +53,13 @@ npm_install() {
travis_retry npm install -g "$@"
}
-check_pyqt() {
- python3 <<EOF
-import sys
-from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, qVersion
-try:
- from PyQt.sip import SIP_VERSION_STR
-except ModuleNotFoundError:
- from sip import SIP_VERSION_STR
-
-print("Python {}".format(sys.version))
-print("PyQt5 {}".format(PYQT_VERSION_STR))
-print("Qt5 {} (runtime {})".format(QT_VERSION_STR, qVersion()))
-print("sip {}".format(SIP_VERSION_STR))
-EOF
-}
-
set -e
if [[ -n $DOCKER ]]; then
exit 0
elif [[ $TRAVIS_OS_NAME == osx ]]; then
- # Disable App Nap
- defaults write NSGlobalDomain NSAppSleepDisabled -bool YES
-
- curl -LO https://bootstrap.pypa.io/get-pip.py
- sudo -H python get-pip.py
-
- brew --version
brew update
- brew upgrade python libyaml
- brew install qt5 pyqt5
-
- pip_install -r misc/requirements/requirements-tox.txt
- python3 -m pip --version
- tox --version
- check_pyqt
- exit 0
+ brew upgrade python
fi
case $TESTENV in
diff --git a/scripts/dev/ci/travis_run.sh b/scripts/dev/ci/travis_run.sh
index 4e338221f..eb1248d96 100644
--- a/scripts/dev/ci/travis_run.sh
+++ b/scripts/dev/ci/travis_run.sh
@@ -26,7 +26,8 @@ elif [[ $TESTENV == shellcheck ]]; then
koalaman/shellcheck:latest "${scripts[@]}"
else
args=()
- [[ $TRAVIS_OS_NAME == osx ]] && args=('--qute-bdd-webengine' '--no-xvfb' 'tests/unit')
+ # We only run unit tests on macOS because it's quite slow.
+ [[ $TRAVIS_OS_NAME == osx ]] && args+=('--qute-bdd-webengine' '--no-xvfb' 'tests/unit')
# WORKAROUND for unknown crash inside swrast_dri.so
# See https://github.com/qutebrowser/qutebrowser/pull/4218#issuecomment-421931770
diff --git a/scripts/dev/cleanup.py b/scripts/dev/cleanup.py
index d1bb84a2f..7f4f7a36e 100755
--- a/scripts/dev/cleanup.py
+++ b/scripts/dev/cleanup.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/gen_resources.py b/scripts/dev/gen_resources.py
index cbfc69b6f..42ed163c5 100644
--- a/scripts/dev/gen_resources.py
+++ b/scripts/dev/gen_resources.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# copyright 2014 florian bruhin (the compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The-Compiler) <me@the-compiler.org>
# this file is part of qutebrowser.
#
diff --git a/scripts/dev/gen_versioninfo.py b/scripts/dev/gen_versioninfo.py
index 1aa4b6429..08b28e625 100644
--- a/scripts/dev/gen_versioninfo.py
+++ b/scripts/dev/gen_versioninfo.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/get_coredumpctl_traces.py b/scripts/dev/get_coredumpctl_traces.py
index d286d381e..8c9fd7ef1 100644
--- a/scripts/dev/get_coredumpctl_traces.py
+++ b/scripts/dev/get_coredumpctl_traces.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/misc_checks.py b/scripts/dev/misc_checks.py
index 27ff0105b..c1619439b 100644
--- a/scripts/dev/misc_checks.py
+++ b/scripts/dev/misc_checks.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/pylint_checkers/qute_pylint/config.py b/scripts/dev/pylint_checkers/qute_pylint/config.py
index 5aa52502f..8cec01198 100644
--- a/scripts/dev/pylint_checkers/qute_pylint/config.py
+++ b/scripts/dev/pylint_checkers/qute_pylint/config.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -81,4 +81,4 @@ def register(linter):
FAILED_LOAD = True
return
with yaml_file.open(mode='r', encoding='utf-8') as f:
- OPTIONS = list(yaml.load(f))
+ OPTIONS = list(yaml.safe_load(f))
diff --git a/scripts/dev/pylint_checkers/qute_pylint/modeline.py b/scripts/dev/pylint_checkers/qute_pylint/modeline.py
index 429974cb9..04bd26fcf 100644
--- a/scripts/dev/pylint_checkers/qute_pylint/modeline.py
+++ b/scripts/dev/pylint_checkers/qute_pylint/modeline.py
@@ -1,4 +1,4 @@
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# This file is part of qutebrowser.
diff --git a/scripts/dev/pylint_checkers/qute_pylint/openencoding.py b/scripts/dev/pylint_checkers/qute_pylint/openencoding.py
index f577011ca..f217f8a70 100644
--- a/scripts/dev/pylint_checkers/qute_pylint/openencoding.py
+++ b/scripts/dev/pylint_checkers/qute_pylint/openencoding.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/pylint_checkers/qute_pylint/settrace.py b/scripts/dev/pylint_checkers/qute_pylint/settrace.py
index c82d646aa..ba060c8e9 100644
--- a/scripts/dev/pylint_checkers/qute_pylint/settrace.py
+++ b/scripts/dev/pylint_checkers/qute_pylint/settrace.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/pylint_checkers/setup.py b/scripts/dev/pylint_checkers/setup.py
index 7833c7dbd..331db7d6b 100644
--- a/scripts/dev/pylint_checkers/setup.py
+++ b/scripts/dev/pylint_checkers/setup.py
@@ -2,7 +2,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/recompile_requirements.py b/scripts/dev/recompile_requirements.py
index 6e26145e9..e4aa6229b 100644
--- a/scripts/dev/recompile_requirements.py
+++ b/scripts/dev/recompile_requirements.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/run_profile.py b/scripts/dev/run_profile.py
index 6f34e819f..ff13da7a3 100755
--- a/scripts/dev/run_profile.py
+++ b/scripts/dev/run_profile.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/run_pylint_on_tests.py b/scripts/dev/run_pylint_on_tests.py
index d8523a4b4..53528734c 100644
--- a/scripts/dev/run_pylint_on_tests.py
+++ b/scripts/dev/run_pylint_on_tests.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/run_vulture.py b/scripts/dev/run_vulture.py
index f9262c946..c320d4325 100755
--- a/scripts/dev/run_vulture.py
+++ b/scripts/dev/run_vulture.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/segfault_test.py b/scripts/dev/segfault_test.py
index aaf495fc1..07c328f0f 100755
--- a/scripts/dev/segfault_test.py
+++ b/scripts/dev/segfault_test.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/src2asciidoc.py b/scripts/dev/src2asciidoc.py
index 1ba272fba..935b320d0 100755
--- a/scripts/dev/src2asciidoc.py
+++ b/scripts/dev/src2asciidoc.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -499,7 +499,7 @@ def _format_block(filename, what, data):
if not found_start:
raise Exception("Marker '// QUTE_{}_START' not found in "
"'{}'!".format(what, filename))
- elif not found_end:
+ if not found_end:
raise Exception("Marker '// QUTE_{}_END' not found in "
"'{}'!".format(what, filename))
except:
diff --git a/scripts/dev/standardpaths_tester.py b/scripts/dev/standardpaths_tester.py
index 27b8382e6..f1b90346e 100644
--- a/scripts/dev/standardpaths_tester.py
+++ b/scripts/dev/standardpaths_tester.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dev/ua_fetch.py b/scripts/dev/ua_fetch.py
index 75ce4c2f7..4bf7b4b6c 100755
--- a/scripts/dev/ua_fetch.py
+++ b/scripts/dev/ua_fetch.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 lamarpavel
# Copyright 2015-2018 Alexey Nabrodov (Averrin)
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -75,42 +75,17 @@ def filter_list(complete_list, browsers):
return table
-def add_diversity(table):
- """Insert a few additional entries for diversity into the dict.
-
- (as returned by filter_list())
- """
- table["Obscure"] = [
- ('Mozilla/5.0 (compatible; Googlebot/2.1; '
- '+http://www.google.com/bot.html',
- "Google Bot"),
- ('Wget/1.16.1 (linux-gnu)',
- "wget 1.16.1"),
- ('curl/7.40.0',
- "curl 7.40.0"),
- ('Mozilla/5.0 (Linux; U; Android 7.1.2) AppleWebKit/534.30 '
- '(KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
- "Mobile Generic Android"),
- ('Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like '
- 'Gecko',
- "IE 11.0 for Desktop Win7 64-bit"),
- ]
- return table
-
-
def main():
"""Generate user agent code."""
fetched = fetch()
lut = {
- "Firefox": {"Win", "MacOSX", "Linux", "Android"},
- "Chrome": {"Win", "MacOSX", "Linux"},
- "Safari": {"MacOSX", "iOS"}
+ "Chrome": {"Win10", "Linux"},
}
filtered = filter_list(fetched, lut)
- filtered = add_diversity(filtered)
+ filtered["empty"] = [('', "Use default QtWebKit/QtWebEngine User-Agent")]
tab = " "
- for browser in ["Firefox", "Safari", "Chrome", "Obscure"]:
+ for browser in ["Chrome", "empty"]:
for it in filtered[browser]:
print('{}- - "{}"'.format(3 * tab, it[0]))
desc = it[1].replace('\xa0', ' ').replace(' ', ' ')
diff --git a/scripts/dev/update_3rdparty.py b/scripts/dev/update_3rdparty.py
index 277d4eefc..3a777765e 100755
--- a/scripts/dev/update_3rdparty.py
+++ b/scripts/dev/update_3rdparty.py
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015 Daniel Schadt
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/dictcli.py b/scripts/dictcli.py
index 4017159b6..6d10b2f3e 100755
--- a/scripts/dictcli.py
+++ b/scripts/dictcli.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2017-2018 Michal Siedlaczek <michal.siedlaczek@gmail.com>
# This file is part of qutebrowser.
diff --git a/scripts/hist_importer.py b/scripts/hist_importer.py
index 31936b4c1..680532762 100755
--- a/scripts/hist_importer.py
+++ b/scripts/hist_importer.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2017-2018 Josefson Souza <josefson.br@gmail.com>
# This file is part of qutebrowser.
@@ -155,10 +155,10 @@ def run():
if browser not in query:
raise Error('Sorry, the selected browser: "{}" is not '
'supported.'.format(browser))
- else:
- history = extract(source, query[browser])
- history = clean(history)
- insert_qb(history, dest)
+
+ history = extract(source, query[browser])
+ history = clean(history)
+ insert_qb(history, dest)
def main():
diff --git a/scripts/hostblock_blame.py b/scripts/hostblock_blame.py
index e5508f515..560c21edb 100644
--- a/scripts/hostblock_blame.py
+++ b/scripts/hostblock_blame.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/importer.py b/scripts/importer.py
index fd3e4ca0b..592b84d19 100755
--- a/scripts/importer.py
+++ b/scripts/importer.py
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Claude (longneck) <longneck@scratchbook.ch>
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/scripts/keytester.py b/scripts/keytester.py
index ee5eb347c..b4427fc5c 100644
--- a/scripts/keytester.py
+++ b/scripts/keytester.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/scripts/link_pyqt.py b/scripts/link_pyqt.py
index e16056fa8..b8aa42c43 100644
--- a/scripts/link_pyqt.py
+++ b/scripts/link_pyqt.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -121,8 +121,7 @@ def get_lib_path(executable, name, required=True):
if required:
raise Error("Could not import {} with {}: {}!".format(
name, executable, data))
- else:
- return None
+ return None
else:
raise ValueError("Unexpected output: {!r}".format(output))
diff --git a/scripts/setupcommon.py b/scripts/setupcommon.py
index 50eabacd0..1c9b22dcd 100644
--- a/scripts/setupcommon.py
+++ b/scripts/setupcommon.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/scripts/testbrowser/testbrowser_webengine.py b/scripts/testbrowser/testbrowser_webengine.py
index fdf67286c..8625d482c 100755
--- a/scripts/testbrowser/testbrowser_webengine.py
+++ b/scripts/testbrowser/testbrowser_webengine.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/testbrowser/testbrowser_webkit.py b/scripts/testbrowser/testbrowser_webkit.py
index 73cae08b1..69c021f89 100755
--- a/scripts/testbrowser/testbrowser_webkit.py
+++ b/scripts/testbrowser/testbrowser_webkit.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/scripts/utils.py b/scripts/utils.py
index 9a1a751b2..039e46457 100644
--- a/scripts/utils.py
+++ b/scripts/utils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/setup.py b/setup.py
index 226b0a73e..028c29a0a 100755
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/conftest.py b/tests/conftest.py
index d06dfcfa6..0f84b0ab7 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/conftest.py b/tests/end2end/conftest.py
index 3240cc7b8..ff4e7941b 100644
--- a/tests/end2end/conftest.py
+++ b/tests/end2end/conftest.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/data/misc/pyeval_file.py b/tests/end2end/data/misc/pyeval_file.py
index 1dadc6853..3800c38e7 100644
--- a/tests/end2end/data/misc/pyeval_file.py
+++ b/tests/end2end/data/misc/pyeval_file.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/data/userscripts/stdinclose.py b/tests/end2end/data/userscripts/stdinclose.py
index 21a7e6ca1..ab680ed9c 100755
--- a/tests/end2end/data/userscripts/stdinclose.py
+++ b/tests/end2end/data/userscripts/stdinclose.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/conftest.py b/tests/end2end/features/conftest.py
index ca14768ef..95e9f8022 100644
--- a/tests/end2end/features/conftest.py
+++ b/tests/end2end/features/conftest.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -20,6 +20,7 @@
"""Steps for bdd-like tests."""
import os
+import os.path
import re
import sys
import time
@@ -27,11 +28,13 @@ import json
import logging
import collections
import textwrap
+import subprocess
import pytest
import pytest_bdd as bdd
-from qutebrowser.utils import log, utils
+import qutebrowser
+from qutebrowser.utils import log, utils, docutils
from qutebrowser.browser import pdfjs
from helpers import utils as testutils
@@ -382,6 +385,32 @@ def clear_ssl_errors(request, quteproc):
quteproc.send_cmd(':debug-clear-ssl-errors')
+@bdd.when("the documentation is up to date")
+def update_documentation():
+ """Update the docs before testing :help."""
+ base_path = os.path.dirname(os.path.abspath(qutebrowser.__file__))
+ doc_path = os.path.join(base_path, 'html', 'doc')
+ script_path = os.path.join(base_path, '..', 'scripts')
+
+ try:
+ os.mkdir(doc_path)
+ except FileExistsError:
+ pass
+
+ files = os.listdir(doc_path)
+ if files and all(docutils.docs_up_to_date(p) for p in files):
+ return
+
+ try:
+ subprocess.run(['asciidoc'], stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL)
+ except OSError:
+ pytest.skip("Docs outdated and asciidoc unavailable!")
+
+ update_script = os.path.join(script_path, 'asciidoc2html.py')
+ subprocess.run([sys.executable, update_script])
+
+
## Then
diff --git a/tests/end2end/features/downloads.feature b/tests/end2end/features/downloads.feature
index b1d92145d..563308e42 100644
--- a/tests/end2end/features/downloads.feature
+++ b/tests/end2end/features/downloads.feature
@@ -92,6 +92,15 @@ Feature: Downloading things from a website.
And I run :leave-mode
Then no crash should happen
+ Scenario: Aborting a download in a different window (issue 3378)
+ When I set downloads.location.suggestion to filename
+ And I set downloads.location.prompt to true
+ And I open data/downloads/download.bin in a new window without waiting
+ And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=<PromptMode.download: 5> *" in the log
+ And I run :window-only
+ And I run :leave-mode
+ Then no crash should happen
+
# https://github.com/qutebrowser/qutebrowser/issues/4240
@qt<5.11.2
Scenario: Downloading with SSL errors (issue 1413)
@@ -141,22 +150,30 @@ Feature: Downloading things from a website.
And I wait until the download is finished
Then the downloaded file download with spaces.bin should exist
- @qtwebkit_skip @qt<5.9
- Scenario: Downloading a file with evil content-disposition header (Qt 5.8 or older)
+ @qtwebkit_skip @qt<5.9 @qt>=5.13
+ Scenario: Downloading a file with evil content-disposition header (Qt 5.8 or older and 5.13 and newer)
# Content-Disposition: download; filename=..%2Ffoo
When I open response-headers?Content-Disposition=download;%20filename%3D..%252Ffoo without waiting
And I wait until the download is finished
Then the downloaded file ../foo should not exist
And the downloaded file foo should exist
- @qtwebkit_skip @qt>=5.9
- Scenario: Downloading a file with evil content-disposition header (Qt 5.9 or newer)
+ @qtwebkit_skip @qt<5.13 @qt>=5.9
+ Scenario: Downloading a file with evil content-disposition header (Qt 5.9 to 5.12)
# Content-Disposition: download; filename=..%2Ffoo
When I open response-headers?Content-Disposition=download;%20filename%3D..%252Ffoo without waiting
And I wait until the download is finished
Then the downloaded file ../foo should not exist
And the downloaded file ..%2Ffoo should exist
+ @qtwebkit_skip @qt>=5.13
+ Scenario: Downloading a file with evil content-disposition header (Qt 5.13 or newer)
+ # Content-Disposition: download; filename=..%252Ffoo
+ When I open response-headers?Content-Disposition=download;%20filename%3D..%25252Ffoo without waiting
+ And I wait until the download is finished
+ Then the downloaded file ../foo should not exist
+ And the downloaded file ..%2Ffoo should exist
+
@windows
Scenario: Downloading a file to a reserved path
When I set downloads.location.prompt to true
@@ -522,6 +539,17 @@ Feature: Downloading things from a website.
And I open data/downloads/download2.bin without waiting
Then the download prompt should be shown with "(tmpdir)/downloads/subdir/download2.bin"
+ Scenario: Clearing the last download directory when changing download location
+ When I set downloads.location.prompt to true
+ And I set downloads.location.suggestion to both
+ And I set downloads.location.remember to true
+ And I open data/downloads/download.bin without waiting
+ And I wait for the download prompt for "*/download.bin"
+ And I run :prompt-accept (tmpdir)(dirsep)downloads(dirsep)subdir
+ And I run :set downloads.location.directory (tmpdir)(dirsep)downloads
+ And I open data/downloads/download2.bin without waiting
+ Then the download prompt should be shown with "(tmpdir)/downloads/download2.bin"
+
Scenario: Not remembering the last download directory
When I set downloads.location.prompt to true
And I set downloads.location.suggestion to both
diff --git a/tests/end2end/features/hints.feature b/tests/end2end/features/hints.feature
index cb146e1ae..9d04fb82d 100644
--- a/tests/end2end/features/hints.feature
+++ b/tests/end2end/features/hints.feature
@@ -19,6 +19,16 @@ Feature: Using hints
When I run :hint --mode=foobar
Then the error "Invalid mode: Invalid value 'foobar' - valid values: number, letter, word" should be shown
+ Scenario: Switching tab between :hint and start_cb (issue 3892)
+ When I open data/hints/html/simple.html
+ And I open data/hints/html/simple.html in a new tab
+ And I run :hint ;; tab-prev
+ And I wait for regex "hints: .*|Current tab changed \(\d* -> \d*\) before _start_cb is run\." in the log
+ # 'hints: .*' is logged when _start_cb is called before tab-prev (on
+ # qtwebkit, _start_cb is called synchronously)
+ And I run :follow-hint a
+ Then the error "follow-hint: This command is only allowed in hint mode, not normal." should be shown
+
### Opening in current or new tab
Scenario: Following a hint and force to open in current tab.
@@ -426,6 +436,21 @@ Feature: Using hints
And I run :follow-hint 1
Then data/numbers/7.txt should be loaded
+ ### hints.leave_on_load
+ Scenario: Leaving hint mode on reload
+ When I open data/hints/html/wrapped.html
+ And I hint with args "all"
+ And I run :reload
+ Then "Leaving mode KeyMode.hint (reason: load started)" should be logged
+
+ Scenario: Leaving hint mode on reload without leave_on_load
+ When I set hints.leave_on_load to false
+ And I open data/hints/html/simple.html
+ And I hint with args "all"
+ And I run :reload
+ Then "Leaving mode KeyMode.hint (reason: load started)" should not be logged
+
+
### hints.auto_follow option
Scenario: Using hints.auto_follow = 'always' in letter mode
@@ -569,3 +594,10 @@ Feature: Using hints
And I run :jseval console.log(document.activeElement.id == "qute-input");
And I run :leave-mode
Then the javascript message "true" should be logged
+
+ # Delete hint target
+ Scenario: Deleting a simple target
+ When I open data/hints/html/simple.html
+ And I hint with args "all delete" and follow a
+ And I run :hint
+ Then the error "No elements found." should be shown
diff --git a/tests/end2end/features/history.feature b/tests/end2end/features/history.feature
index 0706fde17..22eef8bc7 100644
--- a/tests/end2end/features/history.feature
+++ b/tests/end2end/features/history.feature
@@ -57,7 +57,7 @@ Feature: Page history
When I run :tab-only
And I open data/javascript/window_open.html
And I run :click-element id open-invalid
- Then "Changing title for idx 1 to 'about:blank'" should be logged
+ Then "load status for * LoadStatus.success" should be logged
Scenario: History with data URL
When I open data/data_link.html
diff --git a/tests/end2end/features/misc.feature b/tests/end2end/features/misc.feature
index b9677a158..e6b7f9fa4 100644
--- a/tests/end2end/features/misc.feature
+++ b/tests/end2end/features/misc.feature
@@ -331,19 +331,16 @@ Feature: Various utility commands.
When I set content.headers.do_not_track to true
And I open headers
Then the header Dnt should be set to 1
- And the header X-Do-Not-Track should be set to 1
Scenario: DNT header (off)
When I set content.headers.do_not_track to false
And I open headers
Then the header Dnt should be set to 0
- And the header X-Do-Not-Track should be set to 0
Scenario: DNT header (unset)
When I set content.headers.do_not_track to <empty>
And I open headers
Then the header Dnt should be set to <unset>
- And the header X-Do-Not-Track should be set to <unset>
Scenario: Accept-Language header
When I set content.headers.accept_language to en,de
@@ -394,6 +391,12 @@ Feature: Various utility commands.
And I run :command-accept
Then the message "Hello World" should be shown
+ ## https://github.com/qutebrowser/qutebrowser/issues/4720
+ Scenario: Chaining failing commands
+ When I run :scroll x ;; message-info foo
+ Then the error "Invalid value 'x' for direction - *" should be shown
+ And the message "foo" should be shown
+
# We can't run :message-i as startup command, so we use
# :set-cmd-text
@@ -418,32 +421,6 @@ Feature: Various utility commands.
history:
- url: http://localhost:*/data/hello3.txt
- ## Variables
-
- Scenario: {url} as part of an argument
- When I open data/hello.txt
- And I run :message-info foo{url}
- Then the message "foohttp://localhost:*/hello.txt" should be shown
-
- Scenario: Multiple variables in an argument
- When I open data/hello.txt
- And I put "foo" into the clipboard
- And I run :message-info {clipboard}bar{url}
- Then the message "foobarhttp://localhost:*/hello.txt" should be shown
-
- Scenario: escaping {{url}} variable
- When I open data/hello.txt
- And I run :message-info foo{{url}}bar
- Then the message "foo{url}bar" should be shown
-
- @xfail_norun
- Scenario: {url} in clipboard should not be expanded
- When I open data/hello.txt
- # FIXME: {url} should be escaped, otherwise it is replaced before it enters clipboard
- And I put "{url}" into the clipboard
- And I run :message-info {clipboard}bar{url}
- Then the message "{url}barhttp://localhost:*/hello.txt" should be shown
-
## :click-element
Scenario: Clicking an element with unknown ID
diff --git a/tests/end2end/features/navigate.feature b/tests/end2end/features/navigate.feature
index 07bd56c69..2596f3ef1 100644
--- a/tests/end2end/features/navigate.feature
+++ b/tests/end2end/features/navigate.feature
@@ -24,7 +24,8 @@ Feature: Using :navigate
Then data/navigate should be loaded
Scenario: Navigating up in qute://help/
- When I open qute://help/commands.html
+ When the documentation is up to date
+ And I open qute://help/commands.html
And I run :navigate up
Then qute://help/ should be loaded
diff --git a/tests/end2end/features/qutescheme.feature b/tests/end2end/features/qutescheme.feature
index 0f5954e19..35c110dc5 100644
--- a/tests/end2end/features/qutescheme.feature
+++ b/tests/end2end/features/qutescheme.feature
@@ -8,7 +8,8 @@ Feature: Special qute:// pages
# :help
Scenario: :help without topic
- When I run :tab-only
+ When the documentation is up to date
+ And I run :tab-only
And I run :help
And I wait until qute://help/index.html is loaded
Then the following tabs should be open:
@@ -39,7 +40,8 @@ Feature: Special qute:// pages
- qute://help/settings.html#editor.command (active)
Scenario: :help with -t
- When I run :tab-only
+ When the documentation is up to date
+ And I run :tab-only
And I run :help -t
And I wait until qute://help/index.html is loaded
Then the following tabs should be open:
@@ -140,29 +142,25 @@ Feature: Special qute:// pages
And I press the key "<Tab>"
Then "Invalid value 'foo' *" should be logged
- @qtwebkit_skip
- Scenario: qute://settings CSRF via img (webengine)
+ Scenario: qute://settings CSRF via img
When I open data/misc/qutescheme_csrf.html
And I run :click-element id via-img
- Then "Blocking malicious request from http://localhost:*/data/misc/qutescheme_csrf.html to qute://settings/set?*" should be logged
+ Then the img request should be blocked
- @qtwebkit_skip
- Scenario: qute://settings CSRF via link (webengine)
+ Scenario: qute://settings CSRF via link
When I open data/misc/qutescheme_csrf.html
And I run :click-element id via-link
- Then "Blocking malicious request from qute://settings/set?* to qute://settings/set?*" should be logged
+ Then the link request should be blocked
- @qtwebkit_skip
- Scenario: qute://settings CSRF via redirect (webengine)
+ Scenario: qute://settings CSRF via redirect
When I open data/misc/qutescheme_csrf.html
And I run :click-element id via-redirect
- Then "Blocking malicious request from qute://settings/set?* to qute://settings/set?*" should be logged
+ Then the redirect request should be blocked
- @qtwebkit_skip
- Scenario: qute://settings CSRF via form (webengine)
+ Scenario: qute://settings CSRF via form
When I open data/misc/qutescheme_csrf.html
And I run :click-element id via-form
- Then "Blocking malicious request from qute://settings/set?* to qute://settings/set?*" should be logged
+ Then the form request should be blocked
@qtwebkit_skip
Scenario: qute://settings CSRF token (webengine)
@@ -171,32 +169,6 @@ Feature: Special qute:// pages
Then "RequestDeniedError while handling qute://* URL" should be logged
And the error "Invalid CSRF token for qute://settings!" should be shown
- @qtwebengine_skip
- Scenario: qute://settings CSRF via img (webkit)
- When I open data/misc/qutescheme_csrf.html
- And I run :click-element id via-img
- Then "Blocking malicious request from http://localhost:*/data/misc/qutescheme_csrf.html to qute://settings/set?*" should be logged
-
- @qtwebengine_skip
- Scenario: qute://settings CSRF via link (webkit)
- When I open data/misc/qutescheme_csrf.html
- And I run :click-element id via-link
- Then "Blocking malicious request from http://localhost:*/data/misc/qutescheme_csrf.html to qute://settings/set?*" should be logged
- And "Error while loading qute://settings/set?*: Invalid qute://settings request" should be logged
-
- @qtwebengine_skip
- Scenario: qute://settings CSRF via redirect (webkit)
- When I open data/misc/qutescheme_csrf.html
- And I run :click-element id via-redirect
- Then "Blocking malicious request from http://localhost:*/data/misc/qutescheme_csrf.html to qute://settings/set?*" should be logged
- And "Error while loading qute://settings/set?*: Invalid qute://settings request" should be logged
-
- @qtwebengine_skip
- Scenario: qute://settings CSRF via form (webkit)
- When I open data/misc/qutescheme_csrf.html
- And I run :click-element id via-form
- Then "Error while loading qute://settings/set?*: Unsupported request type" should be logged
-
# pdfjs support
Scenario: pdfjs is used for pdf files
diff --git a/tests/end2end/features/search.feature b/tests/end2end/features/search.feature
index 8d9d28e78..2c0aa06a5 100644
--- a/tests/end2end/features/search.feature
+++ b/tests/end2end/features/search.feature
@@ -214,18 +214,20 @@ Feature: Searching on a page
# TODO: wrapping message without scrolling
## follow searched links
- @flaky
+ @skip # Too flaky
Scenario: Follow a searched link
When I run :search follow
And I wait for "search found follow" in the log
+ And I wait 0.5s
And I run :follow-selected
Then data/hello.txt should be loaded
- @flaky
+ @skip # Too flaky
Scenario: Follow a searched link in a new tab
When I run :window-only
And I run :search follow
And I wait for "search found follow" in the log
+ And I wait 0.5s
And I run :follow-selected -t
And I wait until data/hello.txt is loaded
Then the following tabs should be open:
@@ -272,7 +274,8 @@ Feature: Searching on a page
And I run :follow-selected
Then "navigation request: url http://localhost:*/data/hello.txt, type Type.link_clicked, is_main_frame False" should be logged
- @qtwebkit_skip: Not supported in qtwebkit @flaky
+ # Too flaky
+ @qtwebkit_skip: Not supported in qtwebkit @skip
Scenario: Follow a tabbed searched link in an iframe
When I open data/iframe_search.html
And I run :tab-only
diff --git a/tests/end2end/features/sessions.feature b/tests/end2end/features/sessions.feature
index 626a88ba8..494feb0ba 100644
--- a/tests/end2end/features/sessions.feature
+++ b/tests/end2end/features/sessions.feature
@@ -228,7 +228,7 @@ Feature: Saving and loading sessions
url: http://localhost:*/data/hello.txt
# Seems like that bug is fixed upstream in QtWebEngine
- @qtwebkit_skip @flaky
+ @skip # Too flaky
Scenario: Saving a session with a page using history.replaceState() and navigating away
When I open data/sessions/history_replace_state.html without waiting
And I wait for "* Called history.replaceState" in the log
diff --git a/tests/end2end/features/spawn.feature b/tests/end2end/features/spawn.feature
index 87ffb53e0..5fabb044d 100644
--- a/tests/end2end/features/spawn.feature
+++ b/tests/end2end/features/spawn.feature
@@ -8,7 +8,7 @@ Feature: :spawn
Scenario: Running :spawn with command that does not exist
When I run :spawn command_does_not_exist127623
- Then the error "Error while spawning command: The process failed to start." should be shown
+ Then the error "Error while spawning command: *" should be shown
Scenario: Starting a userscript which doesn't exist
When I run :spawn -u this_does_not_exist
diff --git a/tests/end2end/features/tabs.feature b/tests/end2end/features/tabs.feature
index 804f72bbf..3c7749d0b 100644
--- a/tests/end2end/features/tabs.feature
+++ b/tests/end2end/features/tabs.feature
@@ -1357,18 +1357,18 @@ Feature: Tab management
And I run :fake-key -g new
Then the javascript message "contents: existingnew" should be logged
+ @skip # Too flaky
Scenario: Focused prompt after opening link in bg
When I open data/hints/link_input.html
When I run :set-cmd-text -s :message-info
And I open data/hello.txt in a new background tab
- And I run :fake-key -g hello-world
- And I run :command-accept
+ And I run :fake-key -g hello-world<enter>
Then the message "hello-world" should be shown
+ @skip # Too flaky
Scenario: Focused prompt after opening link in fg
When I open data/hints/link_input.html
When I run :set-cmd-text -s :message-info
And I open data/hello.txt in a new tab
- And I run :fake-key -g hello-world
- And I run :command-accept
+ And I run :fake-key -g hello-world<enter>
Then the message "hello-world" should be shown
diff --git a/tests/end2end/features/test_backforward_bdd.py b/tests/end2end/features/test_backforward_bdd.py
index 6d9ab626e..d51ddd494 100644
--- a/tests/end2end/features/test_backforward_bdd.py
+++ b/tests/end2end/features/test_backforward_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_caret_bdd.py b/tests/end2end/features/test_caret_bdd.py
index d444f72b1..b95447baf 100644
--- a/tests/end2end/features/test_caret_bdd.py
+++ b/tests/end2end/features/test_caret_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_completion_bdd.py b/tests/end2end/features/test_completion_bdd.py
index cd0254a83..ecb7b026e 100644
--- a/tests/end2end/features/test_completion_bdd.py
+++ b/tests/end2end/features/test_completion_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_downloads_bdd.py b/tests/end2end/features/test_downloads_bdd.py
index 4aa58d053..4c4ae3202 100644
--- a/tests/end2end/features/test_downloads_bdd.py
+++ b/tests/end2end/features/test_downloads_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_editor_bdd.py b/tests/end2end/features/test_editor_bdd.py
index bc1397bf7..b4ed470df 100644
--- a/tests/end2end/features/test_editor_bdd.py
+++ b/tests/end2end/features/test_editor_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_hints_bdd.py b/tests/end2end/features/test_hints_bdd.py
index d0f25b16f..00fae5d3d 100644
--- a/tests/end2end/features/test_hints_bdd.py
+++ b/tests/end2end/features/test_hints_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_history_bdd.py b/tests/end2end/features/test_history_bdd.py
index 4d477d832..6b0265cd6 100644
--- a/tests/end2end/features/test_history_bdd.py
+++ b/tests/end2end/features/test_history_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_invoke_bdd.py b/tests/end2end/features/test_invoke_bdd.py
index 801de132f..5c4992d60 100644
--- a/tests/end2end/features/test_invoke_bdd.py
+++ b/tests/end2end/features/test_invoke_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_javascript_bdd.py b/tests/end2end/features/test_javascript_bdd.py
index 3753d12ad..69f648eff 100644
--- a/tests/end2end/features/test_javascript_bdd.py
+++ b/tests/end2end/features/test_javascript_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_keyinput_bdd.py b/tests/end2end/features/test_keyinput_bdd.py
index 67795d437..69586727c 100644
--- a/tests/end2end/features/test_keyinput_bdd.py
+++ b/tests/end2end/features/test_keyinput_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_marks_bdd.py b/tests/end2end/features/test_marks_bdd.py
index 4734147af..7dd3c3d2b 100644
--- a/tests/end2end/features/test_marks_bdd.py
+++ b/tests/end2end/features/test_marks_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2016-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_misc_bdd.py b/tests/end2end/features/test_misc_bdd.py
index 7d3da36eb..ff686a2e2 100644
--- a/tests/end2end/features/test_misc_bdd.py
+++ b/tests/end2end/features/test_misc_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_navigate_bdd.py b/tests/end2end/features/test_navigate_bdd.py
index a78042f67..62b6a2f76 100644
--- a/tests/end2end/features/test_navigate_bdd.py
+++ b/tests/end2end/features/test_navigate_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_open_bdd.py b/tests/end2end/features/test_open_bdd.py
index 8081e1fb0..377c8792f 100644
--- a/tests/end2end/features/test_open_bdd.py
+++ b/tests/end2end/features/test_open_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_private_bdd.py b/tests/end2end/features/test_private_bdd.py
index f02602d0f..99943ede4 100644
--- a/tests/end2end/features/test_private_bdd.py
+++ b/tests/end2end/features/test_private_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_prompts_bdd.py b/tests/end2end/features/test_prompts_bdd.py
index 0d74700b4..a13b9644d 100644
--- a/tests/end2end/features/test_prompts_bdd.py
+++ b/tests/end2end/features/test_prompts_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_qutescheme_bdd.py b/tests/end2end/features/test_qutescheme_bdd.py
index 8706a1a9c..fcdd2cdb5 100644
--- a/tests/end2end/features/test_qutescheme_bdd.py
+++ b/tests/end2end/features/test_qutescheme_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -17,40 +17,58 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
-import sys
-import os.path
-import subprocess
-
-import pytest
import pytest_bdd as bdd
-import qutebrowser
-from qutebrowser.utils import docutils
+from qutebrowser.utils import qtutils
-bdd.scenarios('qutescheme.feature')
+bdd.scenarios('qutescheme.feature')
-@bdd.when("the documentation is up to date")
-def update_documentation():
- """Update the docs before testing :help."""
- base_path = os.path.dirname(os.path.abspath(qutebrowser.__file__))
- doc_path = os.path.join(base_path, 'html', 'doc')
- script_path = os.path.join(base_path, '..', 'scripts')
- try:
- os.mkdir(doc_path)
- except FileExistsError:
- pass
+@bdd.then(bdd.parsers.parse("the {kind} request should be blocked"))
+def request_blocked(request, quteproc, kind):
+ blocking_set_msg = (
+ "Blocking malicious request from qute://settings/set?* to "
+ "qute://settings/set?*")
+ blocking_csrf_msg = (
+ "Blocking malicious request from "
+ "http://localhost:*/data/misc/qutescheme_csrf.html to "
+ "qute://settings/set?*")
+ blocking_js_msg = (
+ "[http://localhost:*/data/misc/qutescheme_csrf.html:0] Not allowed to "
+ "load local resource: qute://settings/set?*"
+ )
- files = os.listdir(doc_path)
- if files and all(docutils.docs_up_to_date(p) for p in files):
- return
+ webkit_error_invalid = (
+ "Error while loading qute://settings/set?*: Invalid qute://settings "
+ "request")
+ webkit_error_unsupported = (
+ "Error while loading qute://settings/set?*: Unsupported request type")
- try:
- subprocess.run(['asciidoc'], stdout=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL)
- except OSError:
- pytest.skip("Docs outdated and asciidoc unavailable!")
+ if request.config.webengine and qtutils.version_check('5.12'):
+ # On Qt 5.12, we mark qute:// as a local scheme, causing most requests
+ # being blocked by Chromium internally (logging to the JS console).
+ expected_messages = {
+ 'img': [blocking_js_msg],
+ 'link': [blocking_js_msg],
+ 'redirect': [blocking_set_msg],
+ 'form': [blocking_js_msg],
+ }
+ elif request.config.webengine:
+ expected_messages = {
+ 'img': [blocking_csrf_msg],
+ 'link': [blocking_set_msg],
+ 'redirect': [blocking_set_msg],
+ 'form': [blocking_set_msg],
+ }
+ else: # QtWebKit
+ expected_messages = {
+ 'img': [blocking_csrf_msg],
+ 'link': [blocking_csrf_msg, webkit_error_invalid],
+ 'redirect': [blocking_csrf_msg, webkit_error_invalid],
+ 'form': [webkit_error_unsupported],
+ }
- update_script = os.path.join(script_path, 'asciidoc2html.py')
- subprocess.run([sys.executable, update_script])
+ for pattern in expected_messages[kind]:
+ msg = quteproc.wait_for(message=pattern)
+ msg.expected = True
diff --git a/tests/end2end/features/test_scroll_bdd.py b/tests/end2end/features/test_scroll_bdd.py
index 99de7e8e6..2358aa8a6 100644
--- a/tests/end2end/features/test_scroll_bdd.py
+++ b/tests/end2end/features/test_scroll_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_search_bdd.py b/tests/end2end/features/test_search_bdd.py
index 9a4e33208..3822f2f1a 100644
--- a/tests/end2end/features/test_search_bdd.py
+++ b/tests/end2end/features/test_search_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_sessions_bdd.py b/tests/end2end/features/test_sessions_bdd.py
index 942a16425..0b5a32359 100644
--- a/tests/end2end/features/test_sessions_bdd.py
+++ b/tests/end2end/features/test_sessions_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_spawn_bdd.py b/tests/end2end/features/test_spawn_bdd.py
index d7f72acde..5f45e31eb 100644
--- a/tests/end2end/features/test_spawn_bdd.py
+++ b/tests/end2end/features/test_spawn_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_tabs_bdd.py b/tests/end2end/features/test_tabs_bdd.py
index 962a41b5b..313ccf57a 100644
--- a/tests/end2end/features/test_tabs_bdd.py
+++ b/tests/end2end/features/test_tabs_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_urlmarks_bdd.py b/tests/end2end/features/test_urlmarks_bdd.py
index 20364cebd..2980b866e 100644
--- a/tests/end2end/features/test_urlmarks_bdd.py
+++ b/tests/end2end/features/test_urlmarks_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_utilcmds_bdd.py b/tests/end2end/features/test_utilcmds_bdd.py
index 338c500ca..16be24d1b 100644
--- a/tests/end2end/features/test_utilcmds_bdd.py
+++ b/tests/end2end/features/test_utilcmds_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_yankpaste_bdd.py b/tests/end2end/features/test_yankpaste_bdd.py
index 364044085..c29ee826e 100644
--- a/tests/end2end/features/test_yankpaste_bdd.py
+++ b/tests/end2end/features/test_yankpaste_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/test_zoom_bdd.py b/tests/end2end/features/test_zoom_bdd.py
index c397fd715..35a7156ee 100644
--- a/tests/end2end/features/test_zoom_bdd.py
+++ b/tests/end2end/features/test_zoom_bdd.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/features/utilcmds.feature b/tests/end2end/features/utilcmds.feature
index fac335813..9b4eb5760 100644
--- a/tests/end2end/features/utilcmds.feature
+++ b/tests/end2end/features/utilcmds.feature
@@ -131,7 +131,7 @@ Feature: Miscellaneous utility commands exposed to the user.
And I run :prompt-accept
And I run :repeat-command
Then the message "test3" should be shown
- And the message "test3" should be shown
+ And the error "prompt-accept: This command is only allowed in prompt/yesno mode, not normal." should be shown
And the error "prompt-accept: This command is only allowed in prompt/yesno mode, not normal." should be shown
Scenario: :repeat-command with mode-switching command
diff --git a/tests/end2end/features/yankpaste.feature b/tests/end2end/features/yankpaste.feature
index 08a62d302..46ef92a9c 100644
--- a/tests/end2end/features/yankpaste.feature
+++ b/tests/end2end/features/yankpaste.feature
@@ -45,9 +45,16 @@ Feature: Yanking and pasting.
When I open data/title.html
And I wait for regex "Changing title for idx \d to 'Test title'" in the log
And I run :yank markdown
- Then the message "Yanked markdown URL to clipboard: *" should be shown
+ Then the warning ":yank markdown is deprecated, *" should be shown
+ And the message "Yanked markdown URL to clipboard: *" should be shown
And the clipboard should contain "[Test title](http://localhost:(port)/data/title.html)"
+ Scenario: Yanking inline to clipboard
+ When I open data/title.html
+ And I run :yank inline '[[{url}][qutebrowser</3org]]'
+ Then the message "Yanked inline block to clipboard: [[http://localhost:(port)/data/title.html][qutebrowser</3org]]" should be shown
+ And the clipboard should contain "[[http://localhost:(port)/data/title.html][qutebrowser</3org]]"
+
Scenario: Yanking domain to clipboard
When I open data/title.html
And I run :yank domain
diff --git a/tests/end2end/fixtures/quteprocess.py b/tests/end2end/fixtures/quteprocess.py
index 146817c12..9cad17096 100644
--- a/tests/end2end/fixtures/quteprocess.py
+++ b/tests/end2end/fixtures/quteprocess.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -157,6 +157,10 @@ def is_ignored_chromium_message(line):
# cert_verify_proc_openssl.cc(212)]
# X509 Verification error self signed certificate : 18 : 0 : 4
'X509 Verification error self signed certificate : 18 : 0 : 4',
+ # Qt 5.13
+ # [27789:27805:0325/111821.127349:ERROR:ssl_client_socket_impl.cc(962)]
+ # handshake failed; returned -1, SSL error code 1, net_error -202
+ 'handshake failed; returned -1, SSL error code 1, net_error -202',
# Not reproducible anymore?
@@ -230,6 +234,19 @@ def is_ignored_chromium_message(line):
# content.mojom.RendererAudioOutputStreamFactory
'InterfaceRequest was dropped, the document is no longer active: '
'content.mojom.RendererAudioOutputStreamFactory',
+ # [1920:2168:0225/112442.664:ERROR:in_progress_cache_impl.cc(124)]
+ # Could not write download entries to file: C:\Users\appveyor\AppData\
+ # Local\Temp\1\qutebrowser-basedir-1l3jmxq4\data\webengine\
+ # in_progress_download_metadata_store
+ 'Could not write download entries to file: *',
+
+ # Qt 5.13
+ # [32651:32651:0325/130146.300817:WARNING:
+ # render_frame_host_impl.cc(486)]
+ # InterfaceRequest was dropped, the document is no longer active:
+ # resource_coordinator.mojom.FrameCoordinationUnit
+ 'InterfaceRequest was dropped, the document is no longer active: '
+ 'resource_coordinator.mojom.FrameCoordinationUnit',
]
return any(testutils.pattern_match(pattern=pattern, value=message)
for pattern in ignored_messages)
@@ -639,8 +656,11 @@ class QuteProc(testprocess.Process):
Args:
count: The count to pass to the command.
invalid: If True, we don't wait for "command called: ..." in the
- log
+ log and return None.
escape: Escape backslashes in the command
+
+ Return:
+ The parsed log line with "command called: ..." or None.
"""
summary = command
if count is not None:
@@ -655,9 +675,11 @@ class QuteProc(testprocess.Process):
command.lstrip(':'))
self.send_ipc([command])
- if not invalid:
- self.wait_for(category='commands', module='command',
- function='run', message='command called: *')
+ if invalid:
+ return None
+ else:
+ return self.wait_for(category='commands', module='command',
+ function='run', message='command called: *')
def get_setting(self, opt):
"""Get the value of a qutebrowser setting."""
@@ -699,19 +721,20 @@ class QuteProc(testprocess.Process):
if as_url:
self.send_cmd(url, invalid=True)
+ line = None
elif new_tab:
- self.send_cmd(':open -t ' + url)
+ line = self.send_cmd(':open -t ' + url)
elif new_bg_tab:
- self.send_cmd(':open -b ' + url)
+ line = self.send_cmd(':open -b ' + url)
elif new_window:
- self.send_cmd(':open -w ' + url)
+ line = self.send_cmd(':open -w ' + url)
elif private:
- self.send_cmd(':open -p ' + url)
+ line = self.send_cmd(':open -p ' + url)
else:
- self.send_cmd(':open ' + url)
+ line = self.send_cmd(':open ' + url)
if wait:
- self.wait_for_load_finished_url(url)
+ self.wait_for_load_finished_url(url, after=line)
def mark_expected(self, category=None, loglevel=None, message=None):
"""Mark a given logging message as expected."""
@@ -720,7 +743,7 @@ class QuteProc(testprocess.Process):
line.expected = True
def wait_for_load_finished_url(self, url, *, timeout=None,
- load_status='success'):
+ load_status='success', after=None):
"""Wait until a URL has finished loading."""
__tracebackhide__ = (lambda e: e.errisinstance(
testprocess.WaitForTimeout))
@@ -756,7 +779,7 @@ class QuteProc(testprocess.Process):
load_status=re.escape(load_status), url=re.escape(url)))
try:
- self.wait_for(message=pattern, timeout=timeout)
+ self.wait_for(message=pattern, timeout=timeout, after=after)
except testprocess.WaitForTimeout:
raise testprocess.WaitForTimeout("Timed out while waiting for {} "
"to be loaded".format(url))
@@ -819,9 +842,9 @@ class QuteProc(testprocess.Process):
message = self.wait_for_js('qute:*').message
if message.endswith('qute:no elems'):
raise ValueError('No element with {!r} found'.format(text))
- elif message.endswith('qute:ambiguous elems'):
+ if message.endswith('qute:ambiguous elems'):
raise ValueError('Element with {!r} is not unique'.format(text))
- elif not message.endswith('qute:okay'):
+ if not message.endswith('qute:okay'):
raise ValueError('Invalid response from qutebrowser: {}'
.format(message))
diff --git a/tests/end2end/fixtures/test_quteprocess.py b/tests/end2end/fixtures/test_quteprocess.py
index a0dcaf5ce..20cae3855 100644
--- a/tests/end2end/fixtures/test_quteprocess.py
+++ b/tests/end2end/fixtures/test_quteprocess.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/fixtures/test_testprocess.py b/tests/end2end/fixtures/test_testprocess.py
index 5b9979f85..2e9c8ec93 100644
--- a/tests/end2end/fixtures/test_testprocess.py
+++ b/tests/end2end/fixtures/test_testprocess.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/fixtures/test_webserver.py b/tests/end2end/fixtures/test_webserver.py
index 8187e32cd..7033135de 100644
--- a/tests/end2end/fixtures/test_webserver.py
+++ b/tests/end2end/fixtures/test_webserver.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/fixtures/testprocess.py b/tests/end2end/fixtures/testprocess.py
index eab914a1a..4c2d8d38e 100644
--- a/tests/end2end/fixtures/testprocess.py
+++ b/tests/end2end/fixtures/testprocess.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/fixtures/webserver.py b/tests/end2end/fixtures/webserver.py
index d1e45409e..12bb789bd 100644
--- a/tests/end2end/fixtures/webserver.py
+++ b/tests/end2end/fixtures/webserver.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/fixtures/webserver_sub.py b/tests/end2end/fixtures/webserver_sub.py
index 15cd0becc..92d037cb7 100644
--- a/tests/end2end/fixtures/webserver_sub.py
+++ b/tests/end2end/fixtures/webserver_sub.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/fixtures/webserver_sub_ssl.py b/tests/end2end/fixtures/webserver_sub_ssl.py
index 41a9c5ace..5aaa44c1b 100644
--- a/tests/end2end/fixtures/webserver_sub_ssl.py
+++ b/tests/end2end/fixtures/webserver_sub_ssl.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/misc/test_runners_e2e.py b/tests/end2end/misc/test_runners_e2e.py
new file mode 100644
index 000000000..4605741a3
--- /dev/null
+++ b/tests/end2end/misc/test_runners_e2e.py
@@ -0,0 +1,85 @@
+# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+
+# Copyright 2019 Jay Kamat <jaygkamat@gmail.com>
+#
+# This file is part of qutebrowser.
+#
+# qutebrowser is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# qutebrowser is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
+
+"""Tests for runners."""
+
+import logging
+
+import pytest
+
+
+def command_expansion_base(
+ quteproc, send_msg, recv_msg, url="data/hello.txt"):
+ quteproc.open_path(url)
+ quteproc.send_cmd(':message-info ' + send_msg)
+
+ quteproc.mark_expected(category='message',
+ loglevel=logging.INFO,
+ message=recv_msg)
+
+
+@pytest.mark.parametrize('send_msg, recv_msg', [
+ # escaping by double-quoting
+ ('foo{{url}}bar', 'foo{url}bar'),
+
+ ('foo{url}', 'foohttp://localhost:*/hello.txt'),
+ ('foo{url:pretty}', 'foohttp://localhost:*/hello.txt'),
+ ('foo{url:domain}', 'foohttp://localhost:*'),
+ # test {url:auth} on a site with no auth
+ ('foo{url:auth}', 'foo'),
+ ('foo{url:scheme}', 'foohttp'),
+ ('foo{url:host}', 'foolocalhost'),
+ ('foo{url:path}', 'foo*/hello.txt'),
+])
+def test_command_expansion(quteproc, send_msg, recv_msg):
+ command_expansion_base(quteproc, send_msg, recv_msg)
+
+
+@pytest.mark.parametrize('send_msg, recv_msg, url', [
+ ('foo{title}', 'fooTest title', 'data/title.html'),
+ ('foo{url:query}', 'fooq=bar', 'data/hello.txt?q=bar'),
+
+ # multiple variable expansion
+ ('{title}bar{url}', 'Test titlebarhttp://localhost:*/title.html', 'data/title.html'),
+])
+def test_command_expansion_complex(
+ quteproc, send_msg, recv_msg, url):
+ command_expansion_base(quteproc, send_msg, recv_msg, url)
+
+
+def test_command_expansion_basic_auth(quteproc, server):
+ url = ('http://user1:password1@localhost:{port}/basic-auth/user1/password1'
+ .format(port=server.port))
+ quteproc.open_url(url)
+ quteproc.send_cmd(':message-info foo{url:auth}')
+
+ quteproc.mark_expected(
+ category='message',
+ loglevel=logging.INFO, message='foouser1:password1@')
+
+
+def test_command_expansion_clipboard(quteproc):
+ quteproc.send_cmd(':debug-set-fake-clipboard "foo"')
+ command_expansion_base(
+ quteproc, '{clipboard}bar{url}',
+ "foobarhttp://localhost:*/hello.txt")
+ quteproc.send_cmd(':debug-set-fake-clipboard "{{url}}"')
+ command_expansion_base(
+ quteproc, '{clipboard}bar{url}',
+ "{url}barhttp://localhost:*/hello.txt")
diff --git a/tests/end2end/test_dirbrowser.py b/tests/end2end/test_dirbrowser.py
index 3702c4ee7..1d68e26dc 100644
--- a/tests/end2end/test_dirbrowser.py
+++ b/tests/end2end/test_dirbrowser.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Daniel Schadt
#
# This file is part of qutebrowser.
diff --git a/tests/end2end/test_hints_html.py b/tests/end2end/test_hints_html.py
index 65502c7b7..230812d1a 100644
--- a/tests/end2end/test_hints_html.py
+++ b/tests/end2end/test_hints_html.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/test_insert_mode.py b/tests/end2end/test_insert_mode.py
index 690b5d38b..54e011df6 100644
--- a/tests/end2end/test_insert_mode.py
+++ b/tests/end2end/test_insert_mode.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -85,3 +85,20 @@ def test_auto_leave_insert_mode(quteproc):
# Select the disabled input box to leave insert mode
quteproc.send_cmd(':follow-hint s')
quteproc.wait_for(message='Clicked non-editable element!')
+
+
+@pytest.mark.parametrize('leave_on_load', [True, False])
+def test_auto_leave_insert_mode_reload(quteproc, leave_on_load):
+ url_path = 'data/hello.txt'
+ quteproc.open_path(url_path)
+
+ quteproc.set_setting('input.insert_mode.leave_on_load',
+ str(leave_on_load).lower())
+ quteproc.send_cmd(':enter-mode insert')
+ quteproc.wait_for(message='Entering mode KeyMode.insert (reason: *)')
+ quteproc.send_cmd(':reload')
+ if leave_on_load:
+ quteproc.wait_for(message='Leaving mode KeyMode.insert (reason: *)')
+ else:
+ quteproc.wait_for(
+ message='Ignoring leave_on_load request due to setting.')
diff --git a/tests/end2end/test_invocations.py b/tests/end2end/test_invocations.py
index 0375554b8..5f4056356 100644
--- a/tests/end2end/test_invocations.py
+++ b/tests/end2end/test_invocations.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/end2end/test_mhtml_e2e.py b/tests/end2end/test_mhtml_e2e.py
index 27fdd2abf..52fb71de9 100644
--- a/tests/end2end/test_mhtml_e2e.py
+++ b/tests/end2end/test_mhtml_e2e.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -53,6 +53,10 @@ def normalize_line(line):
line = line.replace('Content-Type: application/x-javascript',
'Content-Type: application/javascript')
+ # With QtWebKit and newer Werkzeug versions, we also get an encoding
+ # specified.
+ line = line.replace('javascript; charset=utf-8', 'javascript')
+
# Added with Qt 5.11
if (line.startswith('Snapshot-Content-Location: ') and
not qtutils.version_check('5.11', compiled=False)):
diff --git a/tests/helpers/fixtures.py b/tests/helpers/fixtures.py
index ef4a4d2f3..ad9de10db 100644
--- a/tests/helpers/fixtures.py
+++ b/tests/helpers/fixtures.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -171,6 +171,7 @@ def testdata_scheme(qapp):
global _qute_scheme_handler
from qutebrowser.browser.webengine import webenginequtescheme
from PyQt5.QtWebEngineWidgets import QWebEngineProfile
+ webenginequtescheme.init()
_qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(
parent=qapp)
_qute_scheme_handler.install(QWebEngineProfile.defaultProfile())
@@ -414,7 +415,7 @@ def qnam(qapp):
@pytest.fixture
-def webengineview(qtbot, monkeypatch):
+def webengineview(qtbot, monkeypatch, web_tab_setup):
"""Get a QWebEngineView if QtWebEngine is available."""
QtWebEngineWidgets = pytest.importorskip('PyQt5.QtWebEngineWidgets')
monkeypatch.setattr(objects, 'backend', usertypes.Backend.QtWebEngine)
@@ -427,7 +428,15 @@ def webengineview(qtbot, monkeypatch):
def webpage(qnam):
"""Get a new QWebPage object."""
QtWebKitWidgets = pytest.importorskip('PyQt5.QtWebKitWidgets')
- page = QtWebKitWidgets.QWebPage()
+ class WebPageStub(QtWebKitWidgets.QWebPage):
+
+ """QWebPage with default error pages disabled."""
+
+ def supportsExtension(self, _ext):
+ """No extensions needed."""
+ return False
+
+ page = WebPageStub()
page.networkAccessManager().deleteLater()
page.setNetworkAccessManager(qnam)
return page
diff --git a/tests/helpers/logfail.py b/tests/helpers/logfail.py
index 740dd4333..dfe0a5995 100644
--- a/tests/helpers/logfail.py
+++ b/tests/helpers/logfail.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/helpers/messagemock.py b/tests/helpers/messagemock.py
index ee32819dd..421abee32 100644
--- a/tests/helpers/messagemock.py
+++ b/tests/helpers/messagemock.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/helpers/stubs.py b/tests/helpers/stubs.py
index 38d82c004..cabd606b6 100644
--- a/tests/helpers/stubs.py
+++ b/tests/helpers/stubs.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -116,7 +116,7 @@ class FakeQApplication:
UNSET = object()
def __init__(self, style=None, all_widgets=None, active_window=None,
- instance=UNSET):
+ instance=UNSET, arguments=None):
if instance is self.UNSET:
self.instance = mock.Mock(return_value=self)
@@ -128,6 +128,7 @@ class FakeQApplication:
self.allWidgets = lambda: all_widgets
self.activeWindow = lambda: active_window
+ self.arguments = lambda: arguments
class FakeNetworkReply:
@@ -301,8 +302,7 @@ class FakeSignal:
def __call__(self):
if self._func is None:
raise TypeError("'FakeSignal' object is not callable")
- else:
- return self._func()
+ return self._func()
def connect(self, slot):
"""Connect the signal to a slot.
@@ -530,10 +530,9 @@ class TabWidgetStub(QObject):
def indexOf(self, _tab):
if self.index_of is None:
raise ValueError("indexOf got called with index_of None!")
- elif self.index_of is RuntimeError:
+ if self.index_of is RuntimeError:
raise RuntimeError
- else:
- return self.index_of
+ return self.index_of
def currentIndex(self):
if self.current_index is None:
diff --git a/tests/helpers/test_helper_utils.py b/tests/helpers/test_helper_utils.py
index a0f3a0885..3398a7624 100644
--- a/tests/helpers/test_helper_utils.py
+++ b/tests/helpers/test_helper_utils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/helpers/test_logfail.py b/tests/helpers/test_logfail.py
index d84ee4a14..3729cdeed 100644
--- a/tests/helpers/test_logfail.py
+++ b/tests/helpers/test_logfail.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/helpers/test_stubs.py b/tests/helpers/test_stubs.py
index 197148b0c..5afd8603f 100644
--- a/tests/helpers/test_stubs.py
+++ b/tests/helpers/test_stubs.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/helpers/utils.py b/tests/helpers/utils.py
index 731103b68..2157eaeb1 100644
--- a/tests/helpers/utils.py
+++ b/tests/helpers/utils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/manual/mouse.html b/tests/manual/mouse.html
index 745672519..eb75df44d 100644
--- a/tests/manual/mouse.html
+++ b/tests/manual/mouse.html
@@ -7,7 +7,7 @@
<body>
<ul>
<li>Middle- or Ctrl-click on a <a href="https://www.qutebrowser.org">link</a> should open it in a new tab (fg/bg according to <code>tabs.background</code>)</li>
- <li>When clicking the link with shift, <code>tabs.background_tabs</code> should be reversed accordingly.</li>
+ <li>When clicking the link with shift, <code>tabs.background</code> should be reversed accordingly.</li>
<li>Ctrl + Mousewheel should zoom in/out</li>
<li>Back/forward keys on mouse should navigate back/forward</li>
<li>With <code>input.rocker_gestures</code> set, no context menu should be shown, but pressing left+right/right+left buttons should navigate back/forward</li>
diff --git a/tests/test_conftest.py b/tests/test_conftest.py
index 2d94add22..daae65de1 100644
--- a/tests/test_conftest.py
+++ b/tests/test_conftest.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/api/test_cmdutils.py b/tests/unit/api/test_cmdutils.py
index 4116045ae..fb8aba06e 100644
--- a/tests/unit/api/test_cmdutils.py
+++ b/tests/unit/api/test_cmdutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/test_caret.py b/tests/unit/browser/test_caret.py
index b3706ffca..a4e7fb2e6 100644
--- a/tests/unit/browser/test_caret.py
+++ b/tests/unit/browser/test_caret.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -24,7 +24,7 @@ import textwrap
import pytest
from PyQt5.QtCore import QUrl
-from qutebrowser.utils import usertypes, qtutils
+from qutebrowser.utils import usertypes
@pytest.fixture
@@ -335,12 +335,10 @@ class TestFollowSelected:
def expose(self, web_tab):
"""Expose the web view if needed.
- On QtWebKit, or Qt < 5.11 on QtWebEngine, we need to show the tab for
- selections to work properly.
+ On QtWebKit, or Qt < 5.11 and > 5.12 on QtWebEngine, we need to
+ show the tab for selections to work properly.
"""
- if (web_tab.backend == usertypes.Backend.QtWebKit or
- not qtutils.version_check('5.11', compiled=False)):
- web_tab.container.expose()
+ web_tab.container.expose()
def test_follow_selected_without_a_selection(self, qtbot, caret, selection, web_tab,
mode_manager):
@@ -368,3 +366,33 @@ class TestFollowSelected:
with qtbot.wait_signal(caret.follow_selected_done):
caret.follow_selected()
assert web_tab.url().path() == '/data/hello.txt'
+
+
+class TestReverse:
+
+ def test_does_not_change_selection(self, caret, selection):
+ selection.toggle()
+ caret.reverse_selection()
+ selection.check("")
+
+ def test_repetition_of_movement_results_in_empty_selection(self, caret, selection):
+ selection.toggle()
+ caret.move_to_end_of_word()
+ caret.reverse_selection()
+ caret.move_to_end_of_word()
+ selection.check("")
+
+ def test_reverse(self, caret, selection):
+ selection.toggle()
+ caret.move_to_end_of_word()
+ caret.reverse_selection()
+ caret.move_to_next_char()
+ selection.check("ne")
+ caret.reverse_selection()
+ caret.move_to_next_char()
+ selection.check("ne ")
+ caret.move_to_end_of_line()
+ selection.check("ne two three")
+ caret.reverse_selection()
+ caret.move_to_start_of_line()
+ selection.check("one two three")
diff --git a/tests/unit/browser/test_hints.py b/tests/unit/browser/test_hints.py
index 609fb3dc6..8ce677a25 100644
--- a/tests/unit/browser/test_hints.py
+++ b/tests/unit/browser/test_hints.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -25,7 +25,7 @@ import operator
import pytest
from PyQt5.QtCore import QUrl
-from qutebrowser.utils import usertypes, qtutils
+from qutebrowser.utils import usertypes
import qutebrowser.browser.hints
@@ -42,11 +42,7 @@ def tabbed_browser(tabbed_browser_stubs, web_tab):
tb.widget.tabs = [web_tab]
tb.widget.current_index = 1
tb.widget.cur_url = QUrl('https://www.example.com/')
-
- if not qtutils.version_check('5.11', compiled=False):
- # No elements found if we don't do this.
- web_tab.container.expose()
-
+ web_tab.container.expose() # No elements found if we don't do this.
return tb
@@ -58,7 +54,8 @@ def test_show_benchmark(benchmark, tabbed_browser, qtbot, message_bridge,
with qtbot.wait_signal(tab.load_finished):
tab.load_url(QUrl('qute://testdata/data/hints/benchmark.html'))
- manager = qutebrowser.browser.hints.HintManager(0, 0)
+ manager = qutebrowser.browser.hints.HintManager(
+ win_id=0, tab_id=tab.tab_id)
def bench():
with qtbot.wait_signal(mode_manager.entered):
@@ -71,14 +68,16 @@ def test_show_benchmark(benchmark, tabbed_browser, qtbot, message_bridge,
def test_match_benchmark(benchmark, tabbed_browser, qtbot, message_bridge,
- mode_manager, qapp):
+ mode_manager, qapp, config_stub):
"""Benchmark matching of hint labels."""
tab = tabbed_browser.widget.tabs[0]
with qtbot.wait_signal(tab.load_finished):
tab.load_url(QUrl('qute://testdata/data/hints/benchmark.html'))
- manager = qutebrowser.browser.hints.HintManager(0, 0)
+ config_stub.val.hints.scatter = False
+ manager = qutebrowser.browser.hints.HintManager(
+ win_id=0, tab_id=tab.tab_id)
with qtbot.wait_signal(mode_manager.entered):
manager.start()
diff --git a/tests/unit/browser/test_history.py b/tests/unit/browser/test_history.py
index 715b597b0..297fd4c2d 100644
--- a/tests/unit/browser/test_history.py
+++ b/tests/unit/browser/test_history.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -183,28 +183,27 @@ class TestAdd:
assert not list(web_history)
assert not list(web_history.completion)
- @pytest.mark.parametrize('environmental', [True, False])
+ @pytest.mark.parametrize('known_error', [True, False])
@pytest.mark.parametrize('completion', [True, False])
def test_error(self, monkeypatch, web_history, message_mock, caplog,
- environmental, completion):
+ known_error, completion):
def raise_error(url, replace=False):
- if environmental:
- raise sql.SqlEnvironmentError("Error message")
- else:
- raise sql.SqlBugError("Error message")
+ if known_error:
+ raise sql.KnownError("Error message")
+ raise sql.BugError("Error message")
if completion:
monkeypatch.setattr(web_history.completion, 'insert', raise_error)
else:
monkeypatch.setattr(web_history, 'insert', raise_error)
- if environmental:
+ if known_error:
with caplog.at_level(logging.ERROR):
web_history.add_url(QUrl('https://www.example.org/'))
msg = message_mock.getmsg(usertypes.MessageLevel.error)
assert msg.text == "Failed to write history: Error message"
else:
- with pytest.raises(sql.SqlBugError):
+ with pytest.raises(sql.BugError):
web_history.add_url(QUrl('https://www.example.org/'))
@pytest.mark.parametrize('level, url, req_url, expected', [
@@ -230,6 +229,37 @@ class TestAdd:
assert list(web_history)
assert not list(web_history.completion)
+ def test_no_immedate_duplicates(self, web_history, mock_time):
+ url = QUrl("http://example.com")
+ url2 = QUrl("http://example2.com")
+ web_history.add_from_tab(QUrl(url), QUrl(url), 'title')
+ hist = list(web_history)
+ assert hist
+ web_history.add_from_tab(QUrl(url), QUrl(url), 'title')
+ assert list(web_history) == hist
+ web_history.add_from_tab(QUrl(url2), QUrl(url2), 'title')
+ assert list(web_history) != hist
+
+ def test_delete_add_tab(self, web_history, mock_time):
+ url = QUrl("http://example.com")
+ web_history.add_from_tab(QUrl(url), QUrl(url), 'title')
+ hist = list(web_history)
+ assert hist
+ web_history.delete_url(QUrl(url))
+ assert len(web_history) == 0
+ web_history.add_from_tab(QUrl(url), QUrl(url), 'title')
+ assert list(web_history) == hist
+
+ def test_clear_add_tab(self, web_history, mock_time):
+ url = QUrl("http://example.com")
+ web_history.add_from_tab(QUrl(url), QUrl(url), 'title')
+ hist = list(web_history)
+ assert hist
+ web_history.clear(force=True)
+ assert len(web_history) == 0
+ web_history.add_from_tab(QUrl(url), QUrl(url), 'title')
+ assert list(web_history) == hist
+
class TestHistoryInterface:
diff --git a/tests/unit/browser/test_pdfjs.py b/tests/unit/browser/test_pdfjs.py
index dcee2b82b..6014dedfb 100644
--- a/tests/unit/browser/test_pdfjs.py
+++ b/tests/unit/browser/test_pdfjs.py
@@ -24,7 +24,7 @@ import pytest
from PyQt5.QtCore import QUrl
from qutebrowser.browser import pdfjs
-from qutebrowser.utils import usertypes, utils
+from qutebrowser.utils import usertypes, utils, urlmatch
pytestmark = [pytest.mark.usefixtures('data_tmpdir')]
@@ -234,6 +234,17 @@ def test_should_use_pdfjs(mimetype, url, enabled, expected, config_stub):
assert pdfjs.should_use_pdfjs(mimetype, QUrl(url)) == expected
+@pytest.mark.parametrize('url, expected', [
+ ('http://example.com', True),
+ ('http://example.org', False),
+])
+def test_should_use_pdfjs_url_pattern(config_stub, url, expected):
+ config_stub.val.content.pdfjs = False
+ pattern = urlmatch.UrlPattern('http://example.com')
+ config_stub.set_obj('content.pdfjs', True, pattern=pattern)
+ assert pdfjs.should_use_pdfjs('application/pdf', QUrl(url)) == expected
+
+
def test_get_main_url():
expected = ('qute://pdfjs/web/viewer.html?filename='
'hello?world.pdf&file=')
diff --git a/tests/unit/browser/test_qutescheme.py b/tests/unit/browser/test_qutescheme.py
index 0741f38db..0be63fa62 100644
--- a/tests/unit/browser/test_qutescheme.py
+++ b/tests/unit/browser/test_qutescheme.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2017-2018 Imran Sobir
#
# This file is part of qutebrowser.
diff --git a/tests/unit/browser/test_shared.py b/tests/unit/browser/test_shared.py
index 78302d8c1..541782bc2 100644
--- a/tests/unit/browser/test_shared.py
+++ b/tests/unit/browser/test_shared.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -26,18 +26,15 @@ from qutebrowser.browser import shared
@pytest.mark.parametrize('dnt, accept_language, custom_headers, expected', [
# DNT
- (True, None, {}, {b'DNT': b'1', b'X-Do-Not-Track': b'1'}),
- (False, None, {}, {b'DNT': b'0', b'X-Do-Not-Track': b'0'}),
+ (True, None, {}, {b'DNT': b'1'}),
+ (False, None, {}, {b'DNT': b'0'}),
(None, None, {}, {}),
# Accept-Language
- (False, 'de, en', {}, {b'DNT': b'0', b'X-Do-Not-Track': b'0',
- b'Accept-Language': b'de, en'}),
+ (False, 'de, en', {}, {b'DNT': b'0', b'Accept-Language': b'de, en'}),
# Custom headers
- (False, None, {'X-Qute': 'yes'}, {b'DNT': b'0', b'X-Do-Not-Track': b'0',
- b'X-Qute': b'yes'}),
+ (False, None, {'X-Qute': 'yes'}, {b'DNT': b'0', b'X-Qute': b'yes'}),
# Mixed
(False, 'de, en', {'X-Qute': 'yes'}, {b'DNT': b'0',
- b'X-Do-Not-Track': b'0',
b'Accept-Language': b'de, en',
b'X-Qute': b'yes'}),
])
diff --git a/tests/unit/browser/test_signalfilter.py b/tests/unit/browser/test_signalfilter.py
index 8ea800e23..f292ff354 100644
--- a/tests/unit/browser/test_signalfilter.py
+++ b/tests/unit/browser/test_signalfilter.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/urlmarks.py b/tests/unit/browser/urlmarks.py
index df7b3286d..f216d3491 100644
--- a/tests/unit/browser/urlmarks.py
+++ b/tests/unit/browser/urlmarks.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2018-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/webengine/test_spell.py b/tests/unit/browser/webengine/test_spell.py
index 2fe6ad8ac..80fba1c84 100644
--- a/tests/unit/browser/webengine/test_spell.py
+++ b/tests/unit/browser/webengine/test_spell.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2017-2018 Michal Siedlaczek <michal.siedlaczek@gmail.com>
# This file is part of qutebrowser.
diff --git a/tests/unit/browser/webengine/test_webenginedownloads.py b/tests/unit/browser/webengine/test_webenginedownloads.py
index a34962522..aaa869616 100644
--- a/tests/unit/browser/webengine/test_webenginedownloads.py
+++ b/tests/unit/browser/webengine/test_webenginedownloads.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -30,6 +30,8 @@ from helpers import utils
@pytest.mark.parametrize('path, expected', [
(os.path.join('subfolder', 'foo'), 'foo'),
('foo(1)', 'foo'),
+ ('foo (1)', 'foo'),
+ ('foo - 1970-01-01T00:00:00.000Z', 'foo'),
('foo(a)', 'foo(a)'),
('foo1', 'foo1'),
pytest.param('foo%20bar', 'foo bar', marks=utils.qt58),
diff --git a/tests/unit/browser/webengine/test_webengineinterceptor.py b/tests/unit/browser/webengine/test_webengineinterceptor.py
new file mode 100644
index 000000000..9ea8ddcf5
--- /dev/null
+++ b/tests/unit/browser/webengine/test_webengineinterceptor.py
@@ -0,0 +1,39 @@
+# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+#
+# This file is part of qutebrowser.
+#
+# qutebrowser is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# qutebrowser is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
+
+"""Test interceptor.py for webengine."""
+
+
+import pytest
+
+pytest.importorskip('PyQt5.QtWebEngineWidgets')
+
+from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInfo
+
+from qutebrowser.browser.webengine import interceptor
+
+
+class TestWebengineInterceptor:
+
+ def test_requestinfo_dict_valid(self):
+ """Test that the RESOURCE_TYPES dict is not missing any values."""
+ qb_keys = interceptor.RequestInterceptor.RESOURCE_TYPES.keys()
+ qt_keys = {i for i in vars(QWebEngineUrlRequestInfo).values()
+ if isinstance(i, QWebEngineUrlRequestInfo.ResourceType)}
+ assert qt_keys == qb_keys
diff --git a/tests/unit/browser/webengine/test_webenginesettings.py b/tests/unit/browser/webengine/test_webenginesettings.py
index d40002a77..0e369d655 100644
--- a/tests/unit/browser/webengine/test_webenginesettings.py
+++ b/tests/unit/browser/webengine/test_webenginesettings.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -30,7 +30,9 @@ from qutebrowser.misc import objects
@pytest.fixture(autouse=True)
-def init(qapp, config_stub, cache_tmpdir, data_tmpdir):
+def init(qapp, config_stub, cache_tmpdir, data_tmpdir, monkeypatch):
+ monkeypatch.setattr(webenginesettings.webenginequtescheme, 'init',
+ lambda: None)
init_args = types.SimpleNamespace(enable_webengine_inspector=False)
webenginesettings.init(init_args)
config_stub.changed.disconnect(webenginesettings._update_settings)
@@ -84,3 +86,7 @@ def test_spell_check_disabled(config_stub, monkeypatch):
for profile in [webenginesettings.default_profile,
webenginesettings.private_profile]:
assert not profile.isSpellCheckEnabled()
+
+
+def test_default_user_agent_saved():
+ assert webenginesettings.default_user_agent is not None
diff --git a/tests/unit/browser/webengine/test_webenginetab.py b/tests/unit/browser/webengine/test_webenginetab.py
index 50bbdf716..380bb8641 100644
--- a/tests/unit/browser/webengine/test_webenginetab.py
+++ b/tests/unit/browser/webengine/test_webenginetab.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -25,8 +25,10 @@ import pytest
QtWebEngineWidgets = pytest.importorskip("PyQt5.QtWebEngineWidgets")
QWebEnginePage = QtWebEngineWidgets.QWebEnginePage
QWebEngineScriptCollection = QtWebEngineWidgets.QWebEngineScriptCollection
+QWebEngineScript = QtWebEngineWidgets.QWebEngineScript
from qutebrowser.browser import greasemonkey
+from qutebrowser.utils import usertypes
pytestmark = pytest.mark.usefixtures('greasemonkey_manager')
@@ -91,3 +93,26 @@ class TestWebengineScripts:
collection = webengine_scripts._widget.page().scripts()
assert collection.toList()[-1].worldId() == worldid
+
+ def test_greasemonkey_document_end_workaround(self, monkeypatch,
+ webengine_scripts):
+ """Make sure document-end is forced when needed."""
+ monkeypatch.setattr(greasemonkey.objects, 'backend',
+ usertypes.Backend.QtWebEngine)
+ monkeypatch.setattr(greasemonkey.qtutils, 'version_check',
+ lambda version, exact=False, compiled=True:
+ True)
+
+ scripts = [
+ greasemonkey.GreasemonkeyScript([
+ ('name', 'Iridium'),
+ ('namespace', 'https://github.com/ParticleCore'),
+ ('run-at', 'document-start'),
+ ], None)
+ ]
+
+ webengine_scripts._inject_greasemonkey_scripts(scripts)
+
+ collection = webengine_scripts._widget.page().scripts()
+ script = collection.toList()[-1]
+ assert script.injectionPoint() == QWebEngineScript.DocumentReady
diff --git a/tests/unit/browser/webkit/http/test_content_disposition.py b/tests/unit/browser/webkit/http/test_content_disposition.py
index c85174b6a..92ad037bb 100644
--- a/tests/unit/browser/webkit/http/test_content_disposition.py
+++ b/tests/unit/browser/webkit/http/test_content_disposition.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/webkit/http/test_http.py b/tests/unit/browser/webkit/http/test_http.py
index 161efd482..5cc71c18a 100644
--- a/tests/unit/browser/webkit/http/test_http.py
+++ b/tests/unit/browser/webkit/http/test_http.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/webkit/http/test_http_hypothesis.py b/tests/unit/browser/webkit/http/test_http_hypothesis.py
index 5727bf1bc..85ee1fa3d 100644
--- a/tests/unit/browser/webkit/http/test_http_hypothesis.py
+++ b/tests/unit/browser/webkit/http/test_http_hypothesis.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/webkit/network/test_filescheme.py b/tests/unit/browser/webkit/network/test_filescheme.py
index 2654097ea..c477ead23 100644
--- a/tests/unit/browser/webkit/network/test_filescheme.py
+++ b/tests/unit/browser/webkit/network/test_filescheme.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Antoni Boucher (antoyo) <bouanto@zoho.com>
#
# This file is part of qutebrowser.
diff --git a/tests/unit/browser/webkit/network/test_networkmanager.py b/tests/unit/browser/webkit/network/test_networkmanager.py
index f6701b419..5a6a19ac6 100644
--- a/tests/unit/browser/webkit/network/test_networkmanager.py
+++ b/tests/unit/browser/webkit/network/test_networkmanager.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/webkit/network/test_networkreply.py b/tests/unit/browser/webkit/network/test_networkreply.py
index 6dffa87cf..0dc9482ec 100644
--- a/tests/unit/browser/webkit/network/test_networkreply.py
+++ b/tests/unit/browser/webkit/network/test_networkreply.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/webkit/network/test_pac.py b/tests/unit/browser/webkit/network/test_pac.py
index 8c03c6cee..c06f9d8c2 100644
--- a/tests/unit/browser/webkit/network/test_pac.py
+++ b/tests/unit/browser/webkit/network/test_pac.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -205,6 +205,20 @@ def test_secret_url(url, has_secret, from_file):
res.resolve(QNetworkProxyQuery(QUrl(url)), from_file=from_file)
+def test_logging(qtlog):
+ """Make sure console.log() works for PAC files."""
+ test_str = """
+ function FindProxyForURL(domain, host) {
+ console.log("logging test");
+ return "DIRECT";
+ }
+ """
+ res = pac.PACResolver(test_str)
+ res.resolve(QNetworkProxyQuery(QUrl("https://example.com/test")))
+ assert len(qtlog.records) == 1
+ assert qtlog.records[0].message == 'logging test'
+
+
def fetcher_test(test_str):
class PACHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
diff --git a/tests/unit/browser/webkit/test_cache.py b/tests/unit/browser/webkit/test_cache.py
index 3fcc833d8..e0fabda0f 100644
--- a/tests/unit/browser/webkit/test_cache.py
+++ b/tests/unit/browser/webkit/test_cache.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 lamarpavel
#
# This file is part of qutebrowser.
diff --git a/tests/unit/browser/webkit/test_cookies.py b/tests/unit/browser/webkit/test_cookies.py
index 99e6d9edc..fbe4427ad 100644
--- a/tests/unit/browser/webkit/test_cookies.py
+++ b/tests/unit/browser/webkit/test_cookies.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Alexander Cogneau (acogneau) <alexander.cogneau@gmail.com>:
#
# This file is part of qutebrowser.
diff --git a/tests/unit/browser/webkit/test_downloads.py b/tests/unit/browser/webkit/test_downloads.py
index 1ab80ec65..95ec826fb 100644
--- a/tests/unit/browser/webkit/test_downloads.py
+++ b/tests/unit/browser/webkit/test_downloads.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/webkit/test_mhtml.py b/tests/unit/browser/webkit/test_mhtml.py
index 015e90b3f..0ad88362c 100644
--- a/tests/unit/browser/webkit/test_mhtml.py
+++ b/tests/unit/browser/webkit/test_mhtml.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Daniel Schadt
#
# This file is part of qutebrowser.
diff --git a/tests/unit/browser/webkit/test_tabhistory.py b/tests/unit/browser/webkit/test_tabhistory.py
index 84a535fa0..a05bc0f98 100644
--- a/tests/unit/browser/webkit/test_tabhistory.py
+++ b/tests/unit/browser/webkit/test_tabhistory.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/browser/webkit/test_webkitelem.py b/tests/unit/browser/webkit/test_webkitelem.py
index 17eae9c09..d01c052e5 100644
--- a/tests/unit/browser/webkit/test_webkitelem.py
+++ b/tests/unit/browser/webkit/test_webkitelem.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -387,7 +387,7 @@ class TestWebKitElement:
def test_simple_getters(self, elem, attribute, code):
sentinel = object()
mock = getattr(elem._elem, attribute)
- setattr(mock, 'return_value', sentinel)
+ mock.return_value = sentinel
assert code(elem) is sentinel
@pytest.mark.parametrize('frame, expected', [
diff --git a/tests/unit/commands/test_argparser.py b/tests/unit/commands/test_argparser.py
index 0b6afc210..6852e872a 100644
--- a/tests/unit/commands/test_argparser.py
+++ b/tests/unit/commands/test_argparser.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/commands/test_runners.py b/tests/unit/commands/test_runners.py
index cd2dea1d4..f73783352 100644
--- a/tests/unit/commands/test_runners.py
+++ b/tests/unit/commands/test_runners.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/commands/test_userscripts.py b/tests/unit/commands/test_userscripts.py
index ff6b9a558..280450b68 100644
--- a/tests/unit/commands/test_userscripts.py
+++ b/tests/unit/commands/test_userscripts.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -65,8 +65,7 @@ def runner(request, runtime_tmpdir):
request.param is userscripts._POSIXUserscriptRunner):
pytest.skip("Requires a POSIX os")
raise utils.Unreachable
- else:
- return request.param()
+ return request.param()
def test_command(qtbot, py_proc, runner):
diff --git a/tests/unit/completion/test_completer.py b/tests/unit/completion/test_completer.py
index 224268c90..d22c3a81e 100644
--- a/tests/unit/completion/test_completer.py
+++ b/tests/unit/completion/test_completer.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2016-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/completion/test_completiondelegate.py b/tests/unit/completion/test_completiondelegate.py
index 7d310380e..77fe05291 100644
--- a/tests/unit/completion/test_completiondelegate.py
+++ b/tests/unit/completion/test_completiondelegate.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2018-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/completion/test_completionmodel.py b/tests/unit/completion/test_completionmodel.py
index 24f5bdf0d..6feb911da 100644
--- a/tests/unit/completion/test_completionmodel.py
+++ b/tests/unit/completion/test_completionmodel.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2017-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
@@ -41,7 +41,7 @@ def test_first_last_item(counts):
cat = mock.Mock(spec=['layoutChanged', 'layoutAboutToBeChanged'])
cat.rowCount = mock.Mock(return_value=c, spec=[])
model.add_category(cat)
- data = [i for i, rowCount in enumerate(counts) if rowCount > 0]
+ data = [i for i, row_count in enumerate(counts) if row_count > 0]
if not data:
# with no items, first and last should be an invalid index
assert not model.first_item().isValid()
diff --git a/tests/unit/completion/test_completionwidget.py b/tests/unit/completion/test_completionwidget.py
index 3d66e1145..0ac91b8a8 100644
--- a/tests/unit/completion/test_completionwidget.py
+++ b/tests/unit/completion/test_completionwidget.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2016-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/completion/test_histcategory.py b/tests/unit/completion/test_histcategory.py
index 02a6cfd1e..b724667df 100644
--- a/tests/unit/completion/test_histcategory.py
+++ b/tests/unit/completion/test_histcategory.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2016-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
@@ -20,11 +20,13 @@
"""Test the web history completion category."""
import datetime
+import logging
import pytest
from qutebrowser.misc import sql
from qutebrowser.completion.models import histcategory
+from qutebrowser.utils import usertypes
@pytest.fixture
@@ -133,6 +135,15 @@ def test_set_pattern_repeated(model_validator, hist):
])
+def test_set_pattern_long(hist, message_mock, caplog):
+ hist.insert({'url': 'example.com/foo', 'title': 'title1', 'last_atime': 1})
+ cat = histcategory.HistoryCategory()
+ with caplog.at_level(logging.ERROR):
+ cat.set_pattern(" ".join(map(str, range(10000))))
+ msg = message_mock.getmsg(usertypes.MessageLevel.error)
+ assert msg.text.startswith("Error with SQL query:")
+
+
@pytest.mark.parametrize('max_items, before, after', [
(-1, [
('a', 'a', '2017-04-16'),
diff --git a/tests/unit/completion/test_listcategory.py b/tests/unit/completion/test_listcategory.py
index 36ea74e41..64b3611e2 100644
--- a/tests/unit/completion/test_listcategory.py
+++ b/tests/unit/completion/test_listcategory.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2017-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/completion/test_models.py b/tests/unit/completion/test_models.py
index 9e75daae8..24e53648e 100644
--- a/tests/unit/completion/test_models.py
+++ b/tests/unit/completion/test_models.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2016-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/components/test_adblock.py b/tests/unit/components/test_adblock.py
index f37b57962..d63c802c8 100644
--- a/tests/unit/components/test_adblock.py
+++ b/tests/unit/components/test_adblock.py
@@ -30,7 +30,7 @@ from PyQt5.QtCore import QUrl
from qutebrowser.components import adblock
from qutebrowser.utils import urlmatch
-from tests.helpers import utils
+from helpers import utils
pytestmark = pytest.mark.usefixtures('qapp')
diff --git a/tests/unit/components/test_misccommands.py b/tests/unit/components/test_misccommands.py
index 95eb0c6e3..09d9d6703 100644
--- a/tests/unit/components/test_misccommands.py
+++ b/tests/unit/components/test_misccommands.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/config/test_config.py b/tests/unit/config/test_config.py
index 946770bf1..9eefedf15 100644
--- a/tests/unit/config/test_config.py
+++ b/tests/unit/config/test_config.py
@@ -1,5 +1,5 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -20,6 +20,7 @@
import types
import unittest.mock
+import functools
import pytest
from PyQt5.QtCore import QObject, QUrl
@@ -701,6 +702,19 @@ class TestConfig:
def test_dump_userconfig_default(self, conf):
assert conf.dump_userconfig() == '<Default configuration>'
+ @pytest.mark.parametrize('case', range(3))
+ def test_get_str_benchmark(self, conf, qtbot, benchmark, case):
+ strings = ['true',
+ ('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML'
+ ', like Gecko) QtWebEngine/5.7.1 Chrome/49.0.2623.111 '
+ 'Safari/537.36'),
+ "a" * 10000]
+ conf.set_obj('content.headers.user_agent', strings[case])
+ benchmark(functools.partial(conf.get, 'content.headers.user_agent'))
+
+ def test_get_dict_benchmark(self, conf, qtbot, benchmark):
+ benchmark(functools.partial(conf.get, 'bindings.default'))
+
class TestContainer:
diff --git a/tests/unit/config/test_configcache.py b/tests/unit/config/test_configcache.py
index 7c0f6012f..d88a71292 100644
--- a/tests/unit/config/test_configcache.py
+++ b/tests/unit/config/test_configcache.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Jay Kamat <jaygkamat@gmail.com>:
+# Copyright 2018-2019 Jay Kamat <jaygkamat@gmail.com>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/config/test_configcommands.py b/tests/unit/config/test_configcommands.py
index bbc3159e6..f11410622 100644
--- a/tests/unit/config/test_configcommands.py
+++ b/tests/unit/config/test_configcommands.py
@@ -1,5 +1,5 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -299,6 +299,12 @@ class TestAdd:
else:
assert yaml_value(name)[-1] == value
+ def test_list_add_invalid_option(self, commands):
+ with pytest.raises(
+ cmdutils.CommandError,
+ match="No option 'nonexistent'"):
+ commands.config_list_add('nonexistent', 'value')
+
def test_list_add_non_list(self, commands):
with pytest.raises(
cmdutils.CommandError,
@@ -342,6 +348,12 @@ class TestAdd:
"overwrite!"):
commands.config_dict_add(name, key, value, replace=False)
+ def test_dict_add_invalid_option(self, commands):
+ with pytest.raises(
+ cmdutils.CommandError,
+ match="No option 'nonexistent'"):
+ commands.config_dict_add('nonexistent', 'key', 'value')
+
def test_dict_add_non_dict(self, commands):
with pytest.raises(
cmdutils.CommandError,
@@ -371,6 +383,12 @@ class TestRemove:
else:
assert value not in yaml_value(name)
+ def test_list_remove_invalid_option(self, commands):
+ with pytest.raises(
+ cmdutils.CommandError,
+ match="No option 'nonexistent'"):
+ commands.config_list_remove('nonexistent', 'value')
+
def test_list_remove_non_list(self, commands):
with pytest.raises(
cmdutils.CommandError,
@@ -396,6 +414,12 @@ class TestRemove:
else:
assert key not in yaml_value(name)
+ def test_dict_remove_invalid_option(self, commands):
+ with pytest.raises(
+ cmdutils.CommandError,
+ match="No option 'nonexistent'"):
+ commands.config_dict_remove('nonexistent', 'key')
+
def test_dict_remove_non_dict(self, commands):
with pytest.raises(
cmdutils.CommandError,
diff --git a/tests/unit/config/test_configdata.py b/tests/unit/config/test_configdata.py
index 61fc66653..a0272fd51 100644
--- a/tests/unit/config/test_configdata.py
+++ b/tests/unit/config/test_configdata.py
@@ -1,5 +1,5 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -167,7 +167,7 @@ class TestParseYamlType:
def _yaml(self, s):
"""Get the type from parsed YAML data."""
- return yaml.load(textwrap.dedent(s))['type']
+ return yaml.safe_load(textwrap.dedent(s))['type']
def test_simple(self):
"""Test type which is only a name."""
@@ -254,7 +254,7 @@ class TestParseYamlBackend:
def _yaml(self, s):
"""Get the type from parsed YAML data."""
- return yaml.load(textwrap.dedent(s))['backend']
+ return yaml.safe_load(textwrap.dedent(s))['backend']
@pytest.mark.parametrize('backend, expected', [
('QtWebKit', [usertypes.Backend.QtWebKit]),
diff --git a/tests/unit/config/test_configexc.py b/tests/unit/config/test_configexc.py
index 98ab19396..f3f86a6dd 100644
--- a/tests/unit/config/test_configexc.py
+++ b/tests/unit/config/test_configexc.py
@@ -1,5 +1,5 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/tests/unit/config/test_configfiles.py b/tests/unit/config/test_configfiles.py
index 79d4b9d89..d05e727dc 100644
--- a/tests/unit/config/test_configfiles.py
+++ b/tests/unit/config/test_configfiles.py
@@ -1,5 +1,5 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -76,14 +76,48 @@ def autoconfig(config_tmpdir):
@pytest.mark.parametrize('old_data, insert, new_data', [
- (None, False, '[general]\n\n[geometry]\n\n'),
- ('[general]\nfooled = true', False, '[general]\n\n[geometry]\n\n'),
- ('[general]\nfoobar = 42', False,
- '[general]\nfoobar = 42\n\n[geometry]\n\n'),
- (None, True, '[general]\nnewval = 23\n\n[geometry]\n\n'),
+ (None,
+ False,
+ '[general]\n'
+ 'qt_version = 5.6.7\n'
+ 'version = 1.2.3\n'
+ '\n'
+ '[geometry]\n'
+ '\n'),
+ ('[general]\n'
+ 'fooled = true',
+ False,
+ '[general]\n'
+ 'qt_version = 5.6.7\n'
+ 'version = 1.2.3\n'
+ '\n'
+ '[geometry]\n'
+ '\n'),
+ ('[general]\n'
+ 'foobar = 42',
+ False,
+ '[general]\n'
+ 'foobar = 42\n'
+ 'qt_version = 5.6.7\n'
+ 'version = 1.2.3\n'
+ '\n'
+ '[geometry]\n'
+ '\n'),
+ (None,
+ True,
+ '[general]\n'
+ 'qt_version = 5.6.7\n'
+ 'version = 1.2.3\n'
+ 'newval = 23\n'
+ '\n'
+ '[geometry]\n'
+ '\n'),
])
-def test_state_config(fake_save_manager, data_tmpdir,
+def test_state_config(fake_save_manager, data_tmpdir, monkeypatch,
old_data, insert, new_data):
+ monkeypatch.setattr(configfiles.qutebrowser, '__version__', '1.2.3')
+ monkeypatch.setattr(configfiles, 'qVersion', lambda: '5.6.7')
+
statefile = data_tmpdir / 'state'
if old_data is not None:
statefile.write_text(old_data, 'utf-8')
@@ -102,6 +136,28 @@ def test_state_config(fake_save_manager, data_tmpdir,
fake_save_manager.add_saveable('state-config', unittest.mock.ANY)
+@pytest.mark.parametrize('old_version, new_version, changed', [
+ (None, '5.12.1', False),
+ ('5.12.1', '5.12.1', False),
+ ('5.12.2', '5.12.1', True),
+ ('5.12.1', '5.12.2', True),
+ ('5.13.0', '5.12.2', True),
+ ('5.12.2', '5.13.0', True),
+])
+def test_qt_version_changed(data_tmpdir, monkeypatch,
+ old_version, new_version, changed):
+ monkeypatch.setattr(configfiles, 'qVersion', lambda: new_version)
+
+ statefile = data_tmpdir / 'state'
+ if old_version is not None:
+ data = ('[general]\n'
+ 'qt_version = {}'.format(old_version))
+ statefile.write_text(data, 'utf-8')
+
+ state = configfiles.StateConfig()
+ assert state.qt_version_changed == changed
+
+
class TestYaml:
pytestmark = pytest.mark.usefixtures('config_tmpdir')
@@ -250,6 +306,19 @@ class TestYaml:
data = autoconfig.read()
assert data['content.webrtc_ip_handling_policy']['global'] == expected
+ @pytest.fixture
+ def migration_test(self, yaml, autoconfig):
+ def run(setting, old, new):
+ autoconfig.write({setting: {'global': old}})
+
+ yaml.load()
+ yaml._save()
+
+ data = autoconfig.read()
+ assert data[setting]['global'] == new
+
+ return run
+
@pytest.mark.parametrize('setting, old, new', [
('tabs.favicons.show', True, 'always'),
('tabs.favicons.show', False, 'never'),
@@ -263,15 +332,25 @@ class TestYaml:
('qt.force_software_rendering', False, 'none'),
('qt.force_software_rendering', 'chromium', 'chromium'),
])
- def test_bool_migrations(self, yaml, autoconfig, setting, old, new):
+ def test_bool_migrations(self, migration_test, setting, old, new):
"""Tests for migration of former boolean settings."""
- autoconfig.write({setting: {'global': old}})
-
- yaml.load()
- yaml._save()
+ migration_test(setting, old, new)
- data = autoconfig.read()
- assert data[setting]['global'] == new
+ @pytest.mark.parametrize('setting', [
+ 'tabs.title.format',
+ 'tabs.title.format_pinned',
+ 'window.title_format'
+ ])
+ @pytest.mark.parametrize('old, new', [
+ ('{title}', '{current_title}'),
+ ('eve{title}duna', 'eve{current_title}duna'),
+ ('eve{{title}}duna', 'eve{{title}}duna'),
+ ('{{title}}', '{{title}}'),
+ ('', ''),
+ (None, None),
+ ])
+ def test_title_format_migrations(self, migration_test, setting, old, new):
+ migration_test(setting, old, new)
def test_renamed_key_unknown_target(self, monkeypatch, yaml,
autoconfig):
diff --git a/tests/unit/config/test_configinit.py b/tests/unit/config/test_configinit.py
index 05e8d4d1e..93ca334ef 100644
--- a/tests/unit/config/test_configinit.py
+++ b/tests/unit/config/test_configinit.py
@@ -1,5 +1,5 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -407,8 +407,8 @@ class TestQtArgs:
assert configinit.qt_args(parsed) == [sys.argv[0], '--foo', '--bar']
@pytest.mark.parametrize('backend, expected', [
- (usertypes.Backend.QtWebEngine, ['--disable-shared-workers']),
- (usertypes.Backend.QtWebKit, []),
+ (usertypes.Backend.QtWebEngine, True),
+ (usertypes.Backend.QtWebKit, False),
])
def test_shared_workers(self, config_stub, monkeypatch, parser,
backend, expected):
@@ -416,6 +416,49 @@ class TestQtArgs:
lambda version, compiled=False: False)
monkeypatch.setattr(configinit.objects, 'backend', backend)
parsed = parser.parse_args([])
+ args = configinit.qt_args(parsed)
+ assert ('--disable-shared-workers' in args) == expected
+
+ @pytest.mark.parametrize('backend, version_check, debug_flag, expected', [
+ # Qt >= 5.12.3: Enable with -D stack, do nothing without it.
+ (usertypes.Backend.QtWebEngine, True, True, True),
+ (usertypes.Backend.QtWebEngine, True, False, None),
+ # Qt < 5.12.3: Do nothing with -D stack, disable without it.
+ (usertypes.Backend.QtWebEngine, False, True, None),
+ (usertypes.Backend.QtWebEngine, False, False, False),
+ # QtWebKit: Do nothing
+ (usertypes.Backend.QtWebKit, True, True, None),
+ (usertypes.Backend.QtWebKit, True, False, None),
+ (usertypes.Backend.QtWebKit, False, True, None),
+ (usertypes.Backend.QtWebKit, False, False, None),
+ ])
+ def test_in_process_stack_traces(self, monkeypatch, parser, backend,
+ version_check, debug_flag, expected):
+ monkeypatch.setattr(configinit.qtutils, 'version_check',
+ lambda version, compiled=False: version_check)
+ monkeypatch.setattr(configinit.objects, 'backend', backend)
+ parsed = parser.parse_args(['--debug-flag', 'stack'] if debug_flag
+ else [])
+ args = configinit.qt_args(parsed)
+
+ if expected is None:
+ assert '--disable-in-process-stack-traces' not in args
+ assert '--enable-in-process-stack-traces' not in args
+ elif expected:
+ assert '--disable-in-process-stack-traces' not in args
+ assert '--enable-in-process-stack-traces' in args
+ else:
+ assert '--disable-in-process-stack-traces' in args
+ assert '--enable-in-process-stack-traces' not in args
+
+ @pytest.mark.parametrize('flags, expected', [
+ ([], []),
+ (['--debug-flag', 'chromium'], ['--enable-logging', '--v=1']),
+ ])
+ def test_chromium_debug(self, monkeypatch, parser, flags, expected):
+ monkeypatch.setattr(configinit.objects, 'backend',
+ usertypes.Backend.QtWebEngine)
+ parsed = parser.parse_args(flags)
assert configinit.qt_args(parsed) == [sys.argv[0]] + expected
def test_disable_gpu(self, config_stub, monkeypatch, parser):
diff --git a/tests/unit/config/test_configtypes.py b/tests/unit/config/test_configtypes.py
index b0b85d997..8d6e7aa29 100644
--- a/tests/unit/config/test_configtypes.py
+++ b/tests/unit/config/test_configtypes.py
@@ -1,5 +1,5 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -38,7 +38,7 @@ from qutebrowser.config import configtypes, configexc, configutils
from qutebrowser.utils import debug, utils, qtutils, urlmatch
from qutebrowser.browser.network import pac
from qutebrowser.keyinput import keyutils
-from tests.helpers import utils as testutils
+from helpers import utils as testutils
class Font(QFont):
@@ -1250,34 +1250,32 @@ class TestQtColor:
('rgba(255, 255, 255, 1.0)', QColor.fromRgb(255, 255, 255, 255)),
- # this should be (36, 25, 25) as hue goes to 359
- # however this is consistent with Qt's CSS parser
- # https://bugreports.qt.io/browse/QTBUG-70897
- ('hsv(10%,10%,10%)', QColor.fromHsv(25, 25, 25)),
- ('hsva(10%,20%,30%,40%)', QColor.fromHsv(25, 51, 76, 102)),
+ ('hsv(10%,10%,10%)', QColor.fromHsv(35, 25, 25)),
+ ('hsva(10%,20%,30%,40%)', QColor.fromHsv(35, 51, 76, 102)),
])
def test_valid(self, klass, val, expected):
assert klass().to_py(val) == expected
- @pytest.mark.parametrize('val', [
- '#00000G',
- '#123456789ABCD',
- '#12',
- 'foobar',
- '42',
- 'foo(1, 2, 3)',
- 'rgb(1, 2, 3',
- 'rgb)',
- 'rgb(1, 2, 3))',
- 'rgb((1, 2, 3)',
- 'rgb()',
- 'rgb(1, 2, 3, 4)',
- 'rgba(1, 2, 3)',
- 'rgb(10%%, 0, 0)',
- ])
- def test_invalid(self, klass, val):
- with pytest.raises(configexc.ValidationError):
+ @pytest.mark.parametrize('val,msg', [
+ ('#00000G', 'must be a valid color'),
+ ('#123456789ABCD', 'must be a valid color'),
+ ('#12', 'must be a valid color'),
+ ('foobar', 'must be a valid color'),
+ ('42', 'must be a valid color'),
+ ('foo(1, 2, 3)', "foo not in ['hsv', 'hsva', 'rgb', 'rgba']"),
+ ('rgb(1, 2, 3', 'must be a valid color'),
+ ('rgb)', 'must be a valid color'),
+ ('rgb(1, 2, 3))', 'must be a valid color value'),
+ ('rgb((1, 2, 3)', 'must be a valid color value'),
+ ('rgb()', 'expected 3 values for rgb'),
+ ('rgb(1, 2, 3, 4)', 'expected 3 values for rgb'),
+ ('rgba(1, 2, 3)', 'expected 4 values for rgba'),
+ ('rgb(10%%, 0, 0)', 'must be a valid color value'),
+ ])
+ def test_invalid(self, klass, val, msg):
+ with pytest.raises(configexc.ValidationError) as excinfo:
klass().to_py(val)
+ assert str(excinfo.value).endswith(msg)
class TestQssColor:
@@ -1441,8 +1439,8 @@ class TestFont:
expected = '10pt Terminus'
elif klass is configtypes.QtFont:
desc = FontDesc(QFont.StyleNormal, QFont.Normal, 10, None,
- 'Terminus'),
- expected = Font.fromdesc(*desc)
+ 'Terminus')
+ expected = Font.fromdesc(desc)
assert klass().to_py('10pt monospace') == expected
@@ -2086,21 +2084,6 @@ class TestConfirmQuit:
klass().to_py(val)
-class TestTimestampTemplate:
-
- @pytest.fixture
- def klass(self):
- return configtypes.TimestampTemplate
-
- @pytest.mark.parametrize('val', ['foobar', '%H:%M', 'foo %H bar %M'])
- def test_to_py_valid(self, klass, val):
- assert klass().to_py(val) == val
-
- def test_to_py_invalid(self, klass):
- with pytest.raises(configexc.ValidationError):
- klass().to_py('%')
-
-
class TestKey:
@pytest.fixture
diff --git a/tests/unit/config/test_configutils.py b/tests/unit/config/test_configutils.py
index e8a7bfb38..5fad71110 100644
--- a/tests/unit/config/test_configutils.py
+++ b/tests/unit/config/test_configutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/extensions/test_loader.py b/tests/unit/extensions/test_loader.py
index 5265c7cdf..2b7c65238 100644
--- a/tests/unit/extensions/test_loader.py
+++ b/tests/unit/extensions/test_loader.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/javascript/conftest.py b/tests/unit/javascript/conftest.py
index 486839237..c9c14546f 100644
--- a/tests/unit/javascript/conftest.py
+++ b/tests/unit/javascript/conftest.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -27,7 +27,7 @@ import jinja2
from PyQt5.QtCore import QUrl
-from qutebrowser.utils import utils
+import qutebrowser
class JSTester:
@@ -90,15 +90,16 @@ class JSTester:
if not force:
assert blocker.args == [True]
- def run_file(self, filename: str, expected=None) -> None:
+ def run_file(self, path: str, expected=None) -> None:
"""Run a javascript file.
Args:
- filename: The javascript filename, relative to
- qutebrowser/javascript.
+ path: The path to the JS file, relative to the qutebrowser package.
expected: The value expected return from the javascript execution
"""
- source = utils.read_file(os.path.join('javascript', filename))
+ base_path = os.path.dirname(os.path.abspath(qutebrowser.__file__))
+ with open(os.path.join(base_path, path), 'r', encoding='utf-8') as f:
+ source = f.read()
self.run(source, expected)
def run(self, source: str, expected, world=None) -> None:
diff --git a/tests/unit/javascript/position_caret/test_position_caret.py b/tests/unit/javascript/position_caret/test_position_caret.py
index 9aeaca345..6b50e5f62 100644
--- a/tests/unit/javascript/position_caret/test_position_caret.py
+++ b/tests/unit/javascript/position_caret/test_position_caret.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -50,7 +50,7 @@ class CaretTester:
def check(self):
"""Check whether the caret is before the MARKER text."""
- self.js.run_file('position_caret.js')
+ self.js.run_file('javascript/position_caret.js')
self.js.tab.caret.toggle_selection()
self.js.tab.caret.move_to_next_word()
diff --git a/tests/unit/javascript/stylesheet/test_stylesheet.py b/tests/unit/javascript/stylesheet/test_stylesheet.py
index 145e8ee5e..768ffaeb9 100644
--- a/tests/unit/javascript/stylesheet/test_stylesheet.py
+++ b/tests/unit/javascript/stylesheet/test_stylesheet.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Jay Kamat
+# Copyright 2017-2019 Jay Kamat <jaygkamat@gmail.com>
#
# This file is part of qutebrowser.
#
@@ -25,7 +25,7 @@ import pytest
QtWebEngineWidgets = pytest.importorskip("PyQt5.QtWebEngineWidgets")
QWebEngineProfile = QtWebEngineWidgets.QWebEngineProfile
-from qutebrowser.utils import javascript, qtutils
+from qutebrowser.utils import javascript
DEFAULT_BODY_BG = "rgba(0, 0, 0, 0)"
@@ -128,11 +128,9 @@ def test_set_error(stylesheet_tester, config_stub):
stylesheet_tester.check_set(GREEN_BODY_BG)
-@pytest.mark.skip(qtutils.version_check('5.12', compiled=False),
- reason='Broken with Qt 5.12')
def test_appendchild(stylesheet_tester):
stylesheet_tester.js.load('stylesheet/simple.html')
stylesheet_tester.init_stylesheet()
- js_test_file_path = ('../../tests/unit/javascript/stylesheet/'
+ js_test_file_path = ('../tests/unit/javascript/stylesheet/'
'test_appendchild.js')
stylesheet_tester.js.run_file(js_test_file_path, {})
diff --git a/tests/unit/javascript/test_greasemonkey.py b/tests/unit/javascript/test_greasemonkey.py
index f5f3d7972..12244db4e 100644
--- a/tests/unit/javascript/test_greasemonkey.py
+++ b/tests/unit/javascript/test_greasemonkey.py
@@ -1,5 +1,5 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
@@ -25,6 +25,7 @@ import pytest
import py.path # pylint: disable=no-name-in-module
from PyQt5.QtCore import QUrl
+from qutebrowser.utils import usertypes
from qutebrowser.browser import greasemonkey
test_gm_script = r"""
@@ -165,6 +166,56 @@ def test_utf8_bom():
assert '// ==UserScript==' in script.code().splitlines()
+class TestForceDocumentEnd:
+
+ @pytest.fixture
+ def patch(self, monkeypatch):
+ def _patch(*, backend, qt_512):
+ monkeypatch.setattr(greasemonkey.objects, 'backend', backend)
+ monkeypatch.setattr(greasemonkey.qtutils, 'version_check',
+ lambda version, exact=False, compiled=True:
+ qt_512)
+ return _patch
+
+ def _get_script(self, *, namespace, name):
+ source = textwrap.dedent("""
+ // ==UserScript==
+ // @namespace {}
+ // @name {}
+ // ==/UserScript==
+ """.format(namespace, name))
+ _save_script(source, 'force.user.js')
+
+ gm_manager = greasemonkey.GreasemonkeyManager()
+
+ scripts = gm_manager.all_scripts()
+ assert len(scripts) == 1
+ return scripts[0]
+
+ @pytest.mark.parametrize('backend, qt_512', [
+ (usertypes.Backend.QtWebKit, True),
+ (usertypes.Backend.QtWebEngine, False),
+ ])
+ def test_not_applicable(self, patch, backend, qt_512):
+ """Test backend/Qt version combinations which don't need a fix."""
+ patch(backend=backend, qt_512=qt_512)
+ script = self._get_script(namespace='https://github.com/ParticleCore',
+ name='Iridium')
+ assert not script.needs_document_end_workaround()
+
+ @pytest.mark.parametrize('namespace, name, force', [
+ ('http://userstyles.org', 'foobar', True),
+ ('https://github.com/ParticleCore', 'Iridium', True),
+ ('https://github.com/ParticleCore', 'Foo', False),
+ ('https://example.org', 'Iridium', False),
+ ])
+ def test_matching(self, patch, namespace, name, force):
+ """Test matching based on namespace/name."""
+ patch(backend=usertypes.Backend.QtWebEngine, qt_512=True)
+ script = self._get_script(namespace=namespace, name=name)
+ assert script.needs_document_end_workaround() == force
+
+
def test_required_scripts_are_included(download_stub, tmpdir):
test_require_script = textwrap.dedent("""
// ==UserScript==
diff --git a/tests/unit/javascript/test_js_execution.py b/tests/unit/javascript/test_js_execution.py
index 1a0ac8dc5..4f37ec473 100644
--- a/tests/unit/javascript/test_js_execution.py
+++ b/tests/unit/javascript/test_js_execution.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/keyinput/conftest.py b/tests/unit/keyinput/conftest.py
index 045b62336..4ce6f1e8f 100644
--- a/tests/unit/keyinput/conftest.py
+++ b/tests/unit/keyinput/conftest.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>:
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/keyinput/key_data.py b/tests/unit/keyinput/key_data.py
index 48b5c8c56..ab12f2d78 100644
--- a/tests/unit/keyinput/key_data.py
+++ b/tests/unit/keyinput/key_data.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/keyinput/test_basekeyparser.py b/tests/unit/keyinput/test_basekeyparser.py
index 764c83e1f..133da3090 100644
--- a/tests/unit/keyinput/test_basekeyparser.py
+++ b/tests/unit/keyinput/test_basekeyparser.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>:
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>:
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/keyinput/test_keyutils.py b/tests/unit/keyinput/test_keyutils.py
index d6e7bce34..8156c89ae 100644
--- a/tests/unit/keyinput/test_keyutils.py
+++ b/tests/unit/keyinput/test_keyutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -26,7 +26,7 @@ from PyQt5.QtCore import Qt, QEvent, pyqtSignal
from PyQt5.QtGui import QKeyEvent, QKeySequence
from PyQt5.QtWidgets import QWidget
-from tests.unit.keyinput import key_data
+from unit.keyinput import key_data
from qutebrowser.keyinput import keyutils
from qutebrowser.utils import utils
diff --git a/tests/unit/keyinput/test_modeman.py b/tests/unit/keyinput/test_modeman.py
index 25b3fc776..8171c0518 100644
--- a/tests/unit/keyinput/test_modeman.py
+++ b/tests/unit/keyinput/test_modeman.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/keyinput/test_modeparsers.py b/tests/unit/keyinput/test_modeparsers.py
index 72f32af32..436843960 100644
--- a/tests/unit/keyinput/test_modeparsers.py
+++ b/tests/unit/keyinput/test_modeparsers.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>:
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/mainwindow/statusbar/test_backforward.py b/tests/unit/mainwindow/statusbar/test_backforward.py
index 11e3da616..3a1f43a6a 100644
--- a/tests/unit/mainwindow/statusbar/test_backforward.py
+++ b/tests/unit/mainwindow/statusbar/test_backforward.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/mainwindow/statusbar/test_percentage.py b/tests/unit/mainwindow/statusbar/test_percentage.py
index c7b5b9fe2..1488ab827 100644
--- a/tests/unit/mainwindow/statusbar/test_percentage.py
+++ b/tests/unit/mainwindow/statusbar/test_percentage.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/mainwindow/statusbar/test_progress.py b/tests/unit/mainwindow/statusbar/test_progress.py
index 5b01aebbf..151ec99ca 100644
--- a/tests/unit/mainwindow/statusbar/test_progress.py
+++ b/tests/unit/mainwindow/statusbar/test_progress.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/mainwindow/statusbar/test_tabindex.py b/tests/unit/mainwindow/statusbar/test_tabindex.py
index 352089099..4f9003885 100644
--- a/tests/unit/mainwindow/statusbar/test_tabindex.py
+++ b/tests/unit/mainwindow/statusbar/test_tabindex.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/mainwindow/statusbar/test_textbase.py b/tests/unit/mainwindow/statusbar/test_textbase.py
index 7ebc4e327..7e66c0197 100644
--- a/tests/unit/mainwindow/statusbar/test_textbase.py
+++ b/tests/unit/mainwindow/statusbar/test_textbase.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -83,7 +83,7 @@ def test_text_elide_none(mocker, qtbot):
'fontMetrics')
label._update_elided_text(20)
- assert not label.fontMetrics.called # pylint: disable=no-member
+ assert not label.fontMetrics.called
def test_unset_text(qtbot):
diff --git a/tests/unit/mainwindow/statusbar/test_url.py b/tests/unit/mainwindow/statusbar/test_url.py
index 7d06cb774..5c3a65437 100644
--- a/tests/unit/mainwindow/statusbar/test_url.py
+++ b/tests/unit/mainwindow/statusbar/test_url.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Clayton Craft (craftyguy) <craftyguy@gmail.com>
+# Copyright 2016-2019 Clayton Craft (craftyguy) <craftyguy@gmail.com>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/mainwindow/test_messageview.py b/tests/unit/mainwindow/test_messageview.py
index cd7c40bc3..fabbdf22a 100644
--- a/tests/unit/mainwindow/test_messageview.py
+++ b/tests/unit/mainwindow/test_messageview.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/mainwindow/test_prompt.py b/tests/unit/mainwindow/test_prompt.py
index 7c8d2b0ad..f20668ed4 100644
--- a/tests/unit/mainwindow/test_prompt.py
+++ b/tests/unit/mainwindow/test_prompt.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/mainwindow/test_tabwidget.py b/tests/unit/mainwindow/test_tabwidget.py
index e2bcf9b29..a16bda246 100644
--- a/tests/unit/mainwindow/test_tabwidget.py
+++ b/tests/unit/mainwindow/test_tabwidget.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Daniel Schadt
#
# This file is part of qutebrowser.
@@ -84,7 +85,7 @@ class TestTabWidget:
widget.addTab(fake_web_tab(), 'foobar' + str(i))
# Set pinned title format longer than unpinned
- config_stub.val.tabs.title.format_pinned = "_" * 20
+ config_stub.val.tabs.title.format_pinned = "_" * 10
config_stub.val.tabs.title.format = "_" * 2
config_stub.val.tabs.pinned.shrink = shrink_pinned
if vertical:
diff --git a/tests/unit/misc/test_autoupdate.py b/tests/unit/misc/test_autoupdate.py
index d4a69a115..2c56e23ce 100644
--- a/tests/unit/misc/test_autoupdate.py
+++ b/tests/unit/misc/test_autoupdate.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Alexander Cogneau (acogneau) <alexander.cogneau@gmail.com>:
#
# This file is part of qutebrowser.
diff --git a/tests/unit/misc/test_checkpyver.py b/tests/unit/misc/test_checkpyver.py
index a02e2f8e0..0b1b7ef94 100644
--- a/tests/unit/misc/test_checkpyver.py
+++ b/tests/unit/misc/test_checkpyver.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# This file is part of qutebrowser.
diff --git a/tests/unit/misc/test_cmdhistory.py b/tests/unit/misc/test_cmdhistory.py
index 8204feb0e..eb6ce5215 100644
--- a/tests/unit/misc/test_cmdhistory.py
+++ b/tests/unit/misc/test_cmdhistory.py
@@ -1,7 +1,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2015-2019 Florian Bruhin (The-Compiler) <me@the-compiler.org>
# Copyright 2015-2018 Alexander Cogneau (acogneau) <alexander.cogneau@gmail.com>
-# Copyright 2015-2018 Florian Bruhin (The-Compiler) <me@the-compiler.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_crashdialog.py b/tests/unit/misc/test_crashdialog.py
index a34192b88..bea09c4e1 100644
--- a/tests/unit/misc/test_crashdialog.py
+++ b/tests/unit/misc/test_crashdialog.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_earlyinit.py b/tests/unit/misc/test_earlyinit.py
index 0882e610f..2cb1d1bcd 100644
--- a/tests/unit/misc/test_earlyinit.py
+++ b/tests/unit/misc/test_earlyinit.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The-Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The-Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_editor.py b/tests/unit/misc/test_editor.py
index 7c13691e7..84879f07e 100644
--- a/tests/unit/misc/test_editor.py
+++ b/tests/unit/misc/test_editor.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_guiprocess.py b/tests/unit/misc/test_guiprocess.py
index cfedab9fe..bb14a0cf2 100644
--- a/tests/unit/misc/test_guiprocess.py
+++ b/tests/unit/misc/test_guiprocess.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -22,7 +22,7 @@
import logging
import pytest
-from PyQt5.QtCore import QProcess, QIODevice
+from PyQt5.QtCore import QProcess
from qutebrowser.misc import guiprocess
from qutebrowser.utils import usertypes
@@ -59,8 +59,10 @@ def test_start(proc, qtbot, message_mock, py_proc):
argv = py_proc("import sys; print('test'); sys.exit(0)")
proc.start(*argv)
+ expected = proc._spawn_format(exitinfo="Testprocess exited successfully.",
+ stdout="test", stderr="")
assert not message_mock.messages
- assert qutescheme.spawn_output == proc._spawn_format(stdout="test")
+ assert qutescheme.spawn_output == expected
def test_start_verbose(proc, qtbot, message_mock, py_proc):
@@ -72,12 +74,14 @@ def test_start_verbose(proc, qtbot, message_mock, py_proc):
argv = py_proc("import sys; print('test'); sys.exit(0)")
proc.start(*argv)
+ expected = proc._spawn_format(exitinfo="Testprocess exited successfully.",
+ stdout="test", stderr="")
msgs = message_mock.messages
assert msgs[0].level == usertypes.MessageLevel.info
assert msgs[1].level == usertypes.MessageLevel.info
assert msgs[0].text.startswith("Executing:")
assert msgs[1].text == "Testprocess exited successfully."
- assert qutescheme.spawn_output == proc._spawn_format(stdout="test")
+ assert qutescheme.spawn_output == expected
def test_start_env(monkeypatch, qtbot, py_proc):
@@ -104,17 +108,6 @@ def test_start_env(monkeypatch, qtbot, py_proc):
assert 'QUTEBROWSER_TEST_2' in data
-@pytest.mark.qt_log_ignore('QIODevice::read.*: WriteOnly device')
-def test_start_mode(proc, qtbot, py_proc):
- """Test simply starting a process with mode parameter."""
- with qtbot.waitSignals([proc.started, proc.finished], timeout=10000,
- order='strict'):
- argv = py_proc("import sys; print('test'); sys.exit(0)")
- proc.start(*argv, mode=QIODevice.NotOpen)
-
- assert not proc._proc.readAll()
-
-
def test_start_detached(fake_proc):
"""Test starting a detached process."""
argv = ['foo', 'bar']
@@ -127,12 +120,11 @@ def test_start_detached_error(fake_proc, message_mock, caplog):
"""Test starting a detached process with ok=False."""
argv = ['foo', 'bar']
fake_proc._proc.startDetached.return_value = (False, 0)
- fake_proc._proc.error.return_value = QProcess.FailedToStart
+
with caplog.at_level(logging.ERROR):
fake_proc.start_detached(*argv)
msg = message_mock.getmsg(usertypes.MessageLevel.error)
- expected = ("Error while spawning testprocess: The process failed to "
- "start.")
+ expected = "Error while spawning testprocess"
assert msg.text == expected
@@ -184,9 +176,7 @@ def test_error(qtbot, proc, caplog, message_mock):
proc.start('this_does_not_exist_either', [])
msg = message_mock.getmsg(usertypes.MessageLevel.error)
- expected_msg = ("Error while spawning testprocess: The process failed to "
- "start.")
- assert msg.text == expected_msg
+ assert msg.text.startswith("Error while spawning testprocess:")
def test_exit_unsuccessful(qtbot, proc, message_mock, py_proc, caplog):
@@ -238,5 +228,7 @@ def test_stdout_not_decodable(proc, qtbot, message_mock, py_proc):
sys.exit(0)
""")
proc.start(*argv)
+ expected = proc._spawn_format(exitinfo="Testprocess exited successfully.",
+ stdout="A\ufffdB", stderr="")
assert not message_mock.messages
- assert qutescheme.spawn_output == proc._spawn_format(stdout="A\ufffdB")
+ assert qutescheme.spawn_output == expected
diff --git a/tests/unit/misc/test_ipc.py b/tests/unit/misc/test_ipc.py
index 29ca0ff9d..78c8b9764 100644
--- a/tests/unit/misc/test_ipc.py
+++ b/tests/unit/misc/test_ipc.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -34,7 +34,7 @@ from PyQt5.QtTest import QSignalSpy
import qutebrowser
from qutebrowser.misc import ipc
-from qutebrowser.utils import standarddir, utils, qtutils
+from qutebrowser.utils import standarddir, utils
from helpers import stubs
@@ -98,7 +98,7 @@ class FakeSocket(QObject):
_connect_successful: The value returned for waitForConnected().
"""
- readyRead = pyqtSignal()
+ readyRead = pyqtSignal() # noqa: N815
disconnected = pyqtSignal()
def __init__(self, *, error=QLocalSocket.UnknownSocketError, state=None,
@@ -177,11 +177,6 @@ def md5(inp):
class TestSocketName:
- POSIX_TESTS = [
- (None, 'ipc-{}'.format(md5('testusername'))),
- ('/x', 'ipc-{}'.format(md5('testusername-/x'))),
- ]
-
WINDOWS_TESTS = [
(None, 'qutebrowser-testusername'),
('/x', 'qutebrowser-testusername-{}'.format(md5('/x'))),
@@ -203,7 +198,10 @@ class TestSocketName:
assert socketname == expected
@pytest.mark.mac
- @pytest.mark.parametrize('basedir, expected', POSIX_TESTS)
+ @pytest.mark.parametrize('basedir, expected', [
+ (None, 'i-{}'.format(md5('testusername'))),
+ ('/x', 'i-{}'.format(md5('testusername-/x'))),
+ ])
def test_mac(self, basedir, expected):
socketname = ipc._get_socketname(basedir)
parts = socketname.split(os.sep)
@@ -211,7 +209,10 @@ class TestSocketName:
assert parts[-1] == expected
@pytest.mark.linux
- @pytest.mark.parametrize('basedir, expected', POSIX_TESTS)
+ @pytest.mark.parametrize('basedir, expected', [
+ (None, 'ipc-{}'.format(md5('testusername'))),
+ ('/x', 'ipc-{}'.format(md5('testusername-/x'))),
+ ])
def test_linux(self, basedir, fake_runtime_dir, expected):
socketname = ipc._get_socketname(basedir)
expected_path = str(fake_runtime_dir / 'qutebrowser' / expected)
@@ -630,8 +631,6 @@ class TestSendOrListen:
assert ret_client is None
@pytest.mark.posix(reason="Unneeded on Windows")
- @pytest.mark.xfail(qtutils.version_check('5.12', compiled=False) and
- utils.is_mac, reason="Broken, see #4471")
def test_correct_socket_name(self, args):
server = ipc.send_or_listen(args)
expected_dir = ipc._get_socketname(args.basedir)
diff --git a/tests/unit/misc/test_keyhints.py b/tests/unit/misc/test_keyhints.py
index 9af30fd16..5f5eff844 100644
--- a/tests/unit/misc/test_keyhints.py
+++ b/tests/unit/misc/test_keyhints.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2016-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
@@ -214,4 +214,5 @@ def test_delay(qtbot, stubs, monkeypatch, config_stub, key_config_stub):
keyhint = KeyHintView(0, None)
keyhint.update_keyhint('normal', 'a')
+ assert timer.isSingleShot()
assert timer.interval() == interval
diff --git a/tests/unit/misc/test_lineparser.py b/tests/unit/misc/test_lineparser.py
index 10575e676..0af165a70 100644
--- a/tests/unit/misc/test_lineparser.py
+++ b/tests/unit/misc/test_lineparser.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_miscwidgets.py b/tests/unit/misc/test_miscwidgets.py
index d5c1183a5..59de8bdb3 100644
--- a/tests/unit/misc/test_miscwidgets.py
+++ b/tests/unit/misc/test_miscwidgets.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_msgbox.py b/tests/unit/misc/test_msgbox.py
index e2fd7bffe..c402ecf6c 100644
--- a/tests/unit/misc/test_msgbox.py
+++ b/tests/unit/misc/test_msgbox.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# This file is part of qutebrowser.
diff --git a/tests/unit/misc/test_objects.py b/tests/unit/misc/test_objects.py
index 8d3c934c8..0ab46ed3b 100644
--- a/tests/unit/misc/test_objects.py
+++ b/tests/unit/misc/test_objects.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_pastebin.py b/tests/unit/misc/test_pastebin.py
index cbd6f4c3e..ea0ebf028 100644
--- a/tests/unit/misc/test_pastebin.py
+++ b/tests/unit/misc/test_pastebin.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2016-2019 Florian Bruhin (The-Compiler) <me@the-compiler.org>
# Copyright 2016-2018 Anna Kobak (avk) <awerk@onet.eu>:
#
# This file is part of qutebrowser.
diff --git a/tests/unit/misc/test_readline.py b/tests/unit/misc/test_readline.py
index 6aedc0951..687b97b03 100644
--- a/tests/unit/misc/test_readline.py
+++ b/tests/unit/misc/test_readline.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_sessions.py b/tests/unit/misc/test_sessions.py
index e2676b4e7..8bb8155c6 100644
--- a/tests/unit/misc/test_sessions.py
+++ b/tests/unit/misc/test_sessions.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_split.py b/tests/unit/misc/test_split.py
index d6d388f8b..352dd085d 100644
--- a/tests/unit/misc/test_split.py
+++ b/tests/unit/misc/test_split.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_split_hypothesis.py b/tests/unit/misc/test_split_hypothesis.py
index c8d6d5147..e6de1b740 100644
--- a/tests/unit/misc/test_split_hypothesis.py
+++ b/tests/unit/misc/test_split_hypothesis.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/misc/test_sql.py b/tests/unit/misc/test_sql.py
index dff6144cc..f354ea279 100644
--- a/tests/unit/misc/test_sql.py
+++ b/tests/unit/misc/test_sql.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
+# Copyright 2016-2019 Ryan Roden-Corrent (rcorre) <ryan@rcorre.net>
#
# This file is part of qutebrowser.
#
@@ -29,7 +29,7 @@ from qutebrowser.misc import sql
pytestmark = pytest.mark.usefixtures('init_sql')
-@pytest.mark.parametrize('klass', [sql.SqlEnvironmentError, sql.SqlBugError])
+@pytest.mark.parametrize('klass', [sql.KnownError, sql.BugError])
def test_sqlerror(klass):
text = "Hello World"
err = klass(text)
@@ -40,10 +40,10 @@ def test_sqlerror(klass):
class TestSqlError:
@pytest.mark.parametrize('error_code, exception', [
- (sql.SqliteErrorCode.BUSY, sql.SqlEnvironmentError),
- (sql.SqliteErrorCode.CONSTRAINT, sql.SqlBugError),
+ (sql.SqliteErrorCode.BUSY, sql.KnownError),
+ (sql.SqliteErrorCode.CONSTRAINT, sql.BugError),
])
- def test_environmental(self, error_code, exception):
+ def test_known(self, error_code, exception):
sql_err = QSqlError("driver text", "db text", QSqlError.UnknownError,
error_code)
with pytest.raises(exception):
@@ -59,13 +59,13 @@ class TestSqlError:
"out of memory",
QSqlError.UnknownError,
sql.SqliteErrorCode.UNKNOWN)
- with pytest.raises(sql.SqlEnvironmentError):
+ with pytest.raises(sql.KnownError):
sql.raise_sqlite_error("Message", sql_err)
def test_logging(self, caplog):
sql_err = QSqlError("driver text", "db text", QSqlError.UnknownError,
'23')
- with pytest.raises(sql.SqlBugError):
+ with pytest.raises(sql.BugError):
sql.raise_sqlite_error("Message", sql_err)
expected = ['SQL error:',
@@ -76,8 +76,7 @@ class TestSqlError:
assert caplog.messages == expected
- @pytest.mark.parametrize('klass',
- [sql.SqlEnvironmentError, sql.SqlBugError])
+ @pytest.mark.parametrize('klass', [sql.KnownError, sql.BugError])
def test_text(self, klass):
sql_err = QSqlError("driver text", "db text")
err = klass("Message", sql_err)
@@ -107,7 +106,7 @@ def test_insert_replace(qtbot):
table.insert({'name': 'one', 'val': 11, 'lucky': True}, replace=True)
assert list(table) == [('one', 11, True)]
- with pytest.raises(sql.SqlBugError):
+ with pytest.raises(sql.BugError):
table.insert({'name': 'one', 'val': 11, 'lucky': True}, replace=False)
@@ -143,7 +142,7 @@ def test_insert_batch_replace(qtbot):
('one', 11, True),
('nine', 19, True)]
- with pytest.raises(sql.SqlBugError):
+ with pytest.raises(sql.BugError):
table.insert_batch({'name': ['one', 'nine'],
'val': [11, 19],
'lucky': [True, True]})
@@ -240,7 +239,7 @@ def test_version():
class TestSqlQuery:
def test_prepare_error(self):
- with pytest.raises(sql.SqlBugError) as excinfo:
+ with pytest.raises(sql.BugError) as excinfo:
sql.Query('invalid')
expected = ('Failed to prepare query "invalid": "near "invalid": '
@@ -254,7 +253,7 @@ class TestSqlQuery:
def test_iter_inactive(self):
q = sql.Query('SELECT 0')
- with pytest.raises(sql.SqlBugError,
+ with pytest.raises(sql.BugError,
match='Cannot iterate inactive query'):
next(iter(q))
@@ -283,7 +282,7 @@ class TestSqlQuery:
def test_run_missing_binding(self):
q = sql.Query('SELECT :answer')
- with pytest.raises(sql.SqlBugError, match='Missing bound values!'):
+ with pytest.raises(sql.BugError, match='Missing bound values!'):
q.run()
def test_run_batch(self):
@@ -293,13 +292,13 @@ class TestSqlQuery:
def test_run_batch_missing_binding(self):
q = sql.Query('SELECT :answer')
- with pytest.raises(sql.SqlBugError, match='Missing bound values!'):
+ with pytest.raises(sql.BugError, match='Missing bound values!'):
q.run_batch(values={})
def test_value_missing(self):
q = sql.Query('SELECT 0 WHERE 0')
q.run()
- with pytest.raises(sql.SqlBugError,
+ with pytest.raises(sql.BugError,
match='No result for single-result query'):
q.value()
diff --git a/tests/unit/misc/test_utilcmds.py b/tests/unit/misc/test_utilcmds.py
index 1b71d5ddc..f5bd2747c 100644
--- a/tests/unit/misc/test_utilcmds.py
+++ b/tests/unit/misc/test_utilcmds.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -89,4 +89,4 @@ def tabbed_browser(stubs, win_registry):
def test_version(tabbed_browser, qapp):
utilcmds.version(win_id=0)
- assert tabbed_browser.loaded_url == QUrl('qute://version')
+ assert tabbed_browser.loaded_url == QUrl('qute://version/')
diff --git a/tests/unit/scripts/test_check_coverage.py b/tests/unit/scripts/test_check_coverage.py
index 026479e38..86e4ece4e 100644
--- a/tests/unit/scripts/test_check_coverage.py
+++ b/tests/unit/scripts/test_check_coverage.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/tests/unit/scripts/test_dictcli.py b/tests/unit/scripts/test_dictcli.py
index 4df65ead6..1b6a2b4ff 100644
--- a/tests/unit/scripts/test_dictcli.py
+++ b/tests/unit/scripts/test_dictcli.py
@@ -1,5 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+# Copyright 2017-2019 Florian Bruhin (The-Compiler) <me@the-compiler.org>
# Copyright 2017-2018 Michal Siedlaczek <michal.siedlaczek@gmail.com>
# This file is part of qutebrowser.
diff --git a/tests/unit/scripts/test_importer.py b/tests/unit/scripts/test_importer.py
index ada0d886c..eeeb7d084 100644
--- a/tests/unit/scripts/test_importer.py
+++ b/tests/unit/scripts/test_importer.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2017-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/tests/unit/scripts/test_run_vulture.py b/tests/unit/scripts/test_run_vulture.py
index c33a7f616..111785fc9 100644
--- a/tests/unit/scripts/test_run_vulture.py
+++ b/tests/unit/scripts/test_run_vulture.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# This file is part of qutebrowser.
#
diff --git a/tests/unit/test_app.py b/tests/unit/test_app.py
index 3d7555bc4..e57fe2b97 100644
--- a/tests/unit/test_app.py
+++ b/tests/unit/test_app.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -30,7 +30,7 @@ def test_on_focus_changed_issue1484(monkeypatch, qapp, caplog):
For some reason, Qt sometimes calls on_focus_changed() with a QBuffer as
argument. Let's make sure we handle that gracefully.
"""
- monkeypatch.setattr(app, 'qApp', qapp)
+ monkeypatch.setattr(app, 'q_app', qapp)
buf = QBuffer()
app.on_focus_changed(buf, buf)
diff --git a/tests/unit/utils/overflow_test_cases.py b/tests/unit/utils/overflow_test_cases.py
index c13f3da5c..2018c7daa 100644
--- a/tests/unit/utils/overflow_test_cases.py
+++ b/tests/unit/utils/overflow_test_cases.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/utils/test_debug.py b/tests/unit/utils/test_debug.py
index bb93cbf10..abf250087 100644
--- a/tests/unit/utils/test_debug.py
+++ b/tests/unit/utils/test_debug.py
@@ -1,4 +1,4 @@
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
#
diff --git a/tests/unit/utils/test_error.py b/tests/unit/utils/test_error.py
index 42a090c75..580c344c9 100644
--- a/tests/unit/utils/test_error.py
+++ b/tests/unit/utils/test_error.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# This file is part of qutebrowser.
diff --git a/tests/unit/utils/test_javascript.py b/tests/unit/utils/test_javascript.py
index f5a2e6261..ea0e564f5 100644
--- a/tests/unit/utils/test_javascript.py
+++ b/tests/unit/utils/test_javascript.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/utils/test_jinja.py b/tests/unit/utils/test_jinja.py
index 34b821dcd..5bc96e0e9 100644
--- a/tests/unit/utils/test_jinja.py
+++ b/tests/unit/utils/test_jinja.py
@@ -1,4 +1,4 @@
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
#
diff --git a/tests/unit/utils/test_log.py b/tests/unit/utils/test_log.py
index a20e335ca..a8793232d 100644
--- a/tests/unit/utils/test_log.py
+++ b/tests/unit/utils/test_log.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/utils/test_qtutils.py b/tests/unit/utils/test_qtutils.py
index 3b625b3a5..a61bac43a 100644
--- a/tests/unit/utils/test_qtutils.py
+++ b/tests/unit/utils/test_qtutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -29,8 +29,9 @@ import unittest.mock
import pytest
from PyQt5.QtCore import (QDataStream, QPoint, QUrl, QByteArray, QIODevice,
QTimer, QBuffer, QFile, QProcess, QFileDevice)
+from PyQt5.QtGui import QColor
-from qutebrowser.utils import qtutils, utils
+from qutebrowser.utils import qtutils, utils, usertypes
import overflow_test_cases
if utils.is_linux:
@@ -111,6 +112,18 @@ def test_is_new_qtwebkit(monkeypatch, version, is_new):
assert qtutils.is_new_qtwebkit() == is_new
+@pytest.mark.parametrize('backend, arguments, single_process', [
+ (usertypes.Backend.QtWebKit, ['--single-process'], False),
+ (usertypes.Backend.QtWebEngine, ['--single-process'], True),
+ (usertypes.Backend.QtWebEngine, [], False),
+])
+def test_is_single_process(monkeypatch, stubs, backend, arguments, single_process):
+ qapp = stubs.FakeQApplication(arguments=arguments)
+ monkeypatch.setattr(qtutils, 'QApplication', qapp)
+ monkeypatch.setattr(qtutils.objects, 'backend', backend)
+ assert qtutils.is_single_process() == single_process
+
+
class TestCheckOverflow:
"""Test check_overflow."""
@@ -153,8 +166,7 @@ class QtObject:
"""Get the fake error, or raise AttributeError if set to None."""
if self._error is None:
raise AttributeError
- else:
- return self._error
+ return self._error
def isValid(self):
return self._valid
@@ -224,6 +236,20 @@ def test_qdatastream_status_count():
assert len(status_vals) == 4
+@pytest.mark.parametrize('color, expected', [
+ (QColor('red'), 'rgba(255, 0, 0, 255)'),
+ (QColor('blue'), 'rgba(0, 0, 255, 255)'),
+ (QColor(1, 3, 5, 7), 'rgba(1, 3, 5, 7)'),
+])
+def test_qcolor_to_qsscolor(color, expected):
+ assert qtutils.qcolor_to_qsscolor(color) == expected
+
+
+def test_qcolor_to_qsscolor_invalid():
+ with pytest.raises(qtutils.QtValueError):
+ qtutils.qcolor_to_qsscolor(QColor())
+
+
@pytest.mark.parametrize('obj', [
QPoint(23, 42),
QUrl('http://www.qutebrowser.org/'),
diff --git a/tests/unit/utils/test_standarddir.py b/tests/unit/utils/test_standarddir.py
index 3c4cea49e..4ac4944f0 100644
--- a/tests/unit/utils/test_standarddir.py
+++ b/tests/unit/utils/test_standarddir.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/utils/test_urlmatch.py b/tests/unit/utils/test_urlmatch.py
index 1dd57a5e9..70f7f02f4 100644
--- a/tests/unit/utils/test_urlmatch.py
+++ b/tests/unit/utils/test_urlmatch.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2018-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/utils/test_urlutils.py b/tests/unit/utils/test_urlutils.py
index 1c1efffab..2c6478b32 100644
--- a/tests/unit/utils/test_urlutils.py
+++ b/tests/unit/utils/test_urlutils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -627,7 +627,15 @@ class TestIncDecNumber:
'http://example.com:80/v1/query_test?value={}',
'http://example.com:80/v1/anchor_test#{}',
'http://host_{}_test.com:80',
- 'http://m4ny.c0m:80/number5/3very?where=yes#{}'
+ 'http://m4ny.c0m:80/number5/3very?where=yes#{}',
+
+ # Make sure that FullyDecoded is not used (to avoid losing information)
+ 'http://localhost/%3A{}',
+ 'http://localhost/:{}',
+ 'http://localhost/?v=%3A{}',
+ 'http://localhost/?v=:{}',
+ 'http://localhost/#%3A{}',
+ 'http://localhost/#:{}',
])
def test_incdec_number(self, incdec, value, url):
"""Test incdec_number with valid URLs."""
@@ -680,6 +688,8 @@ class TestIncDecNumber:
if incdec == 'increment':
expected_value = value.format(20 + count)
else:
+ if count > 20:
+ return
expected_value = value.format(20 - count)
base_url = QUrl(url.format(base_value))
@@ -726,17 +736,22 @@ class TestIncDecNumber:
"http://example.com/%C3%B6/urlencoded/data",
"http://example.com/number/in/anchor#5",
"http://www2.ex4mple.com:42/all/of/the/%C3%A4bove#5",
+ "http://localhost/url_encoded_in_query/?v=%3A",
+ "http://localhost/url_encoded_in_anchor/#%3A",
])
def test_no_number(self, url):
"""Test incdec_number with URLs that don't contain a number."""
with pytest.raises(urlutils.IncDecError):
urlutils.incdec_number(QUrl(url), "increment")
- def test_number_below_0(self):
+ @pytest.mark.parametrize('url, count', [
+ ('http://example.com/page_0.html', 1),
+ ('http://example.com/page_1.html', 2),
+ ])
+ def test_number_below_0(self, url, count):
"""Test incdec_number with a number <0 after decrementing."""
with pytest.raises(urlutils.IncDecError):
- urlutils.incdec_number(QUrl('http://example.com/page_0.html'),
- 'decrement')
+ urlutils.incdec_number(QUrl(url), 'decrement', count=count)
def test_invalid_url(self):
"""Test if incdec_number rejects an invalid URL."""
diff --git a/tests/unit/utils/test_utils.py b/tests/unit/utils/test_utils.py
index 37bd9faaa..014725fa2 100644
--- a/tests/unit/utils/test_utils.py
+++ b/tests/unit/utils/test_utils.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/utils/test_version.py b/tests/unit/utils/test_version.py
index c21ea0624..4c95d599f 100644
--- a/tests/unit/utils/test_version.py
+++ b/tests/unit/utils/test_version.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -176,6 +176,25 @@ from qutebrowser.browser import pdfjs
version.DistributionInfo(
id='funtoo', parsed=version.Distribution.gentoo,
version=None, pretty='Funtoo GNU/Linux')),
+ # KDE Platform
+ ("""
+ NAME=KDE
+ VERSION="5.12 (Flatpak runtime)"
+ VERSION_ID="5.12"
+ ID=org.kde.Platform
+ """,
+ version.DistributionInfo(
+ id='org.kde.Platform', parsed=version.Distribution.kde,
+ version=pkg_resources.parse_version('5.12'),
+ pretty='KDE')),
+ # No PRETTY_NAME
+ ("""
+ NAME="Tux"
+ ID=tux
+ """,
+ version.DistributionInfo(
+ id='tux', parsed=version.Distribution.unknown,
+ version=None, pretty='Tux')),
])
def test_distribution(tmpdir, monkeypatch, os_release, expected):
os_release_file = tmpdir / 'os-release'
@@ -780,7 +799,7 @@ class TestPDFJSVersion:
lambda path: (pdfjs_code, '/foo/bar/pdf.js'))
assert version._pdfjs_version() == '1.2.109 (/foo/bar/pdf.js)'
- def test_real_file(self):
+ def test_real_file(self, data_tmpdir):
"""Test against the real file if pdfjs was found."""
try:
pdfjs.get_pdfjs_res_and_path('build/pdf.js')
@@ -821,19 +840,35 @@ class FakeQSslSocket:
'QtWebEngine/5.8.0 Chrome/53.0.2785.148 Safari/537.36', '53.0.2785.148'),
])
def test_chromium_version(monkeypatch, caplog, ua, expected):
+ pytest.importorskip('PyQt5.QtWebEngineWidgets')
if ua is None:
- monkeypatch.setattr(version, 'QWebEngineProfile', None)
+ monkeypatch.setattr(version, 'webenginesettings', None)
else:
- class FakeWebEngineProfile:
- def httpUserAgent(self):
- return ua
- monkeypatch.setattr(version, 'QWebEngineProfile', FakeWebEngineProfile)
+ monkeypatch.setattr(version.webenginesettings,
+ 'default_user_agent', ua)
with caplog.at_level(logging.ERROR):
assert version._chromium_version() == expected
-def test_chromium_version_unpatched(qapp):
+def test_chromium_version_prefers_saved_user_agent(monkeypatch):
+ pytest.importorskip('PyQt5.QtWebEngineWidgets')
+ monkeypatch.setattr(
+ version.webenginesettings, 'default_user_agent',
+ 'QtWebEngine/5.8.0 Chrome/53.0.2785.148 Safari/537.36'
+ )
+
+ class FakeProfile:
+ def defaultProfile(self):
+ raise AssertionError("Should not be called")
+
+ monkeypatch.setattr(version, 'QWebEngineProfile', FakeProfile())
+
+ version._chromium_version()
+
+
+def test_chromium_version_unpatched(qapp, cache_tmpdir, data_tmpdir,
+ config_stub):
pytest.importorskip('PyQt5.QtWebEngineWidgets')
assert version._chromium_version() not in ['', 'unknown', 'unavailable']
@@ -861,9 +896,9 @@ class VersionParams:
], ids=lambda param: param.name)
def test_version_output(params, stubs, monkeypatch):
"""Test version.version()."""
- class FakeWebEngineProfile:
- def httpUserAgent(self):
- return 'Toaster/4.0.4 Chrome/CHROMIUMVERSION Teapot/4.1.8'
+ class FakeWebEngineSettings:
+ default_user_agent = ('Toaster/4.0.4 Chrome/CHROMIUMVERSION '
+ 'Teapot/4.1.8')
import_path = os.path.abspath('/IMPORTPATH')
patches = {
@@ -902,13 +937,14 @@ def test_version_output(params, stubs, monkeypatch):
if params.with_webkit:
patches['qWebKitVersion'] = lambda: 'WEBKIT VERSION'
patches['objects.backend'] = usertypes.Backend.QtWebKit
- patches['QWebEngineProfile'] = None
+ patches['webenginesettings'] = None
substitutions['backend'] = 'new QtWebKit (WebKit WEBKIT VERSION)'
else:
monkeypatch.delattr(version, 'qtutils.qWebKitVersion', raising=False)
patches['objects.backend'] = usertypes.Backend.QtWebEngine
- patches['QWebEngineProfile'] = FakeWebEngineProfile
substitutions['backend'] = 'QtWebEngine (Chromium CHROMIUMVERSION)'
+ patches['webenginesettings'] = FakeWebEngineSettings
+ patches['QWebEngineProfile'] = True
if params.known_distribution:
patches['distribution'] = lambda: version.DistributionInfo(
diff --git a/tests/unit/utils/usertypes/test_misc.py b/tests/unit/utils/usertypes/test_misc.py
index 631321278..1700b7f51 100644
--- a/tests/unit/utils/usertypes/test_misc.py
+++ b/tests/unit/utils/usertypes/test_misc.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2016-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/utils/usertypes/test_neighborlist.py b/tests/unit/utils/usertypes/test_neighborlist.py
index 7ee1725c2..587dffbd2 100644
--- a/tests/unit/utils/usertypes/test_neighborlist.py
+++ b/tests/unit/utils/usertypes/test_neighborlist.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2014-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/utils/usertypes/test_question.py b/tests/unit/utils/usertypes/test_question.py
index 09a55329f..13eb13e60 100644
--- a/tests/unit/utils/usertypes/test_question.py
+++ b/tests/unit/utils/usertypes/test_question.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tests/unit/utils/usertypes/test_timer.py b/tests/unit/utils/usertypes/test_timer.py
index 928e9d6a8..1f940ed81 100644
--- a/tests/unit/utils/usertypes/test_timer.py
+++ b/tests/unit/utils/usertypes/test_timer.py
@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
-# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+# Copyright 2015-2019 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
diff --git a/tox.ini b/tox.ini
index 75a00961e..0cdf41573 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,7 +4,7 @@
# and then run "tox" from this directory.
[tox]
-envlist = py36-pyqt511-cov,misc,vulture,flake8,pylint,pyroma,check-manifest,eslint
+envlist = py37-pyqt512-cov,misc,vulture,flake8,pylint,pyroma,check-manifest,eslint
distshare = {toxworkdir}
skipsdist = true
@@ -13,8 +13,8 @@ skipsdist = true
setenv =
QT_QPA_PLATFORM_PLUGIN_PATH={envdir}/Lib/site-packages/PyQt5/plugins/platforms
PYTEST_QT_API=pyqt5
- pyqt{,56,571,59,510,511}: LINK_PYQT_SKIP=true
- pyqt{,56,571,59,510,511}: QUTE_BDD_WEBENGINE=true
+ pyqt{,56,571,59,510,511,512}: LINK_PYQT_SKIP=true
+ pyqt{,56,571,59,510,511,512}: QUTE_BDD_WEBENGINE=true
cov: PYTEST_ADDOPTS=--cov --cov-report xml --cov-report=html --cov-report=
passenv = PYTHON DISPLAY XAUTHORITY HOME USERNAME USER CI TRAVIS XDG_* QUTE_* DOCKER QT_QUICK_BACKEND
basepython =
@@ -29,6 +29,8 @@ deps =
pyqt59: PyQt5==5.9.2
pyqt510: PyQt5==5.10.1
pyqt511: PyQt5==5.11.3
+ pyqt512: PyQt5==5.12.3
+ pyqt512: PyQtWebEngine==5.12.1
commands =
{envpython} scripts/link_pyqt.py --tox {envdir}
{envpython} -bb -m pytest {posargs:tests}
diff --git a/www/qute.css b/www/qute.css
index 5c11a72fd..9fa8dbebc 100644
--- a/www/qute.css
+++ b/www/qute.css
@@ -7,6 +7,7 @@ body {
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
-webkit-text-size-adjust: none;
color: #333333;
+ background-color: #ffffff;
overflow-y: scroll;
}