Compare commits

...

1153 Commits
v1.1.1 ... osx

Author SHA1 Message Date
Florian Bruhin
11f930db0d Add more macOS versions 2018-04-24 10:55:37 +02:00
Florian Bruhin
b4f877d991 Update changelog 2018-04-24 09:44:54 +02:00
Florian Bruhin
fa41af63b6 Always set FocusOnNavigationEnabled
This fixes some focus issues after Qt 5.11 changes. There might be better ways
to solve them, but for now, this will work.

See https://codereview.qt-project.org/#/c/221408/10 and #3661:
https://github.com/qutebrowser/qutebrowser/issues/3661#issuecomment-375969315

Might also negatively affect #3834 as it essentially reintroduces QTBUG-52999 on
any Qt version: https://bugreports.qt.io/browse/QTBUG-52999

Might be reverted at a later date, but for now, I want an easy way to make tests
work on Qt 5.11 to spot further issues.
2018-04-23 16:57:10 +02:00
Florian Bruhin
e789296b7f Handle new focus object for Qt 5.11
See https://codereview.qt-project.org/#/c/221408/10 and #3661:
https://github.com/qutebrowser/qutebrowser/issues/3661#issuecomment-375969315
2018-04-23 16:54:47 +02:00
Florian Bruhin
bc9a8dd63f Handle focusProxy being None
This fixes running with Qt 5.11

See https://codereview.qt-project.org/#/c/221408/10 and #3661:
https://github.com/qutebrowser/qutebrowser/issues/3661#issuecomment-375969315
2018-04-23 16:52:53 +02:00
Florian Bruhin
6640768860 Enable libGL workaround on any system where it's available
Fixes #3772
2018-04-23 11:20:56 +02:00
Florian Bruhin
178eeaed0d Update changelog 2018-04-17 07:49:10 +02:00
Florian Bruhin
f1967718b7 Merge remote-tracking branch 'origin/pr/3791' 2018-04-17 07:48:46 +02:00
Florian Bruhin
1021c3a330 Merge remote-tracking branch 'origin/pr/3826' 2018-04-16 17:26:59 +02:00
Florian Bruhin
ec57e58530 Update changelog 2018-04-16 17:21:42 +02:00
Florian Bruhin
06a8a68fcb Merge remote-tracking branch 'origin/pr/3844' 2018-04-16 17:21:13 +02:00
Florian Bruhin
4a78519b63 Mark opening/closing window via JS test as flaky 2018-04-16 17:14:47 +02:00
Florian Bruhin
d2207f66f1 Skip test_set_error entirely
See #3771
2018-04-16 17:14:14 +02:00
Florian Bruhin
23d4d72f3b Update changelog 2018-04-16 17:05:10 +02:00
Florian Bruhin
4a93389356 Merge remote-tracking branch 'origin/pr/3813' 2018-04-16 17:04:53 +02:00
Sebastian Heinlein
3704e3ddd5 Fix DESTDIR and PREFIX in makefile 2018-04-16 13:44:22 +02:00
Florian Bruhin
643bf4bc20 Remove 32-bit check in build_release.py
This is probably not needed anymore, see #3842
2018-04-16 08:33:01 +02:00
Florian Bruhin
b89b38fd3c Use latest release of PyInstaller
This is as a stop-gap solution for #3842.
2018-04-16 08:28:24 +02:00
Jay Kamat
0829511221 Merge pull request #3803 from toofar/fix/greasemonkey_includes_fallback
Greasemonkey: fix default include value
2018-04-13 18:26:46 -04:00
Jay Kamat
48b865073c Update changelog 2018-04-13 12:21:12 -04:00
Jay Kamat
3f9099613b Merge pull request #3807 from slackhead/tabs.mute_messages
Add option to mute the Last Tab/First Tab messages when tabs.wrap is false
2018-04-13 12:11:45 -04:00
Jay Kamat
77fa0730c8 Merge pull request #3802 from jgkamat/jay/tab-take-completion
Fix win_id 0 always being included in :tab-take completion
2018-04-10 16:24:48 -04:00
Jay Kamat
ed76d689b0 Add test for completing other buffer excluding id0 2018-04-10 02:45:12 -04:00
pyup-bot
ca311f8588 Update tox from 2.9.1 to 3.0.0 2018-04-09 18:13:31 +02:00
pyup-bot
849e427231 Update pytest-mock from 1.7.1 to 1.8.0 2018-04-09 18:13:29 +02:00
pyup-bot
9e628901e9 Update pytest-bdd from 2.20.0 to 2.21.0 2018-04-09 18:13:27 +02:00
pyup-bot
28126055da Update py-cpuinfo from 3.3.0 to 4.0.0 2018-04-09 18:13:26 +02:00
pyup-bot
3d75d86123 Update hypothesis from 3.52.0 to 3.55.1 2018-04-09 18:13:24 +02:00
pyup-bot
03ea07e99f Update cheroot from 6.0.0 to 6.1.2 2018-04-09 18:13:23 +02:00
pyup-bot
780ced8a52 Update pylint from 1.8.3 to 1.8.4 2018-04-09 18:13:21 +02:00
pyup-bot
fc33b065c2 Update astroid from 1.6.2 to 1.6.3 2018-04-09 18:13:20 +02:00
pyup-bot
03b7459b00 Update github3.py from 1.0.1 to 1.0.2 2018-04-09 18:13:18 +02:00
pyup-bot
f964bf1b67 Update github3.py from 1.0.1 to 1.0.2 2018-04-09 18:13:17 +02:00
pyup-bot
ef2a2702f5 Update wheel from 0.30.0 to 0.31.0 2018-04-09 18:13:15 +02:00
pyup-bot
6374b6dd4c Update flake8-builtins from 1.1.1 to 1.2.2 2018-04-09 18:13:14 +02:00
toofar
69d642cab8 Merge pull request #3792 from toofar/fix/gm_addstyle_earlyload
Greasemonkey: fix early GM_addStyle with fast sites.
Seems to be a working fix, despite noone having clarity on what is the ideal approach.
2018-04-09 19:11:10 +12:00
Slackhead
62aa9bdbb3 Added debug() logging for next/prev-tab and test scenarios 2018-04-09 02:03:02 +01:00
Florian Bruhin
e35c91043e pyinstaller: Use '.' as path for git-commit-id
See #384
2018-04-08 20:46:43 +02:00
Slackhead
fac546e9b4 Remove test scenarios for last/first tab when wrap is off 2018-04-08 18:56:16 +01:00
Jay Kamat
b74ddc3493 Merge pull request #3820 from AlvaroLuken/master
Added surrounding gray box to launch command for Ubuntu + Tox
2018-04-08 13:39:16 -04:00
Slackhead
b7964d9baf Remove first/last tab messages 2018-04-08 10:31:12 +01:00
AlvaroLuken
feb2f99ea9 Added surrounding gray box to launch command for Ubuntu + Tox 2018-04-05 11:22:38 -04:00
Jay Kamat
d0d5ad2eda Stop read timer when download is cancelled 2018-04-04 01:17:37 -04:00
Slackhead
eb18f0a2ac Adjust the help docs entry 2018-04-03 17:49:51 +01:00
Slackhead
39c08cb582 Add option to mute the Last Tab/First Tab messages when tabs.wrap is false 2018-04-03 16:27:04 +01:00
Jimmy
164ea98a5b Greasemonkey: fix default include value
Greasemonkey scripts are supposed to default to running on all pages.
@jgkamat and @nemanjan00 repurted some script not running on all pages
unless they either removed (or broke) the metadata block or added an
include directive. Indeed I had a logic error when it only defaulted to
being included on all pages when no metadata block at all was included.
Whoops.
2018-04-03 20:11:15 +12:00
Jay Kamat
3b2c0823af Fix win_id 0 always being included in :tab-take completion 2018-04-02 20:34:34 -04:00
Florian Bruhin
79823a9a0b Regenerate docs 2018-04-01 13:22:01 +02:00
Jimmy
1c0616f3ec Greasemonkey: fix early addstyle with fast sites.
nemanjan00 reported this script not having any effect da850e49cc/duckduckgo-deepdark.user.js

It turns out that the previous implementation of GM_addStyle was relying
on `document.onreadystatechange` when the script ran early enough that
there was no `head` element. That event wasn't getting fired for the
main frame of duckduckgo.com for whatever reason. Maybe using
`DOMContentLoaded` or something would have worked but I just copied the
fallback in the above linked script which seems to work just fine.
2018-04-01 12:38:48 +12:00
pylipp
599a3d75a4 Add userscript to download bibtex for DOI scraped from current tab 2018-03-31 21:43:20 +02:00
Florian Bruhin
6151d077e5 Update changelog 2018-03-30 11:49:39 +02:00
Florian Bruhin
d438aa15fa Simplify setting _qute_script_id 2018-03-30 11:48:06 +02:00
Jay Kamat
7f5a79cdfd Escape strings with string_escape rather than tojson 2018-03-30 01:40:49 -04:00
Florian Bruhin
5bc794f85a Update changelog 2018-03-28 21:11:20 +02:00
Florian Bruhin
d7455bcdba Merge remote-tracking branch 'origin/pr/3765' into adblock 2018-03-28 20:32:47 +02:00
Florian Bruhin
0b667e4701 Merge remote-tracking branch 'origin/pr/3763' into adblock 2018-03-28 20:32:39 +02:00
George Edward Bulmer
2789bec1e7 Modify assert_url to treat localhost differently 2018-03-28 14:27:17 +01:00
George Edward Bulmer
1ccb464d1c Return removed comment about hosts format 2018-03-28 14:17:13 +01:00
Florian Bruhin
758ea8b171 Update changelog 2018-03-28 09:36:32 +02:00
Florian Bruhin
32568a6da4 Simplify tests 2018-03-28 09:33:27 +02:00
Florian Bruhin
14792472db Merge remote-tracking branch 'origin/pr/3680' 2018-03-28 09:29:54 +02:00
Florian Bruhin
005fa8b675 Fix newline 2018-03-28 09:14:26 +02:00
Florian Bruhin
c7e5033eaa Set MainWindow as parent of TabbedBrowser
If we close the MainWindow (and it gets deleted), we need to make sure to delete
the TabbedBrowser as well.

Fixes #3781
2018-03-28 08:58:07 +02:00
Florian Bruhin
a828851640 Update recommended Qt version in readme 2018-03-28 08:48:18 +02:00
Jussi Timperi
046a3dc159 Add option to only show favicons for pinned tabs
Closes #3440
2018-03-28 00:45:57 +03:00
Florian Bruhin
68b707c749 Update changelog 2018-03-27 12:01:42 +02:00
Florian Bruhin
9cff0e7367 Merge remote-tracking branch 'origin/pr/3742' 2018-03-27 12:01:18 +02:00
Florian Bruhin
7e66c3cf46 Update changelog 2018-03-27 11:11:34 +02:00
Florian Bruhin
bf4aab79ac Merge remote-tracking branch 'origin/pr/3751' 2018-03-27 11:11:12 +02:00
Florian Bruhin
a6f6fdf19b Update docs 2018-03-27 11:09:18 +02:00
Florian Bruhin
e5ffcbd49f Merge remote-tracking branch 'origin/pr/3750' 2018-03-27 11:07:29 +02:00
Florian Bruhin
730347e449 Merge branch 'pyup-scheduled-update-2018-03-26' 2018-03-27 10:27:59 +02:00
Florian Bruhin
55112b52e0 Merge remote-tracking branch 'origin/pr/3776' 2018-03-27 10:25:41 +02:00
Florian Bruhin
2249a88e3a Make test_simple_js_webengine work correctly 2018-03-27 07:29:43 +02:00
Florian Bruhin
6dbd6d1ddf Move test_qt_javascript.py 2018-03-27 07:14:05 +02:00
Florian Bruhin
6ecea8ef17 Revert accidental changes to test_qt_javascript.py 2018-03-27 07:13:17 +02:00
Florian Bruhin
021bb25622 Add regenerating website to contributing.asciidoc
[ci skip]

(cherry picked from commit 9f95736bbe4a00c9cc4a8b222ab3dc55d6bdf96c)
2018-03-26 22:53:46 +02:00
Florian Bruhin
22e887045b Remove flake8-builtins filter 2018-03-26 18:27:15 +02:00
pyup-bot
4896765fcc Update virtualenv from 15.1.0 to 15.2.0 2018-03-26 18:17:25 +02:00
pyup-bot
d98590d712 Update pytest-faulthandler from 1.4.1 to 1.5.0 2018-03-26 18:17:23 +02:00
pyup-bot
496e6fc624 Update pytest from 3.4.2 to 3.5.0 2018-03-26 18:17:22 +02:00
pyup-bot
55a818b156 Update py from 1.5.2 to 1.5.3 2018-03-26 18:17:20 +02:00
pyup-bot
85be0f2801 Update py from 1.5.2 to 1.5.3 2018-03-26 18:17:19 +02:00
pyup-bot
b7b4cc7f31 Update hypothesis from 3.50.0 to 3.52.0 2018-03-26 18:17:17 +02:00
pyup-bot
056a901da0 Update python-dateutil from 2.7.0 to 2.7.2 2018-03-26 18:17:16 +02:00
pyup-bot
ba9b166962 Update python-dateutil from 2.7.0 to 2.7.2 2018-03-26 18:17:15 +02:00
pyup-bot
edf2652431 Update flake8-builtins from 1.0.post0 to 1.1.1 2018-03-26 18:17:13 +02:00
Florian Bruhin
6755e17630 Update changelog 2018-03-26 10:54:15 +02:00
Florian Bruhin
d4899240de Break long lines 2018-03-26 10:51:04 +02:00
Florian Bruhin
ddbb6b5198 Merge remote-tracking branch 'origin/pr/3769' 2018-03-26 10:45:31 +02:00
Florian Bruhin
1087ce075d Merge remote-tracking branch 'origin/pr/3767' 2018-03-26 10:45:23 +02:00
Philip Lewis
cecb79cf05 Fix keyhints for special characters
`prefix` is a string and `seq` is a key sequence, so removing `len(prefix)`
items from `seq` will remove too many if `prefix` contains a special character
(ex "<Ctrl+x>").  Remove the number of characters from `str(seq)` instead.
2018-03-25 15:18:02 -04:00
Florian Bruhin
d4ea1df232 Improve window_open.html tests 2018-03-25 19:56:48 +02:00
Florian Bruhin
91ca7d0911 tests: Rename close function in window_open.html
Naming it close() conflicts with the global JS close()
2018-03-25 19:39:34 +02:00
bitraid
68e3ad6cba Pyinstaller: don't use upx 2018-03-25 19:43:59 +03:00
Florian Bruhin
12a405965a Make QtWebEngine inspector work with JS disabled 2018-03-25 14:55:03 +02:00
George Edward Bulmer
a85ac1725f Missing fullstop in a docstring 2018-03-24 22:56:47 +00:00
George Edward Bulmer
eb5684e5f7 Pylint fix 2018-03-24 21:52:26 +00:00
George Edward Bulmer
b9bcad9c14 Grammar change 2018-03-24 21:13:22 +00:00
George Edward Bulmer
64b01cc076 Remove extraneous part 2018-03-24 21:10:23 +00:00
George Edward Bulmer
1380fef600 Add test for parsing multiple lines 2018-03-24 21:08:55 +00:00
George Edward Bulmer
8809ef02a1 Add support for more than 1 host on a given line 2018-03-24 20:20:16 +00:00
George Edward Bulmer
3f37fcf8fa Modify tests, localhost should never be blocked 2018-03-24 20:15:34 +00:00
George Edward Bulmer
c8db9e1c76 Remove WHITELISTED, making file parsing satisfy:
1) 'dotless' hosts, e.g. localhost, cannot be blocked by a file
2) hosts ending in '.localdomain' cannot be blocked by a file
2018-03-24 19:42:34 +00:00
George Edward Bulmer
01d8314dd8 Change default blocklist to StevenBlack combined 2018-03-24 18:35:03 +00:00
rien333
fa21d280fa Remove unnecessary hide operation 2018-03-24 05:09:03 +01:00
rien333
e211801e16 Handle wayland decoration option rename through configdata.yml 2018-03-23 15:24:18 +01:00
rien333
6db1ab0a58 Cosmetic changes 2018-03-23 15:21:02 +01:00
rien333
aa70395925 Merge branch 'master' of https://github.com/rien333/qutebrowser 2018-03-23 15:19:58 +01:00
rien333
880b33fff5 Restore correct window visibility after decoration config change 2018-03-23 15:19:37 +01:00
Florian Bruhin
f1789effdc Stabilize navigate.feature on Qt 5.11
Looks like we get qute://help as URL from the previous test otherwise?
See #3661
2018-03-23 10:29:25 +01:00
Florian Bruhin
e095f64eb6 Merge remote-tracking branch 'origin/pr/3752' 2018-03-23 08:25:59 +01:00
Florian Bruhin
06df88075e Merge remote-tracking branch 'origin/pr/3749' 2018-03-23 08:25:49 +01:00
Florian Bruhin
00bdb60627 Ignore "Dropping message on closed channel." message
This seems to happen with this test in tabs.feature with Qt 5.11:
Scenario: :buffer with wrong argument (-1)

It only happens ~1/50 times though, and seems like some Qt bug.

See #3661
2018-03-23 07:59:46 +01:00
rien333
1fc0abb064 Delete .#configfiles.py 2018-03-23 02:50:36 +01:00
rien333
e2250d65e9 Merge branch 'master' of git://github.com/qutebrowser/qutebrowser 2018-03-23 01:43:23 +01:00
rien333
bb0c79b5a2 Fix wayland test 2018-03-23 01:38:45 +01:00
rien333
ff299c87a8 Reinsert wayland specific code for toggling decoration visibility 2018-03-22 23:32:37 +01:00
rien333
2d2bdad2ca Do not require restart after decoration option change 2018-03-22 23:26:45 +01:00
Jay Kamat
07d043fe81 Add basic tests for tab width sizing 2018-03-22 14:27:33 -04:00
Jay Kamat
477da6002a Fix minimum size for vertical tabs 2018-03-22 12:59:35 -04:00
Jay Kamat
d2c01d7ee6 Always display plain titles in tab tooltips
Closes #3741
2018-03-22 12:03:15 -04:00
Florian Bruhin
b67a031151 Rephrase autoconfig.yml docs
[ci skip]
2018-03-22 08:37:12 +01:00
rien333
764e79e505 Small refactor 2018-03-22 03:44:24 +01:00
rien333
7b7faa9f66 Fix silly redefinition 2018-03-22 03:42:57 +01:00
rien333
a6b92dbbd3 General window decoration hiding option 2018-03-22 02:23:21 +01:00
bitraid
4fb940241c Add 32bit color for Windows icon 2018-03-21 23:13:26 +02:00
George Edward Bulmer
51f9464eb2 Add test for hints with numberpad numbers 2018-03-21 17:06:13 +00:00
George Edward Bulmer
0645865d22 Add test case for is_special in keyutils 2018-03-21 16:38:58 +00:00
George Edward Bulmer
991ba54499 Change the formatting of the numpad keys
This makes it consistent with as before
2018-03-21 15:41:08 +00:00
George Edward Bulmer
1cf3d66a22 Revert test and modify returned key 2018-03-21 15:34:32 +00:00
Florian Bruhin
300d873b18 Update Debian install instructions
Supersedes #3707
Fixes #3737

[ci skip]
2018-03-21 10:55:54 +01:00
Florian Bruhin
a8bbd5fa4d Update docs for TimestampTemplate 2018-03-21 10:14:48 +01:00
Florian Bruhin
2d655a7230 Update changelog 2018-03-21 08:27:09 +01:00
George Edward Bulmer
4d7f8e4878 Pylint fix 2018-03-21 00:28:52 +00:00
George Edward Bulmer
bc885cc9ee Modify the keypad test
The new behaviour is for the keypad to yield its usual key,
such that instead of a special <Num+2> keypress, it yields <2>
2018-03-20 23:19:36 +00:00
George Edward Bulmer
a5dc8a3025 Fix crash in string representation of key 2018-03-20 23:13:56 +00:00
George Edward Bulmer
d6463d5ade Remove Qt.KeypadModifier as a special key 2018-03-20 22:33:11 +00:00
bitraid
7601e58c81 Merge remote-tracking branch 'upstream/master' 2018-03-20 23:54:18 +02:00
Ryan Roden-Corrent
16bda94e2b Remove unused import and TODO from urlmarks test. 2018-03-20 21:41:19 +00:00
Ryan Roden-Corrent
5a20052bce Add unit tests for urlmarks. 2018-03-20 21:41:19 +00:00
bitraid
e316f1768e More compatible icon for Windows
Fixes #3601
2018-03-20 23:28:42 +02:00
Florian Bruhin
11696f0073 Fix test_configinit 2018-03-20 22:16:16 +01:00
Florian Bruhin
f9d976880e Disable shared web workers on Qt < 5.11 2018-03-20 21:14:04 +01:00
Florian Bruhin
a5f1022330 Log document.body in JS tests 2018-03-20 11:56:46 +01:00
Florian Bruhin
85d3d4baba Mark test_set_error as flaky 2018-03-20 10:25:03 +01:00
Florian Bruhin
561295238d Another try at stabilizing test_set_error 2018-03-20 08:58:48 +01:00
Florian Bruhin
0e670a597e Update docs 2018-03-20 08:53:59 +01:00
Florian Bruhin
0fd3674d9e Update changelog 2018-03-20 07:07:05 +01:00
Florian Bruhin
0ee9d73fe2 Merge remote-tracking branch 'origin/pr/3692' 2018-03-20 07:05:43 +01:00
Florian Bruhin
81827a3150 Try to stabilize stylesheet tests 2018-03-20 07:05:03 +01:00
Florian Bruhin
32145d579b Merge branch 'pyup-scheduled-update-2018-03-19' 2018-03-20 07:00:37 +01:00
Florian Bruhin
f230fd3abb Rebuild requirement files 2018-03-20 06:59:57 +01:00
Florian Bruhin
51318d66c8 Fix ignore for new flake8-per-file-ignores release 2018-03-20 06:55:05 +01:00
Florian Bruhin
59602ec5b5 requirements: Blacklist flake8-builtins 1.1.0
See https://github.com/gforcada/flake8-builtins/issues/19
2018-03-20 06:55:05 +01:00
Florian Bruhin
a374698693 Fix lint 2018-03-20 06:38:11 +01:00
Florian Bruhin
b56988f0a4 Update changelog 2018-03-20 06:27:48 +01:00
Florian Bruhin
32df91fbae Merge remote-tracking branch 'origin/pr/3604' 2018-03-20 06:24:57 +01:00
Jay Kamat
f6c00babbe Prevent minimumTabsizeHint from being called when booting on mac
Move workaround higher up to the start of tabSizeHint
2018-03-19 18:29:51 -04:00
Florian Bruhin
7eaad59be3 caret: Ignore None value from setInitialCursor
See #3583
2018-03-19 22:32:26 +01:00
Florian Bruhin
ea1e52ea7c Load page before loading stylesheets
If we don't do this, when doing:

   self.config_stub.val.content.user_stylesheets = css_path

then _update_stylesheet gets called before the stylesheet QWebEngineScript did
run (as there was no load yet), so we get:

  [:2] Uncaught TypeError: Cannot read property 'stylesheet' of undefined!

Instead, load the page first and then update the stylesheet.
This tests that live updating works properly, and also makes sure we don't run
into the problem described above.
2018-03-19 21:44:47 +01:00
Florian Bruhin
b588f54a53 Fail javascript tests on logging messages 2018-03-19 20:43:55 +01:00
Florian Bruhin
9031b3e535 Remove @pyqtSlot for on_download_requested
For some reason, this breaks when test_pac is run...
2018-03-19 20:17:15 +01:00
Florian Bruhin
1162e640c5 Remove unused imports 2018-03-19 19:42:56 +01:00
Florian Bruhin
0ea7a1457d Make test_position_caret work again
The tests only work properly with QtWebKit (and aren't needed on QtWebEngine).
Also, for some reason the scrolled_down tests only work without Xvfb.
2018-03-19 19:38:21 +01:00
Florian Bruhin
f5d7605ae0 Add a :scroll-to-anchor command
Fixes #2784
2018-03-19 19:18:33 +01:00
Florian Bruhin
e50068021d Use signals to update statusbar in caret mode
This means we don't use objreg anymore to get the status bar, and also makes the
bar more accurately reflect reality.

See #3583
2018-03-19 18:44:06 +01:00
Florian Bruhin
460bd86579 Initial attempt at using the tab API for tests/unit/javascript 2018-03-19 18:18:21 +01:00
Florian Bruhin
e43f0a61b9 Move all QWebEngineScript related code out of webenginesettings
It looks like there's some issue with QWebEngineScript in a profile, at least
with older Qt versions...

See #3497, #3377
2018-03-19 17:33:02 +01:00
pyup-bot
8eb4d15805 Update hypothesis from 3.49.0 to 3.50.0 2018-03-19 17:13:26 +01:00
pyup-bot
3b7e1b3fe2 Update pylint from 1.8.2 to 1.8.3 2018-03-19 17:13:25 +01:00
pyup-bot
650aa532cd Update astroid from 1.6.1 to 1.6.2 2018-03-19 17:13:23 +01:00
pyup-bot
1f3fc756db Update github3.py from 0.9.6 to 1.0.1 2018-03-19 17:13:22 +01:00
pyup-bot
2d5d485daf Update github3.py from 0.9.6 to 1.0.1 2018-03-19 17:13:20 +01:00
pyup-bot
b77e43d74f Update setuptools from 38.5.2 to 39.0.1 2018-03-19 17:13:18 +01:00
pyup-bot
5a26858e07 Update flake8-per-file-ignores from 0.5 to 0.6 2018-03-19 17:13:17 +01:00
pyup-bot
99ea4b98e8 Update flake8-builtins from 1.0.post0 to 1.1.0 2018-03-19 17:13:15 +01:00
Florian Bruhin
da8b6fb50a Decrease maximum repetitions for QtWebEngine scrolling
At least for Qt debug builds, 5000 seems to be much too much.
See #3661
2018-03-19 14:11:01 +01:00
Florian Bruhin
33066af51d Break long comment 2018-03-19 13:59:30 +01:00
Florian Bruhin
6a971e2846 Ignore OnDidStopLoading error message
See #3661, https://bugreports.qt.io/browse/QTBUG-66661
2018-03-19 12:13:10 +01:00
Florian Bruhin
f28a39571c Fix caret.js indent 2018-03-19 11:49:24 +01:00
Florian Bruhin
bee04a1eec Wait until runner is finished in test_custom_env
This seems to at least lead to less warnings when running the test.
2018-03-19 11:43:08 +01:00
Florian Bruhin
39d25c1127 Update _chromium_version comment
[ci skip]
2018-03-19 11:15:19 +01:00
Florian Bruhin
07e831cee5 Update changelog 2018-03-19 10:28:25 +01:00
Florian Bruhin
b3342d8f70 Merge remote-tracking branch 'origin/pr/3728' 2018-03-19 10:28:04 +01:00
Florian Bruhin
6465d64738 Fix lint 2018-03-19 10:22:21 +01:00
Florian Bruhin
232fd19422 Fix unit tests after refactoring 2018-03-19 09:53:35 +01:00
Florian Bruhin
a4530797ea Add a ProfileSetter class to webenginesettings
Easier than passing a profile around everywhere.
2018-03-19 09:40:57 +01:00
Florian Bruhin
1b84bbd61d Refactor initialization of internal JavaScript
- Initialize JavaScript in webenginesettings.py instead of webenginetab.py
- Move JavaScript snippet into a .js file
- Make sure scripts can be re-run and do nothing if already run.
- Run scripts on DocumentCreation *and* DocumentReady. Closes #3717.
- Give each script an unique name for debugging.
- Also make custom stylesheets work on chrome:// pages
2018-03-19 09:14:55 +01:00
Florian Bruhin
f2864c6253 Break greasemonkey_wrapper lines differently 2018-03-19 09:13:50 +01:00
Florian Bruhin
8ae3047f2a Update changelog 2018-03-18 19:00:07 +01:00
Florian Bruhin
b154846bdc Merge remote-tracking branch 'origin/pr/3733' 2018-03-18 18:59:41 +01:00
Florian Bruhin
8a3d9c0c01 Adjust ignored log messages for Qt 5.11 2018-03-18 18:58:29 +01:00
AlternateData
62d30fe589 use 0 and maxint as bounds 2018-03-18 10:06:41 +01:00
AlternateData
a52d18b700 Add correct maximum and minimum value for tabs.switching_delay 2018-03-17 17:59:31 +01:00
gammelon
f57e47c742 Separate tests for _get_search_url 2018-03-16 11:42:51 +01:00
Bryan Bugyi
18146e2fbc Fix: prevent unmatched quote (#3726) 2018-03-16 06:16:16 -04:00
Florian Bruhin
f7074b80d0 Fix lint 2018-03-16 09:07:25 +01:00
Bryan Bugyi
fa282d574d Fix: preserve exit status of task command (#3726) 2018-03-16 03:44:22 -04:00
Bryan Bugyi
3b0b4ffe66 Fix: restrict output of task to one line (closes #3726) 2018-03-16 03:28:44 -04:00
Florian Bruhin
a6ce188e0d Update changelog 2018-03-16 08:21:11 +01:00
Florian Bruhin
01845faac5 Set window title/icon on correct object
This was a regression introduced in #3613.
Fixes #3727
2018-03-16 08:20:27 +01:00
Florian Bruhin
69a013bc82 Update changelog 2018-03-15 14:53:20 +01:00
Florian Bruhin
6f8eb419ae Emit predicted_navigation when loading sessions
This avoids reloads (because of changed settings) after a session has been
loaded.

Related to #3718
2018-03-15 14:51:36 +01:00
Florian Bruhin
1e4b80d1ac Don't emit predicted_navigation when reloading because of it
When we reload because of a config change in _on_load_finished, we can't use
self.reload() as no URL is set yet. Instead, we call self.openurl with the
current URL.

However, we need to make sure we don't emit predicted_navigation again at that
point.

This should (finally) fix #3718
2018-03-15 14:44:44 +01:00
Florian Bruhin
5dbda3016b Clean up predicted_navigation handling
This also adds some more logging for #3718
2018-03-15 14:16:10 +01:00
Florian Bruhin
1d25b212d5 Add missing qapp fixtures to tests
See #3723
2018-03-15 09:06:40 +01:00
Florian Bruhin
f538fc8b74 Update release checklist
[ci skip]
2018-03-14 21:50:22 +01:00
Florian Bruhin
c2b995edde Update build_release for github3.py 1.0 2018-03-14 21:11:03 +01:00
Florian Bruhin
1d562d919e Include requirements files in built release
This is needed to use "tox -e mkvenv"
2018-03-14 21:10:35 +01:00
Florian Bruhin
a60bae30b7 Release v1.2.1
(cherry picked from commit 6145786e46)
2018-03-14 20:20:20 +01:00
Florian Bruhin
523502785a Update changelog for v1.2.1 2018-03-14 20:17:34 +01:00
Florian Bruhin
84c7c37e8e Swap Control/Meta back on macOS
Fixes #3697

(cherry picked from commit fd9e7bed7fd9842eac22ed304a094a92cc953577)
2018-03-14 19:40:56 +01:00
Florian Bruhin
d232b3ea57 Disable test_software_rendering on macOS
For some reason, macOS doesn't care about us disabling software rendering
2018-03-14 19:31:36 +01:00
Florian Bruhin
7a861b7119 Update changelog 2018-03-14 18:19:11 +01:00
Florian Bruhin
a22f973c99 Don't emit predicted_navigation for reloads at all
When we reload a page because of a config change, we won't get another
titleChanged signal (at least sometimes).

Also, the predicted_navigation signal is worthless when reloading anyways, as
we're going to load the same URL and not something different.

Fixes #3718
2018-03-14 18:19:11 +01:00
Florian Bruhin
724e531087 Merge pull request #3715 from toofar/docs/greasy-faq
Greasemonkey: add FAQ entry.
2018-03-14 11:13:21 +01:00
Florian Bruhin
5c73910a33 Revert "Insert qutebrowser scripts on DocumentCreation and DocumentReady"
This reverts commit fac0f66e52.
2018-03-14 10:19:23 +01:00
Florian Bruhin
84bae210ab Fix wrong number in cheatsheet 2018-03-14 09:06:04 +01:00
Jimmy
e5edc0f940 fixup! Greasemonkey: add FAQ entry.
Change the wording and the `--debug` suggestion.

Add comma after "this is currently not supported", I was tempted to add
a semicolon before it to but I resisted.

Added a "then" after QtWebEngine version list, not a comma.
2018-03-14 20:25:59 +13:00
Florian Bruhin
0d21265005 Update changelog 2018-03-14 08:07:38 +01:00
Florian Bruhin
c0fdf19756 Merge remote-tracking branch 'origin/pr/3704' 2018-03-14 08:06:24 +01:00
Florian Bruhin
102b2be361 Update changelog 2018-03-14 07:56:00 +01:00
Florian Bruhin
fac0f66e52 Insert qutebrowser scripts on DocumentCreation and DocumentReady
In #3521, the injection point was changed to DocumentReady as a fix for
https://bugreports.qt.io/browse/QTBUG-66011 / #3490.

However, that prevents e.g. using hints before a page is fully loaded, which can
be annoying on a mobile connection.

Instead, just run the scripts twice, which won't hurt and makes sure they're
available.
2018-03-14 07:50:41 +01:00
Jimmy
2563ecf6d8 Greasemonkey: add FAQ entry.
The most common questsions regarding greasemonkey support on IRC are
"how do I use it" and "why doesn't my script work", hopefully this can
be a starting point for most people experiencing issues.
2018-03-14 19:48:46 +13:00
Florian Bruhin
64530375ab Update changelog 2018-03-14 07:44:51 +01:00
Jay Kamat
7278b7c2e5 Improve wording of documentation 2018-03-13 22:25:26 -04:00
Jay Kamat
35beff98a9 Add test for #3711 2018-03-13 19:18:42 -04:00
Jay Kamat
a6e94cf30c Fix hinting in frames on qt5.9 with input ranges 2018-03-13 18:54:08 -04:00
Florian Bruhin
8e01353a94 Update changelog 2018-03-13 14:41:40 +01:00
Florian Bruhin
8b9c6ccee2 Split up BaseKeyParser.handle into functions 2018-03-13 14:40:54 +01:00
Florian Bruhin
b88ac51d25 Fall back to non-keypad keys without any keypad bindings
Fixes #3701
2018-03-13 14:40:54 +01:00
Ryan Roden-Corrent
73517f0a51 Fix test_backup_error.
- Need caplog at level error
- Rename test to be unique
2018-03-13 08:50:34 -04:00
Ryan Roden-Corrent
27966c94a6 Fix up editor backup patch.
- Use qutebrowser-editor-backup as the backup file prefix
- Consistently use message.error instead of cmdexc
- Improve test coverage for the backup function
- Fix lint errors in the unit test code
2018-03-13 07:34:18 -04:00
Florian Bruhin
a7b6d179d4 Update changelog 2018-03-13 09:51:03 +01:00
Florian Bruhin
1c9598d2c0 Don't emit predicted_navigation with invalid URLs
Fixes #3706
2018-03-13 09:46:09 +01:00
Florian Bruhin
dcd6bcd2f4 Apply changes from PR review 2018-03-13 08:47:41 +01:00
Florian Bruhin
c590648077 Merge remote-tracking branch 'origin/pr/3613' 2018-03-13 08:39:36 +01:00
Florian Bruhin
80843c0b53 Update changelog 2018-03-13 07:39:04 +01:00
Florian Bruhin
14d6e737fa Merge remote-tracking branch 'origin/pr/3606' 2018-03-13 07:37:57 +01:00
Florian Bruhin
9c613fb700 Merge pull request #3705 from qutebrowser/pyup-scheduled-update-2018-03-12
Scheduled weekly dependency update for week 10
2018-03-12 18:57:36 +01:00
pyup-bot
01aa1f755d Update pytest from 3.4.1 to 3.4.2 2018-03-12 17:10:19 +01:00
pyup-bot
3855d49821 Update hypothesis from 3.48.0 to 3.49.0 2018-03-12 17:10:18 +01:00
pyup-bot
55c24cad9a Update setuptools from 38.5.1 to 38.5.2 2018-03-12 17:10:16 +01:00
Ryan Roden-Corrent
38bb3673db Preserve a backup if editor callback fails.
Currently the editor deletes its temp file whenever editing is finished.
With this patch, the file will not be deleted if the editor callback
encounters an exception.

One example is if the tab containing the edited element is closed. The
editor errors with "Edited element vanished", but with this patch it
will also print "Backup at ..." so the user does not lose their work.

Resolves #1596.

Supersedes #3641, using the cleaner approach started in #1677.
2018-03-12 08:34:50 -04:00
gammelon
455f6b8a70 Fix blank lines 2018-03-12 12:37:52 +01:00
Florian Bruhin
8c5b7bcd03 Fix lint 2018-03-12 08:51:36 +01:00
Florian Bruhin
a6885a0d41 Update changelog 2018-03-12 08:03:20 +01:00
Florian Bruhin
9941812127 Normalize keys read from the config
This makes sure the internal bindings.commands object only contains normalized
key sequences.

Fixes #3699
2018-03-12 08:00:56 +01:00
Florian Bruhin
990c0707f4 Make from_obj() work for List/Dict configtypes
We can't easily make it work for ListOrValue as we don't know which of both we
get at this point.
2018-03-12 08:00:18 +01:00
Florian Bruhin
c03ef10d54 tests: Add a yaml_config_stub fixture 2018-03-12 07:39:20 +01:00
Florian Bruhin
d72691ee49 Simplify ListOrValue configtype 2018-03-12 07:38:56 +01:00
Florian Bruhin
27c2650245 build_release: Wait before detaching volume
This hopefully helps with detaching it properly.
2018-03-11 21:06:31 +01:00
Florian Bruhin
b0bf02e23a Update changelog 2018-03-11 21:05:10 +01:00
Florian Bruhin
30ab1d0218 Force PyQt 5.10.0 with "tox -e mkvenv-pypi"
Fixes #3662
2018-03-11 20:47:01 +01:00
Florian Bruhin
7f68affa30 Merge remote-tracking branch 'origin/pr/3695' 2018-03-11 14:36:06 +01:00
Florian Bruhin
b6e29d8eae Be explicit about expected output in test 2018-03-11 14:35:15 +01:00
Florian Bruhin
591883656e Merge remote-tracking branch 'origin/pr/3700' 2018-03-11 14:34:06 +01:00
Florian Bruhin
f0a649e101 Mark another GreaseMonkey test as flaky
See #3238
2018-03-11 14:29:54 +01:00
Roman Bogorodskiy
d0342bffc4 Show version for POSIX OSes
For POSIX OSes other than Linux and macOS set OS Version to
platform.uname() instead of showing 'OS Version: ?'.
2018-03-11 13:28:53 +04:00
Florian Bruhin
75ab8f077d Fix keybinding cheatsheet URLs in quickstart.asciidoc
The URLs and the patching were changed in
96e8151cce but not in quickstart.asciidoc.
2018-03-11 08:30:41 +01:00
Florian Bruhin
d9f7d401c6 Handle ImportError in version.opengl_vendor
Fixes #3698
2018-03-11 08:15:22 +01:00
Florian Bruhin
5f01c7e79a Release v1.2.0 2018-03-09 22:40:59 +01:00
Jay Kamat
996561b50e Apply tabs.min_width to all tabs when tabs are unshrunk 2018-03-09 14:36:01 -05:00
Sebastian Noack
4cf0311d7f Updated flake8-per-file-ignores to version 0.5 2018-03-09 14:09:49 -05:00
Johannes Wegener
cf4e472461 add basic completion to file dialog 2018-03-09 16:21:57 +01:00
gammelon
0ce94dae1c forgot one bit 2018-03-09 15:55:40 +01:00
gammelon
7e3c966afe rewrite tests 2018-03-09 15:52:03 +01:00
Florian Bruhin
39eb512b27 Fix lint 2018-03-09 14:13:29 +01:00
Florian Bruhin
ebb373ccad Make sure keys with modifiers get handled as special 2018-03-09 09:04:28 +01:00
Florian Bruhin
c7cccf4ba0 Clear key chains when a special key is pressed in hint mode
When we press "s<Escape>", we don't want <Escape> to be handled as part of a key
chain.
2018-03-09 08:43:07 +01:00
Jay Kamat
1672995639 Clean up style issues 2018-03-09 02:19:49 -05:00
Jay Kamat
4a78b0519d Add tabs.min_width setting
Controls min width in pixels of non pinned tabs

Closes #3690
2018-03-09 02:05:49 -05:00
Jay Kamat
46533c3367 Fix pinned tabs being too small in extreme situations 2018-03-09 02:02:31 -05:00
Florian Bruhin
66b06ed84c Add first tests for HintKeyParser 2018-03-09 07:38:16 +01:00
Florian Bruhin
b789e436b8 Fix lint 2018-03-09 07:07:04 +01:00
jakanakae-envangel
0cd73af691 keyinput: Merge keyparser into modeparsers 2018-03-08 19:55:43 +01:00
Florian Bruhin
63d23ca9df Add compiled=False to version checks 2018-03-08 18:48:35 +01:00
Florian Bruhin
9af07d86d6 Don't double HTML escape JavaScript messages
See https://bugreports.qt.io/browse/QTBUG-66104
2018-03-08 18:23:36 +01:00
Florian Bruhin
f561272f9a Remove old comments
See #3687

[ci skip]
2018-03-08 15:48:34 +01:00
Florian Bruhin
2b2473a6d8 Add security entry FAQ
Fixes #3686
2018-03-08 12:58:17 +01:00
Florian Bruhin
0134c1fcfd travis: Test Python 3.5 with Qt 5.7.1
Might run more stable, and makes more sense anyways.
2018-03-08 12:28:10 +01:00
Florian Bruhin
c01f674234 Add Chromium versions to _chromium_version comment 2018-03-08 12:27:41 +01:00
Florian Bruhin
482b622b1b Fix handling of empty bindings without breaking :unbind
1899e313fd as a fix for #3631 broke :unbind, as
the config system treats None and '' equally.

Instead, allow None/'' again, but just handle it as "no binding".
2018-03-08 11:42:27 +01:00
Florian Bruhin
1899e313fd Disallow binding to an empty command
This was introduced (most likely accidentally) in
9cbacf3264.

Fixes #3631
2018-03-08 08:14:52 +01:00
Florian Bruhin
d5c04318b2 Fix test/lint 2018-03-08 06:41:15 +01:00
Florian Bruhin
87c6644751 Add predicted_navigation for reload()
This should avoid a double-reload for 'tsh' etc.
2018-03-07 23:54:58 +01:00
Florian Bruhin
b9d26ee268 Add an input.insert_mode.auto_enter setting
Closes #3143
2018-03-07 23:45:19 +01:00
Florian Bruhin
9b9d7647a4 Show the keystring correctly when entering a count 2018-03-07 22:47:31 +01:00
Florian Bruhin
514138aad2 Allow to bind numbers in keybindings
This mostly reverts 4ef5db1bc4 for #1966, but
fixes #3684 by allowing numbers to be bound again. If the user wants to bind
numbers instead of using them for a count, why not let them.
2018-03-07 22:37:10 +01:00
Florian Bruhin
34815f5cf8 Make bindings.default only settable in autoconfig.yml
Fixes #3131
2018-03-07 18:30:44 +01:00
Florian Bruhin
8a60855b88 Fix lint 2018-03-06 21:44:37 +01:00
Florian Bruhin
e2cdb5c8cf Allow empty vlaue for bindings.key_mappings 2018-03-06 21:43:07 +01:00
Florian Bruhin
0d94c17edc Apply key_mappings to KeySequences correctly
Fixes #3678
2018-03-06 21:39:57 +01:00
Florian Bruhin
db7ccb0434 Update config tests for pattern changes 2018-03-06 13:26:22 +01:00
Florian Bruhin
e1a03929e3 Edit changelog 2018-03-06 13:14:00 +01:00
Florian Bruhin
06bccfeb78 Improve error message for QtWebEngine inspector 2018-03-06 12:57:38 +01:00
Florian Bruhin
0236255a7e Require a reload for more settings 2018-03-06 12:57:28 +01:00
Florian Bruhin
b6efe65891 Add input.spatial_navigation to needs_reload
See #3648
2018-03-06 11:33:36 +01:00
Florian Bruhin
3701eb121f Also remove Qt 5.8 from Travis 2018-03-06 11:23:43 +01:00
Florian Bruhin
69a58c9597 Remove Qt 5.8 support and tests
With QtWebKit it's probably okay to still use it (*cough* Hyperbola
GNU/Linux-libre^tm *cough*), and only blacklisting it with QtWebEngine would be
quite some effort.

Fixes #3608
2018-03-06 11:04:59 +01:00
Florian Bruhin
ea1ff1c1ea Regenerate docs 2018-03-06 10:49:59 +01:00
Florian Bruhin
e28a01351b Add toggling to cheatsheet 2018-03-06 10:49:53 +01:00
Florian Bruhin
e3b8372b8b Make UrlPattern._DEFAULT_PORT private 2018-03-06 10:34:02 +01:00
Florian Bruhin
257753841b Allow lightweight URL patterns without a scheme
See #3622
2018-03-06 10:33:55 +01:00
Florian Bruhin
7fc53ae78a Make path optional in URL patterns
See #3622
2018-03-06 09:45:06 +01:00
Florian Bruhin
de3d2b1cb1 Update userscripts 2018-03-06 09:37:00 +01:00
Florian Bruhin
8c0bca90d3 Merge remote-tracking branch 'origin/pr/3456' 2018-03-06 09:32:39 +01:00
Florian Bruhin
2c03bc3410 Update changelog 2018-03-06 07:47:11 +01:00
Florian Bruhin
513bb381d3 Merge remote-tracking branch 'origin/pr/3676' 2018-03-06 07:46:46 +01:00
Florian Bruhin
0a75c5a302 Make sure options in needs_reload are valid 2018-03-06 07:44:20 +01:00
Florian Bruhin
afd5d2c728 Reload page after content.javascript.can_access_keyboard changed
See #3648
2018-03-06 07:41:35 +01:00
Florian Bruhin
0e2a39da2a Fix tests for keyboard parsing change 2018-03-06 07:39:41 +01:00
Florian Bruhin
c9cd47b5b1 Also clear favicons when possible with QtWebEngine
See #3469
2018-03-06 07:38:01 +01:00
Florian Bruhin
41dfa29648 Improve parsing of invalid keys
This should handle "<>" and "\x1f" correctly.
2018-03-06 06:29:38 +01:00
Olmo Kramer
8a193e2dc5 Add hints to <summary> elements 2018-03-06 03:46:40 +01:00
Florian Bruhin
7a9f8fda72 Get rid of unnecessary lambda 2018-03-05 23:07:03 +01:00
Florian Bruhin
2b84ea9dbe Make sure we have plain keys/modifiers where needed 2018-03-05 23:01:24 +01:00
Florian Bruhin
0ee7fac727 Update test_init_unknown/test_init_invalid for KeyboardModifierMask
-1 & Qt.KeyboardModifierMask == Qt.Key_unknown
2018-03-05 22:56:58 +01:00
Florian Bruhin
78f6ad14c2 Use Qt.KeyboardModifierMask 2018-03-05 22:33:16 +01:00
Florian Bruhin
3b957c5f2e Merge pull request #3673 from qutebrowser/pyup-scheduled-update-2018-03-05
Scheduled weekly dependency update for week 09
2018-03-05 22:24:08 +01:00
Florian Bruhin
8deb38e22d Add test for :bind completion with invalid binding 2018-03-05 22:21:57 +01:00
Florian Bruhin
29fdd1acc4 Make sure all keyboard modifiers are handled correctly
This handles Qt.KeypadModifier (Num+...) correctly, adds tests for converting
modifiers to strings, and strips Qt.GroupSwitchModifier as QKeySequence doesn't
know about it.

Fixes #3675
2018-03-05 22:11:26 +01:00
Florian Bruhin
2ab270dfac Also log modifiers for key presses 2018-03-05 19:32:21 +01:00
Florian Bruhin
fb626ca5a8 Update changelog 2018-03-05 18:40:14 +01:00
Florian Bruhin
9be26a8bfd Merge remote-tracking branch 'origin/pr/3666' 2018-03-05 18:38:37 +01:00
Florian Bruhin
333a37ffb2 Fix old macOS-specific test code 2018-03-05 18:30:34 +01:00
Florian Bruhin
9320214429 Only clear favicons on load with QtWebKit
QtWebEngine seems to automatically clear the favicon when loading e.g.
about:blank, and not clearing it there again fixes #3469.
Original issue: #187
2018-03-05 18:29:01 +01:00
Florian Bruhin
43cab4d978 Add bindings to toggle plugins
See #3622
2018-03-05 18:20:06 +01:00
Florian Bruhin
4da8af0e1d Fix preloading resources on Windows
We always pass paths like javascript/scroll.js no matter what the underlying OS
is, so we also need to cache it with a / separator.
2018-03-05 18:08:51 +01:00
Florian Bruhin
a796d1f33f Always enable JavaScript for file://, chrome:// and qute://
See #3622
2018-03-05 17:09:47 +01:00
pyup-bot
0299bd9764 Update pytest-mock from 1.7.0 to 1.7.1 2018-03-05 17:07:19 +01:00
pyup-bot
17e2915876 Update hypothesis from 3.46.0 to 3.48.0 2018-03-05 17:07:18 +01:00
pyup-bot
1006f181e2 Update packaging from 16.8 to 17.1 2018-03-05 17:07:16 +01:00
Florian Bruhin
430d69f278 Fix lint 2018-03-05 16:43:01 +01:00
Florian Bruhin
a1b73fc113 Elide long URLs in acceptNavigationRequest logging 2018-03-05 16:42:14 +01:00
gammelon
a730290d40 Use QUrl for parsing, add tests 2018-03-05 16:32:41 +01:00
Florian Bruhin
cdbff411d0 Fix travis_install for newer Homebrew 2018-03-05 15:51:26 +01:00
Florian Bruhin
d1854eddaf Handle invalid keys coming from Qt
When pressing a key which doesn't exist as Qt.Key, we don't get Qt.Key_unknown
like we'd expect, but we get 0x0 instead...

Let's add that as a new "nil" key (to not conflict with None/unknown/zero/...)
and handle it appropriately.

This can be reproduced by doing:
setxkbmap -layout us,gr -option grp:alt_shift_toggle
and pressing Alt-Shift/Shift-Alt.
2018-03-05 15:42:52 +01:00
Florian Bruhin
52c280ec12 Add unit tests for BaseKeyParser.handle with dry_run=True 2018-03-05 15:33:56 +01:00
Florian Bruhin
3275681afd Show key when the key string is empty 2018-03-05 12:45:13 +01:00
Florian Bruhin
67b4502fdb Fix test_version without cssutils 2018-03-05 11:36:50 +01:00
Florian Bruhin
2f8686ec70 Fix test_mhtml_e2e with Qt 5.11
See #3661
2018-03-05 11:36:29 +01:00
Florian Bruhin
cc5da4d1fe Fix test_modeman.py 2018-03-05 11:08:21 +01:00
Florian Bruhin
b4a2352833 Cache HTML/JS resource files when starting
This mostly reverts 9edc5a665e (see #1362).
Fixes #1943
2018-03-05 09:08:06 +01:00
Florian Bruhin
78623f4ec8 Update changelog
[ci skip]
2018-03-05 08:15:47 +01:00
Florian Bruhin
2a9d970641 Uninstall application proxy factory before exit
This should help with segfaults on exit.
Fixes #3657
2018-03-05 07:39:36 +01:00
Florian Bruhin
274f2a9d19 Rename eventFilter methods in modeman 2018-03-05 06:36:01 +01:00
Florian Bruhin
e01db79ce9 Filter out ShortcutOverride events properly
Fixes #3419
2018-03-05 06:32:54 +01:00
Florian Bruhin
4ef5db1bc4 Disallow numbers in keybindings
Fixes #1966
2018-03-04 23:17:51 +01:00
Florian Bruhin
47525f6a09 Update changelog 2018-03-04 22:58:33 +01:00
Florian Bruhin
155a1901c0 Merge branch 'keys' 2018-03-04 22:50:41 +01:00
Florian Bruhin
88a5c8d29d Make sure bindings with umlauts work
See #303
2018-03-04 22:38:33 +01:00
Florian Bruhin
e2f17c4be1 Always prefer exact over partial matches 2018-03-04 21:45:46 +01:00
Florian Bruhin
40c3295cd1 Improve logging message for clear_keystring 2018-03-04 21:32:42 +01:00
Florian Bruhin
f2fadd7add Fix handling of key_mappings 2018-03-04 21:32:28 +01:00
Florian Bruhin
0967b6abd2 Fix handling of </> keys 2018-03-04 20:40:16 +01:00
Florian Bruhin
910bbc8521 Refactor keyutils._parse_keystring 2018-03-04 20:40:05 +01:00
Florian Bruhin
c9c0bc0bbd Update docs 2018-03-04 20:28:46 +01:00
Florian Bruhin
d8bfe23c0d Fix lint 2018-03-04 20:21:58 +01:00
Florian Bruhin
58b7599152 Remove old fixme 2018-03-04 20:21:58 +01:00
Florian Bruhin
f85e69ec77 Refactor other keyinput tests 2018-03-04 20:21:58 +01:00
Florian Bruhin
2be7db29ed 100% coverage for keyinput.keyutils 2018-03-04 20:21:58 +01:00
Florian Bruhin
8da878c77c Make KeySequence.matchs() work correctly 2018-03-04 20:21:58 +01:00
Florian Bruhin
866c758660 Add more KeySequence tests 2018-03-04 20:21:58 +01:00
Florian Bruhin
68db8d04ad KeySequence: Make sure we got valid key codes 2018-03-04 20:21:58 +01:00
Florian Bruhin
3649a36869 KeySequence: Add __le__/__ge__ 2018-03-04 20:21:58 +01:00
Florian Bruhin
fb7c75a090 Improve keyutils tests 2018-03-04 20:21:58 +01:00
Florian Bruhin
3c9e8ff9ab Test and fix keyutils._parse_keystring 2018-03-04 20:21:58 +01:00
Florian Bruhin
7f8508a367 Change the way Space keybindings are handled
Using it as " " in a keystring won't work anymore, but instead <Space> and
<Shift-Space> does.
2018-03-04 20:21:58 +01:00
Florian Bruhin
da60d11b24 Refactor keyutils tests 2018-03-04 20:21:58 +01:00
Florian Bruhin
b3834835ed Bring back keyutils.is_modifier() and modifier handling
Turns out when we press yY, we get three events:

Qt.Key_Y, Qt.NoModifier
Qt.Key_Shift, Qt.ShiftModifier
Qt.Key_Y, Qt.ShiftModifier

If we don't ignore the second one, our keychain will be interrupted by the Shift
keypress.
2018-03-04 20:21:58 +01:00
Florian Bruhin
e306e2dadb Improve and fix test_is_printable 2018-03-04 20:21:58 +01:00
Fritz Reichwald
d9a88e139c Test for modifiers and corner case 0xFF 2018-03-04 20:21:58 +01:00
Florian Bruhin
3a11a24be0 Fix modifier handling
We don't want to show <Shift-Shift>, but <Ctrl-Shift> should still work
correctly.
2018-03-04 20:21:58 +01:00
Florian Bruhin
7cb781cc92 Simplify handling of modifier-only keys
Now that we don't rely on str(KeyInfo) being empty anywhere, there's no reason
to return an empty string for only-modifier keypresses anymore.

While those keys can't be bound (QKeySequence('Shift') == Qt.Key_unknown)
there's also no reason to explicitly ignore them.
2018-03-04 20:21:57 +01:00
Florian Bruhin
693178c8ee Refactor KeyInfo.__str__
This removes the special handling for macOS, but this is hopefully not needed
anymore as we don't compare strings.
2018-03-04 20:21:57 +01:00
Florian Bruhin
af6e5b1838 Fix lint 2018-03-04 20:21:57 +01:00
Florian Bruhin
fac8d72d8c Capitalize Escape in TestFullscreenNotification 2018-03-04 20:21:57 +01:00
Florian Bruhin
a57fc5c746 Refactor keyutils tests involving all keys 2018-03-04 20:21:57 +01:00
Florian Bruhin
50d2ef3b90 Fix handling of printable control keys in KeyInfo.text() 2018-03-04 20:21:57 +01:00
Florian Bruhin
4223e2f85d Check all keys against QTest::keyToAscii 2018-03-04 20:21:57 +01:00
Fritz Reichwald
d28c323074 Add printable and ismodifier test 2018-03-04 20:21:57 +01:00
Florian Bruhin
934d586286 Fix handling of Shift-Tab aka. Backtab 2018-03-04 20:21:57 +01:00
Florian Bruhin
65a05f334e Fix KeyInfo.__str__ for <Shift-Tab> 2018-03-04 20:21:57 +01:00
Florian Bruhin
4e505d52df Regenerate docs 2018-03-04 20:21:57 +01:00
Florian Bruhin
0aa17bfa33 Simplify unicodedata.category calls 2018-03-04 20:21:57 +01:00
Florian Bruhin
63e05e12ba Fix lint and tests 2018-03-04 20:21:57 +01:00
Florian Bruhin
e26eaaddc2 Add keyutils.is_modifier_key() 2018-03-04 20:21:57 +01:00
Florian Bruhin
1cd86d79d9 Add keyutils.is_printable() 2018-03-04 20:21:57 +01:00
Florian Bruhin
b4d232badd Simplify KeyInfo.text() 2018-03-04 20:20:31 +01:00
Florian Bruhin
2ca15d7667 Add tests for lower-/uppercase text 2018-03-04 20:20:31 +01:00
Florian Bruhin
8c87040cb6 Improve IDs for qt_key fixture 2018-03-04 20:20:31 +01:00
Florian Bruhin
0b6d2c2b0a Make all key names work 2018-03-04 20:20:30 +01:00
Florian Bruhin
601e56d2fa Make test_keyutils work 2018-03-04 20:20:30 +01:00
Florian Bruhin
8f479407a0 key_data: Update key names to reflect reality
Generated by:

import key_data
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QKeySequence

for key in key_data.KEYS:
    attr = key.attribute
    member = getattr(Qt, 'Key_' + attr, None)
    if member is None:
        continue
    name = QKeySequence(member).toString()
    if name != attr:
        try:
            print("    Key('{}', '{}')".format(attr, name))
        except UnicodeEncodeError:
            print("    Key('{}', '{}')  # FIXME".format(attr, name.encode('unicode-escape').decode('ascii')))
    else:
        print()
2018-03-04 20:20:30 +01:00
Florian Bruhin
f714be0ff7 Initial tests on all Qt keys 2018-03-04 20:20:30 +01:00
Florian Bruhin
19512e988b Expose less from keyutils publicly 2018-03-04 20:20:30 +01:00
Florian Bruhin
880da2d143 Add missing default=True for configmodel.bind 2018-03-04 20:20:30 +01:00
Florian Bruhin
2ed480b40a Refactor configmodel.bind 2018-03-04 20:20:30 +01:00
Florian Bruhin
fdc2458657 Fix test_split_count after _handle_key merge 2018-03-04 20:20:30 +01:00
Florian Bruhin
c3485821c7 Adjust copyright 2018-03-04 20:20:30 +01:00
Florian Bruhin
77e0b8983c Point to Debian repos for .deb downloads
[ci skip]
Fixes #3669
2018-03-04 18:51:16 +01:00
Jimmy
6d415b6653 Greasemonkey: don't inject JS into dead frames
Hopefully closes #3627

This feels like fixing the symptom instead of the problem but I am not
sure how such a situation would arise. Never the less, the crash logs
clearly show that `_inject_userjs()` is being called with a deleted
frame sometimes. It is being called from a closure that gets triggered
on frame.loadFinished so I am not sure how frame could be deleted at
that time unless:
* the error message is misleading and it is actually some reference to
  the object that is no longer valid
* the frame gets deleted from some other handler of loadFinished.
2018-03-03 15:10:44 +13:00
Jimmy
0adda22d3c Greasemonkey: add a way to register scripts directly.
Previously to add a greasemonkey script you had to write it to the
greasemonkey data directory and call load_scripts(). Now you can just
make a new GreasemonkeyScript and pass it to add_script(), yay.

There are no users of the method yet although I could have used it while
writing the tests.
2018-03-03 15:02:43 +13:00
Jimmy
7dab8335e2 Greasemonkey: handle downloads that complete fast
When `@require`ing local files (with the `file://` scheme) the
greasemonkey manager was not catching the DownloadItem.finished signal
because it was being emitted before it had managed to connect.

I didn't see this happening while testing with files that should have
been in cache but I wouldn't be surprised.

I had to change the download mock to be able to give it the appearance
of asynchronicity. Now when using it one must set download.successful
appropriately before firing download.finished. I also added a list of
downloads to the stub so a test could enumerate them in case the
unit-under-test didn't have a reference to them.
2018-03-03 15:02:43 +13:00
Jimmy
87a0c2a7a7 Greasemonkey: indent source of required scripts
This is for the case where a script uses `@require` to pull down another
greasemonkey script. Since QWebEngineScript doesn't support `@require`
we pass scripts to it with any required ones pre-pended. To avoid
QWebEngineScript parsing the first metadata block, the one from the
required script, we indent the whole lot. Because the greasemonkey spec
says that the //==UserScript== text must start in the first column.
2018-03-03 15:02:42 +13:00
Jimmy
60e6d28eb1 Greasemonkey: webkit: Don't use Object.entries in js.
Apparently the currently available QtWebkit's javascript engine doesn't
support Object.entries[1]. It was only using that because I had copied
it from the official gm4 polyfill (maybe I should open an issue there?).

Tested with libqt5webkit5 version 5.212.0~alpha2-5 (debian) and I was
getting the same type of failures as Travis so it looks like this is the
case in arch too.

[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
2018-03-03 15:02:42 +13:00
Jimmy
919fe45813 Greasemonkey: Add test for @require support.
There's is a lot of asserts in that one test but it tests everything.
2018-03-03 15:02:42 +13:00
Jimmy
fa1ac8d93c Move download_stub to helpers/fixtures
I am adding support for downloading dependant assets in
browser/greasemonkey and want to mock the download manager for testing.
2018-03-03 15:02:42 +13:00
Jimmy
cba93954cd Allow download_stub test fixture to handle file targets. 2018-03-03 13:14:49 +13:00
Jimmy
2307a0850f Greasemonkey: Support greasemonkey-reload --force.
Added a new argument to the greasemonkey-reload command to support
also re-downloading any `@required` scripts.
2018-03-03 13:14:49 +13:00
Jimmy
b91e2e3267 Allow download manager to overwrite existing files unprompted.
This is to support the non-interactive use case of setting a
`FileDownloadTarget` and passing auto_remove and not caring if the target
file exists or not.

An alternative to adding the attribute to `FileDownloadTarget` and
having set_target pull it out would be to add a new param to `fetch()`
and `set_target()`. But it would only be used for one target type
anyway.
2018-03-03 13:14:49 +13:00
Jimmy
a7b74d8e83 Greasemonkey: give required scripts a readable filename. 2018-03-03 13:14:49 +13:00
Jimmy
33d66676c9 Greasemonkey: mock the new GM4 promises based API.
Based on the gm4-polyfill.js script from the greasemonkey devs. But not
the same because that script doesn't work for us for a couple of
reasons:

* It assumes all GM_* functions are attributes of `this` which in
this case is the global window object. Which breaks it out of our iife.
It is possible to change what `this` is within the iife but then we
would have to do something weird to ensure the functions were available
with the leading `this.`. And I don't think user javascripts tend to
call GM functions like that anyway, that polyfill script is just making
weird assumptions and then claiming it'll work for "any user script
engine".

* It tries to provide implementations of GM_registerMenuCommand and
GM_getResource text which do unexpected thins or implement a circular
dependency on the new version, respectively.
2018-03-03 13:14:49 +13:00
Jimmy
a76c0067e1 Greasemonkey: Add support for the @require rule.
The greasemonkey spec states that user scripts should be able to put the URL
of a javascript source as the value of an `@require` key and expect to have
that script available in its scope. This commit supports deferring a user
script from being available until it's required scripts are downloaded,
downloading the scripts and prepending them onto the userscripts code before
placing it all in an iffe.

TODO:
* should I be saving the scripts somewhere else? Maybe the cache dir?
  The are just going to data/greasemonkey/requires/ atm.
2018-03-03 13:14:49 +13:00
Florian Bruhin
02c313eafd Add packages needed with tox 2018-03-02 10:22:59 +01:00
Florian Bruhin
be7a21eb56 Make sure the backend is set in test_webenginesettings.py 2018-03-02 07:00:09 +01:00
Florian Bruhin
b0c25e1bed Add missing )
I shouldn't be allowed to push at 6:30 AM...
2018-03-02 06:58:37 +01:00
Florian Bruhin
9721881261 Adjust @issue3572 check for Qt 5.10.1 2018-03-02 06:37:01 +01:00
Florian Bruhin
5d68dc08d5 Update changelog 2018-03-02 06:35:04 +01:00
Florian Bruhin
067be7aaa2 Simplify mock checks 2018-03-02 06:33:56 +01:00
Florian Bruhin
6fc560fc78 Rewrite comment 2018-03-02 06:31:23 +01:00
Florian Bruhin
fb7fa0cb49 Merge remote-tracking branch 'origin/pr/3652' 2018-03-02 06:31:00 +01:00
Florian Bruhin
52129f2e4d Merge remote-tracking branch 'origin/pr/3659' 2018-03-02 06:30:52 +01:00
Ryan Roden-Corrent
d5e30fd728 Don't crash first completion update with min_chars.
When min_chars is nonzero, if the first command that opens the
completion has < min_chars on the word under the cursor, it triggers a
check for a condition where last_cursor_pos is None.

By setting last_cursor_pos=-1 we ensure that the completer always
updates the first time it is opened, and that there is never a check
against None.

This adds a test for the min_chars feature.

Resolves #3635.
2018-03-01 22:07:53 -05:00
Jay Kamat
a2b5bf0b73 Clear old search results on webkit
Fixes an issue with #3626
2018-03-01 16:15:38 -05:00
Ryan Roden-Corrent
2965f954ba Resolve empty completion.timestamp_format crash.
Resolves #3628.
2018-03-01 07:54:20 -05:00
Florian Bruhin
257011a6d2 Fix installing codecov on Travis 2018-03-01 12:56:43 +01:00
Florian Bruhin
f33d659924 Release v1.1.2 2018-03-01 09:15:54 +01:00
Florian Bruhin
b14a37cf1f Update changelog for v1.1.2
[ci skip]
2018-02-28 16:14:34 +01:00
Florian Bruhin
7fd0b52360 Add missing newline
[ci skip]
2018-02-28 08:11:23 +01:00
Florian Bruhin
8ea6cf352b Remove unneeded version check
The option isn't going to magically change as the config system prevents that.
2018-02-28 08:08:47 +01:00
Florian Bruhin
f3aaa1084a Migrate spell tests to unittests 2018-02-28 08:08:23 +01:00
Florian Bruhin
824825e67d Make sure we only show dictionary warnings once
After 3956f81e73 where this was made a function,
the warning was shown twice, causing AppVeyor to fail.
2018-02-28 08:01:11 +01:00
Florian Bruhin
889b03169a Upgrade to PyQt 5.10.1 2018-02-28 06:28:01 +01:00
Florian Bruhin
e6aa6b8235 Add missing docs for {url:host} 2018-02-27 17:29:36 +01:00
Florian Bruhin
5eb340d481 Add missing tests for completions 2018-02-27 15:55:00 +01:00
Florian Bruhin
60f0175a36 Fix getting customized options
This was broken with per-domain settings
Fixes #3649
2018-02-27 15:39:57 +01:00
Florian Bruhin
5a5873d4ee Rename KeyConfig._prepare to ._validate 2018-02-27 14:16:41 +01:00
Florian Bruhin
49d297f7bf Fix tests for parsing KeySequences 2018-02-27 14:10:55 +01:00
Florian Bruhin
b85fe8f678 Merge BaseKeyParser._handle_key into .handle 2018-02-27 14:08:38 +01:00
Florian Bruhin
3a79f1293f Remove FIXMEs 2018-02-27 13:10:25 +01:00
Florian Bruhin
244590f49d Handle unknown keys with :bind/:unbind 2018-02-27 13:09:48 +01:00
Florian Bruhin
88b5007457 Consolidate invalid :bind/:unbind tests 2018-02-27 13:02:32 +01:00
Florian Bruhin
7a27469ecd Handle unknown keys in :bind completion 2018-02-27 13:02:32 +01:00
Florian Bruhin
8090d3e289 Handle invalid keys in config.py 2018-02-27 13:02:32 +01:00
Florian Bruhin
898f5c50c4 Add a test for utils.chunk 2018-02-27 13:02:32 +01:00
Florian Bruhin
bd87b4eb10 Stop logging in PassthroughKeyParser 2018-02-27 13:02:32 +01:00
Florian Bruhin
ec3ad8a969 Get rid of _warn_on_keychains and _supports_chains 2018-02-27 13:02:32 +01:00
Florian Bruhin
ba012c6ba8 Get rid of BaseKeyparser.Type 2018-02-27 13:01:41 +01:00
Florian Bruhin
b906d92053 Remove now uneeded pylint ignore 2018-02-27 10:06:11 +01:00
Florian Bruhin
72e30cc12c Fix following hints 2018-02-27 09:47:06 +01:00
Florian Bruhin
079fcc7eea Add FIXME 2018-02-27 09:38:40 +01:00
Florian Bruhin
c0e2550046 Fix scripts.keytester 2018-02-27 09:36:56 +01:00
Florian Bruhin
362f923f06 Fix lint 2018-02-27 09:34:55 +01:00
Florian Bruhin
f18b5aa782 Fix searching for blacklisted keys in keyhintwidget 2018-02-27 09:23:06 +01:00
Florian Bruhin
5d581d42f5 Improve key parsing with simple keys containing </> 2018-02-27 09:22:11 +01:00
Florian Bruhin
1ba61bbcbe Fix test_modeparsers 2018-02-27 09:22:01 +01:00
Florian Bruhin
911b2daebf Fix test_keyutils 2018-02-27 09:07:20 +01:00
Florian Bruhin
5a03d31f6f More test_basekeyparser fixes 2018-02-27 08:53:28 +01:00
Florian Bruhin
eeeb763f8a Make sure 0 is handled as command 2018-02-27 08:50:50 +01:00
Florian Bruhin
9e27f2b3e7 Initial attempts at fixing test_basekeyparser 2018-02-27 08:48:16 +01:00
Florian Bruhin
44b4cb92be Make keyutils.KeySequence.parse('') work 2018-02-27 08:35:14 +01:00
Florian Bruhin
ac4fd7c563 Add KeyInfo.to_event() 2018-02-27 08:20:06 +01:00
Florian Bruhin
1e8f72dfe6 Adjust test_configtypes 2018-02-27 08:10:54 +01:00
Florian Bruhin
f40f4082ba Validate configtypes.Key correctly 2018-02-27 07:56:34 +01:00
Florian Bruhin
612387633d Adjust test_configfiles 2018-02-27 07:53:29 +01:00
Florian Bruhin
e8d5fb5cca Normalize keybinding with :bind 2018-02-27 07:51:14 +01:00
Florian Bruhin
214e750c69 Adjust test_configcommands.py 2018-02-27 07:51:07 +01:00
Florian Bruhin
b1f4b1eaba Fix :unbind with already bound keys
The previous change was incorrect and caused a regression (test_unbound_twice)
2018-02-27 07:40:54 +01:00
Florian Bruhin
49f8bc3d63 Use KeySequences correctly in test_config.py 2018-02-27 07:37:55 +01:00
Florian Bruhin
fa29a0b686 Expect capitalized bindings in test_models 2018-02-27 06:58:39 +01:00
Florian Bruhin
1b0aea5e05 Bring simple bindings to front in get_reverse_bindings_for 2018-02-27 06:56:57 +01:00
Florian Bruhin
8416e97c6c Fix type which is stubbed in test_models 2018-02-27 06:50:57 +01:00
Florian Bruhin
93ff9006ad Merge remote-tracking branch 'origin/pr/3643' 2018-02-27 06:24:33 +01:00
Florian Bruhin
bc3e1b316d Use "command -v" instead of "which" in bash scripts
shellcheck recently added SC2330 checking for this. "which" is non-standard, and
not guaranteed by POSIX to have a meaningful exit status, while "command -v" is
specified by POSIX: https://stackoverflow.com/q/592620
2018-02-27 06:23:00 +01:00
Florian Bruhin
53fb5af99c Paste version information privately 2018-02-26 23:09:55 +01:00
Florian Bruhin
01462008c9 Clearly separate yesno/prompt key modes 2018-02-26 22:49:15 +01:00
Florian Bruhin
d9ae3fd5aa Fix more hinting issues 2018-02-26 20:49:02 +01:00
Florian Bruhin
de3b4adfd8 Don't force-follow hints when typing chars 2018-02-26 20:48:49 +01:00
Florian Bruhin
6fc391986f Fix KeyInfo.text() for space 2018-02-26 20:48:22 +01:00
Florian Bruhin
e9d58dae2a Fix getting individual items from KeySequence 2018-02-26 20:48:11 +01:00
Florian Bruhin
9f0e1a98a0 Make hint keybinding inhibition work 2018-02-26 20:22:52 +01:00
Florian Bruhin
8bce2ba8e8 Fix expected message 2018-02-26 20:03:21 +01:00
Florian Bruhin
f1b20f6dc4 Fix forward_unbound_keys test 2018-02-26 20:02:43 +01:00
pyup-bot
416712d2dc Update pytest from 3.4.0 to 3.4.1 2018-02-26 17:04:18 +01:00
pyup-bot
3dedd0d178 Update hypothesis from 3.45.2 to 3.46.0 2018-02-26 17:04:17 +01:00
Florian Bruhin
1444634abb Fix :fake-key test 2018-02-26 14:26:12 +01:00
Florian Bruhin
bb647123b7 Fix invalid key sequences 2018-02-26 14:13:46 +01:00
Florian Bruhin
2698b8bb63 Fix unicodedata check 2018-02-26 13:47:45 +01:00
Florian Bruhin
f15e2285ba Fix bindings.key_mappings 2018-02-26 13:41:01 +01:00
Florian Bruhin
0afaf2ce89 Fix capital chars after string change 2018-02-26 11:48:10 +01:00
Florian Bruhin
508a12a84c Try fixing KeyInfo.__str__ with lower-/uppercase chars 2018-02-26 11:36:24 +01:00
Florian Bruhin
1609e0d445 Fix keyhint widget 2018-02-26 11:16:56 +01:00
Florian Bruhin
16940db834 Refactor KeySequence initialization 2018-02-26 11:16:51 +01:00
Florian Bruhin
f92bb16408 Make config.bind work 2018-02-26 10:38:59 +01:00
Florian Bruhin
9aa37febbe Make hints work 2018-02-26 10:33:18 +01:00
Florian Bruhin
be4cd94207 Try getting hints to work 2018-02-26 10:14:30 +01:00
Florian Bruhin
d077f38ac4 Store multiple QKeySequences in KeySequence 2018-02-26 09:13:53 +01:00
Florian Bruhin
79a337767a Initial work at making :fake-key work 2018-02-26 09:13:44 +01:00
Florian Bruhin
cdf6f52d15 Update changelog
[ci skip]
2018-02-26 08:15:34 +01:00
Florian Bruhin
6f9c62b24a Improve marker descriptions 2018-02-26 07:56:51 +01:00
Florian Bruhin
353753c03c Merge remote-tracking branch 'origin/pr/3620' 2018-02-26 07:26:24 +01:00
Florian Bruhin
de0aa32c11 Merge remote-tracking branch 'origin/pr/3626' 2018-02-26 07:20:34 +01:00
Florian Bruhin
edd2f89d5d Update changelog 2018-02-26 07:16:55 +01:00
Florian Bruhin
bd79d7e071 Merge remote-tracking branch 'origin/pr/3637' 2018-02-26 07:16:19 +01:00
Jay Kamat
76bf35cbdd Add qtbug60673 markers to relevant tests 2018-02-25 19:00:15 -05:00
Jay Kamat
7a8fa5f46e Implement deduplication of searches on webkit 2018-02-25 18:40:16 -05:00
Florian Bruhin
e273f163a6 Add a KeyInfo class 2018-02-25 22:09:39 +01:00
Anton S
eeb565319f Handle invalid URLs on Apple events 2018-02-25 23:58:49 +03:00
Florian Bruhin
321d5c5d20 Merge branch 'master' into keys 2018-02-25 21:25:12 +01:00
Florian Bruhin
3df066c694 Update changelog 2018-02-25 21:10:35 +01:00
Florian Bruhin
54713f57e5 Merge remote-tracking branch 'origin/pr/3624' 2018-02-25 21:09:56 +01:00
Florian Bruhin
a98466336e Update changelog 2018-02-25 19:58:23 +01:00
Florian Bruhin
52b5492c6a Merge branch 'per-url' 2018-02-25 19:44:51 +01:00
Florian Bruhin
ba88fc43e0 Stabilize error page test 2018-02-25 19:40:38 +01:00
Florian Bruhin
abf4d10d5b Add a test for :set -p with a pattern 2018-02-25 19:33:27 +01:00
Florian Bruhin
4c147b77c1 Add a test for the error page workaround 2018-02-25 16:35:02 +01:00
Florian Bruhin
a32d74e983 Fix lint 2018-02-25 16:08:15 +01:00
Florian Bruhin
d44ff5ba01 Don't load the URL immediately on :undo
On some pages like Qt's Gerrit, Indiegogo or Telegram Web, this caused a crash
with QtWebEngine and Qt 5.10.1 in
QtWebEngineCore::WebContentsAdapter::webContents().

I'm not sure what causes the crash exactly, but I'm guessing it's some kind of
race condition between loading the URL initially and deserializing the history,
which both ends up loading the URL.

Since restoring the history means we end up on the given URL anyways, let's just
not open the URL beforehand, which seems to fix this.

Fixes #3619.
2018-02-25 15:55:20 +01:00
Florian Bruhin
97e00ba4b5 Only reload after setting changes when needed
Apparently, things work fine with Type.link_clicked even if we don't emit
predicted_navigation there...
2018-02-25 15:17:03 +01:00
Florian Bruhin
eade305965 Add a predicted_navigation signal
This is emitted when we know that we're going to visit some URL, but Qt doesn't
know yet. This way, we can change the settings early, and since we know which
settings have actually changed, prevent a change needing a reload in
_on_navigation_request.
2018-02-25 15:04:04 +01:00
Florian Bruhin
65a62b67a5 Go back to using tab.openurl on config changes
This seems to work most reliably at the moment...
2018-02-25 14:45:30 +01:00
Florian Bruhin
638e880604 Improve workaround for missing error pages 2018-02-25 14:45:30 +01:00
Florian Bruhin
bfb3a6594f Try using tab.reload() on setting changes instead 2018-02-25 14:45:19 +01:00
Florian Bruhin
08bc55995b First attempt at reloading pages after setting changes 2018-02-25 14:45:09 +01:00
Jay Kamat
4602afe770 Add a webengine duplicate search test 2018-02-23 18:13:20 -05:00
Jay Kamat
820ffed07f Remove test blacklists for 5.10 2018-02-23 18:06:57 -05:00
Jay Kamat
f926e7b850 Emulate webkit duplicate search behavior on webengine 2018-02-23 18:06:21 -05:00
Florian Bruhin
2c96446bb9 Track which settings changed for a URL
This is currently only used so only changed settings are logged, but will used
for more in the next commit.
2018-02-23 18:11:33 +01:00
Florian Bruhin
75b65e2f11 Simplify attribute handling in Web(Kit|Engine)Settings
Let's just have lists in _ATTRIBUTES for WebEngineSettings as well, that allows
us to share some more code.
2018-02-23 17:59:12 +01:00
Florian Bruhin
fc6a0dbe64 Show a simple error page on loading errors without JS
We can't tell what exactly the error is, but it's surely better than nothing.
2018-02-23 17:29:17 +01:00
Florian Bruhin
98b2b67b8b Add tests for per-URL JavaScript settings 2018-02-23 15:08:07 +01:00
Florian Bruhin
3956f81e73 Refactor websettings
This refactors the whole web(kit|engine|) settings mess a bit so there's a
Web(Kit|Engine)Settings object for (non-static) settings set on a
QWeb(Engine)Settings object in Qt. Everything else is set on module-level a bit
less declaratively.

The whole inheritance mess is gone, and we can now also construct a
Web(Kit|Engine)Settings object for a given tab.

Fixes #2701
2018-02-23 09:51:28 +01:00
Florian Bruhin
49ead32f13 Update urlmatch tests for Chromium changes
See:
0ab1294c92%5E%21/
https://bugs.chromium.org/p/chromium/issues/detail?id=812543
2018-02-23 06:31:49 +01:00
Jay Kamat
cb8d62866c Blacklist qt versions 5.8.0 through 5.9.4 for caret tests 2018-02-22 18:34:15 -05:00
Jay Kamat
7ecbae765d Use baseNode over anchorNode in follow-selected
baseNode isn't documented anywhere that I can find, but it seems to be
getting us what anchorNode used to get us.
2018-02-22 16:42:58 -05:00
Jay Kamat
c16c625feb Add basic tests for searching and caret mode 2018-02-22 10:28:35 -05:00
Florian Bruhin
eb4c806ddb Add URL pattern to settings output 2018-02-22 08:07:54 +01:00
Florian Bruhin
5c4277aac8 Add some default keybindings for toggling scripts
Those follow the following pattern:

1) "t" for 'toggle"
2) "s" for "scripts", upper-casing ("S") to make the toggle permanent
3) "h" for host, "H" for host with subdomains, "u" for the exact URL
2018-02-22 08:07:54 +01:00
Jay Kamat
2ffb1604d3 Convert search to blue selection when entering caret mode 2018-02-21 10:01:27 -05:00
Florian Bruhin
ada15510a7 Update changelog 2018-02-21 11:07:55 +01:00
Florian Bruhin
81c17627f7 Merge remote-tracking branch 'origin/pr/3617' 2018-02-21 11:06:52 +01:00
Florian Bruhin
d2e996a3b3 Merge remote-tracking branch 'origin/pr/3610' 2018-02-21 11:06:05 +01:00
Florian Bruhin
d2182edc7a Merge remote-tracking branch 'origin/pr/3603' 2018-02-21 11:03:37 +01:00
Florian Bruhin
ca26d97589 Merge remote-tracking branch 'origin/pr/3599' 2018-02-21 11:02:51 +01:00
Florian Bruhin
13bd4dd05d Clean up version.pastebin_url in pbclient fixture 2018-02-21 10:49:42 +01:00
Florian Bruhin
2fbc7b4e1d Merge remote-tracking branch 'origin/pr/3594' 2018-02-21 10:15:27 +01:00
Florian Bruhin
8b09003bd1 Merge remote-tracking branch 'origin/pr/3592' 2018-02-21 10:13:26 +01:00
Florian Bruhin
ecfd4a77a0 Merge remote-tracking branch 'origin/pr/3562' 2018-02-21 10:11:40 +01:00
Florian Bruhin
cfeeb7460b Add docstrings to ConfigAPI 2018-02-21 09:14:49 +01:00
Florian Bruhin
ea6a5de374 Update FIXMEs 2018-02-20 23:28:11 +01:00
Florian Bruhin
0d4e20c395 Whitelist config options which support URL patterns 2018-02-20 23:26:22 +01:00
Florian Bruhin
6c5876a494 Fix tests broken by urlmatch trailing slash change 2018-02-20 23:08:09 +01:00
Florian Bruhin
5fbd488fdf Only change settings for main-frame navigations 2018-02-20 22:45:29 +01:00
Florian Bruhin
18848315f5 urlmatch: Make it possible to leave off trailing slash 2018-02-20 22:45:16 +01:00
Florian Bruhin
17b235b523 Add error handling for parsing patterns from YAML 2018-02-20 22:29:21 +01:00
Florian Bruhin
46aeb25e7e Fix lint 2018-02-20 20:55:42 +01:00
Florian Bruhin
439d51875f Add config.pattern() 2018-02-20 20:54:26 +01:00
Florian Bruhin
de38566c11 Update configuring.asciidoc with per-domain settings 2018-02-20 18:43:51 +01:00
Florian Bruhin
3ade923edb Add basic pattern support for config.py 2018-02-20 18:43:42 +01:00
gammelon
16218a9900 Remove unnecessary try, rephrase to imperative mood 2018-02-20 18:11:50 +01:00
Florian Bruhin
a3dfec20c1 Rename --url to --pattern 2018-02-20 17:56:47 +01:00
Florian Bruhin
f8b1e7739d Update docs 2018-02-20 17:56:47 +01:00
Florian Bruhin
9685445559 Fix issues with Python 3.5 2018-02-20 17:56:47 +01:00
Florian Bruhin
e482c76874 YamlConfig: Refuse to read a newer config version 2018-02-20 17:08:28 +01:00
Florian Bruhin
03114ccf51 Migrate YAML config files in old format 2018-02-20 16:14:06 +01:00
Florian Bruhin
b3d788fead Add YamlConfig._pop_object 2018-02-20 15:46:05 +01:00
Marco Zollinger
96e8151cce use up to date cheatsheet images from repo instead of qutebrowser.org 2018-02-20 15:18:31 +01:00
Florian Bruhin
9595aaf897 Merge pull request #3614 from qutebrowser/pyup-scheduled-update-2018-02-19
Scheduled weekly dependency update for week 07
2018-02-20 13:48:53 +01:00
Florian Bruhin
f2bba2e4fa Fix navigation handling 2018-02-20 12:30:41 +01:00
Florian Bruhin
ae73215724 Fix lint 2018-02-20 12:30:41 +01:00
Florian Bruhin
b9bb515b3b Add missing configfiles tests 2018-02-20 12:30:41 +01:00
Florian Bruhin
9c42d87e7d Add missing configutils test 2018-02-20 12:30:34 +01:00
Florian Bruhin
05017c83d6 Add more config tests 2018-02-20 12:30:34 +01:00
Florian Bruhin
d511c5436d Remove dead config code 2018-02-20 12:30:34 +01:00
Florian Bruhin
36f3e54e1d Finish configutils tests 2018-02-20 12:30:34 +01:00
Florian Bruhin
19c00ff92a configutils: Clean up comments 2018-02-20 12:30:34 +01:00
Florian Bruhin
63c77a4d76 urlmatch: Fix equality with non-UrlPattern types 2018-02-20 12:30:34 +01:00
Florian Bruhin
685e3ffcfe Fix and test UrlPattern/configutils.Values stringification 2018-02-20 12:30:34 +01:00
Florian Bruhin
145a21449b configutils: Add first tests 2018-02-20 12:30:34 +01:00
Florian Bruhin
50c847562f configutils.Values: Make it possible to pass values 2018-02-20 12:30:34 +01:00
Florian Bruhin
ab02fcb116 configutils.Values: Add __repr__ 2018-02-20 12:30:34 +01:00
Florian Bruhin
316b4b5340 Add new files to PERFECT_FILES 2018-02-20 12:30:34 +01:00
Florian Bruhin
7fcb21573d Update backers file 2018-02-20 08:52:16 +01:00
Florian Bruhin
5978b7b35f config: Improve tests for non-existent options 2018-02-19 22:09:54 +01:00
Florian Bruhin
463320b599 Make test_config.py work 2018-02-19 22:09:54 +01:00
Florian Bruhin
1ada821092 Make sure config options exist 2018-02-19 22:09:54 +01:00
Florian Bruhin
cea664e396 Don't emit changed in unset if unneeded 2018-02-19 22:09:54 +01:00
Florian Bruhin
fecebd6ced Start getting test_config.py to run 2018-02-19 22:09:49 +01:00
Florian Bruhin
7d80825853 Fix test_configfiles.py 2018-02-19 22:09:46 +01:00
Florian Bruhin
ab119975e7 Only emit changed in unset if there was a change 2018-02-19 22:09:46 +01:00
Florian Bruhin
8fead148e2 Add FIXME 2018-02-19 22:09:46 +01:00
Florian Bruhin
1409f4e564 Fix migration of tabs.persist_mode_on_change 2018-02-19 22:09:46 +01:00
Florian Bruhin
5d63dfb24c Start fixing test_configfiles.py 2018-02-19 22:09:46 +01:00
Florian Bruhin
19148a4593 Fix :config-unset 2018-02-19 22:09:46 +01:00
Florian Bruhin
615c6ffe5a Make :config-write-py work again 2018-02-19 22:09:46 +01:00
Florian Bruhin
0f907b1a77 Fix getting YAML values in test_configcommands.py 2018-02-19 22:09:46 +01:00
Florian Bruhin
75181e16fa Fix test_models.py
The Config object got initialized via the config_stub fixture early, so we need
to force it to re-init its values after patching configdata.DATA.
2018-02-19 22:09:46 +01:00
Florian Bruhin
19f7b92abb Fix test_configinit.py 2018-02-19 22:09:43 +01:00
Florian Bruhin
c89e804653 Fix handling of invalid types in YamlConfig 2018-02-19 22:08:42 +01:00
Florian Bruhin
87e329aee3 Fix config.dump_userconfig() with defaults 2018-02-19 22:08:42 +01:00
Florian Bruhin
5eeb223338 Use a different directory for file prompt tests
This way they aren't influenced by the config_tmpdir fixture.
2018-02-19 22:08:42 +01:00
Florian Bruhin
f43c7fa360 Fix changing values in configutils.Values 2018-02-19 22:08:42 +01:00
Florian Bruhin
d3e8d46593 Use a real YamlConfig for tests 2018-02-19 22:08:42 +01:00
Florian Bruhin
cb631d532a Fix getting global value from configutils.Values 2018-02-19 22:08:42 +01:00
Florian Bruhin
8b666d2d2e Try to update settings in acceptNavigationRequest
This still doesn't seem to update them early enough?
2018-02-19 22:08:42 +01:00
Florian Bruhin
bd6e99158e Get rid of the second deepcopy for config values
There were two reasons why we deepcopy mutable objects in the config:

1) So mutations don't mess with our internal/default values.
2) So we can detect mutations and update the config.

If we're going to copy the value for 1) in maybe_copy(), we know the original
value is not going to be mutated, so we can use that directly for self._mutables
instead of making another copy.
2018-02-19 22:07:53 +01:00
Florian Bruhin
93972ff3f1 Copy value before watching it for mutations in config
If we copy it afterwards, we are going to mutate the copied object.
2018-02-19 22:07:53 +01:00
Florian Bruhin
ddb914dc65 Refactor YAML init 2018-02-19 22:07:53 +01:00
Florian Bruhin
8504ad6ff3 Change how iterating over Config/YamlConfig works 2018-02-19 22:07:53 +01:00
Florian Bruhin
6abb42a066 Make saving in autoconfig.yml work 2018-02-19 22:07:53 +01:00
Florian Bruhin
4691753965 Avoid running change handlers on config.clear 2018-02-19 22:07:53 +01:00
Florian Bruhin
9c670e13ce Make clearing config work 2018-02-19 22:07:53 +01:00
Florian Bruhin
a6b979539d Add missing configutils.py 2018-02-19 22:07:53 +01:00
Florian Bruhin
14a69d9047 Fix lint 2018-02-19 22:07:53 +01:00
Florian Bruhin
7c1fb1d215 Refactor acceptNavigationRequest handling to use signals 2018-02-19 22:07:53 +01:00
Florian Bruhin
2a7998847f Unset values properly 2018-02-19 22:07:53 +01:00
Florian Bruhin
74a7676111 Fix issues with per-domain proof-of-concept 2018-02-19 22:07:53 +01:00
Florian Bruhin
d09afdf0ee Refactor handling of mutables with url/pattern in Config
This also should not copy stuff coming from the config if it's not needed.
2018-02-19 22:07:53 +01:00
Florian Bruhin
8551288efb Start working on different per-URL storage 2018-02-19 22:07:53 +01:00
Florian Bruhin
5e50824042 Broken per-URL proof-of-concept 2018-02-19 22:07:53 +01:00
Florian Bruhin
4ed07d6062 Initial implementation of per-URL setting storage 2018-02-19 22:07:53 +01:00
Florian Bruhin
894da598d6 urlmatch: Remove dead code 2018-02-19 22:07:53 +01:00
Florian Bruhin
7033af816a urlmatch: Add equality testcases 2018-02-19 22:07:53 +01:00
Florian Bruhin
eda15c53ad urlmatch: Improve port error output 2018-02-19 22:07:53 +01:00
Florian Bruhin
d6ea9b1e47 urlmatch: Add test for invalid IPv6 URL 2018-02-19 22:07:53 +01:00
pyup-bot
8a0be83e1e Update pytest-mock from 1.6.3 to 1.7.0 2018-02-19 17:04:13 +01:00
pyup-bot
11579b3511 Update hypothesis from 3.44.26 to 3.45.2 2018-02-19 17:04:12 +01:00
bttner
e169e2165d Refactor TabbedBrowser from inheritance to composition 2018-02-19 14:29:05 +01:00
Jay Kamat
84907d5a2e Simplify readability logic using get defaults
:D
2018-02-18 14:49:09 -05:00
Jay Kamat
c844023077 Use QUTE_DATA_DIR in readability userscript 2018-02-18 14:28:46 -05:00
Florian Bruhin
ab0034f9da Merge pull request #3607 from rasa/patch-1
Add scoop installer
2018-02-18 11:30:25 +01:00
Ross Smith II
bf72d81bd3 Add scoop installer
See https://github.com/lukesampson/scoop-extras/pull/783
2018-02-18 00:07:02 -08:00
jnphilipp
60a7e483af Add import error message for stem. 2018-02-17 19:57:44 +01:00
gammelon
42ac3dcda0 Add Option url.open_base_url
when set to true, invoking a searchengine shortcut without argument
opens the baseurl of that searchengine instead of DEFAULT searchengine
2018-02-17 11:21:22 +01:00
jnphilipp
6219119476 Update output. 2018-02-17 09:48:39 +01:00
jnphilipp
3ee765869d Add tor_identity userscript. 2018-02-16 14:22:08 +01:00
Florian Bruhin
174dd5dd9e urlmatch: Remove performance FIXME 2018-02-15 18:47:07 +01:00
Florian Bruhin
5f6c8435a4 urlmatch: Add initial benchmark/hypothesis test 2018-02-15 18:47:07 +01:00
Florian Bruhin
41b7ac27d7 urlmatch: Postpone checking scheme 2018-02-15 18:47:07 +01:00
Florian Bruhin
5627a63265 urlmatch: Fix lint 2018-02-15 18:47:07 +01:00
Florian Bruhin
e161458f91 urlmatch: Add test cases for oddballs 2018-02-15 18:47:07 +01:00
Florian Bruhin
33b7c4bdd0 urlmatch: Fix and test port handling 2018-02-15 18:47:07 +01:00
Florian Bruhin
45cc1aaeb0 urlmatch: Add tests for file:// 2018-02-15 18:47:07 +01:00
Florian Bruhin
a2836ba945 urlmatch: Make sure URLs are valid 2018-02-15 18:47:07 +01:00
Florian Bruhin
0a10a4f751 urlmatch: Add more tests for special schemes 2018-02-15 18:47:07 +01:00
Florian Bruhin
084d3de65b urlmatch: Add support for data: and javascript: 2018-02-15 18:47:07 +01:00
Florian Bruhin
dae164abee urlmatch: Get rid of scheme whitelist
There are more schemes like data: or javascript:, and we don't want to restrict
schemes anyways.
2018-02-15 18:47:03 +01:00
Florian Bruhin
28aadc4f96 urlmatch: Add tests for <all_urls> 2018-02-15 18:47:03 +01:00
Florian Bruhin
867f2a8e2b urlmatch: Use None for match-all path 2018-02-15 18:47:03 +01:00
Florian Bruhin
8fd0690959 urlmatch: Fix handling of *:// as scheme 2018-02-15 18:47:03 +01:00
Florian Bruhin
a8a9cdd81e urlmatch: Add more tests from Chromium 2018-02-15 18:47:03 +01:00
Florian Bruhin
978b90b5b1 urlmatch: Implement correct IP matching 2018-02-15 18:47:03 +01:00
Florian Bruhin
2d43a1d2e7 urlmatch: Use None as default for host 2018-02-15 18:47:03 +01:00
Florian Bruhin
5419d1caa1 urlmatch: Add glob escaping tests 2018-02-15 18:47:03 +01:00
Florian Bruhin
9092c3a87f urlmatch: Increase debuggability 2018-02-15 18:47:03 +01:00
Florian Bruhin
faeca30dfa urlmatch: Add more tests 2018-02-15 18:47:03 +01:00
Florian Bruhin
b7c3c10b87 urlmatch: Use class in test 2018-02-15 18:47:03 +01:00
Florian Bruhin
a8a976b324 urlmatch: Simplify/fix matching by using None as sentinel 2018-02-15 18:47:03 +01:00
Florian Bruhin
2b274f8e0b urlmatch: Implement initial matching 2018-02-15 18:47:02 +01:00
Florian Bruhin
3d6cbcf396 urlmatch: Improve matching error for TLD wildcards 2018-02-15 18:47:02 +01:00
Florian Bruhin
fa329c698e urlmatch: Finish port parsing 2018-02-15 18:47:02 +01:00
Florian Bruhin
a2a95f5fee urlmatch: Improve port handling 2018-02-15 18:47:02 +01:00
Florian Bruhin
d266190518 urlmatch: Improve port tests 2018-02-15 18:47:02 +01:00
Florian Bruhin
c728d78bea urlmatch: Host/port parsing 2018-02-15 18:47:02 +01:00
Florian Bruhin
32abb67d1f urlmatch: Use dedicated ParseError exception 2018-02-15 18:47:02 +01:00
Florian Bruhin
3c17bb97c0 urlmatch: Start with port parsing 2018-02-15 18:47:02 +01:00
Florian Bruhin
1b8dfb6c36 urlmatch: Disallow NUL byte
See https://bugs.chromium.org/p/chromium/issues/detail?id=390624
With Qt, we might run into the same issue as well at some point, and it sure
can't hurt to disallow it.
2018-02-15 18:46:58 +01:00
Florian Bruhin
76efba296f urlmatch: Store path/port 2018-02-15 18:46:55 +01:00
Florian Bruhin
b93c0dad5a urlmatch: Start UrlPattern 2018-02-15 18:46:51 +01:00
Florian Bruhin
541abb2324 Merge pull request #3602 from jgkamat/jay/js-linkfix
Fix broken language links in contributing
2018-02-14 17:49:53 +01:00
Jay Kamat
12d74c5b52 Fix broken language links in contributing 2018-02-14 11:40:51 -05:00
George Edward Bulmer
1893a33708 Monkeypatch qapp.launch_time too 2018-02-13 20:51:18 +00:00
George Edward Bulmer
29ff4259d6 Add test for _uptime() 2018-02-13 20:09:19 +00:00
Jonathan Berglind
681bb058fa Use HTTPStatus enum instead of http.client in webserver fixture 2018-02-13 20:57:05 +01:00
Jonathan Berglind
3d5bba9cff Use HTTPStatus in flask test server 2018-02-13 20:57:05 +01:00
Jonathan Berglind
81acba4700 Use HTTPStatus for existing tests, add more ones
Add tests for endpoints being refactored
2018-02-13 20:56:59 +01:00
George Edward Bulmer
ca8d935cf4 Update tests as per code review 2018-02-13 18:38:27 +00:00
George Edward Bulmer
cfa779ecb7 Add trivial test for _uptime 2018-02-13 16:02:20 +00:00
George Edward Bulmer
b959e885fc Pylint fix 2018-02-13 15:25:40 +00:00
George Edward Bulmer
e349af7524 Fix testing with error pastebin_version() 2018-02-13 14:49:15 +00:00
Jay Kamat
6eeacfe82b Fix caret being cleared when leaving any mode 2018-02-13 09:27:15 -05:00
George Edward Bulmer
942dca3444 Add test for pastebin_version() 2018-02-13 13:31:27 +00:00
Florian Bruhin
171392b582 Update changelog 2018-02-13 09:44:10 +01:00
Florian Bruhin
9bf5ff1583 Merge remote-tracking branch 'origin/pr/3584' 2018-02-13 09:43:44 +01:00
Florian Bruhin
0e87c46849 Remove unused win_id argument 2018-02-13 09:43:21 +01:00
Ryan Roden-Corrent
22d7490126 Remove unused import and TODO from urlmarks test. 2018-02-12 19:25:24 -05:00
Florian Bruhin
0fae611021 Update changelog 2018-02-12 23:00:55 +01:00
Florian Bruhin
47451aa495 Open qute://tabs with :buffer 2018-02-12 23:00:26 +01:00
Florian Bruhin
9f163d90e1 Merge remote-tracking branch 'origin/pr/3450' 2018-02-12 22:54:43 +01:00
Simon Doppler
ca199b0d3d Use separate variable to make pylint happy 2018-02-12 22:51:36 +01:00
Simon Doppler
7ae0d584e6 Add 20px margin above the raw list 2018-02-12 22:49:02 +01:00
Simon Doppler
0b047e3e10 Handle url with trailing slash and without 2018-02-12 22:48:41 +01:00
Florian Bruhin
15fd552616 Update changelog 2018-02-12 22:32:11 +01:00
Simon Doppler
9a0c113f8a Fix pylint line-too-long error 2018-02-12 22:25:21 +01:00
Florian Bruhin
1913012c8a Merge remote-tracking branch 'origin/pr/3561' 2018-02-12 22:18:49 +01:00
Florian Bruhin
5f393ce312 Merge remote-tracking branch 'origin/pr/3588' 2018-02-12 22:17:17 +01:00
Florian Bruhin
54bc22dfd4 hostblock_blame: Decode lines properly 2018-02-12 22:16:41 +01:00
Florian Bruhin
deb9ccb564 hostblock_blame: Remove unused import 2018-02-12 22:16:30 +01:00
Florian Bruhin
eca1fb7d3b Update hostblock_blame.py for new config 2018-02-12 17:54:34 +01:00
Florian Bruhin
80a72604c6 Revive hostblock_blame.py 2018-02-12 17:49:20 +01:00
pyup-bot
7fe9f53c97 Update pytest-xvfb from 1.0.0 to 1.1.0 2018-02-12 17:01:33 +01:00
pyup-bot
301aaf5783 Update pytest-faulthandler from 1.3.1 to 1.4.1 2018-02-12 17:01:32 +01:00
pyup-bot
3aa59ea240 Update hypothesis from 3.44.25 to 3.44.26 2018-02-12 17:01:30 +01:00
pyup-bot
bd83ff2c64 Update isort from 4.3.2 to 4.3.4 2018-02-12 17:01:28 +01:00
pyup-bot
e74995e81a Update isort from 4.3.2 to 4.3.4 2018-02-12 17:01:27 +01:00
pyup-bot
75e65b9d4a Update setuptools from 38.5.0 to 38.5.1 2018-02-12 17:01:25 +01:00
pyup-bot
a31f775d70 Update flake8-debugger from 3.0.0 to 3.1.0 2018-02-12 17:01:24 +01:00
pyup-bot
a506788f4f Update coverage from 4.5 to 4.5.1 2018-02-12 17:01:22 +01:00
pyup-bot
f64f873c11 Update coverage from 4.5 to 4.5.1 2018-02-12 17:01:21 +01:00
Simon Doppler
572257921d Use QUrl().toDisplayString() instead of url() 2018-02-12 16:12:15 +01:00
Simon Doppler
417200fa70 Use QUrl instead of str to compare 2018-02-12 16:06:17 +01:00
Simon Doppler
d6912be223 Update import order 2018-02-12 16:04:48 +01:00
Simon Doppler
ee57c30c53 Re-add the raw list (with fixed alignment) 2018-02-12 16:02:06 +01:00
Simon Doppler
0caa5d04d3 Use tabs directly
also ignore tabs page url in list
2018-02-12 15:50:56 +01:00
Florian Bruhin
c736cdf87f Merge remote-tracking branch 'origin/pr/3587' 2018-02-12 15:31:45 +01:00
Florian Bruhin
e66588f818 Update changelog 2018-02-12 15:30:47 +01:00
George Edward Bulmer
9397cc74c1 Pylint indentation fix 2018-02-12 14:24:53 +00:00
George Edward Bulmer
561e5d17b9 Remove extraneous space 2018-02-12 14:22:25 +00:00
Simon Doppler
71d33a47b3 Remove useless intermediary variables 2018-02-12 15:20:41 +01:00
Simon Doppler
ad50a7bfd2 Move import to external ressources 2018-02-12 15:20:06 +01:00
George Edward Bulmer
5b718446b6 Add test for sourcing config with invalid source 2018-02-12 14:19:18 +00:00
George Edward Bulmer
b59a7cdcc0 Report syntax errors as unhandled exceptions
Update tests accordingly
2018-02-12 14:07:05 +00:00
George Edward Bulmer
ce8b457bac Only display exception type if no traceback
Update test to match
2018-02-12 13:43:22 +00:00
Marc Jauvin
68b12e6e9f add missing lines 2018-02-12 07:31:02 -05:00
Marc Jauvin
0a9c0a1385 on_load_finished() signal handler for scroll-pos
remove get_page()
2018-02-12 07:16:01 -05:00
Marc Jauvin
a0e028a851 Update tab scroll position when finished loading.
Resolves #3322
2018-02-11 22:32:03 -05:00
George Edward Bulmer
164b2a3eef Fix a lengthy line 2018-02-11 23:20:24 +00:00
George Edward Bulmer
72103ec730 Format error type in a different way 2018-02-11 23:16:04 +00:00
Ryan Roden-Corrent
d0ca54a0cf Add unit tests for urlmarks. 2018-02-11 16:40:20 -05:00
Ryan Roden-Corrent
4a8b23380c Trigger save on bookmark-add --toggle.
The toggle option was failing to fire the changed signal when it removed
a bookmark. This means the bookmark file would not be marked as dirty,
and would not be saved on exit/autosave (unless another change was
made).
2018-02-11 16:33:00 -05:00
Simon Doppler
ddc41d2fa4 Remove raw list of open tabs 2018-02-11 22:15:14 +01:00
George Edward Bulmer
21a50cf961 Use the repr() of the exception instead of str() 2018-02-11 17:46:09 +00:00
George Edward Bulmer
b2e85a8b83 Simplify to lambda with default argument 2018-02-11 16:33:26 +00:00
Florian Bruhin
3170e35b31 Simplify QtWebKit scheme handlers 2018-02-11 17:14:41 +01:00
George Edward Bulmer
7c0832daf2 Change lambda definition - avoid mutability error 2018-02-11 15:51:48 +00:00
Florian Bruhin
c112290664 Make QtNetwork download manager great^H^H^H^Hlobal again
We originally made it per-window in b502280c06 for
issue #228, but that was back when we still needed window IDs for stuff like
message.info.

Nowadays, there's no reason for it to be per-window anymore. The rest of the
download code can deal with one global download manager (because QtWebEngine has
one), and apart from QNAM code which wasn't used here anyways (as tab_id=None)
there was nothing using the window ID anymore.

Also see #3456 which was the original motivation for this change.
2018-02-11 16:15:29 +01:00
George Edward Bulmer
2f4910f1f2 Add test for escaping {{url}} 2018-02-11 14:17:28 +00:00
Florian Bruhin
e10940100d Improve/regenerate docs 2018-02-11 11:17:37 +01:00
Florian Bruhin
9c4564fd70 Merge remote-tracking branch 'origin/pr/3581' 2018-02-11 11:16:20 +01:00
Florian Bruhin
5510c5fda1 Update changelog 2018-02-11 11:14:50 +01:00
Florian Bruhin
0743094c2f Fix copyright year in __init__.py 2018-02-11 11:12:39 +01:00
Florian Bruhin
32ba5a5c95 Improve styling for qute://version and move button 2018-02-11 11:11:55 +01:00
Florian Bruhin
ab768d6f6a Merge remote-tracking branch 'origin/pr/3567' 2018-02-11 11:11:41 +01:00
Florian Bruhin
b7f54a89db Update changelog 2018-02-11 10:46:45 +01:00
Florian Bruhin
bba1eb0d76 Add missing QUrl.RemovePassword 2018-02-11 10:45:08 +01:00
Florian Bruhin
d306f81130 Merge remote-tracking branch 'origin/pr/3525' 2018-02-11 10:44:27 +01:00
Florian Bruhin
007aa8ab8d Add some newlines 2018-02-11 10:35:46 +01:00
Florian Bruhin
e53cf08548 Update changelog 2018-02-11 10:35:31 +01:00
Florian Bruhin
772f0025f1 Clean up netrc support 2018-02-11 10:29:02 +01:00
Florian Bruhin
b64eb8dfe6 Merge remote-tracking branch 'origin/pr/3505' 2018-02-11 10:27:00 +01:00
Florian Bruhin
4e77aa41d8 Update changelog 2018-02-11 09:39:33 +01:00
Florian Bruhin
f28ab5285c Merge remote-tracking branch 'origin/pr/3582' 2018-02-11 09:37:49 +01:00
Jay Kamat
f6eb8929c3 Fix incorrect scroll offset after tab pin 2018-02-11 00:20:39 -05:00
Florian Bruhin
70868e1d99 Make pylint shut up 2018-02-10 23:18:43 +01:00
Florian Bruhin
219b75524b Fix TestCreatingDir on non-Linux 2018-02-10 23:08:47 +01:00
Florian Bruhin
a472351423 Fix typing.Union check on Python 3.5.2
Apparently 3.5.4 has __origin__ for typing.Union, but 3.5.2 has not. Let's hope
this now works everywhere...
2018-02-10 21:27:40 +01:00
Jay Kamat
11e04c79f4 Add add/remove tests to benchmarks 2018-02-10 15:10:33 -05:00
Florian Bruhin
52d7ff79fc Skip another scroll test with Qt 5.10 and Travis 2018-02-10 20:15:17 +01:00
Florian Bruhin
f25e706e11 Add Python 3.7 compatibility to setup.py 2018-02-10 20:08:33 +01:00
Florian Bruhin
5f62c016cc Fix test_standarddir.TestCreatingDir
What we actually want to test here is that the given type directory is created
and has the correct permission, we don't care much about the basedir itself.

Also, the download dir is not created automatically.

This test failed on Python 3.7 because intermediate directories now aren't
created with the given mode anymore:

https://bugs.python.org/issue19930
https://docs.python.org/3.7/whatsnew/3.7.html#changes-in-the-python-api
2018-02-10 20:07:27 +01:00
Florian Bruhin
cd1bd7d52a Skip ASCII locale tests with Python 3.7 2018-02-10 19:58:30 +01:00
Florian Bruhin
5b22209eef Run test_init_benchmark on CI again
See #2777
2018-02-10 19:50:20 +01:00
Florian Bruhin
aa5da1b312 Don't set up YAML constructors/resolvers for default loaders
After reading https://pyyaml.org/wiki/PyYAMLDocumentation again, turns out
Loader.add_constructor and .add_implicit_resolver are actually *class* methods.

In other words, we've been adding dozens of constructors/resolvers to the
default YAML loader object, causing it to slow down massively in other tests
which call configdata.init().

Instead, create our own loader class and only add them once there.

I'm still not sure why this caused the duration to increase with every YAML load
though - that might still be some kind of bug in PyYAML.

Fixes #2777
2018-02-10 19:35:03 +01:00
Jay Kamat
33d9d4fe90 Improve performance of startup and shutdown
We call 'update_tab_titles' a lot of times which calls 'setTabText' on
every tab. 'setTabText' calls tabSizeHint and minTabSizeHint on every
tab as well, meaning this is an n^2 operation repeated many times.

First, this prevents setTabText from being called unless it's needed,
removing most of the work done.

Second, I remove tabs in reverse, to avoid recomputing the above for
every tab on shutdown (which is at least n^3)
2018-02-10 13:23:35 -05:00
Florian Bruhin
63766c1711 Fix typing.Union checks with Python 3.7 2018-02-10 17:22:21 +01:00
Florian Bruhin
80ee43beca Add Python 3.7 to tox.ini 2018-02-10 16:54:55 +01:00
Florian Bruhin
c9bc72a539 Fix docstring 2018-02-10 16:54:45 +01:00
George Edward Bulmer
a6f09b1f73 Add the modified keys with a loop 2018-02-10 15:41:02 +00:00
Florian Bruhin
015889373e Update docs 2018-02-10 16:28:34 +01:00
Florian Bruhin
6d750aff8b Merge remote-tracking branch 'origin/pr/3430' 2018-02-10 16:27:41 +01:00
George Edward Bulmer
ffddf9a15f Code style review changes 2018-02-10 15:14:07 +00:00
Marc Jauvin
e6749dcf9f [count] overrides win_id for tab-give cmd
- Resolves #3548
2018-02-10 10:13:07 -05:00
Marc Jauvin
e8cc74f499 Merge branch 'master' into issue#2785 2018-02-10 08:17:47 -05:00
rnhmjoj
6f9be72c5b Update tests for statusbar changes 2018-02-10 13:15:12 +01:00
rnhmjoj
715cc7b7dd Make statusbar widgets configurable 2018-02-10 13:15:11 +01:00
Florian Bruhin
5662407e01 Update docs 2018-02-10 11:53:52 +01:00
Florian Bruhin
4ac4833c93 Clean up YamlConfig._handle_migrations 2018-02-10 11:44:18 +01:00
Florian Bruhin
c7133a662c Merge remote-tracking branch 'origin/pr/3577' 2018-02-10 11:40:49 +01:00
Florian Bruhin
11a0580e64 Fix Qt spelling 2018-02-10 10:41:57 +01:00
Florian Bruhin
8d5c0b5fa2 Merge remote-tracking branch 'origin/pr/3565' 2018-02-10 10:41:38 +01:00
Florian Bruhin
4e4a1d01c4 Remove qutebrowser_viewsource userscript
:view-source --edit can now be used instead.
2018-02-10 10:37:05 +01:00
Florian Bruhin
995e563352 Update docs 2018-02-10 10:36:58 +01:00
Florian Bruhin
92bc61d08d Merge remote-tracking branch 'origin/pr/3563' 2018-02-10 10:19:52 +01:00
Marc Jauvin
c6ad23f921 address all mentionned issues except for file://
- re-encode url using QUrl.RemovePassword | QUrl.FullyEncoded
- improve readability for clipboard / primary selection code block
2018-02-10 00:38:27 -05:00
Marc Jauvin
504e29c004 fix configfiles tests
- fix test_renamed_key()
- fix test_deleted_key()
- combine both test_merge_persist tests using @pytest.mark.parametrize
- fix _handle_migrations(): mark data dirty for renamed and deleted
2018-02-09 21:25:11 -05:00
Marc Jauvin
d88a13598a syntax improvements and use real class attributes 2018-02-09 17:14:40 -05:00
Florian Bruhin
b648345bf8 Update changelog 2018-02-09 22:50:36 +01:00
Florian Bruhin
47ec052194 Merge remote-tracking branch 'origin/pr/3558' 2018-02-09 22:50:00 +01:00
Florian Bruhin
3779f59a23 Update changelog 2018-02-09 22:48:51 +01:00
Florian Bruhin
30994b1154 Merge remote-tracking branch 'origin/pr/3555' 2018-02-09 22:48:25 +01:00
Florian Bruhin
207107082d Merge commit '74759fe04c0fa1d465cb36d3f8b00d6ebd9ef49d' 2018-02-09 22:31:34 +01:00
Florian Bruhin
c82be35639 Update changelog 2018-02-09 22:29:40 +01:00
Florian Bruhin
16a3bece34 Add missing import 2018-02-09 22:28:14 +01:00
Florian Bruhin
1ea1c1ac78 Merge remote-tracking branch 'origin/pr/3549' 2018-02-09 22:27:31 +01:00
Florian Bruhin
1ed427c342 Update changelog 2018-02-09 22:27:05 +01:00
Florian Bruhin
7058a3be74 Regenerate docs 2018-02-09 22:25:39 +01:00
Florian Bruhin
0b5ba828db Add missing test 2018-02-09 22:23:07 +01:00
Florian Bruhin
3a5baa1956 Merge remote-tracking branch 'origin/pr/3554' 2018-02-09 22:22:18 +01:00
Marc Jauvin
74759fe04c add missing decorator to _on_proc_finished 2018-02-09 15:33:02 -05:00
Marc Jauvin
9f49ac8e59 revert "fix shorten line" from origin/master 2018-02-09 15:25:20 -05:00
Marc Jauvin
57fe674dc4 shorten lines 2018-02-09 15:22:56 -05:00
Florian Bruhin
80650d4c96 Merge remote-tracking branch 'origin/pr/3544' 2018-02-09 21:04:21 +01:00
Marc Jauvin
44af6f3f1b Merge branch 'master' of https://github.com/qutebrowser/qutebrowser into tabs.mode_on_change 2018-02-09 14:57:41 -05:00
Marc Jauvin
9b7db8ee8a Need to mark config as dirty in _handle_migrations()
Add tests for tabs.persist_mode_on_change migration
2018-02-09 14:41:33 -05:00
Marc Jauvin
4e2e2606ef Merge branch 'tab-input-mode-patch' of https://github.com/mjauvin/qutebrowser into new--tab-input-mode 2018-02-09 12:28:40 -05:00
Marc Jauvin
85dfe5c403 add special code to migrate tabs.persist_mode_on_change setting to tabs.mode_on_change. 2018-02-09 11:28:21 -05:00
Marc Jauvin
a3ce03e0bd address requested changes
- syntax cleanup
- use attr.ib when declaring class attributes
- remove unnecessary comments
- code simplification
2018-02-09 10:39:02 -05:00
Marc Jauvin
fecb551c5e shorten lines 2018-02-09 10:39:02 -05:00
Marc Jauvin
91b70fab70 fix pylint/flake8 errors 2018-02-09 10:39:02 -05:00
Marc Jauvin
f3b52aaf23 fix asciidoc for tabs.mode_on_change 2018-02-09 10:39:02 -05:00
Marc Jauvin
21fc848839 document code a bit more 2018-02-09 10:39:02 -05:00
Marc Jauvin
a7db197e45 replace persist_mode_on_change with mode_on_change
supports old persist_mode_on_change functionality or new save/restore mode
2018-02-09 10:39:02 -05:00
Marc Jauvin
eb7e114e5f add propery to save tab input mode 2018-02-09 10:39:02 -05:00
Marc Jauvin
9e524e4be8 use tabs.mode_on_change to persist or restore mode 2018-02-09 10:39:02 -05:00
Florian Bruhin
5d8b48a2ed Show where a command handler is defined 2018-02-09 16:32:59 +01:00
Florian Bruhin
89bd723eaa Add scripts/*.js to MANIFEST.in 2018-02-09 13:18:12 +01:00
Florian Bruhin
7caab75fa4 Clean up cycle-inputs.js 2018-02-09 12:14:07 +01:00
Florian Bruhin
8c3039abc9 Merge remote-tracking branch 'origin/pr/3452' 2018-02-09 12:13:30 +01:00
Florian Bruhin
3e38aab0f6 Document configdata.Migrations 2018-02-09 11:31:25 +01:00
Florian Bruhin
589605fe92 Fix lint 2018-02-09 10:39:16 +01:00
Florian Bruhin
f92b52b20c Update changelog 2018-02-09 10:38:42 +01:00
Florian Bruhin
1a81f7231b Make sure multiple wrong keys are reported 2018-02-08 22:02:22 +01:00
Florian Bruhin
1a88b64c67 Add a test for keyconfig.get_command(..., default=True) 2018-02-08 21:53:41 +01:00
Florian Bruhin
298dcb4c90 Validate config separately from migrations
It makes for cleaner code, and it makes sure the target of renamed options
actually exists.
2018-02-08 21:49:41 +01:00
Florian Bruhin
e0dd7970d8 Skip fragment test
Looks like this now XPASSes with Qt 5.10 on Windows
2018-02-08 20:23:34 +01:00
Florian Bruhin
ea80ded8d5 Try to stabilize editor end2end test
Let's also wait until we're sure the mtime changed here.
2018-02-08 20:21:25 +01:00
George Edward Bulmer
950e4227e3 Pylint fix 2018-02-08 14:01:51 +00:00
Florian Bruhin
15fecc962d Fix lint 2018-02-08 11:41:58 +01:00
Florian Bruhin
53e7d13c2d Skip failing scrolling tests on Qt 5.10 on Travis
See #3572
2018-02-08 10:42:55 +01:00
Florian Bruhin
c520130389 Add tests for a failing watch/unwatch 2018-02-08 10:29:23 +01:00
Florian Bruhin
9d32807e33 Don't try to remove watched files if none exist
If we try to remove watched files but we couldn't actually watch any earlier,
we'd get a Qt warning message:

QtWarningMsg: QFileSystemWatcher::removePaths: list is empty
2018-02-08 10:29:17 +01:00
Florian Bruhin
1da58b6a4c Break long line 2018-02-08 09:54:20 +01:00
Florian Bruhin
b6f311f4b2 Remove workaround for old pylint issue 2018-02-08 09:52:14 +01:00
Florian Bruhin
35b56f2659 Remove eslint max-lines suppression
We already turn that off globally now.
2018-02-08 09:51:06 +01:00
Florian Bruhin
f51ac8ab6e Log QFileSystemWatcher errors 2018-02-08 00:32:02 +01:00
George Edward Bulmer
a9dfed948a Remove extraneous function 2018-02-07 22:55:42 +00:00
Florian Bruhin
37a9691e29 Only focus qutebrowser again after editing finished
See #3431, #3432
2018-02-07 23:14:16 +01:00
Florian Bruhin
3306247ae5 Merge branch 'editor-watch' 2018-02-07 22:31:49 +01:00
Florian Bruhin
cd97d5e6e2 Update changelog 2018-02-07 22:31:28 +01:00
Florian Bruhin
01ccbc679d Fix lint 2018-02-07 22:26:32 +01:00
Florian Bruhin
abd56a5abd Wait until the mtime changed 2018-02-07 21:40:03 +01:00
George Edward Bulmer
0ee5302836 Pylint fixes 2018-02-07 20:03:46 +00:00
George Edward Bulmer
682c3462f1 Ensure version info only gets pasted once 2018-02-07 19:21:53 +00:00
George Edward Bulmer
9128afa01d Move pastebin_version() to version.py
This also fixes the introduced cyclic dependencies
2018-02-07 19:03:05 +00:00
George Edward Bulmer
a3d62c86df Fix style for linter 2018-02-07 17:28:57 +00:00
George Edward Bulmer
d0ec33730e Add deleteLater to the paste callbacks 2018-02-07 17:28:57 +00:00
George Edward Bulmer
86d3abc0c4 Additional code review changes from PR #3480 2018-02-07 17:28:57 +00:00
George Edward Bulmer
f45d572677 Some style fixes in PR #3480's review 2018-02-07 17:28:57 +00:00
Bryan Kok
1d568a5cf4 Add feature to pastebin version string
Added a --paste flag to the :version command and a JS button with corresponding qutescheme URL in the Version debug page to enable pastebinning version.
2018-02-07 17:28:57 +00:00
Florian Bruhin
7dbe9a59e8 Update changelog 2018-02-07 18:26:43 +01:00
Florian Bruhin
aa3970c83e Merge branch 'pr/3371' 2018-02-07 18:26:19 +01:00
Florian Bruhin
1c662ae94c Revive iframe test as flaky
See #1525
2018-02-07 18:25:25 +01:00
Florian Bruhin
0bdee1e292 Stabilize the flaky iframe test
The test above this one loads hello.txt, but we don't wait for the "load
finished" message, so it can arrive after the previous test already finished and
make this test not wait properly.

However, we also can't easily wait for the load finished message in the
previous test as it only appears with QtWebEngine, not QtWebKit.

As a workaround, we simply load another file in that test, to circumvent this
kind of cross-interaction.
2018-02-07 18:16:03 +01:00
Florian Bruhin
e874db9ce3 Remove pytest version filter 2018-02-07 12:05:29 +01:00
Florian Bruhin
5135e0f35d Add .pytest_cache to .gitignore 2018-02-07 12:04:42 +01:00
Florian Bruhin
6d1e3fb2b7 Add missing more-itertools requirements 2018-02-07 12:04:09 +01:00
Florian Bruhin
e6a4237e1b Revert "Downgrade PyQt again"
This reverts commit c987a94596.
2018-02-07 11:53:47 +01:00
Florian Bruhin
e5771c785e Merge branch 'pyup-scheduled-update-2018-02-05' 2018-02-07 11:49:03 +01:00
Florian Bruhin
29e8c01d17 Merge branch 'qt510-2' 2018-02-07 11:48:39 +01:00
Florian Bruhin
054b92bbe8 Support retrying downloads with Qt 5.10
Fixes #2787
2018-02-07 11:19:41 +01:00
Florian Bruhin
7537acfd5d Use PyQt 5.10 on AppVeyor 2018-02-07 10:53:13 +01:00
Florian Bruhin
d9e095f7cf Add PyQt 5.10 to Travis CI
See #3522
2018-02-07 10:52:34 +01:00
Perry Thompson
ec7583eb97 Add troubleshooting info for widevine to FAQ 2018-02-06 17:52:05 -06:00
Florian Bruhin
5fd3943ebc Make callback mandatory for tab.selection() 2018-02-06 23:33:37 +01:00
Florian Bruhin
c987a94596 Downgrade PyQt again
Upgrading PyQt in a separate branch.
2018-02-06 23:18:53 +01:00
Florian Bruhin
20d5b4e384 Update pytest log handling
In pytest 3.4, we now need to explicitly set the log level and caplog.at_level
now sets the level of the root handler.
2018-02-06 23:17:40 +01:00
Florian Bruhin
ce8d15d2b0 Simplify selection handling and remove QUTE_SELECTED_HTML
It was broken at least since caret support was introduced and it was only
available for QtWebKit anyways, so let's just drop it. This also makes the tab
API a bit simpler.
2018-02-06 22:48:00 +01:00
Florian Bruhin
16375f20d5 Always use JavaScript to get selection
It looks like getting the selection via the widget has issues even with Qt 5.10.

On Windows, we always get wrong results.

On Linux, it seems to be flaky. I first thought this was because of a race
between JavaScript setting the selection and Qt getting it, as now we don't use
JS to get the selection anymore, so it's possible that we get it before the
older JS code finished running. However, even calling selectedText() from a JS
callback didn't seem to help...

Since has_selection also is flawed and it taking a callback would make code more
complex as well, let's just assume there is a selection if the text is not
empty. In fact, that is exactly what QtWebEngine does for hasSelection anyways!

Fixes #3523
2018-02-06 21:58:31 +01:00
George Edward Bulmer
5ceecc2b04 Add docstring for new argument 2018-02-06 18:53:45 +00:00
George Edward Bulmer
9c47128799 Use provided methods instead of protected members 2018-02-06 18:25:15 +00:00
George Edward Bulmer
0893e3a038 Fix boolean variable name 2018-02-06 17:35:24 +00:00
George Edward Bulmer
26810e02c1 Add a way to view source in editor 2018-02-06 17:22:59 +00:00
Florian Bruhin
8c39e8f764 Update changelog
[ci skip]
2018-02-06 14:13:06 +01:00
George Edward Bulmer
22c33ddfb8 Add special cases of double quotes: eg {{url}}
This allows a second level of indirection quite cheaply, but is a
band-aid fix.

This commit should be taken as temporary until command arguments are
reworked.
2018-02-05 21:45:49 +00:00
George Edward Bulmer
8b29ce93ec Add substitutions for the other 3 types 2018-02-05 21:40:12 +00:00
George Edward Bulmer
bfeac178e2 Make {suburl} expand to {url}
This is useful for the following case from IRC:
`:set aliases '{"twmpv": "spawn mpv {suburl}"}'

which now sets:
:twmpv -> spawn mpv {url}
2018-02-05 21:00:29 +00:00
pyup-bot
9eefbf24a2 Update pytest-bdd from 2.19.0 to 2.20.0 2018-02-05 16:59:33 +01:00
pyup-bot
782ec573ab Update pytest from 3.3.1 to 3.4.0 2018-02-05 16:59:32 +01:00
pyup-bot
8ee3c743e4 Update hypothesis from 3.44.21 to 3.44.25 2018-02-05 16:59:30 +01:00
pyup-bot
fac666e607 Update sip from 4.19.6 to 4.19.7 2018-02-05 16:59:29 +01:00
pyup-bot
67623930dd Update pyqt5 from 5.9.2 to 5.10 2018-02-05 16:59:27 +01:00
pyup-bot
4a9cbf8930 Update pylint from 1.8.1 to 1.8.2 2018-02-05 16:59:26 +01:00
pyup-bot
08ea34174c Update astroid from 1.6.0 to 1.6.1 2018-02-05 16:59:24 +01:00
pyup-bot
8579616fea Update isort from 4.2.15 to 4.3.2 2018-02-05 16:59:23 +01:00
pyup-bot
417a114a94 Update isort from 4.2.15 to 4.3.2 2018-02-05 16:59:21 +01:00
pyup-bot
d3050d73ba Update setuptools from 38.4.0 to 38.5.0 2018-02-05 16:59:19 +01:00
pyup-bot
46b85c11f1 Update flake8-bugbear from 17.12.0 to 18.2.0 2018-02-05 16:59:18 +01:00
pyup-bot
cfcd1bba1e Update coverage from 4.4.2 to 4.5 2018-02-05 16:59:16 +01:00
pyup-bot
075dd8e0a4 Update coverage from 4.4.2 to 4.5 2018-02-05 16:59:15 +01:00
pyup-bot
8fc88a68fb Update codecov from 2.0.14 to 2.0.15 2018-02-05 16:59:13 +01:00
Florian Bruhin
6f028e9ad0 Update copyright years 2018-02-05 12:19:50 +01:00
seebye
8dbf506916 Fix #3542 going back twice on lazy loading a tab 2018-02-05 01:20:56 +01:00
Florian Bruhin
c8de4675db Various spelling fixes 2018-02-04 21:30:59 +01:00
Jay Kamat
0ebde6f2e9 Delete QWebEngineDownloadItem objects when wrapper object is deleted 2018-02-04 13:41:23 -05:00
Ryan Roden-Corrent
a8733d7228 Increase timeout in test_editor.
The test with watch=True was failing on the Travis OSX environment
becausee it was timing out before the file_updated signal was fired.
2018-02-04 07:02:25 -05:00
Ryan Roden-Corrent
833df95485 Only detect save for open-editor and config-edit.
Scope down the new trigger-on-save behavior to only open-editor and
config-edit. Other uses of the editor such as edit-url and edit-command
will behave as before.
2018-02-03 19:57:47 -05:00
Marc Jauvin
989e60b01f Revert "fix line length"
This reverts commit def2920a35.
2018-02-03 19:10:19 -05:00
Jay Kamat
d7a436568c Add a new --no-last flag to :tab-focus
--no-last prevents going to the last focused tab if a new tab does not
need to be focused.
2018-02-03 14:31:44 -05:00
Ryan Roden-Corrent
ceab4a4c1f Fix pylint warnings 2018-02-03 08:12:45 -05:00
Ryan Roden-Corrent
0aefffce4d Attempt to solve flaky editor tests.
These are passing locally but failing in travis. This fixes two possible
timing issues:

- Ensure the signals are set up befor the pidfile is written. The
  function that sends the signal waits for the pidfile to exist, so this
  ensures we don't miss a signal.
- Wait for the log message indicating that the editor file was read
  back, so the test doesn't run through before we get a chance to read
  from the editor.
2018-02-01 20:55:18 -05:00
Ryan Roden-Corrent
eab9b70f28 Fix pylint for editor.py.
Notate unused parameter.
2018-02-01 20:43:35 -05:00
Marc Jauvin
a70feae98f Merge branch 'master' of https://github.com/qutebrowser/qutebrowser into issue#3547-spawn-race-condition 2018-01-31 18:13:48 -05:00
Marc Jauvin
132095c98c only open the tab for output once the job has finished running 2018-01-31 18:05:23 -05:00
Marc Jauvin
def2920a35 fix line length 2018-01-31 18:05:14 -05:00
Florian Bruhin
79935e048c Break long line 2018-01-31 22:35:03 +01:00
Florian Bruhin
5e96dc4374 Merge pull request #3543 from Knowlege/master
Updated PyYaml link
2018-01-30 23:33:28 +01:00
Knowlege
532205aafa Updated PyYaml link 2018-01-30 23:29:02 +01:00
lufte
d8510e61aa Use the instance attribute instead of querying the registry 2018-01-30 19:26:45 -03:00
Florian Bruhin
fb5d0f7e14 Merge pull request #3540 from mjauvin/system-proxy
document proxy environment variable for system proxy
2018-01-30 15:56:53 +01:00
Marc Jauvin
b55ae02eda document proxy environment variable for system proxy 2018-01-30 09:48:52 -05:00
Florian Bruhin
400e1bc7d7 Show tab titles as tooltip
Closes #3535
2018-01-30 07:11:48 +01:00
Ryan Roden-Corrent
e9023ce233 Remove newline in editor.py 2018-01-29 07:50:32 -05:00
Marc Jauvin
f16f425cb1 generate the docs 2018-01-28 10:41:09 -05:00
Marc Jauvin
1a2ab0ffe7 add back rl-yank key binding; use alt-y for prompt-yank. 2018-01-28 10:28:11 -05:00
Florian Bruhin
d01a0b1d64 Fix :bookmark-add with no URL 2018-01-28 13:05:49 +01:00
Ryan Roden-Corrent
530a1859a3 Trigger editor signal on exit if content changed.
With the previous code, the editor could miss the final signal on a
save-and-exit. This is avoided by always running the file changed
handler on a successful exit, but only firing the signal if the content
actually changed (to avoid double-signalling).
2018-01-27 15:03:18 -05:00
Ryan Roden-Corrent
7c33ff4046 Fix flaky editor test.
Give the process time to write its PID before trying to interrupt it.
2018-01-27 15:03:18 -05:00
Ryan Roden-Corrent
2e5595b5c6 Update test_configcommands for new editor behavior.
Now that the editor signals on save, the configcommands editing
unittests need to emit the signal in the patch rather than relying on
on_proc_closed to emit the signal.
2018-01-27 15:03:18 -05:00
Ryan Roden-Corrent
a940de3717 Rename editing_finished to file_updated.
ExternalEditor now fires an event on save rather than on exit, so the
signal name should be updated to match the behavior.
2018-01-27 15:03:18 -05:00
Ryan Roden-Corrent
23eb6a6c53 Fix test_editor for edit-on-write behavior.
Now that the editor fires editing_finished on every write, the unit
tests had to be updated.

- Add qtbot to the editor fixture to resolve `QtWarningMsg:
  QSocketNotifier: Can only be used with threads started with QThread`
- Use removePaths instead of disconnect to stop the watcher from
  signalling. This avoids an error when the editor is forcibly cleaned
  up by the tests without the signal ever being connected, but otherwise
  has the same behavior as disconnecting the singal.
- wait for a signal on write instead of proc closed
- wait for _watcher.fileChanged in test_unreadable to ensure the write
  event is fired before the test exits.
2018-01-27 15:03:18 -05:00
Ryan Roden-Corrent
8a9b98c2dc Editor triggers update on every save.
For any command that spawns an editor, tirgger an update on save, not
just on exit.

- :open-editor writes the text field on save
- :edit-url navigates on save
- :edit-url -t opens a new tab on each save
- :edit-command updates the statusbar text on save
- :edit-command --run runs a command on each save
- :config-edit reloads the config on save

Resolves #2307.
Helps mitigate #1596 by allowing users to 'save' partial work, and
notice if there was an error without closing the editor.
2018-01-27 15:03:18 -05:00
Marc Jauvin
fe4dd579f9 add --sel option to prompt-yank 2018-01-26 22:06:05 -05:00
Florian Bruhin
cdaf3ac097 Fix .Xresources example
[ci skip]
2018-01-26 18:32:27 +01:00
Florian Bruhin
1dac05a7ac Fix test_tab.py 2018-01-26 11:58:02 +01:00
Florian Bruhin
24cc54a574 Simplify initializing of AbstractTab subclasses
If we already pass the tab object, no need to pass the window ID separately.
2018-01-26 09:47:26 +01:00
Florian Bruhin
4b9bba7505 Edit changelog 2018-01-26 09:38:49 +01:00
Florian Bruhin
677e188894 Update docs 2018-01-26 09:37:35 +01:00
Florian Bruhin
125b3c1de9 Merge remote-tracking branch 'origin/pr/3521' 2018-01-26 09:25:50 +01:00
Marc Jauvin
d2287b7a2e move backend specific code out of AbstractTab into respective backend
classes.
2018-01-25 22:38:25 -05:00
Marc Jauvin
ddcc960aa5 url arg was a string 2018-01-25 22:01:18 -05:00
Marc Jauvin
88ff0c0425 url_str -> urlstr: urlstr used accross the codebase, more consistent 2018-01-25 18:01:43 -05:00
Marc Jauvin
520b473350 modify Question.yank_text to Question.url
error out when question.url is None
add url to yesno prompts
add default binding in prompt mode (ctrl-y)
2018-01-25 17:48:45 -05:00
Marc Jauvin
bb8bc7ea3c fix test related to view-source
remove pygment title
remove view-source from history
2018-01-25 15:17:03 -05:00
Marc Jauvin
eb888cc8d7 fix latest change requests 2018-01-25 13:35:23 -05:00
Florian Bruhin
b93bee18d0 Regenerate docs 2018-01-25 11:03:45 +01:00
Florian Bruhin
40df5baa83 Merge remote-tracking branch 'origin/pr/3515' 2018-01-25 09:04:44 +01:00
Florian Bruhin
ab4c875792 Update changelog 2018-01-25 09:03:47 +01:00
Florian Bruhin
54e9edfd60 Merge remote-tracking branch 'origin/pr/3515' 2018-01-25 09:02:20 +01:00
Marc Jauvin
3b1fb92b11 remove extra line to satisfy flake8 2018-01-24 19:13:28 -05:00
Marc Jauvin
d77c9ae009 Add prompt-yank command
add yank_text property to utils.usertypes.Question class

Resolves #2591
2018-01-24 18:53:06 -05:00
Marc Jauvin
d7c51f7fc4 implement requested changes for PR #3521. 2018-01-24 18:04:05 -05:00
Daniel Hahler
4f04c776c1 fixup! fixup! incdec_number: add support for port 2018-01-24 22:22:00 +01:00
Florian Bruhin
56f83ddde4 Update changelog 2018-01-24 21:33:32 +01:00
Florian Bruhin
961eebaf71 Merge remote-tracking branch 'origin/pr/3510' 2018-01-24 21:33:04 +01:00
Florian Bruhin
3df469bc38 Update changelog 2018-01-24 21:30:17 +01:00
Florian Bruhin
582236e42b Merge remote-tracking branch 'origin/pr/3509' 2018-01-24 21:28:58 +01:00
Florian Bruhin
c153ff5a97 Update docs 2018-01-24 21:15:10 +01:00
Florian Bruhin
e5b6ccd716 Merge remote-tracking branch 'origin/pr/3506' 2018-01-24 21:14:25 +01:00
Florian Bruhin
7690b9f8cd Update changelog 2018-01-24 20:56:29 +01:00
Florian Bruhin
caca3614f8 Merge remote-tracking branch 'origin/pr/3443' 2018-01-24 20:36:15 +01:00
Florian Bruhin
b1c54f5706 Re-add Qt 5.10 to tox.ini only 2018-01-24 06:17:09 +01:00
Marc Jauvin
2e912eeadf move backend dependent code to AbstractAction respective classes 2018-01-23 23:30:22 -05:00
Florian Bruhin
072d42347a Revert "Also use PyQt 5.10 on AppVeyor"
This reverts commit c3deeaf283.
2018-01-23 20:36:40 +01:00
Florian Bruhin
e26e04985b Revert "Update to PyQt 5.10"
This reverts commit a701426703.
2018-01-23 20:36:31 +01:00
Florian Bruhin
c3deeaf283 Also use PyQt 5.10 on AppVeyor 2018-01-23 20:00:14 +01:00
Florian Bruhin
a701426703 Update to PyQt 5.10 2018-01-23 19:42:22 +01:00
Florian Bruhin
3652553a8f Mark second qute://settings test as flaky 2018-01-23 19:42:22 +01:00
Marc Jauvin
83515628a8 fix line indentation warning 2018-01-23 10:11:34 -05:00
Marc Jauvin
56e6864159 Inject qutebrowser's JS files at DocumentReady
Use WebEngine's view-source: scheme for "view-source" command.
Also add missing URL when viewing source for WebKit.

Resolves #3490
Resolves #2395
Resolves #2948
2018-01-23 10:03:04 -05:00
Florian Bruhin
b0cc0c62cc Merge pull request #3513 from qutebrowser/pyup-scheduled-update-01-22-2018
Scheduled weekly dependency update for week 03
2018-01-23 07:35:37 +01:00
Florian Bruhin
0d12ddc3ea Merge pull request #3514 from blueyed/vim-readonly
scripts/dev/src2asciidoc.py: vim: readonly
2018-01-23 07:35:14 +01:00
Daniel Hahler
9f14ae184f fixup! incdec_number: add support for port 2018-01-22 21:48:21 +01:00
Daniel Hahler
6a40cbf160 incdec_number: add support for port 2018-01-22 21:26:46 +01:00
Daniel Hahler
dd0703eddf scripts/dev/src2asciidoc.py: vim: readonly
Set 'readonly' via Vim modeline in generated scripts.
2018-01-22 21:21:54 +01:00
pyup-bot
c5c01c5364 Update hypothesis from 3.44.16 to 3.44.21 2018-01-22 16:52:20 +01:00
pyup-bot
abd5da1fd1 Update codecov from 2.0.13 to 2.0.14 2018-01-22 16:52:18 +01:00
pyup-bot
036031a48b Update certifi from 2017.11.5 to 2018.1.18 2018-01-22 16:52:17 +01:00
pyup-bot
762205ef07 Update certifi from 2017.11.5 to 2018.1.18 2018-01-22 16:52:15 +01:00
pyup-bot
6edd096de4 Update certifi from 2017.11.5 to 2018.1.18 2018-01-22 16:52:14 +01:00
Simon Doppler
02396cb455 Remove useless function 2018-01-22 16:12:45 +01:00
Simon Doppler
f11d7ab489 Check if the window still exists 2018-01-22 16:11:59 +01:00
Simon Doppler
ab9f17b053 Use default value for dictionary item in tabs handler 2018-01-22 16:08:30 +01:00
Ryan Roden-Corrent
1e9a70855d Show '&' properly in completion widget.
When highlighting the matched part of the text, we need to html-escape
the pattern used to find the matching text so it will replace terms that
have been escaped in the text, like &amp;.

Resolves #3508.
2018-01-21 07:46:53 -05:00
Ryan Roden-Corrent
9d5beff937 Set some PRAGMAs to optimize the history database.
Enable write-ahead-logging and reduce the synchronous level to NORMAL.
This should reduce the number of writes to disk and avoid some of the
hangs users are experiencing.

Resolves #3507.
Resolves #2930 (optimistically, reopen if not fixed).

See https://sqlite.org/pragma.html and https://www.sqlite.org/wal.html.
2018-01-20 15:49:52 -05:00
Florian Bruhin
d62cb58f7d Release v1.1.1
(cherry picked from commit 4e8abaa2d1)
2018-01-20 19:21:40 +01:00
Florian Bruhin
9c3dcae793 Update changelog for v1.1.1 2018-01-20 19:20:12 +01:00
Florian Bruhin
84478cd81c Update changelog 2018-01-20 18:58:03 +01:00
Florian Bruhin
748de85ba2 Fix crash when getting signals for closed tabs
Fixes #3498
2018-01-20 18:50:17 +01:00
Florian Bruhin
4b3a237e2a Update changelog 2018-01-20 18:29:23 +01:00
Florian Bruhin
1f5cbf21a3 Merge remote-tracking branch 'origin/pr/3348' 2018-01-20 18:28:14 +01:00
Florian Bruhin
182bf1d688 Simplify platform handling 2018-01-20 16:43:39 +01:00
Jimmy
aebc1a7d48 Greasemonkey: don't complain about an unset run-at
Apparently is is not an unusual situation to leave it unset and rely on
the default. Logging a warning about this could be unnecerasily
confusing for users.

I'm leaving the log message in there if it is set to something weird
like `window-load` or `document-complete` which scriptish may support.
2018-01-20 13:40:53 +13:00
Jimmy
d5d22783ea Greasemonkey: optimize pattern matching a little
Moving `QUrl.toString()` out of the `_match()` function which is called
for every pattern in every stript seems to make it ~40% faster.
2018-01-20 13:40:53 +13:00
Jimmy
971b413991 Greasemonkey: make *clude regexes case insensitive
Sometimes I don't read specs so good.
2018-01-20 13:40:47 +13:00
Jimmy
b2f95339ce Greasemonkey: support regexes in @include and @exclude.
Like the spec says, if a value for the @include or @exclude rules starts
and ends with a '/' it should be parsed as a regular expression.
Technically a ECMAScript syntax regular expression, but I am not sure of
the differences and I assume they are far fewer than the similarities.
One that I did see mentioned was that javascript RegExp doesn't support
unicode. Although it apparently does support a 'u' flag now.

Note that code will only be ran for QtWebkit and QWebEngine < 5.8
we rely on the builtin support for metadata it QWebEngine for most
things greasemonkey related. Sadly it seems that they missed the regex
requirement too. I've opened a ticket to track that https://bugreports.qt.io/browse/QTBUG-65484
2018-01-20 13:39:19 +13:00
Jay Kamat
968367b042 Simplify logic for checking if an element is a frame 2018-01-19 15:25:03 -05:00
Artur Shaikhullin
1e3f11ca13 Fix eslint warnings 2018-01-19 23:17:03 +06:00
Artur Shaikhullin
22d77fadd7 Eliminate caret blinking 2018-01-19 22:40:47 +06:00
Artur Shaikhullin
2d2d71512f Add initial comment 2018-01-19 22:31:12 +06:00
Artur Shaikhullin
79766aa65b Add chromium license 2018-01-19 22:28:49 +06:00
Artur Shaikhullin
0e522d48ac Add myself to CODEOWNERS to watch for caret code 2018-01-19 22:25:58 +06:00
Artur Shaikhullin
6eb001fc34 Rename js caret file 2018-01-19 22:24:11 +06:00
Artur Shaikhullin
859469c600 Remove redundancy comment 2018-01-19 22:15:54 +06:00
Artur Shaikhullin
4fde8ff204 Add separate function in js to set current platform 2018-01-19 22:14:01 +06:00
Marc Jauvin
4a4a6549d0 use a temporary attribute of the class to prevent the loop; tested to work in both backends 2018-01-19 09:34:45 -05:00
Marc Jauvin
9e258a490e might as well use the same loop prevention mechanism for both backends 2018-01-19 06:59:40 -05:00
Argn0
bd7054fa2e use self.delete and add test 2018-01-19 09:29:37 +01:00
Argn0
aeb7bac886 added :session-load --delete 2018-01-19 02:33:42 +01:00
Marc Jauvin
a2ca59b822 add netrc support for webengine. resolves #2785. 2018-01-18 18:06:47 -05:00
Florian Bruhin
cb2cd615e0 Update docs 2018-01-18 07:57:31 +01:00
Florian Bruhin
380021e818 Merge remote-tracking branch 'origin/pr/3484' 2018-01-18 07:54:42 +01:00
Jay Kamat
12d729c3bc Merge remote-tracking branch 'upstream/master' into jay/frame-hinting 2018-01-17 17:24:43 -05:00
Jay Kamat
ffda82170d Fix several style issues 2018-01-17 17:02:53 -05:00
Slackhead
ef1de133ed remove old cycle-inputs.js 2018-01-17 19:41:54 +00:00
Slackhead
743aa86dfb run eslint on cycle-inputs.js 2018-01-17 19:32:05 +00:00
Marc Jauvin
72c97ca846 sort modes, "normal" mode first 2018-01-17 14:25:07 -05:00
Jay Kamat
c5e688f26c Stop iterating over every frame to check if element is frame 2018-01-17 13:08:04 -05:00
Marc Jauvin
5db4493667 @The-Compiler requested changes addressed. 2018-01-17 10:11:32 -05:00
Florian Bruhin
c86eaa17e2 Update changelog 2018-01-17 15:54:32 +01:00
Florian Bruhin
b3ebcfd394 Merge remote-tracking branch 'origin/pr/3482' 2018-01-17 15:53:47 +01:00
Florian Bruhin
23bdee06b3 Update changelog 2018-01-17 14:42:13 +01:00
Florian Bruhin
923785c781 Merge remote-tracking branch 'origin/pr/3467' 2018-01-17 14:41:45 +01:00
Florian Bruhin
06075a4974 Update docs 2018-01-17 13:38:54 +01:00
Florian Bruhin
a1798b3843 Merge remote-tracking branch 'origin/pr/3474' 2018-01-17 13:38:22 +01:00
Florian Bruhin
54a93dfcf8 Update changelog 2018-01-17 13:27:32 +01:00
Florian Bruhin
4acb63ca49 Merge remote-tracking branch 'origin/pr/3478' 2018-01-17 13:23:31 +01:00
Florian Bruhin
d5f7ec4372 Update changelog 2018-01-17 11:43:31 +01:00
Florian Bruhin
d94c0cf064 Merge remote-tracking branch 'origin/pr/3464' 2018-01-17 11:42:24 +01:00
Marc Jauvin
e25a33790f remove blank line to satisfy flake8 2018-01-15 20:44:56 -05:00
Florian Bruhin
d06f07af80 Fix Makefile and make sure it's tested
Fixes #3492
2018-01-15 22:42:12 +01:00
Marc Jauvin
9bb256b545 shorten lines 2018-01-15 16:19:38 -05:00
Marc Jauvin
fb0a418d0a use url even if we do not need it 2018-01-15 16:03:22 -05:00
Marc Jauvin
2a274f0d8b add test for bind without args and fix other tests to include win_id 2018-01-15 15:52:15 -05:00
Marc Jauvin
528b48dab6 fix line too 2018-01-15 15:51:14 -05:00
Marc Jauvin
9b473093b1 silence pylint warning 2018-01-15 15:45:29 -05:00
Marc Jauvin
f6cfb0c529 add missing super() call 2018-01-15 15:44:21 -05:00
Marc Jauvin
7d620a4bfc fix pylint/flake8 errors 2018-01-15 13:39:42 -05:00
Marc Jauvin
05d076ba9f fix asciidoc for tabs.mode_on_change 2018-01-15 09:09:13 -05:00
Marc Jauvin
81b85994a1 document code a bit more 2018-01-14 13:29:51 -05:00
Nemanja Nedeljkovic
8d8566a5ab Merge branch 'master' of github.com:qutebrowser/qutebrowser into angular-hints 2018-01-13 23:18:39 +01:00
Marc Jauvin
a2cdb2e4db Merge branch 'patch-issue#24' of https://github.com/mjauvin/qutebrowser into patch-issue#24 2018-01-13 15:55:05 -05:00
Marc Jauvin
48b6c160f5 improve styling as suggested by @jgkamat 2018-01-13 15:52:49 -05:00
Christian Helbling
cd20c32973 simplify more 2018-01-13 10:48:13 +01:00
Christian Helbling
141d020ede import debug is not needed anymore 2018-01-13 10:47:58 +01:00
Marc Jauvin
4848182204 code cleanup
- move qute_bindings block AFTER qute_settings block
- remove unnecessary variable declaration
2018-01-13 01:39:05 -05:00
Marc Jauvin
1e8694f3cc remove unused module 2018-01-12 17:35:04 -05:00
Marc Jauvin
3a7ac51a00 html template to render qute://bindings 2018-01-12 17:28:56 -05:00
Marc Jauvin
8940e05baf bind without agruments shows current bindings 2018-01-12 17:27:44 -05:00
Marc Jauvin
4ae33deebd add handler for qute://bindings 2018-01-12 17:24:20 -05:00
Marc Jauvin
5dbfff016e replace persist_mode_on_change with mode_on_change
supports old persist_mode_on_change functionality or new save/restore mode
2018-01-12 17:05:47 -05:00
Marc Jauvin
c87d8d0d8f add propery to save tab input mode 2018-01-12 17:02:34 -05:00
Marc Jauvin
f7a08dfd34 use tabs.mode_on_change to persist or restore mode 2018-01-12 16:57:05 -05:00
Christian Helbling
559059d244 simplify code - state_before_fullscreen seems not to be needed anymore 2018-01-12 11:21:55 +01:00
Christian Helbling
699abef159 fix regression of #2778 which reappeared with qt 5.10 in combination with up-to-date KDE
this should also avoid an unneccessary KDE maximize animation when exiting fullscreen into maximized
2018-01-12 10:54:05 +01:00
Argn0
d9741d56c5 removed a trailing whitespace 2018-01-11 16:38:55 +01:00
Argn0
57e8b428c3 e.accept() and return 2018-01-11 15:45:44 +01:00
Argn0
200b36bd36 review 1 2018-01-11 14:09:08 +01:00
Argn0
2d7dd391a3 review 1 2018-01-11 14:08:17 +01:00
Argn0
e654abf128 deleted folder 2018-01-11 14:05:18 +01:00
Argn0
66d0591684 new method 2018-01-11 14:03:43 +01:00
Argn0
4932323d3b review 1 setText 2018-01-11 12:40:20 +01:00
Argn0
860b22c0e0 review 1 2018-01-10 22:05:14 +01:00
Argn0
9fd2ad9909 review 1 2018-01-10 21:34:19 +01:00
Argn0
1db4309eec review 1 2018-01-10 21:29:31 +01:00
Argn0
2c4d2beea3 option to close commandline by deleting the prefix 2018-01-10 20:14:09 +01:00
Argn0
be5b8e2632 option to close commandline by deleting the prefix 2018-01-10 20:02:39 +01:00
Argn0
5003432a55 option to close commandline by deleting the prefix 2018-01-10 19:59:34 +01:00
Simon Doppler
dea0aa9f7c Add tabs page 2018-01-08 18:01:42 +01:00
Nemanja Nedeljkovic
5f3ee66775 Code style improvement and documentation 2018-01-07 12:06:36 +01:00
Nemanja Nedeljkovic
957d5b3f02 Add more angular1 selectors 2018-01-07 11:58:02 +01:00
Nemanja Nedeljkovic
ec08a19e7d Rename angular.html to angular1.html 2018-01-07 11:23:28 +01:00
Nemanja Nedeljkovic
64dac66259 local angular 2018-01-07 11:22:46 +01:00
Artur Shaikhullin
81a9ea58d6 Restore pylint rule 2018-01-07 09:25:29 +06:00
Fritz Reichwald
9b4da25578 Fix another test by using the new KeySequence 2018-01-07 00:11:47 +01:00
Nemanja Nedeljkovic
9bb6ba0823 Fix 2018-01-06 22:09:17 +01:00
Nemanja Nedeljkovic
22725beede Maybe fix? 2018-01-06 21:22:12 +01:00
Nemanja Nedeljkovic
f64af6b64a Angular 1 test 2018-01-06 20:45:13 +01:00
Jay Kamat
8500509532 Implement is_visible for same-origin frames 2018-01-06 11:13:54 -08:00
Fritz Reichwald
dc66ec5d8c Fix expectation in Fullscreen info message to fit new description of 2018-01-06 20:01:57 +01:00
Nemanja Nedeljković
555f43c854 Add ng-click for hinting to Angular 1.x links 2018-01-06 19:18:17 +01:00
Artur Shaikhullin
aebd59247d Check platform variable 2018-01-06 22:45:53 +06:00
Artur Shaikhullin
c4e50369e7 Enable caret only when mode is 'caret' 2018-01-06 22:43:39 +06:00
Artur Shaikhullin
dc8c919c30 Fix pylint warnings 2018-01-05 22:44:07 +06:00
Artur Shaikhullin
5553e64a75 Restore chrome-caretbrowsing extension comments 2018-01-05 19:21:55 +06:00
Artur Shaikhullin
8268c1d7ff Disable eslint rules globally 2018-01-05 19:02:19 +06:00
Artur Shaikhullin
b6662fd243 Use inner functions for callbacks 2018-01-05 18:35:15 +06:00
Jay Kamat
3d508be9ff Clear unpinned tabs before prompting user with :tab-only 2018-01-04 18:34:40 -08:00
Andrea Scarpino
16fb9bc80e scripts: filter history records
We don't need to import history records about `moz-extensions`, `about` pages, `dactyl` and so on...
2018-01-04 19:46:18 +01:00
Slackhead
7aecebf028 Add cycle-inputs.js to scripts 2017-12-31 15:08:36 +00:00
Slackhead
e989d948ed Add cycle-inputs.js to userscripts 2017-12-31 14:47:42 +00:00
Artur Shaikhullin
695f734142 Extract js call method 2017-12-30 23:46:04 +06:00
Artur Shaikhullin
e22dc1b5c6 Update copyright year 2017-12-30 23:37:57 +06:00
Artur Shaikhullin
fe4eb19ecf Add link to chrome-caretbrowsing extension 2017-12-30 23:37:17 +06:00
Artur Shaikhullin
6dc3108747 Get OS name using python 2017-12-30 23:35:12 +06:00
Artur Shaikhullin
981f5fd09b Remove unused import 2017-12-30 23:20:29 +06:00
Artur Shaikhullin
25436e2544 Fix eslint warnings 2017-12-30 09:43:16 +06:00
Artur Shaikhullin
e254ea2fa7 Add license and description 2017-12-29 23:43:39 +06:00
Florian Bruhin
dcf89f7a28 Fix KeyConfig._prepare 2017-12-29 16:10:12 +01:00
Florian Bruhin
a145497c65 Make :unbind work correctly 2017-12-29 16:05:16 +01:00
Florian Bruhin
81e9060239 Make sure KeySequence keys are valid 2017-12-29 16:04:25 +01:00
Florian Bruhin
caa05df16d Use KeySequences in config.py 2017-12-29 15:58:20 +01:00
Florian Bruhin
7b3cb14e6e Revert "Try to have strings in KeyConfig"
This reverts commit 28b6b97f39.
2017-12-29 15:41:28 +01:00
Florian Bruhin
28b6b97f39 Try to have strings in KeyConfig 2017-12-29 15:41:12 +01:00
Artur Shaikhullin
d04a087c2b Try fix Windows caret issues 2 2017-12-29 20:10:18 +06:00
Florian Bruhin
737ff2cc69 Add <> around special keys in __str__ 2017-12-29 14:43:04 +01:00
Florian Bruhin
f1fe26b0b7 Handle modifiers correctly 2017-12-29 14:40:00 +01:00
Florian Bruhin
7b17ab4b3f Initial str() attempt 2017-12-29 14:22:20 +01:00
Artur Shaikhullin
882beab3f2 Try to fix Windows caret ussues 2017-12-29 19:01:12 +06:00
Florian Bruhin
d9c768ed86 Strip out shift modifier for non-alpha bindings 2017-12-29 13:53:43 +01:00
Artur Shaikhullin
db16a87e68 Removed unused import 2017-12-29 18:39:29 +06:00
Florian Bruhin
917f2a30de Get tests to collect 2017-12-29 13:23:38 +01:00
Artur Shaikhullin
3b836d3483 Fix lint warnings 2017-12-29 17:56:16 +06:00
Florian Bruhin
cc747b00ce Move parsing to class 2017-12-29 01:50:51 +01:00
Florian Bruhin
705767bcfb fixme 2017-12-29 01:43:47 +01:00
Florian Bruhin
5cee39d315 Initial move of keyutils tests 2017-12-29 01:41:55 +01:00
Florian Bruhin
c98eb5502d Add some FIXMEs 2017-12-29 01:24:05 +01:00
Florian Bruhin
d961211188 Delete some old code 2017-12-29 01:24:05 +01:00
Florian Bruhin
21b3e05ed0 Fix getting reverse bindings 2017-12-29 01:24:05 +01:00
Florian Bruhin
b1dde41b74 Rename sequence.py to keyutils.py 2017-12-29 01:24:05 +01:00
Florian Bruhin
dcf0d21121 Move key related utils to sequence.py 2017-12-29 01:24:05 +01:00
Florian Bruhin
600919a23a Add a custom KeySequence class 2017-12-29 01:24:05 +01:00
Florian Bruhin
a565b77bf0 Switch from string to QKeySequence 2017-12-29 01:24:05 +01:00
Florian Bruhin
8478a1ea3d Remove _handle_special_key 2017-12-29 01:24:05 +01:00
Florian Bruhin
26fdc129d3 Split off counts 2017-12-29 01:24:05 +01:00
Florian Bruhin
55803afbd2 Fix matching 2017-12-29 01:24:05 +01:00
Florian Bruhin
a8aaf01ff0 Fix some more stuff (and break some :D) 2017-12-29 01:24:05 +01:00
Florian Bruhin
ddcb5445a2 Initial refactoring for new key parsing 2017-12-29 01:24:05 +01:00
Artur Shaikhullin
7d181ee4b5 Check if document body exists 2017-12-28 23:04:04 +06:00
Artur Shaikhullin
83f8d84012 Finally enable webengine test 2017-12-28 22:27:47 +06:00
Artur Shaik
734684636f Merge branch 'master' into webengine_caret 2017-12-28 20:45:01 +06:00
Artur Shaik
5605d3cd8e Merge branch 'master' into webengine_caret 2017-12-28 20:43:31 +06:00
Artur Shaikhullin
63658d3a1e Catch userscript exception and show error message 2017-12-28 20:40:37 +06:00
Artur Shaikhullin
9728e90401 Enable test in webengine 2017-12-28 20:05:10 +06:00
Artur Shaikhullin
a01566ed15 Fix loosed variable 2017-12-28 19:17:25 +06:00
Jay Kamat
012e63520f Blacklist non-implemented qtwebkit frame features 2017-12-18 18:44:28 -08:00
Jay Kamat
b87f0b6f65 Add support for non-link buttons to test_hints 2017-12-18 17:04:50 -08:00
Jay Kamat
344ebed6ad Add iframe tests for insert on click and follow-selected 2017-12-18 11:00:03 -08:00
Jay Kamat
6433096611 Disable max-lines in eslint 2017-12-15 21:30:08 -05:00
Jay Kamat
7f9d4888fd Fix a couple eslint errors
Restructure serialize_elem into a bunch of smaller functions
2017-12-15 15:55:16 -05:00
Jay Kamat
2898c416aa Simplify and clean up frame logic 2017-12-15 15:16:18 -05:00
Jay Kamat
5c5f992821 Implement find_id inside frames
Fixes :click-element
2017-12-07 14:53:15 -05:00
Jay Kamat
825939633a Implement follow_selected in frames 2017-12-07 14:46:18 -05:00
Jay Kamat
0fc99108bf Implement iframe support for clicking elements 2017-12-07 14:32:08 -05:00
Jay Kamat
052823b74c Fix broken width and height location in frames 2017-12-07 13:03:06 -05:00
Jay Kamat
c737d7ab22 Fix various js problems with frame support 2017-12-07 12:47:51 -05:00
Artur Shaikhullin
a8d79fedf3 Fix fetching selection 2017-12-07 17:45:05 +06:00
Artur Shaikhullin
5f1e0224a9 Pass caret tests 2017-12-07 17:30:32 +06:00
Jay Kamat
d4001a4a98 Add support for hinting elements from within same-origin frames 2017-12-06 23:02:00 -05:00
Artur Shaikhullin
890e26b2b5 Additional fixes 2017-12-06 13:58:23 +06:00
Artur Shaikhullin
ed1d036077 Fix eslint warnings
used some eslint ignore comments
2017-12-06 12:11:06 +06:00
Artur Shaikhullin
4eda328a61 Fix some lint warnings. Enable caret tests 2017-11-30 20:38:38 +06:00
Artur Shaikhullin
c7a5dd6abb Clean up javascript caret code 2017-11-30 18:02:50 +06:00
Artur Shaikhullin
f965c0daec Don't position caret if selection exists 2017-11-29 21:01:47 +06:00
Artur Shaikhullin
70b58d1928 Inject caret css on mode enter 2017-11-29 20:07:24 +06:00
Artur Shaikhullin
72040a3bbb Position caret on top element 2017-11-24 17:32:23 +06:00
Artur Shaikhullin
8a64ce19c3 Fetch selection for userscripts 2017-11-23 20:18:43 +06:00
Artur Shaikhullin
e7a66d92a8 Selection implentation 2017-11-22 19:56:05 +06:00
Artur Shaikhullin
8aca37e5d5 Implement all caret browsing methods 2017-11-21 19:56:00 +06:00
Artur Shaikhullin
82b1bd10ec Add some movement caret actions 2017-11-20 17:49:42 +06:00
Artur Shaikhullin
b184d2f94d dirty initial port of chrome caretbrowser extension 2017-11-16 19:25:15 +06:00
435 changed files with 12427 additions and 4365 deletions

View File

@@ -7,7 +7,7 @@ environment:
PYTHONUNBUFFERED: 1
PYTHON: C:\Python36\python.exe
matrix:
- TESTENV: py36-pyqt59
- TESTENV: py36-pyqt510
- TESTENV: pylint
install:

10
.flake8
View File

@@ -44,11 +44,11 @@ ignore =
min-version = 3.4.0
max-complexity = 12
per-file-ignores =
tests/*/test_*.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
/tests/**/test_*.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
copyright-check = True
copyright-regexp = # Copyright [\d-]+ .*
copyright-min-file-size = 110

2
.github/CODEOWNERS vendored
View File

@@ -8,3 +8,5 @@ tests/unit/completion/* @rcorre
tests/unit/misc/test_sql.py @rcorre
qutebrowser/config/configdata.yml @mschilli87
qutebrowser/javascript/caret.js @artur-shaik

1
.gitignore vendored
View File

@@ -25,6 +25,7 @@ __pycache__
/.tox
/testresults.html
/.cache
/.pytest_cache
/.testmondata
/.hypothesis
/.mypy_cache

View File

@@ -14,17 +14,34 @@ matrix:
services: docker
- os: linux
env: TESTENV=py36-pyqt571
- os: linux
env: TESTENV=py36-pyqt58
- os: linux
python: 3.5
env: TESTENV=py35-pyqt59
env: TESTENV=py35-pyqt571
- os: linux
env: TESTENV=py36-pyqt59-cov
- os: linux
env: TESTENV=py36-pyqt510
# We need a newer Xvfb as a WORKAROUND for:
# https://bugreports.qt.io/browse/QTBUG-64928
sudo: required
addons:
apt:
sources:
- sourceline: "deb http://us.archive.ubuntu.com/ubuntu/ xenial main universe"
packages:
- xvfb
- os: osx
env: TESTENV=py36 OSX=highsierra
osx_image: xcode9.3
language: generic
- os: osx
env: TESTENV=py36 OSX=sierra
osx_image: xcode9.2
language: generic
- os: osx
env: TESTENV=py36 OSX=elcapitan
osx_image: xcode8
language: generic
# https://github.com/qutebrowser/qutebrowser/issues/2013
# - os: osx
# env: TESTENV=py35 OSX=yosemite

View File

@@ -8,7 +8,8 @@ graft icons
graft doc/img
graft misc/apparmor
graft misc/userscripts
recursive-include scripts *.py *.sh
graft misc/requirements
recursive-include scripts *.py *.sh *.js
include qutebrowser/utils/testfile
include qutebrowser/git-commit-id
include LICENSE doc/* README.asciidoc
@@ -32,8 +33,6 @@ include doc/qutebrowser.1.asciidoc
include doc/changelog.asciidoc
prune tests
prune qutebrowser/3rdparty
prune misc/requirements
prune misc/docker
exclude pytest.ini
exclude qutebrowser.rcc
exclude qutebrowser/javascript/.eslintrc.yaml

View File

@@ -44,8 +44,8 @@ Documentation
In addition to the topics mentioned in this README, the following documents are
available:
* https://qutebrowser.org/img/cheatsheet-big.png[Key binding cheatsheet]: +
image:https://qutebrowser.org/img/cheatsheet-small.png["qutebrowser key binding cheatsheet",link="https://qutebrowser.org/img/cheatsheet-big.png"]
* https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/cheatsheet-big.png[Key binding cheatsheet]: +
image:https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/cheatsheet-small.png["qutebrowser key binding cheatsheet",link="https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/cheatsheet-big.png"]
* link:doc/quickstart.asciidoc[Quick start guide]
* https://www.shortcutfoo.com/app/dojos/qutebrowser[Free training course] to remember those key bindings
* link:doc/faq.asciidoc[Frequently asked questions]
@@ -91,7 +91,7 @@ https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser[mailinglist] at
mailto:qutebrowser@lists.qutebrowser.org[].
For security bugs, please contact me directly at mail@qutebrowser.org, GPG ID
https://www.the-compiler.org/pubkey.asc[0xFD55A072].
https://www.the-compiler.org/pubkey.asc[0x916eb0c8fd55a072].
Requirements
------------
@@ -99,7 +99,7 @@ Requirements
The following software and libraries are required to run qutebrowser:
* http://www.python.org/[Python] 3.5 or newer (3.6 recommended)
* http://qt.io/[Qt] 5.7.1 or newer with the following modules:
* http://qt.io/[Qt] 5.7.1 or newer (5.10 recommended) with the following modules:
- QtCore / qtbase
- QtQuick (part of qtbase in some distributions)
- QtSQL (part of qtbase in some distributions)
@@ -109,12 +109,12 @@ The following software and libraries are required to run qutebrowser:
link:https://github.com/annulen/webkit/wiki[updated fork] (5.212) is
supported
* http://www.riverbankcomputing.com/software/pyqt/intro[PyQt] 5.7.0 or newer
(5.9.2 recommended) for Python 3
(5.10 recommended) for Python 3
* https://pypi.python.org/pypi/setuptools/[pkg_resources/setuptools]
* http://fdik.org/pyPEG/[pyPEG2]
* http://jinja.pocoo.org/[jinja2]
* http://pygments.org/[pygments]
* http://pyyaml.org/wiki/PyYAML[PyYAML]
* https://github.com/yaml/pyyaml[PyYAML]
* http://www.attrs.org/[attrs]
The following libraries are optional:

View File

@@ -13,47 +13,75 @@ Thanks a lot to the following people who contributed to it:
Gold sponsors
~~~~~~~~~~~~~
TODO
- Iggy
- zwitschi
- 2x Anonymous
Silver sponsors
~~~~~~~~~~~~~~~
TODO
- https://benary.org[benaryorg]
- https://scratchbook.ch[Claude]
- Martin Tournoij
- http://supported.elsensohn.ch[Thomas Elsensohn]
- Christian Helbling
- Gavin Troy
- Chris King-Parra
- Tim Das Mool Wegener
Other sponsors
~~~~~~~~~~~~~~
TODO: people with t-shirts or higher pledge levels
- 7scan
- AMD1212
- Alex
- Alex Suykov
- Alexey Zhikhartsev
- Allan Nordhøy
- Anirudh Sanjeev
- Anssi Puustinen
- Anton Grensjö
- Aristaeus
- Armin Fisslthaler
- Ashley Hauck
- Benedikt Steindorf
- Bernardo Kuri
- Blaise Duszynski
- Bostan
- Bruno Oliveira
- BunnyApocalypse
- Christian Kellermann
- Colin Jacobs
- Daniel Andersson
- Daniel Nelson
- Daniel P. Schmidt
- Daniel Salby
- Danilo
- David Beley
- David Hollings
- David Keijser
- David Parrish
- Derin Yarsuvat
- Dmytro Kostiuchenko
- Eero Kari
- Epictek
- Eric
- Faure Hu
- Ferus
- Frederik Thorøe
- G4v4g4i
- Granitosaurus
- Gyula Teleki
- H
- Heinz Bruhin
- Hosaka
- Ihor Radchenko
- Iordanis Grigoriou
- Isaac Sandaljian
- Jakub Podeszwik
- Jamie Anderson
- Jasper Woudenberg
- Jay Kamat
- Jens Højgaard
- Johannes
- John Baber-Lucero
@@ -61,9 +89,11 @@ TODO: people with t-shirts or higher pledge levels
- Kenichiro Ito
- Kenny Low
- Lars Ivar Igesund
- Leulas
- Lucas Aride Moulin
- Ludovic Chabant
- Lukas Gierth
- Magnus Lindström
- Marulkan
- Matthew Chun-Lum
- Matthew Cronen
@@ -80,7 +110,10 @@ TODO: people with t-shirts or higher pledge levels
- Peter Rice
- Philipp Middendorf
- Pkill9
- PluMGMK
- Prescott
- ProXicT
- Ram-Z
- Robotichead
- Roshless
- Ryan Ellis
@@ -90,35 +123,53 @@ TODO: people with t-shirts or higher pledge levels
- Sean Herman
- Sebastian Frysztak
- Shelby Cruver
- Simon Désaulniers
- SirCmpwn
- Soham Pal
- Stephan Jauernick
- Stewart Webb
- Sven Reinecke
- Timothée Floure
- Tom Bass
- Tom Kirchner
- Tomas Slusny
- Tomasz Kramkowski
- Tommy Thomas
- Tuscan
- Ulrich Pötter
- Vasilij Schneidermann
- Vlaaaaaaad
- XTaran
- Z2h-A6n
- ayekat
- beanieuptop
- cee
- craftyguy
- demure
- dlangevi
- epon
- evenorbert
- fishss
- gsnewmark
- guillermohs9
- hernani
- hubcaps
- jnphilipp
- lobachevsky
- neodarz
- nihlaeth
- notbenh
- nyctea
- ongy
- patrick suwanvithaya
- pyratebeard
- p≡p foundation
- randm_dave
- sabreman
- toml
- vimja
- wiz
- 44 Anonymous
- 48 Anonymous
2016
----

View File

@@ -15,6 +15,253 @@ 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.3.0 (unreleased)
-------------------
Added
~~~~~
- New `:scroll-to-anchor` command to scroll to an anchor in the document.
- New `url.open_base_url` option to open the base URL of a searchengine when no
search term is given.
- New `tabs.min_width` setting to configure the minimal width for tabs.
- New `getbib` userscript to download bibtex information for DOIs on a page.
Changed
~~~~~~~
- QtWebEngine: Support for JavaScript Shared Web Workers have been disabled on
Qt versions older than 5.11 because of security issues in in Chromium.
You can get the same effect in earlier versions via
`:set qt.args ['disable-shared-workers']`. An equivalent workaround is also
contained in Qt 5.9.5 and 5.10.1.
- The file dialog for downloads now has basic tab completion based on the
entered text.
- `:version` now shows OS information for POSIX OS other than Linux/macOS.
- When there's an error inserting the text from an external editor, a backup
file is now saved.
- The `window.hide_wayland_decoration` setting got renamed to
`window.hide_decoration` and now also works outside of wayland.
- The `tabs.favicons.show` setting now can take three values: `'always'` (was
`True`), `'never'` (was `False`) and `'pinned'` (to only show favicons for
pinned tabs).
- Hover tooltips on tabs now always show the webpage's title.
- The default value for `content.host_blocking.lists` was changed to only
include https://github.com/StevenBlack/hosts[Steven Black's hosts-list] which
combines various sources.
- Error messages when trying to wrap when `tabs.wrap` is `False` are now logged
to debug instead of messages.
Fixed
~~~~~
- Using hints before a page is fully loaded is now possible again.
- Selecting hints with the number keypad now works again.
- Tab titles for tabs loaded from sessions should now really be correct instead
of showing the URL.
- Loading URLs with customized settings from a session now avoids an additional
reload.
- The window icon and title now get set correctly again.
- The `tabs.switching_delay` setting now has a correct maximum value limit set.
- The `taskadd` script now works properly when there's multi-line output.
- QtWebEngine: Worked around issues with GreaseMonkey/stylesheets not being
loaded correctly in some situations.
- The statusbar now more closely reflects the caret mode state.
- The icon on Windows should now be displayed in a higher resolution.
- The QtWebEngine development tools (inspector) now also work when JavaScript is
disabled globally.
- Building `.exe` files now works when `upx` is installed on the system.
- The keyhint widget now shows the correct text for chained modifiers.
- Loading GreaseMonkey scripts now also works with Jinja2 2.8 (e.g. on Debian
Stable).
- Adding styles with GreaseMonkey on fast sites now works properly.
- Window ID 0 is now excluded properly from `:tab-take` completion.
- A rare crash when cancelling a download has been fixed.
- The Makefile (intended for packagers) now supports `PREFIX` properly.
- The workaround for a black window with Nvidia graphics is now enabled on
non-Linux systems (like FreeBSD) as well.
- Initial support for Qt 5.11
v1.2.1
------
Fixed
~~~~~
- qutebrowser now starts properly when the PyQt5 QOpenGLFunctions package wasn't
found.
- The keybinding cheatsheet on the quickstart page is now loaded from a local
`qute://` URL again.
- With "tox -e mkvenv-pypi", PyQt 5.10.0 is used again instead of Qt 5.10.1,
because of an issue with Qt 5.10.1 which causes qutebrowser to fail to start
("Could not find QtWebEngineProcess").
- Unbinding keys which were bound in older qutebrowser versions now doesn't
crash anymore.
- Fixed a crash when reloading a page which wasn't fully loaded with v1.2.0
- Keys on the numeric keypad now fall back to the same bindings without `Num+`
if no `Num+` binding was found.
- Fixed hinting on some pages with Qt < 5.10.
- Titles are now displayed correctly again for tabs which are cloned or loaded
from sessions.
- Shortcuts now correctly use `Ctrl` instead of `Command` on macOS again.
v1.2.0
------
Added
~~~~~
- Initial implementation of per-domain settings:
* `:set` and `:config-cycle` now have a `-u`/`--pattern` argument taking a
https://developer.chrome.com/extensions/match_patterns[URL match pattern]
for supported settings.
* `config.set` in `config.py` now takes a third argument which is the pattern.
* New `with config.pattern('...') as p:` context manager for `config.py` to
use the shorthand syntax with a pattern.
* New `tsh` keybinding to toggle scripts for the current host. With a capital
`S`, the toggle is saved. With a capital `H`, subdomains are included. With
`u` instead of `h`, the exact current URL is used.
* New `tph` keybinding to toggle plugins, with the same additional binding
described above.
- New QtWebEngine features:
* Caret/visual mode
* Authentication via ~/.netrc
* Retrying downloads with Qt 5.10 or newer
* Hinting and other features inside same-origin frames
- New flags for existing commands:
* `:session-load` has a new `--delete` flag which deletes the
session after loading it.
* New `--no-last` flag for `:tab-focus` to not focus the last tab when focusing
the currently focused one.
* New `--edit` flag for `:view-source` to open the source in an external editor.
* New `--select` flag for `:follow-hint` which acts like the given string was entered but doesn't necessary follow the hint.
- New special pages:
* `qute://bindings` (opened via `:bind`) which shows all keybindings.
* `qute://tabs` (opened via `:buffer`) which lists all tabs.
- New settings:
* `statusbar.widgets` to configure which widgets should be shown in which
order in the statusbar.
* `tabs.mode_on_change` which replaces `tabs.persist_mode_on_change`. It can
now be set to `restore` which remembers input modes (input/passthrough)
per tab.
* `input.insert_mode.auto_enter` which makes it possible to disable entering
insert mode automatically when an editable element was clicked. Together
with `input.forward_unbound_keys`, this should allow for emacs-like
"modeless" keybindings.
- New `:prompt-yank` command (bound to `Alt-y` by default) to yank URLs
referenced in prompts.
- The `hostblock_blame` script which was removed in v1.0 was updated for the new
config and re-added.
- New `cycle-inputs.js` script in `scripts/` which can be used with `:jseval -f`
to cycle through inputs.
Changed
~~~~~~~
- Complete refactoring of key input handling, with various effects:
* emacs-like keychains such as `<Ctrl-X><Ctrl-C>` can now be bound.
* Key chains can now be bound in any mode (this allows binding unused keys in
hint mode).
* Yes/no prompts don't use keybindings from the `prompt` section anymore, they
have their own `yesno` section instead.
* Trying to bind invalid keys now shows an error.
* The `bindings.default` setting can now only be set in a `config.py`, and
existing values in `autoconfig.yml` are ignored.
- Improvements for GreaseMonkey support:
* `@include` and `@exclude` now support regex matches. With QtWebEngine and Qt
5.8 and newer, Qt handles the matching, but similar functionality will be
added in Qt 5.11.
* Support for `@requires`
* Support for the GreaseMonkey 4.0 API
- The sqlite history now uses write-ahead logging which should be
a performance and stability improvement.
- When an editor is spawned with `:open-editor` and `:config-edit`, the changes
are now applied as soon as the file is saved in the editor.
- The `hist_importer.py` script now only imports URL schemes qutebrowser can
handle.
- Deleting a prefix (`:`, `/` or `?`) via backspace now leaves command mode.
- Angular 1 elements and `<summary>`/`<details>` now get hints assigned.
- `:tab-only` with pinned tabs now still closes unpinned tabs.
- The `url.incdec_segments` option now also can take `port` as possible segment.
- QtWebEngine: `:view-source` now uses Chromium's `view-source:` scheme.
- Tabs now show their full title as tooltip.
- When there are multiple unknown keys in a autoconfig.yml, they now all get
reported in one error.
- More performance improvements when opening/closing many tabs.
- The `:version` page now has a button to pastebin the information.
- Replacements like `{url}` can now be escaped as `{{url}}`.
Fixed
~~~~~
- QtWebEngine bugfixes:
* Improved fullscreen handling with Qt 5.10.
* Hinting and scrolling now works properly on special `view-source:` pages.
* Scroll positions are now restored correctly from sessions.
* `:follow-selected` should now work in more cases with Qt > 5.10.
* Incremental search now flickers less and doesn't move to the second result
when pressing Enter.
* Keys like `Ctrl-V` or `Shift-Insert` are now correctly handled/filtered with
Qt 5.10.
* Fixed hangs/segfaults on exit with Qt 5.10.1.
* Fixed favicons sometimes getting cleared with Qt 5.10.
* Qt download objects are now cleaned up properly when a download is removed.
* JavaScript messages are now not double-HTML escaped anymore on Qt < 5.11
- QtWebKit bugfixes:
* Fixed GreaseMonkey-related crashes.
* `:view-source` now displays a valid URL.
- URLs containing ampersands and other special chars are now shown correctly
when filtering them in the completion.
- `:bookmark-add "" foo` can now be used to save the current URL with a custom
title.
- `:spawn -o` now waits until the process has finished before trying to show the
output. Previously, it incorrectly showed the previous output immediately.
- Suspended pages now should always load the correct page when being un-suspended.
- Exception types are now shown properly with `:config-source` and `:config-edit`.
- When using `:bookmark-add --toggle`, bookmarks are now saved properly.
- Crash when opening an invalid URL from an application on macOS.
- Crash with an empty `completion.timestamp_format`.
- Crash when `completion.min_chars` is set in some cases.
- HTML/JS resource files are now read into RAM on start to avoid crashes when
changing qutebrowser versions while it's open.
- Setting `bindings.key_mappings` to an empty value is now allowed.
- Bindings to an empty commands are now ignored rather than crashing.
Removed
~~~~~~~
- `QUTE_SELECTED_HTML` is now not set for userscripts anymore except when called
via hints.
- The `qutebrowser_viewsource` userscript has been removed as
`:view-source --edit` can now be used.
- The `tabs.persist_mode_on_change` setting has been removed and replaced by
`tabs.mode_on_change`.
v1.1.2
------
Changed
~~~~~~~
- Windows/macOS releases now bundle Qt 5.10.1 which includes security fixes from
Chromium up to version 64.0.3282.140.
Fixed
~~~~~
- QtWebEngine: Crash with Qt 5.10.1 when using :undo on some tabs.
- Compatibility with Python 3.7
v1.1.1
------
Fixed
~~~~~
- The Makefile now actually works.
- Fixed crashes with Qt 5.10 when closing a tab before it finished loading.
v1.1.0
------
@@ -1094,7 +1341,7 @@ Added
- New `:fake-key` command to send a fake keypress to a website or to
qutebrowser.
- New `--mhtml` argument for `:download` to download a page including all
ressources as MHTML file.
resources as MHTML file.
- New option `tabs -> title-alignment` to change the alignment of tab titles.
Changed
@@ -1294,7 +1541,7 @@ Added
- New argument `--no-err-windows` to suppress all error windows.
- New arguments `--top-navigate` and `--bottom-navigate` (`-t`/`-b`) for `:scroll-page` to specify a navigation action (e.g. automatically go to the next page when arriving at the bottom).
- New flag `-d`/`--detach` for `:spawn` to detach the spawned process so it's not closed when qutebrowser is.
- New flag `-v`/`--verbose` for `:spawn` to print informations when the process started/exited successfully.
- New flag `-v`/`--verbose` for `:spawn` to print information when the process started/exited successfully.
- Many new color settings (foreground setting for every background setting).
- New setting `ui -> modal-js-dialog` to use the standard modal dialogs for javascript questions instead of using the statusbar.
- New setting `colors -> webpage.bg` to set the background color to use for websites which don't set one.

View File

@@ -44,8 +44,8 @@ be easy to solve]
If you prefer C++ or Javascript to Python, see the relevant issues which involve
work in those languages:
* https://github.com/qutebrowser/qutebrowser/issues?utf8=%E2%9C%93&q=is%3Aopen%20is%3Aissue%20label%3Ac%2B%2B[C++] (mostly work on Qt, the library behind qutebrowser)
* https://github.com/qutebrowser/qutebrowser/issues?q=is%3Aopen+is%3Aissue+label%3Ajavascript[JavaScript]
* https://github.com/qutebrowser/qutebrowser/issues?q=is%3Aopen+is%3Aissue+label%3A%22language%3A+c%2B%2B%22[C++] (mostly work on Qt, the library behind qutebrowser)
* https://github.com/qutebrowser/qutebrowser/issues?q=is%3Aopen+is%3Aissue+label%3A%22language%3A+javascript%22[JavaScript]
There are also some things to do if you don't want to write code:
@@ -375,7 +375,7 @@ The following logging levels are available for every logger:
|error |There was an issue and some kind of operation was abandoned.
|warning |There was an issue but the operation can continue running.
|info |General informational messages.
|debug |Verbose debugging informations.
|debug |Verbose debugging information.
|=======================================================================
[[commands]]
@@ -670,10 +670,11 @@ qutebrowser release
~~~~~~~~~~~~~~~~~~~
* Make sure there are no unstaged changes and the tests are green.
* Make sure all issues with the related milestone are closed.
* Run `x=... y=...` to set the respective shell variables.
* Adjust `__version_info__` in `qutebrowser/__init__.py`.
* Update changelog (remove *(unreleased)*).
* Adjust `__version_info__` in `qutebrowser/__init__.py`.
* Commit.
* Create annotated git tag (`git tag -s "v1.$x.$y" -m "Release v1.$x.$y"`).
@@ -683,9 +684,11 @@ qutebrowser release
* Mark the milestone at https://github.com/qutebrowser/qutebrowser/milestones
as closed.
* Linux: Run `git checkout v1.$x.$y && python3 scripts/dev/build_release.py --upload v1.$x.$y`.
* Linux: Run `git checkout v1.$x.$y && ./.venv/bin/python3 scripts/dev/build_release.py --upload v1.$x.$y`.
* Windows: Run `git checkout v1.X.Y; C:\Python36-32\python scripts\dev\build_release.py --asciidoc C:\Python27\python C:\asciidoc-8.6.9\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).
* On server:
- Run `python3 scripts/dev/download_release.py v1.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.

View File

@@ -32,7 +32,7 @@ When qutebrowser was created, the newer
http://webkitgtk.org/reference/webkit2gtk/stable/index.html[WebKit2 API] lacked
basic features like proxy support, and almost no projects have started porting
to WebKit2. In the meantime, this situation has improved a bit, but there are
stil only a few project which have some kind of WebKit2 support (see the
still only a few projects which have some kind of WebKit2 support (see the
https://github.com/qutebrowser/qutebrowser#similar-projects[list of
alternatives]).
+
@@ -70,6 +70,31 @@ But isn't Python too slow for a browser?::
and WebKit in C++, with the
https://wiki.python.org/moin/GlobalInterpreterLock[GIL] released.
Is qutebrowser secure?::
Most security issues are in the backend (which handles networking,
rendering, JavaScript, etc.) and not qutebrowser itself.
+
qutebrowser uses http://wiki.qt.io/QtWebEngine[QtWebEngine] by default.
QtWebEngine is based on Google's https://www.chromium.org/Home[Chromium]. While
Qt only updates to a new Chromium release on every minor Qt release (all ~6
months), every patch release backports security fixes from newer Chromium
versions. In other words: As long as you're using an up-to-date Qt, you should
be recieving security updates on a regular basis, without qutebrowser having to
do anything. Chromium's process isolation and
https://chromium.googlesource.com/chromium/src/+/master/docs/design/sandbox.md[sandboxing]
features are also enabled as a second line of defense.
+
http://wiki.qt.io/QtWebKit[QtWebKit] is also supported as an alternative
backend, but hasn't seen new releases
https://github.com/annulen/webkit/releases[in a while]. It also doesn't have any
process isolation or sandboxing.
+
Security issues in qutebrowser's code happen very rarely (as per March 2018,
there has been one security issue caused by qutebrowser in over four years) and
are fixed timely. To report security bugs, please contact me directly at
mail@qutebrowser.org, GPG ID
https://www.the-compiler.org/pubkey.asc[0x916eb0c8fd55a072].
Is there an adblocker?::
There is a host-based adblocker which takes /etc/hosts-like lists. A "real"
adblocker has a
@@ -187,6 +212,37 @@ Why takes it longer to open an URL in qutebrowser than in chromium?::
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.
How do I make qutebrowser use greasemonkey scripts?::
There is currently no UI elements to handle managing greasemonkey scripts.
All management of what scripts are installed or disabled is done in the
filesystem by you. qutebrowser reads all files that have an extension of
`.js` from the `<data>/greasemonkey/` folder and attempts to load them.
Where `<data>` is the qutebrowser data directory shown in the `Paths`
section of the page displayed by `:version`. If you want to disable a
script just rename it, for example, to have `.disabled` on the end, after
the `.js` extension. To reload scripts from that directory run the command
`:greasemonkey-reload`.
+
Troubleshooting: to check that your script is being loaded when
`:greasemonkey-reload` runs you can start qutebrowser with the arguments
`--debug --logfilter greasemonkey,js` and check the messages on the
program's standard output for errors parsing or loading your script.
You may also see javascript errors if your script is expecting an environment
that we fail to provide.
+
Note that there are some missing features which you may run into:
. Some scripts expect `GM_xmlhttpRequest` to ignore Cross Origin Resource
Sharing restrictions, this is currently not supported, so scripts making
requests to third party sites will often fail to function correctly.
. If your backend is a QtWebEngine version 5.8, 5.9 or 5.10 then regular
expressions are not supported in `@include` or `@exclude` rules. If your
script uses them you can re-write them to use glob expressions or convert
them to `@match` rules.
See https://wiki.greasespot.net/Metadata_Block[the wiki] for more info.
. Any greasemonkey API function to do with adding UI elements is not currently
supported. That means context menu extentensions and background pages.
== Troubleshooting
@@ -216,6 +272,29 @@ And then re-emerging qtwebengine with: +
emerge -1 qtwebengine
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
----
+
For other distributions, download the chromium tarball and widevine-cdm zip from
https://aur.archlinux.org/packages/qt5-webengine-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).
+
Lastly, set your `qt.args` to point to that directory and restart qutebrowser:
+
----
:set qt.args '["ppapi-widevine-path=/usr/lib64/qt5/plugins/ppapi/libwidevinecdmadapter.so"]'
:restart
----
My issue is not listed.::
If you experience any segfaults or crashes, you can report the issue in
https://github.com/qutebrowser/qutebrowser/issues[the issue tracker] or

View File

@@ -1,6 +1,7 @@
// DO NOT EDIT THIS FILE DIRECTLY!
// It is autogenerated by running:
// $ python3 scripts/dev/src2asciidoc.py
// vim: readonly:
= Commands
@@ -13,6 +14,7 @@ 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
- `{clipboard}` expands to the clipboard contents
- `{primary}` expands to the primary selection contents
@@ -91,6 +93,7 @@ It is possible to run or bind multiple commands by separating them with `;;`.
|<<scroll,scroll>>|Scroll the current tab in the given direction.
|<<scroll-page,scroll-page>>|Scroll the frame page-wise.
|<<scroll-px,scroll-px>>|Scroll the current tab by 'count * dx/dy' pixels.
|<<scroll-to-anchor,scroll-to-anchor>>|Scroll to the given anchor in the document.
|<<scroll-to-perc,scroll-to-perc>>|Scroll to a specific percentage of the page.
|<<search,search>>|Search for a text on the current page. With no text, clear results.
|<<search-next,search-next>>|Continue the search to the ([count]th) next term.
@@ -145,14 +148,16 @@ How many pages to go back.
[[bind]]
=== bind
Syntax: +:bind [*--mode* 'mode'] [*--default*] 'key' ['command']+
Syntax: +:bind [*--mode* 'mode'] [*--default*] ['key'] ['command']+
Bind a key to a command.
==== positional arguments
* +'key'+: The keychain or special key (inside `<...>`) to bind.
* +'command'+: The command to execute, with optional args, or not given to print the current binding.
If no command is given, show the current binding for the given key. Using :bind without any arguments opens a page showing all keybindings.
==== positional arguments
* +'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.
==== optional arguments
* +*-m*+, +*--mode*+: A comma-separated list of modes to bind the key in (default: `normal`). See `:help bindings.commands` for the
@@ -174,7 +179,8 @@ Save the current page as a bookmark, or a specific url.
If no url and title are provided, then save the current page as a bookmark. If a url and title have been provided, then save the given url as a bookmark with the provided title. You can view all saved bookmarks on the link:qute://bookmarks[bookmarks page].
==== positional arguments
* +'url'+: url to save as a bookmark. If None, use url of current page.
* +'url'+: url to save as a bookmark. If not given, use url of current page.
* +'title'+: title of the new bookmark.
==== optional arguments
@@ -218,7 +224,7 @@ Syntax: +:buffer ['index']+
Select tab by index or url/title best match.
Focuses window if necessary when index is given. If both index and count are given, use count.
Focuses window if necessary when index is given. If both index and count are given, use count. With neither index nor count given, open the qute://tabs page.
==== positional arguments
* +'index'+: The [win_id/]index of the tab to focus. Or a substring in which case the closest match will be focused.
@@ -271,7 +277,8 @@ Set all settings back to their default.
[[config-cycle]]
=== config-cycle
Syntax: +:config-cycle [*--temp*] [*--print*] 'option' ['values' ['values' ...]]+
Syntax: +:config-cycle [*--pattern* 'pattern'] [*--temp*] [*--print*]
'option' ['values' ['values' ...]]+
Cycle an option between multiple values.
@@ -280,6 +287,7 @@ Cycle an option between multiple values.
* +'values'+: The values to cycle through.
==== optional arguments
* +*-u*+, +*--pattern*+: The URL pattern to use.
* +*-t*+, +*--temp*+: Set value temporarily until qutebrowser is closed.
* +*-p*+, +*--print*+: Print the value after setting.
@@ -492,10 +500,16 @@ Toggle fullscreen mode.
[[greasemonkey-reload]]
=== greasemonkey-reload
Syntax: +:greasemonkey-reload [*--force*]+
Re-read Greasemonkey scripts from disk.
The scripts are read from a 'greasemonkey' subdirectory in qutebrowser's data directory (see `:version`).
==== optional arguments
* +*-f*+, +*--force*+: For any scripts that have required dependencies, re-download them.
[[help]]
=== help
Syntax: +:help [*--tab*] [*--bg*] [*--window*] ['topic']+
@@ -741,7 +755,13 @@ This tries to automatically click on typical _Previous Page_ or _Next Page_ link
- `next`: Open a _next_ link.
- `up`: Go up a level in the current URL.
- `increment`: Increment the last number in the URL.
Uses the
link:settings.html#url.incdec_segments[url.incdec_segments]
config option.
- `decrement`: Decrement the last number in the URL.
Uses the
link:settings.html#url.incdec_segments[url.incdec_segments]
config option.
@@ -1005,6 +1025,15 @@ Scroll the current tab by 'count * dx/dy' pixels.
==== count
multiplier
[[scroll-to-anchor]]
=== scroll-to-anchor
Syntax: +:scroll-to-anchor 'name'+
Scroll to the given anchor in the document.
==== positional arguments
* +'name'+: The anchor to scroll to.
[[scroll-to-perc]]
=== scroll-to-perc
Syntax: +:scroll-to-perc [*--horizontal*] ['perc']+
@@ -1066,7 +1095,7 @@ Delete a session.
[[session-load]]
=== session-load
Syntax: +:session-load [*--clear*] [*--temp*] [*--force*] 'name'+
Syntax: +:session-load [*--clear*] [*--temp*] [*--force*] [*--delete*] 'name'+
Load a session.
@@ -1078,6 +1107,7 @@ Load a session.
* +*-t*+, +*--temp*+: Don't set the current session for :session-save.
* +*-f*+, +*--force*+: Force loading internal sessions (starting with an underline).
* +*-d*+, +*--delete*+: Delete the saved session once it has loaded.
[[session-save]]
=== session-save
@@ -1100,11 +1130,11 @@ Save a session.
[[set]]
=== set
Syntax: +:set [*--temp*] [*--print*] ['option'] ['value']+
Syntax: +:set [*--temp*] [*--print*] [*--pattern* 'pattern'] ['option'] ['value']+
Set an option.
If the option name ends with '?', the value of the option is shown instead.
If the option name ends with '?', the value of the option is shown instead. Using :set without any arguments opens a page where settings can be changed interactively.
==== positional arguments
* +'option'+: The name of the option.
@@ -1113,6 +1143,7 @@ If the option name ends with '?', the value of the option is shown instead.
==== optional arguments
* +*-t*+, +*--temp*+: Set value temporarily until qutebrowser is closed.
* +*-p*+, +*--print*+: Print the value after setting.
* +*-u*+, +*--pattern*+: The URL pattern to use.
[[set-cmd-text]]
=== set-cmd-text
@@ -1202,7 +1233,7 @@ The tab index to close
[[tab-focus]]
=== tab-focus
Syntax: +:tab-focus ['index']+
Syntax: +:tab-focus [*--no-last*] ['index']+
Select the tab given as argument/[count].
@@ -1214,6 +1245,9 @@ If neither count nor index are given, it behaves like tab-next. If both are give
last tab.
==== optional arguments
* +*-n*+, +*--no-last*+: Whether to avoid focusing last tab if already focused.
==== count
The tab index to focus, starting with 1.
@@ -1228,6 +1262,9 @@ If no win_id is given, the tab will get detached into a new window.
==== positional arguments
* +'win-id'+: The window ID of the window to give the current tab to.
==== count
Overrides win_id (index starts at 1 for win_id=0).
[[tab-move]]
=== tab-move
Syntax: +:tab-move ['index']+
@@ -1297,7 +1334,8 @@ Syntax: +:unbind [*--mode* 'mode'] 'key'+
Unbind a keychain.
==== positional arguments
* +'key'+: The keychain or special key (inside <...>) to unbind.
* +'key'+: The keychain to unbind. See the help for `:bind` for the correct syntax for keychains.
==== optional arguments
* +*-m*+, +*--mode*+: A mode to unbind the key in (default: `normal`). See `:help bindings.commands` for the available modes.
@@ -1309,12 +1347,22 @@ Re-open the last closed tab or tabs.
[[version]]
=== version
Syntax: +:version [*--paste*]+
Show version information.
==== optional arguments
* +*-p*+, +*--paste*+: Paste to pastebin.
[[view-source]]
=== view-source
Syntax: +:view-source [*--edit*]+
Show the source of the current page in a new tab.
==== optional arguments
* +*-e*+, +*--edit*+: Edit the source in the editor instead of opening a tab.
[[window-only]]
=== window-only
Close all windows except for the current one.
@@ -1402,6 +1450,7 @@ How many steps to zoom out.
|<<prompt-accept,prompt-accept>>|Accept the current prompt.
|<<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.
|<<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.
@@ -1467,13 +1516,16 @@ Drop selection and keep selection mode enabled.
[[follow-hint]]
=== follow-hint
Syntax: +:follow-hint ['keystring']+
Syntax: +:follow-hint [*--select*] ['keystring']+
Follow a hint.
==== positional arguments
* +'keystring'+: The hint to follow.
==== optional arguments
* +*-s*+, +*--select*+: Only select the given hint, don't necessarily follow it.
[[leave-mode]]
=== leave-mode
Leave the mode we're currently in.
@@ -1607,6 +1659,15 @@ If no specific command is given, this will use the system's default application
==== note
* This command does not split arguments after the last argument and handles quotes literally.
[[prompt-yank]]
=== prompt-yank
Syntax: +:prompt-yank [*--sel*]+
Yank URL to clipboard or primary selection.
==== optional arguments
* +*-s*+, +*--sel*+: Use the primary selection instead of the clipboard.
[[rl-backward-char]]
=== rl-backward-char
Move back a character.

View File

@@ -63,6 +63,10 @@ customizable.
Using the link:commands.html#set[`:set`] command and command completion, you
can quickly set settings interactively, for example `:set tabs.position left`.
Some settings are also customizable for a given
https://developer.chrome.com/apps/match_patterns[URL pattern] by doing e.g.
`:set --pattern=*://example.com/ content.images false`.
To get more help about a setting, use e.g. `:help tabs.position`.
To bind and unbind keys, you can use the link:commands.html#bind[`:bind`] and
@@ -147,7 +151,6 @@ prefix to preserve backslashes) or a Python regex object:
If you want to read a setting, you can use the `c` object to do so as well:
`c.colors.tabs.even.bg = c.colors.tabs.odd.bg`.
Using strings for setting names
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -171,6 +174,26 @@ To read a setting, use the `config.get` method:
color = config.get('colors.completion.fg')
----
Per-domain settings
~~~~~~~~~~~~~~~~~~~
Using `config.set`, some settings are also customizable for a given
https://developer.chrome.com/apps/match_patterns[URL pattern]:
[source,python]
----
config.set('content.images', False, '*://example.com/')
----
Alternatively, you can use `with config.pattern(...) as p:` to get a shortcut
similar to `c.` which is scoped to the given domain:
[source,python]
----
with config.pattern('*://example.com/') as p:
p.content.images = False
----
Binding keys
~~~~~~~~~~~~
@@ -219,10 +242,10 @@ To suppress loading of any default keybindings, you can set
Loading `autoconfig.yml`
~~~~~~~~~~~~~~~~~~~~~~~~
By default, all customization done via `:set`, `:bind` and `:unbind` is
temporary as soon as a `config.py` exists. The settings done that way are always
saved in the `autoconfig.yml` file, but you'll need to explicitly load it in
your `config.py` by doing:
All customization done via the UI (`:set`, `:bind` and `:unbind`) is
stored in the `autoconfig.yml` file, which is not loaded automatically as soon
as a `config.py` exists. If you want those settings to be loaded, you'll need to
explicitly load the `autoconfig.yml` file in your `config.py` by doing:
.config.py:
[source,python]
@@ -254,7 +277,7 @@ Getting the config directory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you need to get the qutebrowser config directory, you can do so by reading
`config.configdir`. Similarily, you can get the qutebrowser data directory via
`config.configdir`. Similarly, you can get the qutebrowser data directory via
`config.datadir`.
This gives you a https://docs.python.org/3/library/pathlib.html[`pathlib.Path`
@@ -366,6 +389,8 @@ You can use something like this to read colors from an `~/.Xresources` file:
[source,python]
----
import subprocess
def read_xresources(prefix):
props = {}
x = subprocess.run(['xrdb', '-query'], stdout=subprocess.PIPE)
@@ -376,7 +401,7 @@ def read_xresources(prefix):
return props
xresources = read_xresources('*')
c.colors.statusbar.normal.bg = xresources['*background']
c.colors.statusbar.normal.bg = xresources['*.background']
----
Avoiding flake8 errors

View File

@@ -1,6 +1,7 @@
// DO NOT EDIT THIS FILE DIRECTLY!
// It is autogenerated by running:
// $ python3 scripts/dev/src2asciidoc.py
// vim: readonly:
= Setting reference
@@ -200,6 +201,7 @@
|<<hints.uppercase,hints.uppercase>>|Make characters in hint strings uppercase.
|<<history_gap_interval,history_gap_interval>>|Maximum time (in minutes) between two history items for them to be considered being from the same browsing session.
|<<input.forward_unbound_keys,input.forward_unbound_keys>>|Which unbound keys to forward to the webview in normal mode.
|<<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.plugins,input.insert_mode.plugins>>|Switch to insert mode when clicking flash and other plugins.
@@ -229,19 +231,21 @@
|<<statusbar.hide,statusbar.hide>>|Hide the statusbar unless a message is shown.
|<<statusbar.padding,statusbar.padding>>|Padding (in pixels) for the statusbar.
|<<statusbar.position,statusbar.position>>|Position of the status bar.
|<<statusbar.widgets,statusbar.widgets>>|List of widgets displayed in the statusbar.
|<<tabs.background,tabs.background>>|Open new tabs (middleclick/ctrl+click) in the background.
|<<tabs.close_mouse_button,tabs.close_mouse_button>>|Mouse button with which to close tabs.
|<<tabs.close_mouse_button_on_bar,tabs.close_mouse_button_on_bar>>|How to behave when the close mouse button is pressed on the tab bar.
|<<tabs.favicons.scale,tabs.favicons.scale>>|Scaling factor for favicons in the tab bar.
|<<tabs.favicons.show,tabs.favicons.show>>|Show favicons in the tab bar.
|<<tabs.favicons.show,tabs.favicons.show>>|When to show favicons in the tab bar.
|<<tabs.indicator.padding,tabs.indicator.padding>>|Padding (in pixels) for tab indicators.
|<<tabs.indicator.width,tabs.indicator.width>>|Width (in pixels) of the progress indicator (0 to disable).
|<<tabs.last_close,tabs.last_close>>|How to behave when the last tab is closed.
|<<tabs.min_width,tabs.min_width>>|Minimum width (in pixels) of tabs (-1 for the default minimum size behavior).
|<<tabs.mode_on_change,tabs.mode_on_change>>|When switching tabs, what input mode is applied.
|<<tabs.mousewheel_switching,tabs.mousewheel_switching>>|Switch between tabs using the mouse wheel.
|<<tabs.new_position.related,tabs.new_position.related>>|Position of new tabs opened from another tab.
|<<tabs.new_position.unrelated,tabs.new_position.unrelated>>|Position of new tabs which aren't opened from another tab.
|<<tabs.padding,tabs.padding>>|Padding (in pixels) around text for tabs.
|<<tabs.persist_mode_on_change,tabs.persist_mode_on_change>>|Stay in insert/passthrough mode when switching tabs.
|<<tabs.pinned.shrink,tabs.pinned.shrink>>|Shrink pinned tabs down to their contents.
|<<tabs.position,tabs.position>>|Position of the tab bar.
|<<tabs.select_on_remove,tabs.select_on_remove>>|Which tab to select when the focused tab is removed.
@@ -256,10 +260,11 @@
|<<url.auto_search,url.auto_search>>|What search to start when something else than a URL is entered.
|<<url.default_page,url.default_page>>|Page to open if :open -t/-b/-w is used without URL.
|<<url.incdec_segments,url.incdec_segments>>|URL segments where `:navigate increment/decrement` will search for a number.
|<<url.open_base_url,url.open_base_url>>|Open base URL of the searchengine if a searchengine shortcut is invoked without parameters.
|<<url.searchengines,url.searchengines>>|Search engines which can be used via the address bar.
|<<url.start_pages,url.start_pages>>|Page(s) to open at the start.
|<<url.yank_ignored_parameters,url.yank_ignored_parameters>>|URL parameters to strip with `:yank url`.
|<<window.hide_wayland_decoration,window.hide_wayland_decoration>>|Hide the window decoration when using wayland.
|<<window.hide_decoration,window.hide_decoration>>|Hide the window decoration.
|<<window.title_format,window.title_format>>|Format to use for the window title. The same placeholders like for
|<<zoom.default,zoom.default>>|Default zoom level.
|<<zoom.levels,zoom.levels>>|Available zoom levels.
@@ -320,7 +325,7 @@ While it's possible to add bindings with this setting, it's recommended to use `
This setting is a dictionary containing mode names and dictionaries mapping keys to commands:
`{mode: {key: command}}`
If you want to map a key to another key, check the `bindings.key_mappings` setting instead.
For special keys (can't be part of a keychain), enclose them in `<`...`>`. For modifiers, you can use either `-` or `+` as delimiters, and these names:
For modifiers, you can use either `-` or `+` as delimiters, and these names:
* Control: `Control`, `Ctrl`
@@ -356,11 +361,8 @@ The following modes are available:
* prompt: Entered when there's a prompt to display, like for download
locations or when invoked from JavaScript.
+
You can bind normal keys in this mode, but they will be only active when
a yes/no-prompt is asked. For other prompt modes, you can only bind
special keys.
* yesno: Entered when there's a yes/no prompt displayed.
* caret: Entered when pressing the `v` mode, used to select text using the
keyboard.
@@ -377,6 +379,8 @@ Default keybindings. If you want to add bindings, modify `bindings.commands` ins
The main purpose of this setting is that you can set it to an empty dictionary if you want to load no default keybindings at all.
If you want to preserve default bindings (and get new bindings when there is an update), use `config.bind()` in `config.py` or the `:bind` command, and leave this setting alone.
This setting can only be set in config.py.
Type: <<types,Dict>>
Default:
@@ -580,8 +584,20 @@ Default:
* +pass:[sk]+: +pass:[set-cmd-text -s :bind]+
* +pass:[sl]+: +pass:[set-cmd-text -s :set -t]+
* +pass:[ss]+: +pass:[set-cmd-text -s :set]+
* +pass:[tPH]+: +pass:[config-cycle -p -u *://*.{url:host}/* content.plugins ;; reload]+
* +pass:[tPh]+: +pass:[config-cycle -p -u *://{url:host}/* content.plugins ;; reload]+
* +pass:[tPu]+: +pass:[config-cycle -p -u {url} content.plugins ;; reload]+
* +pass:[tSH]+: +pass:[config-cycle -p -u *://*.{url:host}/* content.javascript.enabled ;; reload]+
* +pass:[tSh]+: +pass:[config-cycle -p -u *://{url:host}/* content.javascript.enabled ;; reload]+
* +pass:[tSu]+: +pass:[config-cycle -p -u {url} content.javascript.enabled ;; reload]+
* +pass:[th]+: +pass:[back -t]+
* +pass:[tl]+: +pass:[forward -t]+
* +pass:[tpH]+: +pass:[config-cycle -p -t -u *://*.{url:host}/* content.plugins ;; reload]+
* +pass:[tph]+: +pass:[config-cycle -p -t -u *://{url:host}/* content.plugins ;; reload]+
* +pass:[tpu]+: +pass:[config-cycle -p -t -u {url} content.plugins ;; reload]+
* +pass:[tsH]+: +pass:[config-cycle -p -t -u *://*.{url:host}/* content.javascript.enabled ;; reload]+
* +pass:[tsh]+: +pass:[config-cycle -p -t -u *://{url:host}/* content.javascript.enabled ;; reload]+
* +pass:[tsu]+: +pass:[config-cycle -p -t -u {url} content.javascript.enabled ;; reload]+
* +pass:[u]+: +pass:[undo]+
* +pass:[v]+: +pass:[enter-mode caret]+
* +pass:[wB]+: +pass:[set-cmd-text -s :bookmark-load -w]+
@@ -615,6 +631,8 @@ Default:
* +pass:[&lt;Alt-Backspace&gt;]+: +pass:[rl-backward-kill-word]+
* +pass:[&lt;Alt-D&gt;]+: +pass:[rl-kill-word]+
* +pass:[&lt;Alt-F&gt;]+: +pass:[rl-forward-word]+
* +pass:[&lt;Alt-Shift-Y&gt;]+: +pass:[prompt-yank --sel]+
* +pass:[&lt;Alt-Y&gt;]+: +pass:[prompt-yank]+
* +pass:[&lt;Ctrl-?&gt;]+: +pass:[rl-delete-char]+
* +pass:[&lt;Ctrl-A&gt;]+: +pass:[rl-beginning-of-line]+
* +pass:[&lt;Ctrl-B&gt;]+: +pass:[rl-backward-char]+
@@ -632,11 +650,17 @@ Default:
* +pass:[&lt;Shift-Tab&gt;]+: +pass:[prompt-item-focus prev]+
* +pass:[&lt;Tab&gt;]+: +pass:[prompt-item-focus next]+
* +pass:[&lt;Up&gt;]+: +pass:[prompt-item-focus prev]+
* +pass:[n]+: +pass:[prompt-accept no]+
* +pass:[y]+: +pass:[prompt-accept yes]+
- +pass:[register]+:
* +pass:[&lt;Escape&gt;]+: +pass:[leave-mode]+
- +pass:[yesno]+:
* +pass:[&lt;Alt-Shift-Y&gt;]+: +pass:[prompt-yank --sel]+
* +pass:[&lt;Alt-Y&gt;]+: +pass:[prompt-yank]+
* +pass:[&lt;Escape&gt;]+: +pass:[leave-mode]+
* +pass:[&lt;Return&gt;]+: +pass:[prompt-accept]+
* +pass:[n]+: +pass:[prompt-accept no]+
* +pass:[y]+: +pass:[prompt-accept yes]+
[[bindings.key_mappings]]
=== bindings.key_mappings
@@ -1443,6 +1467,8 @@ Default:
Enable support for the HTML 5 web application cache feature.
An application cache acts like an HTTP cache in some sense. For documents that use the application cache via JavaScript, the loader engine will first ask the application cache for the contents, before hitting the network.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[true]+
@@ -1520,6 +1546,8 @@ This setting is only available with the QtWebKit backend.
=== content.dns_prefetch
Try to pre-fetch DNS entries to speed up browsing.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[true]+
@@ -1531,6 +1559,8 @@ This setting is only available with the QtWebKit backend.
Expand each subframe to its contents.
This will flatten all the frames to become one scrollable page.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -1579,7 +1609,7 @@ Default: +pass:[true]+
[[content.headers.referer]]
=== content.headers.referer
When to send the Referer header.
The Referer header tells websites from which website you were coming from when visting them.
The Referer header tells websites from which website you were coming from when visiting them.
Type: <<types,String>>
@@ -1625,11 +1655,7 @@ Type: <<types,List of Url>>
Default:
- +pass:[https://www.malwaredomainlist.com/hostslist/hosts.txt]+
- +pass:[http://someonewhocares.org/hosts/hosts]+
- +pass:[http://winhelp2002.mvps.org/hosts.zip]+
- +pass:[http://malwaredomains.lehigh.edu/files/justdomains.zip]+
- +pass:[https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&amp;mimetype=plaintext]+
- +pass:[https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts]+
[[content.host_blocking.whitelist]]
=== content.host_blocking.whitelist
@@ -1647,6 +1673,8 @@ Default:
=== content.hyperlink_auditing
Enable hyperlink auditing (`<a ping>`).
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -1655,6 +1683,8 @@ Default: +pass:[false]+
=== content.images
Load images automatically in web pages.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[true]+
@@ -1672,6 +1702,8 @@ Default: +pass:[true]+
Allow JavaScript to read from or write to the clipboard.
With QtWebEngine, writing the clipboard as response to a user interaction is always allowed.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -1680,6 +1712,8 @@ Default: +pass:[false]+
=== content.javascript.can_close_tabs
Allow JavaScript to close tabs.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -1690,6 +1724,8 @@ This setting is only available with the QtWebKit backend.
=== content.javascript.can_open_tabs_automatically
Allow JavaScript to open new tabs without user interaction.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -1698,6 +1734,8 @@ Default: +pass:[false]+
=== content.javascript.enabled
Enable JavaScript.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[true]+
@@ -1737,6 +1775,8 @@ Default: +pass:[true]+
=== content.local_content_can_access_file_urls
Allow locally loaded documents to access other local URLs.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[true]+
@@ -1745,6 +1785,8 @@ Default: +pass:[true]+
=== content.local_content_can_access_remote_urls
Allow locally loaded documents to access remote URLs.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -1753,6 +1795,8 @@ Default: +pass:[false]+
=== content.local_storage
Enable support for HTML 5 local storage and Web SQL.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[true]+
@@ -1813,6 +1857,8 @@ This setting is only available with the QtWebKit backend.
=== content.plugins
Enable plugins in Web pages.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -1821,6 +1867,8 @@ Default: +pass:[false]+
=== content.print_element_backgrounds
Draw the background color and images also when the page is printed.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[true]+
@@ -1885,6 +1933,8 @@ Default: empty
=== content.webgl
Enable WebGL.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[true]+
@@ -1902,6 +1952,8 @@ Default: +pass:[false]+
Monitor load requests for cross-site scripting attempts.
Suspicious scripts will be blocked and reported in the inspector's JavaScript console. Enabling this feature might have an impact on performance.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -2347,6 +2399,14 @@ Valid values:
Default: +pass:[auto]+
[[input.insert_mode.auto_enter]]
=== input.insert_mode.auto_enter
Enter insert mode if an editable element is clicked.
Type: <<types,Bool>>
Default: +pass:[true]+
[[input.insert_mode.auto_leave]]
=== input.insert_mode.auto_leave
Leave insert mode if a non-editable element is clicked.
@@ -2375,6 +2435,8 @@ Default: +pass:[false]+
=== input.links_included_in_focus_chain
Include hyperlinks in the keyboard focus chain when tabbing.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[true]+
@@ -2402,6 +2464,8 @@ Default: +pass:[false]+
Enable spatial navigation.
Spatial navigation consists in the ability to navigate between focusable elements in a Web page, such as hyperlinks and form controls, by using Left, Right, Up and Down arrow keys. For example, if the user presses the Right key, heuristics determine whether there is an element he might be trying to reach towards the right and which element he probably wants.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -2546,6 +2610,8 @@ Default: +pass:[false]+
Enable smooth scrolling for web pages.
Note smooth scrolling does not work with the `:scroll-px` command.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -2682,6 +2748,31 @@ Valid values:
Default: +pass:[bottom]+
[[statusbar.widgets]]
=== statusbar.widgets
List of widgets displayed in the statusbar.
Type: <<types,List of String>>
Valid values:
* +url+: Current page URL.
* +scroll+: Percentage of the current page position like `10%`.
* +scroll_raw+: Raw percentage of the current page position like `10`.
* +history+: Display an arrow when possible to go back/forward in history.
* +tabs+: Current active tab, e.g. `2`.
* +keypress+: Display pressed keys when composing a vi command.
* +progress+: Progress bar for the current page loading.
Default:
- +pass:[keypress]+
- +pass:[url]+
- +pass:[scroll]+
- +pass:[history]+
- +pass:[tabs]+
- +pass:[progress]+
[[tabs.background]]
=== tabs.background
Open new tabs (middleclick/ctrl+click) in the background.
@@ -2730,11 +2821,17 @@ Default: +pass:[1.0]+
[[tabs.favicons.show]]
=== tabs.favicons.show
Show favicons in the tab bar.
When to show favicons in the tab bar.
Type: <<types,Bool>>
Type: <<types,String>>
Default: +pass:[true]+
Valid values:
* +always+: Always show favicons.
* +never+: Always hide favicons.
* +pinned+: Show favicons only on pinned tabs.
Default: +pass:[always]+
[[tabs.indicator.padding]]
=== tabs.indicator.padding
@@ -2773,6 +2870,30 @@ Valid values:
Default: +pass:[ignore]+
[[tabs.min_width]]
=== tabs.min_width
Minimum width (in pixels) of tabs (-1 for the default minimum size behavior).
This setting only applies when tabs are horizontal.
This setting does not apply to pinned tabs, unless `tabs.pinned.shrink` is False.
Type: <<types,Int>>
Default: +pass:[-1]+
[[tabs.mode_on_change]]
=== tabs.mode_on_change
When switching tabs, what input mode is applied.
Type: <<types,String>>
Valid values:
* +persist+: Retain the current mode.
* +restore+: Restore previously saved mode.
* +normal+: Always revert to normal mode.
Default: +pass:[normal]+
[[tabs.mousewheel_switching]]
=== tabs.mousewheel_switching
Switch between tabs using the mouse wheel.
@@ -2824,14 +2945,6 @@ Default:
- +pass:[right]+: +pass:[5]+
- +pass:[top]+: +pass:[0]+
[[tabs.persist_mode_on_change]]
=== tabs.persist_mode_on_change
Stay in insert/passthrough mode when switching tabs.
Type: <<types,Bool>>
Default: +pass:[false]+
[[tabs.pinned.shrink]]
=== tabs.pinned.shrink
Shrink pinned tabs down to their contents.
@@ -2993,6 +3106,7 @@ Type: <<types,FlagList>>
Valid values:
* +host+
* +port+
* +path+
* +query+
* +anchor+
@@ -3002,6 +3116,14 @@ Default:
- +pass:[path]+
- +pass:[query]+
[[url.open_base_url]]
=== url.open_base_url
Open base URL of the searchengine if a searchengine shortcut is invoked without parameters.
Type: <<types,Bool>>
Default: +pass:[false]+
[[url.searchengines]]
=== url.searchengines
Search engines which can be used via the address bar.
@@ -3037,10 +3159,12 @@ Default:
- +pass:[utm_term]+
- +pass:[utm_content]+
[[window.hide_wayland_decoration]]
=== window.hide_wayland_decoration
Hide the window decoration when using wayland.
This setting requires a restart.
[[window.hide_decoration]]
=== window.hide_decoration
Hide the window decoration.
This setting requires a restart on Wayland.
Type: <<types,Bool>>
@@ -3101,6 +3225,8 @@ Default: +pass:[512]+
=== zoom.text_only
Apply the zoom factor on a frame only to the text or to all content.
This setting supports URL patterns.
Type: <<types,Bool>>
Default: +pass:[false]+
@@ -3171,7 +3297,7 @@ 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://docs.python.org/3/library/datetime.html#strftime-strptime-behavior for reference.
See https://sqlite.org/lang_datefunc.html for reference.
|UniqueCharString|A string which may not contain duplicate chars.
|Url|A URL as a string.
|VerticalPosition|The position of the download bar.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1024 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -35,25 +35,38 @@ Ubuntu 16.04 doesn't come with an up-to-date engine (a new enough QtWebKit, or
QtWebEngine). However, it comes with Python 3.5, so you can
<<tox,install qutebrowser via tox>>.
You'll need some basic libraries to use the tox-installed PyQt:
----
# apt install libglib2.0-0 libgl1 libfontconfig1 libx11-xcb1 libxi6 libxrender1 libdbus-1-3
----
Debian Stretch / Ubuntu 17.04 and 17.10
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Those versions come with QtWebEngine in the repositories. This makes it possible
to install qutebrowser via the Debian package.
Get the qutebrowser package from the
https://github.com/qutebrowser/qutebrowser/releases[release page] and download
the https://qutebrowser.org/python3-pypeg2_2.15.2-1_all.deb[PyPEG2 package].
You'll need to download three packages:
(If you are using debian testing you can just use the python3-pypeg2 package from the repos)
- https://packages.debian.org/sid/all/python3-pypeg2/download[PyPEG2] (a library
used by qutebrowser which is not in the earlier repositories)
- https://packages.debian.org/sid/all/qutebrowser/download[qutebrowser] itself
- Either https://packages.debian.org/sid/all/qutebrowser-qtwebengine/download[qutebrowser-qtwebengine]
or https://packages.debian.org/sid/all/qutebrowser-qtwebkit/download[qutebrowser-qtwebkit]
(or both) depending on the backend you want to use. QtWebEngine is the
default/recommended choice.
Install the packages:
After downloading, install the packages:
----
# apt install ./python3-pypeg2_*_all.deb
# apt install ./qutebrowser_*_all.deb
# apt install ./qutebrowser*.deb
----
For an update after the initial install, you only need to download/install the
qutebrowser package.
Debian Testing / Ubuntu 18.04
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -277,6 +290,11 @@ PS C:\> Install-Package qutebrowser
----
C:\> choco install qutebrowser
----
* Scoop's client
----
C:\> scoop bucket add extras
C:\> scoop install qutebrowser
----
Manual install
~~~~~~~~~~~~~~
@@ -408,7 +426,11 @@ Creating a wrapper script
~~~~~~~~~~~~~~~~~~~~~~~~~
Running `tox` does not install a system-wide `qutebrowser` script. You can
launch qutebrowser by doing `.venv/bin/python3 -m qutebrowser`.
launch qutebrowser by doing:
----
.venv/bin/python3 -m qutebrowser
----
You can create a simple wrapper script to start qutebrowser somewhere in your
`$PATH` (e.g. `/usr/local/bin/qutebrowser` or `~/bin/qutebrowser`):

View File

@@ -22,9 +22,9 @@ Basic keybindings to get you started
What to do now
--------------
* View the link:https://qutebrowser.org/img/cheatsheet-big.png[key binding cheatsheet]
* View the link:https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/cheatsheet-big.png[key binding cheatsheet]
to make yourself familiar with the key bindings: +
image:https://qutebrowser.org/img/cheatsheet-small.png["qutebrowser key binding cheatsheet",link="https://qutebrowser.org/img/cheatsheet-big.png"]
image:https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/cheatsheet-small.png["qutebrowser key binding cheatsheet",link="https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/cheatsheet-big.png"]
* There's also a https://www.shortcutfoo.com/app/dojos/qutebrowser[free training
course] on shortcutfoo for the keybindings - note that you need to be in
insert mode (i) for it to work.

View File

@@ -37,7 +37,7 @@ is available in the repositories:
Archlinux
^^^^^^^^^
For Archlinux, no debug informations are provided. You can either compile Qt
For Archlinux, no debug information is provided. You can either compile Qt
yourself (which will take a few hours even on a modern machine) or use
debugging symbols compiled/packaged by me (x86_64 only).

View File

@@ -45,8 +45,6 @@ In `command` mode:
- `QUTE_URL`: The current URL.
- `QUTE_TITLE`: The title of the current page.
- `QUTE_SELECTED_TEXT`: The text currently selected on the page.
- `QUTE_SELECTED_HTML` The HTML currently selected on the page (not supported
with QtWebEngine).
In `hints` mode:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 113 KiB

View File

@@ -1,25 +1,31 @@
PYTHON = python3
DESTDIR = /
PREFIX = /usr/local
DESTDIR =
ICONSIZES = 16 24 32 48 64 128 256 512
SETUPTOOLSOPTIONS =
ifdef DESTDIR
SETUPTOOLSOPTS = --root="$(DESTDIR)"
endif
.PHONY: install
doc/qutebrowser.1.html:
a2x -f manpage doc/qutebrowser.1.asciidoc
install: doc/qutebrowser.1.html
$(PYTHON) setup.py install --root="$(DESTDIR)" --optimize=1
$(PYTHON) setup.py install --prefix="$(PREFIX)" --optimize=1 $(SETUPTOOLSOPTS)
install -Dm644 doc/qutebrowser.1 \
"$(DESTDIR)/usr/share/man/man1/qutebrowser.1"
"$(DESTDIR)$(PREFIX)/share/man/man1/qutebrowser.1"
install -Dm644 misc/qutebrowser.desktop \
"$(DESTDIR)/usr/share/applications/qutebrowser.desktop"
"$(DESTDIR)$(PREFIX)/share/applications/qutebrowser.desktop"
$(foreach i,$(ICONSIZES),install -Dm644 "icons/qutebrowser-$(i)x$(i).png" \
"$(DESTDIR)/usr/share/icons/hicolor/$(i)x$(i)/apps/qutebrowser.png";)
"$(DESTDIR)$(PREFIX)/share/icons/hicolor/$(i)x$(i)/apps/qutebrowser.png";)
install -Dm644 icons/qutebrowser.svg \
"$(DESTDIR)/usr/share/icons/hicolor/scalable/apps/qutebrowser.svg"
install -Dm755 -t "$(DESTDIR)/usr/share/qutebrowser/userscripts/" \
"$(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/qutebrowser.svg"
install -Dm755 -t "$(DESTDIR)$(PREFIX)/share/qutebrowser/userscripts/" \
$(wildcard misc/userscripts/*)
install -Dm755 -t "$(DESTDIR)/usr/share/qutebrowser/scripts/" \
install -Dm755 -t "$(DESTDIR)$(PREFIX)/share/qutebrowser/scripts/" \
$(filter-out scripts/__init__.py scripts/__pycache__ scripts/dev \
scripts/testbrowser_cpp scripts/asciidoc2html.py scripts/setupcommon.py \
scripts/testbrowser scripts/asciidoc2html.py scripts/setupcommon.py \
scripts/link_pyqt.py,$(wildcard scripts/*))

View File

@@ -32,22 +32,24 @@
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.24"
inkscape:cx="305.29152"
inkscape:cy="465.48793"
inkscape:zoom="1.7536248"
inkscape:cx="430.72917"
inkscape:cy="268.64059"
inkscape:document-units="px"
inkscape:current-layer="layer1"
width="1024px"
height="640px"
showgrid="false"
inkscape:window-width="1024"
inkscape:window-height="723"
inkscape:window-width="2560"
inkscape:window-height="1440"
inkscape:window-x="0"
inkscape:window-y="0"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-maximized="1"
inkscape:snap-text-baseline="true">
inkscape:window-maximized="0"
inkscape:snap-text-baseline="true"
inkscape:measure-start="0,0"
inkscape:measure-end="0,0">
<inkscape:grid
id="GridFromPre046Settings"
type="xygrid"
@@ -2688,7 +2690,8 @@
id="flowPara5711"> </flowPara></flowRoot> <flowRoot
xml:space="preserve"
id="flowRoot5691-0"
style="font-style:normal;font-weight:normal;font-size:12.80000019px;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"><flowRegion
style="font-style:normal;font-weight:normal;font-size:12.80000019px;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
transform="translate(0,-10)"><flowRegion
id="flowRegion5693-7"
style="font-family:sans-serif;stroke-width:1.06666672"><rect
id="rect5695-0"
@@ -3660,5 +3663,64 @@
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6220">items</tspan></text>
</g>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:TlwgTypewriter;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
x="417.29486"
y="205.18887"
id="text7245-1-3"><tspan
sodipodi:role="line"
x="417.29486"
y="205.18887"
id="tspan7366-3-6"
style="font-size:9.60000038px;line-height:0.89999998;stroke-width:1.06666672"> </tspan><tspan
sodipodi:role="line"
x="417.29486"
y="213.07179"
id="tspan5293-53"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">toggle</tspan><tspan
sodipodi:role="line"
x="417.29486"
y="220.75179"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672;fill:#ff0000"
id="tspan6091">(12)</tspan><tspan
sodipodi:role="line"
x="417.29486"
y="225.70012"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6087" /><tspan
sodipodi:role="line"
x="417.29486"
y="225.70012"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6089" /></text>
<flowRoot
transform="translate(-1.2953814,90.2721)"
xml:space="preserve"
id="flowRoot5691-0-5"
style="font-style:normal;font-weight:normal;font-size:12.80000019px;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"><flowRegion
id="flowRegion5693-7-6"
style="font-family:sans-serif;stroke-width:1.06666672"><rect
id="rect5695-0-2"
width="344"
height="173.33333"
x="19.42783"
y="520.07886"
style="font-family:sans-serif;fill:#000000;stroke-width:1.13777781" /></flowRegion><flowPara
style="font-weight:bold;font-size:10.66666698px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'Sans Bold';fill:#000000;stroke-width:1.06666672"
id="flowPara5701-9-2"><flowSpan
style="font-weight:bold;font-family:sans-serif;-inkscape-font-specification:'Sans Bold';fill:#ff0000;stroke-width:1.06666672"
id="flowSpan5705-5-1">(12)</flowSpan> toggling settings:</flowPara><flowPara
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara6196">tsh - toggle scripts for the current host (temporarily)</flowPara><flowPara
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara6200">tSh - like <flowSpan
style="font-style:italic"
id="flowSpan6202">tsh</flowSpan>, but permanently</flowPara><flowPara
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara6206">tsH/tsu - like <flowSpan
style="font-style:italic"
id="flowSpan6210">tsh</flowSpan>, but including subdomains / with exact URL</flowPara><flowPara
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara6208">tph - toggle plugins</flowPara></flowRoot> </g>
</svg>

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 181 KiB

View File

@@ -15,7 +15,7 @@ def get_data_files():
('../qutebrowser/img', 'img'),
('../qutebrowser/javascript', 'javascript'),
('../qutebrowser/html/doc', 'html/doc'),
('../qutebrowser/git-commit-id', ''),
('../qutebrowser/git-commit-id', '.'),
('../qutebrowser/config/configdata.yml', 'config'),
]
@@ -58,14 +58,14 @@ exe = EXE(pyz,
icon=icon,
debug=False,
strip=False,
upx=True,
upx=False,
console=False )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx=False,
name='qutebrowser')
app = BUNDLE(coll,

View File

@@ -1,9 +1,9 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
certifi==2017.11.5
certifi==2018.1.18
chardet==3.0.4
codecov==2.0.13
coverage==4.4.2
codecov==2.0.15
coverage==4.5.1
idna==2.6
requests==2.18.4
urllib3==1.22

View File

@@ -2,24 +2,26 @@
attrs==17.4.0
flake8==3.5.0
flake8-bugbear==17.12.0
flake8-builtins==1.0.post0
flake8-bugbear==18.2.0
flake8-builtins==1.2.2
flake8-comprehensions==1.4.1
flake8-copyright==0.2.0
flake8-debugger==3.0.0
flake8-debugger==3.1.0
flake8-deprecated==1.3
flake8-docstrings==1.3.0
flake8-future-import==0.4.4
flake8-mock==0.3
flake8-per-file-ignores==0.4
flake8-per-file-ignores==0.6
flake8-polyfill==1.0.2
flake8-string-format==0.2.3
flake8-tidy-imports==1.1.0
flake8-tuple==0.2.13
mccabe==0.6.1
pathmatch==0.2.1
pep8-naming==0.5.0
pycodestyle==2.3.1
pydocstyle==2.1.1
pyflakes==1.6.0
six==1.11.0
snowballstemmer==1.2.1
typing==3.6.4

View File

@@ -1,8 +1,8 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
appdirs==1.4.3
packaging==16.8
packaging==17.1
pyparsing==2.2.0
setuptools==38.4.0
setuptools==39.0.1
six==1.11.0
wheel==0.30.0
wheel==0.31.0

View File

@@ -4,4 +4,4 @@ altgraph==0.15
future==0.16.0
macholib==1.9
pefile==2017.11.5
-e git+https://github.com/pyinstaller/pyinstaller.git@develop#egg=PyInstaller
PyInstaller==3.3.1

View File

@@ -1,4 +1 @@
-e git+https://github.com/pyinstaller/pyinstaller.git@develop#egg=PyInstaller
# remove @commit-id for scm installs
#@ replace: @.*# @develop#
PyInstaller

View File

@@ -1,18 +1,18 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-e git+https://github.com/PyCQA/astroid.git#egg=astroid
certifi==2017.11.5
certifi==2018.1.18
chardet==3.0.4
github3.py==0.9.6
github3.py==1.0.2
idna==2.6
isort==4.2.15
isort==4.3.4
lazy-object-proxy==1.3.1
mccabe==0.6.1
-e git+https://github.com/PyCQA/pylint.git#egg=pylint
python-dateutil==2.7.2
./scripts/dev/pylint_checkers
requests==2.18.4
six==1.11.0
uritemplate==3.0.0
uritemplate.py==3.0.2
urllib3==1.22
wrapt==1.10.11

View File

@@ -1,18 +1,18 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
astroid==1.6.0
certifi==2017.11.5
astroid==1.6.3
certifi==2018.1.18
chardet==3.0.4
github3.py==0.9.6
github3.py==1.0.2
idna==2.6
isort==4.2.15
isort==4.3.4
lazy-object-proxy==1.3.1
mccabe==0.6.1
pylint==1.8.1
pylint==1.8.4
python-dateutil==2.7.2
./scripts/dev/pylint_checkers
requests==2.18.4
six==1.11.0
uritemplate==3.0.0
uritemplate.py==3.0.2
urllib3==1.22
wrapt==1.10.11

View File

@@ -0,0 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
PyQt5==5.10 # rq.filter: != 5.10.1
sip==4.19.8

View File

@@ -0,0 +1,2 @@
PyQt5==5.10.0
#@ filter: PyQt5 != 5.10.1

View File

@@ -1,4 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
PyQt5==5.9.2
sip==4.19.6
PyQt5==5.10.1
sip==4.19.8

View File

@@ -2,37 +2,38 @@
attrs==17.4.0
beautifulsoup4==4.6.0
cheroot==6.0.0
cheroot==6.1.2
click==6.7
# colorama==0.3.9
coverage==4.4.2
coverage==4.5.1
EasyProcess==0.2.3
fields==5.0.0
Flask==0.12.2
glob2==0.6
hunter==2.0.2
hypothesis==3.44.16
hypothesis==3.55.1
itsdangerous==0.24
# Jinja2==2.10
Mako==1.0.7
# MarkupSafe==1.0
more-itertools==4.1.0
parse==1.8.2
parse-type==0.4.2
pluggy==0.6.0
py==1.5.2
py-cpuinfo==3.3.0
pytest==3.3.1 # rq.filter: != 3.3.2
pytest-bdd==2.19.0
py==1.5.3
py-cpuinfo==4.0.0
pytest==3.5.0
pytest-bdd==2.21.0
pytest-benchmark==3.1.1
pytest-cov==2.5.1
pytest-faulthandler==1.3.1
pytest-faulthandler==1.5.0
pytest-instafail==0.3.0
pytest-mock==1.6.3
pytest-mock==1.8.0
pytest-qt==2.3.1
pytest-repeat==0.4.1
pytest-rerunfailures==4.0
pytest-travis-fold==1.3.0
pytest-xvfb==1.0.0
pytest-xvfb==1.1.0
PyVirtualDisplay==0.2.1
six==1.11.0
vulture==0.26

View File

@@ -4,7 +4,7 @@ coverage
Flask
hunter
hypothesis
pytest==3.3.1
pytest
pytest-bdd
pytest-benchmark
pytest-cov
@@ -19,4 +19,3 @@ pytest-xvfb
vulture
#@ ignore: Jinja2, MarkupSafe, colorama
#@ filter: pytest != 3.3.2

View File

@@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
pluggy==0.6.0
py==1.5.2
py==1.5.3
six==1.11.0
tox==2.9.1
virtualenv==15.1.0
tox==3.0.0
virtualenv==15.2.0

View File

@@ -1,4 +1 @@
tox
# The latest tox release still depends on pluggy < 0.4...
pluggy==0.4.0

69
misc/userscripts/getbib Executable file
View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""Qutebrowser userscript scraping the current web page for DOIs and downloading
corresponding bibtex information.
Set the environment variable 'QUTE_BIB_FILEPATH' to indicate the path to
download to. Otherwise, bibtex information is downloaded to '/tmp' and hence
deleted at reboot.
Installation: see qute://help/userscripts.html
Inspired by
https://ocefpaf.github.io/python4oceanographers/blog/2014/05/19/doi2bibtex/
"""
import os
import sys
import shutil
import re
from collections import Counter
from urllib import parse as url_parse
from urllib import request as url_request
FIFO_PATH = os.getenv("QUTE_FIFO")
def message_fifo(message, level="warning"):
"""Send message to qutebrowser FIFO. The level must be one of 'info',
'warning' (default) or 'error'."""
with open(FIFO_PATH, "w") as fifo:
fifo.write("message-{} '{}'".format(level, message))
source = os.getenv("QUTE_TEXT")
with open(source) as f:
text = f.read()
# find DOIs on page using regex
dval = re.compile(r'(10\.(\d)+/([^(\s\>\"\<)])+)')
# https://stackoverflow.com/a/10324802/3865876, too strict
# dval = re.compile(r'\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])\S)+)\b')
dois = dval.findall(text)
dois = Counter(e[0] for e in dois)
try:
doi = dois.most_common(1)[0][0]
except IndexError:
message_fifo("No DOIs found on page")
sys.exit()
message_fifo("Found {} DOIs on page, selecting {}".format(len(dois), doi),
level="info")
# get bibtex data corresponding to DOI
url = "http://dx.doi.org/" + url_parse.quote(doi)
headers = dict(Accept='text/bibliography; style=bibtex')
request = url_request.Request(url, headers=headers)
response = url_request.urlopen(request)
status_code = response.getcode()
if status_code >= 400:
message_fifo("Request returned {}".format(status_code))
sys.exit()
# obtain content and format it
bibtex = response.read().decode("utf-8").strip()
bibtex = bibtex.replace(" ", "\n ", 1).\
replace("}, ", "},\n ").replace("}}", "}\n}")
# append to file
bib_filepath = os.getenv("QUTE_BIB_FILEPATH", "/tmp/qute.bib")
with open(bib_filepath, "a") as f:
f.write(bibtex + "\n\n")

View File

@@ -52,7 +52,7 @@ die() {
if ! [ -d "$DOWNLOAD_DIR" ] ; then
die "Download directory »$DOWNLOAD_DIR« not found!"
fi
if ! which "${ROFI_CMD}" > /dev/null ; then
if ! command -v "${ROFI_CMD}" > /dev/null ; then
die "Rofi command »${ROFI_CMD}« not found in PATH!"
fi

View File

@@ -220,7 +220,7 @@ user_pattern='^(user|username|login): '
GPG_OPTS=( "--quiet" "--yes" "--compress-algo=none" "--no-encrypt-to" )
GPG="gpg"
export GPG_TTY="${GPG_TTY:-$(tty 2>/dev/null)}"
which gpg2 &>/dev/null && GPG="gpg2"
command -v gpg2 &>/dev/null && GPG="gpg2"
[[ -n $GPG_AGENT_INFO || $GPG == "gpg2" ]] && GPG_OPTS+=( "--batch" "--use-agent" )
pass_backend() {

View File

@@ -1,33 +0,0 @@
#!/usr/bin/env bash
# Copyright 2015 Zach-Button <zachrey.button@gmail.com>
# Copyright 2016-2017 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/>.
#
# This script fetches the unprocessed HTML source for a page and opens it in vim.
# :bind gf spawn --userscript qutebrowser_viewsource
#
# Caveat: Does not use authentication of any kind. Add it in if you want it to.
#
path=$(mktemp --tmpdir qutebrowser_XXXXXXXX.html)
curl "$QUTE_URL" > "$path"
urxvt -e vim "$path"
rm "$path"

View File

@@ -13,7 +13,11 @@
from __future__ import absolute_import
import codecs, os
tmpfile=os.path.expanduser('~/.local/share/qutebrowser/userscripts/readability.html')
tmpfile = os.path.join(
os.environ.get('QUTE_DATA_DIR',
os.path.expanduser('~/.local/share/qutebrowser')),
'userscripts/readability.html')
if not os.path.exists(os.path.dirname(tmpfile)):
os.makedirs(os.path.dirname(tmpfile))

View File

@@ -28,7 +28,7 @@
if msg="$(task add "$title" "$*" 2>&1)"; then
# annotate the new task with the url, send the output back to the browser
task +LATEST annotate "$QUTE_URL"
echo "message-info '$msg'" >> "$QUTE_FIFO"
echo "message-info '$(echo "$msg" | head -n 1)'" >> "$QUTE_FIFO"
else
echo "message-error '$msg'" >> "$QUTE_FIFO"
echo "message-error '$(echo "$msg" | head -n 1)'" >> "$QUTE_FIFO"
fi

52
misc/userscripts/tor_identity Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2018 jnphilipp <mail@jnphilipp.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/>.
# Change your tor identity.
#
# Set a hotkey to launch this script, then:
# :bind ti spawn --userscript tor_identity PASSWORD
#
# Use the hotkey to change your tor identity, press 'ti' to change it.
# https://stem.torproject.org/faq.html#how-do-i-request-a-new-identity-from-tor
#
import os
import sys
try:
from stem import Signal
from stem.control import Controller
except ImportError:
if os.getenv('QUTE_FIFO'):
with open(os.environ['QUTE_FIFO'], 'w') as f:
f.write('message-error "Failed to import stem."')
else:
print('Failed to import stem.')
password = sys.argv[1]
with Controller.from_port(port=9051) as controller:
controller.authenticate(password)
controller.signal(Signal.NEWNYM)
if os.getenv('QUTE_FIFO'):
with open(os.environ['QUTE_FIFO'], 'w') as f:
f.write('message-info "Tor identity changed."')
else:
print('Tor identity changed.')

View File

@@ -1,4 +1,5 @@
[pytest]
log_level = NOTSET
addopts = --strict -rfEw --faulthandler-timeout=90 --instafail --pythonwarnings error --benchmark-columns=Min,Max,Median
testpaths = tests
markers =
@@ -25,6 +26,8 @@ markers =
this: Used to mark tests during development
no_invalid_lines: Don't fail on unparseable lines in end2end tests
issue2478: Tests which are broken on Windows with QtWebEngine, https://github.com/qutebrowser/qutebrowser/issues/2478
issue3572: Tests which are broken with QtWebEngine and Qt 5.10, https://github.com/qutebrowser/qutebrowser/issues/3572
qtbug60673: Tests which are broken if the conversion from orange selection to real selection is flaky
fake_os: Fake utils.is_* to a fake operating system
unicode_locale: Tests which need an unicode locale to work
qt_log_level_fail = WARNING

View File

@@ -2,7 +2,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2015 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 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-2017 Florian Bruhin (The Compiler)"
__copyright__ = "Copyright 2014-2018 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
__version_info__ = (1, 1, 0)
__version_info__ = (1, 2, 1)
__version__ = '.'.join(str(e) for e in __version_info__)
__description__ = "A keyboard-driven, vim-like browser based on PyQt5."

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -64,7 +64,7 @@ from qutebrowser.completion.models import miscmodels
from qutebrowser.commands import cmdutils, runners, cmdexc
from qutebrowser.config import config, websettings, configfiles, configinit
from qutebrowser.browser import (urlmarks, adblock, history, browsertab,
downloads, greasemonkey)
qtnetworkdownloads, downloads, greasemonkey)
from qutebrowser.browser.network import proxy
from qutebrowser.browser.webkit import cookies, cache
from qutebrowser.browser.webkit.network import networkmanager
@@ -95,6 +95,7 @@ def run(args):
log.init.debug("Initializing directories...")
standarddir.init(args)
utils.preload_resources()
log.init.debug("Initializing config...")
configinit.early_init(args)
@@ -339,7 +340,7 @@ def _open_startpage(win_id=None):
for cur_win_id in list(window_ids): # Copying as the dict could change
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=cur_win_id)
if tabbed_browser.count() == 0:
if tabbed_browser.widget.count() == 0:
log.init.debug("Opening start pages")
for url in config.val.url.start_pages:
tabbed_browser.tabopen(url)
@@ -491,6 +492,10 @@ def _init_modules(args, crash_handler):
diskcache = cache.DiskCache(standarddir.cache(), parent=qApp)
objreg.register('cache', diskcache)
log.init.debug("Initializing downloads...")
download_manager = qtnetworkdownloads.DownloadManager(parent=qApp)
objreg.register('qtnetwork-download-manager', download_manager)
log.init.debug("Initializing Greasemonkey...")
greasemonkey.init()
@@ -768,6 +773,8 @@ class Quitter:
pre_text="Error while saving {}".format(key))
# Disable storage so removing tempdir will work
websettings.shutdown()
# Disable application proxy factory to fix segfaults with Qt 5.10.1
proxy.shutdown()
# Re-enable faulthandler to stdout, then remove crash log
log.destroy.debug("Deactivating crash log...")
objreg.get('crash-handler').destroy_crashlogfile()
@@ -836,7 +843,11 @@ class Application(QApplication):
def event(self, e):
"""Handle macOS FileOpen events."""
if e.type() == QEvent.FileOpen:
open_url(e.url(), no_raise=True)
url = e.url()
if url.isValid():
open_url(url, no_raise=True)
else:
message.error("Invalid URL: {}".format(url.errorString()))
else:
return super().event(e)
@@ -874,6 +885,7 @@ class EventFilter(QObject):
self._handlers = {
QEvent.KeyPress: self._handle_key_event,
QEvent.KeyRelease: self._handle_key_event,
QEvent.ShortcutOverride: self._handle_key_event,
}
def _handle_key_event(self, event):
@@ -891,7 +903,7 @@ class EventFilter(QObject):
return False
try:
man = objreg.get('mode-manager', scope='window', window='current')
return man.eventFilter(event)
return man.handle_event(event)
except objreg.RegistryUnavailableError:
# No window available yet, or not a MainWindow
return False

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -94,14 +94,8 @@ class HostBlocker:
_done_count: How many files have been read successfully.
_local_hosts_file: The path to the blocked-hosts file.
_config_hosts_file: The path to a blocked-hosts in ~/.config
Class attributes:
WHITELISTED: Hosts which never should be blocked.
"""
WHITELISTED = ('localhost', 'localhost.localdomain', 'broadcasthost',
'local')
def __init__(self):
self._blocked_hosts = set()
self._config_blocked_hosts = set()
@@ -176,8 +170,7 @@ class HostBlocker:
self._config_blocked_hosts)
self._blocked_hosts = set()
self._done_count = 0
download_manager = objreg.get('qtnetwork-download-manager',
scope='window', window='last-focused')
download_manager = objreg.get('qtnetwork-download-manager')
for url in config.val.content.host_blocking.lists:
if url.scheme() == 'file':
filename = url.toLocalFile()
@@ -235,16 +228,14 @@ class HostBlocker:
parts = line.split()
if len(parts) == 1:
# "one host per line" format
host = parts[0]
elif len(parts) == 2:
# /etc/hosts format
host = parts[1]
hosts = [parts[0]]
else:
log.misc.error("Failed to parse: {!r}".format(line))
return False
# /etc/hosts format
hosts = parts[1:]
if host not in self.WHITELISTED:
self._blocked_hosts.add(host)
for host in hosts:
if '.' in host and not host.endswith('.localdomain'):
self._blocked_hosts.add(host)
return True

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -30,7 +30,8 @@ from PyQt5.QtWidgets import QWidget, QApplication
from qutebrowser.keyinput import modeman
from qutebrowser.config import config
from qutebrowser.utils import utils, objreg, usertypes, log, qtutils
from qutebrowser.utils import (utils, objreg, usertypes, log, qtutils,
urlutils, message)
from qutebrowser.misc import miscwidgets, objects
from qutebrowser.browser import mouse, hints
@@ -94,19 +95,28 @@ class TabData:
keep_icon: Whether the (e.g. cloned) icon should not be cleared on page
load.
inspector: The QWebInspector used for this webview.
viewing_source: Set if we're currently showing a source view.
open_target: Where to open the next link.
Only used for QtWebKit.
override_target: Override for open_target for fake clicks (like hints).
Only used for QtWebKit.
pinned: Flag to pin the tab.
fullscreen: Whether the tab has a video shown fullscreen currently.
netrc_used: Whether netrc authentication was performed.
input_mode: current input mode for the tab.
"""
keep_icon = attr.ib(False)
viewing_source = attr.ib(False)
inspector = attr.ib(None)
open_target = attr.ib(usertypes.ClickTarget.normal)
override_target = attr.ib(None)
pinned = attr.ib(False)
fullscreen = attr.ib(False)
netrc_used = attr.ib(False)
input_mode = attr.ib(usertypes.KeyMode.normal)
def should_show_icon(self):
return (config.val.tabs.favicons.show == 'always' or
config.val.tabs.favicons.show == 'pinned' and self.pinned)
class AbstractAction:
@@ -121,8 +131,9 @@ class AbstractAction:
action_class = None
action_base = None
def __init__(self):
def __init__(self, tab):
self._widget = None
self._tab = tab
def exit_fullscreen(self):
"""Exit the fullscreen mode."""
@@ -139,6 +150,10 @@ class AbstractAction:
raise WebTabError("{} is not a valid web action!".format(name))
self._widget.triggerPageAction(member)
def show_source(self):
"""Show the source of the current page in a new tab."""
raise NotImplementedError
class AbstractPrinting:
@@ -245,10 +260,10 @@ class AbstractZoom(QObject):
_default_zoom_changed: Whether the zoom was changed from the default.
"""
def __init__(self, win_id, parent=None):
def __init__(self, tab, parent=None):
super().__init__(parent)
self._tab = tab
self._widget = None
self._win_id = win_id
self._default_zoom_changed = False
self._init_neighborlist()
config.instance.changed.connect(self._on_config_changed)
@@ -322,12 +337,18 @@ class AbstractZoom(QObject):
class AbstractCaret(QObject):
"""Attribute of AbstractTab for caret browsing."""
"""Attribute of AbstractTab for caret browsing.
def __init__(self, win_id, tab, mode_manager, parent=None):
Signals:
selection_toggled: Emitted when the selection was toggled.
arg: Whether the selection is now active.
"""
selection_toggled = pyqtSignal(bool)
def __init__(self, tab, mode_manager, parent=None):
super().__init__(parent)
self._tab = tab
self._win_id = win_id
self._widget = None
self.selection_enabled = False
mode_manager.entered.connect(self._on_mode_entered)
@@ -336,7 +357,7 @@ class AbstractCaret(QObject):
def _on_mode_entered(self, mode):
raise NotImplementedError
def _on_mode_left(self):
def _on_mode_left(self, mode):
raise NotImplementedError
def move_to_next_line(self, count=1):
@@ -390,10 +411,7 @@ class AbstractCaret(QObject):
def drop_selection(self):
raise NotImplementedError
def has_selection(self):
raise NotImplementedError
def selection(self, html=False):
def selection(self, callback):
raise NotImplementedError
def follow_selected(self, *, tab=False):
@@ -432,6 +450,9 @@ class AbstractScroller(QObject):
def to_point(self, point):
raise NotImplementedError
def to_anchor(self, name):
raise NotImplementedError
def delta(self, x=0, y=0):
raise NotImplementedError
@@ -609,6 +630,7 @@ class AbstractTab(QWidget):
process terminated.
arg 0: A TerminationStatus member.
arg 1: The exit code.
predicted_navigation: Emitted before we tell Qt to open a URL.
"""
window_close_requested = pyqtSignal()
@@ -626,6 +648,7 @@ class AbstractTab(QWidget):
add_history_item = pyqtSignal(QUrl, QUrl, str) # url, requested url, title
fullscreen_requested = pyqtSignal(bool)
renderer_process_terminated = pyqtSignal(TerminationStatus, int)
predicted_navigation = pyqtSignal(QUrl)
def __init__(self, *, win_id, mode_manager, private, parent=None):
self.private = private
@@ -639,16 +662,6 @@ class AbstractTab(QWidget):
tab_registry[self.tab_id] = self
objreg.register('tab', self, registry=self.registry)
# self.history = AbstractHistory(self)
# self.scroller = AbstractScroller(self, parent=self)
# self.caret = AbstractCaret(win_id=win_id, tab=self,
# mode_manager=mode_manager, parent=self)
# self.zoom = AbstractZoom(win_id=win_id)
# self.search = AbstractSearch(parent=self)
# self.printing = AbstractPrinting()
# self.elements = AbstractElements(self)
# self.action = AbstractAction()
self.data = TabData()
self._layout = miscwidgets.WrapperLayout(self)
self._widget = None
@@ -666,6 +679,8 @@ class AbstractTab(QWidget):
objreg.register('hintmanager', hintmanager, scope='tab',
window=self.win_id, tab=self.tab_id)
self.predicted_navigation.connect(self._on_predicted_navigation)
def _set_widget(self, widget):
# pylint: disable=protected-access
self._widget = widget
@@ -678,6 +693,7 @@ class AbstractTab(QWidget):
self.printing._widget = widget
self.action._widget = widget
self.elements._widget = widget
self.settings._settings = widget.settings()
self._install_event_filter()
self.zoom.set_default()
@@ -712,6 +728,14 @@ class AbstractTab(QWidget):
evt.posted = True
QApplication.postEvent(recipient, evt)
@pyqtSlot(QUrl)
def _on_predicted_navigation(self, url):
"""Adjust the title if we are going to visit an URL soon."""
qtutils.ensure_valid(url)
url_string = url.toDisplayString()
log.webview.debug("Predicted navigation: {}".format(url_string))
self.title_changed.emit(url_string)
@pyqtSlot(QUrl)
def _on_url_changed(self, url):
"""Update title when URL has changed and no title is available."""
@@ -723,10 +747,26 @@ class AbstractTab(QWidget):
def _on_load_started(self):
self._progress = 0
self._has_ssl_errors = False
self.data.viewing_source = False
self._set_load_status(usertypes.LoadStatus.loading)
self.load_started.emit()
@pyqtSlot(usertypes.NavigationRequest)
def _on_navigation_request(self, navigation):
"""Handle common acceptNavigationRequest code."""
url = utils.elide(navigation.url.toDisplayString(), 100)
log.webview.debug("navigation request: url {}, type {}, is_main_frame "
"{}".format(url,
navigation.navigation_type,
navigation.is_main_frame))
if (navigation.navigation_type == navigation.Type.link_clicked and
not navigation.url.isValid()):
msg = urlutils.get_errstring(navigation.url,
"Invalid link clicked")
message.error(msg)
self.data.open_target = usertypes.ClickTarget.normal
navigation.accepted = False
def handle_auto_insert_mode(self, ok):
"""Handle `input.insert_mode.auto_load` after loading finished."""
if not config.val.input.insert_mode.auto_load or not ok:
@@ -749,6 +789,10 @@ class AbstractTab(QWidget):
@pyqtSlot(bool)
def _on_load_finished(self, ok):
if sip.isdeleted(self._widget):
# https://github.com/qutebrowser/qutebrowser/issues/3498
return
sess_manager = objreg.get('session-manager')
sess_manager.save_autosave()
@@ -761,7 +805,9 @@ class AbstractTab(QWidget):
self._set_load_status(usertypes.LoadStatus.warn)
else:
self._set_load_status(usertypes.LoadStatus.error)
self.load_finished.emit(ok)
if not self.title():
self.title_changed.emit(self.url().toDisplayString())
@@ -790,11 +836,12 @@ class AbstractTab(QWidget):
def load_status(self):
return self._load_status
def _openurl_prepare(self, url):
def _openurl_prepare(self, url, *, predict=True):
qtutils.ensure_valid(url)
self.title_changed.emit(url.toDisplayString())
if predict:
self.predicted_navigation.emit(url)
def openurl(self, url):
def openurl(self, url, *, predict=True):
raise NotImplementedError
def reload(self, *, force=False):
@@ -811,7 +858,7 @@ class AbstractTab(QWidget):
raise NotImplementedError
def dump_async(self, callback, *, plain=False):
"""Dump the current page to a file ascync.
"""Dump the current page's html asynchronously.
The given callback will be called with the result when dumping is
complete.

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -26,20 +26,16 @@ import functools
import typing
from PyQt5.QtWidgets import QApplication, QTabBar, QDialog
from PyQt5.QtCore import Qt, QUrl, QEvent, QUrlQuery
from PyQt5.QtGui import QKeyEvent
from PyQt5.QtCore import pyqtSlot, Qt, QUrl, QEvent, QUrlQuery
from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog
import pygments
import pygments.lexers
import pygments.formatters
from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners
from qutebrowser.config import config, configdata
from qutebrowser.browser import (urlmarks, browsertab, inspector, navigate,
webelem, downloads)
from qutebrowser.keyinput import modeman
from qutebrowser.keyinput import modeman, keyutils
from qutebrowser.utils import (message, usertypes, log, qtutils, urlutils,
objreg, utils, debug, standarddir)
objreg, utils, standarddir)
from qutebrowser.utils.usertypes import KeyMode
from qutebrowser.misc import editor, guiprocess
from qutebrowser.completion.models import urlmodel, miscmodels
@@ -57,7 +53,6 @@ class CommandDispatcher:
cmdutils.register() decorators are run, currentWidget() will return None.
Attributes:
_editor: The ExternalEditor object.
_win_id: The window ID the CommandDispatcher is associated with.
_tabbed_browser: The TabbedBrowser used.
"""
@@ -77,16 +72,16 @@ class CommandDispatcher:
def _count(self):
"""Convenience method to get the widget count."""
return self._tabbed_browser.count()
return self._tabbed_browser.widget.count()
def _set_current_index(self, idx):
"""Convenience method to set the current widget index."""
cmdutils.check_overflow(idx, 'int')
self._tabbed_browser.setCurrentIndex(idx)
self._tabbed_browser.widget.setCurrentIndex(idx)
def _current_index(self):
"""Convenience method to get the current widget index."""
return self._tabbed_browser.currentIndex()
return self._tabbed_browser.widget.currentIndex()
def _current_url(self):
"""Convenience method to get the current url."""
@@ -105,7 +100,7 @@ class CommandDispatcher:
def _current_widget(self):
"""Get the currently active widget from a command."""
widget = self._tabbed_browser.currentWidget()
widget = self._tabbed_browser.widget.currentWidget()
if widget is None:
raise cmdexc.CommandError("No WebView available yet!")
return widget
@@ -151,10 +146,10 @@ class CommandDispatcher:
None if no widget was found.
"""
if count is None:
return self._tabbed_browser.currentWidget()
return self._tabbed_browser.widget.currentWidget()
elif 1 <= count <= self._count():
cmdutils.check_overflow(count + 1, 'int')
return self._tabbed_browser.widget(count - 1)
return self._tabbed_browser.widget.widget(count - 1)
else:
return None
@@ -167,7 +162,7 @@ class CommandDispatcher:
if not show_error:
return
raise cmdexc.CommandError("No last focused tab!")
idx = self._tabbed_browser.indexOf(tab)
idx = self._tabbed_browser.widget.indexOf(tab)
if idx == -1:
raise cmdexc.CommandError("Last focused tab vanished!")
self._set_current_index(idx)
@@ -216,7 +211,7 @@ class CommandDispatcher:
what's configured in 'tabs.select_on_remove'.
count: The tab index to close, or None
"""
tabbar = self._tabbed_browser.tabBar()
tabbar = self._tabbed_browser.widget.tabBar()
selection_override = self._get_selection_override(prev, next_,
opposite)
@@ -268,7 +263,7 @@ class CommandDispatcher:
return
to_pin = not tab.data.pinned
self._tabbed_browser.set_tab_pinned(tab, to_pin)
self._tabbed_browser.widget.set_tab_pinned(tab, to_pin)
@cmdutils.register(instance='command-dispatcher', name='open',
maxsplit=0, scope='window')
@@ -487,7 +482,8 @@ class CommandDispatcher:
"""
cmdutils.check_exclusive((bg, window), 'bw')
curtab = self._current_widget()
cur_title = self._tabbed_browser.page_title(self._current_index())
cur_title = self._tabbed_browser.widget.page_title(
self._current_index())
try:
history = curtab.history.serialize()
except browsertab.WebTabError as e:
@@ -503,18 +499,18 @@ class CommandDispatcher:
newtab = new_tabbed_browser.tabopen(background=bg)
new_tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=newtab.win_id)
idx = new_tabbed_browser.indexOf(newtab)
idx = new_tabbed_browser.widget.indexOf(newtab)
new_tabbed_browser.set_page_title(idx, cur_title)
if config.val.tabs.favicons.show:
new_tabbed_browser.setTabIcon(idx, curtab.icon())
new_tabbed_browser.widget.set_page_title(idx, cur_title)
if curtab.data.should_show_icon():
new_tabbed_browser.widget.setTabIcon(idx, curtab.icon())
if config.val.tabs.tabs_are_windows:
new_tabbed_browser.window().setWindowIcon(curtab.icon())
new_tabbed_browser.widget.window().setWindowIcon(curtab.icon())
newtab.data.keep_icon = True
newtab.history.deserialize(history)
newtab.zoom.set_factor(curtab.zoom.factor())
new_tabbed_browser.set_tab_pinned(newtab, curtab.data.pinned)
new_tabbed_browser.widget.set_tab_pinned(newtab, curtab.data.pinned)
return newtab
@cmdutils.register(instance='command-dispatcher', scope='window')
@@ -536,14 +532,19 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('win_id', completion=miscmodels.window)
def tab_give(self, win_id: int = None):
@cmdutils.argument('count', count=True)
def tab_give(self, win_id: int = None, count=None):
"""Give the current tab to a new or existing window if win_id given.
If no win_id is given, the tab will get detached into a new window.
Args:
win_id: The window ID of the window to give the current tab to.
count: Overrides win_id (index starts at 1 for win_id=0).
"""
if count is not None:
win_id = count - 1
if win_id == self._win_id:
raise cmdexc.CommandError("Can't give a tab to the same window")
@@ -638,7 +639,13 @@ class CommandDispatcher:
- `next`: Open a _next_ link.
- `up`: Go up a level in the current URL.
- `increment`: Increment the last number in the URL.
Uses the
link:settings.html#url.incdec_segments[url.incdec_segments]
config option.
- `decrement`: Decrement the last number in the URL.
Uses the
link:settings.html#url.incdec_segments[url.incdec_segments]
config option.
tab: Open in a new tab.
bg: Open in a background tab.
@@ -761,6 +768,15 @@ class CommandDispatcher:
self._current_widget().scroller.to_perc(x, y)
@cmdutils.register(instance='command-dispatcher', scope='window')
def scroll_to_anchor(self, name):
"""Scroll to the given anchor in the document.
Args:
name: The anchor to scroll to.
"""
self._current_widget().scroller.to_anchor(name)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('top_navigate', metavar='ACTION',
@@ -839,7 +855,7 @@ class CommandDispatcher:
keep: Stay in visual mode after yanking the selection.
"""
if what == 'title':
s = self._tabbed_browser.page_title(self._current_index())
s = self._tabbed_browser.widget.page_title(self._current_index())
elif what == 'domain':
port = self._current_url().port()
s = '{}://{}{}'.format(self._current_url().scheme(),
@@ -849,14 +865,21 @@ class CommandDispatcher:
s = self._yank_url(what)
what = 'URL' # For printing
elif what == 'selection':
def _selection_callback(s):
if not s:
message.info("Nothing to yank")
return
self._yank_to_target(s, sel, what, keep)
caret = self._current_widget().caret
s = caret.selection()
if not caret.has_selection() or not s:
message.info("Nothing to yank")
return
caret.selection(callback=_selection_callback)
return
else: # pragma: no cover
raise ValueError("Invalid value {!r} for `what'.".format(what))
self._yank_to_target(s, sel, what, keep)
def _yank_to_target(self, s, sel, what, keep):
if sel and utils.supports_selection():
target = "primary selection"
else:
@@ -944,7 +967,7 @@ class CommandDispatcher:
force: Avoid confirmation for pinned tabs.
"""
cmdutils.check_exclusive((prev, next_), 'pn')
cur_idx = self._tabbed_browser.currentIndex()
cur_idx = self._tabbed_browser.widget.currentIndex()
assert cur_idx != -1
def _to_close(i):
@@ -953,22 +976,25 @@ class CommandDispatcher:
(prev and i < cur_idx) or
(next_ and i > cur_idx))
# Check to see if we are closing any pinned tabs
if not force:
for i, tab in enumerate(self._tabbed_browser.widgets()):
if _to_close(i) and tab.data.pinned:
self._tabbed_browser.tab_close_prompt_if_pinned(
tab,
force,
lambda: self.tab_only(
prev=prev, next_=next_, force=True))
return
# close as many tabs as we can
first_tab = True
pinned_tabs_cleanup = False
for i, tab in enumerate(self._tabbed_browser.widgets()):
if _to_close(i):
self._tabbed_browser.close_tab(tab, new_undo=first_tab)
first_tab = False
if force or not tab.data.pinned:
self._tabbed_browser.close_tab(tab, new_undo=first_tab)
first_tab = False
else:
pinned_tabs_cleanup = tab
# Check to see if we would like to close any pinned tabs
if pinned_tabs_cleanup:
self._tabbed_browser.tab_close_prompt_if_pinned(
pinned_tabs_cleanup,
force,
lambda: self.tab_only(
prev=prev, next_=next_, force=True),
text="Are you sure you want to close pinned tabs?")
@cmdutils.register(instance='command-dispatcher', scope='window')
def undo(self):
@@ -996,7 +1022,7 @@ class CommandDispatcher:
elif config.val.tabs.wrap:
self._set_current_index(newidx % self._count())
else:
raise cmdexc.CommandError("First tab")
log.webview.debug("First tab")
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@@ -1016,7 +1042,7 @@ class CommandDispatcher:
elif config.val.tabs.wrap:
self._set_current_index(newidx % self._count())
else:
raise cmdexc.CommandError("Last tab")
log.webview.debug("Last tab")
def _resolve_buffer_index(self, index):
"""Resolve a buffer index to the tabbedbrowser and tab.
@@ -1058,11 +1084,11 @@ class CommandDispatcher:
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
if not 0 < idx <= tabbed_browser.count():
if not 0 < idx <= tabbed_browser.widget.count():
raise cmdexc.CommandError(
"There's no tab with index {}!".format(idx))
return (tabbed_browser, tabbed_browser.widget(idx-1))
return (tabbed_browser, tabbed_browser.widget.widget(idx-1))
@cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0)
@@ -1074,29 +1100,32 @@ class CommandDispatcher:
Focuses window if necessary when index is given. If both index and
count are given, use count.
With neither index nor count given, open the qute://tabs page.
Args:
index: The [win_id/]index of the tab to focus. Or a substring
in which case the closest match will be focused.
count: The tab index to focus, starting with 1.
"""
if count is None and index is None:
raise cmdexc.CommandError("buffer: Either a count or the argument "
"index must be specified.")
self.openurl('qute://tabs/', tab=True)
return
if count is not None:
index = str(count)
tabbed_browser, tab = self._resolve_buffer_index(index)
window = tabbed_browser.window()
window = tabbed_browser.widget.window()
window.activateWindow()
window.raise_()
tabbed_browser.setCurrentWidget(tab)
tabbed_browser.widget.setCurrentWidget(tab)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('index', choices=['last'])
@cmdutils.argument('count', count=True)
def tab_focus(self, index: typing.Union[str, int] = None, count=None):
def tab_focus(self, index: typing.Union[str, int] = None,
count=None, no_last=False):
"""Select the tab given as argument/[count].
If neither count nor index are given, it behaves like tab-next.
@@ -1108,13 +1137,14 @@ class CommandDispatcher:
Negative indices count from the end, such that -1 is the
last tab.
count: The tab index to focus, starting with 1.
no_last: Whether to avoid focusing last tab if already focused.
"""
index = count if count is not None else index
if index == 'last':
self._tab_focus_last()
return
elif index == self._current_index() + 1:
elif not no_last and index == self._current_index() + 1:
self._tab_focus_last(show_error=False)
return
elif index is None:
@@ -1173,7 +1203,7 @@ class CommandDispatcher:
cur_idx = self._current_index()
cmdutils.check_overflow(cur_idx, 'int')
cmdutils.check_overflow(new_idx, 'int')
self._tabbed_browser.tabBar().moveTab(cur_idx, new_idx)
self._tabbed_browser.widget.tabBar().moveTab(cur_idx, new_idx)
@cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0, no_replace_variables=True)
@@ -1204,9 +1234,29 @@ class CommandDispatcher:
log.procs.debug("Executing {} with args {}, userscript={}".format(
cmd, args, userscript))
@pyqtSlot()
def _on_proc_finished():
if output:
tb = objreg.get('tabbed-browser', scope='window',
window='last-focused')
tb.openurl(QUrl('qute://spawn-output'), newtab=True)
if userscript:
def _selection_callback(s):
try:
runner = self._run_userscript(s, cmd, args, verbose)
runner.finished.connect(_on_proc_finished)
except cmdexc.CommandError as e:
message.error(str(e))
# ~ expansion is handled by the userscript module.
self._run_userscript(cmd, *args, verbose=verbose)
# dirty hack for async call because of:
# https://bugreports.qt.io/browse/QTBUG-53134
# until it fixed or blocked async call implemented:
# https://github.com/qutebrowser/qutebrowser/issues/3327
caret = self._current_widget().caret
caret.selection(callback=_selection_callback)
else:
cmd = os.path.expanduser(cmd)
proc = guiprocess.GUIProcess(what='command', verbose=verbose,
@@ -1215,18 +1265,14 @@ class CommandDispatcher:
proc.start_detached(cmd, args)
else:
proc.start(cmd, args)
if output:
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window='last-focused')
tabbed_browser.openurl(QUrl('qute://spawn-output'), newtab=True)
proc.finished.connect(_on_proc_finished)
@cmdutils.register(instance='command-dispatcher', scope='window')
def home(self):
"""Open main startpage in current tab."""
self.openurl(config.val.url.start_pages[0])
def _run_userscript(self, cmd, *args, verbose=False):
def _run_userscript(self, selection, cmd, args, verbose):
"""Run a userscript given as argument.
Args:
@@ -1236,21 +1282,15 @@ class CommandDispatcher:
"""
env = {
'QUTE_MODE': 'command',
'QUTE_SELECTED_TEXT': selection,
}
idx = self._current_index()
if idx != -1:
env['QUTE_TITLE'] = self._tabbed_browser.page_title(idx)
tab = self._tabbed_browser.currentWidget()
if tab is not None and tab.caret.has_selection():
env['QUTE_SELECTED_TEXT'] = tab.caret.selection()
try:
env['QUTE_SELECTED_HTML'] = tab.caret.selection(html=True)
except browsertab.UnsupportedOperationError:
pass
env['QUTE_TITLE'] = self._tabbed_browser.widget.page_title(idx)
# FIXME:qtwebengine: If tab is None, run_async will fail!
tab = self._tabbed_browser.widget.currentWidget()
try:
url = self._tabbed_browser.current_url()
@@ -1260,10 +1300,11 @@ class CommandDispatcher:
env['QUTE_URL'] = url.toString(QUrl.FullyEncoded)
try:
userscripts.run_async(tab, cmd, *args, win_id=self._win_id,
env=env, verbose=verbose)
runner = userscripts.run_async(
tab, cmd, *args, win_id=self._win_id, env=env, verbose=verbose)
except userscripts.Error as e:
raise cmdexc.CommandError(e)
return runner
@cmdutils.register(instance='command-dispatcher', scope='window')
def quickmark_save(self):
@@ -1325,7 +1366,8 @@ class CommandDispatcher:
link:qute://bookmarks[bookmarks page].
Args:
url: url to save as a bookmark. If None, use url of current page.
url: url to save as a bookmark. If not given, use url of current
page.
title: title of the new bookmark.
toggle: remove the bookmark instead of raising an error if it
already exists.
@@ -1334,7 +1376,7 @@ class CommandDispatcher:
raise cmdexc.CommandError('Title must be provided if url has '
'been provided')
bookmark_manager = objreg.get('bookmark-manager')
if url is None:
if not url:
url = self._current_url()
else:
try:
@@ -1434,8 +1476,7 @@ class CommandDispatcher:
mhtml_: Download the current page and all assets as mhtml file.
"""
# FIXME:qtwebengine do this with the QtWebEngine download manager?
download_manager = objreg.get('qtnetwork-download-manager',
scope='window', window=self._win_id)
download_manager = objreg.get('qtnetwork-download-manager')
target = None
if dest is not None:
dest = downloads.transform_path(dest)
@@ -1480,34 +1521,26 @@ class CommandDispatcher:
)
@cmdutils.register(instance='command-dispatcher', scope='window')
def view_source(self):
"""Show the source of the current page in a new tab."""
tab = self._current_widget()
if tab.data.viewing_source:
raise cmdexc.CommandError("Already viewing source!")
def view_source(self, edit=False):
"""Show the source of the current page in a new tab.
Args:
edit: Edit the source in the editor instead of opening a tab.
"""
tab = self._current_widget()
try:
current_url = self._current_url()
except cmdexc.CommandError as e:
message.error(str(e))
return
if current_url.scheme() == 'view-source':
raise cmdexc.CommandError("Already viewing source!")
def show_source_cb(source):
"""Show source as soon as it's ready."""
# WORKAROUND for https://github.com/PyCQA/pylint/issues/491
# pylint: disable=no-member
lexer = pygments.lexers.HtmlLexer()
formatter = pygments.formatters.HtmlFormatter(
full=True, linenos='table',
title='Source for {}'.format(current_url.toDisplayString()))
# pylint: enable=no-member
highlighted = pygments.highlight(source, lexer, formatter)
new_tab = self._tabbed_browser.tabopen()
new_tab.set_html(highlighted)
new_tab.data.viewing_source = True
tab.dump_async(show_source_cb)
if edit:
ed = editor.ExternalEditor(self._tabbed_browser)
tab.dump_async(ed.edit)
else:
tab.action.show_source()
@cmdutils.register(instance='command-dispatcher', scope='window',
debug=True)
@@ -1613,9 +1646,11 @@ class CommandDispatcher:
caret_position = elem.caret_position()
ed = editor.ExternalEditor(self._tabbed_browser)
ed.editing_finished.connect(functools.partial(
self.on_editing_finished, elem))
ed = editor.ExternalEditor(watch=True, parent=self._tabbed_browser)
ed.file_updated.connect(functools.partial(
self.on_file_updated, ed, elem))
ed.editing_finished.connect(lambda: mainwindow.raise_window(
objreg.last_focused_window(), alert=False))
ed.edit(text, caret_position)
@cmdutils.register(instance='command-dispatcher', scope='window')
@@ -1628,10 +1663,10 @@ class CommandDispatcher:
tab = self._current_widget()
tab.elements.find_focused(self._open_editor_cb)
def on_editing_finished(self, elem, text):
def on_file_updated(self, ed, elem, text):
"""Write the editor text into the form field and clean up tempfile.
Callback for GUIProcess when the editor was closed.
Callback for GUIProcess when the edited text was updated.
Args:
elem: The WebElementWrapper which was modified.
@@ -1641,10 +1676,10 @@ class CommandDispatcher:
elem.set_value(text)
except webelem.OrphanedError as e:
message.error('Edited element vanished')
ed.backup()
except webelem.Error as e:
raise cmdexc.CommandError(str(e))
mainwindow.raise_window(objreg.last_focused_window(), alert=False)
message.error(str(e))
ed.backup()
@cmdutils.register(instance='command-dispatcher', maxsplit=0,
scope='window')
@@ -1753,10 +1788,10 @@ class CommandDispatcher:
"""
self.set_mark("'")
tab = self._current_widget()
if tab.search.search_displayed:
tab.search.clear()
if not text:
if tab.search.search_displayed:
tab.search.clear()
return
options = {
@@ -2087,15 +2122,13 @@ class CommandDispatcher:
global_: If given, the keys are sent to the qutebrowser UI.
"""
try:
keyinfos = utils.parse_keystring(keystring)
except utils.KeyParseError as e:
sequence = keyutils.KeySequence.parse(keystring)
except keyutils.KeyParseError as e:
raise cmdexc.CommandError(str(e))
for keyinfo in keyinfos:
press_event = QKeyEvent(QEvent.KeyPress, keyinfo.key,
keyinfo.modifiers, keyinfo.text)
release_event = QKeyEvent(QEvent.KeyRelease, keyinfo.key,
keyinfo.modifiers, keyinfo.text)
for keyinfo in sequence:
press_event = keyinfo.to_event(QEvent.KeyPress)
release_event = keyinfo.to_event(QEvent.KeyRelease)
if global_:
window = QApplication.focusWindow()
@@ -2138,7 +2171,7 @@ class CommandDispatcher:
ed = editor.ExternalEditor(self._tabbed_browser)
# Passthrough for openurl args (e.g. -t, -b, -w)
ed.editing_finished.connect(functools.partial(
ed.file_updated.connect(functools.partial(
self._open_if_changed, old_url=old_url, bg=bg, tab=tab,
window=window, private=private, related=related))
@@ -2195,12 +2228,5 @@ class CommandDispatcher:
pass
return
window = self._tabbed_browser.window()
if window.isFullScreen():
window.setWindowState(
window.state_before_fullscreen & ~Qt.WindowFullScreen)
else:
window.state_before_fullscreen = window.windowState()
window.showFullScreen()
log.misc.debug('state before fullscreen: {}'.format(
debug.qflags_key(Qt, window.state_before_fullscreen)))
window = self._tabbed_browser.widget.window()
window.setWindowState(window.windowState() ^ Qt.WindowFullScreen)

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -31,7 +31,7 @@ import enum
import sip
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex,
QTimer, QAbstractListModel)
QTimer, QAbstractListModel, QUrl)
from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.config import config
@@ -166,6 +166,7 @@ def get_filename_question(*, suggested_filename, url, parent=None):
q.title = "Save file to:"
q.text = "Please enter a location for <b>{}</b>".format(
html.escape(url.toDisplayString()))
q.url = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
q.mode = usertypes.PromptMode.download
q.completed.connect(q.deleteLater)
q.default = _path_suggestion(suggested_filename)
@@ -237,11 +238,14 @@ class FileDownloadTarget(_DownloadTarget):
Attributes:
filename: Filename where the download should be saved.
force_overwrite: Whether to overwrite the target without
prompting the user.
"""
def __init__(self, filename):
def __init__(self, filename, force_overwrite=False):
# pylint: disable=super-init-not-called
self.filename = filename
self.force_overwrite = force_overwrite
def suggested_filename(self):
return os.path.basename(self.filename)
@@ -737,7 +741,8 @@ class AbstractDownloadItem(QObject):
if isinstance(target, FileObjDownloadTarget):
self._set_fileobj(target.fileobj, autoclose=False)
elif isinstance(target, FileDownloadTarget):
self._set_filename(target.filename)
self._set_filename(
target.filename, force_overwrite=target.force_overwrite)
elif isinstance(target, OpenFileDownloadTarget):
try:
fobj = temp_download_manager.get_tmpfile(self.basename)

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2017-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -25,12 +25,15 @@ import json
import fnmatch
import functools
import glob
import textwrap
import attr
from PyQt5.QtCore import pyqtSignal, QObject, QUrl
from qutebrowser.utils import log, standarddir, jinja, objreg
from qutebrowser.utils import (log, standarddir, jinja, objreg, utils,
javascript)
from qutebrowser.commands import cmdutils
from qutebrowser.browser import downloads
def _scripts_dir():
@@ -46,6 +49,7 @@ class GreasemonkeyScript:
self._code = code
self.includes = []
self.excludes = []
self.requires = []
self.description = None
self.name = None
self.namespace = None
@@ -67,6 +71,8 @@ class GreasemonkeyScript:
self.run_at = value
elif name == 'noframes':
self.runs_on_sub_frames = False
elif name == 'require':
self.requires.append(value)
HEADER_REGEX = r'// ==UserScript==|\n+// ==/UserScript==\n'
PROPS_REGEX = r'// @(?P<prop>[^\s]+)\s*(?P<val>.*)'
@@ -86,7 +92,7 @@ class GreasemonkeyScript:
props = ""
script = cls(re.findall(cls.PROPS_REGEX, props), source)
script.script_meta = props
if not props:
if not script.includes:
script.includes = ['*']
return script
@@ -94,17 +100,18 @@ class GreasemonkeyScript:
"""Return the processed JavaScript code of this script.
Adorns the source code with GM_* methods for Greasemonkey
compatibility and wraps it in an IFFE to hide it within a
compatibility and wraps it in an IIFE to hide it within a
lexical scope. Note that this means line numbers in your
browser's debugger/inspector will not match up to the line
numbers in the source script directly.
"""
return jinja.js_environment.get_template(
'greasemonkey_wrapper.js').render(
scriptName="/".join([self.namespace or '', self.name]),
scriptInfo=self._meta_json(),
scriptMeta=self.script_meta,
scriptSource=self._code)
template = jinja.js_environment.get_template('greasemonkey_wrapper.js')
return template.render(
scriptName=javascript.string_escape(
"/".join([self.namespace or '', self.name])),
scriptInfo=self._meta_json(),
scriptMeta=javascript.string_escape(self.script_meta),
scriptSource=self._code)
def _meta_json(self):
return json.dumps({
@@ -116,6 +123,14 @@ class GreasemonkeyScript:
'run-at': self.run_at,
})
def add_required_script(self, source):
"""Add the source of a required script to this script."""
# The additional source is indented in case it also contains a
# metadata block. Because we pass everything at once to
# QWebEngineScript and that would parse the first metadata block
# found as the valid one.
self._code = "\n".join([textwrap.indent(source, " "), self._code])
@attr.s
class MatchingScripts(object):
@@ -135,7 +150,7 @@ class GreasemonkeyManager(QObject):
Signals:
scripts_reloaded: Emitted when scripts are reloaded from disk.
Any cached or already-injected scripts should be
considered obselete.
considered obsolete.
"""
scripts_reloaded = pyqtSignal()
@@ -146,15 +161,24 @@ class GreasemonkeyManager(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._run_start = []
self._run_end = []
self._run_idle = []
self._in_progress_dls = []
self.load_scripts()
@cmdutils.register(name='greasemonkey-reload',
instance='greasemonkey')
def load_scripts(self):
def load_scripts(self, force=False):
"""Re-read Greasemonkey scripts from disk.
The scripts are read from a 'greasemonkey' subdirectory in
qutebrowser's data directory (see `:version`).
Args:
force: For any scripts that have required dependencies,
re-download them.
"""
self._run_start = []
self._run_end = []
@@ -170,24 +194,115 @@ class GreasemonkeyManager(QObject):
script = GreasemonkeyScript.parse(script_file.read())
if not script.name:
script.name = script_filename
if script.run_at == 'document-start':
self._run_start.append(script)
elif script.run_at == 'document-end':
self._run_end.append(script)
elif script.run_at == 'document-idle':
self._run_idle.append(script)
else:
log.greasemonkey.warning("Script {} has invalid run-at "
"defined, defaulting to "
"document-end"
.format(script_path))
# Default as per
# https://wiki.greasespot.net/Metadata_Block#.40run-at
self._run_end.append(script)
log.greasemonkey.debug("Loaded script: {}".format(script.name))
self.add_script(script, force)
self.scripts_reloaded.emit()
def add_script(self, script, force=False):
"""Add a GreasemonkeyScript to this manager.
Args:
force: Fetch and overwrite any dependancies which are
already locally cached.
"""
if script.requires:
log.greasemonkey.debug(
"Deferring script until requirements are "
"fulfilled: {}".format(script.name))
self._get_required_scripts(script, force)
else:
self._add_script(script)
def _add_script(self, script):
if script.run_at == 'document-start':
self._run_start.append(script)
elif script.run_at == 'document-end':
self._run_end.append(script)
elif script.run_at == 'document-idle':
self._run_idle.append(script)
else:
if script.run_at:
log.greasemonkey.warning("Script {} has invalid run-at "
"defined, defaulting to "
"document-end"
.format(script.name))
# Default as per
# https://wiki.greasespot.net/Metadata_Block#.40run-at
self._run_end.append(script)
log.greasemonkey.debug("Loaded script: {}".format(script.name))
def _required_url_to_file_path(self, url):
requires_dir = os.path.join(_scripts_dir(), 'requires')
if not os.path.exists(requires_dir):
os.mkdir(requires_dir)
return os.path.join(requires_dir, utils.sanitize_filename(url))
def _on_required_download_finished(self, script, download):
self._in_progress_dls.remove(download)
if not self._add_script_with_requires(script):
log.greasemonkey.debug(
"Finished download {} for script {} "
"but some requirements are still pending"
.format(download.basename, script.name))
def _add_script_with_requires(self, script, quiet=False):
"""Add a script with pending downloads to this GreasemonkeyManager.
Specifically a script that has dependancies specified via an
`@require` rule.
Args:
script: The GreasemonkeyScript to add.
quiet: True to suppress the scripts_reloaded signal after
adding `script`.
Returns: True if the script was added, False if there are still
dependancies being downloaded.
"""
# See if we are still waiting on any required scripts for this one
for dl in self._in_progress_dls:
if dl.requested_url in script.requires:
return False
# Need to add the required scripts to the IIFE now
for url in reversed(script.requires):
target_path = self._required_url_to_file_path(url)
log.greasemonkey.debug(
"Adding required script for {} to IIFE: {}"
.format(script.name, url))
with open(target_path, encoding='utf8') as f:
script.add_required_script(f.read())
self._add_script(script)
if not quiet:
self.scripts_reloaded.emit()
return True
def _get_required_scripts(self, script, force=False):
required_dls = [(url, self._required_url_to_file_path(url))
for url in script.requires]
if not force:
required_dls = [(url, path) for (url, path) in required_dls
if not os.path.exists(path)]
if not required_dls:
# All the required files exist already
self._add_script_with_requires(script, quiet=True)
return
download_manager = objreg.get('qtnetwork-download-manager')
for url, target_path in required_dls:
target = downloads.FileDownloadTarget(target_path,
force_overwrite=True)
download = download_manager.get(QUrl(url), target=target,
auto_remove=True)
download.requested_url = url
self._in_progress_dls.append(download)
if download.successful:
self._on_required_download_finished(script, download)
else:
download.finished.connect(
functools.partial(self._on_required_download_finished,
script, download))
def scripts_for(self, url):
"""Fetch scripts that are registered to run for url.
@@ -196,11 +311,23 @@ class GreasemonkeyManager(QObject):
"""
if url.scheme() not in self.greaseable_schemes:
return MatchingScripts(url, [], [], [])
match = functools.partial(fnmatch.fnmatch,
url.toString(QUrl.FullyEncoded))
string_url = url.toString(QUrl.FullyEncoded)
def _match(pattern):
# For include and exclude rules if they start and end with '/' they
# should be treated as a (ecma syntax) regular expression.
if pattern.startswith('/') and pattern.endswith('/'):
matches = re.search(pattern[1:-1], string_url, flags=re.I)
return matches is not None
# Otherwise they are glob expressions.
return fnmatch.fnmatch(string_url, pattern)
tester = (lambda script:
any(match(pat) for pat in script.includes) and
not any(match(pat) for pat in script.excludes))
any(_match(pat) for pat in script.includes) and
not any(_match(pat) for pat in script.excludes))
return MatchingScripts(
url,
[script for script in self._run_start if tester(script)],

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -291,8 +291,7 @@ class HintActions:
user_agent = context.tab.user_agent()
# FIXME:qtwebengine do this with QtWebEngine downloads?
download_manager = objreg.get('qtnetwork-download-manager',
scope='window', window=self._win_id)
download_manager = objreg.get('qtnetwork-download-manager')
download_manager.get(url, qnam=qnam, user_agent=user_agent,
prompt_download_directory=prompt)
@@ -683,7 +682,7 @@ class HintManager(QObject):
"""
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=self._win_id)
tab = tabbed_browser.currentWidget()
tab = tabbed_browser.widget.currentWidget()
if tab is None:
raise cmdexc.CommandError("No WebView available yet!")
@@ -910,20 +909,27 @@ class HintManager(QObject):
@cmdutils.register(instance='hintmanager', scope='tab',
modes=[usertypes.KeyMode.hint])
def follow_hint(self, keystring=None):
def follow_hint(self, select=False, keystring=None):
"""Follow a hint.
Args:
select: Only select the given hint, don't necessarily follow it.
keystring: The hint to follow, or None.
"""
if keystring is None:
if self._context.to_follow is None:
raise cmdexc.CommandError("No hint to follow")
elif select:
raise cmdexc.CommandError("Can't use --select without hint.")
else:
keystring = self._context.to_follow
elif keystring not in self._context.labels:
raise cmdexc.CommandError("No hint {}!".format(keystring))
self._fire(keystring)
if select:
self.handle_partial_key(keystring)
else:
self._fire(keystring)
@pyqtSlot(usertypes.KeyMode)
def on_mode_left(self, mode):

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -172,7 +172,7 @@ class WebHistory(sql.SqlTable):
@pyqtSlot(QUrl, QUrl, str)
def add_from_tab(self, url, requested_url, title):
"""Add a new history entry as slot, called from a BrowserTab."""
if any(url.scheme() == 'data' or
if any(url.scheme() in ('data', 'view-source') or
(url.scheme(), url.host()) == ('qute', 'back')
for url in (url, requested_url)):
return

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -151,8 +151,9 @@ class MouseEventFilter(QObject):
if elem.is_editable():
log.mouse.debug("Clicked editable element!")
modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
'click', only_if_normal=True)
if config.val.input.insert_mode.auto_enter:
modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
'click', only_if_normal=True)
else:
log.mouse.debug("Clicked non-editable element!")
if config.val.input.insert_mode.auto_leave:

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -34,6 +34,10 @@ def init():
QNetworkProxyFactory.setApplicationProxyFactory(proxy_factory)
def shutdown():
QNetworkProxyFactory.setApplicationProxyFactory(None)
class ProxyFactory(QNetworkProxyFactory):
"""Factory for proxies to be used by qutebrowser."""
@@ -61,6 +65,9 @@ class ProxyFactory(QNetworkProxyFactory):
"""
proxy = config.val.content.proxy
if proxy is configtypes.SYSTEM_PROXY:
# On Linux, use "export http_proxy=socks5://host:port" to manually
# set system proxy.
# ref. http://doc.qt.io/qt-5/qnetworkproxyfactory.html#systemProxyForQuery
proxies = QNetworkProxyFactory.systemProxyForQuery(query)
elif isinstance(proxy, pac.PACFetcher):
proxies = proxy.resolve(query)

View File

@@ -1,7 +1,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015 Daniel Schadt
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -20,6 +20,7 @@
"""Download manager."""
import io
import os.path
import shutil
import functools
@@ -161,6 +162,7 @@ class DownloadItem(downloads.AbstractDownloadItem):
QTimer.singleShot(0, lambda: self._die(reply.errorString()))
def _do_cancel(self):
self._read_timer.stop()
if self._reply is not None:
self._reply.finished.disconnect(self._on_reply_finished)
self._reply.abort()
@@ -198,21 +200,23 @@ class DownloadItem(downloads.AbstractDownloadItem):
def _ask_confirm_question(self, title, msg):
no_action = functools.partial(self.cancel, remove_data=False)
url = 'file://{}'.format(self._filename)
message.confirm_async(title=title, text=msg,
yes_action=self._after_set_filename,
no_action=no_action, cancel_action=no_action,
abort_on=[self.cancelled, self.error])
abort_on=[self.cancelled, self.error], url=url)
def _ask_create_parent_question(self, title, msg,
force_overwrite, remember_directory):
no_action = functools.partial(self.cancel, remove_data=False)
url = 'file://{}'.format(os.path.dirname(self._filename))
message.confirm_async(title=title, text=msg,
yes_action=(lambda:
self._after_create_parent_question(
force_overwrite,
remember_directory)),
no_action=no_action, cancel_action=no_action,
abort_on=[self.cancelled, self.error])
abort_on=[self.cancelled, self.error], url=url)
def _set_fileobj(self, fileobj, *, autoclose=True):
"""Set the file object to write the download to.
@@ -378,10 +382,10 @@ class DownloadManager(downloads.AbstractDownloadManager):
_networkmanager: A NetworkManager for generic downloads.
"""
def __init__(self, win_id, parent=None):
def __init__(self, parent=None):
super().__init__(parent)
self._networkmanager = networkmanager.NetworkManager(
win_id=win_id, tab_id=None,
win_id=None, tab_id=None,
private=config.val.content.private_browsing, parent=self)
@pyqtSlot('QUrl')

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -30,8 +30,10 @@ import time
import textwrap
import mimetypes
import urllib
import collections
import pkg_resources
import sip
from PyQt5.QtCore import QUrlQuery, QUrl
import qutebrowser
@@ -201,6 +203,27 @@ def qute_bookmarks(_url):
return 'text/html', html
@add_handler('tabs')
def qute_tabs(_url):
"""Handler for qute://tabs. Display information about all open tabs."""
tabs = collections.defaultdict(list)
for win_id, window in objreg.window_registry.items():
if sip.isdeleted(window):
continue
tabbed_browser = objreg.get('tabbed-browser',
scope='window',
window=win_id)
for tab in tabbed_browser.widgets():
if tab.url() not in [QUrl("qute://tabs/"), QUrl("qute://tabs")]:
urlstr = tab.url().toDisplayString()
tabs[str(win_id)].append((tab.title(), urlstr))
html = jinja.render('tabs.html',
title='Tabs',
tab_list_by_window=tabs)
return 'text/html', html
def history_data(start_time, offset=None):
"""Return history data.
@@ -240,8 +263,6 @@ def qute_history(url):
return 'text/html', json.dumps(history_data(start_time, offset))
else:
if not config.val.content.javascript.enabled:
return 'text/plain', b'JavaScript is required for qute://history'
return 'text/html', jinja.render(
'history.html',
title='History',
@@ -435,6 +456,22 @@ def qute_settings(url):
return 'text/html', html
@add_handler('bindings')
def qute_bindings(_url):
"""Handler for qute://bindings. View keybindings."""
bindings = {}
defaults = config.val.bindings.default
modes = set(defaults.keys()).union(config.val.bindings.commands)
modes.remove('normal')
modes = ['normal'] + sorted(list(modes))
for mode in modes:
bindings[mode] = config.key_instance.get_bindings_for(mode)
html = jinja.render('bindings.html', title='Bindings',
bindings=bindings)
return 'text/html', html
@add_handler('back')
def qute_back(url):
"""Handler for qute://back.
@@ -460,3 +497,10 @@ def qute_configdiff(url):
else:
data = config.instance.dump_userconfig().encode('utf-8')
return 'text/plain', data
@add_handler('pastebin-version')
def qute_pastebin_version(_url):
"""Handler that pastebins the version string."""
version.pastebin_version()
return 'text/plain', b'Paste called.'

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -19,7 +19,11 @@
"""Various utilities shared between webpage/webview subclasses."""
import os
import html
import netrc
from PyQt5.QtCore import QUrl
from qutebrowser.config import config
from qutebrowser.utils import usertypes, message, log, objreg, jinja, utils
@@ -27,7 +31,6 @@ from qutebrowser.mainwindow import mainwindow
class CallSuper(Exception):
"""Raised when the caller should call the superclass instead."""
@@ -61,30 +64,33 @@ def authentication_required(url, authenticator, abort_on):
else:
msg = '<b>{}</b> needs authentication'.format(
html.escape(url.toDisplayString()))
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
answer = message.ask(title="Authentication required", text=msg,
mode=usertypes.PromptMode.user_pwd,
abort_on=abort_on)
abort_on=abort_on, url=urlstr)
if answer is not None:
authenticator.setUser(answer.user)
authenticator.setPassword(answer.password)
return answer
def javascript_confirm(url, js_msg, abort_on):
def javascript_confirm(url, js_msg, abort_on, *, escape_msg=True):
"""Display a javascript confirm prompt."""
log.js.debug("confirm: {}".format(js_msg))
if config.val.content.javascript.modal_dialog:
raise CallSuper
js_msg = html.escape(js_msg) if escape_msg else js_msg
msg = 'From <b>{}</b>:<br/>{}'.format(html.escape(url.toDisplayString()),
html.escape(js_msg))
js_msg)
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
ans = message.ask('Javascript confirm', msg,
mode=usertypes.PromptMode.yesno,
abort_on=abort_on)
abort_on=abort_on, url=urlstr)
return bool(ans)
def javascript_prompt(url, js_msg, default, abort_on):
def javascript_prompt(url, js_msg, default, abort_on, *, escape_msg=True):
"""Display a javascript prompt."""
log.js.debug("prompt: {}".format(js_msg))
if config.val.content.javascript.modal_dialog:
@@ -92,12 +98,14 @@ def javascript_prompt(url, js_msg, default, abort_on):
if not config.val.content.javascript.prompt:
return (False, "")
js_msg = html.escape(js_msg) if escape_msg else js_msg
msg = '<b>{}</b> asks:<br/>{}'.format(html.escape(url.toDisplayString()),
html.escape(js_msg))
js_msg)
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
answer = message.ask('Javascript prompt', msg,
mode=usertypes.PromptMode.text,
default=default,
abort_on=abort_on)
abort_on=abort_on, url=urlstr)
if answer is None:
return (False, "")
@@ -105,7 +113,7 @@ def javascript_prompt(url, js_msg, default, abort_on):
return (True, answer)
def javascript_alert(url, js_msg, abort_on):
def javascript_alert(url, js_msg, abort_on, *, escape_msg=True):
"""Display a javascript alert."""
log.js.debug("alert: {}".format(js_msg))
if config.val.content.javascript.modal_dialog:
@@ -114,10 +122,12 @@ def javascript_alert(url, js_msg, abort_on):
if not config.val.content.javascript.alert:
return
js_msg = html.escape(js_msg) if escape_msg else js_msg
msg = 'From <b>{}</b>:<br/>{}'.format(html.escape(url.toDisplayString()),
html.escape(js_msg))
js_msg)
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
message.ask('Javascript alert', msg, mode=usertypes.PromptMode.alert,
abort_on=abort_on)
abort_on=abort_on, url=urlstr)
def javascript_log_message(level, source, line, msg):
@@ -164,9 +174,10 @@ def ignore_certificate_errors(url, errors, abort_on):
""".strip())
msg = err_template.render(url=url, errors=errors)
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
ignore = message.ask(title="Certificate errors - continue?", text=msg,
mode=usertypes.PromptMode.yesno, default=False,
abort_on=abort_on)
abort_on=abort_on, url=urlstr)
if ignore is None:
# prompt aborted
ignore = False
@@ -202,15 +213,17 @@ def feature_permission(url, option, msg, yes_action, no_action, abort_on):
config_val = config.instance.get(option)
if config_val == 'ask':
if url.isValid():
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
text = "Allow the website at <b>{}</b> to {}?".format(
html.escape(url.toDisplayString()), msg)
else:
urlstr = None
text = "Allow the website to {}?".format(msg)
return message.confirm_async(
yes_action=yes_action, no_action=no_action,
cancel_action=no_action, abort_on=abort_on,
title='Permission request', text=text)
title='Permission request', text=text, url=urlstr)
elif config_val:
yes_action()
return None
@@ -260,3 +273,41 @@ def get_user_stylesheet():
css += '\nhtml > ::-webkit-scrollbar { width: 0px; height: 0px; }'
return css
def netrc_authentication(url, authenticator):
"""Perform authorization using netrc.
Args:
url: The URL the request was done for.
authenticator: QAuthenticator object used to set credentials provided.
Return:
True if netrc found credentials for the URL.
False otherwise.
"""
if 'HOME' not in os.environ:
# We'll get an OSError by netrc if 'HOME' isn't available in
# os.environ. We don't want to log that, so we prevent it
# altogether.
return False
user, password = None, None
try:
net = netrc.netrc(config.val.content.netrc_file)
authenticators = net.authenticators(url.host())
if authenticators is not None:
(user, _account, password) = authenticators
except FileNotFoundError:
log.misc.debug("No .netrc file found")
except OSError:
log.misc.exception("Unable to read the netrc file")
except netrc.NetrcParseError:
log.misc.exception("Error when parsing the netrc file")
if user is None:
return False
authenticator.setUser(user)
authenticator.setPassword(password)
return True

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -76,11 +76,11 @@ class SignalFilter(QObject):
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=self._win_id)
try:
tabidx = tabbed_browser.indexOf(tab)
tabidx = tabbed_browser.widget.indexOf(tab)
except RuntimeError:
# The tab has been deleted already
return
if tabidx == tabbed_browser.currentIndex():
if tabidx == tabbed_browser.widget.currentIndex():
if log_signal:
log.signals.debug("emitting: {} (tab {})".format(
debug.dbg_signal(signal, args), tabidx))

View File

@@ -1,7 +1,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2017 Antoni Boucher <bouanto@zoho.com>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Antoni Boucher <bouanto@zoho.com>
#
# This file is part of qutebrowser.
#
@@ -161,7 +161,7 @@ class QuickmarkManager(UrlMarkManager):
"Add quickmark:", usertypes.PromptMode.text,
functools.partial(self.quickmark_add, urlstr),
text="Please enter a quickmark name for<br/><b>{}</b>".format(
html.escape(url.toDisplayString())))
html.escape(url.toDisplayString())), url=urlstr)
@cmdutils.register(instance='quickmark-manager')
def quickmark_add(self, url, name):
@@ -192,7 +192,7 @@ class QuickmarkManager(UrlMarkManager):
if name in self.marks:
message.confirm_async(
title="Override existing quickmark?",
yes_action=set_mark, default=True)
yes_action=set_mark, default=True, url=url)
else:
set_mark()
@@ -280,7 +280,7 @@ class BookmarkManager(UrlMarkManager):
if urlstr in self.marks:
if toggle:
del self.marks[urlstr]
self.delete(urlstr)
return False
else:
raise AlreadyExistsError("Bookmark already exists!")

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -41,8 +41,10 @@ Group = enum.Enum('Group', ['all', 'links', 'images', 'url', 'inputs'])
SELECTORS = {
Group.all: ('a, area, textarea, select, input:not([type=hidden]), button, '
'frame, iframe, link, [onclick], [onmousedown], [role=link], '
'[role=option], [role=button], img'),
'frame, iframe, link, summary, [onclick], [onmousedown], '
'[role=link], [role=option], [role=button], img, '
# Angular 1 selectors
'[ng-click], [ngClick], [data-ng-click], [x-ng-click]'),
Group.links: 'a[href], area[href], link[href], [role=link][href]',
Group.images: 'img',
Group.url: '[src], [href]',
@@ -409,8 +411,9 @@ class AbstractWebElement(collections.abc.MutableMapping):
elif self.is_editable(strict=True):
log.webelem.debug("Clicking via JS focus()")
self._click_editable(click_target)
modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
'clicking input')
if config.val.input.insert_mode.auto_enter:
modeman.enter(self._tab.win_id, usertypes.KeyMode.insert,
'clicking input')
else:
self._click_fake_event(click_target)
elif click_target in [usertypes.ClickTarget.tab,

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2017 Michal Siedlaczek <michal.siedlaczek@gmail.com>
# Copyright 2017-2018 Michal Siedlaczek <michal.siedlaczek@gmail.com>
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -45,6 +45,10 @@ class DownloadItem(downloads.AbstractDownloadItem):
qt_item.downloadProgress.connect(self.stats.on_download_progress)
qt_item.stateChanged.connect(self._on_state_changed)
# Ensure wrapped qt_item is deleted manually when the wrapper object
# is deleted. See https://github.com/qutebrowser/qutebrowser/issues/3373
self.destroyed.connect(self._qt_item.deleteLater)
def _is_page_download(self):
"""Check if this item is a page (i.e. mhtml) download."""
return (self._qt_item.savePageFormat() !=
@@ -96,9 +100,15 @@ class DownloadItem(downloads.AbstractDownloadItem):
self._qt_item.cancel()
def retry(self):
# https://bugreports.qt.io/browse/QTBUG-56840
raise downloads.UnsupportedOperationError(
"Retrying downloads is unsupported with QtWebEngine")
state = self._qt_item.state()
assert state == QWebEngineDownloadItem.DownloadInterrupted, state
try:
self._qt_item.resume()
except AttributeError:
raise downloads.UnsupportedOperationError(
"Retrying downloads is unsupported with QtWebEngine on "
"Qt/PyQt < 5.10")
def _get_open_filename(self):
return self._filename
@@ -125,6 +135,7 @@ class DownloadItem(downloads.AbstractDownloadItem):
question = usertypes.Question()
question.title = title
question.text = msg
question.url = 'file://{}'.format(self._filename)
question.mode = usertypes.PromptMode.yesno
question.answered_yes.connect(self._after_set_filename)
question.answered_no.connect(no_action)
@@ -139,6 +150,7 @@ class DownloadItem(downloads.AbstractDownloadItem):
question = usertypes.Question()
question.title = title
question.text = msg
question.url = 'file://{}'.format(os.path.dirname(self._filename))
question.mode = usertypes.PromptMode.yesno
question.answered_yes.connect(lambda:
self._after_create_parent_question(

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -22,7 +22,7 @@
import os
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings
from qutebrowser.browser import inspector
@@ -35,6 +35,8 @@ class WebEngineInspector(inspector.AbstractWebInspector):
super().__init__(parent)
self.port = None
view = QWebEngineView()
settings = view.settings()
settings.setAttribute(QWebEngineSettings.JavascriptEnabled, True)
self._set_widget(view)
def inspect(self, _page):
@@ -43,8 +45,8 @@ class WebEngineInspector(inspector.AbstractWebInspector):
port = int(os.environ['QTWEBENGINE_REMOTE_DEBUGGING'])
except KeyError:
raise inspector.WebInspectorError(
"Debugging is not enabled. See 'qutebrowser --help' for "
"details.")
"QtWebEngine inspector is not enabled. See "
"'qutebrowser --help' for details.")
url = QUrl('http://localhost:{}/'.format(port))
self._widget.load(url)
self.show()

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -17,9 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
# We get various "abstract but not overridden" warnings
# pylint: disable=abstract-method
"""Bridge from QWebEngineSettings to our own settings.
Module attributes:
@@ -29,256 +26,262 @@ Module attributes:
import os
import sip
from PyQt5.QtGui import QFont
from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
QWebEngineScript)
from PyQt5.QtWebEngineWidgets import QWebEngineSettings, QWebEngineProfile
from qutebrowser.browser import shared
from qutebrowser.browser.webengine import spell
from qutebrowser.config import config, websettings
from qutebrowser.utils import (utils, standarddir, javascript, qtutils,
message, log, objreg)
from qutebrowser.utils import utils, standarddir, qtutils, message, log
# The default QWebEngineProfile
default_profile = None
# The QWebEngineProfile used for private (off-the-record) windows
private_profile = None
# The global WebEngineSettings object
global_settings = None
class Base(websettings.Base):
class _SettingsWrapper:
"""Base settings class with appropriate _get_global_settings."""
"""Expose a QWebEngineSettings interface which acts on all profiles.
def _get_global_settings(self):
return [default_profile.settings(), private_profile.settings()]
class Attribute(Base, websettings.Attribute):
"""A setting set via QWebEngineSettings::setAttribute."""
ENUM_BASE = QWebEngineSettings
class Setter(Base, websettings.Setter):
"""A setting set via a QWebEngineSettings setter method."""
pass
class FontFamilySetter(Base, websettings.FontFamilySetter):
"""A setter for a font family.
Gets the default value from QFont.
For read operations, the default profile value is always used.
"""
def __init__(self, font):
# Mapping from WebEngineSettings::initDefaults in
# qtwebengine/src/core/web_engine_settings.cpp
font_to_qfont = {
QWebEngineSettings.StandardFont: QFont.Serif,
QWebEngineSettings.FixedFont: QFont.Monospace,
QWebEngineSettings.SerifFont: QFont.Serif,
QWebEngineSettings.SansSerifFont: QFont.SansSerif,
QWebEngineSettings.CursiveFont: QFont.Cursive,
QWebEngineSettings.FantasyFont: QFont.Fantasy,
def __init__(self):
self._settings = [default_profile.settings(),
private_profile.settings()]
def setAttribute(self, *args, **kwargs):
for settings in self._settings:
settings.setAttribute(*args, **kwargs)
def setFontFamily(self, *args, **kwargs):
for settings in self._settings:
settings.setFontFamily(*args, **kwargs)
def setFontSize(self, *args, **kwargs):
for settings in self._settings:
settings.setFontSize(*args, **kwargs)
def setDefaultTextEncoding(self, *args, **kwargs):
for settings in self._settings:
settings.setDefaultTextEncoding(*args, **kwargs)
def testAttribute(self, *args, **kwargs):
return self._settings[0].testAttribute(*args, **kwargs)
def fontSize(self, *args, **kwargs):
return self._settings[0].fontSize(*args, **kwargs)
def fontFamily(self, *args, **kwargs):
return self._settings[0].fontFamily(*args, **kwargs)
def defaultTextEncoding(self, *args, **kwargs):
return self._settings[0].defaultTextEncoding(*args, **kwargs)
class WebEngineSettings(websettings.AbstractSettings):
"""A wrapper for the config for QWebEngineSettings."""
_ATTRIBUTES = {
'content.xss_auditing':
[QWebEngineSettings.XSSAuditingEnabled],
'content.images':
[QWebEngineSettings.AutoLoadImages],
'content.javascript.enabled':
[QWebEngineSettings.JavascriptEnabled],
'content.javascript.can_open_tabs_automatically':
[QWebEngineSettings.JavascriptCanOpenWindows],
'content.javascript.can_access_clipboard':
[QWebEngineSettings.JavascriptCanAccessClipboard],
'content.plugins':
[QWebEngineSettings.PluginsEnabled],
'content.hyperlink_auditing':
[QWebEngineSettings.HyperlinkAuditingEnabled],
'content.local_content_can_access_remote_urls':
[QWebEngineSettings.LocalContentCanAccessRemoteUrls],
'content.local_content_can_access_file_urls':
[QWebEngineSettings.LocalContentCanAccessFileUrls],
'content.webgl':
[QWebEngineSettings.WebGLEnabled],
'content.local_storage':
[QWebEngineSettings.LocalStorageEnabled],
'input.spatial_navigation':
[QWebEngineSettings.SpatialNavigationEnabled],
'input.links_included_in_focus_chain':
[QWebEngineSettings.LinksIncludedInFocusChain],
'scrolling.smooth':
[QWebEngineSettings.ScrollAnimatorEnabled],
}
_FONT_SIZES = {
'fonts.web.size.minimum':
QWebEngineSettings.MinimumFontSize,
'fonts.web.size.minimum_logical':
QWebEngineSettings.MinimumLogicalFontSize,
'fonts.web.size.default':
QWebEngineSettings.DefaultFontSize,
'fonts.web.size.default_fixed':
QWebEngineSettings.DefaultFixedFontSize,
}
_FONT_FAMILIES = {
'fonts.web.family.standard': QWebEngineSettings.StandardFont,
'fonts.web.family.fixed': QWebEngineSettings.FixedFont,
'fonts.web.family.serif': QWebEngineSettings.SerifFont,
'fonts.web.family.sans_serif': QWebEngineSettings.SansSerifFont,
'fonts.web.family.cursive': QWebEngineSettings.CursiveFont,
'fonts.web.family.fantasy': QWebEngineSettings.FantasyFont,
}
# Mapping from WebEngineSettings::initDefaults in
# qtwebengine/src/core/web_engine_settings.cpp
_FONT_TO_QFONT = {
QWebEngineSettings.StandardFont: QFont.Serif,
QWebEngineSettings.FixedFont: QFont.Monospace,
QWebEngineSettings.SerifFont: QFont.Serif,
QWebEngineSettings.SansSerifFont: QFont.SansSerif,
QWebEngineSettings.CursiveFont: QFont.Cursive,
QWebEngineSettings.FantasyFont: QFont.Fantasy,
}
def __init__(self, settings):
super().__init__(settings)
# Attributes which don't exist in all Qt versions.
new_attributes = {
# Qt 5.8
'content.print_element_backgrounds': 'PrintElementBackgrounds',
}
super().__init__(setter=QWebEngineSettings.setFontFamily, font=font,
qfont=font_to_qfont[font])
for name, attribute in new_attributes.items():
try:
value = getattr(QWebEngineSettings, attribute)
except AttributeError:
continue
self._ATTRIBUTES[name] = [value]
class DefaultProfileSetter(websettings.Base):
class ProfileSetter:
"""A setting set on the QWebEngineProfile."""
"""Helper to set various settings on a profile."""
def __init__(self, setter, converter=None, default=websettings.UNSET):
super().__init__(default)
self._setter = setter
self._converter = converter
def __init__(self, profile):
self._profile = profile
def __repr__(self):
return utils.get_repr(self, setter=self._setter, constructor=True)
def init_profile(self):
"""Initialize settings on the given profile."""
self.set_http_headers()
self.set_http_cache_size()
self._init_attributes()
def _set(self, value, settings=None):
if settings is not None:
raise ValueError("'settings' may not be set with "
"DefaultProfileSetters!")
if qtutils.version_check('5.8'):
self._profile.setSpellCheckEnabled(True)
self.set_dictionary_language()
setter = getattr(default_profile, self._setter)
if self._converter is not None:
value = self._converter(value)
def _init_attributes(self):
"""Initialize hard-coded attributes."""
values = {
'FullScreenSupportEnabled': True,
'FocusOnNavigationEnabled': True,
}
settings = self._profile.settings()
for name, value in values.items():
attr = getattr(QWebEngineSettings, name, None)
if attr is not None:
settings.setAttribute(attr, value)
setter(value)
def set_http_headers(self):
"""Set the user agent and accept-language for the given profile.
We override those per request in the URL interceptor (to allow for
per-domain values), but this one still gets used for things like
window.navigator.userAgent/.languages in JS.
"""
self._profile.setHttpUserAgent(config.val.content.headers.user_agent)
accept_language = config.val.content.headers.accept_language
if accept_language is not None:
self._profile.setHttpAcceptLanguage(accept_language)
class PersistentCookiePolicy(DefaultProfileSetter):
def set_http_cache_size(self):
"""Initialize the HTTP cache size for the given profile."""
size = config.val.content.cache.size
if size is None:
size = 0
else:
size = qtutils.check_overflow(size, 'int', fatal=False)
"""The content.cookies.store setting is different from other settings."""
# 0: automatically managed by QtWebEngine
self._profile.setHttpCacheMaximumSize(size)
def __init__(self):
super().__init__('setPersistentCookiesPolicy')
def set_persistent_cookie_policy(self):
"""Set the HTTP Cookie size for the given profile."""
assert not self._profile.isOffTheRecord()
if config.val.content.cookies.store:
value = QWebEngineProfile.AllowPersistentCookies
else:
value = QWebEngineProfile.NoPersistentCookies
self._profile.setPersistentCookiesPolicy(value)
def _set(self, value, settings=None):
if settings is not None:
raise ValueError("'settings' may not be set with "
"PersistentCookiePolicy!")
setter = getattr(QWebEngineProfile.defaultProfile(), self._setter)
setter(
QWebEngineProfile.AllowPersistentCookies if value else
QWebEngineProfile.NoPersistentCookies
)
def set_dictionary_language(self, warn=True):
"""Load the given dictionaries."""
filenames = []
for code in config.val.spellcheck.languages or []:
local_filename = spell.local_filename(code)
if not local_filename:
if warn:
message.warning("Language {} is not installed - see "
"scripts/dictcli.py in qutebrowser's "
"sources".format(code))
continue
filenames.append(local_filename)
class DictionaryLanguageSetter(DefaultProfileSetter):
"""Sets paths to dictionary files based on language codes."""
def __init__(self):
super().__init__('setSpellCheckLanguages', default=[])
def _find_installed(self, code):
local_filename = spell.local_filename(code)
if not local_filename:
message.warning(
"Language {} is not installed - see scripts/dictcli.py "
"in qutebrowser's sources".format(code))
return local_filename
def _set(self, value, settings=None):
if settings is not None:
raise ValueError("'settings' may not be set with "
"DictionaryLanguageSetter!")
filenames = [self._find_installed(code) for code in value]
log.config.debug("Found dicts: {}".format(filenames))
super()._set([f for f in filenames if f], settings)
def _init_stylesheet(profile):
"""Initialize custom stylesheets.
Partially inspired by QupZilla:
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
"""
old_script = profile.scripts().findScript('_qute_stylesheet')
if not old_script.isNull():
profile.scripts().remove(old_script)
css = shared.get_user_stylesheet()
source = '\n'.join([
'"use strict";',
'window._qutebrowser = window._qutebrowser || {};',
utils.read_file('javascript/stylesheet.js'),
javascript.assemble('stylesheet', 'set_css', css),
])
script = QWebEngineScript()
script.setName('_qute_stylesheet')
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
script.setWorldId(QWebEngineScript.ApplicationWorld)
script.setRunsOnSubFrames(True)
script.setSourceCode(source)
profile.scripts().insert(script)
def _update_stylesheet():
"""Update the custom stylesheet in existing tabs."""
css = shared.get_user_stylesheet()
code = javascript.assemble('stylesheet', 'set_css', css)
for win_id, window in objreg.window_registry.items():
# We could be in the middle of destroying a window here
if sip.isdeleted(window):
continue
tab_registry = objreg.get('tab-registry', scope='window',
window=win_id)
for tab in tab_registry.values():
tab.run_js_async(code)
def _set_http_headers(profile):
"""Set the user agent and accept-language for the given profile.
We override those per request in the URL interceptor (to allow for
per-domain values), but this one still gets used for things like
window.navigator.userAgent/.languages in JS.
"""
profile.setHttpUserAgent(config.val.content.headers.user_agent)
accept_language = config.val.content.headers.accept_language
if accept_language is not None:
profile.setHttpAcceptLanguage(accept_language)
self._profile.setSpellCheckLanguages(filenames)
def _update_settings(option):
"""Update global settings when qwebsettings changed."""
websettings.update_mappings(MAPPINGS, option)
if option in ['scrolling.bar', 'content.user_stylesheets']:
_init_stylesheet(default_profile)
_init_stylesheet(private_profile)
_update_stylesheet()
elif option in ['content.headers.user_agent',
'content.headers.accept_language']:
_set_http_headers(default_profile)
_set_http_headers(private_profile)
global_settings.update_setting(option)
if option in ['content.headers.user_agent',
'content.headers.accept_language']:
default_profile.setter.set_http_headers()
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()
elif (option == 'content.cookies.store' and
# https://bugreports.qt.io/browse/QTBUG-58650
qtutils.version_check('5.9', compiled=False)):
default_profile.setter.set_persistent_cookie_policy()
# 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)
def _init_profiles():
"""Init the two used QWebEngineProfiles."""
global default_profile, private_profile
default_profile = QWebEngineProfile.defaultProfile()
default_profile.setter = ProfileSetter(default_profile)
default_profile.setCachePath(
os.path.join(standarddir.cache(), 'webengine'))
default_profile.setPersistentStoragePath(
os.path.join(standarddir.data(), 'webengine'))
_init_stylesheet(default_profile)
_set_http_headers(default_profile)
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()
_init_stylesheet(private_profile)
_set_http_headers(private_profile)
if qtutils.version_check('5.8'):
default_profile.setSpellCheckEnabled(True)
private_profile.setSpellCheckEnabled(True)
def inject_userscripts():
"""Register user JavaScript files with the global profiles."""
# The Greasemonkey metadata block support in QtWebEngine only starts at
# Qt 5.8. With 5.7.1, we need to inject the scripts ourselves in response
# to urlChanged.
if not qtutils.version_check('5.8'):
return
# Since we are inserting scripts into profile.scripts they won't
# just get replaced by new gm scripts like if we were injecting them
# ourselves so we need to remove all gm scripts, while not removing
# any other stuff that might have been added. Like the one for
# stylesheets.
greasemonkey = objreg.get('greasemonkey')
for profile in [default_profile, private_profile]:
scripts = profile.scripts()
for script in scripts.toList():
if script.name().startswith("GM-"):
log.greasemonkey.debug('Removing script: {}'
.format(script.name()))
removed = scripts.remove(script)
assert removed, script.name()
# Then add the new scripts.
for script in greasemonkey.all_scripts():
# @run-at (and @include/@exclude/@match) is parsed by
# QWebEngineScript.
new_script = QWebEngineScript()
new_script.setWorldId(QWebEngineScript.MainWorld)
new_script.setSourceCode(script.code())
new_script.setName("GM-{}".format(script.name))
new_script.setRunsOnSubFrames(script.runs_on_sub_frames)
log.greasemonkey.debug('adding script: {}'
.format(new_script.name()))
scripts.insert(new_script)
private_profile.setter.init_profile()
def init(args):
@@ -287,111 +290,12 @@ def init(args):
os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = str(utils.random_port())
_init_profiles()
# We need to do this here as a WORKAROUND for
# https://bugreports.qt.io/browse/QTBUG-58650
if not qtutils.version_check('5.9', compiled=False):
PersistentCookiePolicy().set(config.val.content.cookies.store)
Attribute(QWebEngineSettings.FullScreenSupportEnabled).set(True)
websettings.init_mappings(MAPPINGS)
config.instance.changed.connect(_update_settings)
global global_settings
global_settings = WebEngineSettings(_SettingsWrapper())
global_settings.init_settings()
def shutdown():
# FIXME:qtwebengine do we need to do something for a clean shutdown here?
pass
# Missing QtWebEngine attributes:
# - ScreenCaptureEnabled
# - Accelerated2dCanvasEnabled
# - AutoLoadIconsForPage
# - TouchIconsEnabled
# - FocusOnNavigationEnabled (5.8)
# - AllowRunningInsecureContent (5.8)
#
# Missing QtWebEngine fonts:
# - PictographFont
MAPPINGS = {
'content.images':
Attribute(QWebEngineSettings.AutoLoadImages),
'content.javascript.enabled':
Attribute(QWebEngineSettings.JavascriptEnabled),
'content.javascript.can_open_tabs_automatically':
Attribute(QWebEngineSettings.JavascriptCanOpenWindows),
'content.javascript.can_access_clipboard':
Attribute(QWebEngineSettings.JavascriptCanAccessClipboard),
'content.plugins':
Attribute(QWebEngineSettings.PluginsEnabled),
'content.hyperlink_auditing':
Attribute(QWebEngineSettings.HyperlinkAuditingEnabled),
'content.local_content_can_access_remote_urls':
Attribute(QWebEngineSettings.LocalContentCanAccessRemoteUrls),
'content.local_content_can_access_file_urls':
Attribute(QWebEngineSettings.LocalContentCanAccessFileUrls),
'content.webgl':
Attribute(QWebEngineSettings.WebGLEnabled),
'content.local_storage':
Attribute(QWebEngineSettings.LocalStorageEnabled),
'content.cache.size':
# 0: automatically managed by QtWebEngine
DefaultProfileSetter('setHttpCacheMaximumSize', default=0,
converter=lambda val:
qtutils.check_overflow(val, 'int', fatal=False)),
'content.xss_auditing':
Attribute(QWebEngineSettings.XSSAuditingEnabled),
'content.default_encoding':
Setter(QWebEngineSettings.setDefaultTextEncoding),
'input.spatial_navigation':
Attribute(QWebEngineSettings.SpatialNavigationEnabled),
'input.links_included_in_focus_chain':
Attribute(QWebEngineSettings.LinksIncludedInFocusChain),
'fonts.web.family.standard':
FontFamilySetter(QWebEngineSettings.StandardFont),
'fonts.web.family.fixed':
FontFamilySetter(QWebEngineSettings.FixedFont),
'fonts.web.family.serif':
FontFamilySetter(QWebEngineSettings.SerifFont),
'fonts.web.family.sans_serif':
FontFamilySetter(QWebEngineSettings.SansSerifFont),
'fonts.web.family.cursive':
FontFamilySetter(QWebEngineSettings.CursiveFont),
'fonts.web.family.fantasy':
FontFamilySetter(QWebEngineSettings.FantasyFont),
'fonts.web.size.minimum':
Setter(QWebEngineSettings.setFontSize,
args=[QWebEngineSettings.MinimumFontSize]),
'fonts.web.size.minimum_logical':
Setter(QWebEngineSettings.setFontSize,
args=[QWebEngineSettings.MinimumLogicalFontSize]),
'fonts.web.size.default':
Setter(QWebEngineSettings.setFontSize,
args=[QWebEngineSettings.DefaultFontSize]),
'fonts.web.size.default_fixed':
Setter(QWebEngineSettings.setFontSize,
args=[QWebEngineSettings.DefaultFixedFontSize]),
'scrolling.smooth':
Attribute(QWebEngineSettings.ScrollAnimatorEnabled),
}
try:
MAPPINGS['content.print_element_backgrounds'] = Attribute(
QWebEngineSettings.PrintElementBackgrounds)
except AttributeError:
# Added in Qt 5.8
pass
if qtutils.version_check('5.8'):
MAPPINGS['spellcheck.languages'] = DictionaryLanguageSetter()
if qtutils.version_check('5.9', compiled=False):
# https://bugreports.qt.io/browse/QTBUG-58650
MAPPINGS['content.cookies.store'] = PersistentCookiePolicy()

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -21,16 +21,19 @@
import math
import functools
import sys
import re
import html as html_utils
import sip
from PyQt5.QtCore import (pyqtSignal, pyqtSlot, Qt, QEvent, QPoint, QPointF,
QUrl, QTimer)
from PyQt5.QtGui import QKeyEvent
from PyQt5.QtGui import QKeyEvent, QIcon
from PyQt5.QtNetwork import QAuthenticator
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineScript
from qutebrowser.config import configdata, config
from qutebrowser.browser import browsertab, mouse, shared
from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory,
interceptor, webenginequtescheme,
@@ -70,10 +73,6 @@ def init():
download_manager.install(webenginesettings.private_profile)
objreg.register('webengine-download-manager', download_manager)
greasemonkey = objreg.get('greasemonkey')
greasemonkey.scripts_reloaded.connect(webenginesettings.inject_userscripts)
webenginesettings.inject_userscripts()
# Mapping worlds from usertypes.JsWorld to QWebEngineScript world IDs.
_JS_WORLD_MAP = {
@@ -98,6 +97,19 @@ class WebEngineAction(browsertab.AbstractAction):
"""Save the current page."""
self._widget.triggerPageAction(QWebEnginePage.SavePage)
def show_source(self):
try:
self._widget.triggerPageAction(QWebEnginePage.ViewSource)
except AttributeError:
# Qt < 5.8
tb = objreg.get('tabbed-browser', scope='window',
window=self._tab.win_id)
urlstr = self._tab.url().toString(QUrl.RemoveUserInfo)
# The original URL becomes the path of a view-source: URL
# (without a host), but query/fragment should stay.
url = QUrl('view-source:' + urlstr)
tb.tabopen(url, background=False, related=True)
class WebEnginePrinting(browsertab.AbstractPrinting):
@@ -169,6 +181,12 @@ class WebEngineSearch(browsertab.AbstractSearch):
def search(self, text, *, ignore_case='never', reverse=False,
result_cb=None):
# Don't go to next entry on duplicate search
if self.text == text and self.search_displayed:
log.webview.debug("Ignoring duplicate search request"
" for {}".format(text))
return
self.text = text
self._flags = QWebEnginePage.FindFlags(0)
if self._is_case_sensitive(ignore_case):
@@ -201,70 +219,103 @@ class WebEngineCaret(browsertab.AbstractCaret):
@pyqtSlot(usertypes.KeyMode)
def _on_mode_entered(self, mode):
pass
if mode != usertypes.KeyMode.caret:
return
if self._tab.search.search_displayed:
# We are currently in search mode.
# convert the search to a blue selection so we can operate on it
# https://bugreports.qt.io/browse/QTBUG-60673
self._tab.search.clear()
self._tab.run_js_async(
javascript.assemble('caret', 'setPlatform', sys.platform))
self._js_call('setInitialCursor', self._selection_cb)
def _selection_cb(self, enabled):
"""Emit selection_toggled based on setInitialCursor."""
if enabled is None:
log.webview.debug("Ignoring selection status None")
return
self.selection_toggled.emit(enabled)
@pyqtSlot(usertypes.KeyMode)
def _on_mode_left(self):
pass
def _on_mode_left(self, mode):
if mode != usertypes.KeyMode.caret:
return
self.drop_selection()
self._js_call('disableCaret')
def move_to_next_line(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveDown')
def move_to_prev_line(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveUp')
def move_to_next_char(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveRight')
def move_to_prev_char(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveLeft')
def move_to_end_of_word(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToEndOfWord')
def move_to_next_word(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToNextWord')
def move_to_prev_word(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToPreviousWord')
def move_to_start_of_line(self):
log.stub()
self._js_call('moveToStartOfLine')
def move_to_end_of_line(self):
log.stub()
self._js_call('moveToEndOfLine')
def move_to_start_of_next_block(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToStartOfNextBlock')
def move_to_start_of_prev_block(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToStartOfPrevBlock')
def move_to_end_of_next_block(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToEndOfNextBlock')
def move_to_end_of_prev_block(self, count=1):
log.stub()
for _ in range(count):
self._js_call('moveToEndOfPrevBlock')
def move_to_start_of_document(self):
log.stub()
self._js_call('moveToStartOfDocument')
def move_to_end_of_document(self):
log.stub()
self._js_call('moveToEndOfDocument')
def toggle_selection(self):
log.stub()
self._js_call('toggleSelection', self.selection_toggled.emit)
def drop_selection(self):
log.stub()
self._js_call('dropSelection')
def has_selection(self):
return self._widget.hasSelection()
def selection(self, html=False):
if html:
raise browsertab.UnsupportedOperationError
return self._widget.selectedText()
def selection(self, callback):
# Not using selectedText() as WORKAROUND for
# https://bugreports.qt.io/browse/QTBUG-53134
# Even on Qt 5.10 selectedText() seems to work poorly, see
# https://github.com/qutebrowser/qutebrowser/issues/3523
self._tab.run_js_async(javascript.assemble('caret', 'getSelection'),
callback)
def _follow_selected_cb(self, js_elem, tab=False):
"""Callback for javascript which clicks the selected element.
@@ -308,6 +359,9 @@ class WebEngineCaret(browsertab.AbstractCaret):
self._tab.run_js_async(js_code, lambda jsret:
self._follow_selected_cb(jsret, tab))
def _js_call(self, command, callback=None):
self._tab.run_js_async(javascript.assemble('caret', command), callback)
class WebEngineScroller(browsertab.AbstractScroller):
@@ -327,7 +381,7 @@ class WebEngineScroller(browsertab.AbstractScroller):
def _repeated_key_press(self, key, count=1, modifier=Qt.NoModifier):
"""Send count fake key presses to this scroller's WebEngineTab."""
for _ in range(min(count, 5000)):
for _ in range(min(count, 1000)):
self._tab.key_press(key, modifier)
@pyqtSlot(QPointF)
@@ -380,6 +434,11 @@ class WebEngineScroller(browsertab.AbstractScroller):
js_code = javascript.assemble('window', 'scroll', point.x(), point.y())
self._tab.run_js_async(js_code)
def to_anchor(self, name):
url = self._tab.url()
url.setFragment(name)
self._tab.openurl(url)
def delta(self, x=0, y=0):
self._tab.run_js_async(javascript.assemble('window', 'scrollBy', x, y))
@@ -435,7 +494,8 @@ class WebEngineHistory(browsertab.AbstractHistory):
return self._history.itemAt(i)
def _go_to_item(self, item):
return self._history.goToItem(item)
self._tab.predicted_navigation.emit(item.url())
self._history.goToItem(item)
def serialize(self):
if not qtutils.version_check('5.9', compiled=False):
@@ -453,15 +513,23 @@ class WebEngineHistory(browsertab.AbstractHistory):
return qtutils.deserialize(data, self._history)
def load_items(self, items):
if items:
self._tab.predicted_navigation.emit(items[-1].url)
stream, _data, cur_data = tabhistory.serialize(items)
qtutils.deserialize_stream(stream, self._history)
@pyqtSlot()
def _on_load_finished():
self._tab.scroller.to_point(cur_data['scroll-pos'])
self._tab.load_finished.disconnect(_on_load_finished)
if cur_data is not None:
if 'zoom' in cur_data:
self._tab.zoom.set_factor(cur_data['zoom'])
if ('scroll-pos' in cur_data and
self._tab.scroller.pos_px() == QPoint(0, 0)):
QTimer.singleShot(0, functools.partial(
self._tab.scroller.to_point, cur_data['scroll-pos']))
self._tab.load_finished.connect(_on_load_finished)
class WebEngineZoom(browsertab.AbstractZoom):
@@ -557,39 +625,139 @@ class WebEngineTab(browsertab.AbstractTab):
private=private)
self.history = WebEngineHistory(self)
self.scroller = WebEngineScroller(self, parent=self)
self.caret = WebEngineCaret(win_id=win_id, mode_manager=mode_manager,
self.caret = WebEngineCaret(mode_manager=mode_manager,
tab=self, parent=self)
self.zoom = WebEngineZoom(win_id=win_id, parent=self)
self.zoom = WebEngineZoom(tab=self, parent=self)
self.search = WebEngineSearch(parent=self)
self.printing = WebEnginePrinting()
self.elements = WebEngineElements(self)
self.action = WebEngineAction()
self.elements = WebEngineElements(tab=self)
self.action = WebEngineAction(tab=self)
# We're assigning settings in _set_widget
self.settings = webenginesettings.WebEngineSettings(settings=None)
self._set_widget(widget)
self._connect_signals()
self.backend = usertypes.Backend.QtWebEngine
self._init_js()
self._child_event_filter = None
self._saved_zoom = None
self._reload_url = None
config.instance.changed.connect(self._on_config_changed)
self._init_js()
@pyqtSlot(str)
def _on_config_changed(self, option):
if option in ['scrolling.bar', 'content.user_stylesheets']:
self._init_stylesheet()
self._update_stylesheet()
def _update_stylesheet(self):
"""Update the custom stylesheet in existing tabs."""
css = shared.get_user_stylesheet()
code = javascript.assemble('stylesheet', 'set_css', css)
self.run_js_async(code)
def _inject_early_js(self, name, js_code, *,
world=QWebEngineScript.ApplicationWorld,
subframes=False):
"""Inject the given script to run early on a page load.
This runs the script both on DocumentCreation and DocumentReady as on
some internal pages, DocumentCreation will not work.
That is a WORKAROUND for https://bugreports.qt.io/browse/QTBUG-66011
"""
scripts = self._widget.page().scripts()
for injection in ['creation', 'ready']:
injection_points = {
'creation': QWebEngineScript.DocumentCreation,
'ready': QWebEngineScript.DocumentReady,
}
script = QWebEngineScript()
script.setInjectionPoint(injection_points[injection])
script.setSourceCode(js_code)
script.setWorldId(world)
script.setRunsOnSubFrames(subframes)
script.setName('_qute_{}_{}'.format(name, injection))
scripts.insert(script)
def _remove_early_js(self, name):
"""Remove an early QWebEngineScript."""
scripts = self._widget.page().scripts()
for injection in ['creation', 'ready']:
full_name = '_qute_{}_{}'.format(name, injection)
script = scripts.findScript(full_name)
if not script.isNull():
scripts.remove(script)
def _init_js(self):
js_code = '\n'.join([
'"use strict";',
'window._qutebrowser = window._qutebrowser || {};',
"""Initialize global qutebrowser JavaScript."""
js_code = javascript.wrap_global(
'scripts',
utils.read_file('javascript/scroll.js'),
utils.read_file('javascript/webelem.js'),
])
script = QWebEngineScript()
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
script.setSourceCode(js_code)
utils.read_file('javascript/caret.js'),
)
# FIXME:qtwebengine what about subframes=True?
self._inject_early_js('js', js_code, subframes=True)
self._init_stylesheet()
page = self._widget.page()
script.setWorldId(QWebEngineScript.ApplicationWorld)
greasemonkey = objreg.get('greasemonkey')
greasemonkey.scripts_reloaded.connect(self._inject_userscripts)
self._inject_userscripts()
# FIXME:qtwebengine what about runsOnSubFrames?
page.scripts().insert(script)
def _init_stylesheet(self):
"""Initialize custom stylesheets.
Partially inspired by QupZilla:
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
"""
self._remove_early_js('stylesheet')
css = shared.get_user_stylesheet()
js_code = javascript.wrap_global(
'stylesheet',
utils.read_file('javascript/stylesheet.js'),
javascript.assemble('stylesheet', 'set_css', css),
)
self._inject_early_js('stylesheet', js_code, subframes=True)
def _inject_userscripts(self):
"""Register user JavaScript files with the global profiles."""
# The Greasemonkey metadata block support in QtWebEngine only starts at
# Qt 5.8. With 5.7.1, we need to inject the scripts ourselves in
# response to urlChanged.
if not qtutils.version_check('5.8'):
return
# Since we are inserting scripts into profile.scripts they won't
# just get replaced by new gm scripts like if we were injecting them
# ourselves so we need to remove all gm scripts, while not removing
# any other stuff that might have been added. Like the one for
# stylesheets.
greasemonkey = objreg.get('greasemonkey')
scripts = self._widget.page().scripts()
for script in scripts.toList():
if script.name().startswith("GM-"):
log.greasemonkey.debug('Removing script: {}'
.format(script.name()))
removed = scripts.remove(script)
assert removed, script.name()
# Then add the new scripts.
for script in greasemonkey.all_scripts():
# @run-at (and @include/@exclude/@match) is parsed by
# QWebEngineScript.
new_script = QWebEngineScript()
new_script.setWorldId(QWebEngineScript.MainWorld)
new_script.setSourceCode(script.code())
new_script.setName("GM-{}".format(script.name))
new_script.setRunsOnSubFrames(script.runs_on_sub_frames)
log.greasemonkey.debug('adding script: {}'
.format(new_script.name()))
scripts.insert(new_script)
def _install_event_filter(self):
self._widget.focusProxy().installEventFilter(self._mouse_event_filter)
fp = self._widget.focusProxy()
if fp is not None:
fp.installEventFilter(self._mouse_event_filter)
self._child_event_filter = mouse.ChildEventFilter(
eventfilter=self._mouse_event_filter, widget=self._widget,
parent=self)
@@ -597,14 +765,23 @@ class WebEngineTab(browsertab.AbstractTab):
@pyqtSlot()
def _restore_zoom(self):
if sip.isdeleted(self._widget):
# https://github.com/qutebrowser/qutebrowser/issues/3498
return
if self._saved_zoom is None:
return
self.zoom.set_factor(self._saved_zoom)
self._saved_zoom = None
def openurl(self, url):
def openurl(self, url, *, predict=True):
"""Open the given URL in this tab.
Arguments:
url: The QUrl to open.
predict: If set to False, predicted_navigation is not emitted.
"""
self._saved_zoom = self.zoom.factor()
self._openurl_prepare(url)
self._openurl_prepare(url, predict=predict)
self._widget.load(url)
def url(self, requested=False):
@@ -636,10 +813,6 @@ class WebEngineTab(browsertab.AbstractTab):
def shutdown(self):
self.shutting_down.emit()
self.action.exit_fullscreen()
if qtutils.version_check('5.8', exact=True, compiled=False):
# WORKAROUND for
# https://bugreports.qt.io/browse/QTBUG-58563
self.search.clear()
self._widget.shutdown()
def reload(self, *, force=False):
@@ -682,6 +855,16 @@ class WebEngineTab(browsertab.AbstractTab):
self.send_event(press_evt)
self.send_event(release_evt)
def _show_error_page(self, url, error):
"""Show an error page in the tab."""
log.misc.debug("Showing error page for {}".format(error))
url_string = url.toDisplayString()
error_page = jinja.render(
'error.html',
title="Error loading page: {}".format(url_string),
url=url_string, error=error)
self.set_html(error_page)
@pyqtSlot()
def _on_history_trigger(self):
try:
@@ -716,10 +899,11 @@ class WebEngineTab(browsertab.AbstractTab):
"""Called when a proxy needs authentication."""
msg = "<b>{}</b> requires a username and password.".format(
html_utils.escape(proxy_host))
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
answer = message.ask(
title="Proxy authentication required", text=msg,
mode=usertypes.PromptMode.user_pwd,
abort_on=[self.shutting_down, self.load_started])
abort_on=[self.shutting_down, self.load_started], url=urlstr)
if answer is not None:
authenticator.setUser(answer.user)
authenticator.setPassword(answer.password)
@@ -729,21 +913,19 @@ class WebEngineTab(browsertab.AbstractTab):
sip.assign(authenticator, QAuthenticator())
# pylint: enable=no-member, useless-suppression
except AttributeError:
url_string = url.toDisplayString()
error_page = jinja.render(
'error.html',
title="Error loading page: {}".format(url_string),
url=url_string, error="Proxy authentication required",
icon='')
self.set_html(error_page)
self._show_error_page(url, "Proxy authentication required")
@pyqtSlot(QUrl, 'QAuthenticator*')
def _on_authentication_required(self, url, authenticator):
# FIXME:qtwebengine support .netrc
answer = shared.authentication_required(
url, authenticator, abort_on=[self.shutting_down,
self.load_started])
if answer is None:
netrc_success = False
if not self.data.netrc_used:
self.data.netrc_used = True
netrc_success = shared.netrc_authentication(url, authenticator)
if not netrc_success:
abort_on = [self.shutting_down, self.load_started]
answer = shared.authentication_required(url, authenticator,
abort_on)
if not netrc_success and answer is None:
try:
# pylint: disable=no-member, useless-suppression
sip.assign(authenticator, QAuthenticator())
@@ -751,12 +933,7 @@ class WebEngineTab(browsertab.AbstractTab):
except AttributeError:
# WORKAROUND for
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-December/038400.html
url_string = url.toDisplayString()
error_page = jinja.render(
'error.html',
title="Error loading page: {}".format(url_string),
url=url_string, error="Authentication required")
self.set_html(error_page)
self._show_error_page(url, "Authentication required")
@pyqtSlot('QWebEngineFullScreenRequest')
def _on_fullscreen_requested(self, request):
@@ -779,6 +956,7 @@ class WebEngineTab(browsertab.AbstractTab):
# https://bugreports.qt.io/browse/QTBUG-61506
self.search.clear()
super()._on_load_started()
self.data.netrc_used = False
@pyqtSlot(QWebEnginePage.RenderProcessTerminationStatus, int)
def _on_render_process_terminated(self, status, exitcode):
@@ -820,6 +998,74 @@ class WebEngineTab(browsertab.AbstractTab):
if not ok:
self._load_finished_fake.emit(False)
def _error_page_workaround(self, html):
"""Check if we're displaying a Chromium error page.
This gets only called if we got loadFinished(False) without JavaScript,
so we can display at least some error page.
WORKAROUND for https://bugreports.qt.io/browse/QTBUG-66643
Needs to check the page content as a WORKAROUND for
https://bugreports.qt.io/browse/QTBUG-66661
"""
match = re.search(r'"errorCode":"([^"]*)"', html)
if match is None:
return
self._show_error_page(self.url(), error=match.group(1))
@pyqtSlot(bool)
def _on_load_finished(self, ok):
"""Display a static error page if JavaScript is disabled."""
super()._on_load_finished(ok)
js_enabled = self.settings.test_attribute('content.javascript.enabled')
if not ok and not js_enabled:
self.dump_async(self._error_page_workaround)
if ok and self._reload_url is not None:
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-66656
log.config.debug(
"Loading {} again because of config change".format(
self._reload_url.toDisplayString()))
QTimer.singleShot(100, lambda url=self._reload_url:
self.openurl(url, predict=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(QUrl)
def _on_predicted_navigation(self, url):
"""If we know we're going to visit an URL soon, change the settings."""
super()._on_predicted_navigation(url)
self.settings.update_for_url(url)
@pyqtSlot(usertypes.NavigationRequest)
def _on_navigation_request(self, navigation):
super()._on_navigation_request(navigation)
if not navigation.accepted or not navigation.is_main_frame:
return
needs_reload = {
'content.plugins',
'content.javascript.enabled',
'content.javascript.can_access_clipboard',
'content.javascript.can_access_clipboard',
'content.print_element_backgrounds',
'input.spatial_navigation',
'input.spatial_navigation',
}
assert needs_reload.issubset(configdata.DATA)
changed = self.settings.update_for_url(navigation.url)
if (changed & needs_reload and navigation.navigation_type !=
navigation.Type.link_clicked):
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-66656
self._reload_url = navigation.url
def _connect_signals(self):
view = self._widget
page = view.page()
@@ -834,6 +1080,7 @@ class WebEngineTab(browsertab.AbstractTab):
self._on_proxy_authentication_required)
page.fullScreenRequested.connect(self._on_fullscreen_requested)
page.contentsSizeChanged.connect(self.contents_size_changed)
page.navigation_request.connect(self._on_navigation_request)
view.titleChanged.connect(self.title_changed)
view.urlChanged.connect(self._on_url_changed)
@@ -854,5 +1101,9 @@ class WebEngineTab(browsertab.AbstractTab):
page.loadFinished.connect(self._restore_zoom)
page.loadFinished.connect(self._on_load_finished)
self.predicted_navigation.connect(self._on_predicted_navigation)
def event_target(self):
return self._widget.focusProxy()
fp = self._widget.focusProxy()
assert fp is not None
return fp

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -29,8 +29,7 @@ from PyQt5.QtWebEngineWidgets import (QWebEngineView, QWebEnginePage,
from qutebrowser.browser import shared
from qutebrowser.browser.webengine import certificateerror, webenginesettings
from qutebrowser.config import config
from qutebrowser.utils import (log, debug, usertypes, jinja, urlutils, message,
objreg, qtutils)
from qutebrowser.utils import log, debug, usertypes, jinja, objreg, qtutils
class WebEngineView(QWebEngineView):
@@ -124,10 +123,12 @@ class WebEnginePage(QWebEnginePage):
Signals:
certificate_error: Emitted on certificate errors.
shutting_down: Emitted when the page is shutting down.
navigation_request: Emitted on acceptNavigationRequest.
"""
certificate_error = pyqtSignal()
shutting_down = pyqtSignal()
navigation_request = pyqtSignal(usertypes.NavigationRequest)
def __init__(self, *, theme_color, profile, parent=None):
super().__init__(profile, parent)
@@ -242,10 +243,12 @@ class WebEnginePage(QWebEnginePage):
"""Override javaScriptConfirm to use qutebrowser prompts."""
if self._is_shutting_down:
return False
escape_msg = qtutils.version_check('5.11', compiled=False)
try:
return shared.javascript_confirm(url, js_msg,
abort_on=[self.loadStarted,
self.shutting_down])
self.shutting_down],
escape_msg=escape_msg)
except shared.CallSuper:
return super().javaScriptConfirm(url, js_msg)
@@ -255,12 +258,14 @@ class WebEnginePage(QWebEnginePage):
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-November/038293.html
def javaScriptPrompt(self, url, js_msg, default):
"""Override javaScriptPrompt to use qutebrowser prompts."""
escape_msg = qtutils.version_check('5.11', compiled=False)
if self._is_shutting_down:
return (False, "")
try:
return shared.javascript_prompt(url, js_msg, default,
abort_on=[self.loadStarted,
self.shutting_down])
self.shutting_down],
escape_msg=escape_msg)
except shared.CallSuper:
return super().javaScriptPrompt(url, js_msg, default)
@@ -268,10 +273,12 @@ class WebEnginePage(QWebEnginePage):
"""Override javaScriptAlert to use qutebrowser prompts."""
if self._is_shutting_down:
return
escape_msg = qtutils.version_check('5.11', compiled=False)
try:
shared.javascript_alert(url, js_msg,
abort_on=[self.loadStarted,
self.shutting_down])
self.shutting_down],
escape_msg=escape_msg)
except shared.CallSuper:
super().javaScriptAlert(url, js_msg)
@@ -288,21 +295,26 @@ class WebEnginePage(QWebEnginePage):
url: QUrl,
typ: QWebEnginePage.NavigationType,
is_main_frame: bool):
"""Override acceptNavigationRequest to handle clicked links.
This only show an error on invalid links - everything else is handled
in createWindow.
"""
log.webview.debug("navigation request: url {}, type {}, is_main_frame "
"{}".format(url.toDisplayString(),
debug.qenum_key(QWebEnginePage, typ),
is_main_frame))
if (typ == QWebEnginePage.NavigationTypeLinkClicked and
not url.isValid()):
msg = urlutils.get_errstring(url, "Invalid link clicked")
message.error(msg)
return False
return True
"""Override acceptNavigationRequest to forward it to the tab API."""
type_map = {
QWebEnginePage.NavigationTypeLinkClicked:
usertypes.NavigationRequest.Type.link_clicked,
QWebEnginePage.NavigationTypeTyped:
usertypes.NavigationRequest.Type.typed,
QWebEnginePage.NavigationTypeFormSubmitted:
usertypes.NavigationRequest.Type.form_submitted,
QWebEnginePage.NavigationTypeBackForward:
usertypes.NavigationRequest.Type.back_forward,
QWebEnginePage.NavigationTypeReload:
usertypes.NavigationRequest.Type.reloaded,
QWebEnginePage.NavigationTypeOther:
usertypes.NavigationRequest.Type.other,
}
navigation = usertypes.NavigationRequest(url=url,
navigation_type=type_map[typ],
is_main_frame=is_main_frame)
self.navigation_request.emit(navigation)
return navigation.accepted
@pyqtSlot('QUrl')
def _inject_userjs(self, url):

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-2017 Daniel Schadt
# Copyright 2015-2018 Daniel Schadt
#
# This file is part of qutebrowser.
#
@@ -254,7 +254,6 @@ class _Downloader:
_finished_file: A flag indicating if the file has already been
written.
_used: A flag indicating if the downloader has already been used.
_win_id: The window this downloader belongs to.
"""
def __init__(self, tab, target):
@@ -265,7 +264,6 @@ class _Downloader:
self.pending_downloads = set()
self._finished_file = False
self._used = False
self._win_id = tab.win_id
def run(self):
"""Download and save the page.
@@ -365,8 +363,7 @@ class _Downloader:
self.writer.add_file(urlutils.encoded_url(url), b'')
return
download_manager = objreg.get('qtnetwork-download-manager',
scope='window', window=self._win_id)
download_manager = objreg.get('qtnetwork-download-manager')
target = downloads.FileObjDownloadTarget(_NoCloseBytesIO())
item = download_manager.get(url, target=target,
auto_remove=True)

View File

@@ -1,7 +1,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2017 Antoni Boucher (antoyo) <bouanto@zoho.com>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Antoni Boucher (antoyo) <bouanto@zoho.com>
#
# This file is part of qutebrowser.
#
@@ -25,7 +25,7 @@
import os
from qutebrowser.browser.webkit.network import schemehandler, networkreply
from qutebrowser.browser.webkit.network import networkreply
from qutebrowser.utils import jinja
@@ -111,27 +111,21 @@ def dirbrowser_html(path):
return html.encode('UTF-8', errors='xmlcharrefreplace')
class FileSchemeHandler(schemehandler.SchemeHandler):
def handler(request):
"""Handler for a file:// URL.
"""Scheme handler for file: URLs."""
Args:
request: QNetworkRequest to answer to.
def createRequest(self, _op, request, _outgoing_data):
"""Create a new request.
Args:
request: const QNetworkRequest & req
_op: Operation op
_outgoing_data: QIODevice * outgoingData
Return:
A QNetworkReply for directories, None for files.
"""
path = request.url().toLocalFile()
try:
if os.path.isdir(path):
data = dirbrowser_html(path)
return networkreply.FixedDataNetworkReply(
request, data, 'text/html', self.parent())
return None
except UnicodeEncodeError:
return None
Return:
A QNetworkReply for directories, None for files.
"""
path = request.url().toLocalFile()
try:
if os.path.isdir(path):
data = dirbrowser_html(path)
return networkreply.FixedDataNetworkReply(
request, data, 'text/html')
return None
except UnicodeEncodeError:
return None

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -19,9 +19,7 @@
"""Our own QNetworkAccessManager."""
import os
import collections
import netrc
import html
import attr
@@ -127,10 +125,13 @@ class NetworkManager(QNetworkAccessManager):
_scheme_handlers: A dictionary (scheme -> handler) of supported custom
schemes.
_win_id: The window ID this NetworkManager is associated with.
(or None for generic network managers)
_tab_id: The tab ID this NetworkManager is associated with.
(or None for generic network managers)
_rejected_ssl_errors: A {QUrl: [SslError]} dict of rejected errors.
_accepted_ssl_errors: A {QUrl: [SslError]} dict of accepted errors.
_private: Whether we're in private browsing mode.
netrc_used: Whether netrc authentication was performed.
Signals:
shutting_down: Emitted when the QNAM is shutting down.
@@ -150,8 +151,8 @@ class NetworkManager(QNetworkAccessManager):
self._tab_id = tab_id
self._private = private
self._scheme_handlers = {
'qute': webkitqutescheme.QuteSchemeHandler(win_id),
'file': filescheme.FileSchemeHandler(win_id),
'qute': webkitqutescheme.handler,
'file': filescheme.handler,
}
self._set_cookiejar()
self._set_cache()
@@ -161,6 +162,7 @@ class NetworkManager(QNetworkAccessManager):
self.authenticationRequired.connect(self.on_authentication_required)
self.proxyAuthenticationRequired.connect(
self.on_proxy_authentication_required)
self.netrc_used = False
def _set_cookiejar(self):
"""Set the cookie jar of the NetworkManager correctly."""
@@ -194,6 +196,7 @@ class NetworkManager(QNetworkAccessManager):
# This might be a generic network manager, e.g. one belonging to a
# DownloadManager. In this case, just skip the webview thing.
if self._tab_id is not None:
assert self._win_id is not None
tab = objreg.get('tab', scope='tab', window=self._win_id,
tab=self._tab_id)
abort_on.append(tab.load_started)
@@ -270,28 +273,12 @@ class NetworkManager(QNetworkAccessManager):
@pyqtSlot('QNetworkReply*', 'QAuthenticator*')
def on_authentication_required(self, reply, authenticator):
"""Called when a website needs authentication."""
user, password = None, None
if not hasattr(reply, "netrc_used") and 'HOME' in os.environ:
# We'll get an OSError by netrc if 'HOME' isn't available in
# os.environ. We don't want to log that, so we prevent it
# altogether.
reply.netrc_used = True
try:
net = netrc.netrc(config.val.content.netrc_file)
authenticators = net.authenticators(reply.url().host())
if authenticators is not None:
(user, _account, password) = authenticators
except FileNotFoundError:
log.misc.debug("No .netrc file found")
except OSError:
log.misc.exception("Unable to read the netrc file")
except netrc.NetrcParseError:
log.misc.exception("Error when parsing the netrc file")
if user is not None:
authenticator.setUser(user)
authenticator.setPassword(password)
else:
netrc_success = False
if not self.netrc_used:
self.netrc_used = True
netrc_success = shared.netrc_authentication(reply.url(),
authenticator)
if not netrc_success:
abort_on = self._get_abort_signals(reply)
shared.authentication_required(reply.url(), authenticator,
abort_on=abort_on)
@@ -386,9 +373,9 @@ class NetworkManager(QNetworkAccessManager):
scheme = req.url().scheme()
if scheme in self._scheme_handlers:
result = self._scheme_handlers[scheme].createRequest(
op, req, outgoing_data)
result = self._scheme_handlers[scheme](req)
if result is not None:
result.setParent(self)
return result
for header, value in shared.custom_headers():
@@ -408,6 +395,7 @@ class NetworkManager(QNetworkAccessManager):
current_url = QUrl()
if self._tab_id is not None:
assert self._win_id is not None
try:
tab = objreg.get('tab', scope='tab', window=self._win_id,
tab=self._tab_id)

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# Based on the Eric5 helpviewer,
# Copyright (c) 2009 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>

View File

@@ -1,51 +0,0 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# Based on the Eric5 helpviewer,
# Copyright (c) 2009 - 2014 Detlev Offenbach <detlev@die-offenbachs.de>
#
# 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/>.
"""Base class for custom scheme handlers."""
from PyQt5.QtCore import QObject
class SchemeHandler(QObject):
"""Abstract base class for custom scheme handlers.
Attributes:
_win_id: The window ID this scheme handler is associated with.
"""
def __init__(self, win_id, parent=None):
super().__init__(parent)
self._win_id = win_id
def createRequest(self, op, request, outgoing_data):
"""Create a new request.
Args:
op: Operation op
req: const QNetworkRequest & req
outgoing_data: QIODevice * outgoingData
Return:
A QNetworkReply.
"""
raise NotImplementedError

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -24,46 +24,36 @@ import mimetypes
from PyQt5.QtNetwork import QNetworkReply
from qutebrowser.browser import pdfjs, qutescheme
from qutebrowser.browser.webkit.network import schemehandler, networkreply
from qutebrowser.browser.webkit.network import networkreply
from qutebrowser.utils import log, usertypes, qtutils
class QuteSchemeHandler(schemehandler.SchemeHandler):
def handler(request):
"""Scheme handler for qute:// URLs.
"""Scheme handler for qute:// URLs."""
Args:
request: QNetworkRequest to answer to.
def createRequest(self, _op, request, _outgoing_data):
"""Create a new request.
Return:
A QNetworkReply.
"""
try:
mimetype, data = qutescheme.data_for_url(request.url())
except qutescheme.NoHandlerFound:
errorstr = "No handler found for {}!".format(
request.url().toDisplayString())
return networkreply.ErrorNetworkReply(
request, errorstr, QNetworkReply.ContentNotFoundError)
except qutescheme.QuteSchemeOSError as e:
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.ContentNotFoundError)
except qutescheme.QuteSchemeError as e:
return networkreply.ErrorNetworkReply(request, e.errorstring, e.error)
except qutescheme.Redirect as e:
qtutils.ensure_valid(e.url)
return networkreply.RedirectNetworkReply(e.url)
Args:
request: const QNetworkRequest & req
_op: Operation op
_outgoing_data: QIODevice * outgoingData
Return:
A QNetworkReply.
"""
try:
mimetype, data = qutescheme.data_for_url(request.url())
except qutescheme.NoHandlerFound:
errorstr = "No handler found for {}!".format(
request.url().toDisplayString())
return networkreply.ErrorNetworkReply(
request, errorstr, QNetworkReply.ContentNotFoundError,
self.parent())
except qutescheme.QuteSchemeOSError as e:
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.ContentNotFoundError,
self.parent())
except qutescheme.QuteSchemeError as e:
return networkreply.ErrorNetworkReply(request, e.errorstring,
e.error, self.parent())
except qutescheme.Redirect as e:
qtutils.ensure_valid(e.url)
return networkreply.RedirectNetworkReply(e.url, self.parent())
return networkreply.FixedDataNetworkReply(request, data, mimetype,
self.parent())
return networkreply.FixedDataNetworkReply(request, data, mimetype)
@qutescheme.add_handler('pdfjs', backend=usertypes.Backend.QtWebKit)

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2014-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2015-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2015-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#

View File

@@ -1,6 +1,6 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016-2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
# Copyright 2016-2018 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
@@ -17,9 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
# We get various "abstract but not overridden" warnings
# pylint: disable=abstract-method
"""Bridge from QWebSettings to our own settings.
Module attributes:
@@ -37,85 +34,130 @@ from qutebrowser.utils import standarddir, urlutils
from qutebrowser.browser import shared
class Base(websettings.Base):
"""Base settings class with appropriate _get_global_settings."""
def _get_global_settings(self):
return [QWebSettings.globalSettings()]
# The global WebKitSettings object
global_settings = None
class Attribute(Base, websettings.Attribute):
class WebKitSettings(websettings.AbstractSettings):
"""A setting set via QWebSettings::setAttribute."""
"""A wrapper for the config for QWebSettings."""
ENUM_BASE = QWebSettings
_ATTRIBUTES = {
'content.images':
[QWebSettings.AutoLoadImages],
'content.javascript.enabled':
[QWebSettings.JavascriptEnabled],
'content.javascript.can_open_tabs_automatically':
[QWebSettings.JavascriptCanOpenWindows],
'content.javascript.can_close_tabs':
[QWebSettings.JavascriptCanCloseWindows],
'content.javascript.can_access_clipboard':
[QWebSettings.JavascriptCanAccessClipboard],
'content.plugins':
[QWebSettings.PluginsEnabled],
'content.webgl':
[QWebSettings.WebGLEnabled],
'content.hyperlink_auditing':
[QWebSettings.HyperlinkAuditingEnabled],
'content.local_content_can_access_remote_urls':
[QWebSettings.LocalContentCanAccessRemoteUrls],
'content.local_content_can_access_file_urls':
[QWebSettings.LocalContentCanAccessFileUrls],
'content.dns_prefetch':
[QWebSettings.DnsPrefetchEnabled],
'content.frame_flattening':
[QWebSettings.FrameFlatteningEnabled],
'content.cache.appcache':
[QWebSettings.OfflineWebApplicationCacheEnabled],
'content.local_storage':
[QWebSettings.LocalStorageEnabled,
QWebSettings.OfflineStorageDatabaseEnabled],
'content.developer_extras':
[QWebSettings.DeveloperExtrasEnabled],
'content.print_element_backgrounds':
[QWebSettings.PrintElementBackgrounds],
'content.xss_auditing':
[QWebSettings.XSSAuditingEnabled],
'input.spatial_navigation':
[QWebSettings.SpatialNavigationEnabled],
'input.links_included_in_focus_chain':
[QWebSettings.LinksIncludedInFocusChain],
'zoom.text_only':
[QWebSettings.ZoomTextOnly],
'scrolling.smooth':
[QWebSettings.ScrollAnimatorEnabled],
}
_FONT_SIZES = {
'fonts.web.size.minimum':
QWebSettings.MinimumFontSize,
'fonts.web.size.minimum_logical':
QWebSettings.MinimumLogicalFontSize,
'fonts.web.size.default':
QWebSettings.DefaultFontSize,
'fonts.web.size.default_fixed':
QWebSettings.DefaultFixedFontSize,
}
_FONT_FAMILIES = {
'fonts.web.family.standard': QWebSettings.StandardFont,
'fonts.web.family.fixed': QWebSettings.FixedFont,
'fonts.web.family.serif': QWebSettings.SerifFont,
'fonts.web.family.sans_serif': QWebSettings.SansSerifFont,
'fonts.web.family.cursive': QWebSettings.CursiveFont,
'fonts.web.family.fantasy': QWebSettings.FantasyFont,
}
# Mapping from QWebSettings::QWebSettings() in
# qtwebkit/Source/WebKit/qt/Api/qwebsettings.cpp
_FONT_TO_QFONT = {
QWebSettings.StandardFont: QFont.Serif,
QWebSettings.FixedFont: QFont.Monospace,
QWebSettings.SerifFont: QFont.Serif,
QWebSettings.SansSerifFont: QFont.SansSerif,
QWebSettings.CursiveFont: QFont.Cursive,
QWebSettings.FantasyFont: QFont.Fantasy,
}
class Setter(Base, websettings.Setter):
"""A setting set via a QWebSettings setter method."""
pass
def _set_user_stylesheet(settings):
"""Set the generated user-stylesheet."""
stylesheet = shared.get_user_stylesheet().encode('utf-8')
url = urlutils.data_url('text/css;charset=utf-8', stylesheet)
settings.setUserStyleSheetUrl(url)
class StaticSetter(Base, websettings.StaticSetter):
"""A setting set via a static QWebSettings setter method."""
pass
class FontFamilySetter(Base, websettings.FontFamilySetter):
"""A setter for a font family.
Gets the default value from QFont.
"""
def __init__(self, font):
# Mapping from QWebSettings::QWebSettings() in
# qtwebkit/Source/WebKit/qt/Api/qwebsettings.cpp
font_to_qfont = {
QWebSettings.StandardFont: QFont.Serif,
QWebSettings.FixedFont: QFont.Monospace,
QWebSettings.SerifFont: QFont.Serif,
QWebSettings.SansSerifFont: QFont.SansSerif,
QWebSettings.CursiveFont: QFont.Cursive,
QWebSettings.FantasyFont: QFont.Fantasy,
}
super().__init__(setter=QWebSettings.setFontFamily, font=font,
qfont=font_to_qfont[font])
class CookiePolicy(Base):
"""The ThirdPartyCookiePolicy setting is different from other settings."""
MAPPING = {
def _set_cookie_accept_policy(settings):
"""Update the content.cookies.accept setting."""
mapping = {
'all': QWebSettings.AlwaysAllowThirdPartyCookies,
'no-3rdparty': QWebSettings.AlwaysBlockThirdPartyCookies,
'never': QWebSettings.AlwaysBlockThirdPartyCookies,
'no-unknown-3rdparty': QWebSettings.AllowThirdPartyWithExistingCookies,
}
def _set(self, value, settings=None):
for obj in self._get_settings(settings):
obj.setThirdPartyCookiePolicy(self.MAPPING[value])
value = config.val.content.cookies.accept
settings.setThirdPartyCookiePolicy(mapping[value])
def _set_user_stylesheet():
"""Set the generated user-stylesheet."""
stylesheet = shared.get_user_stylesheet().encode('utf-8')
url = urlutils.data_url('text/css;charset=utf-8', stylesheet)
QWebSettings.globalSettings().setUserStyleSheetUrl(url)
def _set_cache_maximum_pages(settings):
"""Update the content.cache.maximum_pages setting."""
value = config.val.content.cache.maximum_pages
settings.setMaximumPagesInCache(value)
def _update_settings(option):
"""Update global settings when qwebsettings changed."""
global_settings.update_setting(option)
settings = QWebSettings.globalSettings()
if option in ['scrollbar.hide', 'content.user_stylesheets']:
_set_user_stylesheet()
websettings.update_mappings(MAPPINGS, option)
_set_user_stylesheet(settings)
elif option == 'content.cookies.accept':
_set_cookie_accept_policy(settings)
elif option == 'content.cache.maximum_pages':
_set_cache_maximum_pages(settings)
def init(_args):
@@ -131,92 +173,20 @@ def init(_args):
QWebSettings.setOfflineStoragePath(
os.path.join(data_path, 'offline-storage'))
websettings.init_mappings(MAPPINGS)
_set_user_stylesheet()
settings = QWebSettings.globalSettings()
_set_user_stylesheet(settings)
_set_cookie_accept_policy(settings)
_set_cache_maximum_pages(settings)
config.instance.changed.connect(_update_settings)
global global_settings
global_settings = WebKitSettings(QWebSettings.globalSettings())
global_settings.init_settings()
def shutdown():
"""Disable storage so removing tmpdir will work."""
QWebSettings.setIconDatabasePath('')
QWebSettings.setOfflineWebApplicationCachePath('')
QWebSettings.globalSettings().setLocalStoragePath('')
MAPPINGS = {
'content.images':
Attribute(QWebSettings.AutoLoadImages),
'content.javascript.enabled':
Attribute(QWebSettings.JavascriptEnabled),
'content.javascript.can_open_tabs_automatically':
Attribute(QWebSettings.JavascriptCanOpenWindows),
'content.javascript.can_close_tabs':
Attribute(QWebSettings.JavascriptCanCloseWindows),
'content.javascript.can_access_clipboard':
Attribute(QWebSettings.JavascriptCanAccessClipboard),
'content.plugins':
Attribute(QWebSettings.PluginsEnabled),
'content.webgl':
Attribute(QWebSettings.WebGLEnabled),
'content.hyperlink_auditing':
Attribute(QWebSettings.HyperlinkAuditingEnabled),
'content.local_content_can_access_remote_urls':
Attribute(QWebSettings.LocalContentCanAccessRemoteUrls),
'content.local_content_can_access_file_urls':
Attribute(QWebSettings.LocalContentCanAccessFileUrls),
'content.cookies.accept':
CookiePolicy(),
'content.dns_prefetch':
Attribute(QWebSettings.DnsPrefetchEnabled),
'content.frame_flattening':
Attribute(QWebSettings.FrameFlatteningEnabled),
'content.cache.appcache':
Attribute(QWebSettings.OfflineWebApplicationCacheEnabled),
'content.local_storage':
Attribute(QWebSettings.LocalStorageEnabled,
QWebSettings.OfflineStorageDatabaseEnabled),
'content.cache.maximum_pages':
StaticSetter(QWebSettings.setMaximumPagesInCache),
'content.developer_extras':
Attribute(QWebSettings.DeveloperExtrasEnabled),
'content.print_element_backgrounds':
Attribute(QWebSettings.PrintElementBackgrounds),
'content.xss_auditing':
Attribute(QWebSettings.XSSAuditingEnabled),
'content.default_encoding':
Setter(QWebSettings.setDefaultTextEncoding),
# content.user_stylesheets is handled separately
'input.spatial_navigation':
Attribute(QWebSettings.SpatialNavigationEnabled),
'input.links_included_in_focus_chain':
Attribute(QWebSettings.LinksIncludedInFocusChain),
'fonts.web.family.standard':
FontFamilySetter(QWebSettings.StandardFont),
'fonts.web.family.fixed':
FontFamilySetter(QWebSettings.FixedFont),
'fonts.web.family.serif':
FontFamilySetter(QWebSettings.SerifFont),
'fonts.web.family.sans_serif':
FontFamilySetter(QWebSettings.SansSerifFont),
'fonts.web.family.cursive':
FontFamilySetter(QWebSettings.CursiveFont),
'fonts.web.family.fantasy':
FontFamilySetter(QWebSettings.FantasyFont),
'fonts.web.size.minimum':
Setter(QWebSettings.setFontSize, args=[QWebSettings.MinimumFontSize]),
'fonts.web.size.minimum_logical':
Setter(QWebSettings.setFontSize,
args=[QWebSettings.MinimumLogicalFontSize]),
'fonts.web.size.default':
Setter(QWebSettings.setFontSize, args=[QWebSettings.DefaultFontSize]),
'fonts.web.size.default_fixed':
Setter(QWebSettings.setFontSize,
args=[QWebSettings.DefaultFixedFontSize]),
'zoom.text_only':
Attribute(QWebSettings.ZoomTextOnly),
'scrolling.smooth':
Attribute(QWebSettings.ScrollAnimatorEnabled),
}

Some files were not shown because too many files have changed in this diff Show More