Compare commits

...

722 Commits

Author SHA1 Message Date
Florian Bruhin
293e322905 Release v0.6.2 2016-04-30 15:05:19 +02:00
Florian Bruhin
354bd5d606 Update changelog for v0.6.2 2016-04-30 14:50:04 +02:00
Florian Bruhin
8e619fa74e Fix dictionary hints crash 2016-04-30 14:44:25 +02:00
Florian Bruhin
5b944fb272 Add @pyqtSlot for qApp.focusChanged slot 2016-04-30 14:43:11 +02:00
Daniel Schadt
36d2fc4b92 cache: fix crash when cache_dir is None
Issue #1412

When passing --cachedir="" on the command line, standarddir.cache()
returns None, which stands for "deactivate cache" and has to be
properly handled in DiskCache.__init__() (i.e. don't pass it to
os.path.join)
2016-04-30 14:42:52 +02:00
Florian Bruhin
26f4acb10a Split IPCServer.on_ready_read into two methods 2016-04-30 14:42:44 +02:00
Florian Bruhin
991277e9de Work around PyQt 5.6 segfault when using IPC
PyQt 5.6 seems to segfault when emitting None with a signal which is
declared as emitting a string:

https://www.riverbankcomputing.com/pipermail/pyqt/2016-April/037375.html

We now avoid this by using an empty string explicitly instead of None.
2016-04-30 14:42:17 +02:00
Florian Bruhin
133e959ecc Remove @pyqtSlot for on_new_window
This worked fine with Python 3.5 but causes a circular import which is
hard to break with Python 3.4.

The original solution was to do @pyqtSlot(object), but that doesn't work
with PyQt 5.6 anymore...
2016-04-30 14:42:17 +02:00
Florian Bruhin
be1630f7d0 Fix types in @pyqtSlot decorations
PyQt 5.5 enforces correct type signatures, and there were a lot of
places where we were simply wrong, causing qutebrowser to not start at
all...
2016-04-30 14:42:00 +02:00
Ryan Roden-Corrent
c57bf8701e Don't crash when undoing twice on default page.
Avoid a crash when undoing twice on the default page with last-close set to
default-page.
This was caused by logic to reuse the current tab if it is on the default page
and has no history. The fix is using openurl rather than removeTab/tabopen.
2016-04-30 14:41:48 +02:00
Florian Bruhin
ea2ae94cd0 Fix crash with :tab-{prev,next,focus} with 0 tabs
When using :tab-prev/:tab-next (or :tab-focus which uses :tab-next
internally) immediately after the last tab, those functions could be
called with 0 tabs open, which caused a ZeroDivisionError when trying to
do % 0.

Fixes #1448.
2016-04-30 14:41:26 +02:00
Florian Bruhin
356eb7e5e7 Release v0.6.1 2016-04-10 21:13:33 +02:00
Florian Bruhin
bdd2afa1a2 Make sure the cheatsheet PNG is included in sdist
Fixes #1403
2016-04-10 21:01:41 +02:00
Florian Bruhin
e02ff26d0e Fix cheatsheet link URL in quickstart 2016-04-10 21:01:41 +02:00
Florian Bruhin
128fb2826a Add missing file 2016-04-10 20:35:07 +02:00
Florian Bruhin
3521ee16e4 Fix downloading of non-ascii files with LC_ALL=C
Fixes #908.
2016-04-10 20:35:07 +02:00
Florian Bruhin
af5cb36591 Rename test_cmdline_args to test_invocations 2016-04-10 20:35:07 +02:00
Florian Bruhin
8aaae5b78c Fix test_last_window_session_none 2016-04-10 18:23:10 +02:00
Florian Bruhin
ced87b163f Don't crash if data is None while saving session
Under some circumstances I can't reproduce (switching/turning off
monitors?) it seems it's possible that SessionManager.save gets called
with last_window=True, without on_last_window_closed being called.

This might be to one of the Qt screen management bugs fixed in Qt 5.6,
which would explain why I can't reproduce it.

Instead of crashing, let's log the error and not save the session.
2016-04-10 18:03:29 +02:00
Florian Bruhin
c5459abb65 Add some more logging for standarddir 2016-04-10 18:03:29 +02:00
Florian Bruhin
83b7c0dd6f Fix #1414 with a weird workaround 2016-04-10 18:03:29 +02:00
Florian Bruhin
93fff9a69c freeze: Add pkg_resources._vendor.six
Another package added by pkg_resources and not picked up by cx_Freeze...
2016-04-10 18:03:29 +02:00
Florian Bruhin
b2247fa406 tox: Update setuptools in cxfreeze-windows env
In 43a4a6a3e7 we added
pkg_resources._vendor.pyparsing to the frozen modules - however, older
setuptools (and thus pkg_resources) versions don't have that module yet,
so freezing would fail.
2016-04-10 18:03:29 +02:00
Florian Bruhin
fafba9af3f build_release: Don't call update_3rdparty.main
main tries to parse sys.argv which will fail when called from
build_release when e.g. --asciidoc is given.
2016-04-10 18:03:29 +02:00
Florian Bruhin
806436297a Release v0.6.0 2016-04-04 18:16:56 +02:00
Florian Bruhin
c67edcf811 tests: Add v0.6.0 config to test_old_config 2016-04-04 18:16:31 +02:00
Florian Bruhin
08a7ee4ffb Merge branch 'rcorre-contributor-config' 2016-04-04 07:59:42 +02:00
Florian Bruhin
5cdb433669 Regenerate authors 2016-04-04 07:59:22 +02:00
Florian Bruhin
c3d154a856 Revert "Move note about conifg redirect to CONTRIBUTING."
This reverts commit 2634b333f2.
2016-04-04 07:59:14 +02:00
Florian Bruhin
88e648d6f9 Merge branch 'contributor-config' of https://github.com/rcorre/qutebrowser into rcorre-contributor-config 2016-04-04 07:58:57 +02:00
Florian Bruhin
27818e3e33 Merge branch 'paretje-password' 2016-04-04 07:52:50 +02:00
Florian Bruhin
2b2ab5268a Regenerate authors 2016-04-04 07:52:44 +02:00
Ryan Roden-Corrent
2634b333f2 Move note about conifg redirect to CONTRIBUTING.
This was a note for developers, so it makes more sense to have in
CONTRIBUTING.
This also adds a section on using tox, which was mentioned only in
INSTALL and not CONTRIBUTING.
2016-04-02 11:56:26 -04:00
Ryan Roden-Corrent
973afbcec9 Add note about redirecting config for testing.
New contributors might like to be reminded to redirect the config
access of their locally-built qutebrowser to avoid overwriting their
global settings.
2016-04-02 08:29:40 -04:00
Kevin Velghe
35fa7b3989 Implement libsecret password backend 2016-04-01 22:52:32 +02:00
Florian Bruhin
3b24e70db1 Update cheatsheet PNGs
Closes #1388
2016-04-01 18:18:53 +02:00
Florian Bruhin
9b25f8f91d Add --cheatsheet to src2asciidoc.py 2016-04-01 18:18:41 +02:00
Florian Bruhin
4b9cd1c544 Add qute:verizon 2016-04-01 10:30:30 +02:00
Florian Bruhin
4daf4a8e64 Fix lint 2016-04-01 08:16:28 +02:00
Florian Bruhin
272eb28d7b Fix saving of history titles
This is a regression introduced in d83d2e4.
2016-04-01 07:53:44 +02:00
Florian Bruhin
19edea7343 Rename unit/misc/test_sessions.py to *_unit.py
Otherwise we get:

import file mismatch:
imported module 'test_sessions' has this __file__ attribute:
  /home/florian/proj/qutebrowser/git/tests/integration/features/test_sessions.py
which is not the same as the test file we want to collect:
  /home/florian/proj/qutebrowser/git/tests/unit/misc/test_sessions.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
2016-04-01 07:52:54 +02:00
Florian Bruhin
e3a8d00f27 Include cheatsheet images in offline help
Fixes #329.
Note the png's are kind of outdated right now.
2016-04-01 07:42:40 +02:00
Florian Bruhin
6631c6456c Merge branch 'session-tests' 2016-04-01 06:15:52 +02:00
Florian Bruhin
70fedf618a Merge branch 'paretje-force-current-tab' 2016-04-01 06:14:39 +02:00
Florian Bruhin
b5636a3531 Update changelog 2016-04-01 06:14:30 +02:00
Florian Bruhin
aad2407de1 Merge branch 'force-current-tab' of https://github.com/paretje/qutebrowser into paretje-force-current-tab 2016-04-01 06:13:08 +02:00
Kevin Velghe
0652637fbe Refactor unit tests for remove_blank_target 2016-04-01 01:32:27 +02:00
Florian Bruhin
451ea05393 Ignore "Frame load interrupted by policy change"
Searching for that error doesn't turn up many helpful results, but it
seems to be harmless and shown when downloading a file - it's also new
in Qt 5.6 it seems, so let's just ignore it.
2016-03-31 22:41:25 +02:00
Florian Bruhin
dd9145d650 travis: Remove sources.list patching again
Turns out the other mirrors aren't really more stable either.
2016-03-31 21:26:44 +02:00
Florian Bruhin
d30093b877 Skip "Focusing download widget via Tab" on old Qt
Qt < 5.3.1 (used on Travis with Ubuntu Trusty) has a bug with its
javascript prompt implementation, so we can't run that test there.
2016-03-31 21:12:13 +02:00
Florian Bruhin
89742beb4e pylint: useless-suppression in test_qt_javascript
When QtWebEngine is available, the suppression is useless.
2016-03-31 20:18:26 +02:00
Florian Bruhin
27b31b7ded Avoid DownloadView being focused when pressing tab
The previous fix didn't work in situations where the web view was
actually focused, but had no focused element (like about:blank).

The new fix always works, and even is a lot simpler!

Fixes #504.
2016-03-31 19:45:36 +02:00
Florian Bruhin
123fd18af5 Fix crash when removing download in closed window
When a download is finished with `removed-finished-download` set to a
delay, it's removed via a singleshot QTimer.

However, when the window was closed in the meantime, the slot still was
executed by Qt, even though the DownloadManager was already deleted.

Fixes #1242
2016-03-31 19:09:43 +02:00
Kevin Velghe
f4f98c54fa Keep pylint happy 2016-03-31 11:25:35 +02:00
Kevin Velghe
7b4a3fc867 Update docs 2016-03-31 10:53:05 +02:00
Kevin Velghe
e90ad3d9c0 Complete coverage for webelem 2016-03-31 10:25:44 +02:00
Kevin Velghe
ef6ffd6a3a Add link_span.html 2016-03-31 09:36:13 +02:00
Florian Bruhin
305c8a2f03 Update changelog 2016-03-31 07:16:00 +02:00
Florian Bruhin
da1338278a Merge branch 'toofar-tab-complete' 2016-03-31 07:10:20 +02:00
Florian Bruhin
d15a3c6de8 Update cheatsheet 2016-03-31 07:10:13 +02:00
Florian Bruhin
cae496565b Bind gt to show buffer list 2016-03-31 07:05:30 +02:00
Florian Bruhin
14b9f3d8f5 Remove gt/gT bindings
Those were added in #443, inspired by luakit.

However, all other bindings follow dwb's defaults, and dwb uses `gt` for
showing buffers. To be consistent, let's rebind gt to show :buffer.
2016-03-31 07:02:59 +02:00
Florian Bruhin
c1cec53c0e Merge branch 'tab-complete' of https://github.com/toofar/qutebrowser into toofar-tab-complete 2016-03-31 06:58:22 +02:00
Florian Bruhin
d83d2e442e Work around getting an empty session title.
Fixes #879.
Supersedes #880.
2016-03-31 06:38:09 +02:00
Florian Bruhin
99263ae351 Rename minimal_webkit_testbrowser.py to testbrowser.py 2016-03-31 06:29:48 +02:00
Jimmy
3846ce1f82 Add docs for :buffer 2016-03-31 14:00:36 +13:00
Jimmy
97ab6db655 Adds tests for buffer command.
The buffer_troubling_args tests may look a little un-intuitive but that is
because they are testing the edge cases for the current behaviour. If these
edge cases are encountered during normal usage you are doing something wrong.
2016-03-31 14:00:36 +13:00
Jimmy
1c10a1aecf Adds new buffer command with completion.
`buffer` takes either a tab index or a string and focuses the specified
tab. The index can be of the form [0-9]+ which will switch to the
relevant tab in the current window or [0-9]+/[0-9]+ (that is
win_id/index) which will focus the specified window before switching
tabs. If a string is passed the list of open tabs across all windows is
sorted based on title and url (just like in the completion widget) and
the top result is selected.
2016-03-31 14:00:36 +13:00
Kevin Velghe
0fe0f84546 Fix loop and support area tag
It appears the output of qtwebkit has a cycle, so we end in an endless
loop. This limits the loop to 5 steps.
2016-03-31 00:58:19 +02:00
Kevin Velghe
0432ba68c6 Add hints integration test 2016-03-30 23:53:18 +02:00
Florian Bruhin
4b4b3f2bc9 Add Homebrew note to OS X install instructions 2016-03-30 23:51:11 +02:00
Kevin Velghe
00f1e699d4 Add extra test to test_remove_blank_target 2016-03-30 23:46:02 +02:00
Kevin Velghe
a242ba28d9 Support multiple levels when checking link target 2016-03-30 23:44:05 +02:00
Florian Bruhin
bb4e5ca740 Regenerate authors 2016-03-30 22:43:18 +02:00
Patric Schmitz
a54e77f118 add coverage test example to CONTRIBUTING file 2016-03-30 22:36:23 +02:00
Florian Bruhin
a6a2210ce8 Add tests for #879 2016-03-30 22:16:36 +02:00
Kevin Velghe
dd4710d596 Fix test_remove_blank_target 2016-03-30 19:54:42 +02:00
Kevin Velghe
f4f926cdca Add integration tests for current target hints 2016-03-30 19:49:25 +02:00
Kevin Velghe
a432102be0 Add webelem tests for remove_blank_target 2016-03-30 19:08:37 +02:00
Kevin Velghe
571d6519e9 Handle frames 2016-03-30 19:08:10 +02:00
Kevin Velghe
201739a7e6 Add current hint target 2016-03-30 16:27:34 +02:00
Florian Bruhin
5a5e8167dd Fix lint 2016-03-29 23:20:39 +02:00
Florian Bruhin
8a1d45210c Merge branch 'Kingdread-dirbrowser-issue-1334' 2016-03-29 22:38:58 +02:00
Florian Bruhin
8a1c99d3ff Update changelog 2016-03-29 22:38:50 +02:00
Florian Bruhin
6c7e2492e9 Merge branch 'dirbrowser-issue-1334' of https://github.com/Kingdread/qutebrowser into Kingdread-dirbrowser-issue-1334 2016-03-29 22:38:04 +02:00
Florian Bruhin
fc7e75c355 Fix lint 2016-03-29 22:30:26 +02:00
Florian Bruhin
4067d38cb0 Add some tests for QtWebKit/Engine JS capabilities 2016-03-29 22:08:49 +02:00
Florian Bruhin
81e284c1f1 Merge branch 'phansch-bdd_test_spawn_command' 2016-03-29 21:13:04 +02:00
Florian Bruhin
1691156f96 Regenerate authors 2016-03-29 21:12:54 +02:00
Florian Bruhin
fee3b9a02b Merge branch 'bdd_test_spawn_command' of https://github.com/phansch/qutebrowser into phansch-bdd_test_spawn_command 2016-03-29 21:12:29 +02:00
Florian Bruhin
de5ecbf4e7 Fix lint 2016-03-29 21:10:29 +02:00
Daniel Schadt
bd5b1f207d fix lint 2016-03-29 21:02:54 +02:00
Daniel Schadt
3007fbf5c2 tests: add tests for quteproc.click_element 2016-03-29 20:52:23 +02:00
Daniel Schadt
f82d0f0c94 quteprocess: properly escape xpath expression
Since XPath doesn't have a way to escape quotes (or any other
character), we have to use a workaround by using concat() and switching
between quoting styles.
2016-03-29 20:34:40 +02:00
Philipp Hansch
e0e8bc805b Remove unneeded argument
Instead, figure out the data directory from the helpers directory.
2016-03-29 19:52:46 +02:00
Philipp Hansch
4a1ba45efa Merge remote-tracking branch 'upstream/master' into bdd_test_spawn_command 2016-03-29 19:24:43 +02:00
Florian Bruhin
06510832d0 Merge branch 'arsana7-master' 2016-03-29 19:24:15 +02:00
Florian Bruhin
c9f1f11489 Regenerate authors 2016-03-29 19:23:21 +02:00
Florian Bruhin
f43cbed72f tests: Inherit HTTPPostStub from QObject
This way we can test the actual signals instead of calling
on_client_success by hand.
2016-03-29 19:22:28 +02:00
Florian Bruhin
86ab33c558 Pass HTTPClient to PastebinClient as argument 2016-03-29 19:21:15 +02:00
Florian Bruhin
25555682dc Merge branch 'master' of https://github.com/arsana7/qutebrowser into arsana7-master 2016-03-29 18:59:06 +02:00
Florian Bruhin
b704c7167b tox: Update pytest-rerunfailures to 1.0.2
- Add support for --resultlog option by parsing reruns accordingly.
2016-03-29 18:48:33 +02:00
Florian Bruhin
89a061c536 INSTALL: Mention gstreamer packages for Archlinux 2016-03-29 18:47:54 +02:00
Philipp Hansch
5ae0b0cf87 Ignore test on Windows
The userscript is a bash script and there is no bash on windows.
One solution could be to use a python userscript, but there may be
other issues (file associations), too.
2016-03-29 14:17:47 +02:00
Daniel Schadt
b6c5ff25fd tests: add click_element to quteprocess 2016-03-29 13:32:35 +02:00
Philipp Hansch
8a619ea84c Prevent slashes from being stripped on Windows 2016-03-29 13:25:04 +02:00
Daniel Schadt
f085eb6eca tests/dirbrowser: move parse out of DirLayout 2016-03-29 12:43:50 +02:00
Daniel Schadt
2db5b95552 tests: use "if not parent_elem"
Also add a new test for browsing the root directory
2016-03-29 12:36:43 +02:00
Philipp Hansch
b1ecdf2924 Try to fix path issue on windows 2016-03-29 12:11:01 +02:00
Florian Bruhin
95d1f48b01 docker: Use non-debug packages for Archlinux
Upstream Arch now updated to Qt 5.6 (which means it works with Xvfb), and using
debug packages means the image is a lot bigger and builds slower, so let's use
the normal packages from [extra].
2016-03-29 07:31:11 +02:00
Florian Bruhin
32c9f2ac94 Fix starting with -c "" 2016-03-29 07:43:11 +02:00
Florian Bruhin
80433edce4 Merge branch 'craftyguy-test_statusbar_url' 2016-03-29 07:10:47 +02:00
Florian Bruhin
f15fb16ad4 Fix small nitpick 2016-03-29 07:09:17 +02:00
Florian Bruhin
cce1747e3e Regenerate authors 2016-03-29 07:08:48 +02:00
Florian Bruhin
606471c4b6 Merge branch 'test_statusbar_url' of https://github.com/craftyguy/qutebrowser into craftyguy-test_statusbar_url 2016-03-29 07:07:45 +02:00
Florian Bruhin
3eb782b204 pylint: Remove now useless no-member suppression
This is now useless since introducing the jinja.render wrapper.
2016-03-29 07:06:32 +02:00
Florian Bruhin
2aaf22df76 Also read blocked hosts from ~/.config 2016-03-29 06:59:23 +02:00
Philipp Hansch
c016c77da4 Try to fix Windows path issue with new custom step
On windows, using '/' in pathnames won't work, so it's impossible to use
to describe a path in a feature spec. The solution is to move the path
logic out of the feature spec and hand it over to `os.path.join` in a
new custom step for userscripts.
2016-03-29 01:37:40 +02:00
Clayton Craft
c811db5424 remove unused import 2016-03-28 15:31:28 -07:00
Clayton Craft
e0c0613db6 Added new test for simulating loading page and hover/unhover URL 2016-03-28 15:12:16 -07:00
Philipp Hansch
e9ae2156d3 Comply with flake8 2016-03-29 00:08:14 +02:00
Philipp Hansch
449adc2dc1 Try not to confuse syntax highlighting with quotes 2016-03-28 23:53:26 +02:00
Philipp Hansch
5811a25299 Add a datapath replacement for spawning userscripts
This adds a `(datapath)` replacement for feature tests.

`(datapath)` will expand to the absolute path to the integration data
directory.
2016-03-28 23:48:37 +02:00
Daniel Schadt
6a96e1d6d8 quteprocess: remove duplicate code 2016-03-28 23:10:20 +02:00
Daniel Schadt
c0b40aefdd tests/dirbrowser: normalize paths before comparing
This avoids errors because some libraries use '/' even on windows, while
others use '\' on windows.
2016-03-28 23:10:20 +02:00
Daniel Schadt
f6e8815871 tests: add integration tests for dirbrowser 2016-03-28 23:10:20 +02:00
Daniel Schadt
5e73a2ea37 dirbrowser: move parent dir logic to own function 2016-03-28 23:10:20 +02:00
Daniel Schadt
7fe4c7e06d fix lint 2016-03-28 23:10:20 +02:00
Daniel Schadt
e97b10517f tests: use file_url for dirbrowser tests
Otherwise the tests will fail on windows.
2016-03-28 23:10:20 +02:00
Daniel Schadt
375e60627a dirbrowser: ditch .lstrip, add file_url function 2016-03-28 23:10:20 +02:00
Daniel Schadt
700756aa16 tests: add more cases for dirbrowser.is_root
The trailing slash might have an effect on the function result, so we
should have cases with/without the slash.
2016-03-28 23:08:54 +02:00
Daniel Schadt
a77e085952 dirbrowser: fix navigation on windows
Issue #1334

The problem was that there were too few slashes. On Linux, absolute
paths start with /, so

    file:// + /home

gives file:///home, which is a valid path. On windows however, absolute
paths start with a drive letter, so

    file:// + C:/Users

gives file://C:/Users, which is parsed as "host C, path Users", which is
why it could be written as file://c/Users (strip out the empty "port"),
giving us an invalid path.

The solution is to add the third slash in the template, and strip the
redundant slash on unix systems.

Additionally, this fixes a bug where navigating from '/home/' to the
parent directory would give '/home' instead of '/'
2016-03-28 23:08:54 +02:00
Florian Bruhin
c0f9ab9b2b tox: Update Werkzeug to 0.11.5
- werkzeug.serving: Fix crash when attempting SSL connection to HTTP
  server.
2016-03-28 20:14:15 +02:00
Florian Bruhin
eb2bd91e4b Merge branch 'IsSuEat-master' 2016-03-28 19:59:26 +02:00
Florian Bruhin
6d190fc16e Regenerate authors 2016-03-28 19:59:18 +02:00
issue
654d2ac676 Added openSUSE repo 2016-03-28 14:40:35 +02:00
Kevin Velghe
76935291c0 Open links in current tab
Fix for #676

It removes the target of the link, as to prevent the website to overrule
the user. I guess the following things should be done:
 - add setting to enable/disable this behaviour
 - and/or add "hint all current"

Only the first one would be easiest. The second one requires us to keep track
of the original target. I should open a pull request for discussion.
2016-03-28 13:29:44 +02:00
Florian Bruhin
bec8bd0285 Mention QtWebEngine in segfault report dialog 2016-03-27 23:11:45 +02:00
Florian Bruhin
952daf0479 Well, this is embarassing. Fix segfault reports. 2016-03-27 22:53:05 +02:00
Florian Bruhin
4cd49d42cc Fix pdfjs error page after jinja.render changes 2016-03-27 12:53:53 +02:00
Florian Bruhin
e0475bf4e1 Revert "Allow eslint to fail for now"
This reverts commit ebfe476319.
2016-03-26 17:28:08 +01:00
Florian Bruhin
cb9ff97edb Mention to clone repo in INSTALL.asciidoc 2016-03-26 14:36:42 +01:00
Florian Bruhin
3ccbf3ce1f tox: Use -m pytest instead of -m py.test
Using -m py.test seems to cause some issues, see e.g.
https://github.com/The-Compiler/qutebrowser/pull/1317#issuecomment-196923033
2016-03-26 12:15:56 +01:00
Clayton Craft
32304f36dd fix pylint failure 2016-03-25 16:35:49 -07:00
Florian Bruhin
387e35d3e5 Fix lint 2016-03-26 00:24:54 +01:00
Florian Bruhin
9edc5a665e Handle jinja's UndefinedError in jinja.render
We can get UndefinedError when a new function got added to the jinja
env (and gets called from a template) and the user did update the
on-disk templates but not restart qutebrowser yet.

In this case, let's show a special error page to the user and tell them
to do :report in the unlikely case it's actually a bug.

Fixes #1362.
See #1360.
2016-03-26 00:00:06 +01:00
Clayton Craft
4778ff6f9c Cleaned up url test and improved coveraged based on feedback 2016-03-25 15:56:39 -07:00
Florian Bruhin
ebfe476319 Allow eslint to fail for now
https://github.com/eslint/eslint/issues/5680
2016-03-25 22:04:48 +01:00
Florian Bruhin
a81345c91d Merge branch 'craftyguy-importer-fix-order' 2016-03-25 21:51:08 +01:00
Florian Bruhin
af54255cee Regenerate authors 2016-03-25 21:47:46 +01:00
Florian Bruhin
8e1f8be5e8 Merge branch 'importer-fix-order' of https://github.com/craftyguy/qutebrowser into craftyguy-importer-fix-order 2016-03-25 21:47:33 +01:00
Clayton Craft
8addc19d47 Added option to output in "bookmark" format, clarified some "help" msgs 2016-03-25 13:01:21 -07:00
Philipp Hansch
0083538491 Add basic test for spawning userscripts 2016-03-25 18:21:38 +01:00
Philipp Hansch
69da5d7545 Add BDD tests for spawn command
Issue-Link: https://github.com/The-Compiler/qutebrowser/issues/999
2016-03-25 18:19:35 +01:00
Florian Bruhin
86b12a302e Add a jinja.render helper
This simplifies some code and will make #1362 possible.
2016-03-25 14:29:30 +01:00
Florian Bruhin
e4625a2849 Merge branch 'craftyguy-system-wide-data-path' 2016-03-25 11:10:57 +01:00
Florian Bruhin
f2f0f429fb Update docs 2016-03-25 11:10:38 +01:00
Florian Bruhin
74ee0d88e3 Merge branch 'system-wide-data-path' of https://github.com/craftyguy/qutebrowser into craftyguy-system-wide-data-path 2016-03-25 11:04:10 +01:00
Clayton Craft
81ce9b818f Fix importer script to output bookmarks in the right format for qutebrowser to use 2016-03-24 18:58:08 -07:00
Clayton Craft
439d815601 Now runner calls cmd_path instead of cmd 2016-03-24 16:26:19 -07:00
Florian Bruhin
58363d66ce Merge branch 'paretje-openfeeds' 2016-03-24 23:26:56 +01:00
Florian Bruhin
8a7550ae8b Regenerate authors 2016-03-24 23:26:49 +01:00
Florian Bruhin
3680bc8ddf Merge branch 'openfeeds' of https://github.com/paretje/qutebrowser into paretje-openfeeds 2016-03-24 23:26:42 +01:00
Kevin Velghe
11075457de Complete url's in openfeeds 2016-03-24 22:13:03 +01:00
Clayton Craft
ff4e17190f Allow searching system-wide data path on Linux for userscripts 2016-03-24 13:22:00 -07:00
Clayton Craft
a78644a199 Implement statusbar.url test 2016-03-24 12:57:14 -07:00
Florian Bruhin
74e1900910 Merge branch 'phansch-feature_test_tab_settings' 2016-03-24 20:21:53 +01:00
Florian Bruhin
1c3516bfac Regenerate authors 2016-03-24 20:21:46 +01:00
Florian Bruhin
84b558ecd2 Merge branch 'feature_test_tab_settings' of https://github.com/phansch/qutebrowser into phansch-feature_test_tab_settings 2016-03-24 20:21:36 +01:00
Florian Bruhin
9559a0695d Merge branch 'tosmarcel-master' 2016-03-24 20:16:10 +01:00
Florian Bruhin
4fda35be66 Regenerate authors 2016-03-24 20:16:00 +01:00
Marcelo Santos
2a58cf09c5 Fix formatting and add video to the instructions 2016-03-24 13:44:42 +00:00
Marcelo Santos
9b3f17da61 Add sound troubleshooting instructions for debian-based distros 2016-03-24 13:25:46 +00:00
Philipp Hansch
a0e32753a5 Forgot a possible race condition 2016-03-24 12:20:08 +01:00
Philipp Hansch
624aa9b41d Try to fix possible race conditions 2016-03-24 11:40:10 +01:00
Philipp Hansch
7e55eee1b9 Set background-tabs to false for rest of the tests
Because it is set to true in a previous test and it is better to avoid
shared state in tests. Especially, if we want to randomize tests later
on.
2016-03-24 10:20:21 +01:00
Philipp Hansch
38bda67adc Add background-tabs and new-tab-position tests
Using hints to select and open the link.
Not sure if there are better ways.

Issue-Link: https://github.com/The-Compiler/qutebrowser/issues/999
2016-03-24 10:09:19 +01:00
Florian Bruhin
cd5cb2f50d Improve check_coverage.py output on failure 2016-03-24 06:51:22 +01:00
Florian Bruhin
504332cd6e Add a crowdfunding link to the README for GitHub 2016-03-23 18:10:19 +01:00
Florian Bruhin
bc20b7c313 Add crowdfunding banner to website 2016-03-23 11:20:39 +01:00
Florian Bruhin
20799f9740 tox: Update astroid/pylint to 1.4.5/1.5.5
astroid
-------

2016-03-21 -- 1.4.5

    * decoratornames() does not leak InferenceError anymore.

    * wildcard_imported_names() got replaced by _public_names()

      Our understanding of wildcard imports through __all__ was
      half baked to say at least, since we couldn't account for
      modifications of the list, which results in tons of false positives.
      Instead, we replaced it with _public_names(), a method which returns
      all the names that are publicly available in a module, that is that
      don't start with an underscore, even though this means that there
      is a possibility for other names to be leaked out even though
      they are not present in the __all__ variable.

      The method is private in 1.4.X.

pylint
------

2016-03-21 -- 1.5.5

    * Let visit_importfrom from Python 3 porting checker be called when everything is disabled

      Because the visit method was filtering the patterns it was expecting to be activated,
      it didn't run when everything but one pattern was disabled, leading to spurious false
      positives

    * Don't emit unsubscriptable-value for classes with unknown
      base classes.

    * Use an OrderedDict for storing the configuration elements

      This fixes an issue related to impredictible order of the disable / enable
      elements from a config file. In certain cases, the disable was coming before
      the enable which resulted in classes of errors to be enabled, even though the intention
      was to disable them. The best example for this was in the context of running multiple
      processes, each one of it having different enables / disables that affected the output.

    * Don't consider bare and broad except handlers as ignoring NameError,
      AttributeError and similar exceptions, in the context of checkers for
      these issues.
2016-03-21 21:05:01 +01:00
Florian Bruhin
456aa8bc97 Merge branch 'phansch-netscape-bookmarks-import' 2016-03-21 12:57:05 +01:00
Florian Bruhin
2d152fd036 Regenerate authors. 2016-03-21 12:56:55 +01:00
Philipp Hansch
a50363ca67 Fix flake8 issues 2016-03-20 13:02:04 +01:00
Philipp Hansch
573660f36d Fix lint issue 2016-03-20 12:08:48 +01:00
Philipp Hansch
8000af1664 Generalize bookmarks import
This change adds `firefox` and `ie` as possible arguments to the importer
script.
2016-03-20 10:49:33 +01:00
Florian Bruhin
93e0f29254 travis: Allow OS X to fail for now 2016-03-19 10:58:16 +01:00
Florian Bruhin
fdce4e9692 tox: Update pytest-bdd to 2.16.1
- Cleaned up hooks of the plugin
- Fixed report serialization
2016-03-19 10:41:36 +01:00
Florian Bruhin
4c8f84f97d tox: Update to pytest 2.9.1
- Improve error message when a plugin fails to load.
- pytest.fail with non-ascii characters raises an internal pytest error.
- junit parses report.nodeid incorrectly, when params IDs contain ::.
- SyntaxErrors containing non-ascii lines at the point of failure generated an
  internal py.test error.
- When passing in a bytestring regex pattern to parameterize attempt to decode
  it as utf-8 ignoring errors.
- parametrized test nodes cannot be specified to run on the command line.
2016-03-18 22:41:42 +01:00
Florian Bruhin
e72e7dbf5f Update changelog 2016-03-18 06:35:52 +01:00
Florian Bruhin
72e081b8da Regenerate authors. 2016-03-18 06:18:33 +01:00
Florian Bruhin
a932183909 Merge branch 'master' of https://github.com/haxwithaxe/qutebrowser into haxwithaxe-master 2016-03-18 06:17:54 +01:00
haxwithaxe
eed13467f3 allow {0} in search engine specification strings to allow multiple instances of the search term in the url 2016-03-17 20:38:05 -04:00
Florian Bruhin
74706abbc1 Fix lint 2016-03-17 22:10:58 +01:00
Florian Bruhin
05bb435687 Merge branch 't-wissmann-password_fill' 2016-03-17 22:05:31 +01:00
Florian Bruhin
0944293fdd Merge branch 'password_fill' of https://github.com/t-wissmann/qutebrowser into t-wissmann-password_fill 2016-03-17 22:05:13 +01:00
Florian Bruhin
d8c999aa73 Merge branch 'EliteTK-editor_crash_behaviour' 2016-03-17 21:41:35 +01:00
Florian Bruhin
0830b400fe Merge branch 'editor_crash_behaviour' of https://github.com/EliteTK/qutebrowser into EliteTK-editor_crash_behaviour 2016-03-17 21:40:17 +01:00
Florian Bruhin
20cc17b5a7 Merge branch 'hcraT-multi_url_heuristic' 2016-03-17 21:36:52 +01:00
Florian Bruhin
99fadacda6 Merge branch 'multi_url_heuristic' of https://github.com/hcraT/qutebrowser into hcraT-multi_url_heuristic 2016-03-17 21:28:40 +01:00
Florian Bruhin
dad26cc395 Fix line length 2016-03-16 19:43:18 +01:00
Florian Bruhin
0336048781 Merge branch 'NoctuaNivalis-fix/hints-auto-follow' 2016-03-16 18:17:43 +01:00
Florian Bruhin
91415105f3 Regenerate docs. 2016-03-16 18:17:32 +01:00
Florian Bruhin
a52334333b Merge branch 'fix/hints-auto-follow' of https://github.com/NoctuaNivalis/qutebrowser into NoctuaNivalis-fix/hints-auto-follow 2016-03-16 18:17:08 +01:00
Florian Bruhin
abfadb5631 Fix asciidoc2html --no-authors 2016-03-16 07:35:12 +01:00
Florian Bruhin
ee4fa6c118 travis: Use prebuilt docker images 2016-03-16 07:23:17 +01:00
Florian Bruhin
b76886d2ff Ignore --no-authors in asciidoc2html.py
This makes it possible to run "tox -e docs -- --no-args" with {posargs} passed
to both src2asciidoc.py and asciidoc2html.py.
2016-03-16 07:11:40 +01:00
Florian Bruhin
a2b9749dbf docker: Don't install base-devel on Arch 2016-03-16 06:57:44 +01:00
Florian Bruhin
bb2847fee9 Fix argument passing to Travis 2016-03-16 06:52:06 +01:00
Florian Bruhin
0eb12b8fa0 Fix spelling 2016-03-16 06:23:39 +01:00
Florian Bruhin
236572e0f5 Check docs on Travis, take two
We don't regenerate the authors there, as that doesn't work due to Travis
cloning with --depth=50
2016-03-16 06:22:36 +01:00
Florian Bruhin
172611a1b9 Revert "Revert "Check docs on Travis""
This reverts commit cc6d2ddc1d.
2016-03-16 06:19:33 +01:00
Florian Bruhin
cc6d2ddc1d Revert "Check docs on Travis"
This reverts commit f1ec6e1e00.
--depth=50 on Travis messes up author generation
2016-03-15 23:22:19 +01:00
Florian Bruhin
f1ec6e1e00 Check docs on Travis 2016-03-15 22:46:49 +01:00
Florian Bruhin
07d31634c6 Add script to check for doc changes 2016-03-15 22:43:47 +01:00
Florian Bruhin
5ae9f0405d travis: Fine-tune IRC notifications 2016-03-15 22:32:53 +01:00
Florian Bruhin
543aa48e26 travis: Add IRC notifications 2016-03-15 21:42:48 +01:00
Florian Bruhin
0bc31e5373 docker: Also run on Ubuntu Wily on Travis 2016-03-15 21:39:30 +01:00
Florian Bruhin
b19da05097 flake8: Ignore "If is too complex" in ci/install.py 2016-03-15 21:38:17 +01:00
Florian Bruhin
bc6bf82301 docker: Minimize Debian Jessie image 2016-03-15 21:08:19 +01:00
Florian Bruhin
6d225a7858 Set DEBIAN_FRONTEND=noninteractive for Debian Dockerfile 2016-03-15 19:48:43 +01:00
Florian Bruhin
123de8783f ci/install.py fixup 2016-03-15 19:32:20 +01:00
Florian Bruhin
62db2c724f Try to run Docker on Travis 2016-03-15 19:25:01 +01:00
Florian Bruhin
cc94e7bfee Move ci_install.py to subdir 2016-03-15 19:20:28 +01:00
Florian Bruhin
bc080f047e Add Dockerfile for Archlinux 2016-03-15 19:16:11 +01:00
Florian Bruhin
241536dcdc travis: Use explicit matrix 2016-03-15 19:14:49 +01:00
Florian Bruhin
3ec7a01590 Add Dockerfile for Debian jessie 2016-03-15 19:14:37 +01:00
Florian Bruhin
ed3fd71e6f Force showing of label in test_elided_text
It seems the paintEvent of TextBase never got called since we switched to using
fake_statusbar, breaking the 100% coverage check.
2016-03-15 08:29:33 +01:00
Florian Bruhin
569e7b11fb Make test_elided_text work with non-unicode output
When Qt detects it can't output unicode (via the locale?), it elides using
"..." instead of the unicode char "…". Now the test works in both scenarios.
2016-03-15 07:19:43 +01:00
Florian Bruhin
97ddd674dd Use fake_statusbar for test_elided_text
See #1313
2016-03-15 07:14:39 +01:00
Florian Bruhin
60c293846f Un-deprecate :download-remove --all 2016-03-14 19:11:41 +01:00
Florian Bruhin
41b6f68fd7 bdd: Add some more tests for downloads 2016-03-14 19:06:42 +01:00
Florian Bruhin
06190a0488 bdd: Do better cleanup/separation for downloads 2016-03-14 19:06:16 +01:00
Florian Bruhin
ca7361a8a2 Update default font list in settings docs 2016-03-14 19:05:45 +01:00
Florian Bruhin
35731feeb5 Fix docs for :download-* commands 2016-03-14 19:05:36 +01:00
Florian Bruhin
25ee48d28b Add an --all flag to :download-cancel 2016-03-14 19:05:15 +01:00
Florian Bruhin
42a4c1ce4c Also test transform in test_configtypes_hypothesis
If validating works, we might as well also check if transforming does too.
2016-03-11 07:26:16 +01:00
Florian Bruhin
0c6d6367de Force qapp fixture for test_configtypes_hypothesis.
The test needs a QApplication
2016-03-11 07:17:11 +01:00
Florian Bruhin
8a0d89d940 tox: Update Mako to 1.0.4
[test] [feature] The default test runner is now py.test. Running “python
setup.py test” will make use of py.test instead of nose. nose still works as a
test runner as well, however.

[lexer] [bug] Major improvements to lexing of intricate Python sections which
may contain complex backslash sequences, as well as support for the bitwise
operator (e.g. pipe symbol) inside of expression sections distinct from the
Mako “filter” operator, provided the operator is enclosed within parentheses or
brackets. Pull request courtesy Daniel Martin.

[feature] Added new method Template.list_defs(). Pull request courtesy Jonathan
Vanasco.
2016-03-11 06:55:05 +01:00
Florian Bruhin
a94abb0858 tox: Update CherryPy to 5.1.0
* Bugfix for ``test_HTTP11_pipelining`` test in Python 3.5
* Bugfix regarding the keyword arguments support for Python 3 on the config
  file.
* Bugfix for ``test_2_KeyboardInterrupt`` test in Python 3.5.
  by monkey patching the HTTPRequest given a bug on CPython
  that is affecting the testsuite (https://bugs.python.org/issue23377).
* Add additional parameter ``raise_subcls`` to the tests helpers
  `openURL` and ``CPWebCase.getPage`` to have finer control on
  which exceptions can be raised.
* Add support for direct keywords on the calls (e.g. ``foo=bar``) on
  the config file under Python 3.
* Add additional validation to determine if the process is running
  as a daemon on ``cherrypy.process.plugins.SignalHandler`` to allow
  the execution of the testsuite under CI tools.
2016-03-11 06:53:52 +01:00
Florian Bruhin
b509bc330f Remove unnecessary cmdline args on CI 2016-03-10 20:41:55 +01:00
Florian Bruhin
2fb186efcd Fix UnboundLocalError in :unbind 2016-03-10 20:27:03 +01:00
Florian Bruhin
119f01bd5f tox: Add {posargs} to pylint envs 2016-03-10 20:11:15 +01:00
Florian Bruhin
82b52d8799 tox: Rename pylint-tip to pylint-master 2016-03-10 20:11:15 +01:00
Florian Bruhin
c681d6203f tox: Add missing requests dependency for pylint-tip 2016-03-10 20:11:15 +01:00
Florian Bruhin
146c44b351 tox: Update pylint-tip repo to github 2016-03-10 20:11:15 +01:00
Florian Bruhin
88e4102ae1 Move Liberation Mono after Courier as default font
Before, in fonts -> _monospace we preferred Liberation Mono to Courier and
Courier New. Unfortunately, that font looks horrible on Windows if it's
installed, so let's avoid using it if possible.

On Linux, hopefully Courier New/Courier isn't available, and Liberation Mono
will get picked up instead (or one of the other alternatives).
2016-03-09 10:12:39 +01:00
Florian Bruhin
bb5c483b7a requirements: Update colorama to 0.3.7
* check if stream has 'closed' attribute before testing it
* objects might become None at exit
2016-03-08 17:41:40 +01:00
Florian Bruhin
0c3eb7a31c Specify valid loglevels for --loglevel/-l 2016-03-08 17:38:26 +01:00
Florian Bruhin
e32e2000bf Merge branch 'Kingdread-xdg-download-dir-fix' 2016-03-08 07:14:08 +01:00
Florian Bruhin
18b6d7ea50 Merge branch 'xdg-download-dir-fix' of https://github.com/Kingdread/qutebrowser into Kingdread-xdg-download-dir-fix 2016-03-08 07:13:03 +01:00
Florian Bruhin
4eac8bae76 Merge branch 'torsava-pull-request-1' 2016-03-07 20:25:13 +01:00
Florian Bruhin
4189d6e327 Regenerate authors. 2016-03-07 20:25:06 +01:00
Florian Bruhin
0bef594902 Remove manual install for Fedora 2016-03-07 20:24:58 +01:00
Florian Bruhin
abb8d850c2 Merge branch 'pull-request-1' of https://github.com/torsava/qutebrowser into torsava-pull-request-1 2016-03-07 20:24:18 +01:00
Florian Bruhin
c28dbe84f7 tox: Update pyroma to 2.0.2
- Faked the __name__ variable to allow you to have a "if __name__" construct
  in the setup.py.
- Fixed a bug under Python 3 with certain imports.
2016-03-06 16:45:41 +01:00
Florian Bruhin
3a76df3fd0 tox: Update hypothesis to 3.1.0
- Add a 'nothing' strategy that never successfully generates values.
- sampled_from() and one_of() can both now be called with an empty argument
  list, in which case they also never generate any values.
- one_of may now be called with a single argument that is a collection of
  strategies as well as as varargs.
- Add a 'runner' strategy which returns the instance of the current test object
  if there is one.
- 'Bundle' for RuleBasedStateMachine is now a normal(ish) strategy and can be
  used as such.
- Tests using RuleBasedStateMachine should now shrink significantly better.
- Hypothesis now uses a pretty-printing library internally, compatible with
  IPython's pretty printing protocol (actually using the same code). This may
  improve the quality of output in some cases.
- As a 'phases' setting that allows more fine grained control over which parts
  of the process Hypothesis runs
- Add a suppress_health_check setting which allows you to turn off specific
  health checks in a fine grained manner.
- Fix a bug where lists of non fixed size would always draw one more element
  than they included. This mostly didn't matter, but if would cause problems
  with empty strategies or ones with side effects.
- Add a mechanism to the Django model generator to allow you to explicitly
  request the default value (thanks to Jeremy Thurgood for this one).
2016-03-06 16:43:42 +01:00
Florian Bruhin
38c17af191 tox: Update flake8-pep3101 to 0.3
- Allow stdin processing, this way text editor can pass input to flake8.
2016-03-06 16:42:52 +01:00
Florian Bruhin
69b160d9d4 requirements: Update Pygments to 2.1.3 2016-03-06 16:41:39 +01:00
Florian Bruhin
7e3337a901 tox: Update pyflakes to 1.1.0 2016-03-02 08:18:37 +01:00
Florian Bruhin
5d87770513 tests: Allow XPASS for test_installed_package
We need to use strict=False here as test_installed_package can XPASS when
running frozen tests.
2016-03-02 08:09:04 +01:00
Florian Bruhin
38ac95d907 Revert "pytest.ini: Remove registration of flaky marker"
This reverts commit 0f5b4d58e2.

Seems this is needed when freezing, otherwise we get a "'flaky' not a
registered marker" error despite the plugin being installed.

Conflicts:
	pytest.ini
2016-03-02 08:05:15 +01:00
Florian Bruhin
43a4a6a3e7 Add pkg_resources._vendor.pyparsing when freezing.
This is similar to 85299d293f.
2016-03-02 08:01:47 +01:00
Florian Bruhin
d799970f65 requirements: Update pygments to 2.1.1
- Fixed Jython compatibility
- Fixed HTML formatter output with leading empty lines
- Added a mapping table for LaTeX encodings and added utf8
- Fixed image formatter font searching on Macs
- Fixed deepcopy-ing of Token instances
- Fixed Julia string interpolation
- Fixed statefulness of HttpLexer between get_tokens calls
- Many smaller fixes to various lexers
2016-03-02 07:29:41 +01:00
Florian Bruhin
4314d6420b pytest: Don't show skipped test summaries by default 2016-03-02 07:27:25 +01:00
Florian Bruhin
9efae021fa Set xfail_strict=true for pytest 2016-03-02 07:14:50 +01:00
Florian Bruhin
d1ec64cab1 Remove skip marker as it's builtin in pytest now 2016-03-02 07:14:06 +01:00
Florian Bruhin
1169d5ac52 Reduce pytest output on CI.
We don't need -v anymore as pytest 2.9 will display full diffs either way.
2016-03-02 07:12:47 +01:00
Florian Bruhin
531f4a85ff tox: Update pytest to 2.9.0.
New Features

- New pytest.mark.skip mark, which unconditionally skips marked tests.
- --doctest-glob may now be passed multiple times in the command-line.
- New -rp and -rP reporting options give the summary and full output of passing
  tests, respectively.
- pytest.mark.xfail now has a strict option which makes XPASS tests to fail the
  test suite, defaulting to False. There’s also a xfail_strict ini option that
  can be used to configure it project-wise.
- Parser.addini now supports options of type bool.
- New ALLOW_BYTES doctest option strips b prefixes from byte strings in doctest
  output (similar to ALLOW_UNICODE).
- give a hint on KeyboardInterrupt to use the –fulltrace option to show the
  errors
- catch IndexError exceptions when getting exception source location. This
  fixes pytest internal error for dynamically generated code (fixtures and
  tests) where source lines are fake by intention

Changes

- Important: py.code has been merged into the pytest repository as
  pytest._code. This decision was made because py.code had very few uses
  outside pytest and the fact that it was in a different repository made it
  difficult to fix bugs on its code in a timely manner. The team hopes with
  this to be able to better refactor out and improve that code. This change
  shouldn’t affect users, but it is useful to let users aware if they encounter
  any strange behavior.

  Keep in mind that the code for pytest._code is private and experimental, so
  you definitely should not import it explicitly!

  Please note that the original py.code is still available in pylib.

- pytest_enter_pdb now optionally receives the pytest config object.

- Removed code and documentation for Python 2.5 or lower versions, including
  removal of the obsolete _pytest.assertion.oldinterpret module.

- Comparisons now always show up in full when CI or BUILD_NUMBER is found in
  the environment, even when -vv isn’t used.

- --lf and --ff now support long names: --last-failed and --failed-first
  respectively.

- Added expected exceptions to pytest.raises fail message

- Collection only displays progress (“collecting X items”) when in a terminal.
  This avoids cluttering the output when using --color=yes to obtain colors in
  CI integrations systems

Bug Fixes

- The -s and -c options should now work under xdist; Config.fromdictargs now
  represents its input much more faithfully.
- support Python 3.5’s @ operator in assertion rewriting.
- Fix formatting utf-8 explanation messages.
- Fix traceback style docs to describe all of the available options
  (auto/long/short/line/native/no), with auto being the default since v2.6.
- junit record_xml_property doesn’t allow multiple records with same name.
2016-03-02 07:08:04 +01:00
Tomas Orsava
ffe289b410 Updated installation instructions for Fedora. 2016-02-29 17:55:09 +01:00
Florian Bruhin
2542f114ad tox: Update pyroma to 2.0.0
- Big rewrite of how data is extracted from Distutils/Setuptools.
2016-02-29 06:47:33 +01:00
Tarcisio Fedrizzi
9286fadeee Adds wait to paste multiline text test 2016-02-29 00:39:37 +01:00
Tarcisio Fedrizzi
8f593d948c Fixing flake8 error 2016-02-28 23:56:23 +01:00
Tarcisio Fedrizzi
25bc2dc1db Changes formatters to print multiline text on one line 2016-02-28 23:45:02 +01:00
Tarcisio Fedrizzi
a9fdf09a04 Adds test of the heuristic 2016-02-28 23:44:26 +01:00
Tarcisio Fedrizzi
89ac5cba62 Adds test to reach 100% coverage on urlutils 2016-02-28 23:43:38 +01:00
Tarcisio Fedrizzi
d8ad0a14af Fixes wrong documentation 2016-02-28 23:42:14 +01:00
Tarcisio Fedrizzi
0ab44c4f4a Reformats code as requested 2016-02-28 23:41:20 +01:00
Florian Bruhin
c6c4762be1 Merge branch 'Kingdread-data-link-fix' 2016-02-28 15:27:12 +01:00
Florian Bruhin
5395e0f6e2 tests: Use a fresh instance as a workaround
Waiting seems like a perfect recipe for another flaky test, so let's better be
safe.
2016-02-28 15:26:18 +01:00
Florian Bruhin
108d0c8763 tox: Update flake8-deprecated to 1.0.
- Warn if using xmlconfig.file, self.loadZCML is the preferred option.
- Avoid false reports by suffixing an opening parenthesis on all methods.
- Add decorators from zope.interface and zope.component.

Due to the bugfix we can also remove the D001 suppression.
2016-02-28 14:47:24 +01:00
Tarcisio Fedrizzi
79ad65ee64 Fixes flake8 errors 2016-02-27 12:36:13 +01:00
Tarcisio Fedrizzi
67ebdc6eb6 Fixes the position of the logging line 2016-02-27 11:54:23 +01:00
Tarcisio Fedrizzi
702b235981 Fixes formatting to make pylint happy. 2016-02-27 11:54:23 +01:00
Tarcisio Fedrizzi
006d8760c4 Adds path checking to the multiline url heuristic 2016-02-27 11:54:23 +01:00
Tarcisio Fedrizzi
4500bc24d4 fuzzy_url uses path check function 2016-02-27 11:54:23 +01:00
Tarcisio Fedrizzi
594b0d2910 Refactors path validity check to its own function 2016-02-27 11:54:23 +01:00
Tarcisio Fedrizzi
4aa7649c0a Implemented heurisitc on multiline paste 2016-02-27 11:54:23 +01:00
Florian Bruhin
c156f53eba Merge branch 'data-link-fix' of https://github.com/Kingdread/qutebrowser into Kingdread-data-link-fix 2016-02-27 03:01:19 +01:00
Florian Bruhin
48f87d1656 Revert "Use pytest-platform-markers"
This reverts commit 2e12fb3c65.

It seems like it's currently broken...
2016-02-27 02:45:34 +01:00
Florian Bruhin
a4687c6745 Fix lint 2016-02-27 02:41:01 +01:00
Florian Bruhin
0f5b4d58e2 pytest.ini: Remove registration of flaky marker
It's already registered by the plugin.
2016-02-27 02:40:30 +01:00
Florian Bruhin
fab86cce5e tox: Update pytest-xvfb to 0.2.0
- The ``no_xvfb``-marker is now registered automatically so pytest doesn't fail
  when run with ``--strict``.
- The ``xvfb`` fixture is now session-scoped.
2016-02-27 02:25:08 +01:00
Florian Bruhin
83e86706ff tests: Make check for ddg being loaded less strict
Before this change, adding a new logging message involving logging e.g. the
default duckduckgo setting value failed.

Now we basically use a black- instead of a whitelist and only fail if we get a
load status message for duckduckgo.
2016-02-27 02:16:42 +01:00
Florian Bruhin
2e12fb3c65 Use pytest-platform-markers 2016-02-27 00:26:24 +01:00
Florian Bruhin
10f9ac6c27 tox: Update hypothesis to 3.0.5
- Fix a bug where Hypothesis would now error on py.test development versions.
2016-02-25 21:12:47 +01:00
Florian Bruhin
7c90f8900c tox: Update pytest-mock to 0.11.0.
- PropertyMock is now accessible from mocker.
- Fix regression using one of the assert_* methods in patched functions which
  receive a parameter named method.
2016-02-24 20:15:10 +01:00
Florian Bruhin
8c6c976afc tox: Update pytest-html to 1.8.0.
- Remove duplication from the environment section
- Dropped support for Python 3.2
- Indicated setup and teardown in report
- Fixed colour of errors in report
2016-02-24 20:14:14 +01:00
Florian Bruhin
2dfce20602 tox: Update hypothesis to 3.0.4.
- Fix version parsing of py.test to work with py.test release candidates
- More general handling of the health check problem where things could fail
  because of a cache miss - now one "free" example is generated before the start
  of the health check run.
- Fix a bug where Hypothesis would error when running on Python 2.7.3 or earlier
  because it was trying to pass a bytearray object to struct.unpack (which is
  only supported since 2.7.4).
2016-02-24 20:11:40 +01:00
Daniel Schadt
20daf1f86e fix lint 2016-02-23 14:33:10 +01:00
Florian Bruhin
0df4da5b91 Also display XDG_* in crash reports 2016-02-23 08:47:53 +01:00
Daniel Schadt
e5dc10a29e downloads: handle relative XDG_DOWNLOAD_DIR
Issues #1269, #866

qutebrowser would crash when XDG_DOWNLOAD_DIR was set to some
non-absolute value (which should not happen, but it can) and
"storage -> download-dir" was empty, since when the user didn't give an
absolute filename, even the joined path of download_dir() (i.e.
XDG_DOWNLOAD_DIR in this case) and the filename was not absolute either.

Since the path was not absolute, create_full_filename returned None,
which meant that os.path.basename(self._filename) raised an exception.

Now we display an error message and fall back to $HOME.
2016-02-22 23:43:09 +01:00
Daniel Schadt
a382b366bc tests: increase wait time
Otherwise the test might still fail on some systems
2016-02-22 21:46:54 +01:00
avk
c9bb6d0111 tests for browser.network.pastebin - code refactor 2016-02-22 20:46:22 +01:00
Daniel Schadt
a84c8ac247 tests: add workaround for QPainter bug
As suggested in the github discussion.
2016-02-22 17:39:34 +01:00
avk
90c8078225 More tests for browser.network.pastebin 2016-02-22 16:09:57 +01:00
avk
6826a97910 Tests for browser.network.pastebin 2016-02-22 15:10:39 +01:00
avk
7cc43d3954 Merge branch 'master' of https://github.com/The-Compiler/qutebrowser 2016-02-22 12:28:41 +01:00
Florian Bruhin
92ea15cc7a Merge branch 'NoctuaNivalis-fix/ellipses-on-fullscreen' 2016-02-22 11:50:50 +01:00
Florian Bruhin
609d9b9a25 Regenerate authors. 2016-02-22 11:50:38 +01:00
Florian Bruhin
3ff419f685 Merge branch 'fix/ellipses-on-fullscreen' of https://github.com/NoctuaNivalis/qutebrowser into NoctuaNivalis-fix/ellipses-on-fullscreen 2016-02-22 11:50:26 +01:00
Florian Bruhin
f64916b516 Only run geolocation tests on CI
Trying to get the device location while running the tests can trigger all kind
of funny effects.

Since we can't easily mock the GPS responses, we only run those on the CI where
we at least have some predictable setup.

Fixes #1297.
2016-02-21 17:24:33 +01:00
avk
033ac0bbad Merge branch 'master' of https://github.com/The-Compiler/qutebrowser 2016-02-19 22:13:39 +01:00
Florian Bruhin
513e4d5236 Switch to flake8-docstrings with pydocstyle
We used to use flake8-pep257 because docstrings claims no codes are ignorable
(which is wrong). However, that doesn't work with pydocstyle, so we had a
separate pydocstyle environment (and flake8-pep257 to check tests with relaxed
rules).

Now we only use flake8-docstrings + pydocstyle (which it switches to if it's
available, even though it still depends on pep257), and drop the pydocstyle tox
env.

As soon as flake8-docstrings is updated to drop the (unneeded) pep257
dependency, we can drop it as well.
2016-02-19 18:05:51 +01:00
avk
108f0e9073 Merge branch 'master' of https://github.com/The-Compiler/qutebrowser 2016-02-19 12:14:06 +01:00
Florian Bruhin
d0e79b2af7 Fix lint 2016-02-19 07:39:17 +01:00
Florian Bruhin
0b362e76ea Move pylint plugins to an installed package.
This means we can now run things like running pylint --version without having
to set PYTHONPATH correctly now.

When using skip_install=true, the plugins wouldn't work as they need to import
qutebrowser.

We have to keep setting PYTHONPATH in run_pylint_on_tests.py, otherwise we get
this error I don't quite understand:

    F:  1, 0: error while code parsing: Unable to load file
    '/home/florian/proj/qutebrowser/git/__init__.py' ([Errno 2] No such
    file or directory: '...') (parse-error)
2016-02-19 07:15:09 +01:00
Florian Bruhin
67b9904772 Include pytest-xvfb properly in frozen tests 2016-02-19 06:52:19 +01:00
Florian Bruhin
b201b65669 tests: Handle trailing / in wait_for_load_finished.
We actually already added that in 16ec035418, but
in 9a02dc174d we accidentally dropped it again.
2016-02-19 06:42:23 +01:00
Florian Bruhin
6a077f5d5a Fix lint. 2016-02-18 21:38:23 +01:00
Florian Bruhin
0c4a961505 tox: Upgrade hypothesis to 3.0.2.
(3.0.2: performance fix)

------------------
3.0.1 - 2016-02-18
------------------

* Fix a case where it was possible to trigger an "Unreachable" assertion when
  running certain flaky stateful tests.
* Improve shrinking of large stateful tests by eliminating a case where it was
  hard to delete early steps.
* Improve efficiency of drawing binary(min_size=n, max_size=n) significantly by
  provide a custom implementation for fixed size blocks that can bypass a lot
  of machinery.
* Set default home directory based on the current working directory at the
  point Hypothesis is imported, not whenever the function first happens to be
  called.

------------------
3.0.0 - 2016-02-17
------------------

Codename: This really should have been 2.1.

Externally this looks like a very small release. It has one small breaking change
that probably doesn't affect anyone at all (some behaviour that never really worked
correctly is now outright forbidden) but necessitated a major version bump and one
visible new feature.

Internally this is a complete rewrite. Almost nothing other than the public API is
the same.

New features:

* Addition of data() strategy which allows you to draw arbitrary data interactively
  within the test.
* New "exploded" database format which allows you to more easily check the example
  database into a source repository while supporting merging.
* Better management of how examples are saved in the database.
* Health checks will now raise as errors when they fail. It was too easy to have
  the warnings be swallowed entirely.

New limitations:

* choices and streaming strategies may no longer be used with find(). Neither may
  data() (this is the change that necessitated a major version bump).

Feature removal:

* The ForkingTestCase executor has gone away. It may return in some more working
  form at a later date.

Performance improvements:

* A new model which allows flatmap, composite strategies and stateful testing to
  perform *much* better. They should also be more reliable.
* Filtering may in some circumstances have improved significantly. This will
  help especially in cases where you have lots of values with individual filters
  on them, such as lists(x.filter(...)).
* Modest performance improvements to the general test runner by avoiding expensive
  operations

In general your tests should have got faster. If they've instead got significantly
slower, I'm interested in hearing about it.

Data distribution:

The data distribution should have changed significantly. This may uncover bugs the
previous version missed. It may also miss bugs the previous version could have
uncovered. Hypothesis is now producing less strongly correlated data than it used
to, but the correlations are extended over more of the structure.

Shrinking:

Shrinking quality should have improved. In particular Hypothesis can now perform
simultaneous shrinking of separate examples within a single test (previously it
was only able to do this for elements of a single collection). In some cases
performance will have improved, in some cases it will have got worse but generally
shouldn't have by much.
2016-02-18 20:46:15 +01:00
Florian Bruhin
36b0e304fc tests: Add first end-to-end test for hints.
This is based on HTML files with a global YAML comment, currently with "target"
as the only allowed key.

The tests then do this:

- Open a HTML file in data/hints/html
- Start hinting
- Make sure only one hint is visible
- Follow it, and make sure the page mentioned in "target:" is reached

Some ideas for the future:

- A "scroll" key, to scroll before hinting
- A "zoom" key, to zoom
- Multiple hints via a list
- Checking position of hints?
- A mode to manually check the pages (to check hint positions)
2016-02-18 20:46:15 +01:00
Florian Bruhin
9b1db7ec0b hints: Log the used hint chars
Useful for debugging and for end2end tests.
2016-02-18 20:46:15 +01:00
Florian Bruhin
9a02dc174d bdd: use quteproc.wait_for_load_finished.
Why duplicate that logic?
2016-02-18 20:46:15 +01:00
Daniel Schadt
007425cf16 downloads: fix filename for data: links
Issue #1214

Now uses a sensible filename for data: links instead of the whole base64
content. For PDF.js, it even uses the correct pdf filename.

TODO: Produces "QPainter:🔚 Painter ended with 2 saved states" while
running the tests here (Arch Linux):
CPython: 3.5.1
Qt: 5.5.1, runtime: 5.5.1
PyQt: 5.5.1
2016-02-18 16:17:35 +01:00
avk
50acf270d8 Merge branch 'master' of https://github.com/The-Compiler/qutebrowser 2016-02-17 08:17:17 +01:00
Florian Bruhin
504bf6eb3b Remove xvfbwrapper from freeze_tests.py. 2016-02-17 07:45:36 +01:00
Florian Bruhin
ae7cbb6dce Merge branch 'arsana7-master' 2016-02-17 07:10:22 +01:00
Florian Bruhin
7ba6752020 Regenerate authors. 2016-02-17 07:10:14 +01:00
Florian Bruhin
2b2331754d Combine launch/crash time into one section. 2016-02-17 07:10:01 +01:00
Florian Bruhin
36019c0cab Split long lines. 2016-02-17 07:04:25 +01:00
Florian Bruhin
116ab5429a Merge branch 'master' of https://github.com/arsana7/qutebrowser into arsana7-master 2016-02-17 07:03:17 +01:00
Florian Bruhin
5c617b861c Switch to pytest-xvfb. Fixes #1309. 2016-02-16 20:36:23 +01:00
Felix Van der Jeugt
c52e93e296 no ellipsis is inserted in big windows 2016-02-15 22:52:28 +01:00
Florian Bruhin
aad8dfc0ce Merge branch 'NoctuaNivalis-fix/#1308' 2016-02-15 22:08:50 +01:00
Florian Bruhin
9a18bc4ced Regenerate authors. 2016-02-15 22:08:42 +01:00
Florian Bruhin
aa579d76c9 Merge branch 'fix/#1308' of https://github.com/NoctuaNivalis/qutebrowser into NoctuaNivalis-fix/#1308 2016-02-15 22:08:33 +01:00
Felix Van der Jeugt
60c2b9c0b2 fixes #1308 2016-02-15 21:59:09 +01:00
Felix Van der Jeugt
b45db0f1dd let help text match reality 2016-02-15 14:38:11 +01:00
avk
cee017cc96 Merge branch 'master' of https://github.com/The-Compiler/qutebrowser 2016-02-15 08:45:30 +01:00
Florian Bruhin
ff779ef329 Update .eslintrc for eslint 2.0. 2016-02-15 07:52:51 +01:00
Florian Bruhin
74e168c339 Update Pygments test file. 2016-02-15 07:47:29 +01:00
Florian Bruhin
3aaa4395b8 tox: Update Werkzeug to 0.11.4.
- Fixed werkzeug.serving not working from -m flag.
- Fixed incorrect weak etag handling.
2016-02-15 07:08:31 +01:00
Florian Bruhin
f8cfdf0623 requirements: Update Pygments to 2.1.1.
- Fixed Jython compatibility
- Fixed HTML formatter output with leading empty lines
- Added a mapping table for LaTeX encodings and added utf8
- Fixed image formatter font searching on Macs
- Fixed deepcopy-ing of Token instances
- Fixed Julia string interpolation
- Fixed statefulness of HttpLexer between get_tokens calls
- Many smaller fixes to various lexers
2016-02-15 07:07:34 +01:00
avk
d551591b42 Added crash time to crash report 2016-02-12 11:59:45 +01:00
avk
53719366e0 Added time to standard log 2016-02-12 11:02:08 +01:00
Florian Bruhin
5c53cf0054 Merge branch 'flv0-contributing-toxhelp' 2016-02-12 06:43:31 +01:00
Florian Bruhin
0c0a624b5c Regenerate authors. 2016-02-12 06:43:22 +01:00
Florian Bruhin
07492db9fe Merge branch 'contributing-toxhelp' of https://github.com/flv0/qutebrowser into flv0-contributing-toxhelp 2016-02-12 06:43:10 +01:00
Florian Bruhin
8534010f02 tox: Update flake8 to 2.5.4.
Actually parse output_file and enable_extensions from config files.
2016-02-11 19:29:05 +01:00
Florian Bruhin
5b66d81f7d Include pstats for frozen tests. 2016-02-11 08:26:31 +01:00
Florian Bruhin
02f367a308 Add basic profiling capability for quteproc tests.
When --qute-profile-subprocs is given, we write a profile file for each
qutebrowser invocation and also create prof/combined.pstats afterwards.
2016-02-11 08:02:44 +01:00
Florian Bruhin
6d11e9ffd8 Fix lint. 2016-02-11 07:17:00 +01:00
Florian Bruhin
45935c86af Rewrite run_profile script.
There's now --profile-tool to select between various tools, a new
--profile-file option, and it uses argparse.
2016-02-11 06:48:16 +01:00
Patric Schmitz
e4c8bd98cd minor CONTRIBUTION fixes (utils renaming) 2016-02-10 23:01:50 +01:00
Patric Schmitz
c0cc3f3842 refining toxhelp PR. added a newline as well. 2016-02-10 22:12:48 +01:00
Florian Bruhin
5311576c34 Check pep257 via flake8.
We'll still keep the pydocstyle environment though until flake8-pep257 adds
support for that:

https://github.com/Robpol86/flake8-pep257/issues/6
2016-02-10 19:18:47 +01:00
Patric Schmitz
5878cd37fa add CONTRIBUTING to index and asciidoc2html.py 2016-02-10 18:37:46 +01:00
Patric Schmitz
c429991f88 update checkers list, add 'Running Specific Tests' 2016-02-10 18:37:07 +01:00
Florian Bruhin
7f791dfcb8 Remove now obsolete test. 2016-02-10 07:06:34 +01:00
Florian Bruhin
b6f1dd963d Handle Shift-Insert correctly in prompt mode.
Fixes #1299.
2016-02-10 06:40:54 +01:00
Florian Bruhin
d6267c30f6 tox: Update decorator to 4.0.9.
No changes.
2016-02-08 23:46:41 +01:00
Florian Bruhin
5ae677376b Rerun TestPyQIODevice.test_qprocess if needed.
This adds a new pytest-rerunfailures dependency. For some reason, that test
sometimes fails with an empty string read, and I can't tell why.
2016-02-08 06:54:47 +01:00
Daniel Schadt
ec4ba31b52 pdfjs: fix misplaced comma 2016-02-08 06:12:24 +01:00
Florian Bruhin
c332db4703 tox: Update decorator to 4.0.8.
Switched to a new changelog format (the one in http://keepachangelog.com/)
since it was contributed by Alexander Artemenko. Re-added a newline to support
old version of Python, as requested by azjps.
2016-02-07 17:57:39 +01:00
Florian Bruhin
66f52dbd86 tox: Update wheel to 0.29.0.
- Fix compression type of files in archive
2016-02-07 12:31:08 +01:00
Florian Bruhin
893284fea9 Merge branch 'Kingdread-pdfjs-fix' 2016-02-07 12:29:31 +01:00
Florian Bruhin
63968749d4 Update changelog. 2016-02-07 12:29:21 +01:00
Florian Bruhin
b3563fcee6 Merge branch 'pdfjs-fix' of https://github.com/Kingdread/qutebrowser into Kingdread-pdfjs-fix 2016-02-07 12:28:44 +01:00
Florian Bruhin
e3508cc37c tox: Filter decorator==4.0.7 for requirements.io.
See https://github.com/micheles/decorator/issues/25
2016-02-07 12:13:51 +01:00
Florian Bruhin
8f74734718 tox: Update cherrypy to 5.0.1.
* Removed deprecated support for ``ssl_certificate`` and
  ``ssl_private_key`` attributes and implicit construction
  of SSL adapter on Python 2 WSGI servers.
* Default SSL Adapter on Python 2 is the builtin SSL adapter,
  matching Python 3 behavior.
* In proxy tool, defer to Host header for resolving the base if no base is
  supplied.
2016-02-06 16:35:29 +01:00
Florian Bruhin
7ef368fc13 tox: Update wheel to 0.28.0.
- Fix file modes in archive
- Support forcing a platform tag using –plat-name on pure-Python wheels, as
  well as nonstandard platform tags on non-pure wheels
- Add SOABI tags to platform-specific wheels built for Python 2.X
- Support reproducible wheel files, wheels that can be rebuilt and will hash to
  the same values as previous builds
- Support for changes in keyring >= 8.0
- Use the file context manager when checking if dependency_links.txt is empty,
  fixes problems building wheels under PyPy on Windows
- Don’t attempt to (recursively) create a build directory ending with ..
  (invalid on all platforms, but code was only executed on Windows)
- Added the PyPA Code of Conduct
2016-02-06 16:33:37 +01:00
Daniel Schadt
9676eab592 qutescheme: call base __init__ in QuteSchemeError 2016-02-05 15:18:27 +01:00
Daniel Schadt
d02ec62e33 tests: fix tests for test_version
Broken since we changed pdfjs.PDFJSNotFound to have a parameter, which
was not given here.
2016-02-05 15:16:23 +01:00
Daniel Schadt
df8f87f8b6 tests: add tests for qutescheme 2016-02-05 15:14:23 +01:00
Florian Bruhin
1a42bae627 ci_install: Cleanup, improve messages.
This cleans up the whole script, and outputs nicer folded messages.
2016-02-05 09:24:39 +01:00
Florian Bruhin
41f82b2ad4 travis: Avoid using the default GCE mirror.
We patch sources.list to use the US loudbalancer instead of the hardcoded GCE
mirror which Travis uses by default - because that seems to be quite unstable.
2016-02-05 09:23:52 +01:00
Daniel Schadt
59c782f383 qutescheme: handle pdfjs failures more gracefully
Now the browser does not crash anymore if an invalid pdfjs resource is
requested, instead it will reply with a 404 error.
2016-02-05 01:43:56 +01:00
Daniel Schadt
804b4750ab pdfjs: use list of tuples instead of dictionary
Even though the dict seemed to be fine, this gives us a predictable
replacement order and helps with debugging in the future.
2016-02-04 21:18:15 +01:00
Daniel Schadt
da4f69cf72 pdfjs: throw PDFJSNotFound from None
Otherwise the stacktrace might be confusing since it will show the
FileNotFoundException as the causing error, which is not true (it just
happens to be the last checked place).

The .path attribute was added so that we still have the requested path
in the error log.

See #1280.
2016-02-04 21:11:20 +01:00
Florian Bruhin
83dc390808 tests: Move fixtures into a separate file. 2016-02-04 07:27:23 +01:00
Florian Bruhin
eb692ba7f6 Fix lint. 2016-02-04 07:13:27 +01:00
Florian Bruhin
774bcbf6b3 tests: Don't fail on teardown too if test failed.
When a end-to-end test failed which would've marked an error message as
expected later in the test, seeing the teardown message about an unexpected
error being logged is really confusing.
2016-02-04 06:43:14 +01:00
Florian Bruhin
43b6f18864 Whoops, don't use repr(json.dumps(...)) 2016-02-03 21:28:20 +01:00
Florian Bruhin
e5e1a0d95c Reject hints -> chars containing duplicate chars
Fixes #1286.
2016-02-03 21:05:35 +01:00
Florian Bruhin
0b491f6caf Use json.dumps for logged fake clipboard.
For some reason, when comparing the repr in the two processes, we get different
results on OS X and Windows:

- expected: "fünf"
- "f\xfcnf" coming back from the subprocess on OS X
- "fnf" on Windows

Instead we're comparing the json dump now, which should be more predictable.
2016-02-03 20:54:35 +01:00
Florian Bruhin
79f83a033d Add a fake clipboard for tests
There are a lot of problems and flakiness with using a real clipboard.

Instead we now have a :debug-set-fake-clipboard command to set a text, and use
logging when getting the contents.

Fixes #1285.
2016-02-03 20:27:11 +01:00
Florian Bruhin
7fe818f9c8 Revert "Delay :yank notification until message was yanked."
This reverts commit b79049261e.
2016-02-03 19:19:13 +01:00
Florian Bruhin
921e8b50b7 Fix lint. 2016-02-03 08:16:59 +01:00
Florian Bruhin
2ba2b38277 tests: Ignore new Qt warnings.
It seems since the recent QClipboard changes we get a new warning
"QXcbClipboard: Cannot transfer data, no data available" in some tests.

This ignores the warning, let's hope the tests still work.

See #1285.
2016-02-03 08:11:18 +01:00
Florian Bruhin
3292c05340 tests: Display some more qutebrowser logs w/o -v.
50 lines of context is almost useless, e.g. when an exception occurs we don't
even see the traceback.
2016-02-03 07:55:10 +01:00
Florian Bruhin
6008adcb9f bdd: xfail broken yankpaste tests for now.
Using the clipboard seems to be a good recipe for a lot of weird pain.
Until we avoid it altogether (see #1285) we xfail those problematic tests.
2016-02-03 07:49:45 +01:00
Florian Bruhin
302745e0fe tests: Also poll clipboard after setting it. 2016-02-03 07:44:41 +01:00
Florian Bruhin
a90618128d tests: Empty clipboard after testing if it works.
Otherwise, if a test fails to actually put something into the clipboard, we end
up pasting "Does this work?" which could e.g. trigger a search.

When it's cleared, we at least get some "clipboard is empty" error instead.
2016-02-03 06:55:21 +01:00
Florian Bruhin
af28996f82 tests: Fail if duckduckgo gets loaded accidentally
In the long run, we should detect any accidental external accesses using
mitmproxy, as per #1282. In the meantime, we try to detect duckduckgo requests
being logged and fail the tests if that happens.

However, a duckduckgo URL is logged in fuzzy_url during startup/config init,
which is why we ignore it there.
2016-02-03 06:50:48 +01:00
Daniel Schadt
1e52f459c9 mhtml: new complex test case
The-Compiler wants a more beautiful test case since the old one was
pretty weird and took lots of explaining at pytest demos, so I made a
new one. This one is a bit nicer on the eye and - to say it with
The-Compiler's words - has no "weird pixelated globe with the
geocities-like background".

To compensate for the globe I've put in some trivia facts so that - if
you are one of the people that like to stare at test pages - you can
always learn something.
2016-02-02 22:23:40 +01:00
Florian Bruhin
67efd1c5e0 Fix lint. 2016-02-02 19:23:24 +01:00
Florian Bruhin
cf0034d42c Set __tracebackhide__ in quteproc.after_test 2016-02-02 19:16:45 +01:00
Florian Bruhin
2636467ea7 Merge branch 'NoctuaNivalis-master' 2016-02-02 18:59:06 +01:00
Florian Bruhin
9d73c93ebe Update docs. 2016-02-02 18:59:00 +01:00
Florian Bruhin
65a4c71488 Merge branch 'master' of https://github.com/NoctuaNivalis/qutebrowser into NoctuaNivalis-master 2016-02-02 18:58:16 +01:00
Florian Bruhin
fec77b7c32 MANIFEST.in: Exclude qutebrowser/3rdparty.
We don't want external sources in our source releases, and check-manifest
complained about it.
2016-02-02 18:46:26 +01:00
Florian Bruhin
fdd763704f Regenerate authors. 2016-02-02 07:39:10 +01:00
Jimmy
42160335dc Improve performance when scrolling with many tabs.
Closes #1278.
2016-02-02 07:33:07 +01:00
Florian Bruhin
8166a4a76d Update changelog.
[ci skip]
2016-02-02 06:55:38 +01:00
Florian Bruhin
74a9f730da Merge branch 'Olical-relax-editor-templating' 2016-02-02 06:54:40 +01:00
Florian Bruhin
37bb26bdd5 Add a test in test_editor.py. 2016-02-02 06:53:12 +01:00
Florian Bruhin
bc012cbaed Regenerate authors. 2016-02-02 06:50:05 +01:00
Florian Bruhin
ad290e8702 Merge branch 'relax-editor-templating' of https://github.com/Olical/qutebrowser into Olical-relax-editor-templating 2016-02-02 06:49:57 +01:00
Florian Bruhin
8e0cb28fe4 Regenerate authors. 2016-02-02 06:41:38 +01:00
Florian Bruhin
7e584bb31d Merge branch 'master' of https://github.com/XRevan86/qutebrowser into XRevan86-master 2016-02-02 06:41:29 +01:00
Florian Bruhin
312daca2b0 fuzzy_url: Raise InvalidUrlError on empty URLs.
Before we raised QtValueError (via qtutils.ensure_valid), but maybe there are
more callers out there which call fuzzy_url with an empty input - and it makes
more sense to raise InvalidUrlError which gets displayed to the user than
raising QtValueError which is more like an assertion.
2016-02-02 06:38:48 +01:00
Florian Bruhin
14042403f6 Fix pasting of empty URLs. 2016-02-02 06:37:49 +01:00
Sorokin Alexei
04afcef239 Use system icon for windows if available 2016-02-02 00:48:07 +03:00
Oliver Caldwell
a617bc3ef4 Add missing commas
I haven't written Python in quite a long time :|
2016-02-01 21:41:14 +00:00
Oliver Caldwell
5474f902dd Add more tests for new editor config 2016-02-01 21:36:24 +00:00
Oliver Caldwell
a14f8a201e Merge remote-tracking branch 'TheCompiler/master' into relax-editor-templating 2016-02-01 21:19:50 +00:00
Florian Bruhin
2f9ec515db requirements: Update colorlog to 2.6.1. 2016-02-01 21:52:47 +01:00
Florian Bruhin
4103e7eba2 Revert "update_3rdparty: add docstring to main()"
This reverts commit 90e88ce0d0.
2016-02-01 20:09:17 +01:00
Florian Bruhin
7be296333a Merge branch 'pdfjs' of https://github.com/Kingdread/qutebrowser into Kingdread-pdfjs 2016-02-01 20:07:56 +01:00
Florian Bruhin
7a268a41f6 pylint: Don't require docstring for main() funcs. 2016-02-01 20:06:49 +01:00
Daniel Schadt
90e88ce0d0 update_3rdparty: add docstring to main() 2016-02-01 18:14:24 +01:00
Daniel Schadt
63f0171d30 update_3rdparty: add option for pdfjs version
This way we can instruct update_3rdparty to download a specific version
of pdfjs, e.g. to make debugging easier or to match the version of a
system package.

Syntax:
update_3rdparty.py -p 1.2.109
or
update_3rdparty.py --pdfjs=1.2.109

If the command line argument is not given, the script will automatically
download the latest release.
2016-02-01 17:46:16 +01:00
Daniel Schadt
449a54c7d0 pdfjs: add file path to version information
Shows "bundled" if the bundled version is used.
2016-02-01 17:28:18 +01:00
Daniel Schadt
6342febb44 pdfjs: Update documentation
The-Compiler made an AUR package for pdfjs so we should mention it in
the SYSTEM_PDFJS_PATHS, even though it uses the same path as the Debian
package.
2016-02-01 16:43:20 +01:00
Florian Bruhin
0e6c6d3750 Revert "ci_install: Pin virtualenv to 14.0.3 on Windows."
This reverts commit ec214f4897.
Fixed upstream in virtualenv 14.0.5.
2016-02-01 08:43:42 +01:00
Florian Bruhin
ec214f4897 ci_install: Pin virtualenv to 14.0.3 on Windows.
WORKAROUND for https://github.com/pypa/virtualenv/issues/858
2016-02-01 07:29:41 +01:00
Oliver Caldwell
4cd7d193f1 Simplify arg placeholder replacement 2016-01-31 22:56:11 +00:00
Oliver Caldwell
54ff2aa46c Merge remote-tracking branch 'TheCompiler/master' into relax-editor-templating 2016-01-31 22:43:58 +00:00
Oliver Caldwell
a9a42e0a99 Removed invalid placeholder test 2016-01-31 22:36:58 +00:00
Oliver Caldwell
84c44f3395 Remove invalid test parameter 2016-01-31 22:23:35 +00:00
Florian Bruhin
b4a54822a0 Merge branch 'lahwaacz-shift_ins' 2016-01-31 22:09:13 +01:00
Florian Bruhin
d50e1be566 Add some more :paste-primary tests. 2016-01-31 22:08:46 +01:00
Florian Bruhin
701cdc7f76 Update docs. 2016-01-31 20:57:56 +01:00
Florian Bruhin
af5d199e8f bdd: Simplify :paste-primary tests. 2016-01-31 20:56:37 +01:00
Florian Bruhin
44625b254c Merge branch 'shift_ins' of https://github.com/lahwaacz/qutebrowser into lahwaacz-shift_ins 2016-01-31 19:46:41 +01:00
Florian Bruhin
30f68e55d6 tox: Update xvfbwrapper to 0.2.8.
- better error handling when xvfb is not installed
- don't hardcode tmp dir location
- use terminate instead of kill so Xvfb can clean up lock files
2016-01-31 13:06:28 +01:00
Florian Bruhin
bf2adf19b2 tox: Update pytest-cov to 2.2.1.
- Fixed incorrect merging of coverage data when xdist was used and coverage was
  >= 4.0.
2016-01-30 23:39:55 +01:00
Florian Bruhin
c9deee0835 tox: Update flake8 to 2.5.2.
- Parse output_file and enable_extensions from config files
- Raise upper bound on mccabe plugin to allow for version 0.4.0
2016-01-30 23:39:55 +01:00
Florian Bruhin
67fd94b189 tox: Update check-manifest to 0.31.
- Drop Python 3.2 support.
- Ignore commented-out lines in MANIFEST.in.
2016-01-30 23:39:55 +01:00
Florian Bruhin
dc07f7ca9b Add a .pydocstylerc. 2016-01-30 23:39:55 +01:00
Florian Bruhin
39ca471685 tox: Switch from pep257 to pydocstyle.
Major Updates
-------------

The project was renamed to pydocstyle and the new release will be 1.0.0!

New Features
------------

- Added support for Python 3.5.
- Classes nested inside classes are no longer considered private. Nested
  classes are considered public if their names are not prepended with an
  underscore and if their parent class is public, recursively.
- Added the D403 error code - "First word of the first line should be properly
  capitalized". This new error is turned on by default.
- Added support for .pydocstylerc and as configuration file name.

Bug Fixes
---------

- Fixed an issue where a NameError was raised when parsing complex definitions
  of __all__.
- Fixed a bug where D202 was falsely reported when a function with just a
  docstring and no content was followed by a comment.
- Fixed wrong __all__ definition in main module.
- Fixed a bug where an AssertionError could occur when parsing __future__
  imports.
2016-01-30 23:23:21 +01:00
Jakub Klinkovský
cc8e7007b4 Fixed docstring formatting error 2016-01-30 14:13:41 +01:00
Jakub Klinkovský
5ec224d1f9 Simplified test for paste-primary command
We don't need to move around for this test...
2016-01-30 14:03:54 +01:00
Jakub Klinkovský
b358566156 Added tests for paste-primary command 2016-01-30 13:57:26 +01:00
Florian Bruhin
6af1cce45f tox: Update pytest-mock to 0.10.1.
- Fix regression in frozen tests due to distutils import dependency.
- Fix regression when using pytest-mock with pytest-2.7.X.
2016-01-28 06:22:00 +01:00
Florian Bruhin
b4972b3c08 tox: Update pytest-mock to 0.10.0.
pytest-mock now monkeypatches the mock library to improve pytest output
for failures of mock call assertions like Mock.assert_called_with().
2016-01-27 22:32:21 +01:00
Florian Bruhin
2b6d35b987 tox: Update mccabe to 0.4.0.
- Stop testing on Python 3.2
- Add support for async/await keywords on Python 3.5 from PEP 0492
2016-01-27 22:30:58 +01:00
Florian Bruhin
dcd62abe2b tox: Update httpbin to 0.4.1.
Added floating-point support for /delay endpoint
2016-01-27 22:20:07 +01:00
Jakub Klinkovský
db6a0d53ca Addressed code-quality remarks 2016-01-27 10:04:24 +01:00
Florian Bruhin
959e96f05a tox: Update ebb-lint to 0.4.4
- Read from stdin
- Strip trailing whitespace and \ before tokenizing.
- EOF bug?
2016-01-27 06:41:00 +01:00
Florian Bruhin
d74fb7ed88 www: Fix link from FAQ to stacktrace page.
See #1268.
2016-01-26 22:47:20 +01:00
Florian Bruhin
85adf7593d Fix crash when downloading URL without path infos.
Fixes #1243.
2016-01-26 22:39:10 +01:00
Florian Bruhin
ea1627c1e6 Cancel permission prompt when tab is closed.
Fixes #1250.
2016-01-26 19:47:31 +01:00
Oliver Caldwell
e9128ebb2a Relax editor templating
I tried to set my editor to `termite -e "vim -f {}"`, termite being a
pretty cool and light terminal I use within my i3wm Arch linux box.

So when I open my editor I want it to launch a terminal with Vim inside
instead of GVim for various reasons.

The validation rejected this at first because it was looking for '{}'
inside ['foo', 'bar', 'baz {}'], essentially. So I need it to look
inside the sub-strings, not just the list.

Then after validation I need to perform the '{}' replacement inside the
sub-string too, not just replacing the whole string.
2016-01-26 09:18:43 +00:00
Florian Bruhin
4d9ea06768 tests: Make test IDs predictable.
This means we could use xdist in the future.
2016-01-25 22:15:31 +01:00
Florian Bruhin
8e5014fc0f tox: Update pytest to 2.8.7.
- use predictable object resolution for monkeypatch

- allow for double nodeids in junitxml,
  this was a regression failing plugins combinations like pytest-pep8 +
  pytest-flakes

- Workaround for exception that occurs in pyreadline when using ``--pdb`` with
  standard I/O capture enabled.

- Better error message in case the target of a ``monkeypatch`` call raises an
  ``ImportError``.

- monkeypatch calls (setattr, setenv, etc.) are now O(1).

- captured stdout and stderr are now properly displayed before entering pdb
  when ``--pdb`` is used instead of being thrown away.

- pytest warnings emitted during ``pytest_terminal_summary`` are now properly
  displayed.

- fixed internal UnicodeDecodeError when doctests contain unicode.

- Add captured stdout to jUnit XML report on setup error.
2016-01-25 06:11:09 +01:00
Florian Bruhin
e9662b71f0 Move pytest arguments to pytest.ini.
Closes #1260.
2016-01-24 21:10:22 +01:00
Florian Bruhin
95fe54f010 Avoid running coverage when it's unneeded.
Unfortunately running coverage means our tests need more than a minute longer
to run.

We still run it in the following scenarios:
    - Full 'tox' run
    - On Travis CI on Linux
    - On the buildbot on Archlinux

But not anymore in the following scenarios:
    - When running 'tox -e py35' (or py34)
    - On Travis CI on OS X
    - On AppVeyor
    - On the buildbot except on Archlinux
2016-01-24 20:17:28 +01:00
Florian Bruhin
44a096012b tests: Ignore another Qt warning. 2016-01-24 19:34:00 +01:00
Florian Bruhin
aede904b3a bdd: Stabilize "Cloning to background tab" test.
I think this didn't actually wait until hello.txt was loaded because some logs
were parsed from the previous test:

http://www.qutebrowser.org/testresults/osx/1294.html
2016-01-24 19:17:39 +01:00
Florian Bruhin
785e2052f6 Ignore 'Method "GetAll"' Qt warning with escapes.
For some reason, since some time this message appears with those escapes in it.
2016-01-24 19:13:11 +01:00
Florian Bruhin
be2c0e30b6 bdd: Stabilize "Closing a JS window twice" test.
After pressing the button to open a window, we have to wait until it's loaded
before continuing, otherwise the test is flaky:
http://www.qutebrowser.org/testresults/osx/1295.html

We can't simply wait with "wait until about:blank is loaded" as that page is
already loaded earlier.
2016-01-24 18:47:26 +01:00
Florian Bruhin
90c34bce17 tox: Filter pytest 2.8.6 for requirements.io. 2016-01-24 18:32:24 +01:00
Florian Bruhin
d47a24cdf2 Merge branch 'mikeri-master' 2016-01-24 17:32:03 +01:00
Florian Bruhin
7dca8d7329 Fix lint. 2016-01-24 17:30:59 +01:00
Florian Bruhin
9eefb935c2 Update docs. 2016-01-24 17:02:11 +01:00
Florian Bruhin
86f03c7d81 Merge branch 'master' of https://github.com/mikeri/qutebrowser into mikeri-master 2016-01-24 17:01:35 +01:00
Florian Bruhin
f4e3b73c3e Merge branch 'rumpelsepp-patch-1' 2016-01-24 16:58:51 +01:00
Florian Bruhin
03a770ebe1 Regenerate authors. 2016-01-24 16:58:22 +01:00
Florian Bruhin
1144837e8a Merge branch 'patch-1' of https://github.com/rumpelsepp/qutebrowser into rumpelsepp-patch-1 2016-01-24 16:58:14 +01:00
Florian Bruhin
fd12aaef5f tox: Update pytest-catchlog to 1.2.2.
- Fix unicode vs str compatibility issues between Python2 and Python3.
2016-01-24 16:56:12 +01:00
Florian Bruhin
e6d9799c4b Revert "tox: Update pytest to 2.8.6."
This reverts commit cf0e13d51a.
See https://github.com/pytest-dev/pytest/issues/1338
2016-01-24 16:54:49 +01:00
Florian Bruhin
cf0e13d51a tox: Update pytest to 2.8.6.
- allow for double nodeids in junitxml,
  this was a regression failing plugins combinations like pytest-pep8 +
  pytest-flakes

- Workaround for exception that occurs in pyreadline when using ``--pdb`` with
  standard I/O capture enabled.

- Better error message in case the target of a ``monkeypatch`` call raises an
  ``ImportError``.

- monkeypatch calls (setattr, setenv, etc.) are now O(1).

- captured stdout and stderr are now properly displayed before entering pdb
  when ``--pdb`` is used instead of being thrown away.

- pytest warnings emitted during ``pytest_terminal_summary`` are now properly
  displayed.

- fixed internal UnicodeDecodeError when doctests contain unicode.

- Add captured stdout to jUnit XML report on setup error.
2016-01-24 01:02:14 +01:00
Florian Bruhin
85299d293f Add pkg_resources._vendor.packaging to freeze.py.
Workaround for https://bitbucket.org/anthony_tuininga/cx_freeze/issues/175/
Also see https://github.com/pyinstaller/pyinstaller/issues/1773

This hopefully fixes AppVeyor builds.
2016-01-24 00:30:26 +01:00
Stefan Tatschner
2f7b03c8e9 Update INSTALL.asciidoc
The Arch Linux section has been quite out of date:

* The AUR has a Git backend now, thus the links have been obsolete.
* python-pypeg2 is in [community]
* qutebrowser is in [community]
2016-01-22 20:11:12 +01:00
Florian Bruhin
c8408c6a5f Merge branch 'flake8'
See #1226.
2016-01-22 19:45:51 +01:00
Florian Bruhin
7fa0dc68bf flake8: Add flake8-pep3101 plugin.
Checks for old string formatting.
https://pypi.python.org/pypi/flake8-pep3101/
2016-01-22 19:40:10 +01:00
Florian Bruhin
a4a8c00e0f flake8: Ignore L302 (ebb-lint "line was too long") 2016-01-22 19:39:21 +01:00
Florian Bruhin
483d246e0d pylint: Allow long lines with # pylint: disable=... 2016-01-22 19:38:53 +01:00
Florian Bruhin
7945e632ba flake8: Add flake8-mock plugin. 2016-01-22 19:17:55 +01:00
Florian Bruhin
dbdbc1d8db flake8: Add flake8-deprecated plugin.
Warns about deprecated method calls.
https://pypi.python.org/pypi/flake8-deprecated/
2016-01-22 19:13:23 +01:00
Florian Bruhin
f74d1f26c7 flake8: Add flake8-string-format plugin.
string format checker, plugin for flake8
https://pypi.python.org/pypi/flake8-string-format/
2016-01-22 19:00:29 +01:00
Jakub Klinkovský
35e16a8e6e paste-primary: fix undo/redo not working
It seems that unlike Gecko, WebKit does not support undo/redo operations
when the textarea's `value` attribute is changed directly. Fortunately
there is a WebKit-specific workaround using textInput event.

References:
* http://stackoverflow.com/a/7554295
* http://help.dottoro.com/ljuecqgv.php
2016-01-22 18:18:17 +01:00
Florian Bruhin
8bdb1b6b14 flake8: Add flake8-copyright plugin.
Adds copyright checks to flake8
https://pypi.python.org/pypi/flake8-copyright/
2016-01-22 17:46:33 +01:00
Florian Bruhin
3a7ced5843 flake8: Add ebb-lint plugin.
lint for ensuring quality software
https://pypi.python.org/pypi/ebb-lint/
2016-01-22 17:33:58 +01:00
Florian Bruhin
58fb2826ee flake8: Add flake8-putty plugin.
Apply a bit of putty to flake8.
https://pypi.python.org/pypi/flake8-putty/
2016-01-22 17:33:58 +01:00
Florian Bruhin
fccde768ed flake8: Add pep8-naming plugin.
Check PEP-8 naming conventions, plugin for flake8
https://pypi.python.org/pypi/pep8-naming/
2016-01-22 17:33:58 +01:00
Florian Bruhin
7e3507aba1 flake8: Add flake8-debugger plugin.
flake8 debug statement checker
https://github.com/JBKahn/flake8-debugger
2016-01-22 17:33:58 +01:00
Florian Bruhin
289891a828 flake8: Check W503 (line break before binary op) 2016-01-22 17:33:58 +01:00
Florian Bruhin
526441bcae Fix new flake8 lint.
For some reason these issues weren't shown with pytest-pep8/flakes.
2016-01-22 17:33:58 +01:00
Florian Bruhin
1952e070fd Initial switch to flake8. 2016-01-22 17:33:58 +01:00
Florian Bruhin
d5d4e42c64 ci_install: Update Python3 for flake8 env. 2016-01-22 17:33:57 +01:00
Florian Bruhin
af0067526b ci_install: Show Python version. 2016-01-22 17:33:57 +01:00
Jakub Klinkovský
4d7e39470e Added paste-primary command
The Shift+Ins key should arguably insert primary selection, not the
clipboard selection as every Qt program does. This commit makes it
possible via the hidden paste-primary command (enabled by default).

Unfortunately QtWebKit does not provide any straightforward way to
insert text at cursor position into editable fields, so we work around
this by executing a JavaScript snippet - inspired by this SO answer:
http://stackoverflow.com/a/11077016
2016-01-21 22:30:43 +01:00
Michael Ilsaas
4ad2d63c8a Shortened urlincdec tests to one and some styling 2016-01-21 18:37:46 +01:00
Michael Ilsaas
1ecccc1133 Fix: decrement url test was set to increment. 2016-01-21 17:15:48 +01:00
Florian Bruhin
7f70964171 Update changelog. 2016-01-20 21:25:49 +01:00
Florian Bruhin
3c625790cc Don't crash if JS tab is closed twice.
Fixes #906.
2016-01-20 21:24:51 +01:00
Florian Bruhin
6bd092a948 tests: Skip custom_environment_no_system on Win.
Seems like it's broken on AppVeyor for some reason.
2016-01-20 20:34:19 +01:00
Florian Bruhin
90ab2a7b38 Merge branch 'tex-autocompletion_enhancement' 2016-01-20 20:07:05 +01:00
Florian Bruhin
80712caf50 Update docs. 2016-01-20 20:06:47 +01:00
Florian Bruhin
fc3c928326 Merge branch 'autocompletion_enhancement' of https://github.com/tex/qutebrowser into tex-autocompletion_enhancement 2016-01-20 20:04:53 +01:00
Florian Bruhin
4c64619263 tests: Fix configdir None tests for UserStyleSheet. 2016-01-20 19:55:34 +01:00
Michael Ilsaas
c33e9555a1 Tester for url increment/decrement with zeroes 2016-01-20 19:38:03 +01:00
Florian Bruhin
c02183652f Fix starting with -c "" and add test.
Fixes #1169.
2016-01-20 18:20:19 +01:00
Florian Bruhin
03118bd804 tests: Add a quteproc_new fixture.
This can be used to spawn a dedicated qutebrowser subprocess for a given test,
e.g. to test specific commandline arguments.
2016-01-20 18:19:29 +01:00
Florian Bruhin
039ae74662 tests: pass HOME to testprocess with custom env. 2016-01-20 18:19:05 +01:00
Florian Bruhin
10f3617b5e tests: Only pass DISPLAY if it exists in the env. 2016-01-20 08:51:15 +01:00
Florian Bruhin
037be96718 tests: Increase testprocess.start timeout on CI.
Under some circumstances, starting qutebrowser needs more than 30 seconds
there.
2016-01-20 08:49:25 +01:00
Florian Bruhin
a249d8d426 tests: Ignore another Qt warning by hypothesis. 2016-01-20 08:06:36 +01:00
Florian Bruhin
258855cf50 tests: Don't wait for testprocess if it quits. 2016-01-20 07:47:50 +01:00
Florian Bruhin
e944239ae8 tests: Simplify QuitPythonProcess. 2016-01-20 07:38:27 +01:00
Florian Bruhin
28258be599 tests: Add arg to set custom env for testprocess. 2016-01-20 07:34:56 +01:00
Florian Bruhin
d3f0c27a87 tests: Add testprocess.wait_for_quit.
This was in conftest.py before, but we might want to use it outside of that as
well.
2016-01-20 06:54:00 +01:00
Florian Bruhin
ef17c86586 tests: Allow custom args when starting testprocess. 2016-01-20 06:53:25 +01:00
Michael Ilsaas
d6cda0ed27 Include leading zeroes in URL increment/decrement 2016-01-19 21:37:49 +01:00
Felix Van der Jeugt
6d33e7843e should use the same keyword in config and code
hey this config check on startup is actually useful
2016-01-19 11:44:28 +01:00
Florian Bruhin
eb276df876 Handle empty term in urlutils._get_search_url.
Fixes #1239.
2016-01-19 07:03:43 +01:00
Florian Bruhin
041aa61508 Make :restart work with --temp-basedir.
Fixes #1244.
2016-01-19 06:51:36 +01:00
Florian Bruhin
a1eb26c042 tox: Don't install unneeded deps for tox -e mkvenv.
Fixes #1225.
2016-01-19 06:19:54 +01:00
Florian Bruhin
d9a58547b0 bdd: Add some more waiting to :undo tests. 2016-01-19 06:16:07 +01:00
Alexander Cogneau
cee1101f67 Fix install instructions for OSX 2016-01-18 23:54:50 +01:00
Florian Bruhin
faed088735 Wait until tabs are loaded for last-close tests. 2016-01-18 23:08:16 +01:00
Florian Bruhin
dfcd3087c2 Increase timeout for test_quteprocess_quitting. 2016-01-18 23:00:41 +01:00
Florian Bruhin
1892915146 bdd: Increase timeout for should_quit even more. 2016-01-18 22:13:24 +01:00
Florian Bruhin
8a757c8603 Release v0.5.1. 2016-01-18 22:12:52 +01:00
Felix Van der Jeugt
7ad871fab1 Merge remote-tracking branch 'source/master' 2016-01-18 21:45:47 +01:00
Florian Bruhin
9aa881faee Update changelog for v0.5.1. 2016-01-18 21:40:41 +01:00
Florian Bruhin
111f46adc5 bdd: Increase timeout for should_quit. 2016-01-18 08:11:38 +01:00
Florian Bruhin
9394f13a08 tests: Update hello.txt.html for pygments 2.1. 2016-01-18 08:11:38 +01:00
Florian Bruhin
3bf20c7c7b tests: Adjust check_contents comparison.
When doing the read() during the assert we'd get a weird pytest output which
doesn't make sense.
2016-01-18 08:11:35 +01:00
Florian Bruhin
31af303d07 tox: Update pep8 to 1.7.
We're now ready for #1226, but this only updates pep8 for now.

Changes:

* Reverted the fix, "options passed on command line are only ones accepted"
feature. This has many unintended consequences in pep8 and flake8 and needs to
be reworked when I have more time.
* Added support for Python 3.5.
* Added support for multi-line config_file option parsing.
* Improved parameter parsing.

Bugs:

* Fixed BytesWarning on Python 3.
2016-01-18 07:40:42 +01:00
Florian Bruhin
e79e01fc97 tox: Update pylint/astroid to 1.5.4/1.4.4.
pylint:

* Merge StringMethodChecker with StringFormatChecker. This fixes a
  bug where disabling all the messages and enabling only a handful of
  messages from the StringFormatChecker would have resulted in no
  messages at all.

* Don't apply unneeded-not over sets.

astroid:

* unpack_infer raises InferenceError if it can't operate
  with the given sequences of nodes.

* Support accessing properties with super().

* Enforce strong updates per frames.

  When looking up a name in a scope, Scope.lookup will return
  only the values which will be reachable after execution, as seen
  in the following code:

       a = 1
       a = 2

  In this case it doesn't make sense to return two values, but
  only the last one.
2016-01-18 07:38:34 +01:00
Florian Bruhin
eb6e0212ac requirements: Update Pygments to 2.1.
- Added lexers:
    - Emacs Lisp
    - Arduino
    - Modula-2 with multi-dialect support
    - Fortran fixed format
    - Archetype Definition language
    - Terraform
    - Jcl, Easytrieve
    - ParaSail
    - Boogie
    - Turtle
    - Fish Shell
    - Roboconf
    - Test Anything Protocol
    - Shen
    - Component Pascal
    - SuperCollider
    - Shell consoles (Tcsh, PowerShell, MSDOS)
    - Elm and J
    - Crmsh
    - Praat
    - CSound
    - Ezhil
    - Thrift
    - QVT Operational
    - Hexdump
    - CAmkES Configuration
    - Added styles:
    - Lovelace
    - Algol and Algol-nu
- Added formatters:
    - IRC
- True color (24-bit) terminal ANSI sequences (formatter alias: “16m”)
- New “filename” option for HTML formatter.
- Improved performance of the HTML formatter for long lines.
- Updated autopygmentize script.
- Fixed style inheritance for non-standard token types in HTML output.
- Added support for async/await to Python 3 lexer.
- Rewrote linenos option for TerminalFormatter (it’s better, but slightly
  different output than before).
- Javascript lexer now supports most of ES6.
- Cocoa builtins updated for iOS 8.1.
- Combined BashSessionLexer and ShellSessionLexer, new version should support
  the prompt styles of either.
- Added option to pygmentize to show a full traceback on exceptions.
- Fixed incomplete output on Windows and Python 3 (e.g. when using iPython
  Notebook).
- Allowed more traceback styles in Python console lexer.
- Added decorators to TypeScript.
- Fix highlighting of certain IRC logs formats.
2016-01-18 07:35:46 +01:00
Florian Bruhin
3864ae8aae bdd: Wait until page is loaded (last-close tests). 2016-01-18 07:33:17 +01:00
Florian Bruhin
c8538bdbb8 Fix config validation for String types.
Fixes #1231.
2016-01-18 07:29:15 +01:00
Florian Bruhin
f7784e641e bdd: Add some tests for tabs -> last-close. 2016-01-18 07:08:07 +01:00
Florian Bruhin
d6fafd474b pylint: Disable no-member for http.client.*
Seems like this is potentially the same issue as
https://github.com/PyCQA/pylint/issues/399, it also happens on the same
machines.
2016-01-17 21:27:24 +01:00
Florian Bruhin
0936ed4e61 Disable useless-suppression in webserver_sub_ssl.
Seems like this pylint bug doesn't happen on all systems...
2016-01-17 21:21:26 +01:00
Florian Bruhin
11dc51031d tests: Increase timeout for quteprocess_quitting. 2016-01-17 21:20:28 +01:00
Felix Van der Jeugt
cbb6e73b1f cleaner condition, less force 2016-01-17 21:06:36 +01:00
Florian Bruhin
9c5974c054 bdd: Add a "qutebrowser should quit" step. 2016-01-17 20:59:39 +01:00
Florian Bruhin
6e390bdc01 tests: Add a quteproc test for quitting. 2016-01-17 20:46:55 +01:00
Felix Van der Jeugt
beba5a3d6c limit smart hint length 2016-01-17 20:44:14 +01:00
Felix Van der Jeugt
9a889c6866 extended tests to cover new file argument 2016-01-17 20:38:33 +01:00
Florian Bruhin
6c5e158fc5 tests: Add a test for a quitting testprocess. 2016-01-17 20:19:41 +01:00
Florian Bruhin
dd211adf0f tests: Make sure testprocess raises if start fails. 2016-01-17 20:18:07 +01:00
Florian Bruhin
b2dbd8baef Merge branch 'Link-Satonaka-patch-1' 2016-01-15 07:53:11 +01:00
Florian Bruhin
fba78945a4 Regenerate authors. 2016-01-15 07:53:05 +01:00
Florian Bruhin
7780fde62f Use different headers. 2016-01-15 07:53:01 +01:00
Florian Bruhin
be903e0c2f Merge branch 'patch-1' of https://github.com/Link-Satonaka/qutebrowser into Link-Satonaka-patch-1 2016-01-15 07:50:23 +01:00
Florian Bruhin
79cf6fa095 Merge branch 'Evidlo-master' 2016-01-15 07:48:37 +01:00
Florian Bruhin
b859bde9dc Regenerate authors. 2016-01-15 07:42:56 +01:00
Florian Bruhin
f1c31233c8 Merge branch 'master' of https://github.com/Evidlo/qutebrowser into Evidlo-master 2016-01-15 07:42:47 +01:00
Florian Bruhin
6774894e9e tests: Check HTTP server status per path.
Stricter and simpler, ha! :)
2016-01-15 07:13:45 +01:00
Florian Bruhin
9d520b7312 Avoid trying to load .netrc if $HOME isn't set.
This logged an error on Windows:

ERROR    misc       networkmanager:on_authentication_required:269 Unable to read the netrc file
Traceback (most recent call last):
  File "c:\python34\Lib\netrc.py", line 27, in __init__
    file = os.path.join(os.environ['HOME'], ".netrc")
  File "C:\Users\florian\buildbot\slave\win8\build\.tox\py34\lib\os.py", line 633, in __getitem__
    raise KeyError(key) from None
KeyError: 'HOME'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\florian\buildbot\slave\win8\build\qutebrowser\browser\network\networkmanager.py", line 262, in on_authentication_required
    net = netrc.netrc()
  File "c:\python34\Lib\netrc.py", line 29, in __init__
    raise OSError("Could not find .netrc: $HOME is not set")

Since this case is pretty common, we don't want to log it - and checking the
variable beforehand is easier than parsing the exception message.

This should fix the failing tests on Windows.
2016-01-15 06:57:43 +01:00
Florian Bruhin
40721a2b6b bdd: Wait until basic-auth page is fully loaded.
This hopefully fixes this flakyness in
test_successful_webpage_authentification:

    tests/integration/features/test_prompts.py:129:
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    [...]
    tests/integration/features/conftest.py:381: in check_contents_json
	actual = json.loads(content)
    /usr/lib/python3.4/json/__init__.py:318: in loads
	return _default_decoder.decode(s)
    /usr/lib/python3.4/json/decoder.py:343: in decode
	obj, end = self.raw_decode(s, idx=_w(s, 0).end())
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    [...]
    >           raise ValueError(errmsg("Expecting value", s, err.value)) from None
    E           ValueError: Expecting value: line 1 column 1 (char 0)
2016-01-15 06:51:48 +01:00
Florian Bruhin
6420cdaa26 bdd: Open geolocation/notification page in new tab
This hopefully fixes this flaky error in test_notifications_with_ask__true on
OS X:

    Failed: Logged unexpected errors:

    LogLine('22:40:06 DEBUG    js         webpage:javaScriptConsoleMessage:531 [http://localhost:57758/data/prompt/notifications.html:28] [FAIL] unknown initial value for Notification.permission: denied')
    [...]
    testprocess.WaitForTimeout: Timed out after 15000ms waiting for {'message': 'Entering mode KeyMode.* (reason: question asked)'}.
2016-01-15 06:44:01 +01:00
evan
982ac5150d issue 1213: Display yanked link in statusbar
copied string format from `yank()` in `commands.py`
2016-01-14 19:17:12 -05:00
Florian Bruhin
5856b24d20 bdd: Compare HTTP status to a whitelist.
401 (authorization required) is not < 400, and it makes more sense to be strict
here anyways.
2016-01-14 22:34:26 +01:00
Florian Bruhin
cda6d7c06d bdd: Add test for webpage authentication. 2016-01-14 22:27:09 +01:00
Florian Bruhin
573654ece1 bdd: Add check_contents_json. 2016-01-14 22:27:00 +01:00
Florian Bruhin
c79f013050 bdd: Allow to load a page without waiting for it. 2016-01-14 22:26:42 +01:00
Florian Bruhin
23107a242b bdd: Ignore POSITION_UNAVAILABLE for geolocation. 2016-01-14 20:40:46 +01:00
Florian Bruhin
0b116729f7 bdd: Fix skipping tests from JS.
With the previous solution, we'd call pytest.skip on teardown only, which means
the rest of the test (e.g. because of a wait_for) could still fail.
2016-01-14 20:32:17 +01:00
Florian Bruhin
d4e2ece38b bdd: Ignore QGeoClue errors.
The geolocation tests emitted those errors on the Archlinux buildbot:

    QGeoclueMaster error creating GeoclueMasterClient.
    Geoclue error: Process org.freedesktop.Geoclue.Master exited with status 127

I don't really know what they mean, but let's see if the test passes now.
2016-01-14 19:06:36 +01:00
Florian Bruhin
b8a50dc475 bdd: Log error code on geolocation errors. 2016-01-14 19:04:48 +01:00
Florian Bruhin
e7a816c0c0 bdd: Skip geolocation tests if it's unavailable.
This should unbreak the build with older Qt versions.
2016-01-14 18:51:28 +01:00
Florian Bruhin
9c87eaf371 bdd: Allow to skip a test from JS.
This is a bit tricky since the test will actually run, but be marked as
skipped. The problem is we can't raise a pytest.skip.Exception during a test,
or it'll show up as an exception in a virtual Qt method.

Still this is better than nothing.
2016-01-14 18:50:36 +01:00
Florian Bruhin
14ff684e99 bdd: Add a xfail_norun marker. 2016-01-14 07:53:00 +01:00
Florian Bruhin
cf09e477a4 bdd: Add some tests for HTML5 notifications. 2016-01-14 07:49:39 +01:00
Florian Bruhin
1ddf817f4c bdd: Add some tests for geolocation. 2016-01-14 07:30:52 +01:00
Florian Bruhin
252dc5bf1b bdd: Add ability to fail tests from javascript. 2016-01-14 07:03:55 +01:00
Florian Bruhin
1d63e2dff4 bdd: Make "I wait for a prompt" step explicit. 2016-01-14 07:03:55 +01:00
Link
2e281a19d3 bullets 2016-01-13 17:51:21 -05:00
Link
082a910250 words 2016-01-13 17:50:02 -05:00
Link
4f5e59d6f8 Mention chocolatey and packagemanagement/onget 2016-01-13 17:19:51 -05:00
Florian Bruhin
abcb366c12 bdd: Add some more SSL tests. 2016-01-13 22:36:45 +01:00
Florian Bruhin
d0fda5467a bdd: Add a "I wait for a prompt" step. 2016-01-13 22:36:45 +01:00
Florian Bruhin
9c2a38938d bdd: Clear SSL errors before SSL test. 2016-01-13 22:36:45 +01:00
Florian Bruhin
0e631a2c11 bdd: Mark should_be_logged messages as expected. 2016-01-13 22:36:45 +01:00
Florian Bruhin
0203bb3ed5 Add a :debug-clear-ssl-errors command. 2016-01-13 21:05:48 +01:00
Florian Bruhin
2fbf218a0f bdd: Use textwrap.dedent. 2016-01-13 18:29:14 +01:00
Florian Bruhin
6014a963d4 Merge branch 'hcraT-master' 2016-01-13 18:22:15 +01:00
Florian Bruhin
f61b9fd42c Update docs. 2016-01-13 18:20:44 +01:00
Florian Bruhin
7ccc58bb68 Remove empty line. 2016-01-13 18:13:16 +01:00
Florian Bruhin
6c916d166d Merge branch 'master' of https://github.com/hcraT/qutebrowser into hcraT-master 2016-01-13 18:12:37 +01:00
Florian Bruhin
6b7f9fad9e Fix ssl-strict = ask.
This was introduced in b13f2aa6f0.
2016-01-13 15:54:25 +01:00
Florian Bruhin
b13f2aa6f0 Also deduplicate SSL errors with ssl-strict false.
Otherwise, on OS X we got the same SSL error logged twice as on_ssl_errors is
called twice. This means the tests only marked one as expected, and it failed
because of the other one.
2016-01-13 07:52:12 +01:00
Florian Bruhin
00f5b3cf74 Log debug information on SSL errors. 2016-01-13 07:52:12 +01:00
Florian Bruhin
e17a332400 Fix lint. 2016-01-13 07:01:31 +01:00
Florian Bruhin
0ca9cd361a Fix webserver_sub_ssl file header. 2016-01-13 00:00:55 +01:00
Florian Bruhin
f515165140 Add docstring. 2016-01-12 23:51:36 +01:00
Florian Bruhin
5f2ca88176 bdd: Don't test exact SSL error text.
Turns out those are platform specific.
2016-01-12 23:50:25 +01:00
Florian Bruhin
9479b65d25 bdd: Add first SSL test. 2016-01-12 23:35:48 +01:00
Florian Bruhin
8dd7f080f4 tests: Default to 5s timeout if not on CI. 2016-01-12 22:49:54 +01:00
Florian Bruhin
adbdfcbad3 tests: Add an SSL server subprocess. 2016-01-12 22:48:38 +01:00
Florian Bruhin
25dbf3731b tests: Split wait_for_load_finished from open_path. 2016-01-12 22:47:09 +01:00
Florian Bruhin
df03099468 Fix completion for String config type.
Since 2a705e2eb6 non-specialized config types are
String. However, String had an overloaded complete() which defaulted to
returning None.

Now we use the normal complete() which relies on valid_values if completions
isn't given instead.

Fixes #1223.
2016-01-12 18:53:53 +01:00
Tarcisio Fedrizzi
f813bc2415 Adds unit test to check that paths ending with newlines are handled
correctly
2016-01-12 11:27:11 +01:00
Tarcisio Fedrizzi
5917bbbe5c Fixes wrong indentation in multiline clipboard text 2016-01-12 11:25:14 +01:00
Tarcisio Fedrizzi
524341fd7a Use textwrap.dedent to parse multiline clipboard text 2016-01-12 11:24:31 +01:00
Tarcisio Fedrizzi
f08704e789 Adds function to insert multiple lines in the clipboard 2016-01-12 09:59:03 +01:00
Tarcisio Fedrizzi
4bbc1e2d8a Changes line as suggested in review 2016-01-12 09:58:08 +01:00
Florian Bruhin
22d255f49f bdd: Skip JS prompt() tests on PyQt < 5.3.1.
Those versions had a PyQt bug when overloading javaScriptPrompt, so we don't do
that there.
2016-01-12 09:04:03 +01:00
Florian Bruhin
df40b39e3e Work around pytest madness. 2016-01-12 08:20:08 +01:00
Florian Bruhin
df98312f42 tox: Update pylint to 1.5.3.
* Handle the import fallback idiom with regard to wrong-import-order.

* Decouple the displaying of reports from the displaying of messages

  Some reporters are aggregating the messages instead of displaying
  them when they are available. The actual displaying was conflatted
  in the generate_reports. Unfortunately this behaviour was flaky
  and in the case of the JSON reporter, the messages weren't shown
  at all if a file had syntax errors or if it was missing.
  In order to fix this, the aggregated messages can now be
  displayed with Reporter.display_message, while the reports are
  displayed with display_reports.

* Ignore function calls with variadic arguments without a context.

  Inferring variadic positional arguments and keyword arguments
  will result into empty Tuples and Dicts, which can lead in
  some cases to false positives with regard to no-value-for-parameter.
  In order to avoid this, until we'll have support for call context
  propagation, we're ignoring such cases if detected.

* Treat AsyncFunctionDef just like FunctionDef nodes,
  by implementing visit_asyncfunctiondef in terms of
  visit_functiondef.

* Take in account kwonlyargs when verifying that arguments
  are defined with the check_docs extension.

* Suppress reporting 'unneeded-not' inside `__ne__` methods
2016-01-12 08:05:27 +01:00
Florian Bruhin
046194ad6f bdd: Add first tests for JS prompt/confirm/alert. 2016-01-12 08:04:56 +01:00
Florian Bruhin
71b74329a3 requirements: Update colorama to 0.3.6.
0.3.6
- fix ValueError when a closed stream was used

0.3.5
- Bumping version to re-upload a wheel distribution

0.3.4
- stream redirection now strips ANSI codes on Linux
- strip readline markers
- assign orig_stdout and orig_stderr when initialising
- Fore.RESET did not reset style of LIGHT_EX colors. Fixed by Andy Neff
- add context manager syntax. Thanks to Matt Olsen.
- colorama didn't work on Windows when environment variable 'TERM' was set.
- fix pylint errors in client code.
- Changes to readme and other improvements by Marc Abramowitz and Zearin
2016-01-11 07:47:53 +01:00
Florian Bruhin
3f21accaeb tests: Use sip.delete to clean up prompt.
It looks like using deleteLater and waiting for the destroyed signal took too
long on the buildbot: http://www.qutebrowser.org/testresults/osx/1245.html
2016-01-11 07:38:58 +01:00
Florian Bruhin
70cd18fc98 100% coverage for mainwindow/statusbar/prompt.py. 2016-01-11 07:14:51 +01:00
Florian Bruhin
5ddc94bc8d Whitelist prompt.py for 100% coverage check.
It has 100% due to integration tests, but no unit tests yet.
2016-01-10 23:22:44 +01:00
Florian Bruhin
20610807c1 tests: Add missing files. 2016-01-10 22:08:52 +01:00
Florian Bruhin
97d5342f0c Adjust hypothesis setting for 2.0. 2016-01-10 21:57:06 +01:00
Florian Bruhin
01ffd9f46f tox: Update hypothesis to 2.0.0.
2.0.0 - 2016-01-10
------------------

Codename: A new beginning

This release cleans up all of the legacy that accrued in the course of
Hypothesis 1.0. These are mostly things that were emitting deprecation warnings
in 1.19.0, but there were a few additional changes.

In particular:

- non-strategy values will no longer be converted to strategies when used in
  given or find.
- FailedHealthCheck is now an error and not a warning.
- Handling of non-ascii reprs in user types have been simplified by using raw
  strings in more places in Python 2.
- given no longer allows mixing positional and keyword arguments.
- given no longer works with functions with defaults.
- given no longer turns provided arguments into defaults - they will not appear
  in the argspec at all.
- the basic() strategy no longer exists.
- the n_ary_tree strategy no longer exists.
- the average_list_length setting no longer exists. Note: If you're using using
  recursive() this will cause you a significant slow down. You should pass
  explicit average_size parameters to collections in recursive calls.
- @rule can no longer be applied to the same method twice.
- Python 2.6 and 3.3 are no longer officially supported, although in practice
  they still work fine.

This also includes two non-deprecation changes:

- given's keyword arguments no longer have to be the rightmost arguments and
  can appear anywhere in the method signature.
- The max_shrinks setting would sometimes not have been respected.

1.19.0 - 2016-01-09
-------------------

Codename: IT COMES

This release heralds the beginning of a new and terrible age of Hypothesis 2.0.

It's primary purpose is some final deprecations prior to said release. The goal
is that if your code emits no warnings under this release then it will probably
run unchanged under Hypothesis 2.0 (there are some caveats to this: 2.0 will
drop support for some Python versions, and if you're using internal APIs then
as usual that may break without warning).

It does have two new features:

- New @seed() decorator which allows you to manually seed a test. This may be
  harmlessly combined with and overrides the derandomize setting.
- settings objects may now be used as a decorator to fix those settings to a
  particular @given test.

API changes (old usage still works but is deprecated):

- Settings has been renamed to settings (lower casing) in order to make the
  decorator usage more natural.
- Functions for the storage directory that were in hypothesis.settings are now
  in a new hypothesis.configuration module.

Additional deprecations:

- the average_list_length setting has been deprecated in favour of being
  explicit.
- the basic() strategy has been deprecated as it is impossible to support it
  under a Conjecture based model, which will hopefully be implemented at some
  point in the 2.x series.
- the n_ary_tree strategy (which was never actually part of the public API) has
  been deprecated.
- Passing settings or random as keyword arguments to given is deprecated (use
  the new functionality instead)

Bug fixes:

- No longer emit PendingDeprecationWarning for __iter__ and StopIteration in
  streaming() values.
- When running in health check mode with non strict, don't print quite so many
  errors for an exception in reify.
- When an assumption made in a test or a filter is flaky, tests will now raise
  Flaky instead of UnsatisfiedAssumption.
2016-01-10 21:42:57 +01:00
Florian Bruhin
fce4351463 bdd: Add some tests for quickmarks. 2016-01-10 21:21:32 +01:00
Tarcisio Fedrizzi
b2c7ab9211 Fixes: forgot to rename removed variable instances 2016-01-09 12:49:56 +01:00
Tarcisio Fedrizzi
1b31a3fee4 Allows to paste multiple URLs
- The paste command will now open one tab/window per url if multiple
  URLs (separated by newline) are present in the clipboard
- Adds the tests for the new multitab functionality
- Changes test/integration/conftest.py to be able to insert newlines in
  the clipboard for the test
2016-01-09 11:32:12 +01:00
Tarcisio Fedrizzi
6327d0fe36 Strip url before trying to open it as a path 2016-01-09 11:26:17 +01:00
Florian Bruhin
c385580b81 bdd: Add some tests for bookmarks. 2016-01-09 00:15:57 +01:00
Florian Bruhin
4ef0c3e09f tests: Ensure lines look right when checking tabs. 2016-01-09 00:14:57 +01:00
Florian Bruhin
364d069e74 Stop IPC timeout timer while executing command.
This hopefully helps with #1183.
2016-01-08 13:48:19 +01:00
Florian Bruhin
d84b15d35c ipc: Add missing 0x prefix for logged socket IDs. 2016-01-08 13:09:49 +01:00
Florian Bruhin
8ca85b9c66 Also show testprocess output on teardown errors. 2016-01-08 12:53:36 +01:00
Florian Bruhin
ab79cd2496 tests: Avoid pytrace=False for now.
Using pytest.fail with pytrace=False hides the quteprocess output, which makes
it a lot harder to debug stuff.

This is because TestReport.longrepr is suddenly a string and we can't add infos
to it - see https://github.com/pytest-dev/pytest/issues/1316
2016-01-08 12:35:12 +01:00
Florian Bruhin
ff2024a565 Add socket IDs to ipc debug messages. 2016-01-08 12:02:36 +01:00
Florian Bruhin
60b04422a3 Replace pytest-sugar by pytest-instafail.
While pytest-sugar was nice to look at, it produced a lot of issues:

- Unusable on CI
- Unusable on OS X and Windows
- Garbage when terminal was resized during tests
- Missing space after test name since some while

This replaces it by pytest-instafail, which replaces the most important feature
of sugar, and on top of that, also works on CI.
2016-01-08 10:29:01 +01:00
Florian Bruhin
879725100f tox: Get rid of pytest-cache. 2016-01-08 10:29:01 +01:00
Florian Bruhin
ab0cd17772 Fix lint. 2016-01-08 10:00:42 +01:00
Florian Bruhin
9ed79ad57d tests: Switch to qtbot.assertNotEmitted. 2016-01-08 10:00:42 +01:00
Florian Bruhin
f004e45566 tests: Remove pointless CookieJar test.
There's no code between those two lines which could possibly emit that signal.
2016-01-08 09:57:04 +01:00
Florian Bruhin
1fb34331e5 tests: Default to raising=True for qtbot.
- qtbot.waitSignal with raising=True is the default this way, so we remove the
  raising=True.
- qtbot.waitSignal with raising=False stay untouched
- Some qtbot.waitSignal without raising had one added (because we don't want it
  to raise)
- Some qtbot.waitSignal without raising actually should've raised, which they
  do now.
2016-01-08 09:49:06 +01:00
Florian Bruhin
a0a6b488e6 tox: Update pytest-qt to 1.11.0.
- New qt_wait_signal_raising ini option can be used to override the default
  value of the raising parameter of the qtbot.waitSignal and qtbot.waitSignals
  functions when omitted:

  Calls which explicitly pass the raising parameter are not affected.

- qtbot now has a new assertNotEmitted context manager which can be used to
  ensure the given signal is not emitted.
2016-01-08 09:38:29 +01:00
Florian Bruhin
eebed7a5a7 tests: Poll clipboard for changes.
For some reason I can't explain, since 2b0870084b
we got test failures on OS X, as the clipboard had the old value before waiting
for the change, the new (correct) value after waiting for it, but never
actually emitted 'changed'.

We could just re-check the contents after the timeout, but that'd mean we wait
1s for every test where this weird thing happens.

Instead, we poll the clipboard for every 100ms as long as the timeout (1s)
hasn't passed, and return as soon as it has the correct contents.
2016-01-08 09:35:03 +01:00
Florian Bruhin
eef1604dcd tests: Improve WaitForClipboardTimeout message. 2016-01-08 08:35:34 +01:00
Florian Bruhin
0d9cbba3b9 tests: Dump contents in WaitForClipboardTimeout. 2016-01-08 01:56:27 +01:00
Florian Bruhin
aecf410707 Make pylint shut up about pytest.config. 2016-01-08 01:16:58 +01:00
Florian Bruhin
2b0870084b bdd: Run :tab-only between tests for caret/search.
Otherwise we end up opening a lot of tabs which slow down qutebrowser,
The latest issue in #1183 might actually be caused by that.
2016-01-08 00:58:01 +01:00
Florian Bruhin
5eafccb604 tests: Print logs live when -s is given. 2016-01-07 21:15:24 +01:00
Florian Bruhin
7ed3edd00f tox: Add pytest-repeat.
Useful to track down flaky tests.
2016-01-07 21:03:48 +01:00
Florian Bruhin
9e9cedf3e0 tests: Shorten (not suppress) quteproc log w/o -v.
The output was almost always useless without -v because the debug log wasn't
shown at all, only error/info.

Now we display a maximum of 50 lines (regardless of what level) without -v.
2016-01-07 19:41:49 +01:00
Florian Bruhin
df6d9d741f bdd: Add search tests for known bugs/regressions.
This adds a test for #874, #507 and #940.
2016-01-07 19:41:26 +01:00
Florian Bruhin
37022b8c45 bdd: Improve search tests. 2016-01-07 08:21:18 +01:00
Florian Bruhin
18b5860584 bdd: Add "When I open ... in a new window" step. 2016-01-07 08:20:48 +01:00
Florian Bruhin
f9645e447a bdd: Add first tests for searching. 2016-01-07 07:49:45 +01:00
Florian Bruhin
6a592576eb bdd: Fix timeout exception in _wait_for_clipboard. 2016-01-07 07:43:36 +01:00
Florian Bruhin
360f0b6180 bdd: Improve :inspector tests. 2016-01-07 07:12:51 +01:00
Florian Bruhin
ab22b7740f bdd: Add test for :follow-selected --tab with JS. 2016-01-06 23:29:16 +01:00
Florian Bruhin
c9a35e7f1e bdd: Add a test for :follow-selected --tab 2016-01-06 23:24:17 +01:00
Florian Bruhin
7cc98a1248 Fix lint. 2016-01-06 23:19:44 +01:00
Florian Bruhin
16ec035418 bdd: Handle trailing slash for URLs loaded.
For some reason, older Qt versions (Debian Jessie/Ubuntu Trusty) like to add a
/, so we need to handle that case too.
2016-01-06 23:19:04 +01:00
Florian Bruhin
a2c3f8c402 bdd: Add some tests for :follow-selected. 2016-01-06 22:59:42 +01:00
Florian Bruhin
916b294976 bdd: Fix regex escape.
The . chars weren't properly escaped.
2016-01-06 22:59:05 +01:00
Florian Bruhin
7dc03710b1 bdd: Only check logs for "... should be loaded".
Checking the requests from the webserver proved problematic, as often there's
some kind of caching going on. Instead, we only check the log, as this is used
for things like :navigate anyways, so if the log says the page got loaded, we
can trust it.

There's still "... should be requested" to check the actual requests.
2016-01-06 22:57:49 +01:00
Florian Bruhin
b1bf75f069 bdd: Add a test for :drop-selection. 2016-01-06 22:15:13 +01:00
Florian Bruhin
2d9900a5ad bdd: Add test for :paste with invalid URL. 2016-01-06 22:07:19 +01:00
Milan Svoboda
20cdb45da5 use greedy highlighting 2016-01-06 21:52:56 +01:00
Florian Bruhin
bd611b7ee4 bdd: Skip :print test.
This sometimes seem to cause the following warning:

    QPainter:🔚 Painter ended with 2 saved states
2016-01-06 18:27:14 +01:00
Florian Bruhin
275f1ede82 bdd: Add test for :undo. 2016-01-06 18:27:14 +01:00
Florian Bruhin
4bb38f1488 bdd: Handle some more corner cases in commands.py. 2016-01-06 18:27:14 +01:00
Florian Bruhin
3f15186a64 Add some coverage pragmas for caret workarounds. 2016-01-06 17:52:44 +01:00
Florian Bruhin
9720d879ad Remove dead code. 2016-01-06 17:52:11 +01:00
Florian Bruhin
56766acf18 Add /qutebrowser/3rdparty/ to .gitignore. 2016-01-06 08:50:46 +01:00
Florian Bruhin
4099a40e35 Fix lint. 2016-01-06 08:50:22 +01:00
Florian Bruhin
d2a1282c0b tests: Split up testprocess.wait_for. 2016-01-06 08:49:30 +01:00
Florian Bruhin
b1b767ed96 tests: Don't start Xvfb for unittests-nodisp. 2016-01-06 08:36:40 +01:00
Florian Bruhin
b0f001d3f1 Skip :print test when window can't be focused.
For some reason the window doesn't get focused on Travis. If that happens,
let's just skip the test instead of failing it.
2016-01-06 08:29:53 +01:00
Florian Bruhin
29dd6af976 tests: Optionally skip a test when waiting for log. 2016-01-06 08:29:46 +01:00
Florian Bruhin
6a97e98007 Fix lint. 2016-01-06 07:55:42 +01:00
Florian Bruhin
02e30873e1 Only test :print on Linux. 2016-01-06 07:54:54 +01:00
Florian Bruhin
fc755c104b bdd: Add test for exception with :pyeval. 2016-01-06 07:42:33 +01:00
Milan Svoboda
ec8dc35a68 rename patternre, use ignorecase in re instead of casefold 2016-01-06 07:38:55 +01:00
Florian Bruhin
03ebdfd641 bdd: Add tests for :pyeval. 2016-01-06 07:15:42 +01:00
Florian Bruhin
677dcd6748 bdd: Add tests for :print. 2016-01-06 07:15:34 +01:00
Florian Bruhin
2cadac6b6e bdd: Add tests for :stop/:reload with wrong count. 2016-01-06 07:15:20 +01:00
Florian Bruhin
e2994e9375 bdd: Add "the page should contain the plaintext". 2016-01-06 07:15:06 +01:00
Florian Bruhin
c7edb8e1f2 Make QApplication available to :debug-pyeval. 2016-01-06 07:14:49 +01:00
Florian Bruhin
1619b89df7 pytest: Add a skip mark for use with bdd. 2016-01-06 07:14:30 +01:00
Florian Bruhin
1db662fbff Update docs. 2016-01-06 06:31:56 +01:00
Florian Bruhin
05281a7d1f Add a --quiet argument to :debug-pyeval.
Closes #1156.
2016-01-06 06:19:37 +01:00
Florian Bruhin
f943891ce6 Fix :reload test when :stop is skipped.
I don't know why, but :stop being skipped causes something to be cached with
hello2.txt.
2016-01-05 22:46:52 +01:00
Felix Van der Jeugt
362db3d986 fix remarks 2016-01-05 22:45:52 +01:00
Felix Van der Jeugt
8873aba09f rename strng to more sensible names 2016-01-05 21:44:29 +01:00
Felix Van der Jeugt
e28c1bf9b8 allow config files to be optional 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
32de5b76a9 urgh be awake 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
12cc96a94b fix most of the-compiler's remarks 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
b89e0f8803 refactor all the things 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
9f81a9c3c6 lines also hey, a useful suggestion 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
cb8b16ecc5 yes, this looks less complex 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
aa9e58b520 take this, pep8 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
fc06283d91 fix more pep8/pylint complaints 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
d0979b9fac fix pep8 and pylint errors
Though I quite disagree on some remarks, as usual.
2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
4814abe286 refactor tag extraction and fix string shadowing 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
38803375f5 add dictionary config value and fix wrong variable 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
351420310d fix some of the style warnings and errors 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
766a94a539 fixed when new hints are prefixes of existing
good thing I used this some days before any merging
2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
1dfcf99d22 more extensive smart hinting 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
2f9051c6e1 shorten unique word hints 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
50b7f260c7 use link text as hints 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
86828930a2 use object state in stead of class state to store hint words 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
aaad8588b6 include dictionary parsing in first hinting
I though this would be to slow, but it's actually OK
2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
f549b4aa1e add word hint generator script 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
3be81ba62a word hints should be generated on first call 2016-01-05 20:43:29 +01:00
Felix Van der Jeugt
49e6b656f6 add word hints 2016-01-05 20:43:29 +01:00
Florian Bruhin
0ce9b28da7 Skip :stop test on OS X.
This triggers the OS X kernel bug explained here:
https://bitbucket.org/cherrypy/cherrypy/pull-requests/117/

Fixes #1183.
2016-01-05 20:13:25 +01:00
Milan Svoboda
382f7c6bf1 fix lint 2015-12-30 16:15:17 +01:00
Milan Svoboda
ed032ea107 fix lint 2015-12-30 15:54:50 +01:00
Milan Svoboda
4caffccca6 fix lint, highlight properly 2015-12-30 15:32:40 +01:00
Milan Svoboda
1f3a8a60d8 escape search string, explicit boolean test 2015-12-26 23:44:03 +01:00
Milan Svoboda
a652688566 fix lint errors 2015-12-26 18:04:01 +01:00
Milan Svoboda
013df51fd2 fix lint errors 2015-12-26 17:44:30 +01:00
Milan Svoboda
f64a3451fa fix lint errors 2015-12-26 17:15:46 +01:00
Milan Svoboda
8914404d59 allow to narrow down search by adding more words separated with space 2015-12-26 16:27:53 +01:00
Thorsten Wißmann
26f2ae5ad0 Do proper javascript escaping in password_fill 2015-12-11 17:04:50 +01:00
Thorsten Wißmann
9592eb0c69 Add documentation in password_fill
Describe usage and configuration. Also allow "login:" as a prefix for
login name in pass entries.
2015-12-11 16:54:16 +01:00
Tobias Werth
e4b809927f Escape password properly in generated JS. 2015-12-11 16:23:47 +01:00
Thorsten Wißmann
497a6e0720 Fixup url simplifier loop
Now, the loop which successively simplifies the url, always terminates.
2015-12-09 23:26:29 +01:00
Thorsten Wißmann
ffdc0f664f Ask for confirmation on fuzzy entry matching 2015-12-09 23:26:29 +01:00
Thorsten Wißmann
fb5e6e6c35 More sane defaults
- Remove Port from URL
  - Use zenity per default
  - Allow customization of handling of no entries are found
2015-12-09 23:26:29 +01:00
Thorsten Wißmann
d73491b0c8 Add password_fill userscript
Add a configurable userscript that fills login forms (i.e. the fiels
"Username" and "Password) of websites using a configurable backend where
the actual passwords are stored. The only backend yet is using the
password store "pass".
2015-12-09 23:26:29 +01:00
Tomasz Kramkowski
c575435782 misc/editor: Fix tempfile deleted on error / editor crash
This patch attempts to fix an issue where an error occuring in
misc/guiprocess or the editor process crashing would delete the
temporary file thus making it impossible to recover changes not commited
to the form field from the editor.
2015-12-01 20:22:05 +00:00
256 changed files with 8253 additions and 2072 deletions

View File

@@ -11,7 +11,7 @@ environment:
- TESTENV: pylint
install:
- C:\Python27\python -u scripts\dev\ci_install.py
- C:\Python27\python -u scripts\dev\ci\install.py
test_script:
- C:\Python34\Scripts\tox -e %TESTENV% -- -p "no:sugar" -v --junitxml=junit.xml
- C:\Python34\Scripts\tox -e %TESTENV%

View File

@@ -30,7 +30,7 @@ rules:
no-unneeded-ternary: 2
operator-assignment: [2, "always"]
operator-linebreak: [2, "after"]
space-after-keywords: [2, "always"]
keyword-spacing: 2
space-before-blocks: [2, "always"]
space-before-function-paren: [2, {"anonymous": "never", "named": "never"}]
object-curly-spacing: [2, "never"]

2
.gitignore vendored
View File

@@ -11,6 +11,7 @@ __pycache__
/setuptools-*.egg
/setuptools-*.zip
/qutebrowser/git-commit-id
/qutebrowser/3rdparty
/doc/*.html
/README.html
/CHANGELOG.html
@@ -28,4 +29,5 @@ __pycache__
/.cache
/.testmondata
/.hypothesis
/prof
TODO

13
.pydocstylerc Normal file
View File

@@ -0,0 +1,13 @@
[pydocstyle]
# Disabled checks:
# D102: Missing docstring in public method (will be handled by others)
# D103: Missing docstring in public function (will be handled by others)
# D104: Missing docstring in public package (will be handled by others)
# D105: Missing docstring in magic method (will be handled by others)
# D209: Blank line before closing """ (removed from PEP257)
# D211: No blank lines allowed before class docstring
# (PEP257 got changed, but let's stick to the old standard)
# D402: First line should not be function's signature (false-positives)
ignore = D102,D103,D104,D105,D209,D211,D402
match = (?!resources|test_*).*\.py
inherit = false

View File

@@ -3,10 +3,10 @@
[MASTER]
ignore=resources.py
extension-pkg-whitelist=PyQt5,sip
load-plugins=pylint_checkers.config,
pylint_checkers.modeline,
pylint_checkers.openencoding,
pylint_checkers.settrace
load-plugins=qute_pylint.config,
qute_pylint.modeline,
qute_pylint.openencoding,
qute_pylint.settrace
[MESSAGES CONTROL]
enable=all
@@ -41,10 +41,11 @@ attr-rgx=[a-z_][a-z0-9_]{0,30}$
argument-rgx=[a-z_][a-z0-9_]{0,30}$
variable-rgx=[a-z_][a-z0-9_]{0,30}$
docstring-min-length=3
no-docstring-rgx=(^_|^main$)
[FORMAT]
max-line-length=79
ignore-long-lines=(<?https?://|^# Copyright 201\d)
ignore-long-lines=(<?https?://|^# Copyright 201\d|# (pylint|flake8): disable=)
expected-line-ending-format=LF
[SIMILARITIES]

View File

@@ -1,76 +1,71 @@
# So we get Ubuntu Trusty - using "dist: trusty" breaks OS X.
sudo: required
dist: trusty
os:
- linux
- osx
env:
global:
- PATH=/home/travis/bin:/home/travis/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
matrix:
- TESTENV=py35
- TESTENV=py34
- TESTENV=unittests-nodisp
- TESTENV=misc
- TESTENV=vulture
- TESTENV=pep257
- TESTENV=pyflakes
- TESTENV=pep8
- TESTENV=mccabe
- TESTENV=pyroma
- TESTENV=check-manifest
- TESTENV=pylint
- TESTENV=eslint
# Not really, but this is here so we can do stuff by hand.
language: c
matrix:
include:
- os: linux
env: TESTENV=py34-cov
- os: linux
env: TESTENV=unittests-nodisp
- os: linux
env: DOCKER=debian-jessie
services: docker
- os: linux
env: DOCKER=archlinux
services: docker
- os: linux
env: DOCKER=ubuntu-wily
services: docker
- os: osx
env: TESTENV=py35
- os: linux
env: TESTENV=pylint
- os: linux
env: TESTENV=flake8
- os: linux
env: TESTENV=docs
- os: linux
env: TESTENV=vulture
- os: linux
env: TESTENV=misc
- os: linux
env: TESTENV=pyroma
- os: linux
env: TESTENV=check-manifest
- os: linux
env: TESTENV=eslint
allow_failures:
- os: osx
env: TESTENV=py35
cache:
directories:
- $HOME/.cache/pip
- $HOME/build/The-Compiler/qutebrowser/.cache
install:
- python scripts/dev/ci_install.py
- python scripts/dev/ci/install.py
script:
- tox -e $TESTENV -- -p no:sugar -v --cov-report term tests
- bash scripts/dev/ci/travis_run.sh
after_success:
- '[[ ($TESTENV == py34 || $TESTENV == py35) && $TRAVIS_OX == linux ]] && codecov -e TESTENV -X gcov'
matrix:
exclude:
- os: linux
env: TESTENV=py35
- os: osx
env: TESTENV=py34
- os: osx
env: TESTENV=unittests-nodisp
- os: osx
env: TESTENV=misc
- os: osx
env: TESTENV=vulture
- os: osx
env: TESTENV=pep257
- os: osx
env: TESTENV=pyflakes
- os: osx
env: TESTENV=pep8
- os: osx
env: TESTENV=mccabe
- os: osx
env: TESTENV=pyroma
- os: osx
env: TESTENV=check-manifest
- os: osx
env: TESTENV=pylint
- os: osx
env: TESTENV=eslint
- '[[ $TESTENV == *-cov ]] && codecov -e TESTENV -X gcov'
notifications:
webhooks:
- https://buildtimetrend.herokuapp.com/travis
irc:
channels:
- "chat.freenode.net#qutebrowser"
on_success: change
on_failure: always
skip_join: true
template:
- "%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message}"
- "%{compare_url} - %{build_url}"

View File

@@ -14,6 +14,114 @@ This project adheres to http://semver.org/[Semantic Versioning].
// `Fixed` for any bug fixes.
// `Security` to invite users to upgrade in case of vulnerabilities.
v0.6.2
------
Fixed
~~~~~
- Fixed crash when using `:tab-{prev,next,focus}` right after closing the last
tab with `last-close` set to `close`.
- Fixed crash when doing `:undo` in a new instance with `tabs -> last-close` set
to `default-page`.
- Fixed crash when starting with --cachedir=""
- Fixed crash in some circumstances when using dictionary hints
- Fixed various crashes related to PyQt 5.6
v0.6.1
------
Fixed
~~~~~~
- Fixed broken cheatsheet image which was missing from package
- Fixed occasional crash when switching/disconnecting monitors
- Fixed crash when downloading non-ascii files with a broken locale (`LC_ALL=C`)
- Added workaround for a Qt/PyQt bug which is too weird to describe here
v0.6.0
------
Added
~~~~~
- New `:buffer` command to easily switch tabs by name. This is not bound to a
key by default for existing users due to a conflict with the `gt`/`gT`
bindings (which are now removed from the default bindings).
You can bind it by hand by running `:bind -f gt set-cmd-text -s :buffer`.
- New `--quiet` argument for the `:debug-pyeval` command to not open a tab with
the results. Note `:debug-pyeval` is still only intended for debugging.
- The completion now matches each entered word separately.
- A new command `:paste-primary` got added to paste the primary selection, and
`<Shift-Insert>` got added as a binding so it pastes primary rather than
clipboard.
- New mode `word` for `hints -> mode` which uses a dictionary and link-texts
for hints instead of single characters.
- New `--all` argument for `:download-cancel` to cancel all running downloads.
- New `password_fill` userscript to fill passwords using the `pass` executable.
- New `current` hinting mode which forces opening hints in the current tab
(even with `target="_blank"`)
Changed
~~~~~~~
- Pasting multiple lines via `:paste` now opens each line in a new tab.
- `:navigate increment/decrement` now preserves leading zeroes in URLs.
- `general -> editor` can now also handle `{}` inside another argument (e.g. to open `vim` via `termite`)
- Improved performance when scrolling with many tabs open.
- Shift-Insert now also pastes primary selection for prompts.
- `:download-remove --all` got un-deprecated to provide symmetry with
`:download-cancel --all`. It does the same as `:download-clear`.
- Improved detection of URLs/search terms when pasting multiple lines.
- Don't remove `qutebrowser-editor-*` temporary file if editor subprocess crashed
- Userscripts are also searched in `/usr/share/qutebrowser/userscripts`.
- Blocked hosts are now also read from a `blocked-hosts` file in the config dir
(e.g. `~/.config/qutebrowser/blocked-hosts`).
Fixed
~~~~~
- Fixed starting with -c "".
- Fixed crash when a tab is closed twice via javascript (e.g. Dropbox
authentication dialogs)
- Fixed crash when a notification/geolocation prompt is answered after closing
the tab it belongs to.
- Fixed crash when downloading a file without any path information (e.g a
magnet link).
- Fixed crashes when opening an empty URL (e.g. via pasting).
- Fixed validation of duplicate values in `hints -> chars`.
- Fixed crash when PDF.js was partially installed.
- Fixed crash when XDG_DOWNLOAD_DIR was not an absolute path.
- Fixed very long filenames when downloading `data://`-URLs.
- Fixed ugly UI fonts on Windows when Liberation Mono is installed
- Fixed crash when unbinding key from a section which doesn't exist in the config
- Fixed report window after a segfault
- Fixed some directory browser issues on Windows
- Fixed crash when closing a window with a finished download and delayed
`remove-finished-downloads` setting.
- Fixed crash when hitting `<Tab>` then `<Ctrl-C>` on pages without keyboard
focus.
- Fixed "Frame load interrupted by policy change" error showing up when
downloading files with Qt 5.6.
Removed
~~~~~~~
- The `gt`/`gT` bindings (luakit-like alternatives to `J`/`K`) were removed
(except for existing configs) to make room for the `gt` binding to show
buffers.
v0.5.1
------
Fixed
~~~~~
- Fixed completion for various config values when using `:set`.
- Fixed config validation for various config values.
- Prevented an error being logged when a website with HTTP authentication was
opened on Windows.
v0.5.0
------

View File

@@ -89,21 +89,39 @@ Checkers
qutebrowser uses http://tox.readthedocs.org/en/latest/[tox] to run its
unittests and several linters/checkers.
Currently, the following tools will be invoked when you run `tox`:
Currently, following tox environments are available:
* Unit tests using https://www.pytest.org[pytest].
* https://pypi.python.org/pypi/pyflakes[pyflakes] via https://pypi.python.org/pypi/pytest-flakes[pytest-flakes]
* https://pypi.python.org/pypi/pep8[pep8] via https://pypi.python.org/pypi/pytest-pep8[pytest-pep8]
* https://pypi.python.org/pypi/mccabe[mccabe] via https://pypi.python.org/pypi/pytest-mccabe[pytest-mccabe]
* https://github.com/GreenSteam/pep257/[pep257]
* http://pylint.org/[pylint]
* https://pypi.python.org/pypi/pyroma/[pyroma]
* https://github.com/mgedmin/check-manifest[check-manifest]
* `scripts/misc_checks.py` which checks for the following things:
* Tests using https://www.pytest.org[pytest]:
- `py34`: Run pytest for python-3.4.
- `py35`: Run pytest for python-3.5.
- `py34-cov`: Run pytest for python-3.4 with code coverage report.
- `py35-cov`: Run pytest for python-3.5 with code coverage report.
* `flake8`: Run https://pypi.python.org/pypi/flake8[flake8] checks:
https://pypi.python.org/pypi/pyflakes[pyflakes],
https://pypi.python.org/pypi/pep8[pep8],
https://pypi.python.org/pypi/mccabe[mccabe]
* `vulture`: Run https://pypi.python.org/pypi/vulture[vulture] to find
unused code portions.
* `pylint`: Run http://pylint.org/[pylint] static code analysis.
* `pydocstyle`: Check
https://www.python.org/dev/peps/pep-0257/[PEP257] compliance with
https://github.com/PyCQA/pydocstyle[pydocstyle]
* `pyroma`: Check packaging practices with
https://pypi.python.org/pypi/pyroma/[pyroma]
* `eslint`: Run http://eslint.org/[ESLint] javascript checker.
* `check-manifest`: Check MANIFEST.in completeness with
https://github.com/mgedmin/check-manifest[check-manifest]
* `mkvenv`: Bootstrap a virtualenv for testing.
* `misc`: Run `scripts/misc_checks.py` to check for:
- untracked git files
- VCS conflict markers
- common spelling mistakes
The default test suite is run with `tox`, the list of default
environments is obtained with `tox -l` .
Please make sure the checks run without any warnings on your new contributions.
There's of course the possibility of false-positives, and the following
techniques are useful to handle these:
@@ -122,6 +140,34 @@ smallest scope which makes sense. Most of the time, this will be line scope.
* If you really think a check shouldn't be done globally as it yields a lot of
false-positives, let me know! I'm still tweaking the parameters.
Running Specific Tests
~~~~~~~~~~~~~~~~~~~~~~
While you are developing you often don't want to run the full test
suite each time.
Specific test environments can be run with `tox -e <envlist>`.
Additional parameters can be passed to the test scripts by separating
them from `tox` arguments with `--`.
Examples:
----
# run only pytest tests which failed in last run:
tox -e py35 -- --lf
# run only the integration feature tests:
tox -e py35 -- tests/integration/features
# run everything with undo in the generated name, based on the scenario text
tox -e py35 -- tests/integration/features/test_tabs.py -k undo
# run coverage test for specific file (updates htmlcov/index.html)
tox -e py35-cov -- tests/unit/browser/test_webelem.py
----
Profiling
~~~~~~~~~
@@ -246,22 +292,22 @@ When using Qt objects, two issues must be taken care of:
* Methods of Qt objects report their status by using their return values,
instead of using exceptions.
+
If a function gets or returns a Qt object which
has an `.isValid()` method such as `QUrl` or `QModelIndex`, there's a helper
function `ensure_valid` in `qutebrowser.utils.qt` which should get called on
all such objects. It will raise `qutebrowser.utils.qt.QtValueError` if the
value is not valid.
If a function gets or returns a Qt object which has an `.isValid()`
method such as `QUrl` or `QModelIndex`, there's a helper function
`ensure_valid` in `qutebrowser.utils.qtutils` which should get called
on all such objects. It will raise
`qutebrowser.utils.qtutils.QtValueError` if the value is not valid.
+
If a function returns something else on error, the return value should
carefully be checked.
* Methods of Qt objects have certain maximum values, based on their underlying
C++ types.
* Methods of Qt objects have certain maximum values, based on their
underlying C++ types.
+
When passing a numeric parameter to a Qt function, all numbers should be
range-checked using `qutebrowser.utils.check_overflow`, or passing a value
which is too large should be avoided by other means (e.g. by setting a maximum
value for a config object).
When passing a numeric parameter to a Qt function, all numbers should
be range-checked using `qutebrowser.qtutils.check_overflow`, or
passing a value which is too large should be avoided by other means
(e.g. by setting a maximum value for a config object).
[[object-registry]]
The object registry
@@ -363,9 +409,9 @@ then gets passed as the `self` parameter to the handler. The `scope` argument
selects which object registry (global, per-tab, etc.) to use. See the
<<object-registry,object registry>> section for details.
There are also other arguments to customize the way the command is registered,
see the class documentation for `register` in `qutebrowser.commands.utils` for
details.
There are also other arguments to customize the way the command is
registered, see the class documentation for `register` in
`qutebrowser.commands.cmdutils` for details.
The types of the function arguments are inferred based on their default values,
e.g. an argument `foo=True` will be converted to a flag `-f`/`--foo` in

View File

@@ -143,5 +143,5 @@ My issue is not listed.::
https://github.com/The-Compiler/qutebrowser/issues[the issue tracker] or
using the `:report` command.
If you are reporting a segfault, make sure you read the
https://github.com/The-Compiler/qutebrowser/blob/master/doc/stacktrace.asciidoc[guide]
on how to report them with all needed information.
link:doc/stacktrace.asciidoc[guide] on how to report them with all needed
information.

View File

@@ -61,61 +61,53 @@ repository (rather than a release):
$ python3 scripts/asciidoc2html.py
----
If video or sound don't seem to work, try installing the gstreamer plugins:
----
# apt-get install gstreamer1.0-plugins-{bad,base,good,ugly}
----
Then <<tox,install qutebrowser via tox>>.
On Fedora
---------
qutebrowser should run on Fedora 22.
Unfortunately there is no Fedora package yet, but installing qutebrowser is
still relatively easy! If you want to help packaging it for Fedora, please
mailto:mail@qutebrowser.org[get in touch]!
Install the dependencies via dnf:
qutebrowser is available in the official repositories for Fedora 22 and newer.
----
# dnf update
# dnf install python3-qt5 python-tox python3-sip
# dnf install qutebrowser
----
To generate the documentation for the `:help` command, when using the git
repository (rather than a release):
----
# dnf install asciidoc source-highlight
$ python3 scripts/asciidoc2html.py
----
Then <<tox,install qutebrowser via tox>>.
On Archlinux
------------
There are two Archlinux packages available in the AUR:
https://aur.archlinux.org/packages/qutebrowser/[qutebrowser] and
https://aur.archlinux.org/packages/qutebrowser-git/[qutebrowser-git].
You can install them (and the needed pypeg2 dependency) like this:
qutebrowser is available in the official [community] repository.
----
$ wget https://aur.archlinux.org/packages/py/python-pypeg2/python-pypeg2.tar.gz
$ tar xzf python-pypeg2.tar.gz
$ cd python-pypeg2
$ makepkg -si
$ cd ..
$ rm -r python-pypeg2 python-pypeg2.tar.gz
# pacman -S qutebrowser
----
$ wget https://aur.archlinux.org/packages/qu/qutebrowser/qutebrowser.tar.gz
$ tar xzf qutebrowser.tar.gz
$ cd qutebrowser
There is also a -git version available in the AUR:
https://aur.archlinux.org/packages/qutebrowser-git/[qutebrowser-git].
You can install it using `makepkg` like this:
----
$ git clone https://aur.archlinux.org/qutebrowser-git.git
$ cd qutebrowser-git
$ makepkg -si
$ cd ..
$ rm -r qutebrowser qutebrowser.tar.gz
$ rm -r qutebrowser-git
----
or you could use an AUR helper, e.g. `yaourt -S qutebrowser-git`.
If video or sound don't seem to work, try installing the gstreamer plugins:
----
# pacman -S gst-plugins-{base,good,bad,ugly} gst-libav
----
On Gentoo
---------
@@ -149,12 +141,47 @@ it with:
$ nix-env -i qutebrowser
----
On openSUSE
-----------
There are prebuilt RPMs available for Tumbleweed and Leap 42.1:
http://software.opensuse.org/download.html?project=home%3Aarpraher&package=qutebrowser[One Click Install]
Or add the repo manually:
----
# zypper addrepo http://download.opensuse.org/repositories/home:arpraher/openSUSE_Tumbleweed/home:arpraher.repo
# zypper refresh
# zypper install qutebrowser
----
On Windows
----------
You can either use one of the
https://github.com/The-Compiler/qutebrowser/releases[prebuilt standalone
packages or MSI installers], or install manually:
There are different ways to install qutebrowser on Windows:
Prebuilt binaries
~~~~~~~~~~~~~~~~~
Prebuilt standalone packages and MSI installers
https://github.com/The-Compiler/qutebrowser/releases[are built] for every
release.
https://chocolatey.org/packages/qutebrowser[Chocolatey package]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* PackageManagement PowerShell module
----
PS C:\> Install-Package qutebrowser
----
* Chocolatey's client
----
C:\> choco install qutebrowser
----
Manual install
~~~~~~~~~~~~~~
* Use the installer from http://www.python.org/downloads[python.org] to get
Python 3 (be sure to install pip).
@@ -173,6 +200,10 @@ Then <<tox,install qutebrowser via tox>>.
On OS X
-------
*Using qutebrowser with Homebrew on OS X is currently broken, as Homebrew
dropped QtWebKit support with Qt 5.6. I'm working on building a standalone
`.app` for OS X instead, but it'll still take a few days until it's ready.*
To install qutebrowser on OS X, you'll want a package manager, e.g.
http://brew.sh/[Homebrew] or https://www.macports.org/[MacPorts]. Also make
sure, you have https://itunes.apple.com/en/app/xcode/id497799835[XCode]
@@ -180,7 +211,7 @@ installed to compile PyQt5 in a later step.
----
$ brew install python3 pyqt5
$ pip3.4 install qutebrowser
$ pip3.5 install qutebrowser
----
if you are using Homebrew. For MacPorts, run:
@@ -208,7 +239,16 @@ it as part of the packaging process.
Installing qutebrowser with tox
-------------------------------
Run tox inside the qutebrowser repository to set up a
First of all, clone the repository using http://git-scm.org/[git] and switch
into the repository folder:
----
$ git clone https://github.com/The-Compiler/qutebrowser.git
$ cd qutebrowser
----
Then run tox inside the qutebrowser repository to set up a
https://docs.python.org/3/library/venv.html[virtual environment]:
----
@@ -226,6 +266,14 @@ your `$PATH` (e.g. `/usr/local/bin/qutebrowser` or `~/bin/qutebrowser`):
~/path/to/qutebrowser/.venv/bin/python3 -m qutebrowser "$@"
----
If you are developing on qutebrowser, you may want to redirect it to a local
config:
----
#!/bin/bash
~/path/to/qutebrowser/.venv/bin/python3 -m qutebrowser -c .qutebrowser-local "$@"
----
Updating
~~~~~~~~

View File

@@ -1,8 +1,8 @@
recursive-include qutebrowser *.py
recursive-include qutebrowser/html *.html
recursive-include qutebrowser/img *.svg *.png
recursive-include qutebrowser/test *.py
recursive-include qutebrowser/javascript *.js
graft qutebrowser/html
graft qutebrowser/3rdparty
graft icons
graft doc/img
@@ -23,6 +23,7 @@ exclude doc/notes
recursive-exclude doc *.asciidoc
include doc/qutebrowser.1.asciidoc
prune tests
prune qutebrowser/3rdparty
exclude pytest.ini
exclude qutebrowser.rcc
exclude .coveragerc
@@ -32,6 +33,7 @@ exclude .eslintignore
exclude doc/help
exclude .appveyor.yml
exclude .travis.yml
exclude .pydocstylerc
exclude misc/appveyor_install.py
global-exclude __pycache__ *.pyc *.pyo

View File

@@ -22,6 +22,12 @@ on Python, PyQt5 and QtWebKit and free software, licensed under the GPL.
It was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl.
// QUTE_WEB_HIDE
**qutebrowser is currently running a crowdfunding campaign to add support for
the QtWebEngine backend, which fixes many issues. Please
link:http://igg.me/at/qutebrowser[check it out]!**
// QUTE_WEB_HIDE_END
Screenshots
-----------
@@ -147,28 +153,37 @@ Contributors, sorted by the number of commits in descending order:
* Bruno Oliveira
* Alexander Cogneau
* Martin Tournoij
* Felix Van der Jeugt
* Raphael Pierzina
* Joel Torstensson
* Patric Schmitz
* Claude
* meles5
* Patric Schmitz
* Tarcisio Fedrizzi
* Artur Shaik
* Nathan Isom
* Austin Anderson
* Thorsten Wißmann
* Philipp Hansch
* Kevin Velghe
* Austin Anderson
* Alexey "Averrin" Nabrodov
* avk
* ZDarian
* Milan Svoboda
* John ShaggyTwoDope Jenkins
* Jimmy
* Peter Vilim
* Clayton Craft
* Oliver Caldwell
* Jonas Schürmann
* Panagiotis Ktistakis
* Jimmy
* Jakub Klinkovský
* skinnay
* error800
* Zach-Button
* Halfwit
* Felix Van der Jeugt
* rikn00
* Michael Ilsaas
* Martin Zimmermann
* Brian Jackson
* sbinix
@@ -176,19 +191,30 @@ Contributors, sorted by the number of commits in descending order:
* jnphilipp
* Tobias Patzl
* Peter Michely
* Link
* Larry Hynes
* Johannes Altmanninger
* Samir Benmendil
* Ryan Roden-Corrent
* Regina Hug
* Mathias Fussenegger
* Marcelo Santos
* Fritz V155 Reichwald
* Franz Fellner
* Corentin Jule
* zwarag
* xd1le
* issue
* haxwithaxe
* evan
* dylan araps
* Tomasz Kramkowski
* Tomas Orsava
* Tobias Werth
* Tim Harder
* Thiago Barroso Perrotta
* Stefan Tatschner
* Sorokin Alexei
* Samuel Loury
* Matthias Lisin
* Marcel Schilling

View File

@@ -11,6 +11,7 @@
|<<bookmark-add,bookmark-add>>|Save the current page as a bookmark.
|<<bookmark-del,bookmark-del>>|Delete a bookmark.
|<<bookmark-load,bookmark-load>>|Load a bookmark.
|<<buffer,buffer>>|Select tab by index or url/title best match.
|<<close,close>>|Close the current window.
|<<download,download>>|Download a given URL, or current page if no URL given.
|<<download-cancel,download-cancel>>|Cancel the last/[count]th download.
@@ -72,6 +73,8 @@
=== adblock-update
Update the adblock block lists.
This updates ~/.local/share/qutebrowser/blocked-hosts with downloaded host lists and re-reads ~/.config/qutebrowser/blocked-hosts.
[[back]]
=== back
Syntax: +:back [*--tab*] [*--bg*] [*--window*]+
@@ -140,6 +143,18 @@ Load a bookmark.
* This command does not split arguments after the last argument and handles quotes literally.
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
[[buffer]]
=== buffer
Syntax: +:buffer 'index'+
Select tab by index or url/title best match.
Focuses window if necessary.
==== positional arguments
* +'index'+: The [win_id/]index of the tab to focus. Or a substring in which case the closest match will be focused.
[[close]]
=== close
Close the current window.
@@ -161,8 +176,13 @@ The form `:download [url] [dest]` is deprecated, use `:download --dest [dest] [u
[[download-cancel]]
=== download-cancel
Syntax: +:download-cancel [*--all*]+
Cancel the last/[count]th download.
==== optional arguments
* +*-a*+, +*--all*+: Cancel all running downloads
==== count
The index of the download to cancel.
@@ -175,14 +195,14 @@ Remove all finished downloads from the list.
Delete the last/[count]th download from disk.
==== count
The index of the download to cancel.
The index of the download to delete.
[[download-open]]
=== download-open
Open the last/[count]th download.
==== count
The index of the download to cancel.
The index of the download to open.
[[download-remove]]
=== download-remove
@@ -191,17 +211,17 @@ Syntax: +:download-remove [*--all*]+
Remove the last/[count]th download from the list.
==== optional arguments
* +*-a*+, +*--all*+: Deprecated argument for removing all finished downloads.
* +*-a*+, +*--all*+: Remove all finished downloads.
==== count
The index of the download to cancel.
The index of the download to remove.
[[download-retry]]
=== download-retry
Retry the first failed/[count]th download.
==== count
The index of the download to cancel.
The index of the download to retry.
[[fake-key]]
=== fake-key
@@ -270,7 +290,8 @@ Start hinting.
* +'target'+: What to do with the selected element.
- `normal`: Open the link in the current tab.
- `normal`: Open the link.
- `current`: Open the link in the current tab.
- `tab`: Open the link in a new tab (honoring the
background-tabs setting).
- `tab-fg`: Open the link in a new foreground tab.
@@ -402,6 +423,8 @@ Syntax: +:paste [*--sel*] [*--tab*] [*--bg*] [*--window*]+
Open a page from the clipboard.
If the pasted text contains newlines, each line gets opened in its own tab.
==== optional arguments
* +*-s*+, +*--sel*+: Use the primary selection instead of the clipboard.
* +*-t*+, +*--tab*+: Open in a new tab.
@@ -618,8 +641,11 @@ Note the {url} variable which gets replaced by the current URL might be useful h
* +'cmdline'+: The commandline to execute.
==== optional arguments
* +*-u*+, +*--userscript*+: Run the command as a userscript. Either store the userscript in `~/.local/share/qutebrowser/userscripts`
(or `$XDG_DATA_DIR`), or use an absolute path.
* +*-u*+, +*--userscript*+: Run the command as a userscript. You can use an absolute path, or store the userscript in one of those
locations:
- `~/.local/share/qutebrowser/userscripts`
(or `$XDG_DATA_DIR`)
- `/usr/share/qutebrowser/userscripts`
* +*-v*+, +*--verbose*+: Show notifications when the command started/exited.
* +*-d*+, +*--detach*+: Whether the command should be detached from qutebrowser.
@@ -831,6 +857,7 @@ How many steps to zoom out.
|<<move-to-start-of-next-block,move-to-start-of-next-block>>|Move the cursor or selection to the start of next block.
|<<move-to-start-of-prev-block,move-to-start-of-prev-block>>|Move the cursor or selection to the start of previous block.
|<<open-editor,open-editor>>|Open an external editor with the currently selected form field.
|<<paste-primary,paste-primary>>|Paste the primary selection at cursor position.
|<<prompt-accept,prompt-accept>>|Accept the current prompt.
|<<prompt-no,prompt-no>>|Answer no to a yes/no prompt.
|<<prompt-yes,prompt-yes>>|Answer yes to a yes/no prompt.
@@ -1044,6 +1071,10 @@ Open an external editor with the currently selected form field.
The editor which should be launched can be configured via the `general -> editor` config option.
[[paste-primary]]
=== paste-primary
Paste the primary selection at cursor position.
[[prompt-accept]]
=== prompt-accept
Accept the current prompt.
@@ -1224,10 +1255,12 @@ These commands are mainly intended for debugging. They are hidden if qutebrowser
|Command|Description
|<<debug-all-objects,debug-all-objects>>|Print a list of all objects to the debug log.
|<<debug-cache-stats,debug-cache-stats>>|Print LRU cache stats.
|<<debug-clear-ssl-errors,debug-clear-ssl-errors>>|Clear remembered SSL error answers.
|<<debug-console,debug-console>>|Show the debugging console.
|<<debug-crash,debug-crash>>|Crash for debugging purposes.
|<<debug-dump-page,debug-dump-page>>|Dump the current page's content to a file.
|<<debug-pyeval,debug-pyeval>>|Evaluate a python string and display the results as a web page.
|<<debug-set-fake-clipboard,debug-set-fake-clipboard>>|Put data into the fake clipboard and enable logging, used for tests.
|<<debug-trace,debug-trace>>|Trace executed code via hunter.
|<<debug-webaction,debug-webaction>>|Execute a webaction.
|==============
@@ -1239,6 +1272,10 @@ Print a list of all objects to the debug log.
=== debug-cache-stats
Print LRU cache stats.
[[debug-clear-ssl-errors]]
=== debug-clear-ssl-errors
Clear remembered SSL error answers.
[[debug-console]]
=== debug-console
Show the debugging console.
@@ -1266,17 +1303,29 @@ Dump the current page's content to a file.
[[debug-pyeval]]
=== debug-pyeval
Syntax: +:debug-pyeval 's'+
Syntax: +:debug-pyeval [*--quiet*] 's'+
Evaluate a python string and display the results as a web page.
==== positional arguments
* +'s'+: The string to evaluate.
==== optional arguments
* +*-q*+, +*--quiet*+: Don't show the output in a new tab.
==== note
* This command does not split arguments after the last argument and handles quotes literally.
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
[[debug-set-fake-clipboard]]
=== debug-set-fake-clipboard
Syntax: +:debug-set-fake-clipboard ['s']+
Put data into the fake clipboard and enable logging, used for tests.
==== positional arguments
* +'s'+: The text to put into the fake clipboard, or unset to enable logging.
[[debug-trace]]
=== debug-trace
Syntax: +:debug-trace ['expr']+

View File

@@ -12,6 +12,7 @@ The following help pages are currently available:
* link:commands.html[Documentation of commands]
* link:settings.html[Documentation of settings]
* link:userscripts.html[How to write userscripts]
* link:CONTRIBUTING.html[Contributing to qutebrowser]
Getting help
------------

View File

@@ -179,7 +179,8 @@
|<<hints-min-chars,min-chars>>|Minimum number of chars used for hint strings.
|<<hints-scatter,scatter>>|Whether to scatter hint key chains (like Vimium) or not (like dwb).
|<<hints-uppercase,uppercase>>|Make chars in hint strings uppercase.
|<<hints-auto-follow,auto-follow>>|Whether to auto-follow a hint if there's only one left.
|<<hints-dictionary,dictionary>>|The dictionary file to be used by the word hints.
|<<hints-auto-follow,auto-follow>>|Follow a hint immediately when the hint text is completely matched.
|<<hints-next-regexes,next-regexes>>|A comma-separated list of regexes to use for 'next' links.
|<<hints-prev-regexes,prev-regexes>>|A comma-separated list of regexes to use for 'prev' links.
|==============
@@ -1538,6 +1539,7 @@ Valid values:
* +number+: Use numeric hints.
* +letter+: Use the chars in the hints -> chars setting.
* +word+: Use hints words based on the html elements and the extra words.
Default: +pass:[letter]+
@@ -1575,9 +1577,15 @@ Valid values:
Default: +pass:[false]+
[[hints-dictionary]]
=== dictionary
The dictionary file to be used by the word hints.
Default: +pass:[/usr/share/dict/words]+
[[hints-auto-follow]]
=== auto-follow
Whether to auto-follow a hint if there's only one left.
Follow a hint immediately when the hint text is completely matched.
Valid values:
@@ -2033,7 +2041,7 @@ Fonts used for the UI, with optional style/weight/size.
=== _monospace
Default monospace fonts.
Default: +pass:[Terminus, Monospace, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Bitstream Vera Sans Mono&quot;, &quot;Andale Mono&quot;, &quot;Liberation Mono&quot;, &quot;Courier New&quot;, Courier, monospace, Fixed, Consolas, Terminal]+
Default: +pass:[Terminus, Monospace, &quot;DejaVu Sans Mono&quot;, Monaco, &quot;Bitstream Vera Sans Mono&quot;, &quot;Andale Mono&quot;, &quot;Courier New&quot;, Courier, &quot;Liberation Mono&quot;, monospace, Fixed, Consolas, Terminal]+
[[fonts-completion]]
=== completion

BIN
doc/img/cheatsheet-big.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -8,7 +8,7 @@ time, use the `:help` command.
What to do now
--------------
* View the http://qutebrowser.org/img/cheatsheet-big.png[key binding cheatsheet]
* View the link:http://qutebrowser.org/img/cheatsheet-big.png[key binding cheatsheet]
to make yourself familiar with the key bindings: +
image:http://qutebrowser.org/img/cheatsheet-small.png["qutebrowser key binding cheatsheet",link="http://qutebrowser.org/img/cheatsheet-big.png"]
* Run `:adblock-update` to download adblock lists and activate adblocking.

View File

@@ -66,7 +66,7 @@ show it.
How URLs should be opened if there is already a qutebrowser instance running.
=== debug arguments
*-l* 'LOGLEVEL', *--loglevel* 'LOGLEVEL'::
*-l* '{critical,error,warning,info,debug,vdebug}', *--loglevel* '{critical,error,warning,info,debug,vdebug}'::
Set loglevel
*--logfilter* 'LOGFILTER'::

View File

@@ -13,7 +13,7 @@
height="640"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.48.5 r10040"
inkscape:version="0.91 r13725"
version="1.0"
sodipodi:docname="cheatsheet.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
@@ -32,18 +32,18 @@
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.8791156"
inkscape:cx="768.67127"
inkscape:cy="133.80749"
inkscape:zoom="1.7582312"
inkscape:cx="875.18895"
inkscape:cy="136.8726"
inkscape:document-units="px"
inkscape:current-layer="layer1"
width="1024px"
height="640px"
showgrid="false"
inkscape:window-width="636"
inkscape:window-height="536"
inkscape:window-x="2560"
inkscape:window-y="0"
inkscape:window-width="1362"
inkscape:window-height="740"
inkscape:window-x="0"
inkscape:window-y="24"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-maximized="0"
@@ -3040,17 +3040,13 @@
style="font-weight:bold;-inkscape-font-specification:'Sans Bold';fill:#ff0000"
id="flowSpan3852">(10)</flowSpan> misc. commands:</flowPara><flowPara
style="font-size:10px;fill:#000000"
id="flowPara3725-0"><flowSpan
style="fill:#0000ff"
id="flowSpan5471">gm</flowSpan> - move tab</flowPara><flowPara
id="flowPara3725-0">gt - switch tabs by name</flowPara><flowPara
style="font-size:10px;fill:#000000"
id="flowPara3854"><flowSpan
id="flowPara4052"><flowSpan
style="fill:#0000ff"
id="flowSpan5473">gl</flowSpan> - move tab to left</flowPara><flowPara
id="flowSpan4054">gm/gl/lr</flowSpan> - move tab</flowPara><flowPara
style="font-size:10px;fill:#000000"
id="flowPara3856"><flowSpan
style="fill:#0000ff"
id="flowSpan5475">gr</flowSpan> - move tab to right</flowPara><flowPara
id="flowPara4056"> (to index/left/right)</flowPara><flowPara
style="font-size:10px;fill:#000000"
id="flowPara3858">gC - clone tab</flowPara><flowPara
style="font-size:10px;fill:#000000"

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 137 KiB

View File

@@ -0,0 +1,35 @@
FROM base/archlinux
MAINTAINER Florian Bruhin <me@the-compiler.org>
RUN echo 'Server = http://mirror.de.leaseweb.net/archlinux/$repo/os/$arch' > /etc/pacman.d/mirrorlist
RUN pacman-key --init && pacman-key --populate archlinux && pacman -Sy --noconfirm archlinux-keyring
RUN pacman -Suyy --noconfirm
RUN pacman-db-upgrade
RUN pacman -S --noconfirm \
git \
python-tox \
qt5-base \
qt5-webkit \
python-pyqt5 \
xorg-xinit \
herbstluftwm \
xorg-server-xvfb
RUN echo 'en_US.UTF-8 UTF-8' > /etc/locale.gen && locale-gen
RUN useradd user && mkdir /home/user && chown -R user:users /home/user
USER user
WORKDIR /home/user
ENV DISPLAY=:0
ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
CMD Xvfb -screen 0 800x600x24 :0 & \
sleep 2 && \
herbstluftwm & \
git clone /outside qutebrowser.git && \
cd qutebrowser.git && \
tox -e py35

View File

@@ -0,0 +1,26 @@
FROM debian:jessie
MAINTAINER Florian Bruhin <me@the-compiler.org>
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get -y update && \
apt-get -y dist-upgrade && \
apt-get -y install python3-pyqt5 python3-pyqt5.qtwebkit python-tox \
python3-sip xvfb git python3-setuptools wget \
herbstluftwm locales
RUN echo 'en_US.UTF-8 UTF-8' > /etc/locale.gen && locale-gen
RUN useradd user && mkdir /home/user && chown -R user:users /home/user
USER user
WORKDIR /home/user
ENV DISPLAY=:0
ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
CMD Xvfb -screen 0 800x600x24 :0 & \
sleep 2 && \
herbstluftwm & \
git clone /outside qutebrowser.git && \
cd qutebrowser.git && \
tox -e py34

View File

@@ -0,0 +1,25 @@
FROM ubuntu:wily
MAINTAINER Florian Bruhin <me@the-compiler.org>
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get -y update && \
apt-get -y dist-upgrade && \
apt-get -y install python3-pyqt5 python3-pyqt5.qtwebkit python-tox \
python3-sip xvfb git python3-setuptools wget \
herbstluftwm language-pack-en
RUN useradd user && mkdir /home/user && chown -R user:users /home/user
USER user
WORKDIR /home/user
ENV DISPLAY=:0
ENV LC_ALL=en_US.UTF-8
ENV LANG=en_US.UTF-8
CMD Xvfb -screen 0 800x600x24 :0 & \
sleep 2 && \
herbstluftwm & \
git clone /outside qutebrowser.git && \
cd qutebrowser.git && \
tox -e py34

View File

@@ -30,9 +30,10 @@ import os
import re
from bs4 import BeautifulSoup
from urllib.parse import urljoin
with open(os.environ['QUTE_HTML'], 'r') as f:
soup = BeautifulSoup(f)
with open(os.environ['QUTE_FIFO'], 'w') as f:
for link in soup.find_all('link', rel='alternate', type=re.compile(r'application/((rss|rdf|atom)\+)?xml|text/xml')):
f.write('open -t %s\n' % link.get('href'))
f.write('open -t %s\n' % urljoin(os.environ['QUTE_URL'], link.get('href')))

364
misc/userscripts/password_fill Executable file
View File

@@ -0,0 +1,364 @@
#!/bin/bash -e
help() {
blink=$'\e[1;31m' reset=$'\e[0m'
cat <<EOF
This script can only be used as a userscript for qutebrowser
2015, Thorsten Wißmann <edu _at_ thorsten-wissmann _dot_ de>
In case of questions or suggestions, do not hesitate to send me an E-Mail or to
directly ask me via IRC (nickname thorsten\`) in #qutebrowser on freenode.
$blink!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$reset
WARNING: the passwords are stored in qutebrowser's
debug log reachable via the url qute:log
$blink!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$reset
Usage: run as a userscript form qutebrowser, e.g.:
spawn --userscript ~/.config/qutebrowser/password_fill
Pass backend: (see also passwordstore.org)
This script expects pass to store the credentials of each page in an extra
file, where the filename (or filepath) contains the domain of the respective
page. The first line of the file must contain the password, the login name
must be contained in a later line beginning with "user:", "login:", or
"username:" (configurable by the user_pattern variable).
Behaviour:
It will try to find a username/password entry in the configured backend
(currently only pass) for the current website and will load that pair of
username and password to any form on the current page that has some password
entry field. If multiple entries are found, a zenity menu is offered.
If no entry is found, then it crops subdomains from the url if at least one
entry is found in the backend. (In that case, it always shows a menu)
Configuration:
This script loads the bash script ~/.config/qutebrowser/password_fill_rc (if
it exists), so you can change any configuration variable and overwrite any
function you like.
EOF
}
set -o pipefail
shopt -s nocasematch # make regexp matching in bash case insensitive
if [ -z "$QUTE_FIFO" ] ; then
help
exit
fi
error() {
local msg="$*"
echo "message-error '${msg//\'/\\\'}'" >> "$QUTE_FIFO"
}
msg() {
local msg="$*"
echo "message-info '${msg//\'/\\\'}'" >> "$QUTE_FIFO"
}
die() {
error "$*"
exit 0
}
javascript_escape() {
# print the first argument in a escaped way, such that it can savely
# be used within javascripts double quotes
sed "s,[\\\'\"],\\\&,g" <<< "$1"
}
# ======================================================= #
# CONFIGURATION
# ======================================================= #
# The configuration file is per default located in
# ~/.config/qutebrowser/password_fill_rc and is a bash script that is loaded
# later in the present script. So basically you can replace all of the
# following definitions and make them fit your needs.
# The following simplifies a URL to the domain (e.g. "wiki.qutebrowser.org")
# which is later used to search the correct entries in the password backend. If
# you e.g. don't want the "www." to be removed or if you want to distinguish
# between different paths on the same domain.
simplify_url() {
simple_url="${1##*://}" # remove protocoll specification
simple_url="${simple_url%%\?*}" # remove GET parameters
simple_url="${simple_url%%/*}" # remove directory path
simple_url="${simple_url%:*}" # remove port
simple_url="${simple_url##www.}" # remove www. subdomain
}
# no_entries_found() is called if the first query_entries() call did not find
# any matching entries. Multiple implementations are possible:
# The easiest behaviour is to quit:
#no_entries_found() {
# if [ 0 -eq "${#files[@]}" ] ; then
# die "No entry found for »$simple_url«"
# fi
#}
# But you could also fill the files array with all entries from your pass db
# if the first db query did not find anything
# no_entries_found() {
# if [ 0 -eq "${#files[@]}" ] ; then
# query_entries ""
# if [ 0 -eq "${#files[@]}" ] ; then
# die "No entry found for »$simple_url«"
# fi
# fi
# }
# Another beahviour is to drop another level of subdomains until search hits
# are found:
no_entries_found() {
while [ 0 -eq "${#files[@]}" ] && [ -n "$simple_url" ]; do
shorter_simple_url=$(sed 's,^[^.]*\.,,' <<< "$simple_url")
if [ "$shorter_simple_url" = "$simple_url" ] ; then
# if no dot, then even remove the top level domain
simple_url=""
query_entries "$simple_url"
break
fi
simple_url="$shorter_simple_url"
query_entries "$simple_url"
#die "No entry found for »$simple_url«"
# enforce menu if we do "fuzzy" matching
menu_if_one_entry=1
done
if [ 0 -eq "${#files[@]}" ] ; then
die "No entry found for »$simple_url«"
fi
}
# Backend implementations tell, how the actual password store is accessed.
# Right now, there is only one fully functional password backend, namely for
# the program "pass".
# A password backend consists of three actions:
# - init() initializes backend-specific things and does sanity checks.
# - query_entries() is called with a simplified url and is expected to fill
# the bash array $files with the names of matching password entries. There
# are no requirements how these names should look like.
# - open_entry() is called with some specific entry of the $files array and is
# expected to write the username of that entry to the $username variable and
# the corresponding password to $password
reset_backend() {
init() { true ; }
query_entries() { true ; }
open_entry() { true ; }
}
# choose_entry() is expected to choose one entry from the array $files and
# write it to the variable $file.
choose_entry() {
choose_entry_zenity
}
# The default implementation chooses a random entry from the array. So if there
# are multiple matching entries, multiple calls to this userscript will
# eventually pick the "correct" entry. I.e. if this userscript is bound to
# "zl", the user has to press "zl" until the correct username shows up in the
# login form.
choose_entry_random() {
local nr=${#files[@]}
file="${files[$((RANDOM % nr))]}"
# Warn user, that there might be other matching password entries
if [ "$nr" -gt 1 ] ; then
msg "Picked $file out of $nr entries: ${files[*]}"
fi
}
# another implementation would be to ask the user via some menu (like rofi or
# dmenu or zenity or even qutebrowser completion in future?) which entry to
# pick
MENU_COMMAND=( head -n 1 )
# whether to show the menu if there is only one entrie in it
menu_if_one_entry=0
choose_entry_menu() {
local nr=${#files[@]}
if [ "$nr" -eq 1 ] && ! ((menu_if_one_entry)) ; then
file="${files[0]}"
else
file=$( printf "%s\n" "${files[@]}" | "${MENU_COMMAND[@]}" )
fi
}
choose_entry_rofi() {
MENU_COMMAND=( rofi -p "qutebrowser> " -dmenu
-mesg $'Pick a password entry for <b>'"${QUTE_URL//&/&amp;}"'</b>' )
choose_entry_menu || true
}
choose_entry_zenity() {
MENU_COMMAND=( zenity --list --title "Qutebrowser password fill"
--text "Pick the password entry:"
--column "Name" )
choose_entry_menu || true
}
choose_entry_zenity_radio() {
zenity_helper() {
awk '{ print $0 ; print $0 }' \
| zenity --list --radiolist \
--title "Qutebrowser password fill" \
--text "Pick the password entry:" \
--column " " --column "Name"
}
MENU_COMMAND=( zenity_helper )
choose_entry_menu || true
}
# =======================================================
# backend: PASS
# configuration options:
match_filename=1 # whether allowing entry match by filepath
match_line=0 # whether allowing entry match by URL-Pattern in file
# Note: match_line=1 gets very slow, even for small password stores!
match_line_pattern='^url: .*' # applied using grep -iE
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"
[[ -n $GPG_AGENT_INFO || $GPG == "gpg2" ]] && GPG_OPTS+=( "--batch" "--use-agent" )
pass_backend() {
init() {
PREFIX="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
if ! [ -d "$PREFIX" ] ; then
die "Can not open password store dir »$PREFIX«"
fi
}
query_entries() {
local url="$1"
if ((match_line)) ; then
# add entries with matching URL-tag
while read -r -d "" passfile ; do
if $GPG "${GPG_OPTS}" -d "$passfile" \
| grep --max-count=1 -iE "${match_line_pattern}${url}" > /dev/null
then
passfile="${passfile#$PREFIX}"
passfile="${passfile#/}"
files+=( "${passfile%.gpg}" )
fi
done < <(find -L "$PREFIX" -iname '*.gpg' -print0)
fi
if ((match_filename)) ; then
# add entries wth matching filepath
while read -r passfile ; do
passfile="${passfile#$PREFIX}"
passfile="${passfile#/}"
files+=( "${passfile%.gpg}" )
done < <(find -L "$PREFIX" -iname '*.gpg' | grep "$url")
fi
}
open_entry() {
local path="$PREFIX/${1}.gpg"
password=""
local firstline=1
while read -r line ; do
if ((firstline)) ; then
password="$line"
firstline=0
else
if [[ $line =~ $user_pattern ]] ; then
# remove the matching prefix "user: " from the beginning of the line
username=${line#${BASH_REMATCH[0]}}
break
fi
fi
done < <($GPG "${GPG_OPTS}" -d "$path" )
}
}
# =======================================================
# =======================================================
# backend: secret
secret_backend() {
init() {
return
}
query_entries() {
local domain="$1"
while read -r line ; do
if [[ "$line" =~ "attribute.username = " ]] ; then
files+=("$domain ${line#${BASH_REMATCH[0]}}")
fi
done < <( secret-tool search --unlock --all domain "$domain" 2>&1 )
}
open_entry() {
local domain="${1%% *}"
username="${1#* }"
password=$(secret-tool lookup domain "$domain" username "$username")
}
}
# =======================================================
# load some sane default backend
reset_backend
pass_backend
# load configuration
QUTE_CONFIG_DIR=${QUTE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/qutebrowser/}
PWFILL_CONFIG=${PWFILL_CONFIG:-${QUTE_CONFIG_DIR}/password_fill_rc}
if [ -f "$PWFILL_CONFIG" ] ; then
source "$PWFILL_CONFIG"
fi
init
simplify_url "$QUTE_URL"
query_entries "${simple_url}"
no_entries_found
# remove duplicates
mapfile -t files < <(printf "%s\n" "${files[@]}" | sort | uniq )
choose_entry
if [ -z "$file" ] ; then
# choose_entry didn't want any of these entries
exit 0
fi
open_entry "$file"
#username="$(date)"
#password="XYZ"
#msg "$username, ${#password}"
[ -n "$username" ] || die "Username not set in entry $file"
[ -n "$password" ] || die "Password not set in entry $file"
js() {
cat <<EOF
function hasPasswordField(form) {
var inputs = form.getElementsByTagName("input");
for (var j = 0; j < inputs.length; j++) {
var input = inputs[j];
if (input.type == "password") {
return true;
}
}
return false;
};
function loadData2Form (form) {
var inputs = form.getElementsByTagName("input");
for (var j = 0; j < inputs.length; j++) {
var input = inputs[j];
if (input.type == "text" || input.type == "email") {
input.value = "$(javascript_escape "${username}")";
}
if (input.type == "password") {
input.value = "$(javascript_escape "${password}")";
}
}
};
var forms = document.getElementsByTagName("form");
for (i = 0; i < forms.length; i++) {
if (hasPasswordField(forms[i])) {
loadData2Form(forms[i]);
}
}
EOF
}
printjs() {
js | sed 's,//.*$,,' | tr '\n' ' '
}
echo "jseval -q $(printjs)" >> "$QUTE_FIFO"

View File

@@ -1,5 +1,6 @@
[pytest]
norecursedirs = .tox .venv
addopts = --strict -rfEw --faulthandler-timeout=70 --instafail
markers =
gui: Tests using the GUI (e.g. spawning widgets)
posix: Tests which only can run on a POSIX OS.
@@ -8,22 +9,14 @@ markers =
osx: Tests which only can run on OS X.
not_osx: Tests which can not run on OS X.
not_frozen: Tests which can't be run if sys.frozen is True.
not_xvfb: Tests which can't be run with Xvfb.
no_xvfb: Tests which can't be run with Xvfb.
frozen: Tests which can only be run if sys.frozen is True.
integration: Tests which test a bigger portion of code, run without coverage.
flakes-ignore =
UnusedImport
UnusedVariable
resources.py ALL
pep8ignore =
E265 # Block comment should start with '#'
E501 # Line too long
E402 # module level import not at top of file
E266 # too many leading '#' for block comment
W503 # line break before binary operator
resources.py ALL
.hypothesis/* ALL
mccabe-complexity = 12
skip: Always skipped test.
pyqt531_or_newer: Needs PyQt 5.3.1 or newer.
xfail_norun: xfail the test with out running it
ci: Tests which should only run on CI.
flaky: Tests which are flaky and should be rerun
qt_log_level_fail = WARNING
qt_log_ignore =
^SpellCheck: .*
@@ -31,6 +24,7 @@ qt_log_ignore =
^QWindowsWindow::setGeometryDp: Unable to set geometry .*
^QProcess: Destroyed while process .* is still running\.
^"Method "GetAll" with signature "s" on interface "org\.freedesktop\.DBus\.Properties" doesn't exist
^"Method \\"GetAll\\" with signature \\"s\\" on interface \\"org\.freedesktop\.DBus\.Properties\\" doesn't exist\\n"
^virtual void QSslSocketBackendPrivate::transmit\(\) SSL write failed with error: -9805
^virtual void QSslSocketBackendPrivate::transmit\(\) SSLRead failed with: -9805
^Type conversion already registered from type .*
@@ -39,3 +33,9 @@ qt_log_ignore =
^QXcbXSettings::QXcbXSettings\(QXcbScreen\*\) Failed to get selection owner for XSETTINGS_S atom
^QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to .*
^QXcbClipboard: SelectionRequest too old
^QGeoclueMaster error creating GeoclueMasterClient\.
^Geoclue error: Process org\.freedesktop\.Geoclue\.Master exited with status 127
^QObject::connect: Cannot connect \(null\)::stateChanged\(QNetworkSession::State\) to QNetworkReplyHttpImpl::_q_networkSessionStateChanged\(QNetworkSession::State\)
^QXcbClipboard: Cannot transfer data, no data available
qt_wait_signal_raising = true
xfail_strict = true

View File

@@ -28,7 +28,7 @@ __copyright__ = "Copyright 2014-2016 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
__version_info__ = (0, 5, 0)
__version_info__ = (0, 6, 2)
__version__ = '.'.join(str(e) for e in __version_info__)
__description__ = "A keyboard-driven, vim-like browser based on PyQt5 and QtWebKit."

View File

@@ -35,7 +35,7 @@ from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtGui import QDesktopServices, QPixmap, QIcon, QCursor, QWindow
from PyQt5.QtCore import (pyqtSlot, qInstallMessageHandler, QTimer, QUrl,
QObject, Qt, QEvent)
QObject, Qt, QEvent, pyqtSignal)
try:
import hunter
except ImportError:
@@ -165,11 +165,14 @@ def init(args, crash_handler):
def _init_icon():
"""Initialize the icon of qutebrowser."""
icon = QIcon()
fallback_icon = QIcon()
for size in (16, 24, 32, 48, 64, 96, 128, 256, 512):
filename = ':/icons/qutebrowser-{}x{}.png'.format(size, size)
pixmap = QPixmap(filename)
qtutils.ensure_not_null(pixmap)
icon.addPixmap(pixmap)
fallback_icon.addPixmap(pixmap)
qtutils.ensure_not_null(fallback_icon)
icon = QIcon.fromTheme('qutebrowser', fallback_icon)
qtutils.ensure_not_null(icon)
qApp.setWindowIcon(icon)
@@ -241,12 +244,7 @@ def process_pos_args(args, via_ipc=False, cwd=None, target_arg=None):
cwd: The cwd to use for fuzzy_url.
target_arg: Command line argument received by a running instance via
ipc. If the --target argument was not specified, target_arg
will be an empty string instead of None. This behavior is
caused by the PyQt signal
``got_args = pyqtSignal(list, str, str)``
used in the misc.ipc.IPCServer class. PyQt converts the
None value into a null QString and then back to an empty
python string
will be an empty string.
"""
if via_ipc and not args:
win_id = mainwindow.get_window(via_ipc, force_window=True)
@@ -257,7 +255,7 @@ def process_pos_args(args, via_ipc=False, cwd=None, target_arg=None):
if cmd.startswith(':'):
if win_id is None:
win_id = mainwindow.get_window(via_ipc, force_tab=True)
log.init.debug("Startup cmd {}".format(cmd))
log.init.debug("Startup cmd {!r}".format(cmd))
commandrunner = runners.CommandRunner(win_id)
commandrunner.run_safely_init(cmd[1:])
elif not cmd:
@@ -272,6 +270,8 @@ def process_pos_args(args, via_ipc=False, cwd=None, target_arg=None):
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
log.init.debug("Startup URL {}".format(cmd))
if not cwd: # could also be an empty string due to the PyQt signal
cwd = None
try:
url = urlutils.fuzzy_url(cmd, cwd, relative=True)
except urlutils.InvalidUrlError as e:
@@ -339,6 +339,7 @@ def _save_version():
state_config['general']['version'] = qutebrowser.__version__
@pyqtSlot('QWidget*', 'QWidget*')
def on_focus_changed(_old, new):
"""Register currently focused main window in the object registry."""
if new is None:
@@ -550,6 +551,10 @@ class Quitter:
else:
argdict['session'] = session
argdict['override_restore'] = False
# Ensure :restart works with --temp-basedir
argdict['temp_basedir'] = False
argdict['temp_basedir_restarted'] = True
# Dump the data
data = json.dumps(argdict)
args += ['--json-args', data]
@@ -572,7 +577,7 @@ class Quitter:
raise cmdexc.CommandError("SyntaxError in {}:{}: {}".format(
e.filename, e.lineno, e))
if ok:
self.shutdown()
self.shutdown(restart=True)
def restart(self, pages=(), session=None):
"""Inner logic to restart qutebrowser.
@@ -615,7 +620,8 @@ class Quitter:
@cmdutils.register(instance='quitter', name=['quit', 'q'],
ignore_args=True)
def shutdown(self, status=0, session=None, last_window=False):
def shutdown(self, status=0, session=None, last_window=False,
restart=False):
"""Quit qutebrowser.
Args:
@@ -623,6 +629,7 @@ class Quitter:
session: A session name if saving should be forced.
last_window: If the shutdown was triggered due to the last window
closing.
restart: If we're planning to restart.
"""
if self._shutting_down:
return
@@ -652,13 +659,14 @@ class Quitter:
# in the real main event loop, or we'll get a segfault.
log.destroy.debug("Deferring real shutdown because question was "
"active.")
QTimer.singleShot(0, functools.partial(self._shutdown, status))
QTimer.singleShot(0, functools.partial(self._shutdown, status,
restart=restart))
else:
# If we have no questions to shut down, we are already in the real
# event loop, so we can shut down immediately.
self._shutdown(status)
self._shutdown(status, restart=restart)
def _shutdown(self, status):
def _shutdown(self, status, restart):
"""Second stage of shutdown."""
log.destroy.debug("Stage 2 of shutting down...")
if qApp is None:
@@ -699,7 +707,8 @@ class Quitter:
log.destroy.debug("Deactivating crash log...")
objreg.get('crash-handler').destroy_crashlogfile()
# Delete temp basedir
if self._args.temp_basedir:
if ((self._args.temp_basedir or self._args.temp_basedir_restarted) and
not restart):
atexit.register(shutil.rmtree, self._args.basedir,
ignore_errors=True)
# If we don't kill our custom handler here we might get segfaults
@@ -731,6 +740,8 @@ class Application(QApplication):
_args: ArgumentParser instance.
"""
new_window = pyqtSignal(mainwindow.MainWindow)
def __init__(self, args):
"""Constructor.

View File

@@ -92,9 +92,11 @@ class HostBlocker:
Attributes:
_blocked_hosts: A set of blocked hosts.
_config_blocked_hosts: A set of blocked hosts from ~/.config.
_in_progress: The DownloadItems which are currently downloading.
_done_count: How many files have been read successfully.
_hosts_file: The path to the blocked-hosts file.
_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.
@@ -105,13 +107,22 @@ class HostBlocker:
def __init__(self):
self._blocked_hosts = set()
self._config_blocked_hosts = set()
self._in_progress = []
self._done_count = 0
data_dir = standarddir.data()
if data_dir is None:
self._hosts_file = None
self._local_hosts_file = None
else:
self._hosts_file = os.path.join(data_dir, 'blocked-hosts')
self._local_hosts_file = os.path.join(data_dir, 'blocked-hosts')
config_dir = standarddir.config()
if config_dir is None:
self._config_hosts_file = None
else:
self._config_hosts_file = os.path.join(config_dir, 'blocked-hosts')
objreg.get('config').changed.connect(self.on_config_changed)
def is_blocked(self, url):
@@ -119,21 +130,46 @@ class HostBlocker:
if not config.get('content', 'host-blocking-enabled'):
return False
host = url.host()
return host in self._blocked_hosts and not is_whitelisted_host(host)
return ((host in self._blocked_hosts or
host in self._config_blocked_hosts) and
not is_whitelisted_host(host))
def _read_hosts_file(self, filename, target):
"""Read hosts from the given filename.
Args:
filename: The file to read.
target: The set to store the hosts in.
Return:
True if a read was attempted, False otherwise
"""
if filename is None or not os.path.exists(filename):
return False
try:
with open(filename, 'r', encoding='utf-8') as f:
for line in f:
target.add(line.strip())
except OSError:
log.misc.exception("Failed to read host blocklist!")
return True
def read_hosts(self):
"""Read hosts from the existing blocked-hosts file."""
self._blocked_hosts = set()
if self._hosts_file is None:
if self._local_hosts_file is None:
return
if os.path.exists(self._hosts_file):
try:
with open(self._hosts_file, 'r', encoding='utf-8') as f:
for line in f:
self._blocked_hosts.add(line.strip())
except OSError:
log.misc.exception("Failed to read host blocklist!")
else:
self._read_hosts_file(self._config_hosts_file,
self._config_blocked_hosts)
found = self._read_hosts_file(self._local_hosts_file,
self._blocked_hosts)
if not found:
args = objreg.get('args')
if (config.get('content', 'host-block-lists') is not None and
args.basedir is None):
@@ -142,8 +178,14 @@ class HostBlocker:
@cmdutils.register(instance='host-blocker', win_id='win_id')
def adblock_update(self, win_id):
"""Update the adblock block lists."""
if self._hosts_file is None:
"""Update the adblock block lists.
This updates ~/.local/share/qutebrowser/blocked-hosts with downloaded
host lists and re-reads ~/.config/qutebrowser/blocked-hosts.
"""
self._read_hosts_file(self._config_hosts_file,
self._config_blocked_hosts)
if self._local_hosts_file is None:
raise cmdexc.CommandError("No data storage is configured!")
self._blocked_hosts = set()
self._done_count = 0
@@ -221,7 +263,7 @@ class HostBlocker:
def on_lists_downloaded(self):
"""Install block lists after files have been downloaded."""
with open(self._hosts_file, 'w', encoding='utf-8') as f:
with open(self._local_hosts_file, 'w', encoding='utf-8') as f:
for host in sorted(self._blocked_hosts):
f.write(host + '\n')
message.info('current', "adblock: Read {} hosts from {} sources."
@@ -233,7 +275,7 @@ class HostBlocker:
urls = config.get('content', 'host-block-lists')
if urls is None:
try:
os.remove(self._hosts_file)
os.remove(self._local_hosts_file)
except OSError:
log.misc.exception("Failed to delete hosts file.")

View File

@@ -32,16 +32,23 @@ class DiskCache(QNetworkDiskCache):
"""Disk cache which sets correct cache dir and size.
If the cache is deactivated via the command line argument --cachedir="",
both attributes _cache_dir and _http_cache_dir are set to None.
Attributes:
_activated: Whether the cache should be used.
_cache_dir: The base directory for cache files (standarddir.cache())
_http_cache_dir: the HTTP subfolder in _cache_dir.
_cache_dir: The base directory for cache files (standarddir.cache()) or
None.
_http_cache_dir: the HTTP subfolder in _cache_dir or None.
"""
def __init__(self, cache_dir, parent=None):
super().__init__(parent)
self._cache_dir = cache_dir
self._http_cache_dir = os.path.join(cache_dir, 'http')
if cache_dir is None:
self._http_cache_dir = None
else:
self._http_cache_dir = os.path.join(cache_dir, 'http')
self._maybe_activate()
objreg.get('config').changed.connect(self.on_config_changed)

View File

@@ -30,7 +30,7 @@ import xml.etree.ElementTree
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWidgets import QApplication, QTabBar
from PyQt5.QtCore import Qt, QUrl, QEvent
from PyQt5.QtGui import QClipboard, QKeyEvent
from PyQt5.QtGui import QKeyEvent
from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog
from PyQt5.QtWebKitWidgets import QWebPage
import pygments
@@ -45,6 +45,7 @@ from qutebrowser.utils import (message, usertypes, log, qtutils, urlutils,
objreg, utils)
from qutebrowser.utils.usertypes import KeyMode
from qutebrowser.misc import editor, guiprocess
from qutebrowser.completion.models import instances, sortfilter
class CommandDispatcher:
@@ -659,7 +660,6 @@ class CommandDispatcher:
title: Yank the title instead of the URL.
domain: Yank only the scheme, domain, and port number.
"""
clipboard = QApplication.clipboard()
if title:
s = self._tabbed_browser.page_title(self._current_index())
what = 'title'
@@ -673,23 +673,16 @@ class CommandDispatcher:
s = self._current_url().toString(
QUrl.FullyEncoded | QUrl.RemovePassword)
what = 'URL'
if sel and clipboard.supportsSelection():
mode = QClipboard.Selection
if sel and QApplication.clipboard().supportsSelection():
target = "primary selection"
else:
mode = QClipboard.Clipboard
sel = False
target = "clipboard"
log.misc.debug("Yanking to {}: '{}'".format(target, s))
msg = "Yanked {} to {}: {}".format(what, target, s)
clipboard.changed.connect(functools.partial(
self._display_yank_msg, clipboard, msg))
clipboard.setText(s, mode)
def _display_yank_msg(self, clipboard, msg):
"""Display a message when something was yanked."""
message.info(self._win_id, msg)
clipboard.changed.disconnect()
utils.set_clipboard(s, selection=sel)
message.info(self._win_id, "Yanked {} to {}: {}".format(
what, target, s))
@cmdutils.register(instance='command-dispatcher', scope='window',
count='count')
@@ -781,6 +774,10 @@ class CommandDispatcher:
Args:
count: How many tabs to switch back.
"""
if self._count() == 0:
# Running :tab-prev after last tab was closed
# See https://github.com/The-Compiler/qutebrowser/issues/1448
return
newidx = self._current_index() - count
if newidx >= 0:
self._set_current_index(newidx)
@@ -797,6 +794,10 @@ class CommandDispatcher:
Args:
count: How many tabs to switch forward.
"""
if self._count() == 0:
# Running :tab-next after last tab was closed
# See https://github.com/The-Compiler/qutebrowser/issues/1448
return
newidx = self._current_index() + count
if newidx < self._count():
self._set_current_index(newidx)
@@ -809,28 +810,92 @@ class CommandDispatcher:
def paste(self, sel=False, tab=False, bg=False, window=False):
"""Open a page from the clipboard.
If the pasted text contains newlines, each line gets opened in its own
tab.
Args:
sel: Use the primary selection instead of the clipboard.
tab: Open in a new tab.
bg: Open in a background tab.
window: Open in new window.
"""
clipboard = QApplication.clipboard()
if sel and clipboard.supportsSelection():
mode = QClipboard.Selection
if sel and QApplication.clipboard().supportsSelection():
target = "Primary selection"
else:
mode = QClipboard.Clipboard
sel = False
target = "Clipboard"
text = clipboard.text(mode)
if not text:
text = utils.get_clipboard(selection=sel)
if not text.strip():
raise cmdexc.CommandError("{} is empty.".format(target))
log.misc.debug("{} contained: '{}'".format(target, text))
log.misc.debug("{} contained: {!r}".format(target, text))
text_urls = [u for u in text.split('\n') if u.strip()]
if (len(text_urls) > 1 and not urlutils.is_url(text_urls[0]) and
urlutils.get_path_if_valid(
text_urls[0], check_exists=True) is None):
text_urls = [text]
for i, text_url in enumerate(text_urls):
if not window and i > 0:
tab = False
bg = True
try:
url = urlutils.fuzzy_url(text_url)
except urlutils.InvalidUrlError as e:
raise cmdexc.CommandError(e)
self._open(url, tab, bg, window)
@cmdutils.register(instance='command-dispatcher', scope='window',
completion=[usertypes.Completion.tab])
def buffer(self, index):
"""Select tab by index or url/title best match.
Focuses window if necessary.
Args:
index: The [win_id/]index of the tab to focus. Or a substring
in which case the closest match will be focused.
"""
index_parts = index.split('/', 1)
try:
url = urlutils.fuzzy_url(text)
except urlutils.InvalidUrlError as e:
raise cmdexc.CommandError(e)
self._open(url, tab, bg, window)
for part in index_parts:
int(part)
except ValueError:
model = instances.get(usertypes.Completion.tab)
sf = sortfilter.CompletionFilterModel(source=model)
sf.set_pattern(index)
if sf.count() > 0:
index = sf.data(sf.first_item())
index_parts = index.split('/', 1)
else:
raise cmdexc.CommandError(
"No matching tab for: {}".format(index))
if len(index_parts) == 2:
win_id = int(index_parts[0])
idx = int(index_parts[1])
elif len(index_parts) == 1:
idx = int(index_parts[0])
active_win = objreg.get('app').activeWindow()
if active_win is None:
# Not sure how you enter a command without an active window...
raise cmdexc.CommandError(
"No window specified and couldn't find active window!")
win_id = active_win.win_id
if win_id not in objreg.window_registry:
raise cmdexc.CommandError(
"There's no window with id {}!".format(win_id))
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
if not 0 < idx <= tabbed_browser.count():
raise cmdexc.CommandError(
"There's no tab with index {}!".format(idx))
window = objreg.window_registry[win_id]
window.activateWindow()
window.raise_()
tabbed_browser.setCurrentIndex(idx-1)
@cmdutils.register(instance='command-dispatcher', scope='window',
count='count')
@@ -916,9 +981,12 @@ class CommandDispatcher:
useful here.
Args:
userscript: Run the command as a userscript. Either store the
userscript in `~/.local/share/qutebrowser/userscripts`
(or `$XDG_DATA_DIR`), or use an absolute path.
userscript: Run the command as a userscript. You can use an
absolute path, or store the userscript in one of those
locations:
- `~/.local/share/qutebrowser/userscripts`
(or `$XDG_DATA_DIR`)
- `/usr/share/qutebrowser/userscripts`
verbose: Show notifications when the command started/exited.
detach: Whether the command should be detached from qutebrowser.
cmdline: The commandline to execute.
@@ -1298,6 +1366,33 @@ class CommandDispatcher:
except webelem.IsNullError:
raise cmdexc.CommandError("Element vanished while editing!")
@cmdutils.register(instance='command-dispatcher',
modes=[KeyMode.insert], hide=True, scope='window',
needs_js=True)
def paste_primary(self):
"""Paste the primary selection at cursor position."""
frame = self._current_widget().page().currentFrame()
try:
elem = webelem.focus_elem(frame)
except webelem.IsNullError:
raise cmdexc.CommandError("No element focused!")
if not elem.is_editable(strict=True):
raise cmdexc.CommandError("Focused element is not editable!")
try:
sel = utils.get_clipboard(selection=True)
except utils.SelectionUnsupportedError:
return
log.misc.debug("Pasting primary selection into element {}".format(
elem.debug_text()))
elem.evaluateJavaScript("""
var sel = '{}';
var event = document.createEvent('TextEvent');
event.initTextEvent('textInput', true, true, null, sel);
this.dispatchEvent(event);
""".format(webelem.javascript_escape(sel)))
def _clear_search(self, view, text):
"""Clear search string/highlights for the given view.
@@ -1462,11 +1557,11 @@ class CommandDispatcher:
webview = self._current_widget()
if not webview.selection_enabled:
act = [QWebPage.MoveToNextWord]
if sys.platform == 'win32':
if sys.platform == 'win32': # pragma: no cover
act.append(QWebPage.MoveToPreviousChar)
else:
act = [QWebPage.SelectNextWord]
if sys.platform == 'win32':
if sys.platform == 'win32': # pragma: no cover
act.append(QWebPage.SelectPreviousChar)
for _ in range(count):
for a in act:
@@ -1483,11 +1578,11 @@ class CommandDispatcher:
webview = self._current_widget()
if not webview.selection_enabled:
act = [QWebPage.MoveToNextWord]
if sys.platform != 'win32':
if sys.platform != 'win32': # pragma: no branch
act.append(QWebPage.MoveToNextChar)
else:
act = [QWebPage.SelectNextWord]
if sys.platform != 'win32':
if sys.platform != 'win32': # pragma: no branch
act.append(QWebPage.SelectNextChar)
for _ in range(count):
for a in act:
@@ -1640,14 +1735,12 @@ class CommandDispatcher:
message.info(self._win_id, "Nothing to yank")
return
clipboard = QApplication.clipboard()
if sel and clipboard.supportsSelection():
mode = QClipboard.Selection
if sel and QApplication.clipboard().supportsSelection():
target = "primary selection"
else:
mode = QClipboard.Clipboard
sel = False
target = "clipboard"
clipboard.setText(s, mode)
utils.set_clipboard(s, sel)
message.info(self._win_id, "{} {} yanked to {}".format(
len(s), "char" if len(s) == 1 else "chars", target))
if not keep:
@@ -1755,3 +1848,10 @@ class CommandDispatcher:
QApplication.postEvent(receiver, press_event)
QApplication.postEvent(receiver, release_event)
@cmdutils.register(instance='command-dispatcher', scope='window',
debug=True)
def debug_clear_ssl_errors(self):
"""Clear remembered SSL error answers."""
nam = self._current_widget().page().networkAccessManager()
nam.clear_all_ssl_errors()

View File

@@ -27,6 +27,7 @@ import shutil
import functools
import collections
import sip
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, QObject, QTimer,
Qt, QVariant, QAbstractListModel, QModelIndex, QUrl)
from PyQt5.QtGui import QDesktopServices
@@ -103,6 +104,11 @@ def create_full_filename(basename, filename):
Return:
The full absolute path, or None if filename creation was not possible.
"""
# Remove chars which can't be encoded in the filename encoding.
# See https://github.com/The-Compiler/qutebrowser/issues/427
encoding = sys.getfilesystemencoding()
filename = utils.force_encoding(filename, encoding)
basename = utils.force_encoding(basename, encoding)
if os.path.isabs(filename) and os.path.isdir(filename):
# We got an absolute directory from the user, so we save it under
# the default filename in that directory.
@@ -225,7 +231,7 @@ class DownloadItemStats(QObject):
else:
return remaining_bytes / avg
@pyqtSlot(int, int)
@pyqtSlot('qint64', 'qint64')
def on_download_progress(self, bytes_done, bytes_total):
"""Update local variables when the download progress changed.
@@ -522,10 +528,6 @@ class DownloadItem(QObject):
"existing: {}, fileobj {}".format(
filename, self._filename, self.fileobj))
filename = os.path.expanduser(filename)
# Remove chars which can't be encoded in the filename encoding.
# See https://github.com/The-Compiler/qutebrowser/issues/427
encoding = sys.getfilesystemencoding()
filename = utils.force_encoding(filename, encoding)
self._filename = create_full_filename(self.basename, filename)
if self._filename is None:
# We only got a filename (without directory) or a relative path
@@ -534,6 +536,22 @@ class DownloadItem(QObject):
self._filename = create_full_filename(
self.basename, os.path.join(download_dir(), filename))
# At this point, we have a misconfigured XDG_DOWNLOAd_DIR, as
# download_dir() + filename is still no absolute path.
# The config value is checked for "absoluteness", but
# ~/.config/user-dirs.dirs may be misconfigured and a non-absolute path
# may be set for XDG_DOWNLOAD_DIR
if self._filename is None:
message.error(
self._win_id,
"XDG_DOWNLOAD_DIR points to a relative path - please check"
" your ~/.config/user-dirs.dirs. The download is saved in"
" your home directory.",
)
# fall back to $HOME as download_dir
self._filename = create_full_filename(
self.basename, os.path.expanduser(os.path.join('~', filename)))
self.basename = os.path.basename(self._filename)
last_used_directory = os.path.dirname(self._filename)
@@ -632,7 +650,7 @@ class DownloadItem(QObject):
except OSError as e:
self._die(e.strerror)
@pyqtSlot(int)
@pyqtSlot('QNetworkReply::NetworkError')
def on_reply_error(self, code):
"""Handle QNetworkReply errors."""
if code == QNetworkReply.OperationCanceledError:
@@ -774,7 +792,28 @@ class DownloadManager(QAbstractListModel):
# https://bugreports.qt.io/browse/QTBUG-42757
request.setAttribute(QNetworkRequest.CacheLoadControlAttribute,
QNetworkRequest.AlwaysNetwork)
suggested_fn = urlutils.filename_from_url(request.url())
if request.url().scheme().lower() != 'data':
suggested_fn = urlutils.filename_from_url(request.url())
else:
# We might be downloading a binary blob embedded on a page or even
# generated dynamically via javascript. We try to figure out a more
# sensible name than the base64 content of the data.
origin = request.originatingObject()
try:
origin_url = origin.url()
except AttributeError:
# Raised either if origin is None or some object that doesn't
# have its own url. We're probably fine with a default fallback
# then.
suggested_fn = 'binary blob'
else:
# Use the originating URL as a base for the filename (works
# e.g. for pdf.js).
suggested_fn = urlutils.filename_from_url(origin_url)
if suggested_fn is None:
suggested_fn = 'qutebrowser-download'
# We won't need a question if a filename or fileobj is already given
if fileobj is None and filename is None:
@@ -911,22 +950,30 @@ class DownloadManager(QAbstractListModel):
@cmdutils.register(instance='download-manager', scope='window',
count='count')
def download_cancel(self, count=0):
def download_cancel(self, all_=False, count=0):
"""Cancel the last/[count]th download.
Args:
all_: Cancel all running downloads
count: The index of the download to cancel.
"""
try:
download = self.downloads[count - 1]
except IndexError:
self.raise_no_download(count)
if download.done:
if not count:
count = len(self.downloads)
raise cmdexc.CommandError("Download {} is already done!"
.format(count))
download.cancel()
if all_:
# We need to make a copy as we're indirectly mutating
# self.downloads here
for download in self.downloads[:]:
if not download.done:
download.cancel()
else:
try:
download = self.downloads[count - 1]
except IndexError:
self.raise_no_download(count)
if download.done:
if not count:
count = len(self.downloads)
raise cmdexc.CommandError("Download {} is already done!"
.format(count))
download.cancel()
@cmdutils.register(instance='download-manager', scope='window',
count='count')
@@ -934,7 +981,7 @@ class DownloadManager(QAbstractListModel):
"""Delete the last/[count]th download from disk.
Args:
count: The index of the download to cancel.
count: The index of the download to delete.
"""
try:
download = self.downloads[count - 1]
@@ -953,7 +1000,7 @@ class DownloadManager(QAbstractListModel):
"""Open the last/[count]th download.
Args:
count: The index of the download to cancel.
count: The index of the download to open.
"""
try:
download = self.downloads[count - 1]
@@ -971,7 +1018,7 @@ class DownloadManager(QAbstractListModel):
"""Retry the first failed/[count]th download.
Args:
count: The index of the download to cancel.
count: The index of the download to retry.
"""
if count:
try:
@@ -1057,12 +1104,10 @@ class DownloadManager(QAbstractListModel):
"""Remove the last/[count]th download from the list.
Args:
all_: Deprecated argument for removing all finished downloads.
count: The index of the download to cancel.
all_: Remove all finished downloads.
count: The index of the download to remove.
"""
if all_:
message.warning(self._win_id, ":download-remove --all is "
"deprecated - use :download-clear instead!")
self.download_clear()
else:
try:
@@ -1087,6 +1132,9 @@ class DownloadManager(QAbstractListModel):
def remove_item(self, download):
"""Remove a given download."""
if sip.isdeleted(self):
# https://github.com/The-Compiler/qutebrowser/issues/1242
return
try:
idx = self.downloads.index(download)
except ValueError:

View File

@@ -79,6 +79,7 @@ class DownloadView(QListView):
self.setResizeMode(QListView.Adjust)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
self.setFocusPolicy(Qt.NoFocus)
self.setFlow(QListView.LeftToRight)
self.setSpacing(1)
self._menu = None

View File

@@ -19,14 +19,15 @@
"""A HintManager to draw hints over links."""
import math
import functools
import collections
import functools
import math
import re
import string
from PyQt5.QtCore import (pyqtSignal, pyqtSlot, QObject, QEvent, Qt, QUrl,
QTimer)
from PyQt5.QtGui import QMouseEvent, QClipboard
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWebKit import QWebElement
from PyQt5.QtWebKitWidgets import QWebPage
@@ -34,17 +35,22 @@ from qutebrowser.config import config
from qutebrowser.keyinput import modeman, modeparsers
from qutebrowser.browser import webelem
from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners
from qutebrowser.utils import usertypes, log, qtutils, message, objreg
from qutebrowser.utils import usertypes, log, qtutils, message, objreg, utils
from qutebrowser.misc import guiprocess
ElemTuple = collections.namedtuple('ElemTuple', ['elem', 'label'])
Target = usertypes.enum('Target', ['normal', 'tab', 'tab_fg', 'tab_bg',
'window', 'yank', 'yank_primary', 'run',
'fill', 'hover', 'download', 'userscript',
'spawn'])
Target = usertypes.enum('Target', ['normal', 'current', 'tab', 'tab_fg',
'tab_bg', 'window', 'yank', 'yank_primary',
'run', 'fill', 'hover', 'download',
'userscript', 'spawn'])
class WordHintingError(Exception):
"""Exception raised on errors during word hinting."""
@pyqtSlot(usertypes.KeyMode)
@@ -65,7 +71,8 @@ class HintContext:
elems: A mapping from key strings to (elem, label) namedtuples.
baseurl: The URL of the current page.
target: What to do with the opened links.
normal/tab/tab_fg/tab_bg/window: Get passed to BrowserTab.
normal/current/tab/tab_fg/tab_bg/window: Get passed to
BrowserTab.
yank/yank_primary: Yank to clipboard/primary selection.
run: Run a command.
fill: Fill commandline with link.
@@ -122,6 +129,7 @@ class HintManager(QObject):
HINT_TEXTS = {
Target.normal: "Follow hint",
Target.current: "Follow hint in current tab",
Target.tab: "Follow hint in new tab",
Target.tab_fg: "Follow hint in foreground tab",
Target.tab_bg: "Follow hint in background tab",
@@ -146,6 +154,7 @@ class HintManager(QObject):
self._win_id = win_id
self._tab_id = tab_id
self._context = None
self._word_hinter = WordHinter()
mode_manager = objreg.get('mode-manager', scope='window',
window=win_id)
mode_manager.left.connect(self.on_mode_left)
@@ -198,7 +207,14 @@ class HintManager(QObject):
Return:
A list of hint strings, in the same order as the elements.
"""
if config.get('hints', 'mode') == 'number':
hint_mode = config.get('hints', 'mode')
if hint_mode == 'word':
try:
return self._word_hinter.hint(elems)
except WordHintingError as e:
message.error(self._win_id, str(e), immediately=True)
# falls back on letter hints
if hint_mode == 'number':
chars = '0123456789'
else:
chars = config.get('hints', 'chars')
@@ -373,7 +389,7 @@ class HintManager(QObject):
label.setStyleProperty('left', '{}px !important'.format(left))
label.setStyleProperty('top', '{}px !important'.format(top))
def _draw_label(self, elem, string):
def _draw_label(self, elem, text):
"""Draw a hint label over an element.
Args:
@@ -398,7 +414,7 @@ class HintManager(QObject):
label = webelem.WebElementWrapper(parent.lastChild())
label['class'] = 'qutehint'
self._set_style_properties(elem, label)
label.setPlainText(string)
label.setPlainText(text)
return label
def _show_url_error(self):
@@ -415,6 +431,7 @@ class HintManager(QObject):
"""
target_mapping = {
Target.normal: usertypes.ClickTarget.normal,
Target.current: usertypes.ClickTarget.normal,
Target.tab_fg: usertypes.ClickTarget.tab,
Target.tab_bg: usertypes.ClickTarget.tab_bg,
Target.window: usertypes.ClickTarget.window,
@@ -449,6 +466,8 @@ class HintManager(QObject):
QMouseEvent(QEvent.MouseButtonRelease, pos, Qt.LeftButton,
Qt.NoButton, modifiers),
]
if context.target == Target.current:
elem.remove_blank_target()
for evt in events:
self.mouse_event.emit(evt)
if elem.is_text_input() and elem.is_editable():
@@ -465,11 +484,13 @@ class HintManager(QObject):
context: The HintContext to use.
"""
sel = context.target == Target.yank_primary
mode = QClipboard.Selection if sel else QClipboard.Clipboard
urlstr = url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
QApplication.clipboard().setText(urlstr, mode)
message.info(self._win_id, "URL yanked to {}".format(
"primary selection" if sel else "clipboard"))
utils.set_clipboard(urlstr, selection=sel)
msg = "Yanked URL to {}: {}".format(
"primary selection" if sel else "clipboard",
urlstr)
message.info(self._win_id, msg)
def _run_cmd(self, url, context):
"""Run the command based on a hint URL.
@@ -660,14 +681,15 @@ class HintManager(QObject):
elems = [e for e in elems if filterfunc(e)]
if not elems:
raise cmdexc.CommandError("No elements found.")
strings = self._hint_strings(elems)
for e, string in zip(elems, strings):
label = self._draw_label(e, string)
self._context.elems[string] = ElemTuple(e, label)
hints = self._hint_strings(elems)
log.hints.debug("hints: {}".format(', '.join(hints)))
for e, hint in zip(elems, hints):
label = self._draw_label(e, hint)
self._context.elems[hint] = ElemTuple(e, label)
keyparsers = objreg.get('keyparsers', scope='window',
window=self._win_id)
keyparser = keyparsers[usertypes.KeyMode.hint]
keyparser.update_bindings(strings)
keyparser.update_bindings(hints)
def follow_prevnext(self, frame, baseurl, prev=False, tab=False,
background=False, window=False):
@@ -724,7 +746,8 @@ class HintManager(QObject):
target: What to do with the selected element.
- `normal`: Open the link in the current tab.
- `normal`: Open the link.
- `current`: Open the link in the current tab.
- `tab`: Open the link in a new tab (honoring the
background-tabs setting).
- `tab-fg`: Open the link in a new foreground tab.
@@ -810,11 +833,11 @@ class HintManager(QObject):
def handle_partial_key(self, keystr):
"""Handle a new partial keypress."""
log.hints.debug("Handling new keystring: '{}'".format(keystr))
for (string, elems) in self._context.elems.items():
for (text, elems) in self._context.elems.items():
try:
if string.startswith(keystr):
matched = string[:len(keystr)]
rest = string[len(keystr):]
if text.startswith(keystr):
matched = text[:len(keystr)]
rest = text[len(keystr):]
match_color = config.get('colors', 'hints.fg.match')
elems.label.setInnerXml(
'<font color="{}">{}</font>{}'.format(
@@ -874,6 +897,7 @@ class HintManager(QObject):
# Handlers which take a QWebElement
elem_handlers = {
Target.normal: self._click,
Target.current: self._click,
Target.tab: self._click,
Target.tab_fg: self._click,
Target.tab_bg: self._click,
@@ -915,8 +939,8 @@ class HintManager(QObject):
# Show all hints again
self.filter_hints(None)
# Undo keystring highlighting
for (string, elems) in self._context.elems.items():
elems.label.setInnerXml(string)
for (text, elems) in self._context.elems.items():
elems.label.setInnerXml(text)
handler()
@cmdutils.register(instance='hintmanager', scope='tab', hide=True,
@@ -959,3 +983,120 @@ class HintManager(QObject):
# hinting.
return
self._cleanup()
class WordHinter:
"""Generator for word hints.
Attributes:
words: A set of words to be used when no "smart hint" can be
derived from the hinted element.
"""
def __init__(self):
# will be initialized on first use.
self.words = set()
self.dictionary = None
def ensure_initialized(self):
"""Generate the used words if yet uninialized."""
dictionary = config.get("hints", "dictionary")
if not self.words or self.dictionary != dictionary:
self.words.clear()
self.dictionary = dictionary
try:
with open(dictionary, encoding="UTF-8") as wordfile:
alphabet = set(string.ascii_lowercase)
hints = set()
lines = (line.rstrip().lower() for line in wordfile)
for word in lines:
if set(word) - alphabet:
# contains none-alphabetic chars
continue
if len(word) > 4:
# we don't need words longer than 4
continue
for i in range(len(word)):
# remove all prefixes of this word
hints.discard(word[:i + 1])
hints.add(word)
self.words.update(hints)
except IOError as e:
error = "Word hints requires reading the file at {}: {}"
raise WordHintingError(error.format(dictionary, str(e)))
def extract_tag_words(self, elem):
"""Extract tag words form the given element."""
attr_extractors = {
"alt": lambda elem: elem["alt"],
"name": lambda elem: elem["name"],
"title": lambda elem: elem["title"],
"src": lambda elem: elem["src"].split('/')[-1],
"href": lambda elem: elem["href"].split('/')[-1],
"text": str,
}
extractable_attrs = collections.defaultdict(
list, {
"IMG": ["alt", "title", "src"],
"A": ["title", "href", "text"],
"INPUT": ["name"]
}
)
return (attr_extractors[attr](elem)
for attr in extractable_attrs[elem.tagName()]
if attr in elem or attr == "text")
def tag_words_to_hints(self, words):
"""Take words and transform them to proper hints if possible."""
for candidate in words:
if not candidate:
continue
match = re.search('[A-Za-z]{3,}', candidate)
if not match:
continue
if 4 < match.end() - match.start() < 8:
yield candidate[match.start():match.end()].lower()
def any_prefix(self, hint, existing):
return any(hint.startswith(e) or e.startswith(hint)
for e in existing)
def filter_prefixes(self, hints, existing):
return (h for h in hints if not self.any_prefix(h, existing))
def new_hint_for(self, elem, existing, fallback):
"""Return a hint for elem, not conflicting with the existing."""
new = self.tag_words_to_hints(self.extract_tag_words(elem))
new_no_prefixes = self.filter_prefixes(new, existing)
fallback_no_prefixes = self.filter_prefixes(fallback, existing)
# either the first good, or None
return (next(new_no_prefixes, None) or
next(fallback_no_prefixes, None))
def hint(self, elems):
"""Produce hint labels based on the html tags.
Produce hint words based on the link text and random words
from the words arg as fallback.
Args:
words: Words to use as fallback when no link text can be used.
elems: The elements to get hint strings for.
Return:
A list of hint strings, in the same order as the elements.
"""
self.ensure_initialized()
hints = []
used_hints = set()
words = iter(self.words)
for elem in elems:
hint = self.new_hint_for(elem, used_hints, words)
if not hint:
raise WordHintingError("Not enough words in the dictionary.")
used_hints.add(hint)
hints.append(hint)
return hints

View File

@@ -57,9 +57,29 @@ def is_root(directory):
Return:
Whether the directory is a root directory or not.
"""
# If you're curious as why this works:
# dirname('/') = '/'
# dirname('/home') = '/'
# dirname('/home/') = '/home'
# dirname('/home/foo') = '/home'
# basically, for files (no trailing slash) it removes the file part, and
# for directories, it removes the trailing slash, so the only way for this
# to be equal is if the directory is the root directory.
return os.path.dirname(directory) == directory
def parent_dir(directory):
"""Return the parent directory for the given directory.
Args:
directory: The path to the directory.
Return:
The path to the parent directory.
"""
return os.path.normpath(os.path.join(directory, os.pardir))
def dirbrowser_html(path):
"""Get the directory browser web page.
@@ -70,30 +90,25 @@ def dirbrowser_html(path):
The HTML of the web page.
"""
title = "Browse directory: {}".format(path)
template = jinja.env.get_template('dirbrowser.html')
# pylint: disable=no-member
# WORKAROUND for https://bitbucket.org/logilab/pylint/issue/490/
if is_root(path):
parent = None
else:
parent = os.path.dirname(path)
parent = parent_dir(path)
try:
all_files = os.listdir(path)
except OSError as e:
html = jinja.env.get_template('error.html').render(
title="Error while reading directory",
url='file://%s' % path,
error=str(e),
icon='')
html = jinja.render('error.html',
title="Error while reading directory",
url='file:///{}'.format(path), error=str(e),
icon='')
return html.encode('UTF-8', errors='xmlcharrefreplace')
files = get_file_list(path, all_files, os.path.isfile)
directories = get_file_list(path, all_files, os.path.isdir)
html = template.render(title=title, url=path, icon='',
parent=parent, files=files,
directories=directories)
html = jinja.render('dirbrowser.html', title=title, url=path, icon='',
parent=parent, files=files, directories=directories)
return html.encode('UTF-8', errors='xmlcharrefreplace')

View File

@@ -19,6 +19,7 @@
"""Our own QNetworkAccessManager."""
import os
import collections
import netrc
@@ -29,7 +30,7 @@ from PyQt5.QtNetwork import (QNetworkAccessManager, QNetworkReply, QSslError,
from qutebrowser.config import config
from qutebrowser.utils import (message, log, usertypes, utils, objreg, qtutils,
urlutils)
urlutils, debug)
from qutebrowser.browser import cookies
from qutebrowser.browser.network import qutescheme, networkreply
from qutebrowser.browser.network import filescheme
@@ -62,6 +63,11 @@ class SslError(QSslError):
except TypeError:
return hash((self.certificate().toDer(), self.error()))
def __repr__(self):
return utils.get_repr(
self, error=debug.qenum_key(QSslError, self.error()),
string=self.errorString())
class NetworkManager(QNetworkAccessManager):
@@ -189,44 +195,51 @@ class NetworkManager(QNetworkAccessManager):
"""
errors = [SslError(e) for e in errors]
ssl_strict = config.get('network', 'ssl-strict')
log.webview.debug("SSL errors {!r}, strict {}".format(
errors, ssl_strict))
try:
host_tpl = urlutils.host_tuple(reply.url())
except ValueError:
host_tpl = None
is_accepted = False
is_rejected = False
else:
is_accepted = set(errors).issubset(
self._accepted_ssl_errors[host_tpl])
is_rejected = set(errors).issubset(
self._rejected_ssl_errors[host_tpl])
if (ssl_strict and ssl_strict != 'ask') or is_rejected:
return
elif is_accepted:
reply.ignoreSslErrors()
return
if ssl_strict == 'ask':
try:
host_tpl = urlutils.host_tuple(reply.url())
except ValueError:
host_tpl = None
is_accepted = False
is_rejected = False
else:
is_accepted = set(errors).issubset(
self._accepted_ssl_errors[host_tpl])
is_rejected = set(errors).issubset(
self._rejected_ssl_errors[host_tpl])
if is_accepted:
err_string = '\n'.join('- ' + err.errorString() for err in errors)
answer = self._ask('SSL errors - continue?\n{}'.format(err_string),
mode=usertypes.PromptMode.yesno, owner=reply)
if answer:
reply.ignoreSslErrors()
elif is_rejected:
pass
err_dict = self._accepted_ssl_errors
else:
err_string = '\n'.join('- ' + err.errorString() for err in
errors)
answer = self._ask('SSL errors - continue?\n{}'.format(
err_string), mode=usertypes.PromptMode.yesno,
owner=reply)
if answer:
reply.ignoreSslErrors()
d = self._accepted_ssl_errors
else:
d = self._rejected_ssl_errors
if host_tpl is not None:
d[host_tpl] += errors
elif ssl_strict:
pass
err_dict = self._rejected_ssl_errors
if host_tpl is not None:
err_dict[host_tpl] += errors
else:
for err in errors:
# FIXME we might want to use warn here (non-fatal error)
# https://github.com/The-Compiler/qutebrowser/issues/114
message.error(self._win_id,
'SSL error: {}'.format(err.errorString()))
message.error(self._win_id, 'SSL error: {}'.format(
err.errorString()))
reply.ignoreSslErrors()
self._accepted_ssl_errors[host_tpl] += errors
def clear_all_ssl_errors(self):
"""Clear all remembered SSL errors."""
self._accepted_ssl_errors.clear()
self._rejected_ssl_errors.clear()
@pyqtSlot(QUrl)
def clear_rejected_ssl_errors(self, url):
@@ -240,11 +253,14 @@ class NetworkManager(QNetworkAccessManager):
except KeyError:
pass
@pyqtSlot('QNetworkReply', 'QAuthenticator')
@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"):
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()
@@ -270,7 +286,7 @@ class NetworkManager(QNetworkAccessManager):
authenticator.setUser(user)
authenticator.setPassword(password)
@pyqtSlot('QNetworkProxy', 'QAuthenticator')
@pyqtSlot('QNetworkProxy', 'QAuthenticator*')
def on_proxy_authentication_required(self, proxy, authenticator):
"""Called when a proxy needs authentication."""
proxy_id = ProxyId(proxy.type(), proxy.hostName(), proxy.port())

View File

@@ -30,7 +30,8 @@ class FixedDataNetworkReply(QNetworkReply):
"""QNetworkReply subclass for fixed data."""
def __init__(self, request, fileData, mimeType, parent=None):
def __init__(self, request, fileData, mimeType, # flake8: disable=N803
parent=None):
"""Constructor.
Args:

View File

@@ -23,8 +23,6 @@ import urllib.parse
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QUrl
from qutebrowser.misc import httpclient
class PastebinClient(QObject):
@@ -47,11 +45,17 @@ class PastebinClient(QObject):
success = pyqtSignal(str)
error = pyqtSignal(str)
def __init__(self, parent=None):
def __init__(self, client, parent=None):
"""Constructor.
Args:
client: The HTTPClient to use. Will be reparented.
"""
super().__init__(parent)
self._client = httpclient.HTTPClient(self)
self._client.error.connect(self.error)
self._client.success.connect(self.on_client_success)
client.setParent(self)
client.error.connect(self.error)
client.success.connect(self.on_client_success)
self._client = client
def paste(self, name, title, text, parent=None):
"""Paste the text into a pastebin and return the URL.

View File

@@ -16,12 +16,6 @@
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
#
# pylint complains when using .render() on jinja templates, so we make it shut
# up for this whole module.
# pylint: disable=no-member
# WORKAROUND for https://bitbucket.org/logilab/pylint/issue/490/
"""Handler functions for different qute:... pages.
@@ -58,6 +52,25 @@ def add_handler(name):
return namedecorator
class QuteSchemeError(Exception):
"""Exception to signal that a handler should return an ErrorReply.
Attributes correspond to the arguments in
networkreply.ErrorNetworkReply.
Attributes:
errorstring: Error string to print.
error: Numerical error value.
"""
def __init__(self, errorstring, error):
"""Constructor."""
self.errorstring = errorstring
self.error = error
super().__init__(errorstring)
class QuteSchemeHandler(schemehandler.SchemeHandler):
"""Scheme handler for qute: URLs."""
@@ -95,6 +108,9 @@ class QuteSchemeHandler(schemehandler.SchemeHandler):
return networkreply.ErrorNetworkReply(
request, str(e), QNetworkReply.ContentNotFoundError,
self.parent())
except QuteSchemeError as e:
return networkreply.ErrorNetworkReply(
request, e.errorstring, e.error, self.parent())
mimetype, _encoding = mimetypes.guess_type(request.url().fileName())
if mimetype is None:
mimetype = 'text/html'
@@ -127,17 +143,17 @@ class JSBridge(QObject):
@add_handler('pyeval')
def qute_pyeval(_win_id, _request):
"""Handler for qute:pyeval. Return HTML content as bytes."""
html = jinja.env.get_template('pre.html').render(
title='pyeval', content=pyeval_output)
html = jinja.render('pre.html', title='pyeval', content=pyeval_output)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('version')
@add_handler('verizon')
def qute_version(_win_id, _request):
"""Handler for qute:version. Return HTML content as bytes."""
html = jinja.env.get_template('version.html').render(
title='Version info', version=version.version(),
copyright=qutebrowser.__copyright__)
html = jinja.render('version.html', title='Version info',
version=version.version(),
copyright=qutebrowser.__copyright__)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@@ -148,7 +164,7 @@ def qute_plainlog(_win_id, _request):
text = "Log output was disabled."
else:
text = log.ram_handler.dump_log()
html = jinja.env.get_template('pre.html').render(title='log', content=text)
html = jinja.render('pre.html', title='log', content=text)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@@ -159,8 +175,7 @@ def qute_log(_win_id, _request):
html_log = None
else:
html_log = log.ram_handler.dump_log(html=True)
html = jinja.env.get_template('log.html').render(
title='log', content=html_log)
html = jinja.render('log.html', title='log', content=html_log)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@@ -176,7 +191,8 @@ def qute_help(win_id, request):
try:
utils.read_file('html/doc/index.html')
except OSError:
html = jinja.env.get_template('error.html').render(
html = jinja.render(
'error.html',
title="Error while loading documentation",
url=request.url().toDisplayString(),
error="This most likely means the documentation was not generated "
@@ -195,16 +211,19 @@ def qute_help(win_id, request):
message.error(win_id, "Your documentation is outdated! Please re-run "
"scripts/asciidoc2html.py.")
path = 'html/doc/{}'.format(urlpath)
return utils.read_file(path).encode('UTF-8', errors='xmlcharrefreplace')
if urlpath.endswith('.png'):
return utils.read_file(path, binary=True)
else:
data = utils.read_file(path)
return data.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('settings')
def qute_settings(win_id, _request):
"""Handler for qute:settings. View/change qute configuration."""
config_getter = functools.partial(objreg.get('config').get, raw=True)
html = jinja.env.get_template('settings.html').render(
win_id=win_id, title='settings', config=configdata,
confget=config_getter)
html = jinja.render('settings.html', win_id=win_id, title='settings',
config=configdata, confget=config_getter)
return html.encode('UTF-8', errors='xmlcharrefreplace')
@@ -212,4 +231,13 @@ def qute_settings(win_id, _request):
def qute_pdfjs(_win_id, request):
"""Handler for qute://pdfjs. Return the pdf.js viewer."""
urlpath = request.url().path()
return pdfjs.get_pdfjs_res(urlpath)
try:
return pdfjs.get_pdfjs_res(urlpath)
except pdfjs.PDFJSNotFound as e:
# Logging as the error might get lost otherwise since we're not showing
# the error page if a single asset is missing. This way we don't lose
# information, as the failed pdfjs requests are still in the log.
log.misc.warning(
"pdfjs resource requested but not found: {}".format(e.path))
raise QuteSchemeError("Can't find pdfjs resource '{}'".format(e.path),
QNetworkReply.ContentNotFoundError)

View File

@@ -29,9 +29,16 @@ from qutebrowser.utils import utils
class PDFJSNotFound(Exception):
"""Raised when no pdf.js installation is found."""
"""Raised when no pdf.js installation is found.
pass
Attributes:
path: path of the file that was requested but not found.
"""
def __init__(self, path):
self.path = path
message = "Path '{}' not found".format(path)
super().__init__(message)
def generate_pdfjs_page(url):
@@ -63,54 +70,63 @@ def _generate_pdfjs_script(url):
def fix_urls(asset):
"""Take a html page and replace each relative URL wth an absolute.
"""Take a html page and replace each relative URL with an absolute.
This is specialized for pdf.js files and not a general purpose function.
Args:
asset: js file or html page as string.
"""
new_urls = {
'viewer.css': 'qute://pdfjs/web/viewer.css',
'compatibility.js': 'qute://pdfjs/web/compatibility.js',
'locale/locale.properties':
'qute://pdfjs/web/locale/locale.properties',
'l10n.js': 'qute://pdfjs/web/l10n.js',
'../build/pdf.js': 'qute://pdfjs/build/pdf.js',
'debugger.js': 'qute://pdfjs/web/debugger.js',
'viewer.js': 'qute://pdfjs/web/viewer.js',
'compressed.tracemonkey-pldi-09.pdf': '',
'./images/': 'qute://pdfjs/web/images/',
'../build/pdf.worker.js': 'qute://pdfjs/build/pdf.worker.js',
'../web/cmaps/': 'qute://pdfjs/web/cmaps/',
}
for original, new in new_urls.items():
new_urls = [
('viewer.css', 'qute://pdfjs/web/viewer.css'),
('compatibility.js', 'qute://pdfjs/web/compatibility.js'),
('locale/locale.properties',
'qute://pdfjs/web/locale/locale.properties'),
('l10n.js', 'qute://pdfjs/web/l10n.js'),
('../build/pdf.js', 'qute://pdfjs/build/pdf.js'),
('debugger.js', 'qute://pdfjs/web/debugger.js'),
('viewer.js', 'qute://pdfjs/web/viewer.js'),
('compressed.tracemonkey-pldi-09.pdf', ''),
('./images/', 'qute://pdfjs/web/images/'),
('../build/pdf.worker.js', 'qute://pdfjs/build/pdf.worker.js'),
('../web/cmaps/', 'qute://pdfjs/web/cmaps/'),
]
for original, new in new_urls:
asset = asset.replace(original, new)
return asset
SYSTEM_PDFJS_PATHS = [
'/usr/share/pdf.js/', # Debian pdf.js-common
'/usr/share/javascript/pdf/', # Debian libjs-pdf
os.path.expanduser('~/.local/share/qutebrowser/pdfjs/'), # fallback
# Debian pdf.js-common
# Arch Linux pdfjs (AUR)
'/usr/share/pdf.js/',
# Debian libjs-pdf
'/usr/share/javascript/pdf/',
# fallback
os.path.expanduser('~/.local/share/qutebrowser/pdfjs/'),
]
def get_pdfjs_res(path):
def get_pdfjs_res_and_path(path):
"""Get a pdf.js resource in binary format.
Returns a (content, path) tuple, where content is the file content and path
is the path where the file was found. If path is None, the bundled version
was used.
Args:
path: The path inside the pdfjs directory.
"""
path = path.lstrip('/')
content = None
file_path = None
# First try a system wide installation
# System installations might strip off the 'build/' or 'web/' prefixes.
# qute expects them, so we need to adjust for it.
names_to_try = [path, _remove_prefix(path)]
for system_path in SYSTEM_PDFJS_PATHS:
content = _read_from_system(system_path, names_to_try)
content, file_path = _read_from_system(system_path, names_to_try)
if content is not None:
break
@@ -120,15 +136,25 @@ def get_pdfjs_res(path):
try:
content = utils.read_file(res_path, binary=True)
except FileNotFoundError:
raise PDFJSNotFound
raise PDFJSNotFound(path) from None
try:
# Might be script/html or might be binary
text_content = content.decode('utf-8')
except UnicodeDecodeError:
return content
return (content, file_path)
text_content = fix_urls(text_content)
return text_content.encode('utf-8')
return (text_content.encode('utf-8'), file_path)
def get_pdfjs_res(path):
"""Get a pdf.js resource in binary format.
Args:
path: The path inside the pdfjs directory.
"""
content, _path = get_pdfjs_res_and_path(path)
return content
def _remove_prefix(path):
@@ -147,10 +173,13 @@ def _remove_prefix(path):
def _read_from_system(system_path, names):
"""Try to read a file with one of the given names in system_path.
Returns a (content, path) tuple, where the path is the filepath that was
used.
Each file in names is considered equal, the first file that is found
is read and its binary content returned.
Returns None if no file could be found
Returns (None, None) if no file could be found
Args:
system_path: The folder where the file should be searched.
@@ -158,11 +187,12 @@ def _read_from_system(system_path, names):
"""
for name in names:
try:
with open(os.path.join(system_path, name), 'rb') as f:
return f.read()
full_path = os.path.join(system_path, name)
with open(full_path, 'rb') as f:
return (f.read(), full_path)
except OSError:
continue
return None
return (None, None)
def is_available():

View File

@@ -49,7 +49,7 @@ attr_chars = string.ascii_letters + string.digits + attr_chars_nonalnum
# RFC 5987 gives this alternative construction of the token character class
token_chars = attr_chars + "*'%"
token_chars = attr_chars + "*'%" # flake8: disable=S001
# Definitions from https://tools.ietf.org/html/rfc2616#section-2.2

View File

@@ -285,6 +285,19 @@ class WebElementWrapper(collections.abc.MutableMapping):
tag = self._elem.tagName().lower()
return self.get('role', None) in roles or tag in ('input', 'textarea')
def remove_blank_target(self):
"""Remove target from link."""
elem = self._elem
for _ in range(5):
if elem is None:
break
tag = elem.tagName().lower()
if tag == 'a' or tag == 'area':
if elem.attribute('target') == '_blank':
elem.setAttribute('target', '_top')
break
elem = elem.parent()
def debug_text(self):
"""Get a text based on an element suitable for debug output."""
self._check_vanished()

View File

@@ -122,7 +122,10 @@ class BrowserPage(QWebPage):
"""
ignored_errors = [
(QWebPage.QtNetwork, QNetworkReply.OperationCanceledError),
(QWebPage.WebKit, 203), # "Loading is handled by the media engine"
# "Loading is handled by the media engine"
(QWebPage.WebKit, 203),
# "Frame load interrupted by policy change"
(QWebPage.WebKit, 102),
]
errpage.baseUrl = info.url
urlstr = info.url.toDisplayString()
@@ -166,10 +169,8 @@ class BrowserPage(QWebPage):
log.webview.debug("Error domain: {}, error code: {}".format(
info.domain, info.error))
title = "Error loading page: {}".format(urlstr)
template = jinja.env.get_template('error.html')
# pylint: disable=no-member
# WORKAROUND for https://bitbucket.org/logilab/pylint/issue/490/
html = template.render(
html = jinja.render(
'error.html',
title=title, url=urlstr, error=error_str, icon='')
errpage.content = html.encode('utf-8')
errpage.encoding = 'utf-8'
@@ -221,14 +222,12 @@ class BrowserPage(QWebPage):
def _show_pdfjs(self, reply):
"""Show the reply with pdfjs."""
try:
page = pdfjs.generate_pdfjs_page(reply.url()).encode('utf-8')
page = pdfjs.generate_pdfjs_page(reply.url())
except pdfjs.PDFJSNotFound:
# pylint: disable=no-member
# WORKAROUND for https://bitbucket.org/logilab/pylint/issue/490/
page = (jinja.env.get_template('no_pdfjs.html')
.render(url=reply.url().toDisplayString())
.encode('utf-8'))
self.mainFrame().setContent(page, 'text/html', reply.url())
page = jinja.render('no_pdfjs.html',
url=reply.url().toDisplayString())
self.mainFrame().setContent(page.encode('utf-8'), 'text/html',
reply.url())
reply.deleteLater()
def shutdown(self):
@@ -289,7 +288,7 @@ class BrowserPage(QWebPage):
window=self._win_id)
download_manager.get_request(req, page=self)
@pyqtSlot('QNetworkReply')
@pyqtSlot('QNetworkReply*')
def on_unsupported_content(self, reply):
"""Handle an unsupportedContent signal.
@@ -335,7 +334,7 @@ class BrowserPage(QWebPage):
else:
self.error_occurred = False
@pyqtSlot('QWebFrame', 'QWebPage::Feature')
@pyqtSlot('QWebFrame*', 'QWebPage::Feature')
def on_feature_permission_requested(self, frame, feature):
"""Ask the user for approval for geolocation/notifications."""
options = {
@@ -372,6 +371,7 @@ class BrowserPage(QWebPage):
q.answered_no.connect(no_action)
q.cancelled.connect(no_action)
self.shutting_down.connect(q.abort)
q.completed.connect(q.deleteLater)
self.featurePermissionRequestCanceled.connect(functools.partial(
@@ -439,7 +439,7 @@ class BrowserPage(QWebPage):
if 'scroll-pos' in data and frame.scrollPosition() == QPoint(0, 0):
frame.setScrollPosition(data['scroll-pos'])
@pyqtSlot(str)
@pyqtSlot(usertypes.ClickTarget)
def on_start_hinting(self, hint_target):
"""Emitted before a hinting-click takes place.

View File

@@ -27,7 +27,7 @@ from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QTimer, QUrl
from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import QApplication, QStyleFactory
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWebKitWidgets import QWebView, QWebPage
from PyQt5.QtWebKitWidgets import QWebView, QWebPage, QWebFrame
from qutebrowser.config import config
from qutebrowser.keyinput import modeman
@@ -352,9 +352,14 @@ class WebView(QWebView):
frame = self.page().mainFrame()
frame.javaScriptWindowObjectCleared.connect(self.add_js_bridge)
@pyqtSlot()
def add_js_bridge(self):
"""Add the javascript bridge for qute:... pages."""
frame = self.sender()
if not isinstance(frame, QWebFrame):
log.webview.error("Got non-QWebFrame in add_js_bridge")
return
if frame.url().scheme() == 'qute':
bridge = objreg.get('js-bridge')
frame.addToJavaScriptWindowObject('qute', bridge)

View File

@@ -249,6 +249,7 @@ class CommandRunner(QObject):
result.cmd.run(self._win_id, args)
@pyqtSlot(str, int)
@pyqtSlot(str)
def run_safely(self, text, count=None):
"""Run a command and display exceptions in the statusbar."""
try:

View File

@@ -344,14 +344,18 @@ def run(cmd, *args, win_id, env, verbose=False):
user_agent = config.get('network', 'user-agent')
if user_agent is not None:
env['QUTE_USER_AGENT'] = user_agent
cmd = os.path.expanduser(cmd)
cmd_path = os.path.expanduser(cmd)
# if cmd is not given as an absolute path, look it up
# ~/.local/share/qutebrowser/userscripts (or $XDG_DATA_DIR)
if not os.path.isabs(cmd):
log.misc.debug("{} is no absolute path".format(cmd))
cmd = os.path.join(standarddir.data(), "userscripts", cmd)
if not os.path.isabs(cmd_path):
log.misc.debug("{} is no absolute path".format(cmd_path))
cmd_path = os.path.join(standarddir.data(), "userscripts", cmd)
if not os.path.exists(cmd_path):
cmd_path = os.path.join(standarddir.system_data(),
"userscripts", cmd)
log.misc.debug("Userscript to run: {}".format(cmd_path))
runner.run(cmd, *args, env=env, verbose=verbose)
runner.run(cmd_path, *args, env=env, verbose=verbose)
runner.finished.connect(commandrunner.deleteLater)
runner.finished.connect(runner.deleteLater)

View File

@@ -198,8 +198,8 @@ class CompletionItemDelegate(QStyledItemDelegate):
columns_to_filter = index.model().srcmodel.columns_to_filter
if index.column() in columns_to_filter and pattern:
repl = r'<span class="highlight">\g<0></span>'
text = re.sub(re.escape(pattern), repl, self._opt.text,
flags=re.IGNORECASE)
text = re.sub(re.escape(pattern).replace(r'\ ', r'.*'),
repl, self._opt.text, flags=re.IGNORECASE)
self._doc.setHtml(text)
else:
self._doc.setPlainText(self._opt.text)

View File

@@ -59,6 +59,14 @@ def _init_url_completion():
_instances[usertypes.Completion.url] = model
def _init_tab_completion():
"""Initialize the tab completion model."""
log.completion.debug("Initializing tab completion.")
with debug.log_time(log.completion, 'tab completion init'):
model = miscmodels.TabCompletionModel()
_instances[usertypes.Completion.tab] = model
def _init_setting_completions():
"""Initialize setting completion models."""
log.completion.debug("Initializing setting completion.")
@@ -115,6 +123,7 @@ INITIALIZERS = {
usertypes.Completion.command: _init_command_completion,
usertypes.Completion.helptopic: _init_helptopic_completion,
usertypes.Completion.url: _init_url_completion,
usertypes.Completion.tab: _init_tab_completion,
usertypes.Completion.section: _init_setting_completions,
usertypes.Completion.option: _init_setting_completions,
usertypes.Completion.value: _init_setting_completions,

View File

@@ -19,6 +19,9 @@
"""Misc. CompletionModels."""
from PyQt5.QtCore import Qt, QTimer, pyqtSlot
from qutebrowser.browser import webview
from qutebrowser.config import config, configdata
from qutebrowser.utils import objreg, log
from qutebrowser.commands import cmdutils
@@ -138,3 +141,74 @@ class SessionCompletionModel(base.BaseCompletionModel):
self.new_item(cat, name)
except OSError:
log.completion.exception("Failed to list sessions!")
class TabCompletionModel(base.BaseCompletionModel):
"""A model to complete on open tabs across all windows.
Used for switching the buffer command."""
# https://github.com/The-Compiler/qutebrowser/issues/545
# pylint: disable=abstract-method
#IDX_COLUMN = 0
URL_COLUMN = 1
TEXT_COLUMN = 2
COLUMN_WIDTHS = (6, 40, 54)
DUMB_SORT = Qt.DescendingOrder
def __init__(self, parent=None):
super().__init__(parent)
self.columns_to_filter = [self.URL_COLUMN, self.TEXT_COLUMN]
for win_id in objreg.window_registry:
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
for i in range(tabbed_browser.count()):
tab = tabbed_browser.widget(i)
tab.url_text_changed.connect(self.rebuild)
tab.shutting_down.connect(self.delayed_rebuild)
tabbed_browser.new_tab.connect(self.on_new_tab)
objreg.get("app").new_window.connect(self.on_new_window)
self.rebuild()
def on_new_window(self, window):
"""Add hooks to new windows."""
window.tabbed_browser.new_tab.connect(self.on_new_tab)
@pyqtSlot(webview.WebView)
def on_new_tab(self, tab):
"""Add hooks to new tabs."""
tab.url_text_changed.connect(self.rebuild)
tab.shutting_down.connect(self.delayed_rebuild)
self.rebuild()
@pyqtSlot()
def delayed_rebuild(self):
"""Fire a rebuild indirectly so widgets get a chance to update."""
QTimer.singleShot(0, self.rebuild)
@pyqtSlot()
def rebuild(self):
"""Rebuild completion model from current tabs.
Very lazy method of keeping the model up to date. We could connect to
signals for new tab, tab url/title changed, tab close, tab moved and
make sure we handled background loads too ... but iterating over a
few/few dozen/few hundred tabs doesn't take very long at all.
"""
self.removeRows(0, self.rowCount())
for win_id in objreg.window_registry:
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
if tabbed_browser.shutting_down:
continue
c = self.new_category("{}".format(win_id))
for i in range(tabbed_browser.count()):
tab = tabbed_browser.widget(i)
self.new_item(c, "{}/{}".format(win_id, i+1),
tab.url().toDisplayString(),
tabbed_browser.page_title(i))

View File

@@ -27,6 +27,7 @@ from PyQt5.QtCore import QSortFilterProxyModel, QModelIndex, Qt
from qutebrowser.utils import log, qtutils, debug
from qutebrowser.completion.models import base as completion
import re
class CompletionFilterModel(QSortFilterProxyModel):
@@ -46,6 +47,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
super().setSourceModel(source)
self.srcmodel = source
self.pattern = ''
self.pattern_re = None
dumb_sort = self.srcmodel.DUMB_SORT
if dumb_sort is None:
@@ -69,6 +71,9 @@ class CompletionFilterModel(QSortFilterProxyModel):
"""
with debug.log_time(log.completion, 'Setting filter pattern'):
self.pattern = val
val = re.escape(val)
val = val.replace(r'\ ', r'.*')
self.pattern_re = re.compile(val, re.IGNORECASE)
self.invalidateFilter()
sortcol = 0
try:
@@ -146,7 +151,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
data = self.srcmodel.data(idx)
if not data:
continue
elif self.pattern.casefold() in data.casefold():
elif self.pattern_re.search(data):
return True
return False

View File

@@ -95,6 +95,7 @@ class change_filter: # pylint: disable=invalid-name
"""
if self._function:
@pyqtSlot(str, str)
@pyqtSlot()
@functools.wraps(func)
def wrapper(sectname=None, optname=None):
if sectname is None and optname is None:
@@ -108,6 +109,7 @@ class change_filter: # pylint: disable=invalid-name
return func()
else:
@pyqtSlot(str, str)
@pyqtSlot()
@functools.wraps(func)
def wrapper(wrapper_self, sectname=None, optname=None):
if sectname is None and optname is None:

View File

@@ -863,12 +863,14 @@ def data(readonly=False):
valid_values=typ.ValidValues(
('number', "Use numeric hints."),
('letter', "Use the chars in the hints -> "
"chars setting.")
"chars setting."),
('word', "Use hints words based on the html "
"elements and the extra words."),
)), 'letter'),
"Mode to use for hints."),
('chars',
SettingValue(typ.String(minlen=2, completions=[
SettingValue(typ.UniqueCharString(minlen=2, completions=[
('asdfghjkl', "Home row"),
('dhtnaoeu', "Home row (Dvorak)"),
('abcdefghijklmnopqrstuvwxyz', "All letters"),
@@ -888,9 +890,14 @@ def data(readonly=False):
SettingValue(typ.Bool(), 'false'),
"Make chars in hint strings uppercase."),
('dictionary',
SettingValue(typ.File(required=False), '/usr/share/dict/words'),
"The dictionary file to be used by the word hints."),
('auto-follow',
SettingValue(typ.Bool(), 'true'),
"Whether to auto-follow a hint if there's only one left."),
"Follow a hint immediately when the hint text is completely "
"matched."),
('next-regexes',
SettingValue(typ.RegexList(flags=re.IGNORECASE),
@@ -1193,7 +1200,7 @@ def data(readonly=False):
SettingValue(typ.Font(), 'Terminus, Monospace, '
'"DejaVu Sans Mono", Monaco, '
'"Bitstream Vera Sans Mono", "Andale Mono", '
'"Liberation Mono", "Courier New", Courier, '
'"Courier New", Courier, "Liberation Mono", '
'monospace, Fixed, Consolas, Terminal'),
"Default monospace fonts."),
@@ -1324,7 +1331,8 @@ KEY_SECTION_DESC = {
"Since normal keypresses are passed through, only special keys are "
"supported in this mode.\n"
"Useful hidden commands to map in this section:\n\n"
" * `open-editor`: Open a texteditor with the focused field."),
" * `open-editor`: Open a texteditor with the focused field.\n"
" * `paste-primary`: Paste primary selection at cursor position."),
'hint': (
"Keybindings for hint mode.\n"
"Since normal keypresses are passed through, only special keys are "
@@ -1389,8 +1397,8 @@ KEY_DATA = collections.OrderedDict([
('tab-move', ['gm']),
('tab-move -', ['gl']),
('tab-move +', ['gr']),
('tab-focus', ['J', 'gt']),
('tab-prev', ['K', 'gT']),
('tab-focus', ['J']),
('tab-prev', ['K']),
('tab-clone', ['gC']),
('reload', ['r']),
('reload -f', ['R']),
@@ -1469,6 +1477,7 @@ KEY_DATA = collections.OrderedDict([
('download-cancel', ['ad']),
('download-clear', ['cd']),
('view-source', ['gf']),
('set-cmd-text -s :buffer', ['gt']),
('tab-focus last', ['<Ctrl-Tab>']),
('enter-mode passthrough', ['<Ctrl-V>']),
('quit', ['<Ctrl-Q>']),
@@ -1495,6 +1504,7 @@ KEY_DATA = collections.OrderedDict([
('insert', collections.OrderedDict([
('open-editor', ['<Ctrl-E>']),
('paste-primary', ['<Shift-Ins>']),
])),
('hint', collections.OrderedDict([

View File

@@ -258,6 +258,13 @@ class String(BaseType):
self._basic_validation(value)
if not value:
return
if self.valid_values is not None:
if value not in self.valid_values:
raise configexc.ValidationError(
value, "valid values: {}".format(', '.join(
self.valid_values)))
if self.forbidden is not None and any(c in value
for c in self.forbidden):
raise configexc.ValidationError(value, "may not contain the chars "
@@ -270,7 +277,25 @@ class String(BaseType):
"long!".format(self.maxlen))
def complete(self):
return self._completions
if self._completions is not None:
return self._completions
else:
return super().complete()
class UniqueCharString(String):
"""A string which may not contain duplicate chars."""
def validate(self, value):
super().validate(value)
if not value:
return
# Check for duplicate values
if len(set(value)) != len(value):
raise configexc.ValidationError(
value, "String contains duplicate values!")
class List(BaseType):
@@ -891,6 +916,10 @@ class File(BaseType):
"""A file on the local filesystem."""
def __init__(self, required=True, **kwargs):
super().__init__(**kwargs)
self.required = required
def transform(self, value):
if not value:
return None
@@ -899,7 +928,7 @@ class File(BaseType):
if not os.path.isabs(value):
cfgdir = standarddir.config()
assert cfgdir is not None
return os.path.join(cfgdir, value)
value = os.path.join(cfgdir, value)
return value
def validate(self, value):
@@ -915,15 +944,13 @@ class File(BaseType):
raise configexc.ValidationError(
value, "must be an absolute path when not using a "
"config directory!")
elif not os.path.isfile(os.path.join(cfgdir, value)):
raise configexc.ValidationError(
value, "must be a valid path relative to the config "
"directory!")
else:
return
elif not os.path.isfile(value):
raise configexc.ValidationError(
value, "must be a valid file!")
value = os.path.join(cfgdir, value)
not_isfile_message = ("must be a valid path relative to the "
"config directory!")
else:
not_isfile_message = "must be a valid file!"
if self.required and not os.path.isfile(value):
raise configexc.ValidationError(value, not_isfile_message)
except UnicodeEncodeError as e:
raise configexc.ValidationError(value, e)
@@ -1084,7 +1111,7 @@ class ShellCommand(BaseType):
shlex.split(value)
except ValueError as e:
raise configexc.ValidationError(value, str(e))
if self.placeholder and '{}' not in self.transform(value):
if self.placeholder and '{}' not in value:
raise configexc.ValidationError(value, "needs to contain a "
"{}-placeholder.")
@@ -1169,7 +1196,7 @@ class SearchEngineUrl(BaseType):
self._basic_validation(value)
if not value:
return
elif '{}' not in value:
elif not ('{}' in value or '{0}' in value):
raise configexc.ValidationError(value, "must contain \"{}\"")
try:
value.format("")
@@ -1259,8 +1286,16 @@ class UserStyleSheet(File):
def transform(self, value):
if not value:
return None
path = super().transform(value)
if os.path.exists(path):
if standarddir.config() is None:
# We can't call super().transform() here as this counts on the
# validation previously ensuring that we don't have a relative path
# when starting with -c "".
path = None
else:
path = super().transform(value)
if path is not None and os.path.exists(path):
return QUrl.fromLocalFile(path)
else:
data = base64.b64encode(value.encode('utf-8')).decode('ascii')

View File

@@ -201,7 +201,7 @@ class KeyConfigParser(QObject):
sect = self.keybindings[mode]
except KeyError:
raise cmdexc.CommandError("Can't find mode section '{}'!".format(
sect))
mode))
try:
del sect[key]
except KeyError:

View File

@@ -46,21 +46,21 @@ ul.files > li {
<p id="dirbrowserTitleText">Browse directory: {{url}}</p>
</div>
{% if parent %}
{% if parent is not none %}
<ul class="parent">
<li><a href="{{parent}}">..</a></li>
<li><a href="{{ file_url(parent) }}">..</a></li>
</ul>
{% endif %}
<ul class="folders">
{% for item in directories %}
<li><a href="file://{{item.absname}}">{{item.name}}</a></li>
<li><a href="{{ file_url(item.absname) }}">{{item.name}}</a></li>
{% endfor %}
</ul>
<ul class="files">
{% for item in files %}
<li><a href="file://{{item.absname}}">{{item.name}}</a></li>
<li><a href="{{ file_url(item.absname) }}">{{item.name}}</a></li>
{% endfor %}
</ul>
</div>

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<!--
vim: ft=html fileencoding=utf-8 sts=4 sw=4 et:
-->
<html>
<head>
<meta charset="utf-8">
<title>Error while rendering HTML</title>
</head>
<body>
<h1>Error while rendering internal qutebrowser page</h1>
<p>There was an error while rendering {pagename}.</p>
<p>This most likely happened because you updated qutebrowser but didn't restart yet.</p>
<p>If you believe this isn't the case and this is a bug, please do :report.<p>
<h2>Traceback</h2>
<pre>{traceback}</pre>
</body>
</html>

View File

@@ -23,7 +23,6 @@ import functools
from PyQt5.QtCore import pyqtSignal, Qt, QObject, QEvent
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebKitWidgets import QWebView
from qutebrowser.keyinput import modeparsers, keyparser
from qutebrowser.config import config
@@ -171,13 +170,9 @@ class ModeManager(QObject):
is_non_alnum = (
event.modifiers() not in (Qt.NoModifier, Qt.ShiftModifier) or
not event.text().strip())
focus_widget = QApplication.instance().focusWidget()
is_tab = event.key() in (Qt.Key_Tab, Qt.Key_Backtab)
if handled:
filter_this = True
elif is_tab and not isinstance(focus_widget, QWebView):
filter_this = True
elif (parser.passthrough or
self._forward_unbound_keys == 'all' or
(self._forward_unbound_keys == 'auto' and is_non_alnum)):
@@ -189,11 +184,12 @@ class ModeManager(QObject):
self._releaseevents_to_pass.add(KeyEvent(event))
if curmode != usertypes.KeyMode.insert:
focus_widget = QApplication.instance().focusWidget()
log.modes.debug("handled: {}, forward-unbound-keys: {}, "
"passthrough: {}, is_non_alnum: {}, is_tab {} --> "
"passthrough: {}, is_non_alnum: {} --> "
"filter: {} (focused: {!r})".format(
handled, self._forward_unbound_keys,
parser.passthrough, is_non_alnum, is_tab,
parser.passthrough, is_non_alnum,
filter_this, focus_widget))
return filter_this

View File

@@ -79,8 +79,8 @@ def get_window(via_ipc, force_window=False, force_tab=False,
if open_target not in ('tab-silent', 'tab-bg-silent'):
window_to_raise = window
if window_to_raise is not None:
window_to_raise.setWindowState(window.windowState() &
~Qt.WindowMinimized | Qt.WindowActive)
window_to_raise.setWindowState(
window.windowState() & ~Qt.WindowMinimized | Qt.WindowActive)
window_to_raise.raise_()
window_to_raise.activateWindow()
QApplication.instance().alert(window_to_raise)
@@ -187,6 +187,8 @@ class MainWindow(QWidget):
#self.tabWidget.setCurrentIndex(0)
#QtCore.QMetaObject.connectSlotsByName(MainWindow)
objreg.get("app").new_window.emit(self)
def __repr__(self):
return utils.get_repr(self)
@@ -417,9 +419,6 @@ class MainWindow(QWidget):
window=self.win_id)
download_count = download_manager.rowCount()
quit_texts = []
# Close if set to never ask for confirmation
if 'never' in confirm_quit:
pass
# Ask if multiple-tabs are open
if 'multiple-tabs' in confirm_quit and tab_count > 1:
quit_texts.append("{} {} open.".format(

View File

@@ -22,6 +22,7 @@
from PyQt5.QtCore import pyqtSlot
from qutebrowser.mainwindow.statusbar import textbase
from qutebrowser.browser import webview
class Percentage(textbase.TextBase):
@@ -48,7 +49,7 @@ class Percentage(textbase.TextBase):
else:
self.setText('[{:2}%]'.format(y))
@pyqtSlot(object)
@pyqtSlot(webview.WebView)
def on_tab_changed(self, tab):
"""Update scroll position when tab changed."""
self.set_perc(*tab.scroll_pos)

View File

@@ -59,7 +59,7 @@ class Progress(QProgressBar):
self.setValue(0)
self.show()
@pyqtSlot(int)
@pyqtSlot(webview.WebView)
def on_tab_changed(self, tab):
"""Set the correct value when the current tab changed."""
if self is None: # pragma: no branch

View File

@@ -24,6 +24,7 @@ from PyQt5.QtCore import pyqtSlot
from qutebrowser.config import config
from qutebrowser.mainwindow.statusbar import textbase
from qutebrowser.utils import usertypes, log, objreg
from qutebrowser.browser import webview
class Text(textbase.TextBase):
@@ -98,7 +99,7 @@ class Text(textbase.TextBase):
"""Clear jstext when page loading started."""
self._jstext = ''
@pyqtSlot(int)
@pyqtSlot(webview.WebView)
def on_tab_changed(self, tab):
"""Set the correct jstext when the current tab changed."""
self._jstext = tab.statusbar_message

View File

@@ -158,7 +158,7 @@ class UrlText(textbase.TextBase):
self._hover_url = None
self._update_url()
@pyqtSlot(int)
@pyqtSlot(webview.WebView)
def on_tab_changed(self, tab):
"""Update URL if the tab changed."""
self._hover_url = None

View File

@@ -63,7 +63,7 @@ class TabbedBrowser(tabwidget.TabWidget):
tabbar -> new-tab-position set to 'left'.
_tab_insert_idx_right: Same as above, for 'right'.
_undo_stack: List of UndoEntry namedtuples of closed tabs.
_shutting_down: Whether we're currently shutting down.
shutting_down: Whether we're currently shutting down.
Signals:
cur_progress: Progress of the current tab changed (loadProgress).
@@ -82,6 +82,7 @@ class TabbedBrowser(tabwidget.TabWidget):
widget can adjust its size to it.
arg: The new size.
current_tab_changed: The current tab changed to the emitted WebView.
new_tab: Emits the new WebView and its index when a new tab is opened.
"""
cur_progress = pyqtSignal(int)
@@ -96,13 +97,14 @@ class TabbedBrowser(tabwidget.TabWidget):
resized = pyqtSignal('QRect')
got_cmd = pyqtSignal(str)
current_tab_changed = pyqtSignal(webview.WebView)
new_tab = pyqtSignal(webview.WebView, int)
def __init__(self, win_id, parent=None):
super().__init__(win_id, parent)
self._win_id = win_id
self._tab_insert_idx_left = 0
self._tab_insert_idx_right = -1
self._shutting_down = False
self.shutting_down = False
self.tabCloseRequested.connect(self.on_tab_close_requested)
self.currentChanged.connect(self.on_current_changed)
self.cur_load_started.connect(self.on_cur_load_started)
@@ -234,7 +236,7 @@ class TabbedBrowser(tabwidget.TabWidget):
def shutdown(self):
"""Try to shut down all tabs cleanly."""
self._shutting_down = True
self.shutting_down = True
for tab in self.widgets():
self._remove_tab(tab)
@@ -272,8 +274,8 @@ class TabbedBrowser(tabwidget.TabWidget):
"""
idx = self.indexOf(tab)
if idx == -1:
raise ValueError("tab {} is not contained in TabbedWidget!".format(
tab))
raise TabDeletedError("tab {} is not contained in "
"TabbedWidget!".format(tab))
if tab is self._now_focused:
self._now_focused = None
if tab is objreg.get('last-focused-tab', None, scope='window',
@@ -303,6 +305,7 @@ class TabbedBrowser(tabwidget.TabWidget):
"""Undo removing of a tab."""
# Remove unused tab which may be created after the last tab is closed
last_close = config.get('tabs', 'last-close')
use_current_tab = False
if last_close in ['blank', 'startpage', 'default-page']:
only_one_tab_open = self.count() == 1
no_history = self.widget(0).history().count() == 1
@@ -315,12 +318,17 @@ class TabbedBrowser(tabwidget.TabWidget):
last_close_urlstr = urls[last_close].toString().rstrip('/')
first_tab_urlstr = first_tab_url.toString().rstrip('/')
last_close_url_used = first_tab_urlstr == last_close_urlstr
if only_one_tab_open and no_history and last_close_url_used:
self.removeTab(0)
use_current_tab = (only_one_tab_open and no_history and
last_close_url_used)
url, history_data = self._undo_stack.pop()
newtab = self.tabopen(url, background=False)
if use_current_tab:
self.openurl(url, newtab=False)
newtab = self.widget(0)
else:
newtab = self.tabopen(url, background=False)
qtutils.deserialize(history_data, newtab.history())
@pyqtSlot('QUrl', bool)
@@ -350,7 +358,11 @@ class TabbedBrowser(tabwidget.TabWidget):
@pyqtSlot(webview.WebView)
def on_window_close_requested(self, widget):
"""Close a tab with a widget given."""
self.close_tab(widget)
try:
self.close_tab(widget)
except TabDeletedError:
log.webview.debug("Requested to close {!r} which does not "
"exist!".format(widget))
@pyqtSlot('QUrl', bool)
def tabopen(self, url=None, background=None, explicit=False):
@@ -394,6 +406,7 @@ class TabbedBrowser(tabwidget.TabWidget):
if not background:
self.setCurrentWidget(tab)
tab.show()
self.new_tab.emit(tab, idx)
return tab
def _get_new_tab_idx(self, explicit):
@@ -542,7 +555,7 @@ class TabbedBrowser(tabwidget.TabWidget):
@pyqtSlot(int)
def on_current_changed(self, idx):
"""Set last-focused-tab and leave hinting mode when focus changed."""
if idx == -1 or self._shutting_down:
if idx == -1 or self.shutting_down:
# closing the last tab (before quitting) or shutting down
return
tab = self.widget(idx)
@@ -609,7 +622,7 @@ class TabbedBrowser(tabwidget.TabWidget):
def on_scroll_pos_changed(self):
"""Update tab and window title when scroll position changed."""
self.update_window_title()
self.update_tab_titles()
self.update_tab_title(self.currentIndex())
def resizeEvent(self, e):
"""Extend resizeEvent of QWidget to emit a resized signal afterwards.

View File

@@ -1,5 +1,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2016 Florian Bruhin (The-Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify

View File

@@ -26,6 +26,7 @@ import html
import getpass
import fnmatch
import traceback
import datetime
import pkg_resources
from PyQt5.QtCore import pyqtSlot, Qt, QSize, qVersion
@@ -35,7 +36,7 @@ from PyQt5.QtWidgets import (QDialog, QLabel, QTextEdit, QPushButton,
import qutebrowser
from qutebrowser.utils import version, log, utils, objreg, qtutils
from qutebrowser.misc import miscwidgets, autoupdate, msgbox
from qutebrowser.misc import miscwidgets, autoupdate, msgbox, httpclient
from qutebrowser.browser.network import pastebin
from qutebrowser.config import config
@@ -95,12 +96,13 @@ def get_fatal_crash_dialog(debug, data):
def _get_environment_vars():
"""Gather environment variables for the crash info."""
masks = ('DESKTOP_SESSION', 'DE', 'QT_*', 'PYTHON*', 'LC_*', 'LANG')
masks = ('DESKTOP_SESSION', 'DE', 'QT_*', 'PYTHON*', 'LC_*', 'LANG',
'XDG_*')
info = []
for key, value in os.environ.items():
for m in masks:
if fnmatch.fnmatch(key, m):
info.append('%s = %s' % (key, value))
info.append('{} = {}'.format(key, value))
return '\n'.join(sorted(info))
@@ -139,7 +141,8 @@ class _CrashDialog(QDialog):
self.setWindowTitle("Whoops!")
self.resize(QSize(640, 600))
self._vbox = QVBoxLayout(self)
self._paste_client = pastebin.PastebinClient(self)
http_client = httpclient.HTTPClient()
self._paste_client = pastebin.PastebinClient(http_client, self)
self._pypi_client = autoupdate.PyPIVersionClient(self)
self._init_text()
@@ -236,7 +239,9 @@ class _CrashDialog(QDialog):
try:
application = QApplication.instance()
launch_time = application.launch_time.ctime()
self._crash_info.append(('Launch time', launch_time))
crash_time = datetime.datetime.now().ctime()
text = 'Launch: {}\nCrash: {}'.format(launch_time, crash_time)
self._crash_info.append(('Timestamps', text))
except Exception:
self._crash_info.append(("Launch time", traceback.format_exc()))
try:
@@ -504,11 +509,23 @@ class FatalCrashDialog(_CrashDialog):
def _init_text(self):
super()._init_text()
text = ("<b>qutebrowser was restarted after a fatal crash.</b><br/>"
"<br/>Note: Crash reports for fatal crashes sometimes don't "
"QTWEBENGINE_NOTE"
"<br/>Crash reports for fatal crashes sometimes don't "
"contain the information necessary to fix an issue. Please "
"follow the steps in <a href='https://github.com/The-Compiler/"
"qutebrowser/blob/master/doc/stacktrace.asciidoc'>"
"stacktrace.asciidoc</a> to submit a stacktrace.<br/>")
if datetime.datetime.now() < datetime.datetime(2016, 4, 23):
note = ("<br/>Fatal crashes like this are often caused by the "
"current QtWebKit backend.<br/><b>I'm currently running a "
"crowdfunding for the new QtWebEngine backend, based on "
"Chromium:</b> <a href='http://igg.me/at/qutebrowser'>"
"igg.me/at/qutebrowser</a><br/>")
text = text.replace('QTWEBENGINE_NOTE', note)
else:
text = text.replace('QTWEBENGINE_NOTE', '')
self._lbl.setText(text)
def _init_checkboxes(self):

View File

@@ -22,7 +22,7 @@
import os
import sys
import bdb
import pdb
import pdb # flake8: disable=T002
import signal
import functools
import faulthandler
@@ -72,7 +72,7 @@ class CrashHandler(QObject):
def handle_segfault(self):
"""Handle a segfault from a previous run."""
data_dir = None
data_dir = standarddir.data()
if data_dir is None:
return
logname = os.path.join(data_dir, 'crash.log')

View File

@@ -1,5 +1,7 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014-2016 Florian Bruhin (The-Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify

View File

@@ -58,7 +58,8 @@ class ExternalEditor(QObject):
return
try:
os.close(self._oshandle)
os.remove(self._filename)
if self._proc.exit_status() != QProcess.CrashExit:
os.remove(self._filename)
except OSError as e:
# NOTE: Do not replace this with "raise CommandError" as it's
# executed async.
@@ -124,6 +125,6 @@ class ExternalEditor(QObject):
self._proc.error.connect(self.on_proc_error)
editor = config.get('general', 'editor')
executable = editor[0]
args = [self._filename if arg == '{}' else arg for arg in editor[1:]]
args = [arg.replace('{}', self._filename) for arg in editor[1:]]
log.procs.debug("Calling \"{}\" with args {}".format(executable, args))
self._proc.start(executable, args)

View File

@@ -160,3 +160,6 @@ class GUIProcess(QObject):
else:
message.error(self._win_id, "Error while spawning {}: {}.".format(
self._what, self._proc.error()), immediately=True)
def exit_status(self):
return self._proc.exitStatus()

View File

@@ -221,7 +221,7 @@ class IPCServer(QObject):
# This means we only use setSocketOption on Windows...
os.chmod(self._server.fullServerName(), 0o700)
@pyqtSlot(int)
@pyqtSlot('QLocalSocket::LocalSocketError')
def on_error(self, err):
"""Raise SocketError on fatal errors."""
if self._socket is None:
@@ -229,8 +229,9 @@ class IPCServer(QObject):
log.ipc.debug("In on_error with None socket!")
return
self._timer.stop()
log.ipc.debug("Socket error {}: {}".format(
self._socket.error(), self._socket.errorString()))
log.ipc.debug("Socket 0x{:x}: error {}: {}".format(
id(self._socket), self._socket.error(),
self._socket.errorString()))
if err != QLocalSocket.PeerClosedError:
raise SocketError("handling IPC connection", self._socket)
@@ -241,13 +242,14 @@ class IPCServer(QObject):
return
if self._socket is not None:
log.ipc.debug("Got new connection but ignoring it because we're "
"still handling another one.")
"still handling another one (0x{:x}).".format(
id(self._socket)))
return
socket = self._server.nextPendingConnection()
if socket is None:
log.ipc.debug("No new connection to handle.")
return
log.ipc.debug("Client connected.")
log.ipc.debug("Client connected (socket 0x{:x}).".format(id(socket)))
self._timer.start()
self._socket = socket
socket.readyRead.connect(self.on_ready_read)
@@ -267,7 +269,8 @@ class IPCServer(QObject):
@pyqtSlot()
def on_disconnected(self):
"""Clean up socket when the client disconnected."""
log.ipc.debug("Client disconnected.")
log.ipc.debug("Client disconnected from socket 0x{:x}.".format(
id(self._socket)))
self._timer.stop()
if self._socket is None:
log.ipc.debug("In on_disconnected with None socket!")
@@ -279,11 +282,61 @@ class IPCServer(QObject):
def _handle_invalid_data(self):
"""Handle invalid data we got from a QLocalSocket."""
log.ipc.error("Ignoring invalid IPC data.")
log.ipc.error("Ignoring invalid IPC data from socket 0x{:x}.".format(
id(self._socket)))
self.got_invalid_data.emit()
self._socket.error.connect(self.on_error)
self._socket.disconnectFromServer()
def _handle_data(self, data):
"""Handle data (as bytes) we got from on_ready_ready_read."""
try:
decoded = data.decode('utf-8')
except UnicodeDecodeError:
log.ipc.error("invalid utf-8: {}".format(
binascii.hexlify(data)))
self._handle_invalid_data()
return
log.ipc.debug("Processing: {}".format(decoded))
try:
json_data = json.loads(decoded)
except ValueError:
log.ipc.error("invalid json: {}".format(decoded.strip()))
self._handle_invalid_data()
return
for name in ('args', 'target_arg'):
if name not in json_data:
log.ipc.error("Missing {}: {}".format(name, decoded.strip()))
self._handle_invalid_data()
return
try:
protocol_version = int(json_data['protocol_version'])
except (KeyError, ValueError):
log.ipc.error("invalid version: {}".format(decoded.strip()))
self._handle_invalid_data()
return
if protocol_version != PROTOCOL_VERSION:
log.ipc.error("incompatible version: expected {}, got {}".format(
PROTOCOL_VERSION, protocol_version))
self._handle_invalid_data()
return
args = json_data['args']
target_arg = json_data['target_arg']
if target_arg is None:
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-April/037375.html
target_arg = ''
cwd = json_data.get('cwd', '')
assert cwd is not None
self.got_args.emit(args, target_arg, cwd)
@pyqtSlot()
def on_ready_read(self):
"""Read json data from the client."""
@@ -292,56 +345,20 @@ class IPCServer(QObject):
# active for some reason.
log.ipc.warning("In on_ready_read with None socket!")
return
self._timer.start()
self._timer.stop()
while self._socket is not None and self._socket.canReadLine():
data = bytes(self._socket.readLine())
self.got_raw.emit(data)
log.ipc.debug("Read from socket: {}".format(data))
try:
decoded = data.decode('utf-8')
except UnicodeDecodeError:
log.ipc.error("invalid utf-8: {}".format(
binascii.hexlify(data)))
self._handle_invalid_data()
return
log.ipc.debug("Processing: {}".format(decoded))
try:
json_data = json.loads(decoded)
except ValueError:
log.ipc.error("invalid json: {}".format(decoded.strip()))
self._handle_invalid_data()
return
for name in ('args', 'target_arg'):
if name not in json_data:
log.ipc.error("Missing {}: {}".format(name,
decoded.strip()))
self._handle_invalid_data()
return
try:
protocol_version = int(json_data['protocol_version'])
except (KeyError, ValueError):
log.ipc.error("invalid version: {}".format(decoded.strip()))
self._handle_invalid_data()
return
if protocol_version != PROTOCOL_VERSION:
log.ipc.error("incompatible version: expected {}, "
"got {}".format(
PROTOCOL_VERSION, protocol_version))
self._handle_invalid_data()
return
cwd = json_data.get('cwd', None)
self.got_args.emit(json_data['args'], json_data['target_arg'], cwd)
log.ipc.debug("Read from socket 0x{:x}: {}".format(
id(self._socket), data))
self._handle_data(data)
self._timer.start()
@pyqtSlot()
def on_timeout(self):
"""Cancel the current connection if it was idle for too long."""
log.ipc.error("IPC connection timed out.")
log.ipc.error("IPC connection timed out "
"(socket 0x{:x}).".format(id(self._socket)))
self._socket.disconnectFromServer()
if self._socket is not None: # pragma: no cover
# on_socket_disconnected sets it to None
@@ -369,7 +386,8 @@ class IPCServer(QObject):
def shutdown(self):
"""Shut down the IPC server cleanly."""
log.ipc.debug("Shutting down IPC")
log.ipc.debug("Shutting down IPC (socket 0x{:x})".format(
id(self._socket)))
if self._socket is not None:
self._socket.deleteLater()
self._socket = None

View File

@@ -20,9 +20,9 @@
"""Misc. widgets used at different places."""
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QSize
from PyQt5.QtWidgets import (QLineEdit, QApplication, QWidget, QHBoxLayout,
QLabel, QStyleOption, QStyle)
from PyQt5.QtGui import QValidator, QClipboard, QPainter
from PyQt5.QtWidgets import (QLineEdit, QWidget, QHBoxLayout, QLabel,
QStyleOption, QStyle)
from PyQt5.QtGui import QValidator, QPainter
from qutebrowser.utils import utils
from qutebrowser.misc import cmdhistory
@@ -42,6 +42,19 @@ class MinimalLineEditMixin:
""")
self.setAttribute(Qt.WA_MacShowFocusRect, False)
def keyPressEvent(self, e):
"""Override keyPressEvent to paste primary selection on Shift + Ins."""
if e.key() == Qt.Key_Insert and e.modifiers() == Qt.ShiftModifier:
try:
text = utils.get_clipboard(selection=True)
except utils.SelectionUnsupportedError:
pass
else:
e.accept()
self.insert(text)
return
super().keyPressEvent(e)
def __repr__(self):
return utils.get_repr(self)
@@ -98,17 +111,6 @@ class CommandLineEdit(QLineEdit):
if mark:
self.setSelection(self._promptlen, oldpos - self._promptlen)
def keyPressEvent(self, e):
"""Override keyPressEvent to paste primary selection on Shift + Ins."""
if e.key() == Qt.Key_Insert and e.modifiers() == Qt.ShiftModifier:
clipboard = QApplication.clipboard()
if clipboard.supportsSelection():
e.accept()
text = clipboard.text(QClipboard.Selection)
self.insert(text)
return
super().keyPressEvent(e)
class _CommandValidator(QValidator):

View File

@@ -86,9 +86,9 @@ class Saveable:
(not config.get(*self._config_opt)) and
(not explicit) and (not force)):
if not silent:
log.save.debug("Not saving {} because autosaving has been "
log.save.debug("Not saving {name} because autosaving has been "
"disabled by {cfg[0]} -> {cfg[1]}.".format(
self._name, cfg=self._config_opt))
name=self._name, cfg=self._config_opt))
return
do_save = self._dirty or (self._save_on_exit and is_exit) or force
if not silent:

View File

@@ -143,10 +143,20 @@ class SessionManager(QObject):
history = tab.page().history()
for idx, item in enumerate(history.items()):
qtutils.ensure_valid(item)
item_data = {
'url': bytes(item.url().toEncoded()).decode('ascii'),
'title': item.title(),
}
if item.title():
item_data['title'] = item.title()
else:
# https://github.com/The-Compiler/qutebrowser/issues/879
if history.currentItemIndex() == idx:
item_data['title'] = tab.page().mainFrame().title()
else:
item_data['title'] = item_data['url']
if item.originalUrl() != item.url():
encoded = item.originalUrl().toEncoded()
item_data['original-url'] = bytes(encoded).decode('ascii')
@@ -231,7 +241,9 @@ class SessionManager(QObject):
log.sessions.debug("Saving session {} to {}...".format(name, path))
if last_window:
data = self._last_window_session
assert data is not None
if data is None:
log.sessions.error("last_window_session is None while saving!")
return
else:
data = self._save_all()
log.sessions.vdebug("Saving data: {}".format(data))

View File

@@ -29,12 +29,14 @@ except ImportError:
hunter = None
from qutebrowser.browser.network import qutescheme
from qutebrowser.utils import log, objreg, usertypes, message, debug
from qutebrowser.utils import log, objreg, usertypes, message, debug, utils
from qutebrowser.commands import cmdutils, runners, cmdexc
from qutebrowser.config import style
from qutebrowser.misc import consolewidget
from PyQt5.QtCore import QUrl
# so it's available for :debug-pyeval
from PyQt5.QtWidgets import QApplication # pylint: disable=unused-import
@cmdutils.register(maxsplit=1, no_cmd_split=True, win_id='win_id')
@@ -176,18 +178,36 @@ def debug_trace(expr=""):
@cmdutils.register(maxsplit=0, debug=True, no_cmd_split=True)
def debug_pyeval(s):
def debug_pyeval(s, quiet=False):
"""Evaluate a python string and display the results as a web page.
Args:
s: The string to evaluate.
quiet: Don't show the output in a new tab.
"""
try:
r = eval(s)
out = repr(r)
except Exception:
out = traceback.format_exc()
qutescheme.pyeval_output = out
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window='last-focused')
tabbed_browser.openurl(QUrl('qute:pyeval'), newtab=True)
if quiet:
log.misc.debug("pyeval output: {}".format(out))
else:
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window='last-focused')
tabbed_browser.openurl(QUrl('qute:pyeval'), newtab=True)
@cmdutils.register(debug=True)
def debug_set_fake_clipboard(s=None):
"""Put data into the fake clipboard and enable logging, used for tests.
Args:
s: The text to put into the fake clipboard, or unset to enable logging.
"""
if s is None:
utils.log_clipboard = True
else:
utils.fake_clipboard = s

View File

@@ -70,10 +70,13 @@ def get_argparser():
help="How URLs should be opened if there is already a "
"qutebrowser instance running.")
parser.add_argument('--json-args', help=argparse.SUPPRESS)
parser.add_argument('--temp-basedir-restarted', help=argparse.SUPPRESS)
debug = parser.add_argument_group('debug arguments')
debug.add_argument('-l', '--loglevel', dest='loglevel',
help="Set loglevel", default='info')
help="Set loglevel", default='info',
choices=['critical', 'error', 'warning', 'info',
'debug', 'vdebug'])
debug.add_argument('--logfilter',
help="Comma-separated list of things to be logged "
"to the debug log on stdout.")
@@ -129,7 +132,6 @@ def get_argparser():
def main():
"""Main entry point for qutebrowser."""
parser = get_argparser()
if sys.platform == 'darwin' and getattr(sys, 'frozen', False):
# Ignore Mac OS X' idiotic -psn_* argument...

View File

@@ -21,10 +21,12 @@
import os
import os.path
import traceback
import jinja2
import jinja2.exceptions
from qutebrowser.utils import utils
from qutebrowser.utils import utils, log
from PyQt5.QtCore import QUrl
@@ -71,5 +73,28 @@ def resource_url(path):
image = utils.resource_filename(path)
return QUrl.fromLocalFile(image).toString(QUrl.FullyEncoded)
env = jinja2.Environment(loader=Loader('html'), autoescape=_guess_autoescape)
env.globals['resource_url'] = resource_url
def file_url(path):
"""Return a file:// url (as string) to the given local path.
Arguments:
path: The absolute path to the local file
"""
return QUrl.fromLocalFile(path).toString(QUrl.FullyEncoded)
def render(template, **kwargs):
"""Render the given template and pass the given arguments to it."""
try:
return _env.get_template(template).render(**kwargs)
except jinja2.exceptions.UndefinedError:
log.misc.exception("UndefinedError while rendering " + template)
err_path = os.path.join('html', 'undef_error.html')
err_template = utils.read_file(err_path)
tb = traceback.format_exc()
return err_template.format(pagename=template, traceback=tb)
_env = jinja2.Environment(loader=Loader('html'), autoescape=_guess_autoescape)
_env.globals['resource_url'] = resource_url
_env.globals['file_url'] = file_url

View File

@@ -51,10 +51,11 @@ else:
colorama.deinit()
# Log formats to use.
SIMPLE_FMT = '{levelname}: {message}'
SIMPLE_FMT = '{asctime:8} {levelname}: {message}'
EXTENDED_FMT = ('{asctime:8} {levelname:8} {name:10} {module}:{funcName}:'
'{lineno} {message}')
SIMPLE_FMT_COLORED = '%(log_color)s%(levelname)s%(reset)s: %(message)s'
SIMPLE_FMT_COLORED = ('%(green)s%(asctime)-8s%(reset)s '
'%(log_color)s%(levelname)s%(reset)s: %(message)s')
EXTENDED_FMT_COLORED = (
'%(green)s%(asctime)-8s%(reset)s '
'%(log_color)s%(levelname)-8s%(reset)s '
@@ -274,7 +275,7 @@ def qt_message_handler(msg_type, context, msg):
# PNGs in Qt with broken color profile
# https://bugreports.qt.io/browse/QTBUG-39788
'libpng warning: iCCP: Not recognizing known sRGB profile that has '
'been edited', # noqa
'been edited', # flake8: disable=E131
'libpng warning: iCCP: known incorrect sRGB profile',
# Hopefully harmless warning
'OpenType support missing for script ',
@@ -294,6 +295,8 @@ def qt_message_handler(msg_type, context, msg):
# Hopefully harmless
'"Method "GetAll" with signature "s" on interface '
'"org.freedesktop.DBus.Properties" doesn\'t exist',
'"Method \\"GetAll\\" with signature \\"s\\" on interface '
'\\"org.freedesktop.DBus.Properties\\" doesn\'t exist\\n"',
'WOFF support requires QtWebKit to be built with zlib support.',
# Weird Enlightment/GTK X extensions
'QXcbWindow: Unhandled client message: "_E_',
@@ -312,7 +315,7 @@ def qt_message_handler(msg_type, context, msg):
'libpng warning: iCCP: known incorrect sRGB profile',
# https://bugreports.qt.io/browse/QTBUG-47154
'virtual void QSslSocketBackendPrivate::transmit() SSLRead failed '
'with: -9805', # noqa
'with: -9805', # flake8: disable=E131
]
# Messages which will trigger an exception immediately

View File

@@ -25,7 +25,7 @@ import os.path
from PyQt5.QtCore import QCoreApplication, QStandardPaths
from qutebrowser.utils import log, qtutils
from qutebrowser.utils import log, qtutils, debug
# The argparse namespace passed to init()
@@ -65,6 +65,17 @@ def data():
return path
def system_data():
"""Get a location for system-wide data. This path may be read-only."""
if sys.platform.startswith('linux'):
path = "/usr/share/qutebrowser"
if not os.path.exists(path):
path = data()
else:
path = data()
return path
def cache():
"""Get a location for the cache."""
typ = QStandardPaths.CacheLocation
@@ -113,6 +124,8 @@ def _writable_location(typ):
"""Wrapper around QStandardPaths.writableLocation."""
with qtutils.unset_organization():
path = QStandardPaths.writableLocation(typ)
typ_str = debug.qenum_key(QStandardPaths, typ)
log.misc.debug("writable location for {}: {}".format(typ_str, path))
if not path:
raise ValueError("QStandardPaths returned an empty value!")
# Qt seems to use '/' as path separator even on Windows...

View File

@@ -74,11 +74,13 @@ def _parse_search_term(s):
term = s
else:
term = split[1]
elif not split:
raise ValueError("Empty search term!")
else:
engine = None
term = s
log.url.debug("engine {}, term '{}'".format(engine, term))
log.url.debug("engine {}, term {!r}".format(engine, term))
return (engine, term)
@@ -91,7 +93,7 @@ def _get_search_url(txt):
Return:
The search URL as a QUrl.
"""
log.url.debug("Finding search engine for '{}'".format(txt))
log.url.debug("Finding search engine for {!r}".format(txt))
engine, term = _parse_search_term(txt)
assert term
if engine is None:
@@ -168,24 +170,13 @@ def fuzzy_url(urlstr, cwd=None, relative=False, do_search=True):
Return:
A target QUrl to a search page or the original URL.
"""
expanded = os.path.expanduser(urlstr)
if os.path.isabs(expanded):
path = expanded
elif relative and cwd:
path = os.path.join(cwd, expanded)
elif relative:
try:
path = os.path.abspath(expanded)
except OSError:
path = None
else:
path = None
urlstr = urlstr.strip()
path = get_path_if_valid(urlstr, cwd=cwd, relative=relative,
check_exists=True)
stripped = urlstr.strip()
if path is not None and os.path.exists(path):
log.url.debug("URL is a local file")
if path is not None:
url = QUrl.fromLocalFile(path)
elif (not do_search) or is_url(stripped):
elif (not do_search) or is_url(urlstr):
# probably an address
log.url.debug("URL is a fuzzy address")
url = qurl_from_user_input(urlstr)
@@ -194,10 +185,10 @@ def fuzzy_url(urlstr, cwd=None, relative=False, do_search=True):
try:
url = _get_search_url(urlstr)
except ValueError: # invalid search engine
url = qurl_from_user_input(stripped)
log.url.debug("Converting fuzzy term {} to URL -> {}".format(
url = qurl_from_user_input(urlstr)
log.url.debug("Converting fuzzy term {!r} to URL -> {}".format(
urlstr, url.toDisplayString()))
if do_search and config.get('general', 'auto-search'):
if do_search and config.get('general', 'auto-search') and urlstr:
qtutils.ensure_valid(url)
else:
if not url.isValid():
@@ -215,9 +206,9 @@ def _has_explicit_scheme(url):
# after the scheme delimiter. Since we don't know of any URIs
# using this and want to support e.g. searching for scoped C++
# symbols, we treat this as not an URI anyways.
return (url.isValid() and url.scheme()
and not url.path().startswith(' ')
and not url.path().startswith(':'))
return (url.isValid() and url.scheme() and
not url.path().startswith(' ') and
not url.path().startswith(':'))
def is_special_url(url):
@@ -243,7 +234,7 @@ def is_url(urlstr):
"""
autosearch = config.get('general', 'auto-search')
log.url.debug("Checking if '{}' is a URL (autosearch={}).".format(
log.url.debug("Checking if {!r} is a URL (autosearch={}).".format(
urlstr, autosearch))
urlstr = urlstr.strip()
@@ -253,8 +244,12 @@ def is_url(urlstr):
if not autosearch:
# no autosearch, so everything is a URL unless it has an explicit
# search engine.
engine, _term = _parse_search_term(urlstr)
return engine is None
try:
engine, _term = _parse_search_term(urlstr)
except ValueError:
return False
else:
return engine is None
if not qurl_userinput.isValid():
# This will also catch URLs containing spaces.
@@ -342,6 +337,44 @@ def raise_cmdexc_if_invalid(url):
raise cmdexc.CommandError(get_errstring(url))
def get_path_if_valid(pathstr, cwd=None, relative=False, check_exists=False):
"""Check if path is a valid path.
Args:
pathstr: The path as string.
cwd: The current working directory, or None.
relative: Whether to resolve relative files.
check_exists: Whether to check if the file
actually exists of filesystem.
Return:
The path if it is a valid path, None otherwise.
"""
pathstr = pathstr.strip()
log.url.debug("Checking if {!r} is a path".format(pathstr))
expanded = os.path.expanduser(pathstr)
if os.path.isabs(expanded):
path = expanded
elif relative and cwd:
path = os.path.join(cwd, expanded)
elif relative:
try:
path = os.path.abspath(expanded)
except OSError:
path = None
else:
path = None
if check_exists:
if path is not None and os.path.exists(path):
log.url.debug("URL is a local file")
else:
path = None
return path
def filename_from_url(url):
"""Get a suitable filename from an URL.
@@ -462,6 +495,28 @@ class IncDecError(Exception):
return '{}: {}'.format(self.msg, self.url.toString())
def _get_incdec_value(match, incdec, url):
"""Get a incremented/decremented URL based on a URL match."""
pre, zeroes, number, post = match.groups()
# This should always succeed because we match \d+
val = int(number)
if incdec == 'decrement':
if val <= 0:
raise IncDecError("Can't decrement {}!".format(val), url)
val -= 1
elif incdec == 'increment':
val += 1
else:
raise ValueError("Invalid value {} for indec!".format(incdec))
if zeroes:
if len(number) < len(str(val)):
zeroes = zeroes[1:]
elif len(number) > len(str(val)):
zeroes += '0'
return ''.join([pre, zeroes, str(val), post])
def incdec_number(url, incdec, segments=None):
"""Find a number in the url and increment or decrement it.
@@ -503,23 +558,11 @@ def incdec_number(url, incdec, segments=None):
continue
# Get the last number in a string
match = re.match(r'(.*\D|^)(\d+)(.*)', getter())
match = re.match(r'(.*\D|^)(0*)(\d+)(.*)', getter())
if not match:
continue
pre, number, post = match.groups()
# This should always succeed because we match \d+
val = int(number)
if incdec == 'decrement':
if val <= 0:
raise IncDecError("Can't decrement {}!".format(val), url)
val -= 1
elif incdec == 'increment':
val += 1
else:
raise ValueError("Invalid value {} for indec!".format(incdec))
new_value = ''.join([pre, str(val), post])
setter(new_value)
setter(_get_incdec_value(match, incdec, url))
return url
raise IncDecError("No number found in URL!", url)

View File

@@ -237,7 +237,7 @@ KeyMode = enum('KeyMode', ['normal', 'hint', 'command', 'yesno', 'prompt',
# Available command completions
Completion = enum('Completion', ['command', 'section', 'option', 'value',
'helptopic', 'quickmark_by_name',
'bookmark_by_url', 'url', 'sessions'])
'bookmark_by_url', 'url', 'tab', 'sessions'])
# Exit statuses for errors. Needs to be an int for sys.exit.

View File

@@ -22,6 +22,7 @@
import io
import sys
import enum
import json
import os.path
import collections
import functools
@@ -29,13 +30,23 @@ import contextlib
import itertools
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QKeySequence, QColor
from PyQt5.QtGui import QKeySequence, QColor, QClipboard
from PyQt5.QtWidgets import QApplication
import pkg_resources
import qutebrowser
from qutebrowser.utils import qtutils, log
fake_clipboard = None
log_clipboard = False
class SelectionUnsupportedError(Exception):
"""Raised if [gs]et_clipboard is used and selection=True is unsupported."""
def elide(text, length):
"""Elide text so it uses a maximum of length chars."""
if length < 1:
@@ -743,3 +754,33 @@ def newest_slice(iterable, count):
return iterable
else:
return itertools.islice(iterable, len(iterable) - count, len(iterable))
def set_clipboard(data, selection=False):
"""Set the clipboard to some given data."""
clipboard = QApplication.clipboard()
if selection and not clipboard.supportsSelection():
raise SelectionUnsupportedError
if log_clipboard:
what = 'primary selection' if selection else 'clipboard'
log.misc.debug("Setting fake {}: {}".format(what, json.dumps(data)))
else:
mode = QClipboard.Selection if selection else QClipboard.Clipboard
clipboard.setText(data, mode=mode)
def get_clipboard(selection=False):
"""Get data from the clipboard."""
global fake_clipboard
clipboard = QApplication.clipboard()
if selection and not clipboard.supportsSelection():
raise SelectionUnsupportedError
if fake_clipboard is not None:
data = fake_clipboard
fake_clipboard = None
else:
mode = QClipboard.Selection if selection else QClipboard.Clipboard
data = clipboard.text(mode=mode)
return data

View File

@@ -192,16 +192,20 @@ def _pdfjs_version():
A string with the version number.
"""
try:
pdfjs_file = pdfjs.get_pdfjs_res('build/pdf.js').decode('utf-8')
pdfjs_file, file_path = pdfjs.get_pdfjs_res_and_path('build/pdf.js')
except pdfjs.PDFJSNotFound:
return 'no'
else:
pdfjs_file = pdfjs_file.decode('utf-8')
version_re = re.compile(r"^PDFJS\.version = '([^']+)';$", re.MULTILINE)
match = version_re.search(pdfjs_file)
if not match:
return 'unknown'
pdfjs_version = 'unknown'
else:
return match.group(1)
pdfjs_version = match.group(1)
if file_path is None:
file_path = 'bundled'
return '{} ({})'.format(pdfjs_version, file_path)
def version(short=False):

View File

@@ -1,10 +1,8 @@
Jinja2==2.8.0
MarkupSafe==0.23
Pygments==2.0.2
Pygments==2.1.3
pyPEG2==2.15.2
PyYAML==3.11
# "ValueError: I/O operation on closed file" with pytest since 0.3.5
# WORKAROUND for https://github.com/tartley/colorama/issues/81
colorama==0.3.3 # rq.filter: <=0.3.3
colorlog==2.6.0
colorama==0.3.7
colorlog==2.6.1
cssutils==1.0.1

View File

@@ -43,6 +43,7 @@ class AsciiDoc:
FILES = [
('FAQ.asciidoc', 'qutebrowser/html/doc/FAQ.html'),
('CHANGELOG.asciidoc', 'qutebrowser/html/doc/CHANGELOG.html'),
('CONTRIBUTING.asciidoc', 'qutebrowser/html/doc/CONTRIBUTING.html'),
('doc/quickstart.asciidoc', 'qutebrowser/html/doc/quickstart.html'),
('doc/userscripts.asciidoc', 'qutebrowser/html/doc/userscripts.html'),
]
@@ -75,6 +76,7 @@ class AsciiDoc:
self._build_website()
else:
self._build_docs()
self._copy_images()
def _build_docs(self):
"""Render .asciidoc files to .html sites."""
@@ -83,8 +85,38 @@ class AsciiDoc:
name, _ext = os.path.splitext(os.path.basename(src))
dst = 'qutebrowser/html/doc/{}.html'.format(name)
files.append((src, dst))
# patch image links to use local copy
replacements = [
("http://qutebrowser.org/img/cheatsheet-big.png",
"qute://help/img/cheatsheet-big.png"),
("http://qutebrowser.org/img/cheatsheet-small.png",
"qute://help/img/cheatsheet-small.png")
]
for src, dst in files:
self.call(src, dst)
src_basename = os.path.basename(src)
modified_src = os.path.join(self._tempdir, src_basename)
with open(modified_src, 'w', encoding='utf-8') as modified_f, \
open(src, 'r', encoding='utf-8') as f:
for line in f:
for orig, repl in replacements:
line = line.replace(orig, repl)
modified_f.write(line)
self.call(modified_src, dst)
def _copy_images(self):
"""Copy image files to qutebrowser/html/doc."""
print("Copying files...")
dst_path = os.path.join('qutebrowser', 'html', 'doc', 'img')
try:
os.mkdir(dst_path)
except FileExistsError:
pass
for filename in ['cheatsheet-big.png', 'cheatsheet-small.png']:
src = os.path.join('doc', 'img', filename)
dst = os.path.join(dst_path, filename)
shutil.copy(src, dst)
def _build_website_file(self, root, filename):
"""Build a single website file."""
@@ -248,6 +280,8 @@ def main(colors=False):
"asciidoc.py. If not given, it's searched in PATH.",
nargs=2, required=False,
metavar=('PYTHON', 'ASCIIDOC'))
parser.add_argument('--no-authors', help=argparse.SUPPRESS,
action='store_true')
args = parser.parse_args()
try:
os.mkdir('qutebrowser/html/doc')

View File

@@ -91,7 +91,7 @@ def smoke_test(executable):
def build_windows():
"""Build windows executables/setups."""
utils.print_title("Updating 3rdparty content")
update_3rdparty.main()
update_3rdparty.update_pdfjs()
utils.print_title("Building Windows binaries")
parts = str(sys.version_info.major), str(sys.version_info.minor)
@@ -182,7 +182,6 @@ def build_sdist():
def main():
"""Main entry point."""
parser = argparse.ArgumentParser()
parser.add_argument('--asciidoc', help="Full path to python and "
"asciidoc.py. If not given, it's searched in PATH.",

View File

@@ -65,6 +65,8 @@ PERFECT_FILES = [
'qutebrowser/browser/network/filescheme.py'),
('tests/unit/browser/network/test_networkreply.py',
'qutebrowser/browser/network/networkreply.py'),
('tests/unit/browser/network/test_pastebin.py',
'qutebrowser/browser/network/pastebin.py'),
('tests/unit/browser/test_signalfilter.py',
'qutebrowser/browser/signalfilter.py'),
@@ -100,6 +102,10 @@ PERFECT_FILES = [
'qutebrowser/mainwindow/statusbar/tabindex.py'),
('tests/unit/mainwindow/statusbar/test_textbase.py',
'qutebrowser/mainwindow/statusbar/textbase.py'),
('tests/unit/mainwindow/statusbar/test_prompt.py',
'qutebrowser/mainwindow/statusbar/prompt.py'),
('tests/unit/mainwindow/statusbar/test_url.py',
'qutebrowser/mainwindow/statusbar/url.py'),
('tests/unit/config/test_configtypes.py',
'qutebrowser/config/configtypes.py'),
@@ -133,6 +139,10 @@ PERFECT_FILES = [
]
# 100% coverage because of integration tests, but no perfect unit tests yet.
WHITELISTED_FILES = []
class Skipped(Exception):
"""Exception raised when skipping coverage checks."""
@@ -199,7 +209,8 @@ def check(fileobj, perfect_files):
text = "{} has {}% line and {}% branch coverage!".format(
filename, line_cov, branch_cov)
messages.append(Message(MsgType.insufficent_coverage, text))
elif filename not in perfect_src_files and not is_bad:
elif (filename not in perfect_src_files and not is_bad and
filename not in WHITELISTED_FILES):
text = ("{} has 100% coverage but is not in "
"perfect_files!".format(filename))
messages.append(Message(MsgType.perfect_file, text))
@@ -216,8 +227,16 @@ def main_check():
print(e)
messages = []
for msg in messages:
print(msg.text)
if messages:
print()
print()
utils.print_title("Coverage check failed")
for msg in messages:
print(msg.text)
print()
print("You can run 'tox -e py35-cov' (or py34-cov) locally and check "
"htmlcov/index.html to debug this.")
print()
if 'CI' in os.environ:
print("Keeping coverage.xml on CI.")
@@ -257,11 +276,6 @@ def main_check_all():
def main():
"""Main entry point.
Return:
The return code to return.
"""
utils.change_cwd()
if '--check-all' in sys.argv:
return main_check_all()

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016 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/>.
"""Check if docs changed and output an error if so."""
import sys
import subprocess
code = subprocess.call(['git', '--no-pager', 'diff', '--exit-code', '--stat'])
if code != 0:
print()
print('The autogenerated docs changed, please run this to update them:')
print(' tox -e docs')
print(' git commit -am "Update docs"')
print()
print('(Or you have uncommitted changes, in which case you can ignore '
'this.)')
sys.exit(code)

View File

@@ -29,35 +29,51 @@ CI machines.
from __future__ import print_function
import os
import re
import sys
import subprocess
import urllib
import contextlib
try:
import _winreg as winreg
except ImportError:
winreg = None
TESTENV = os.environ['TESTENV']
TESTENV = os.environ.get('TESTENV', None)
TRAVIS_OS = os.environ.get('TRAVIS_OS_NAME', None)
INSTALL_PYQT = TESTENV in ('py34', 'py35', 'unittests-nodisp', 'vulture',
'pylint')
INSTALL_PYQT = TESTENV in ('py34', 'py35', 'py34-cov', 'py35-cov',
'unittests-nodisp', 'vulture', 'pylint', 'docs')
XVFB = TRAVIS_OS == 'linux' and TESTENV == 'py34'
pip_packages = ['tox']
if TESTENV in ['py34', 'py35'] and TRAVIS_OS == 'linux':
if TESTENV is not None and TESTENV.endswith('-cov'):
pip_packages.append('codecov')
def apt_get(args):
subprocess.check_call(['sudo', 'apt-get', '-y', '-q'] + args)
def brew(args, silent=False):
if silent:
with open(os.devnull, 'w') as f:
subprocess.check_call(['brew'] + args, stdout=f)
@contextlib.contextmanager
def travis_fold(text):
if 'TRAVIS' in os.environ:
marker = re.compile(r'\W+').sub('-', text.lower()).strip('-')
print("travis_fold:start:{}".format(marker))
yield
print("travis_fold:end:{}".format(marker))
else:
subprocess.check_call(['brew'] + args + ['--verbose'])
yield
def folded_cmd(argv):
"""Output a command with travis folding markers."""
with travis_fold(''.join(argv)):
print(" $ " + ' '.join(argv))
subprocess.check_call(argv)
def apt_get(args):
folded_cmd(['sudo', 'apt-get', '-y', '-q'] + args)
def brew(args):
folded_cmd(['brew'] + args)
def check_setup(executable):
@@ -65,6 +81,7 @@ def check_setup(executable):
print("Checking setup...")
subprocess.check_call([executable, '-c', 'import PyQt5'])
subprocess.check_call([executable, '-c', 'import sip'])
subprocess.check_call([executable, '--version'])
if 'APPVEYOR' in os.environ:
@@ -85,21 +102,18 @@ if 'APPVEYOR' in os.environ:
print("Installing PyQt5...")
subprocess.check_call([r'C:\install-PyQt5.exe', '/S'])
print("Installing tox...")
subprocess.check_call([r'C:\Python34\Scripts\pip', 'install', '-U'] +
pip_packages)
folded_cmd([r'C:\Python34\Scripts\pip', 'install', '-U'] + pip_packages)
print("Linking Python...")
with open(r'C:\Windows\system32\python3.bat', 'w') as f:
f.write(r'@C:\Python34\python %*')
check_setup(r'C:\Python34\python')
elif TRAVIS_OS == 'linux' and 'DOCKER' in os.environ:
pass
elif TRAVIS_OS == 'linux':
print("travis_fold:start:ci_install")
print("Installing via pip...")
subprocess.check_call(['sudo', 'pip', 'install'] + pip_packages)
folded_cmd(['sudo', 'pip', 'install'] + pip_packages)
print("Installing packages...")
pkgs = []
if XVFB:
@@ -108,33 +122,35 @@ elif TRAVIS_OS == 'linux':
pkgs += ['python3-pyqt5', 'python3-pyqt5.qtwebkit']
if TESTENV == 'eslint':
pkgs += ['npm', 'nodejs', 'nodejs-legacy']
if TESTENV == 'docs':
pkgs += ['asciidoc']
if pkgs:
print("apt-get update...")
apt_get(['update'])
print("apt-get install...")
apt_get(['install'] + pkgs)
if TESTENV == 'flake8':
apt_get(['update'])
# We need an up-to-date Python because of:
# https://github.com/google/yapf/issues/46
apt_get(['install', '-t', 'trusty-updates', 'python3.4'])
if TESTENV == 'eslint':
subprocess.check_call(['sudo', 'npm', 'install', '-g', 'eslint'])
folded_cmd(['sudo', 'npm', 'install', '-g', 'eslint'])
else:
check_setup('python3')
print("travis_fold:end:ci_install")
elif TRAVIS_OS == 'osx':
print("Disabling App Nap...")
subprocess.check_call(['defaults', 'write', 'NSGlobalDomain',
'NSAppSleepDisabled', '-bool', 'YES'])
print("brew update...")
brew(['update'], silent=True)
brew(['update'])
print("Installing packages...")
pkgs = ['python3']
if INSTALL_PYQT:
pkgs.append('pyqt5')
brew(['install'] + pkgs)
brew(['install', '--verbose'] + pkgs)
print("Installing tox/codecov...")
subprocess.check_call(['sudo', 'pip3', 'install'] + pip_packages)
folded_cmd(['sudo', 'pip3', 'install'] + pip_packages)
check_setup('python3')
else:

View File

@@ -0,0 +1,15 @@
#!/bin/bash
if [[ $DOCKER ]]; then
# To build a fresh image:
# docker build -t img misc/docker/$DOCKER
# docker run --privileged -v $PWD:/outside img
docker run --privileged -v $PWD:/outside \
thecompiler/qutebrowser-manual:$DOCKER
else
args=()
[[ $TESTENV == docs ]] && args=('--no-authors')
tox -e $TESTENV -- "${args[@]}"
fi

View File

@@ -86,7 +86,9 @@ def get_build_exe_options(skip_html=False):
'include_msvcr': True,
'includes': [],
'excludes': ['tkinter'],
'packages': ['pygments'],
'packages': ['pygments', 'pkg_resources._vendor.packaging',
'pkg_resources._vendor.pyparsing',
'pkg_resources._vendor.six'],
}
@@ -100,7 +102,6 @@ def get_exe(base, target_name):
def main():
"""Main entry point."""
if sys.platform.startswith('win'):
base = 'Win32GUI'
target_name = 'qutebrowser.exe'

View File

@@ -55,9 +55,8 @@ def get_build_exe_options():
opts = freeze.get_build_exe_options(skip_html=True)
opts['includes'] += pytest.freeze_includes() # pylint: disable=no-member
opts['includes'] += ['unittest.mock', 'PyQt5.QtTest', 'hypothesis', 'bs4',
'httpbin', 'jinja2.ext', 'xvfbwrapper',
'cherrypy.wsgiserver',
'cherrypy.wsgiserver.wsgiserver3']
'httpbin', 'jinja2.ext', 'cherrypy.wsgiserver',
'cherrypy.wsgiserver.wsgiserver3', 'pstats']
httpbin_dir = os.path.dirname(httpbin.__file__)
opts['include_files'] += [
@@ -70,7 +69,6 @@ def get_build_exe_options():
def main():
"""Main entry point."""
base = 'Win32GUI' if sys.platform.startswith('win') else None
with temp_git_commit_file():
cx.setup(

View File

@@ -135,7 +135,6 @@ def check_prerequisites():
def main():
"""Main entry point."""
check_prerequisites()
parser = argparse.ArgumentParser()

View File

@@ -141,7 +141,6 @@ def check_vcs_conflict():
def main():
"""Main entry point."""
parser = argparse.ArgumentParser()
parser.add_argument('checker', choices=('git', 'vcs', 'spelling'),
help="Which checker to run.")

View File

@@ -41,7 +41,8 @@ class ConfigChecker(checkers.BaseChecker):
__implements__ = interfaces.IAstroidChecker
name = 'config'
msgs = {
'E0000': ('"%s -> %s" is no valid config option.', 'bad-config-call',
'E0000': ('"%s -> %s" is no valid config option.', # flake8: disable=S001
'bad-config-call',
None),
}
priority = -1

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016 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 is only here so we can install those plugins in tox.ini easily."""
from setuptools import setup
setup(name='qute_pylint', packages=['qute_pylint'])

View File

@@ -26,6 +26,10 @@ import pytest
import pytestqt.plugin
import pytest_mock
import pytest_catchlog
import pytest_instafail
import pytest_faulthandler
import pytest_xvfb
sys.exit(pytest.main(plugins=[pytestqt.plugin, pytest_mock,
pytest_catchlog]))
pytest_catchlog, pytest_instafail,
pytest_faulthandler, pytest_xvfb]))

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