Compare commits

...

982 Commits

Author SHA1 Message Date
Florian Bruhin
8486efa940 Release v1.1.2 2018-03-01 09:02:53 +01:00
Florian Bruhin
ea22ad9f49 Upgrade to PyQt 5.10.1
(cherry picked from commit 889b03169a)
2018-03-01 09:01:11 +01:00
Florian Bruhin
90229208c0 Update changelog from master 2018-02-28 16:18:16 +01:00
Florian Bruhin
d298818b85 Don't load the URL immediately on :undo
On some pages like Qt's Gerrit, Indiegogo or Telegram Web, this caused a crash
with QtWebEngine and Qt 5.10.1 in
QtWebEngineCore::WebContentsAdapter::webContents().

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

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

Fixes #3619.

(cherry picked from commit d44ff5ba01)
2018-02-28 16:11:14 +01:00
Florian Bruhin
d134e0b1d0 Fix typing.Union checks with Python 3.7
(cherry picked from commit 63766c1711)
2018-02-28 16:07:20 +01:00
Florian Bruhin
4e8abaa2d1 Release v1.1.1 2018-01-20 19:21:20 +01:00
Florian Bruhin
9d83bfe5cd Update changelog for v1.1.1 2018-01-20 19:21:08 +01:00
Florian Bruhin
501e4dba9c Fix crash when getting signals for closed tabs
Fixes #3498

(cherry picked from commit 748de85ba2)
2018-01-20 18:54:53 +01:00
Florian Bruhin
de147b5a93 Fix Makefile and make sure it's tested
Fixes #3492

(cherry picked from commit d06f07af80)
2018-01-15 22:42:53 +01:00
Florian Bruhin
fbbb9ae940 Release v1.1.0 2018-01-15 19:39:16 +01:00
Florian Bruhin
d3f3be03dd Update changelog for v1.1.0 2018-01-15 19:29:14 +01:00
Florian Bruhin
8fd6a2ff77 Merge pull request #3445 from seelaman/hist_import-cleaning
filter out records with None in any field.
2018-01-15 19:15:08 +01:00
Florian Bruhin
af163eca09 Merge pull request #3491 from qutebrowser/pyup-scheduled-update-01-15-2018
Scheduled weekly dependency update for week 02
2018-01-15 19:06:06 +01:00
pyup-bot
f2beaa455e Update hypothesis from 3.44.13 to 3.44.16 2018-01-15 16:44:12 +01:00
Florian Bruhin
8c8cb3bc29 Fix crash when clicking <form> element with name="value" child
https://stackoverflow.com/q/22942689/2085149

Fixes #2877
See #2569
2018-01-14 20:20:51 +01:00
Florian Bruhin
1f8d6e2168 Update changelog 2018-01-10 09:39:46 +01:00
Florian Bruhin
6b9edefb05 Merge remote-tracking branch 'origin/pr/3432' 2018-01-10 09:39:08 +01:00
Florian Bruhin
0518a03b1e Merge remote-tracking branch 'origin/pr/3423' 2018-01-10 09:38:07 +01:00
Florian Bruhin
c1855e1741 Update changelog 2018-01-10 09:35:42 +01:00
Florian Bruhin
b2ed0c0081 Merge remote-tracking branch 'origin/pr/3468' 2018-01-10 09:35:28 +01:00
Florian Bruhin
05b005ce5c Merge pull request #3475 from qutebrowser/pyup-scheduled-update-01-08-2018
Scheduled weekly dependency update for week 01
2018-01-09 13:01:31 +01:00
pyup-bot
7b348fe17c Update pytest-qt from 2.3.0 to 2.3.1 2018-01-08 16:39:21 +01:00
pyup-bot
70ad02b79b Update hypothesis from 3.44.4 to 3.44.13 2018-01-08 16:39:20 +01:00
pyup-bot
6a3b5a9d4e Update setuptools from 38.2.5 to 38.4.0 2018-01-08 16:39:18 +01:00
pyup-bot
8459c662e7 Update pep8-naming from 0.4.1 to 0.5.0 2018-01-08 16:39:17 +01:00
pyup-bot
f836b615c1 Update flake8-future-import from 0.4.3 to 0.4.4 2018-01-08 16:39:15 +01:00
pyup-bot
6c91633293 Update flake8-docstrings from 1.1.0 to 1.3.0 2018-01-08 16:39:14 +01:00
pyup-bot
0101596148 Update codecov from 2.0.10 to 2.0.13 2018-01-08 16:39:12 +01:00
Florian Bruhin
089a3990ff Merge pull request #3454 from qutebrowser/pyup-scheduled-update-01-01-2018
Scheduled weekly dependency update for week 00
2018-01-06 09:57:44 +01:00
Florian Bruhin
a90730bea7 Pin pytest to 3.3.1 for now
See https://github.com/pytest-dev/pytest-bdd/issues/229
2018-01-05 11:36:26 +01:00
Ryan Roden-Corrent
c290b3f80f Don't attempt completion if input starts with flag.
Always interpret the first word in the command string as the command to
offer completions for, even if that word looks like a flag.

Fixes #3460, where the command string `:-w open` would attempt to offer
completions for `open` but crash because the parsing was thrown off.
By moving the flag-stripping logic to _after_ we determine the command,
`:-w open` interprets `:-w` as the command. Since that is not a valid
command, we won't offer any completions.
2018-01-04 12:34:06 -05:00
Florian Bruhin
c3bcb1d9ba Remove old testbrowser.py 2018-01-03 10:15:00 +01:00
Manuel Seelaus
9363bc3f24 replace empty titles with an empty string. https://github.com/qutebrowser/qutebrowser/pull/3445#issuecomment-354840724 2018-01-02 20:06:29 -07:00
pyup-bot
673919451e Update werkzeug from 0.13 to 0.14.1 2018-01-01 16:34:16 +01:00
pyup-bot
a98cd16ff3 Update flake8-polyfill from 1.0.1 to 1.0.2 2018-01-01 16:34:15 +01:00
pyup-bot
8cec185e4b Update attrs from 17.3.0 to 17.4.0 2018-01-01 16:34:13 +01:00
pyup-bot
9c256740c6 Update attrs from 17.3.0 to 17.4.0 2018-01-01 16:34:12 +01:00
pyup-bot
26bbd10952 Update attrs from 17.3.0 to 17.4.0 2018-01-01 16:34:10 +01:00
Florian Bruhin
f5edd4941e Fix MANIFEST.in for testbrowser 2017-12-30 18:33:15 +01:00
Florian Bruhin
28889cf099 Use a dict for ModeManager.eventFilter 2017-12-29 20:36:55 +01:00
Florian Bruhin
e7af961be2 Remove filtering of mouse events
This was needed for the hide-mouse-cursor setting. However, this setting was
removed in 2223a285ef, so this code has been dead
since then.
2017-12-29 19:36:52 +01:00
Florian Bruhin
a6adbdf167 Clean up testbrowser scripts 2017-12-29 19:10:33 +01:00
Florian Bruhin
7fe0f9fb16 Update qutebrowser xpm 2017-12-29 01:23:45 +01:00
Manuel Seelaus
2a7423a515 filter out records with None in any field. 2017-12-27 18:00:02 -07:00
RyanJenkins
53575aaeed Default raise_windows() alert param to True to preserve existing
behavior
2017-12-27 12:40:55 -08:00
RyanJenkins
9cb25e0c76 Raise browser window after editor closes regardless of outcome of
inserting text and avoid calling QApplication.instance().alert() in this
scenario.
2017-12-26 20:19:39 -08:00
Florian Bruhin
2ef6e740d9 Merge pull request #3441 from strburst/doc-configuring-fix-typo
Fix minor doc typo in example code
2017-12-26 17:26:47 +01:00
Allen Zheng
b5a9612840 Fix minor doc typo in example code
There should be an extra parenthesis to close the call to the outer
print function.
2017-12-26 11:21:02 -05:00
Florian Bruhin
d2f0c5dcac Update changelog 2017-12-26 15:45:50 +01:00
Florian Bruhin
73b6dea1f4 Merge remote-tracking branch 'origin/pr/3427' 2017-12-26 15:45:00 +01:00
Florian Bruhin
aa68e97922 Merge pull request #3435 from qutebrowser/pyup-scheduled-update-12-25-2017
Scheduled weekly dependency update for week 52
2017-12-26 15:05:37 +01:00
pyup-bot
501cabc6a0 Update pytest-rerunfailures from 3.1 to 4.0 2017-12-25 16:26:14 +01:00
pyup-bot
0d61c75ce4 Update hypothesis from 3.44.1 to 3.44.4 2017-12-25 16:26:13 +01:00
pyup-bot
c5c3684581 Update setuptools from 38.2.4 to 38.2.5 2017-12-25 16:26:11 +01:00
RyanJenkins
d9b00acdc6 Return focus to qutebrowser when external editor finishes. 2017-12-23 23:59:02 -08:00
Ryan Farley
46f6336e6e and add back needed connection 2017-12-22 12:47:38 -06:00
Ryan Farley
1d0b91475d remove broken connection 2017-12-22 12:45:37 -06:00
Ryan Farley
611f3621ec skip test
tests/end2end/features/test_marks_bdd.py::test_jumping_back_after_following_a_link
2017-12-22 12:36:45 -06:00
Ryan Farley
252fbf651f add back blank line for D204 2017-12-22 11:47:13 -06:00
Ryan Farley
f90342741a comma spacing 2017-12-22 11:41:07 -06:00
Ryan Farley
feb327e80e fix style issues, better names, less indirection
Added spaces to comments, use python naming conventions, remove
_load_progress_fake as unnecessary, rename _on_load_*_fake to
_on_load_*_workaround (for less confusion), and use qtutils rather than
QT_VERSION_STR
2017-12-22 11:32:31 -06:00
seebye
125af531cb database qute://back 2017-12-22 15:44:42 +01:00
Ryan Farley
fa10b76ce8 remove extraneous loadStarted connection
Copying and pasting without thinking might lead to redundancy.
2017-12-22 01:27:35 -06:00
Ryan Farley
4a6c9ecc34 only reroute load signals with Qt=5.10
This stops regressions on Qt<=5.9. It also reintroduces #3110, but
fixing #3110 was just a nice side effect rather than the main goal here.
2017-12-21 21:22:20 -06:00
Ryan Farley
d6c56b83a8 fix line length 2017-12-21 16:31:45 -06:00
Ryan Farley
5bfab54828 supplement broken webengine load signals
This uses the much more reliable `loadProgress(100)` in place of
`loadFinished(true)` for WebEngine, with `loadProgressFake` and
`loadFinishedFake` used instead of the 'official' variants.
2017-12-21 15:35:43 -06:00
Florian Bruhin
5c00eea122 Fix stripping of lines in asciidoc2html
This broke in #3382 since re.fullmatch does a different thing for trailing
newlines:

    >>> line
    '===========\n'
    >>> re.match(r'^=+$', line)
    <_sre.SRE_Match object; span=(0, 11), match='==========='>
    >>> re.fullmatch(r'=+', line)
    >>>

This now strips the line by default, and adds newlines if needed.
2017-12-20 11:35:27 +01:00
seebye
801b6b90ce pylint adjustments 2017-12-20 01:15:12 +01:00
seebye
c8ae405bfe fix #3396 2017-12-20 00:10:21 +01:00
Cody Scott
3c0d51c253 Fix broken link 2017-12-19 12:18:10 -05:00
Florian Bruhin
4ffdd9da0e Add new B008 to flake8 ignores 2017-12-19 08:57:33 +01:00
Florian Bruhin
fde0516ccf Merge remote-tracking branch 'origin/pr/3413' 2017-12-19 08:56:01 +01:00
Florian Bruhin
f2c93a0061 Use request instead of pytestconfig
This unifies QuteProc and the other Process subclasses a bit.
2017-12-19 08:55:35 +01:00
Florian Bruhin
12ba642547 Avoid using pytest.config
It's going to be removed in some future pytest release.
2017-12-19 08:32:32 +01:00
pyup-bot
23e3a5ef7d Update hypothesis from 3.42.1 to 3.44.1 2017-12-18 16:23:16 +01:00
pyup-bot
7d3645adc2 Update flake8-bugbear from 17.4.0 to 17.12.0 2017-12-18 16:23:15 +01:00
Florian Bruhin
dbb89b1073 Update docs 2017-12-18 16:11:29 +01:00
Florian Bruhin
f203535e00 Merge remote-tracking branch 'origin/pr/3407' 2017-12-18 16:11:16 +01:00
Ryan Roden-Corrent
ef2de8201a Fix colors.completion.fg default and description.
Update the description to mention the number of columns and change the
default to ["white", "white", "white"] to make it more obvious that
multiple colors can be specified. This also satisfies the config test
that expects the default value for ListOrValue types to be a list.

One other test had to be tweaked to use a config option that is still
just a QtColor rather than a ListOrValue.

While it is possible to provide just two colors, it is "undefined
behavior". It will use the first color as the third color, but that is
an artifact of the implementation and therefore not documented (though
also not an error, as it is harmless).
2017-12-18 08:42:22 -05:00
Ryan Roden-Corrent
31c2988693 Fix test_config.test_get for updated config.
colors.completion.fg is now a list instead of a QColor. As this test
specifically wanted to test a QColor, I just changed it to a different
config option.
2017-12-17 13:28:00 -05:00
Florian Bruhin
e66dce2360 Merge pull request #3402 from tbroadley/fix-typos
Fix typo
2017-12-16 17:28:18 +01:00
Thomas Broadley
3775bf929f Fix typos 2017-12-16 11:24:14 -05:00
Florian Bruhin
d03e314762 Explain eslint philosophy 2017-12-15 23:26:18 +01:00
Florian Bruhin
b8a5c04b69 Clean up run_pylint_on_tests 2017-12-15 23:22:26 +01:00
Florian Bruhin
c506ffa4cd pylint: More config adjustments 2017-12-15 23:17:28 +01:00
Florian Bruhin
430126dcc8 pylint: Re-enable ungrouped-imports 2017-12-15 23:08:53 +01:00
Florian Bruhin
f5dd392701 Regenerate docs 2017-12-15 23:00:06 +01:00
Florian Bruhin
21bf446147 Reorder pylint ignores 2017-12-15 20:06:12 +01:00
Florian Bruhin
e65c0dd8a7 pylint: Re-enable bad-continuation
And lots and lots of whitespace changes.
2017-12-15 19:16:55 +01:00
Florian Bruhin
93cd200bb7 Add docstring 2017-12-15 19:06:23 +01:00
Florian Bruhin
4c24b9ed4a Reorder pylint disables 2017-12-15 17:16:55 +01:00
Florian Bruhin
26a622c46d Disable wrong inconsistent-return-statements 2017-12-15 16:33:47 +01:00
Florian Bruhin
f4ed31b295 Add an utils.Unreachable exception 2017-12-15 16:33:47 +01:00
Florian Bruhin
016fc0ebb1 Fix some inconsistent returns 2017-12-15 16:33:47 +01:00
Florian Bruhin
97a4e8d847 Rewrite error handling in hist_importer script
Raise an exception instead of calling sys.exit
2017-12-15 16:33:47 +01:00
Florian Bruhin
1a4a9b4392 Declare *args before keyword arguments
See https://pylint.readthedocs.io/en/latest/whatsnew/1.8.html
2017-12-15 16:33:47 +01:00
Florian Bruhin
fc987ea9c0 Make message.confirm_async keyword-only 2017-12-15 14:49:49 +01:00
Florian Bruhin
79717528ec Fix exception message formatting 2017-12-15 14:42:37 +01:00
Florian Bruhin
7cebd95936 Simplify test_getitem 2017-12-15 14:41:38 +01:00
Florian Bruhin
bb44f1d4cc Remove old pylint disables 2017-12-15 14:39:42 +01:00
Florian Bruhin
e76732693c Fix wrong import order 2017-12-15 14:35:07 +01:00
Florian Bruhin
a4101662b2 pylint: Disable logging-not-lazy
We log to RAM anyways
2017-12-15 14:29:50 +01:00
Florian Bruhin
3f9ded3bed Add missing docstrings 2017-12-15 13:55:06 +01:00
Florian Bruhin
03a339b93a Update pylint 2017-12-15 13:42:54 +01:00
Florian Bruhin
8173a48b8a Don't access stale settings object after hinting
When QtWebEngine shuts down, it calls pending callbacks, which means we access
an invalid 'settings' object when that happens. The stack would look something
like this:

0  QtWebEngineCore::WebEngineSettings::setAttribute(QtWebEngineCore::WebEngineSettings::Attribute, bool)
12 QtWebEngineCore::CallbackDirectory::invokeEmptyInternal<QVariant const&>(QtWebEnginePrivate::QWebEngineCallbackPrivateBase<QVariant const&>*)
14 QtWebEngineCore::CallbackDirectory::~CallbackDirectory()
19 QWebEnginePage::~QWebEnginePage()

If we instead get the settings from the view freshly, we get a RuntimeError from
PyQt telling us that it's dead. Not sure why it doesn't know about settings
being dead...

With that, we'd get a RuntimeError, which we can simply ignore as it doesn't
matter anyways if the tab is gone.

Fixes #3399
2017-12-14 22:56:44 +01:00
Florian Bruhin
76db8d6f81 Make webelem.OrphanedError subclass of webelem.Error
This means something like this:

  :hint ;; later 20 follow-hint a ;; later 20 tab-close

Won't crash anymore, as the webelem.Error will be shown in the statusbar.
2017-12-14 22:43:19 +01:00
Florian Bruhin
dc1d5036b6 Simplify scrollbar width calculation
This gives us slightly different values it seems, but I think they are more
correct (and don't need the "+ 5" above).

Taking the width directly (not the sizeHint width) returned values like 100 or
so when the scrollbar wasn't shown yet, so that seems wrong.
2017-12-14 09:39:07 +01:00
Florian Bruhin
58043b5653 Always subtract scroll bar width from completion view
The situation where there's no scroll bar at the point the column widths are
calculated is a very rare one. What happens more often is that the scroll bar
disappears due to filtering, in which case we didn't recalculate the column
widths anyways.

Furthermore, we can even go wrong with this calculation, when we calculate the
column widths while the entire completion is invisible - then the scroll bar
won't be visible either, and we won't subtract the space needed for it.

Let's not try to optimize for this uncommon case, and just always subtract the
scrollbar, even if it's not there initially.

Fixes #3359
Closes #3389
2017-12-14 09:13:34 +01:00
Florian Bruhin
f0ad24b08a Remove long deprecated :download invocation 2017-12-14 09:06:46 +01:00
Florian Bruhin
dce4c68827 Update docs 2017-12-14 09:03:51 +01:00
Florian Bruhin
43588b2818 Merge remote-tracking branch 'origin/pr/3393' 2017-12-14 09:02:31 +01:00
Florian Bruhin
5620acb81f Update Debian install instructions
[ci skip]
2017-12-14 08:59:54 +01:00
Florian Bruhin
ac7b56b2b8 Merge remote-tracking branch 'origin/pr/3392' 2017-12-13 23:05:40 +01:00
Ryan Roden-Corrent
57e2d407ce Support different colors per completion column.
Now colors.completion.fg may be set to a list to specify a different
color for each completion column. For example:

:set colors.completion.fg [black,blue,white] will use black text for the
first column, blue for the second, and white for the third.

Setting to a single value still works and behaves as before. The default
is unchanged from 'white'.

Resolves #1794.
2017-12-13 17:03:59 -05:00
Florian Bruhin
7a3554e77a Stabilize :session-save --quiet test
By adding a way to check for the loglevel, we can easily check there's no
message but still wait for the session to be saved.
2017-12-13 23:02:44 +01:00
Florian Bruhin
f34bdfbb50 Revert "Remove :session-save --quiet test"
This reverts commit bea71ed3a2.
I think I can think of a way to stabilize it now.
2017-12-13 22:46:38 +01:00
Ryan Roden-Corrent
12112e0fc7 Implement command-accept --rapid.
command-accept --rapid will run the command without clearing the prompt,
allowing "rapid fire" commands. For example, one could open completion
for `open -t` and open several tabs in a row.

The default binding is ctrl+enter.

Resolves #588.
2017-12-13 16:30:42 -05:00
Florian Bruhin
0a612db733 Rename/move encoding test 2017-12-13 21:13:47 +01:00
Florian Bruhin
ddcdfa54aa Fix test for invalid guiprocess encoding 2017-12-13 21:12:56 +01:00
Kevin Velghe
cc4e8c1aae fix password_fill using libsecret 2017-12-13 21:06:09 +01:00
Florian Bruhin
922b1e8f10 Use system locale to decode subprocess output 2017-12-13 20:09:56 +01:00
Florian Bruhin
07d07c7fae Update changelog 2017-12-13 20:06:43 +01:00
Florian Bruhin
2b3250144b Merge remote-tracking branch 'origin/pr/3388' 2017-12-13 20:06:00 +01:00
Florian Bruhin
cdb90cbee7 Regenerate docs 2017-12-13 19:59:54 +01:00
Florian Bruhin
afb0807064 Update changelog 2017-12-13 19:58:01 +01:00
Florian Bruhin
f32b4d88ba Merge remote-tracking branch 'origin/pr/3385' 2017-12-13 19:56:53 +01:00
George Edward Bulmer
84e0ce757a Fix erroneous docstring in a recently added test. 2017-12-13 14:50:25 +00:00
Ryan Roden-Corrent
6420037dd9 Fix histcategory query reuse logic.
I mistakenly checked the length of wheres instead of words. This fixes
that check, renames 'wheres' to 'where_clause' to be clear
that it is a string and not an array, and adds a test.
2017-12-13 08:39:34 -05:00
Ryan Roden-Corrent
2e36e5151e Fix comment in histcategory. 2017-12-13 08:21:48 -05:00
George Edward Bulmer
28961ab177 Add a test with invalid unicode in spawned stdout.
stderr features identical behaviour, so is currently untested.
2017-12-13 12:46:46 +00:00
Florian Bruhin
4caf2fd8b7 Update changelog 2017-12-13 09:27:25 +01:00
Florian Bruhin
c8aef015b0 Merge remote-tracking branch 'origin/pr/3201' 2017-12-13 09:22:36 +01:00
Florian Bruhin
31e3356d01 Merge remote-tracking branch 'origin/pr/3382' 2017-12-13 08:43:21 +01:00
Florian Bruhin
bea71ed3a2 Remove :session-save --quiet test
When nothing gets logged, we can't check whether the session was already saved.
2017-12-13 08:41:29 +01:00
Ryan Roden-Corrent
ae294e92ad Remove unused re import 2017-12-12 20:27:06 -05:00
Ryan Roden-Corrent
8358c76f86 Fix casing of LIKE in comment 2017-12-12 20:26:30 -05:00
Ryan Roden-Corrent
158cfa1194 Clean up "any order" SQL query code.
- Replace a list with a generator
- Add commments to the less obvious parts
- Simplify the binding variable names
2017-12-12 17:28:38 -05:00
George Edward Bulmer
16a9948759 Replace malformed utf-8 characters in spawn output.
Previously this simply crashed if there was ever malformed utf-8 in the
stderr or stdout streams, perhaps as a result of an incorrectly spawned
command. See e.g. #3222
2017-12-12 22:23:33 +00:00
Florian Bruhin
19596e3104 Make qute://log lines darker 2017-12-12 22:52:35 +01:00
George Edward Bulmer
4844a68bfc Change a rogue re.fullmatch into a re.search.
Sometimes tests were timing out. Perhaps with fullmatch these tests were
rarely failing to parse the logs for the information.
2017-12-12 21:42:10 +00:00
Justin Partain
8f5394934f Fix bad merge when rebasing incremental_search feature 2017-12-12 11:32:52 -05:00
Justin Partain
aff6510e35 Refactor _incremental_search() based on PR review 2017-12-12 11:31:28 -05:00
Justin Partain
bcd9d13684 Update tests to use search.ignore_case 2017-12-12 11:31:28 -05:00
Justin Partain
9f511fe18c pylint fix, change if len(text) to if text 2017-12-12 11:31:28 -05:00
Justin Partain
8451899a76 Add block for ignore_case 2017-12-12 11:31:28 -05:00
Justin Partain
4eebd2a85d Create config.search.* group with ignore_case and incremental 2017-12-12 11:31:28 -05:00
Justin Partain
bb2fcddcd4 Update incremental_search PR with changes from review 2017-12-12 11:31:28 -05:00
Justin Partain
77054cc063 Make 'Text not found on page!' warnings replace 2017-12-12 11:31:28 -05:00
Justin Partain
c1094b6660 Feature - incremental_search
Added config option to find on a page incrementally, renewing the search
each time a new character is entered.
2017-12-12 11:31:28 -05:00
George Edward Bulmer
9ca6baca4f Modify instances of re.match to fullmatch or search.
This applies the changes to the tests directory only.
2017-12-12 15:07:37 +00:00
Florian Bruhin
22434f4d1b Merge pull request #3386 from ykgmfq/patch-1
Fedora instructions for non-free codecs
2017-12-12 15:57:39 +01:00
ykgmfq
dadf6c0e0a Fedora instructions for non-free codecs 2017-12-12 15:53:17 +01:00
George Edward Bulmer
b07a4c8c28 Add explicit left anchor to directory check regex. 2017-12-12 13:25:35 +00:00
George Edward Bulmer
3cf4e8ba67 Merge remote-tracking branch 'upstream/master' into regex-match 2017-12-12 13:22:11 +00:00
Ryan Roden-Corrent
6a20f9d4c9 Cache url query when possible.
We don't need to regenerate a new query every keystroke, but rather
every time the user adds a new word.
2017-12-12 07:37:31 -05:00
Florian Bruhin
5fe91c30cc Fix :click-element with an ID containing non-alphanumeric characters
See #3201
2017-12-12 11:33:59 +01:00
Florian Bruhin
2e8acf4825 Improve terminating of test processes
There are various small changes here:

- If the process is already finished, we don't try to terminate it.
- On Windows, we use QProcess::kill instead of QProcess::terminate, as terminate
  will only work with processes which have a GUI loop.
- We assert that quitting the suprocess actually worked.

Fixes #3384
2017-12-12 09:36:28 +01:00
Florian Bruhin
6655793e6a Use 'terminate' to clean up webserver subprocess
We already have TestProcess.terminate which does exactly the same
WebserverProcess.cleanup does.

See #3384
2017-12-12 09:33:34 +01:00
Florian Bruhin
5a97e79099 Update changelog 2017-12-12 07:05:55 +01:00
Florian Bruhin
12f6304659 Fix indent 2017-12-12 07:03:48 +01:00
Florian Bruhin
8e319a762f Merge remote-tracking branch 'origin/pr/3374' 2017-12-12 07:03:10 +01:00
Florian Bruhin
4f2f1a6494 Make sure editor test doesn't run on Windows 2017-12-12 06:57:39 +01:00
Florian Bruhin
1587181a76 Merge remote-tracking branch 'origin/pr/3380' 2017-12-12 06:51:53 +01:00
Florian Bruhin
81bfa81448 Don't run end2end tests on macOS anymore
They are just too flaky on macOS to be useful, and I have no idea how to make
things more stable there
2017-12-12 06:45:47 +01:00
George Edward Bulmer
f74832328f Modify re.match usage in scripts directory. 2017-12-11 23:06:52 +00:00
George Edward Bulmer
747a9bc5b6 Modify usage of re.match to fit re.fullmatch or re.search.
re.match features an implicit left anchor, which can be surprising.

re.fullmatch features implicit anchors on both sides, but is aptly named
and unsurprising.

re.search has no such implicit anchors, which ought to be the default
even if a single anchor is needed.
2017-12-11 21:32:55 +00:00
Florian Bruhin
481dec067d Don't override background-color for qutebrowser pages
Fixes #3381
2017-12-11 17:38:12 +01:00
pyup-bot
d114deac70 Update werkzeug from 0.12.2 to 0.13 2017-12-11 16:23:21 +01:00
pyup-bot
d57a81a3d3 Update pytest from 3.3.0 to 3.3.1 2017-12-11 16:23:19 +01:00
pyup-bot
22fe42d38e Update hypothesis from 3.40.1 to 3.42.1 2017-12-11 16:23:18 +01:00
pyup-bot
5d8e3a969f Update cheroot from 5.10.0 to 6.0.0 2017-12-11 16:23:16 +01:00
pyup-bot
713a2ef2c1 Update pylint from 1.7.4 to 1.7.5 2017-12-11 16:23:15 +01:00
pyup-bot
519dc6a7c9 Update setuptools from 38.2.3 to 38.2.4 2017-12-11 16:23:13 +01:00
pyup-bot
dd7a082265 Update codecov from 2.0.9 to 2.0.10 2017-12-11 16:23:12 +01:00
George Edward Bulmer
a2bcd68d56 Code review changes.
This fixes whitespace and alignment issues, and removes a stray test.
2017-12-11 13:35:39 +00:00
Ryan Roden-Corrent
8909e03f1c Match url completion terms in any order.
Perviously, 'foo bar' would match 'foo/bar' but not 'bar/foo'. Now it
will match both, using a query with a WHERE clause like:

WHERE ((url || title) like '%foo%' AND (url || title) like '%bar%')

This does not seem to change the performance benchmark. However, it does
create a new query for every character added rather than re-running the
same query with different parameters. We could re-use queries if we
maintained a list like self._queries=[1_arg_query, 2_arg_query, ...].
However, it isn't clear that such a complexity would be necessary.

Resolves #1651.
2017-12-11 07:46:50 -05:00
Florian Bruhin
72d847d687 travis: Use newer macOS image 2017-12-11 09:36:27 +01:00
Florian Bruhin
6a7d2f4275 Remove dead code
QUrl.path() never returns None
2017-12-11 09:14:26 +01:00
Florian Bruhin
f7a94b946f Add changelog for font size change
See 22f3fade24
2017-12-11 08:12:13 +01:00
Florian Bruhin
444f0a36df Update docs 2017-12-11 07:12:45 +01:00
Florian Bruhin
2a8b74cbec Get rid of FakeUrl stub
We can just use a real QUrl...
2017-12-11 07:10:17 +01:00
Florian Bruhin
6c7b8ce895 Merge remote-tracking branch 'origin/pr/3370' 2017-12-11 07:09:49 +01:00
George Edward Bulmer
3b10584749 Update tests to work with the earlier consumption of stdin etc.
Note: this adds an element to vulture's whitelist that vulture
mistakenly identified as unused.
2017-12-10 23:46:35 +00:00
George Edward Bulmer
d32a4ea99e Seperate _output from guiprocess and keep window opening in spawn.
This removes the extraneous variable, and makes testing easier.
2017-12-10 23:45:43 +00:00
George Edward Bulmer
038bb85a67 Capture stdout and stderr always for spawn.
This change makes it so that stderr and stdout is unconditionally read
from for a completed process, and sent to qute://spawn-output. This
allows the user to see the results of the previous process, even if they
had forgotten to use --output.
2017-12-10 19:12:47 +00:00
George Edward Bulmer
9f8dbe95e4 Code review changes.
This fixes the following problems found in a review:

1. Manual modification of the asciidoc has been undone.
2. --output-to-tab has been renamed to the less verbose --output.
3. spawn_output has been changed to spawn-output in the url.
4. Erroneous newline in imports has been removed.
5. output in guiprocess.py has been marked private.
6. If there is no output for either stderr or stdout, say so.
7. Missing space in a text line was added.
8. Redundant initialising of an empty string removed.
2017-12-08 19:00:46 +00:00
George Edward Bulmer
9f9311840a Add --output-to-tab flag for :spawn.
This puts the exit status, stdout, and stderr in a new tab.
2017-12-08 18:00:07 +00:00
evanlee123
9685eb36b6 Changed FakeUrl's url command to toDisplayString 2017-12-07 16:30:34 -07:00
unknown
25526f00bf fixed catch error in tabwidget 2017-12-07 15:47:03 -07:00
unknown
2483b8315c Merge remote-tracking branch 'refs/remotes/origin/master' 2017-12-07 13:36:49 -07:00
evanlee123
18609f1a24 fixed spacing on FakeURL 2017-12-07 02:36:31 -07:00
evanlee123
d1a00eb934 Clarity on protocol field 2017-12-07 02:35:34 -07:00
evanlee123
20ac618752 Simplified code in get_tab_fields
changed self.tab_url(idx) to url in get_tab_fields()
2017-12-07 02:04:02 -07:00
Florian Bruhin
d4cadcc62e Add comment about @run-at
[ci skip]
2017-12-07 08:17:15 +01:00
evanlee123
4d13941290 added the scheme field to FakeURL 2017-12-06 23:57:19 -07:00
evanlee123
02b24e8dfb Update tabwidget.py 2017-12-06 21:35:09 -07:00
unknown
f0de3601cb Merge remote-tracking branch 'upstream/master' 2017-12-06 13:37:05 -07:00
unknown
94809032a4 field[protocol] gives the right protocol] 2017-12-06 13:24:27 -07:00
Florian Bruhin
0f20f16b15 Merge branch 'greasemonkey' 2017-12-06 21:24:15 +01:00
Florian Bruhin
f033b228b1 Use py.path.local in save_script 2017-12-06 21:21:55 +01:00
unknown
30b25da273 Added protocol key to field 2017-12-06 13:09:44 -07:00
Florian Bruhin
04d2004528 tox: Fix eslint environment
We need to set basepython there to not get InterpreterNotFound
2017-12-06 20:58:14 +01:00
Florian Bruhin
eb90f9835f Mark qute://settings test as flaky 2017-12-06 20:54:14 +01:00
Florian Bruhin
d6039a0e34 Fix markers for editor test 2017-12-06 20:30:46 +01:00
Florian Bruhin
6aafe02320 Make sure scripts are removed correctly 2017-12-06 20:18:41 +01:00
Florian Bruhin
a37ecc353c Simplify for loop 2017-12-06 20:18:41 +01:00
Florian Bruhin
2633dcc0d5 Fix lint 2017-12-06 20:18:41 +01:00
Florian Bruhin
dd63508be7 Add a greasemonkey.init()
This also creates the greasemonkey directory if it doesn't exist yet, for
discoverability.
2017-12-06 11:55:08 +01:00
Florian Bruhin
0c792d228e Update docs 2017-12-06 11:12:25 +01:00
Florian Bruhin
3cd2910fa2 Merge branch 'greasemonkey' of https://github.com/toofar/qutebrowser into greasemonkey 2017-12-06 10:47:29 +01:00
Jimmy
6b3e16b163 Greasemonkey: mark failing no(sub)frames test as flaky.
This test is supposed to ensure that user scripts don't run on iframes
when the @noframes directive is set in the greasemonkey metadata. It is
failing sometimes on travis but passing on local test runs. Personally I
haven't actually ran the whole test suite through, just the javascript
tests. It maybe be some stale state that only shows up when you run the
whole suite. It may be some timing issue that only shows up on travis
because ???. Hopefully this stops the red x from showing up on the PR.
2017-12-06 20:34:29 +13:00
Jimmy
ead108eeeb fixup! Greasemonkey: Add run-at document-idle. 2017-12-06 20:27:56 +13:00
Jimmy
129f97873a Greasemonkey: add assert to tests scripts_for assumptions.
And crash the users browsing session as a result of any accidental and
totally, otherwise, non-fatal unforseen errors.
2017-12-06 20:21:29 +13:00
Florian Bruhin
7d7c841250 Update changelog 2017-12-06 08:01:39 +01:00
Florian Bruhin
1a3f8662e6 Improve handling of cancelled search callbacks 2017-12-06 07:56:59 +01:00
Florian Bruhin
9ec4e749f1 Merge branch 'fix_search_callbacks' of https://github.com/jupart/qutebrowser 2017-12-06 07:51:19 +01:00
Florian Bruhin
a3ba7b9f60 Reformat hist_importer epilog. 2017-12-06 07:45:52 +01:00
Florian Bruhin
16e09d18fa Update changelog 2017-12-06 07:42:07 +01:00
Florian Bruhin
549a3a8f70 Improve hist_importer messages 2017-12-06 07:41:41 +01:00
Florian Bruhin
6ea250dc83 Merge remote-tracking branch 'origin/pr/3044' 2017-12-06 07:17:22 +01:00
Florian Bruhin
b326f12427 Mark editor test as flaky
See #3367
2017-12-06 06:59:08 +01:00
Florian Bruhin
9c042e4313 Update changelog 2017-12-06 06:58:22 +01:00
Florian Bruhin
0df1d07558 Merge remote-tracking branch 'origin/pr/3367' 2017-12-06 06:57:59 +01:00
Florian Bruhin
58212a7b15 Update docs 2017-12-06 06:56:12 +01:00
Florian Bruhin
7a6d568c8c Remove blank line 2017-12-06 06:53:27 +01:00
Florian Bruhin
7f81f0c0ab Always open session tabs in foreground
This helps with issues with lazy sessions as document.hidden was set
incorrectly.

See #3345, #3366
2017-12-06 06:51:15 +01:00
Florian Bruhin
dcb4448594 Merge remote-tracking branch 'origin/pr/3345' 2017-12-06 06:51:03 +01:00
Justin Partain
00a09354c3 Track number of active searches in tab, ignore all but most recent search callbacks 2017-12-05 08:28:10 -05:00
Ryan Roden-Corrent
636f9edff6 History completion by both URL and title.
Resolves #1649.
2017-12-05 07:32:58 -05:00
Florian Bruhin
e97fbfdf56 Merge remote-tracking branch 'origin/pr/3355' 2017-12-05 13:22:36 +01:00
Florian Bruhin
8a3437c6a4 Adjust Debian install instructions 2017-12-05 09:36:14 +01:00
Florian Bruhin
29c2e7b45f Skip :follow-selected tests on Qt 5.10
See #3003, #2635
2017-12-05 08:35:12 +01:00
Florian Bruhin
0ce9a355ae Fix download test with Qt 5.10
Not sure why this is needed (no prompt is shown otherwise), but it works like
this.

This probably is related to https://bugreports.qt.io/browse/QTBUG-63388

See #3003
2017-12-05 08:34:37 +01:00
Florian Bruhin
62228752aa Fix most end2end tests with Qt 5.10
For some reason, if we don't wait for about:blank to be fully loaded with
Qt 5.10, we get the next LoadStatus.finished notification with about:blank as
URL.

This is most likely caused by the changes in
https://codereview.qt-project.org/#/c/202924/

See #3003
2017-12-05 08:34:33 +01:00
Florian Bruhin
a8f4444c24 tests: Show more of the message 2017-12-04 22:07:49 +01:00
Florian Bruhin
b554e1f763 tests: Add after= argument to wait_for 2017-12-04 22:07:23 +01:00
François Chavant
9675ea93ee Do not call pip in travis_install.sh when TESTENV=shellcheck 2017-12-04 20:31:28 +01:00
mhm@mhm.com
02104a318e delay added, text changed 2017-12-04 19:03:12 +01:00
mhm@mhm.com
28caddf3c1 delay added, text changed 2017-12-04 19:02:09 +01:00
Florian Bruhin
3a04de62ae Recompile requirements 2017-12-04 19:01:21 +01:00
François Chavant
86c37538d7 Simply search for shell scripts to search
Use 2 simpler find commands and redirect the output to a temporary
file.
2017-12-04 18:29:55 +01:00
François Chavant
4467f51e42 Use 'language: generic' for shellcheck, fix typo, correct indentation 2017-12-04 18:15:02 +01:00
Josefson Fraga
b6466b7410 revision 2 2017-12-04 13:08:56 -03:00
Florian Bruhin
6973a703c5 Add pluggy to requirements 2017-12-04 16:56:39 +01:00
Florian Bruhin
2cdc32ca58 Remove pytest-catchlog 2017-12-04 16:55:57 +01:00
pyup-bot
956c257d19 Update pytest-travis-fold from 1.2.0 to 1.3.0 2017-12-04 16:09:25 +01:00
pyup-bot
71095da975 Update pytest from 3.2.5 to 3.3.0 2017-12-04 16:09:23 +01:00
pyup-bot
a0caa2b7b1 Update hypothesis from 3.38.5 to 3.40.1 2017-12-04 16:09:22 +01:00
pyup-bot
f7ccb8061b Update pyroma from 2.2 to 2.3 2017-12-04 16:09:20 +01:00
pyup-bot
96b6f7c443 Update macholib from 1.8 to 1.9 2017-12-04 16:09:19 +01:00
pyup-bot
a3612a624a Update altgraph from 0.14 to 0.15 2017-12-04 16:09:17 +01:00
pyup-bot
905748f2d0 Update setuptools from 38.2.1 to 38.2.3 2017-12-04 16:09:16 +01:00
pyup-bot
a3f57b9a9b Update flake8-builtins from 1.0 to 1.0.post0 2017-12-04 16:09:14 +01:00
Florian Bruhin
7ef64c0f87 Read $PYTHON in every tox.ini environment
See #2341
2017-12-04 06:45:47 +01:00
Florian Bruhin
2c2d7fe734 Copy-paste pylint commands for second environment
Otherwise, tox 2.3.1 (shipped with various distributions) fails with:

    tox.ConfigError: ConfigError: substitution key 'posargs' not found
2017-12-04 06:36:42 +01:00
Florian Bruhin
6b65d96fe1 Reformat comment 2017-12-04 06:32:54 +01:00
Florian Bruhin
fe60556a34 Merge remote-tracking branch 'origin/pr/3349' 2017-12-04 06:32:46 +01:00
Florian Bruhin
a137a29cce Style improvements
This adds a blank line and makes Completer arguments keyword-only to make their
meaning more clear.
2017-12-03 22:32:17 +01:00
Florian Bruhin
9dfff43d99 Merge remote-tracking branch 'origin/pr/3357' 2017-12-03 22:30:47 +01:00
Florian Bruhin
bbc2f14e45 Merge remote-tracking branch 'origin/pr/3356' 2017-12-03 22:30:30 +01:00
Ryan Farley
38b2d42b40 cleanup PYTEST_ADDOPTS for pytest subprocess
See https://github.com/qutebrowser/qutebrowser/pull/3349
2017-12-03 15:09:47 -06:00
Ryan Roden-Corrent
b610563e7f Don't show current window for :tab-give/:tab-take.
Resolves #3144.
2017-12-03 08:03:54 -05:00
Florian Bruhin
97054ca35d Don't hide report dialog early
It looks like hiding it already causes it to be accepted.
Fixes #1128
2017-12-03 13:04:08 +01:00
Florian Bruhin
f07301cfb5 Revert "Restart correctly after reporting crash."
This reverts commit 7001f068b3.
2017-12-03 12:48:29 +01:00
François Chavant
59c9a2b243 Ignore shellcheck false positive 2017-12-03 11:30:59 +01:00
François Chavant
22e4a800a1 Refactor format_json userscript to not parse 'ls' output
The script now also works under MacOS
2017-12-03 10:50:54 +01:00
François Chavant
ccb8e74998 Use koalaman/shellcheck:latest 2017-12-03 09:29:38 +01:00
François Chavant
dd589f180b Fix remaining shellcheck warnings 2017-12-02 21:09:24 +01:00
François Chavant
31710b7045 Trivial fixes for shellcheck warnings 2017-12-02 19:37:20 +01:00
François Chavant
595a53ad3b Apply patch from #1697 2017-12-02 19:37:18 +01:00
François Chavant
b91a39be22 Run shellcheck on Travis CI 2017-12-02 19:37:10 +01:00
Florian Bruhin
ce46b30a1e Show error instead of warning 2017-12-02 14:49:06 +01:00
Florian Bruhin
f1f573d651 Update changelog 2017-12-02 14:48:31 +01:00
Florian Bruhin
003ec31848 Merge remote-tracking branch 'origin/pr/3333' 2017-12-02 14:47:24 +01:00
Florian Bruhin
a41db970e8 Update changelog
[ci skip]
2017-12-02 14:42:14 +01:00
Florian Bruhin
689fe96393 Improve workaround comment 2017-12-02 14:37:59 +01:00
Florian Bruhin
e9be357104 Merge remote-tracking branch 'origin/pr/3352' 2017-12-02 14:37:01 +01:00
Ryan Farley
fbd325f8d1 Revert "update tox env name in CI config"
This reverts commit 2f231c86ac.
2017-12-01 10:55:08 -06:00
Ryan Farley
5607cc2be8 Revert "update contributing.asciidoc with -pyqtlink envs"
This reverts commit 6b76203780.
2017-12-01 10:52:58 -06:00
Ryan Farley
df6ff55b7a allow pytest to default to link_pyqt
link_pyqt now checks for LINK_PYQT_SKIP, allowing pytest env names like
`py36` to work properly without negative conditionals in tox.ini
2017-12-01 10:51:41 -06:00
Ryan Roden-Corrent
780ac3f4c2 Remove needles quteproc/server fixture deps.
A few step definitions listed these in the parameters although they were
unused.
2017-12-01 11:34:47 -05:00
Ryan Roden-Corrent
3cfa0f7586 Make pylint happy for test_editor_bdd.
windows has no SIGUSR1, but we don't run this on windows anyways
for posix, there IS a member so we need to ignore useless-suppression
2017-12-01 08:41:08 -05:00
Ryan Roden-Corrent
1102ae4d7e Skip editor orphaned test on windows.
Tried SIGINT/SIGTERM, neither worked. Just skip this test on windows and
go back to SIGUSR1 otherwise.
2017-12-01 07:35:13 -05:00
Ryan Roden-Corrent
822f6bae2c Fix webkitelem test.
Now that it checks tab.is_deleted we need to mock that.
2017-12-01 07:28:02 -05:00
Ryan Farley
49485ca220 tox.ini: fix conditional syntax errors
`{[testenv]deps}` was passing conditionals in their raw form; this
simply lists them manually to avoid this.
2017-11-30 16:58:14 -06:00
Ryan Farley
6b76203780 update contributing.asciidoc with -pyqtlink envs 2017-11-30 14:21:37 -06:00
Ryan Farley
a5d0b9851a tox.ini: remove pyqt5.6, use requirements-pyqt.txt 2017-11-30 14:14:11 -06:00
mhm@mhm.com
b58cfead05 style fixed 2017-11-30 16:05:01 +01:00
Ryan Farley
2f231c86ac update tox env name in CI config
Use py36-pyqtlink instead of py36 for macOS
2017-11-30 08:35:02 -06:00
Ryan Farley
f7b0ac503e generate pytest envs with tox factors
This eliminates all separate pytest envs in favor of conditionals in
[testenv]. This requires renaming some environments to make the lack of
certain functionality explicit:

- instead of omitting pyqt{version}, use pyqtlink to use host PyQt

tox.ini: eliminate -nocov

It is possible to set the `PYTEST_ADDOPTS` environment variable to
enable coverage checks, rather than a new command.
2017-11-30 08:29:00 -06:00
Ryan Roden-Corrent
4497f710f9 Try SIGINT instead of SIGTERM for windows. 2017-11-30 07:56:37 -05:00
Florian Bruhin
45a1989a1f Add some more links to initial readme line
[ci skip]
2017-11-30 01:26:44 +01:00
mhm@mhm.com
d29cf1ee4d lazy sessions, restore if visible, forward user after restore 2017-11-30 00:09:28 +01:00
Florian Bruhin
ac89ab23a9 Revert "Add nEXT to list of alternatives"
It uses a buggy legacy WebKit...
This reverts commit 814a88b741.
2017-11-29 22:36:06 +01:00
Florian Bruhin
2752055281 Fix lint in webserver_sub.py 2017-11-29 22:17:48 +01:00
Ryan Roden-Corrent
b465c109ee Fix test_editor_bdd.py for windows.
- Use a raw string to handle windows path separators
- Use SIGTERM instead of SIGUSR1
2017-11-29 07:42:12 -05:00
Ryan Roden-Corrent
fcad40ceb7 Add orphaned tab check to WebKit as well.
This implements the orphaned editor fix for WebKit. Webkit wasn't
crashing before, but this causes webkit to show the same warning
webengine does if the editor is orhpaned (rather than silently
continuing). This allows the same BDD test to pass for both webkit and
webengine.
2017-11-29 07:35:11 -05:00
Ryan Roden-Corrent
e09a8c77e9 Simplify check for orphaned editor.
Instead of rewiring signals on tab.shutting_down, have the webelem check
if its parent tab is deleted, and throw a specific exception.

This is only necessary in WebEngine, Webkit does not crash when the
editor is orphaned.

I tried to write a test for is_deleted, but could not get it to pass:
```
def test_is_deleted(qtbot, view, config_stub, tab_registry, mode_manager):
    tab_w = Tab(win_id=0, mode_manager=mode_manager)
    qtbot.add_widget(tab_w)
    tab_w._set_widget(view)
    assert not tab_w.is_deleted()
    sip.delete(view)
    #assert tab_w.is_deleted()
```

The qtbot post-test cleanup would error due to the deleted view.
2017-11-29 07:01:48 -05:00
Florian Bruhin
81045fb1bd Drop unneeded parens 2017-11-29 10:44:50 +01:00
Florian Bruhin
af638ec430 Move hint unittests to their own file 2017-11-29 10:44:32 +01:00
Florian Bruhin
911616707e Merge remote-tracking branch 'origin/pr/3329' 2017-11-29 10:40:40 +01:00
Florian Bruhin
edba3f83bc Bump open_url_in_instance version to 1.0.4 2017-11-29 10:38:09 +01:00
Florian Bruhin
e7c4df7a9c Merge remote-tracking branch 'origin/pr/3332' 2017-11-29 10:38:06 +01:00
Rouji
afb4a6be51 bump _qb_version 2017-11-29 08:43:46 +01:00
Rouji
938198e92a quote _qute_bin (paths may contain whitespace), remove unnecessary --backend
argument
2017-11-29 08:43:02 +01:00
Rouji
d4291dd4ae don't 'exec' printf 2017-11-29 08:40:40 +01:00
Jay Kamat
19cecbdeae Fix style issues in scattered hint tests 2017-11-28 22:08:22 -05:00
Florian Bruhin
43ff35eaea Revert "Make sure docs are up-to-date for navigate.feature"
This action doesn't exist in navigate.feature

This reverts commit 3857491cf9.
2017-11-28 22:15:56 +01:00
Florian Bruhin
26edf55f85 Update install instructions for Fedora/OpenBSD 2017-11-28 17:56:17 +01:00
Florian Bruhin
3857491cf9 Make sure docs are up-to-date for navigate.feature 2017-11-28 17:06:41 +01:00
Florian Bruhin
ca74991900 Read backend after args.temp_settings
This should hopefully not affect any config change handlers, as almost nothing
is registered this early.

Fixes #3340
2017-11-28 17:00:45 +01:00
Ryan Roden-Corrent
01a9405391 Make ophaned editor test less flaky.
Instead of having the editor sleep a short time, explicitly send it a
signal to exit.
2017-11-28 08:38:04 -05:00
Ryan Roden-Corrent
9dfc6b0f61 Change wording for orphaned editor.
The term "vanished" is used elsewhere.
2017-11-28 08:37:38 -05:00
Ryan Roden-Corrent
b6dcd4d387 Reapply "Hide quickmark/bookmark completion if empty."
This reverts commit e72e8b8556.

Now that the SQL category works in isolation, it is possible to hide
quickmarks/bookmarks when those categories are empty.

Fixes #960
2017-11-28 07:21:26 -05:00
Florian Bruhin
b407f4ab41 Release v1.0.4 2017-11-28 10:56:15 +01:00
Florian Bruhin
9a8d68aa25 Mark :undo test as flaky
I don't get why it fails sometimes - so another @flaky stop-gap for now.
2017-11-28 09:19:37 +01:00
Florian Bruhin
93bdff5d40 Merge remote-tracking branch 'origin/pr/3330' 2017-11-28 08:29:17 +01:00
Florian Bruhin
56759cca6b Make more unit tests run with Qt 5.7.1 on a newer Linux 2017-11-28 08:16:07 +01:00
Florian Bruhin
0850aab96f Merge remote-tracking branch 'origin/pr/3337' 2017-11-28 07:58:42 +01:00
Florian Bruhin
1d17e7ab03 Update changelog 2017-11-28 07:04:57 +01:00
Florian Bruhin
ef1825efb0 Handle sqlite errors during :history-clear 2017-11-28 07:02:33 +01:00
Florian Bruhin
73587b1e16 Add SQLITE_CORRUPT to environmental SQL errors 2017-11-28 06:55:55 +01:00
Florian Bruhin
4fed8518e1 Handle "out of memory" error in sql.init() 2017-11-28 06:53:41 +01:00
Florian Bruhin
814a88b741 Add nEXT to list of alternatives
[ci skip]
2017-11-28 06:24:45 +01:00
Ryan Roden-Corrent
40e4e73e36 Ensure HistoryCategory works in isolation.
While QSortFilterProxyModel emits layoutChanged when changing the
pattern, QSqlQueryModel emits modelReset. As only layoutChanged was
connected, a HistoryCategory would only work in a model that also had at
least one ListCategory.

The simplest solution is to have the parent model emit the signal
directly. This also emits a single signal on a pattern change rather
that one for each child model.

Resolves #3016.
2017-11-27 11:49:32 -05:00
pyup-bot
9a8bac18ae Update pluggy from 0.5.2 to 0.6.0 2017-11-27 16:02:24 +01:00
pyup-bot
b820b9d530 Update pytest-qt from 2.2.1 to 2.3.0 2017-11-27 16:02:22 +01:00
pyup-bot
5f30016901 Update hypothesis from 3.38.0 to 3.38.5 2017-11-27 16:02:21 +01:00
pyup-bot
54db781b97 Update hunter from 2.0.1 to 2.0.2 2017-11-27 16:02:20 +01:00
pyup-bot
5df2025745 Update cheroot from 5.9.1 to 5.10.0 2017-11-27 16:02:18 +01:00
pyup-bot
6c47b5d2d7 Update setuptools from 36.8.0 to 38.2.1 2017-11-27 16:02:17 +01:00
pyup-bot
a4b96c3443 Update check-manifest from 0.35 to 0.36 2017-11-27 16:02:15 +01:00
Jimmy
0381d74e9a Greasemonkey: privatise some utility functions 2017-11-27 20:10:38 +13:00
Florian Bruhin
0e80be2d30 Clear end2end test data again after initializing
If we don't do this, earlier tests can affect later ones when e.g. using "...
should not be logged", as we don't really wait until a test has been fully
finished.
2017-11-27 20:10:38 +13:00
Florian Bruhin
db353c4030 Connect the page signal for GreaseMonkey
Looks like we don't get the mainFrame's loadFinished signal properly.
2017-11-27 20:10:38 +13:00
Florian Bruhin
6933bc05b4 Add some debug logging for GreaseMonkey with QtWebKit 2017-11-27 20:10:38 +13:00
Jimmy
df624944f9 Greasemonkey: webkit: injected all scripts on loadFinished.
The signal we were using to inject greasemonkey scripts registered to
run at document-start (javaScriptWindowObjectCleared) was unreliable to
non-existant. The initialLayoutCompleted signal is a bit of an odd duck
too I suppose. Anyway, we don't anticipate any scripts would break from
being injected when the page is finished loaded that wouldn't already
have been flaky due to the complexities of the modern web. If there is
an issue hopefully someone raises an issue and we can look into it.
2017-11-27 20:10:38 +13:00
Jimmy
8a5b42ffbd Greasemonkey: es6ify the greasemonkey wrapper js.
Because backwards compatibility sucks I guess.
2017-11-27 20:10:38 +13:00
Jimmy
92b48e77c7 Greasemonkey: add unit tests for GreasemonkeyManager 2017-11-27 20:10:38 +13:00
Jimmy
dd59f8d724 Greasemonkey: add more end2end tests
Test document-end and noframes. Because coverage.py told me to.
Hopefully this doesn't slow the test run down too much, particularly the
"should not be logged" bit.

I'm just reusing and existing test html page that used an iframe because
I'm lazy.
2017-11-27 20:10:38 +13:00
Jimmy
361a1ed6e4 Greasemonkey: change PROPS_REGEX to handle non-value keys.
We weren't actually picking up the @noframes greasemonkey directive
because of this. I haven't tested this very extensively but it seems to
work for making the property value optional.
2017-11-27 19:27:31 +13:00
Jimmy
9aeb5775c1 greasemonkey: run scripts on subframes on webkit
Use the `QWebPage.frameCreated` signal to get notifications of subframes
and connect the javascript injection triggering signals on those frames
too.

I had to add a `url = url() or requestedUrl()` bit in there because the
inject_userjs method was getting called to early or something when
frame.url() wasn't set or was set to the previous page so we were
passing the wrong url to greasemonkey.scripts_for().

I ran into a bizarre (I maybe it is completely obvious and I just don't
see it) issue where the signals attached to the main frame that were
connected to a partial function with the main frame as an argument were
not getting emitted, or at least those partial functions were not being
called. I worked around it by using None to mean defaulting to the main
frame in a couple of places.
2017-11-27 19:27:31 +13:00
Jimmy
4c3461038d Greasemonkey: add minimal end-to-end test.
Just runs a greasemonkey script on a test page and uses console.log to
ensure it is running.

Tests @include, and basic happy path greasemonkey.py operation (loading
and parsing script, scrip_for on webkit), only testing document-start
injecting point but that is the troublsome one at this point.

Tested on py35 debian unstable (oldwebkit and qtwebengine5.9) debian
stable qtwebengine5.7.

Note the extra :reload call for qt5.7 because document-start scripts
don't seem to run on the first page load with the current insertion
point. I need to look into this more to look at ways of fixing this.
2017-11-27 19:27:31 +13:00
Jimmy
7c497427ce Greasemonkey: various javascript fixups to GM wrapper template.
Thanks to @sandrosc. A few breaking changes fixed (default method to
GM_xhr not working, GM_listvalues not cleaning up output, GM_setvalue
param checking logic wrong) and a few hygenic changes made.
2017-11-27 19:27:31 +13:00
Jimmy
c0832eb04b Greasemonkey: support @nosubframes.
And run on frames by default. At least on webengine. There is probably
some api to enumerate frames on a webkit page.

Not tested.
2017-11-27 19:27:31 +13:00
Jimmy
fb019b2dab Address second round line comments.
Add qute version to GM_info object in GM wrapper.
Support using the greasemonkey @namespace metadata for its intended
purpose of avoiding name collisions.
Get a nice utf8 encoded string from a QUrl more better.
2017-11-27 19:27:31 +13:00
Jimmy
efde31aa57 Greasemonkey: Support QTWebEngine versions < 5.8
QTWebEngine 5.8 added support for parsing greasemonkey metadata blocks
and scripts added to the QWebEngineScriptCollection of a page or its
profile and then deciding what urls to run those scripts on and at what
point in the load process to run them. For earlier versions we must do
that work ourselves. But with the additional handicap of the less rich
qtwebengine api.

We have acceptNavigationRequest, loadStarted, loadProgress,
loadFinished, urlChanged to choose from regarding points at which to
register scripts for the current page.

Adding scripts on acceptNavigation loadStarted and loadFinished causes
scripts to run too early or too late (eg on the pages being navigated
from/to) and not run on the desired page at the time they are inserted.
We could maybe do some more sophisticated stuff with loadProgress but it
didn't have any better behaviour in the brief testing I gave it.
Registering scripts on the urlChanged event seems to work fine. Even if
it seems like there could be problems with the signal firing too often,
due to not necessarily being tied to the page load progress, that
doesn't seem to have an effect in practice. The event is fired when, for
example, the url fragment changes and even if we add a new script to the
collection (or remove an existing one) it doesn't have an effect on what
is running on the page.

I suspect all of those timing issues is due to the signals being
forwarded fairly directly from the underlying chomium/blink code but the
webengine script stuff only being pushed back to the implementation on
certain events.

Anyway, using urlChanged seems to work fine due to some quirk(s) of the
implementation. That might change with later development but this
codepath is only ever going to be used for version 5.7.

There are other potential optimizations like not removing and then
re-adding scripts for the current page. But they probably wouldn't do
anything anyway, or at least anything that you would expect.
2017-11-27 19:27:31 +13:00
Jimmy
209e43e0ba Greasemonkey: Match against percent encoded urls only.
This change requires urls specified in @include, @exclude and @matches
directives in metadata blocks to be in the same form that
QUrl.toEncoded() returns. That is a punycoded domain and percent encoded
path and query. This seems to be what Tampermonkey on chrome expects to.

Also changes the scripts_for() function to take a QUrl arg so the caller
doesn't need to worry about encodings.
2017-11-27 19:27:31 +13:00
Jimmy
d318178567 Greasemonkey: Fix metadata block regex.
This regex was broken since the original PR and subsequent code seemed to be
working around it. Before re.split was returning [everything up to
/UserScript, everything else], now it returns [before UserScript, metadata,
after /UserScript], which is good.

Also I added the check for the UserScript line starting at column 0 as per
spec.
2017-11-27 19:27:31 +13:00
Jimmy
5e49e7eef2 Greasemonkey: Throw Errors if GM_ function args wrong type.
These argument type restrictions are mentioned on the greasespot pages for
these value storage functions. We could call JSON.dumps() instead but better
to push that onto the caller so we don't have to try handle deserialization.

Also removes the check for localstorage because everyone has supported that
for years.
2017-11-27 19:27:31 +13:00
Jimmy
d93c583c0d Greasemonkey: Escape jinja variables for JS strings. 2017-11-27 19:27:31 +13:00
Jimmy
a7f41b4564 Greasemonkey: ensure only GM scripts are cleaned up on reload.
WebEngine only. Previously we were just removing every script from the
main world. But some other scripts might got here in the future so new
we are overriding the name field to add a GM- prefix so hopefully we
only remove greasemonkey scripts before adding new ones.
2017-11-27 19:27:31 +13:00
Jimmy
fd5d44182b Greasemonkey: move GM_* template into seperate file.
Also ported it to jinja rather than str.format().

Also ran the js through jslint and fixed up a few very minor things.
2017-11-27 19:27:31 +13:00
Jimmy
c1b912f567 Greasemonkey: move inject_userscripts into webenginesettings 2017-11-27 19:27:31 +13:00
Jimmy
edf737ff7d Greasemonkey: move scripts for a domain into data class.
Also makes scripts that don't include a greasemonkey metadata block
match any url. QWebEngine already has that behaviour.
2017-11-27 19:27:31 +13:00
Jimmy
41035cb5ca Greasemonkey: restrict page schemes that scripts can run on
Scripts shouldn't run on qute://settings or source:// etc.

Whitelist from:
https://wiki.greasespot.net/Include_and_exclude_rules
2017-11-27 19:27:31 +13:00
Jimmy
799730f686 Remove GM_ and userscript variables from global scope. 2017-11-27 19:27:31 +13:00
Jimmy
325c595b89 Greasemonkey: Don't strip gm metadata from scripts when loading.
Since we just pass them to webenginescriptcollection on that backend and
that wants to parse it itself to figure out injection point etc.
2017-11-27 19:27:31 +13:00
Jimmy
f26377351c Greasemonkey: Add greasemonkey hooks for webengine.
For qtwebengine 5.8+ only. This is because as of 5.8 some greasemonkey
script support is in upstream. That is, qtwebenginescript(collection)
parses the greasemonkey metadata block and uses @include/match/exclude
to decide what sites to inject a script onto and @run-at to decide when
to inject it, which saves us the trouble. Notes on doing this in <5.8
are below.

Scripts are currently injected into the main "world", that is the same
world as the javascript from the page. This is good because it means
userscripts can modify more stuff on the page but it would be nice if we
could have more isolation without sacrificing functionality. I'm still
looking into why my more feature-full scripts are not having any effect
on the page while running in a separate world.

Userscripts are added to both the default and private profile because I
that if people have scripts installed they want them to run in private mode
too.

We are grabbing the scripts from the greasemonkey module, as opposed to
reading them directly from disk, because the module adds some GM_* functions
that the scripts may expect, and because that is used for webkit anyway.

I have code to support qtwebengine <5.8 but didn't because I am not
happy with the timing of some of the signals that we are provided
regarding page load state, and the actual load state. While the
difference between document-end and document-idle isn't so bad,
injecting document-start scripts when a urlChanged event is emitted
results in the script being injected into the environment for the page
being navigated away from. Anyway, if anyone wants this for earlier
webengines I can oblige them.
2017-11-27 19:27:31 +13:00
Jimmy
be9f8bd0de Greasemonkey: Lift greasemonkey init app.py
To prepare for multiple-backend support.
2017-11-27 19:27:31 +13:00
Jimmy
25f626a436 Greasemonkey: Add run-at document-idle.
Supposed to be after all the assets have finished loading and in page js
has run. Not that we can garuntee that last bit. If a script misbehaves
because a precondition isn't yet met I suggest adding a defer method to
the script that adds a timer until the precondition is met.

Also changed the map/filter calls to use list comprehensions to keep
pylint happy. Even if it does look uglier.
2017-11-27 19:27:31 +13:00
Jimmy
13728387d7 Greasemonkey: Fix crash on undefined metadata. 2017-11-27 19:27:31 +13:00
Jimmy
ecdde7663f Add greasemonkey-reload command.
Also add a signal to emit when scripts are reloaded. Had to make
GreasemonkeyManager inherit from QObject to get signals to work.
2017-11-27 19:27:31 +13:00
Andor Uhlár
568d60753e Add greasemonkey compatible userscript module.
WebKit backend only for now. Loads all .js files from a directory,
specified in the greasemonkey-directory key in the storage section,
defaulting to data/greasemonkey, and wraps them in a minimal environment
providing some GM_* functions. Makes those scripts available via the
"greasemonkey" registered object in objreg and injects scripts at appropriate
times in a page load base on @run-at directives.
2017-11-27 19:27:31 +13:00
Florian Bruhin
75a8938e83 Add flake8-bugbear 2017-11-26 21:50:12 +01:00
Florian Bruhin
248a12a8b9 Add flake8-comprehensions 2017-11-26 21:42:50 +01:00
Florian Bruhin
1981239478 Add flake8-builtins 2017-11-26 21:22:33 +01:00
Florian Bruhin
5490f70b25 Remove flake8-pep3101
It seems to trigger when using modulo on ints as well, which is kind of
annoying.

See #3320
2017-11-26 20:30:42 +01:00
Florian Bruhin
b5dd647678 Upgrade pydocstyle/flake8-docstrings
See #3320
2017-11-26 20:30:32 +01:00
Florian Bruhin
7520a365eb Update comments 2017-11-26 19:43:49 +01:00
Florian Bruhin
0f3cff60fa Merge remote-tracking branch 'origin/pr/3335' 2017-11-26 19:42:54 +01:00
Florian Bruhin
95f34d755f Update changelog 2017-11-26 19:35:58 +01:00
Florian Bruhin
38f8cacd2b Merge remote-tracking branch 'origin/pr/3336' 2017-11-26 19:35:26 +01:00
Florian Bruhin
4c1f6158bd Update changelog
[ci skip]
2017-11-26 17:32:29 +01:00
Florian Bruhin
67253726fa Handle empty messages in qt_message_handler
I can't reproduce this, but someone on KDE reported always getting a crash (as
msg.splitlines()[0] gives an IndexError) when trying to select a file with
Qt 5.9.3.
2017-11-26 17:31:07 +01:00
Ryan Roden-Corrent
54fffc8264 Resolve crash when editor tab is closed.
If an editor is open on a form in a tab and that tab is closed, rewire
the callback to print a warning. Previously, the callback would access a
deleted C++ object and cause a crash.
Resolves #2758.
2017-11-26 07:50:49 -05:00
Panagiotis Ktistakis
2bb8d404d2 Adjust :bind completion tests 2017-11-26 14:07:41 +02:00
Panagiotis Ktistakis
e05dabefdf Show default keybinding in :bind completion 2017-11-26 13:34:18 +02:00
Ryan Farley
650b0051e6 remove useless ignores 2017-11-26 01:59:21 -06:00
Ryan Farley
5ed8019115 update flake8 and flake8-deprecated
Updated requirements and adjusted the configuration in `.flake8`; other
files have been modified where the lack of per-file auto-ignore caused
problems, where putty's `# flake8: disable=` syntax could be replaced
with a simpler `noqa`, or where pylint directives already suppressed the
same error.
2017-11-26 00:16:14 -06:00
狼耳
e8db59a9ef Use socat exit status to determine if the socket is usable
Instead of checking, if *any* qutebrowser process is running (which may or may not have an IPC socket where we expect it), simply launch a new instance  *if socat fails*. 
Which it does, if: 
* the socket file doesn't exist (qutebrowser simply not running), or
* the socket isn't connectable (qutebrowser crashed, left orphaned socket)
 
Also put new instances into background, so the script behaves a bit more consistently. (Else it *sometimes* blocks and *sometimes doesn't*, when run.)
2017-11-25 11:09:57 +01:00
Jay Kamat
c9af36909f Add tests for hint scattering 2017-11-24 13:21:21 -05:00
mhm@mhm.com
9df149fe8f urlencode fix 2017-11-24 17:15:26 +01:00
Florian Bruhin
03a9cbdfb4 Break long lines
(cherry picked from commit 18a45bbd5b)
2017-11-24 16:03:34 +01:00
狼耳
765a22189c check if qutebrowser process is running
Sometimes when qutebrowser crashes, it leaves the IPC socket file behind. In those cases this script still tried to use it, failed, and didn't open your URL at all.
2017-11-24 14:52:33 +01:00
Florian Bruhin
06fc52321e Ignore new Qt 5.9.3 error message 2017-11-24 14:24:15 +01:00
Florian Bruhin
15c7ede916 Update to PyQt 5.9.2 2017-11-24 14:24:15 +01:00
Lucas Hoffmann
6cc78aeaee Register qutebrowser as a handler for qute:// links
These links mostly occur within qutebrowser's documentation.  But the
are also written to the auto generated config file.  Clicking them in
any application that consults the desktop database (or uses xdg-open)
will thus open them in qutebrowser correctly.
2017-11-24 13:32:13 +01:00
Florian Bruhin
0afd6b23c9 Add the option name to the backend error message 2017-11-24 09:25:45 +01:00
Florian Bruhin
28d7c5e204 Fix lint 2017-11-24 07:25:10 +01:00
Jay Kamat
739cfc03ba Fix undercounting short hints 2017-11-23 23:14:21 -05:00
Ryan Roden-Corrent
8eab402820 Abort :edit-command on invalid input.
Show an error message if the user edits the command such that it is
missing a start character (:, /, or ?). Previously, this would cause the
browser to crash.

Resolves #3326.
2017-11-23 08:15:27 -05:00
Florian Bruhin
b31360b6e3 Fix line break 2017-11-22 17:19:21 +01:00
Florian Bruhin
750d2c490f Fix :completion-item-focus --history with / or ?
If we have no completion (like when searching), we can just always go through
history with up/down.
2017-11-22 15:34:48 +01:00
Florian Bruhin
5d8c9577a7 Improve hypothesis example generation for configtypes.Dict 2017-11-22 11:53:49 +01:00
Florian Bruhin
72d466d236 Break long lines 2017-11-22 11:34:10 +01:00
Florian Bruhin
487951cd31 Fix joining :jseval path 2017-11-22 10:57:48 +01:00
Florian Bruhin
cbf5fc01fa Avoid more about:blank loads 2017-11-22 10:15:18 +01:00
Florian Bruhin
221b81ae90 Fix typo in changelog 2017-11-22 09:37:17 +01:00
Florian Bruhin
12f4940ef3 Make :jseval use a fixed path with relative paths 2017-11-22 09:37:17 +01:00
Florian Bruhin
3b3acba34e Edit description of tabs.persist_mode_on_change 2017-11-22 09:11:17 +01:00
Florian Bruhin
2581be051f Always leave hint/caret mode when switching tabs
See #3323
2017-11-22 08:53:01 +01:00
Florian Bruhin
401a37bf4b Stabilize :spawn with userscript tests 2017-11-22 08:43:47 +01:00
Florian Bruhin
e5cabb6d23 Match QtWebKit error message for qute://help/img test 2017-11-22 08:40:20 +01:00
Florian Bruhin
fd93e7ba6c Update docs 2017-11-22 08:02:38 +01:00
Florian Bruhin
94b2a41ed7 Merge remote-tracking branch 'origin/pr/3323' 2017-11-22 08:00:57 +01:00
Florian Bruhin
aa417019ae Try stabilizing loading about:blank in end2end tests 2017-11-22 07:59:22 +01:00
Florian Bruhin
8acfe501fe Revert "Stabilize cleaning up open tabs"
We're going to fix this in a more generic way.

This reverts commit 8440303d82.
2017-11-22 07:56:31 +01:00
Florian Bruhin
c4291a8ed5 Update GitHub contributing docs 2017-11-22 07:52:03 +01:00
mhm@mhm.com
e2d5a443cc lazy sessions 2017-11-21 23:57:06 +01:00
Vladimir Shulyak
358c888760 Fix long line 2017-11-21 22:35:19 +00:00
Vladimir Shulyak
7532db83c4 Add option to persist current mode on tab change 2017-11-21 18:57:41 +00:00
Florian Bruhin
b684e50cdf Stabilize view-source test 2017-11-21 18:14:17 +01:00
Florian Bruhin
9744a3d0bc Skip test_webenginesettings without QtWebEngine 2017-11-21 17:58:32 +01:00
Florian Bruhin
8440303d82 Stabilize cleaning up open tabs
For some reason, about:blank isn't properly loaded sometimes. But this should
always work.
2017-11-21 14:53:31 +01:00
Florian Bruhin
2f12233cb7 Update changelog 2017-11-21 14:10:48 +01:00
Florian Bruhin
6c9f496edf Add a test for setting content.cache.size to a big value 2017-11-21 14:09:38 +01:00
Florian Bruhin
a451e8ac9d Add a cache_tmpdir fixture 2017-11-21 14:09:30 +01:00
Florian Bruhin
c9d42c8bea Enable strict overflow checking in tests 2017-11-21 14:09:20 +01:00
Florian Bruhin
203b6c354f Fix content.cache.size overflow with QtWebEngine
While 64-bit values are allowed with QtWebKit/QNetworkDiskCache, QtWebEngine
only allows 32-bit values here. With the updated sip's strict overflow checking,
that means we get an exception when setting a too big value.
2017-11-21 14:07:49 +01:00
Florian Bruhin
75555fc244 Fix warning regex 2017-11-21 13:21:50 +01:00
Florian Bruhin
cff557d2fc Try to stabilize command test, take 2 2017-11-21 13:19:11 +01:00
Florian Bruhin
56d1c5c7dd Stabilize command history test 2017-11-21 11:31:22 +01:00
Florian Bruhin
54af872825 Add missing comma 2017-11-21 10:45:49 +01:00
Florian Bruhin
dc00bc1774 Add an initial Makefile 2017-11-21 10:35:11 +01:00
Florian Bruhin
273747624f Update tox environment list in contributing docs 2017-11-21 09:24:43 +01:00
Florian Bruhin
c3128494a1 Create CODE_OF_CONDUCT.md 2017-11-21 09:19:06 +01:00
mhm@mhm.com
607cd9ba6e indent adjusted 2017-11-21 01:19:04 +01:00
mhm@mhm.com
aa40842848 lazy sessions, docstring formatted, settings renamed, javascript notice changed, insert method changed 2017-11-21 00:38:51 +01:00
Florian Bruhin
d90d626ac4 Merge remote-tracking branch 'origin/pr/3316' 2017-11-20 21:17:29 +01:00
Florian Bruhin
25be4d4383 Merge remote-tracking branch 'origin/pr/3318' 2017-11-20 21:16:57 +01:00
Florian Bruhin
203233c894 Track the view correctly in the webengineview fixture
This makes sure the view is closed after the test (fixing test_none on AppVeyor)
and also makes sure we have a QApplication.
2017-11-20 20:47:40 +01:00
Florian Bruhin
a5d9661d73 Simplify is_ignored_lowlevel_message 2017-11-20 19:29:31 +01:00
Ryan Roden-Corrent
5495380580 Exit command mode after :edit-command --run.
Resolves #3317, where the command prompt was left open and populated
with text after running the command.
2017-11-20 11:46:26 -05:00
pyup-bot
feb02769ad Update pytest from 3.2.3 to 3.2.5 2017-11-20 16:02:20 +01:00
pyup-bot
8dcd5708e3 Update py from 1.4.34 to 1.5.2 2017-11-20 16:02:19 +01:00
pyup-bot
934fb5f7d5 Update py from 1.4.34 to 1.5.2 2017-11-20 16:02:17 +01:00
pyup-bot
b3d757d034 Update hypothesis from 3.37.0 to 3.38.0 2017-11-20 16:02:16 +01:00
pyup-bot
8f0332bcf6 Update cheroot from 5.8.3 to 5.9.1 2017-11-20 16:02:14 +01:00
pyup-bot
1cc6e7190e Update setuptools from 36.7.1 to 36.8.0 2017-11-20 16:02:13 +01:00
Florian Bruhin
abb5c9f638 Ignore Qt 5.7 OpenSSL logging message 2017-11-20 13:58:37 +01:00
Florian Bruhin
3b680d0bff Pass --disable-seccomp-filter-sandbox for tests with Qt 5.7.1
This is a stop-gap so I'm able to run end2end tests at least.
See #3163.

For unit tests, we need https://github.com/pytest-dev/pytest-qt/pull/193 first.
2017-11-20 13:54:52 +01:00
Florian Bruhin
b6bfe7c171 Update docs 2017-11-19 21:11:10 +01:00
Florian Bruhin
8555b86e3b Add copyright notice for pyeval_file.py 2017-11-19 21:09:48 +01:00
Florian Bruhin
a2c549b954 Merge remote-tracking branch 'origin/pr/3313' 2017-11-19 21:09:19 +01:00
Florian Bruhin
87b174b418 Simplify :completion-item-focus 2017-11-19 21:07:33 +01:00
Florian Bruhin
112800bab9 Fix backslashes in string 2017-11-19 21:04:57 +01:00
Florian Bruhin
62f37df573 Make cursor keys go through completion if a text was entered
This hopefully helps with people who try to use arrow keys for the completion,
while still making the command history somewhat discoverable.
2017-11-19 20:35:16 +01:00
akhilkpdasan
740d629b36 Update utilcmds.py 2017-11-20 00:56:09 +05:30
Florian Bruhin
c14135a6ce Add :edit-command to docs 2017-11-19 19:57:44 +01:00
Akhil kp
21e731ebeb fixed build errors(typing errors) 2017-11-19 23:49:11 +05:30
akhilkpdasan
9a58fe229c fixed spelling error 2017-11-19 19:32:24 +05:30
akhilkpdasan
4644642c38 fixed test for pyeval --file 2017-11-19 19:10:36 +05:30
akhilkpdasan
ba6d90aa7a fixed docmentation for pyeval 2017-11-19 19:08:52 +05:30
Florian Bruhin
6a90cebe85 Get rid of backslash 2017-11-19 14:29:22 +01:00
Florian Bruhin
28d3771005 Update changelog 2017-11-19 14:25:47 +01:00
Florian Bruhin
5e20aa668a Merge remote-tracking branch 'origin/pr/3262' 2017-11-19 14:24:48 +01:00
Florian Bruhin
91c909cb80 Merge remote-tracking branch 'origin/pr/3212' 2017-11-19 14:24:40 +01:00
Florian Bruhin
8cd9cdea84 Update changelog 2017-11-19 14:11:20 +01:00
Florian Bruhin
8c7bf12b88 Merge remote-tracking branch 'origin/pr/3306' 2017-11-19 14:08:58 +01:00
Florian Bruhin
c2973ebca3 Merge remote-tracking branch 'origin/pr/3305' 2017-11-19 14:07:26 +01:00
Florian Bruhin
1a1f0fc1ee Update changelog 2017-11-19 14:06:11 +01:00
Florian Bruhin
2b063f577e Handle OSError in :config-write-py 2017-11-19 14:06:11 +01:00
Florian Bruhin
8fb03208e7 Improve parsing of fatal stacktraces
We now also recognize "Windows fatal exception: ..." message and refuse to
send empty Windows access violation messages.
2017-11-19 14:06:11 +01:00
Florian Bruhin
4a37e40fcc Merge pull request #3311 from novel/doc-freebsd-port
Document installation using FreeBSD port
2017-11-19 14:05:00 +01:00
Akhil kp
c5eab53a87 Added --file for :debug-pyeval 2017-11-19 18:20:58 +05:30
Roman Bogorodskiy
51ce534638 Document installation using FreeBSD port 2017-11-19 14:30:32 +04:00
Ryan Roden-Corrent
d145b304d0 Remove maxsplit from edit_command.
This was a copy-paste typo, no need for maxsplit as this command takes
no positional args.
2017-11-18 20:41:23 -05:00
mhm@mhm.com
13dc24f6ca debug code removed 2017-11-18 14:31:55 +01:00
mhm@mhm.com
cf8130bd22 lazy session, fix: active entry is not the end of the history 2017-11-18 14:28:44 +01:00
mhm@mhm.com
2debeafe1b lazy sessions, dont save qute://back 2017-11-18 13:51:30 +01:00
mhm@mhm.com
1a33c88c96 lazy sessions, dont save qute://back 2017-11-18 13:47:57 +01:00
mhm@mhm.com
c150c5481a lazy sessions, dont save qute://back 2017-11-18 13:46:50 +01:00
mhm@mhm.com
c4bb134313 lazy sessions, improved version 2017-11-18 11:05:54 +01:00
Jay Kamat
6338810396 Increase timeouts for javascript tests 2017-11-17 21:42:24 -05:00
mhm@mhm.com
51dea053f4 lazy sessions 2017-11-18 01:00:16 +01:00
mhm@mhm.com
ade7004f8f lazy sessions 2017-11-18 00:48:31 +01:00
mhm@mhm.com
95f8c07d7f lazy sessions 2017-11-18 00:31:53 +01:00
Jay Kamat
6c241f96ed Add test for appendChild #2723
Does some of #3295
2017-11-17 17:52:35 -05:00
cryzed
d8887f12c0 Deduplicate documentation 2017-11-17 21:40:08 +01:00
Ryan Roden-Corrent
0f93d53210 Implement :edit-command.
:edit-command opens the current command line in an editor, and updates
the command line if the editor exits successfully. If --run is passed,
the command is executed when the editor exits sucessfully.

Resolves #2453.
2017-11-17 11:16:42 -05:00
Josefson Fraga
3131d3d3bc Flake8 warnings pointed by travis. 2017-11-17 11:48:34 -03:00
cryzed
274c92a64b Add documentation additionally to the help page of qute-pass (complaint from the Arch wiki) 2017-11-17 12:42:25 +01:00
Josefson Fraga
96599b9684 revisions set by The Compiler 2017-11-17 02:38:56 -03:00
Florian Bruhin
3a012ca1e3 Update changelog 2017-11-16 11:21:00 +01:00
Florian Bruhin
b26f2290bc Merge remote-tracking branch 'origin/pr/3097' 2017-11-16 11:14:59 +01:00
Florian Bruhin
e856639db7 Update changelog 2017-11-16 10:19:47 +01:00
Florian Bruhin
b3085f5d60 Merge remote-tracking branch 'origin/pr/3291' 2017-11-16 10:17:02 +01:00
Florian Bruhin
e3a3edaf9a Update list of alternatives
[ci skip]
2017-11-16 10:05:26 +01:00
Florian Bruhin
47480d07f0 Make the docs for a tox wrapper script clearer
[ci skip]
2017-11-16 08:52:28 +01:00
Florian Bruhin
625a2c3060 Merge remote-tracking branch 'origin/pr/3293' 2017-11-16 08:03:02 +01:00
Ryan Farley
e2169d2d92 importer: fix style issues 2017-11-15 20:00:14 -06:00
Florian Bruhin
8104869ab6 Update docs 2017-11-15 13:04:11 +01:00
dwagle
233cea4b62 discarded unnecessary comment and adjusted some code to make pylint happy, also made adjustments to pytest scenarios 2017-11-15 15:48:21 +05:45
Florian Bruhin
dbefaccf06 Set python_requires in setup.py 2017-11-15 09:47:45 +01:00
Panagiotis K
e4be834b39 Platform-agnostic test. 2017-11-15 09:51:05 +02:00
Jay Kamat
92a6e61b52 Use importorskip to skip stylesheet tests on webkit only systems 2017-11-15 02:05:34 -05:00
Florian Bruhin
ccdd1e5f06 Update changelog 2017-11-15 07:33:03 +01:00
Florian Bruhin
ea71f0e318 Merge remote-tracking branch 'origin/pr/3285' 2017-11-15 07:32:04 +01:00
Florian Bruhin
404f9ea1d0 Merge remote-tracking branch 'origin/pr/3290' 2017-11-15 07:31:10 +01:00
Ryan Farley
2b6763ad13 importer: tests
Added tests for Netscape and Mozilla formats.
2017-11-14 19:23:34 -06:00
dwagle
b3b768f4a8 normalize url path and strip trailing slashes when doing gu/gU, normalize every qute://* urls and raise OSError when a url redirects to a directory in qute://help/ pages 2017-11-14 21:23:40 +05:45
Florian Bruhin
e72e8b8556 Revert "Hide quickmark/bookmark completion if empty."
This reverts commit 23716f1212.

See #3016
Fixes #3288
Reopens #960
2017-11-14 13:29:58 +01:00
Florian Bruhin
9febcc2e76 Use https:// links for qutebrowser.org
Fixes #3289
2017-11-14 10:43:05 +01:00
Florian Bruhin
62f35ee064 Fix lint 2017-11-14 09:05:28 +01:00
Dasith Gunawardhana
ea70a0dea1 changed setting name and reverted non-issue fix 2017-11-14 01:41:15 -05:00
Florian Bruhin
111cc7093f Update changelog 2017-11-14 06:20:09 +01:00
Florian Bruhin
1203be2a44 Remove unnecessary str() call 2017-11-14 06:19:42 +01:00
Jay Kamat
28572ce3b1 Fix stylesheet tests crashing when no QtWebEngine available 2017-11-14 00:00:53 -05:00
Dasith Gunawardhana
4419e59d46 prevent WM fullscreen from being unset when desktop_fullscreen is false 2017-11-13 23:25:10 -05:00
Jay Kamat
4845180689 Update version tests for uptime 2017-11-13 23:20:50 -05:00
Jay Kamat
ae48fa68a8 Add an uptime section to qute:version 2017-11-13 21:58:00 -05:00
Dasith Gunawardhana
36c8ca9790 added option to limit fullscreen to window only 2017-11-13 21:38:02 -05:00
Jay Kamat
5913552dfe Fix style issues in stylesheet tests 2017-11-13 19:57:11 -05:00
Florian Bruhin
408ceefad1 Merge branch 'none-position' 2017-11-13 20:42:22 +01:00
Florian Bruhin
3c9bd25f3d Merge remote-tracking branch 'origin/pr/3284' 2017-11-13 20:40:30 +01:00
Florian Bruhin
870c15a02c Merge remote-tracking branch 'origin/pr/3264' 2017-11-13 20:40:23 +01:00
Ryan Roden-Corrent
b72343d126 Yank selected text with completion-item-yank.
If text is highlighted in the status command bar, completion-item-yank
should yank that rather than the selected completion item.

Resolves #3281.
2017-11-13 13:25:18 -05:00
Jay Kamat
0f17e6633d Stop calling _register automatically for StyleSheetObservers 2017-11-13 12:04:31 -05:00
pyup-bot
ebe44e5f65 Update jinja2 from 2.9.6 to 2.10 2017-11-13 15:59:18 +01:00
pyup-bot
a3f9991ce2 Update hypothesis from 3.36.0 to 3.37.0 2017-11-13 15:59:16 +01:00
pyup-bot
8407d0a227 Update attrs from 17.2.0 to 17.3.0 2017-11-13 15:59:15 +01:00
pyup-bot
327613d02a Update attrs from 17.2.0 to 17.3.0 2017-11-13 15:59:13 +01:00
pyup-bot
ccc671b998 Update setuptools from 36.6.0 to 36.7.1 2017-11-13 15:59:12 +01:00
Florian Bruhin
b9f807011a Update changelog
[ci skip]
2017-11-13 13:11:05 +01:00
Florian Bruhin
df4a011d48 Put files into the config dir with :config-write-py and rel. paths 2017-11-13 10:58:51 +01:00
Florian Bruhin
5c43dca0da Improve error message for files which don't exist 2017-11-13 10:47:37 +01:00
Florian Bruhin
8057f5c281 Set __tracebackhide__ for _check_completions 2017-11-13 09:02:16 +01:00
Florian Bruhin
f6cc6677dd Remove hiding of commands
This was often confusing for people - let's instead just hide commands which are
not available in normal mode.
2017-11-13 09:02:16 +01:00
Florian Bruhin
009fa845f4 Update docs 2017-11-13 07:12:48 +01:00
Florian Bruhin
ec6017b3b2 Remove unneeded parens 2017-11-13 07:09:59 +01:00
Florian Bruhin
7f0ecaa89e Merge remote-tracking branch 'origin/pr/3266' 2017-11-13 07:09:49 +01:00
Florian Bruhin
fc8f2090f0 Merge remote-tracking branch 'origin/pr/3271' 2017-11-13 07:09:29 +01:00
Florian Bruhin
ccb564de36 Merge remote-tracking branch 'origin/pr/3279' 2017-11-13 07:08:53 +01:00
Ryan Roden-Corrent
23716f1212 Hide quickmark/bookmark completion if empty.
If there are no quickmarks/bookmarks, hide the entire category in url
completion. Note that this only hides the category if
quickmarks/bookmarks is empty to begin with. An empty category is still
shown if the completion pattern filters out all items in that category.

See #960.
2017-11-12 22:28:49 -05:00
Florian Bruhin
f6e6f9d27b Make qutebrowser aware of settings requiring a restart
See #3270
2017-11-12 17:17:19 +01:00
Jay Kamat
c1fcabe846 Remove default config-cycle bindings
Many people accidentally hit 'x{x,t,b}', hiding their statusbar by mistake
2017-11-11 16:16:26 -05:00
Jay Kamat
f242fc5cd7 Add setting to avoid shrinking pinned tabs 2017-11-11 11:33:33 -05:00
Jay Kamat
e00a072d15 Fix garbage collection of StyleSheetObserver objects 2017-11-10 23:25:46 -05:00
Jay Kamat
324c537a3d Refactor webkit and webengine js testers to have a common subclass 2017-11-10 13:00:44 -05:00
Jay Kamat
83e28a70c5 Fix error message printing for webengine js tests 2017-11-10 12:34:23 -05:00
Jay Kamat
d39dda38ce Refactor CallbackChecker into test utils 2017-11-10 12:27:00 -05:00
Jay Kamat
155ee198cd Update stylesheet tests for updates in stylesheet.js 2017-11-10 12:19:49 -05:00
Jay Kamat
5ac8e5ad3e Clean up stylesheet tests 2017-11-10 12:19:35 -05:00
Florian Bruhin
c47f0402ab Fix lint 2017-11-10 13:14:51 +01:00
Florian Bruhin
456c854f06 Improve documentation for :hint --rapid 2017-11-10 10:23:16 +01:00
Florian Bruhin
d19d896881 Update changelog 2017-11-10 09:42:27 +01:00
Florian Bruhin
8df759ecad Merge remote-tracking branch 'origin/pr/3259' 2017-11-10 09:42:05 +01:00
Florian Bruhin
fa456b0c6e Update changelog 2017-11-10 09:16:06 +01:00
Florian Bruhin
9bb3f8d677 Regenerate docs 2017-11-10 09:12:24 +01:00
Florian Bruhin
74af52a0c0 Merge remote-tracking branch 'origin/pr/3261' 2017-11-10 09:05:58 +01:00
Florian Bruhin
78f4abf5a1 Merge pull request #3257 from ryan-farley/import-chrome
importer: Chrome support
2017-11-10 09:02:09 +01:00
Jay Kamat
2f9a857a27 Add test for styling error pages 2017-11-09 14:44:33 -05:00
Jay Kamat
04b66e1a0a Add a test for svg files 2017-11-09 14:44:33 -05:00
Jay Kamat
03eae9140e Implement proper loading of stylesheet.js 2017-11-09 14:44:33 -05:00
Jay Kamat
9a1d10ca11 Add tests which override existing css 2017-11-09 14:44:33 -05:00
Jay Kamat
e7fdff5632 Implement basic stylesheet tests 2017-11-09 14:44:32 -05:00
Jay Kamat
2b5e8daba0 Implement qtwebengine version of JSTester 2017-11-09 14:44:32 -05:00
Ulrik de Muelenaere
b37517e55f Fix error in stylesheet.js on older QtWebEngine 2017-11-09 19:28:36 +02:00
Ryan Farley
b5bf114ad4 importer: add chrome profile tests 2017-11-09 02:39:43 -06:00
dkanada
2f7a705015 forgot to update the settings page 2017-11-08 15:29:35 -07:00
dkanada
6ecd429d8f group indicator preferences 2017-11-08 15:27:16 -07:00
dkanada
b8b49637e2 replace changes to desc 2017-11-08 14:46:00 -07:00
dkanada
785bf24652 change the code for the renamed preferences 2017-11-08 14:42:09 -07:00
Ryan Farley
5688fc9910 importer: test unsupported opensearch separate 2017-11-08 15:13:16 -06:00
Ryan Farley
2b7210f6d1 importer: trailing commas 2017-11-08 15:11:07 -06:00
Ryan Farley
8a695648d3 :%s/Qutebrowser/qutebrowser/g 2017-11-08 15:08:20 -06:00
Panagiotis K
59cebae28e Remove redundant import. 2017-11-08 18:23:51 +02:00
Florian Bruhin
7cc3fb4a4e Update FAQ entry for WebKitGTK projects
[ci skip]
2017-11-08 16:44:46 +01:00
cryzed
222c51aa6e Ignore additional Qt error messages 2017-11-08 16:34:40 +01:00
Florian Bruhin
180fb0d65a Fix handling of caret position with Qt 5.10
With Chromium 61 in Qt 5.10, we get null when getting .selectionStart on a
non-text element, like changed in the WhatWG HTML standard:
https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea/input-selectionstart

See https://www.chromestatus.com/feature/5740194741354496

Older QtWebEngines and QtWebKit raise InvalidStateError instead.

This also changes the surrounding code and API so None is used to say "there's
no caret position available", which seems like a nicer API.
2017-11-08 16:27:26 +01:00
cryzed
6e719d1796 Fix issue #3251 2017-11-08 15:08:36 +01:00
Florian Bruhin
b9aa5df5ed Add unit tests for UnicodeEncodeError handling 2017-11-08 07:47:11 +01:00
Florian Bruhin
be08cee63c Make testsuite work with LC_ALL=C 2017-11-07 17:23:38 +01:00
Florian Bruhin
fdc43438ef Make tests for non-ASCII files work 2017-11-07 17:00:08 +01:00
Florian Bruhin
743dbbbcd6 Break long lines 2017-11-07 11:29:53 +01:00
Florian Bruhin
fdc9dfdf87 Merge remote-tracking branch 'origin/pr/3175' 2017-11-07 11:24:41 +01:00
Florian Bruhin
9f898611f3 Add missing path assignment 2017-11-07 11:24:00 +01:00
Florian Bruhin
32914cfaf8 Remove unneeded backslash 2017-11-07 11:17:18 +01:00
Florian Bruhin
3eafdc13d7 Merge remote-tracking branch 'origin/pr/3177' 2017-11-07 11:17:00 +01:00
Florian Bruhin
4a4948e601 Update docs 2017-11-07 10:00:25 +01:00
Florian Bruhin
73a6b6b730 Merge pull request #3252 from qutebrowser/pyup-scheduled-update-11-06-2017
Scheduled weekly dependency update for week 45
2017-11-07 08:19:18 +01:00
Florian Bruhin
0d68b8bb8f Update changelog 2017-11-07 07:47:17 +01:00
Florian Bruhin
4f0d8a84ee Merge remote-tracking branch 'origin/pr/3253' 2017-11-07 07:46:30 +01:00
Florian Bruhin
9f40b40942 Merge pull request #3255 from cincodenada/update-dict-docs
Update documentation to reflect new dictcli.py script
2017-11-07 07:30:38 +01:00
Joel Bradshaw
52be2dd665 Update documents to reflect new dictcli.py script 2017-11-06 22:21:07 -08:00
Florian Bruhin
8ddf843c64 Adjust flake8 pins
Looks like flake8-debugger 3.0.0 works with the old flake8 again, while
flake8-deprecated doesn't anymore (hah, the irony :D).
2017-11-07 06:34:04 +01:00
Florian Bruhin
bc8d767f6e Pin PyQt5 to 5.9 for now
A Linux wheel isn't available yet for 5.9.1, see:
https://www.riverbankcomputing.com/pipermail/pyqt/2017-November/039698.html
2017-11-07 06:32:32 +01:00
Florian Bruhin
aaed6549b3 Merge pull request #3254 from jgkamat/jay/pinned-tabs-mnemonics
Fix Qt Mnemonics affecting min tab width
2017-11-07 06:15:23 +01:00
Ryan Farley
f5d719dfd4 importer: Chrome support
This adds Chrome/Chromium support to the importer (which ought to be the
last of these). Bookmarks are read from JSON, while keywords/search
engines (the same thing here) are read from the Web Data sqlite3
database, and converted from OpenSearch format.

importer: add tests for opensearch
2017-11-06 21:19:57 -06:00
Jay Kamat
ecf6f4bca0 Fix Qt Mnemonics affecting min tab width
See #3245
2017-11-06 15:05:26 -05:00
Jan Verbeek
3e8c84c018 Make :undo re-open all tabs closed by :tab-only
This changes the undo stack from a list of UndoEntry objects to a list
of lists of UndoEntry objects, so groups of tabs can be added. Only
:tab-only does that, but it's exposed by TabbedBrowser.close_tab as a
keyword argument.
2017-11-06 19:32:10 +01:00
Florian Bruhin
b1f1248a05 Update changelog
[ci skip]
2017-11-06 16:27:17 +01:00
Florian Bruhin
0053b10e4d Merge remote-tracking branch 'origin/pr/3243' 2017-11-06 16:26:21 +01:00
pyup-bot
82fd26268b Update pytest-bdd from 2.18.2 to 2.19.0 2017-11-06 15:50:31 +01:00
pyup-bot
409f8327c2 Update hypothesis from 3.33.0 to 3.36.0 2017-11-06 15:50:30 +01:00
pyup-bot
360e0aaa67 Update sip from 4.19.3 to 4.19.5 2017-11-06 15:50:28 +01:00
pyup-bot
b42346b616 Update pyqt5 from 5.9 to 5.9.1 2017-11-06 15:50:27 +01:00
pyup-bot
0fdf0ff3b1 Update pefile from 2017.9.3 to 2017.11.5 2017-11-06 15:50:25 +01:00
pyup-bot
b759dbfc27 Update flake8-deprecated from 1.2.1 to 1.3 2017-11-06 15:50:23 +01:00
pyup-bot
b61a9c9512 Update flake8-debugger from 1.4.0 to 3.0.0 2017-11-06 15:50:22 +01:00
pyup-bot
0cc855019e Update coverage from 4.4.1 to 4.4.2 2017-11-06 15:50:20 +01:00
pyup-bot
cd27fb6af6 Update coverage from 4.4.1 to 4.4.2 2017-11-06 15:50:19 +01:00
pyup-bot
120fa41009 Update certifi from 2017.7.27.1 to 2017.11.5 2017-11-06 15:50:17 +01:00
pyup-bot
6a415aee4a Update certifi from 2017.7.27.1 to 2017.11.5 2017-11-06 15:50:16 +01:00
pyup-bot
1fbd209213 Update certifi from 2017.7.27.1 to 2017.11.5 2017-11-06 15:50:14 +01:00
Florian Bruhin
ad4caeac3a Regenerate docs 2017-11-06 13:52:42 +01:00
Florian Bruhin
e7da2142f3 Merge remote-tracking branch 'origin/pr/3249' 2017-11-06 13:52:19 +01:00
Florian Bruhin
18cd608493 Update docs 2017-11-06 13:47:50 +01:00
Florian Bruhin
29cbf75615 Merge remote-tracking branch 'origin/pr/3249' 2017-11-06 13:46:24 +01:00
Ryan Roden-Corrent
c74cb22374 Improve completion-item-yank documentation. 2017-11-06 07:34:31 -05:00
Florian Bruhin
f56692d836 Update changelog 2017-11-06 12:14:27 +01:00
Florian Bruhin
378b280f9a Fix qute://gpl 2017-11-06 12:13:54 +01:00
Florian Bruhin
55815bd17b Add some debug logging for #3219 2017-11-06 10:53:37 +01:00
Florian Bruhin
b55bb5dc6f Work around QUrl::query() not being available with PyQt 5.9.1
See https://www.riverbankcomputing.com/pipermail/pyqt/2017-November/039702.html
2017-11-06 08:50:03 +01:00
Florian Bruhin
2514b009af Use QUrlQuery to get log level on qute://log
This helps with
https://www.riverbankcomputing.com/pipermail/pyqt/2017-November/039702.html
2017-11-06 08:42:59 +01:00
Florian Bruhin
4d8ac7486c Go back to using subprocess.Popen for :restart
With subprocess.run, we wait until the subprocess has completed, which means the
parent process will hang on :restart.

Since we *don't* want to wait for the subprocess here, using subprocess.Popen
seems the right thing to do.

This was introduced in bb54a954fe / #3203
Probably doesn't affect #3210 and #3220.
2017-11-06 07:45:17 +01:00
Florian Bruhin
22f3fade24 Bump up default font size to 10pt
See #1585
2017-11-06 07:36:52 +01:00
Florian Bruhin
f52930c857 Make the window.hide_wayland_decoration option less special 2017-11-06 07:33:13 +01:00
Florian Bruhin
4fdf2d6f40 Update docs 2017-11-06 07:11:00 +01:00
Florian Bruhin
d8392d4852 Merge environment variable init tests 2017-11-06 07:05:32 +01:00
Florian Bruhin
341e8ca864 Add a qt.highdpi setting
See #1585
2017-11-06 07:02:07 +01:00
Florian Bruhin
4857374fb0 Update changelog 2017-11-06 06:53:47 +01:00
Florian Bruhin
f222aa30a6 Merge remote-tracking branch 'origin/pr/3250' 2017-11-06 06:53:11 +01:00
Florian Bruhin
e03fffe604 Update changelog 2017-11-06 06:49:21 +01:00
Florian Bruhin
fef6b8e5fb Merge remote-tracking branch 'origin/pr/3247' 2017-11-06 06:48:50 +01:00
Florian Bruhin
691a152ec8 Remove old config file 2017-11-06 06:48:23 +01:00
Jay Kamat
ca0aa68f74 Fix icon width calculation for pinned tabs 2017-11-05 23:23:33 -05:00
Michal Siedlaczek
9153bf8c19 Additional version() test 2017-11-05 20:12:29 -05:00
Michal Siedlaczek
855d0312b5 Review fixes 2017-11-05 18:12:15 -05:00
Michael Hoang
966aa810df Set maxsplit to 0 on :buffer
Remove double quotes from tests
2017-11-06 06:41:43 +11:00
Florian Bruhin
f6b6b2ed7d Merge pull request #3244 from sim590/cast-custom-path
userscripts/cast: effectively kill old proc
2017-11-05 18:18:06 +01:00
Ryan Roden-Corrent
db3b1aee0d Add default ctrl+c binding for completion yank.
By default, ctrl+c will yank the selection from the completion menu onto
the clipboard, and ctrl+shift+c will yank it onto the primary selection.

Unfortunately ctrl+y was already taken by rl-yank (which,
counter-intuitively to vim users, will paste the last deleted text).
2017-11-05 11:14:28 -05:00
Ryan Roden-Corrent
bb63f9fd92 Implement completion-item-yank.
Yank the text from the first column of the completion menu.
Resolves #1588.
2017-11-05 11:07:38 -05:00
Simon Désaulniers
3cb06f9a81 userscripts/cast: effectively kill old proc
Custom location installed castnow can't be killed with the command
`pkill -f /usr/bin/castnow`. Now recover the path to the binary in the path for
calling and killing the program.
2017-11-05 00:19:06 -04:00
Michal Siedlaczek
51a61cf02d Fix test: sort when comparing file collection 2017-11-04 20:03:53 -04:00
Michal Siedlaczek
9ea986a569 Fixed typo 2017-11-04 20:02:49 -04:00
Michal Siedlaczek
3ac2cfdf73 Support updating dictionaries and removing old versions. 2017-11-04 18:16:05 -04:00
Panagiotis K
5215321e64 Error handling, better code quality.
Handling of os errors raised during parent
directory creation.
2017-11-04 20:17:35 +02:00
Florian Bruhin
af93c0fbc0 Fix changelog
[ci skip]
2017-11-04 17:15:20 +01:00
Florian Bruhin
87c339587f Release v1.0.3
(cherry picked from commit fc63cea917)
2017-11-04 17:05:05 +01:00
Florian Bruhin
990be79933 Update changelog 2017-11-04 16:07:04 +01:00
Florian Bruhin
5689a3c0dc Fix unbinding default keys twice
When doing :unbind with a default keybinding the first time, it gets inserted
into bindings.commands with None as value.

When then doing :unbind a second time, instead of just leaving that None value
as-is, we removed it again (because it got treated as a custom binding).

Fixes #3162
2017-11-04 15:17:19 +01:00
Michal Siedlaczek
2dc0115c81 Load the newest version of the dictionary. 2017-11-03 19:20:31 -04:00
Michal Siedlaczek
16ad9182f1 Add en-AU (Australia) to the list of valid languages 2017-11-03 17:24:33 -04:00
Florian Bruhin
b8e1ed752f Update docs
(cherry picked from commit f85f31ebe92c961b29d5882dbf857cf75debd66d)
2017-11-03 15:03:05 +01:00
Florian Bruhin
c22a27d47f Add missing trailing dots
(cherry picked from commit 5f43b02badc20a4fc67931ab6e76f1050ab283aa)
2017-11-03 15:03:05 +01:00
Florian Bruhin
6233358b71 Sort codeowners file
(cherry picked from commit 291cddc170caf552b5ed3587bbe5096fac8111e4)
2017-11-03 15:03:05 +01:00
Florian Bruhin
864249d798 Merge remote-tracking branch 'origin/pr/3181' 2017-11-03 15:02:27 +01:00
Florian Bruhin
568bb5d540 Merge pull request #3229 from ryan-farley/import-moz-bookmarks
importer: add mozilla places.sqlite support
2017-11-03 14:41:10 +01:00
Florian Bruhin
0f28804032 Merge pull request #3237 from rcorre/completionsort
Fix completion sorting
2017-11-03 14:36:42 +01:00
Florian Bruhin
1c2f0c5359 Merge pull request #3232 from cryzed/qute-pass-userscript
Add qute-pass userscript
2017-11-03 14:36:11 +01:00
cryzed
600d2a543d Exit successfully when the user makes no selection 2017-11-03 13:54:43 +01:00
cryzed
4ec2e5485a Sort candidates alphabetically 2017-11-03 13:14:29 +01:00
cryzed
22dcd775da Improve warning message and adjust copyright 2017-11-03 11:57:23 +01:00
Florian Bruhin
1536c098cf Merge pull request #3215 from deewakar/issue3161
Add trailing slash to qute://help pages
2017-11-03 11:49:31 +01:00
cryzed
a96e4490ee Add qutebrowser license header and warning about login details in qute's debug log 2017-11-03 11:32:32 +01:00
cryzed
ee6b4bc7ee Add option to merge pass candidates for the fully-qualified and registered domain name 2017-11-03 11:25:35 +01:00
Ulrik de Muelenaere
ce1494e5ec Update stylesheet.js to ES6 2017-11-03 12:17:35 +02:00
Ulrik de Muelenaere
72c57d16f4 Merge branch 'master' into stylesheet 2017-11-03 12:13:52 +02:00
Florian Bruhin
d53a96d9f2 Merge pull request #3208 from 7lb/refactor/make_completer_less_stateful
[RDY] Make completer less stateful
2017-11-03 10:47:52 +01:00
Florian Bruhin
be325853d8 Revert "Inject JS into the profile"
This reverts commit acfb3aa26f.

The related code doesn't really belong in webenginesettings.py after all, and
for some reason I don't understand right now this breaks tests in
javascript.feature because window._qutebrowser is undefined when running them.
2017-11-03 09:59:00 +01:00
Florian Bruhin
25bda66260 Merge pull request #3191 from gyorb/refactor/enum
use Enum start number
2017-11-03 09:30:47 +01:00
Marcel Schilling
7e07f5c996 standardize placeholders in configdata descriptions
* Keep descriptions concise.
 * Prefer starting descriptions with a noun.
 * Don't explain that placeholders are placeholders/get replaced.
 * Introduce placeholder list by the following line:
   'The following placeholders are defined:'
 * List placeholders in a markdown-style list:
   '* `{<placeholder>}`: <description>.'
2017-11-03 08:48:30 +01:00
Marcel Schilling
af9c94bd23 add myself as codeowner for configdata YAML file
* to be notified of changes so I can help maintain consistency
2017-11-03 08:44:11 +01:00
Marcel Schilling
c6d7509220 rephrase configdata descriptions
* see discussion of PR #3181
2017-11-03 08:44:11 +01:00
Marcel Schilling
87ec7a1a0b prefer nouns for configdata descriptions
* reserve interrogative words for selection type options
2017-11-03 08:44:11 +01:00
Marcel Schilling
aebe4c8f9e assume single user in configdata descriptions
* 'a user' -> 'the user'
2017-11-03 08:44:11 +01:00
Marcel Schilling
a6451c05d7 add missing units to configdata descriptions
* fixes #3171
2017-11-03 08:44:11 +01:00
Marcel Schilling
01b29cd640 use interrogative words for configdata descriptions
* for selections, use appropriate determiner/pro-adverb/pronoun:
   * 'When to [...].'
   * 'How to [...].'
   * 'Which [...] to [...].'
   * 'What [...] to [...].'
2017-11-03 08:44:11 +01:00
Marcel Schilling
0a908206bc avoid boolean redundancy in configdata descriptions
* 'Enable or disable [...]' -> 'Enable [...]'
What else? ---^^^^^^^
2017-11-03 08:44:11 +01:00
Marcel Schilling
494aceec45 use imperative mood for bools in configdata descriptions
* considers ConfirmQuit and BoolAsk in addition to Bool
2017-11-03 08:44:11 +01:00
Marcel Schilling
f76af6c949 define type before desc in configdata YAML file 2017-11-03 08:44:11 +01:00
Marcel Schilling
b187a83d59 avoid spaces before colons in confidata YAML file
* '  desc : [...]' -> '  desc: [...]'
space ----^      no space ----^
2017-11-03 08:44:11 +01:00
Marcel Schilling
56671e5787 avoid articles in configdata descriptions
* includes `valid_value` descriptions in addition to `desc` fields
2017-11-03 08:44:11 +01:00
Marcel Schilling
e744a7c25a avoid code duplication in configdata descriptions
* available placeholders are defined for tabs.title.format
 * tabs.title.format_pinned refers to that definition
 * window.title.format repeats the identical(!) definition
 * this replaces the repetion by another reference
2017-11-03 08:44:11 +01:00
Marcel Schilling
fe8b9519c8 avoid redundancy in configdata descriptions
* drop phrases referring to the settings themselves:
   * 'set ...'
   * 'control ...'
   * 'definitons of ...'
2017-11-03 08:44:11 +01:00
Marcel Schilling
fd52409d0c standardize units in configdata descriptions
* encapsulate units in parentheses: ('(in <unit>)')
 * move units right behind the corresponding noun
2017-11-03 08:44:11 +01:00
Marcel Schilling
e126faf8c1 prefer 'duration' in configdata descriptions 2017-11-03 08:44:11 +01:00
Marcel Schilling
7672fb5241 avoid abbreviations in configdata description
* chars -> characters
 * px -> pixels
 * ms -> milliseconds
 * regexes -> regular expressions

 * includes `valid_value` descriptions in addition to `desc` fields

ms_fix
2017-11-03 08:44:11 +01:00
Marcel Schilling
99ad1547bc break long lines in configdata YAML file
* max. 79 chars (as per PEP8)
 * two long lines remain (as I didn't know how to safely break them):

>    389      - "http://malwaredomains.lehigh.edu/files/justdomains.zip"
> -> 390      - "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext"
>    391    type:
> --
>   2222        Sh: open qute://history
> ->2223        xx: config-cycle statusbar.hide ;; config-cycle tabs.show always switching
>   2224        xt: config-cycle tabs.show always switching
2017-11-03 08:44:11 +01:00
Marcel Schilling
31e7d8dd3f fix capitalization in configdata descriptions
* url -> URL
 * os -> OS
 * Page Cache -> page cache
 * Spatial Navigation -> spatial navigation
2017-11-03 08:44:11 +01:00
Marcel Schilling
a55d12bf70 add missing periods (.) to configdata descriptions
* includes `valid_value` descriptions in addition to `desc` fields
2017-11-03 08:44:11 +01:00
Marcel Schilling
0c01d9b61a fixed typos in configdata descriptions 2017-11-03 08:44:11 +01:00
Ryan Roden-Corrent
a9926e44f0 Don't check date string in test_histcategory.
We really just need to check that the row exists here, the date doesn't
matter. Checking the date here is actually flaky with regards to time.
When running locally at 11:50 EST, it failed with:

```
assert self._model.data(self._model.index(row, col)) == item
AssertionError: assert '1969-12-31' == '1970-01-01'
- 1969-12-31
+ 1970-01-01
```

It was wrong to assume that an atime of 0 would always format to
1970-01-01.
2017-11-02 22:10:00 -04:00
Ryan Roden-Corrent
47447c047a Ensure completions are sorted after filtering.
I previously removed the sorting logic from SortFilter thinking it was
unnecessary if we construct the model with a sorted list. However, this
only worked when no pattern was set, and the items are misordered as
soon as a pattern is input.

This patch reintroduces alpha-sorting, which can be disabled by passing
sort=False to the ListCategory constructor. The session completion test
had to be tweaked as it simulated the incorrect assumption that the
session list is not alpha-ordered; sessions come out of the
session-manager pre-sorted so we may as well use alpha-sorting in the
session completion model.

Resolves #3156.
2017-11-02 22:10:00 -04:00
cryzed
78eb7b5da8 Select pass candidates for the fully-qualified domain name first, then for the registered domain and finally the IPv4 address if that is what the URL was 2017-11-03 02:43:33 +01:00
Florian Bruhin
acfb3aa26f Inject JS into the profile
Closes #3216
2017-11-02 21:59:22 +01:00
Florian Bruhin
a14ef88acf Remove some obsolete/deprecated eslint customizations 2017-11-02 20:00:29 +01:00
Florian Bruhin
1cf66976d2 Merge remote-tracking branch 'origin/pr/3225' 2017-11-02 19:43:04 +01:00
Luca Benci
c28d681736 Change test to avoid calling private functions 2017-11-02 19:42:33 +01:00
Florian Bruhin
bb208f4e77 Un-hide :open-editor
It can be used in normal mode as well, and it's nice to have it discoverable.
Fixes #3235.
2017-11-02 19:32:45 +01:00
Florian Bruhin
5469a238de Fix docs for new editor replacements
See #3100
2017-11-02 19:30:47 +01:00
Gyorgy Orban
98c6b49cde use enum module instead or usertypes.enum
Remove the usertypes.enum from the source and use
the standard enum module instead.
Enum start number is available since python 3.5
2017-11-02 18:56:11 +01:00
plexigras
6e624bcd3c Merge branch 'master' into es6ify-js 2017-11-02 16:44:25 +01:00
cryzed
16fefc1c7b Make changes suggested here: 0e3c42db69 2017-11-02 14:06:17 +01:00
Florian Bruhin
c0eae5d4e4 Update changelog 2017-11-02 11:35:40 +01:00
Florian Bruhin
9a69ccc9e3 Merge remote-tracking branch 'origin/pr/3100' 2017-11-02 11:32:45 +01:00
Florian Bruhin
4a1cdef887 Fix indent 2017-11-02 11:03:19 +01:00
Florian Bruhin
3385585ca5 Merge remote-tracking branch 'origin/pr/3203' 2017-11-02 11:02:49 +01:00
Florian Bruhin
4498141c8b Update changelog 2017-11-02 09:15:41 +01:00
Florian Bruhin
f620ffd9d4 Merge remote-tracking branch 'origin/pr/3228' 2017-11-02 09:14:49 +01:00
Florian Bruhin
1c39715267 Clarify qute://configdiff/old title 2017-11-01 22:36:59 +01:00
Ryan Farley
2e051ab008 importer: add mozilla places.sqlite support
This adds supports for the places.sqlite format as used by Firefox,
Seamonkey, Pale Moon, and presumably others. Search engine support is
limited to keyword-style '%s' functionality.

vulture whitelist for row_factory
2017-11-01 15:33:13 -05:00
cryzed
0e3c42db69 Rename qute-passmenu to qute-pass again 2017-11-01 20:40:59 +01:00
cryzed
6d37e4671a Add support for not automatically entering insert mode 2017-11-01 19:08:49 +01:00
cryzed
09d55cb271 Add support for only inserting the username or password 2017-11-01 19:01:17 +01:00
cryzed
c97b416cb1 Rename qute-pass to qute-passmenu 2017-11-01 18:19:46 +01:00
cryzed
19fc4de484 Add qute-pass userscript 2017-11-01 17:57:30 +01:00
Gyorgy Orban
bb54a954fe use subprocess run
The usage of subprocess.run is recommended since python 3.5.
Popen, check_call, call and check_output calls were replaced with run.
2017-11-01 09:59:32 +01:00
Florian Bruhin
385337eb90 Use lts version of NopeJS
Looks like npm doesn't work with Node v9:
https://github.com/nodejs/node/issues/16649
2017-11-01 09:24:57 +01:00
Jay Kamat
cb7e6ab02d Abort pinned tab prompt if tab is destroyed
Closes #3223
2017-10-31 19:07:01 -04:00
Luca Benci
24231ae405 Remove unnecessary parens 2017-10-31 23:22:17 +01:00
Luca Benci
bc0c877b87 Formatting 2017-10-31 23:21:37 +01:00
Luca Benci
370405c0ed Remove assert 2017-10-31 23:20:13 +01:00
Luca Benci
35597a7c01 Change tests for trailing-space behaviour change 2017-10-31 23:15:11 +01:00
Luca Benci
dcc53026a3 Stay within 79 columns 2017-10-31 23:14:07 +01:00
plexigras
fa8476f762 keep old pac_utils.js 2017-10-31 16:40:09 +01:00
Florian Bruhin
dc26808a94 Fix setting names in FAQ 2017-10-31 14:41:36 +01:00
plexigras
905c984148 change some lambdas to functions 2017-10-31 12:54:26 +01:00
plexigras
d4d791f14e es6ified js 2017-10-31 11:53:35 +01:00
Florian Bruhin
0b86b302a2 pylint: Turn off some more too-many-* stuff globally
Humans are just better at judging what's okay here than a machine.
2017-10-31 07:35:00 +01:00
dwagle
95539961a4 made some adjustments in tests/end2end/features/qutescheme.feature for the tests to pass. These are to account for changes made in f70740c, 4c9482b and aab7496 2017-10-31 12:08:43 +05:45
Florian Bruhin
2becc17099 Merge remote-tracking branch 'origin/pr/2966' 2017-10-31 07:15:52 +01:00
Florian Bruhin
dad7e7b9d2 Update changelog 2017-10-31 07:06:04 +01:00
Florian Bruhin
e9483bc485 Merge remote-tracking branch 'origin/pr/3122' 2017-10-31 07:05:38 +01:00
dwagle
f70740cc3a set original query parameters if any before redirecting to new_url 2017-10-31 11:47:06 +05:45
Ulrik de Muelenaere
95b41b311f Disable ESLint no-bitwise rule 2017-10-30 22:24:59 +02:00
Ulrik de Muelenaere
3adc2e0f83 Add filter to NodeIterator checking for styled nodes 2017-10-30 19:56:12 +02:00
Ulrik de Muelenaere
34b27437d0 Clarify function names in stylesheet.js 2017-10-30 19:55:37 +02:00
Ulrik de Muelenaere
0540a43995 Check for deleted window 2017-10-30 19:52:15 +02:00
Jay Kamat
64b6852ae3 Fix a couple style issues 2017-10-30 12:40:44 -04:00
dwagle
4c9482be84 added a Scenario: Opening link with qute://help to tests/end2end/features/qutescheme.feature 2017-10-30 17:49:22 +05:45
dwagle
aab7496916 fixes issue #3161 2017-10-30 17:09:45 +05:45
Florian Bruhin
43aa7423ab Update docs 2017-10-30 08:26:47 +01:00
Florian Bruhin
9d415587bc Mark flaky test as flaky 2017-10-30 07:05:54 +01:00
Florian Bruhin
08965399c5 Update changelog 2017-10-30 06:59:16 +01:00
Florian Bruhin
daee729fc2 Merge remote-tracking branch 'origin/pr/3200' 2017-10-30 06:58:46 +01:00
Florian Bruhin
3d53ffb7ef Bump up YAML load deadline some more 2017-10-30 06:55:55 +01:00
Ulrik de Muelenaere
2fe1a1db89 Remove unused variable 2017-10-29 00:23:11 +02:00
Ulrik de Muelenaere
51d48f6b00 Rewrite user stylesheet injection for WebEngine
This now works correctly in XML documents. The stylesheet is applied at
document creation to reduce flickering, and is updated if the
user_stylesheets setting is changed after page load.
2017-10-28 22:16:29 +02:00
Florian Bruhin
0d1e716760 Add Vim Vixen to list of alternatives 2017-10-28 18:20:17 +02:00
Florian Bruhin
023c59f8c0 Reset the webserver process correctly between tests
If we don't call before_test(), if the server shows an error, all following
tests will fail.

See #3207
2017-10-28 17:29:55 +02:00
Florian Bruhin
f44985548b Merge pull request #3211 from regines/cheatsheet-update
Update cheatsheet
2017-10-28 17:24:31 +02:00
Regina Hug
493468e08f Update cheatsheet
Fixes #2466
2017-10-28 17:35:35 +02:00
Jay Kamat
2a4163b2c7 Fix ellipsis on pinned tabs with index > 10
See #3209
2017-10-27 17:20:55 -04:00
Luca Benci
249164eb9b Fix test_quickcomplete_flicker
The test needed to be fixed because of how the completer behaviour
changed.

Before:
completer always scheduled a completion update on selection changed,
but the updates themselves were ignored if not needed.

Now:
completer only schedules completion updates when actually needed, but
never ignores a completion update.

So, before it was correct to check whether `set_model` was called, now
we must check if the completion was actually scheduled. This can be
done by checking the parameters with which `_change_completed_part`
is called, since a completion is scheduled only when `immediate=True`
2017-10-27 22:25:41 +02:00
Luca Benci
f5f11f7f4e Remove _ignore_change 2017-10-27 20:15:33 +02:00
Luca Benci
2947b75ab9 Make eslint happy 2017-10-27 19:52:10 +02:00
Ryan Roden-Corrent
8f068dda1b Disable pylint's too-many-boolean-expressions. 2017-10-27 07:23:41 -04:00
Florian Bruhin
17e0f6d23c Remove -f for :bind in configuring.asciidoc
[ci skip]
2017-10-27 07:15:25 +02:00
Ryan Roden-Corrent
24f466b2c3 Add --related flag to edit-url. 2017-10-26 22:13:35 -04:00
Jay Kamat
97d719b179 Add a simple benchmark for _update_tab_titles 2017-10-26 21:33:10 -04:00
Ryan Farley
879e8dfb2c fix D401 in importer 2017-10-26 17:09:45 -05:00
Florian Bruhin
dc01b4eaf0 Use Pygments for syntax highlighting 2017-10-26 22:42:55 +02:00
Florian Bruhin
d7dac40c2c Update Gentoo install instructions again 2017-10-26 21:38:37 +02:00
Ryan Roden-Corrent
6519f500a9 Add --private flag to edit_url.
The command :edit-url --private (or :edit-url -p) will spawn a new
private window with the url input from the editor.

I had to add 'Given I have a fresh instance' to the feature file to
ensure tests were not interfering.

Resolves #3185.
2017-10-26 07:21:51 -04:00
Florian Bruhin
02c996a785 Fix wrong 'When' in bdd file 2017-10-26 09:47:02 +02:00
Florian Bruhin
eee5f8263f Merge remote-tracking branch 'origin/pr/3179' 2017-10-26 09:43:42 +02:00
Florian Bruhin
c883d6b429 Merge remote-tracking branch 'origin/pr/3196' 2017-10-26 08:46:21 +02:00
Florian Bruhin
1c9dc581a4 Skip "Clearing history" test on Windows 2017-10-26 08:45:15 +02:00
Florian Bruhin
c443def24e Explicitly mention qute://configdiff/old link target
Thanks GitHub for just stripping the link...
2017-10-26 08:14:40 +02:00
Ryan Farley
5d2975293b remove unused import 2017-10-25 16:49:12 -05:00
Luca Benci
ff7edf79e7 Rethrow exception if we can't handle it 2017-10-25 22:53:54 +02:00
Luca Benci
ae2dad7d18 Only catch the correct exception 2017-10-25 22:43:17 +02:00
Luca Benci
3fd7fb3e14 Do not assume elem.selectionStart exists 2017-10-25 22:38:44 +02:00
Ryan Farley
3d87f4ebdf default to Netscape format for importer 2017-10-25 14:52:53 -05:00
Luca Benci
df3f0124fc Add test 2017-10-25 21:37:22 +02:00
Luca Benci
f195b7e4d2 Fix flake8 failures 2017-10-25 21:18:53 +02:00
Florian Bruhin
d8461d79cc Update changelog 2017-10-25 20:50:48 +02:00
Florian Bruhin
2ab441a5a3 Merge remote-tracking branch 'origin/pr/3129' 2017-10-25 20:49:55 +02:00
lxhillwind
4c7f6e5339 Update configfiles.py: line too long fix 2017-10-26 02:04:09 +08:00
lxhillwind
048b792c6f add <EOL> in :config-write-py generated file 2017-10-26 00:52:22 +08:00
lxhillwind
66c5350989 handle <EOL> of :config-write-py generated file 2017-10-26 00:06:53 +08:00
Florian Bruhin
2051a5d95e Stabilize :history-clear test
Something seems special with the previous view:source tab which prevents us
from loading the new page.

See #3003
2017-10-25 14:08:31 +02:00
Florian Bruhin
94f8bb9574 bdd tests: Make sure initial about:blank check is redone on restart
When we did "Given I have a fresh instance", we immediately did run the commands
without waiting for the initial about:blank load again.

With Qt 5.10, this causes issues as the loadFinished signal is emitted with
about:blank then, and not the real URL.

See #3003
2017-10-25 14:06:55 +02:00
Ryan Farley
38e3c1ee8f fix whitespace 2017-10-24 19:58:38 -05:00
Ryan Farley
137a7114e1 importer: documentation of bookmark types 2017-10-24 19:41:22 -05:00
Ryan Farley
4ed7fe731d removed wrong option 2017-10-24 17:31:42 -05:00
Florian Bruhin
ed2f473a8e Make it more clear that :messages helps with failing processes 2017-10-24 22:56:04 +02:00
Florian Bruhin
cb4aea2f69 Update/clarify some docs 2017-10-24 22:39:41 +02:00
Jay Kamat
cb6f4313d7 Lower tabbar cache bound and clean up code 2017-10-24 10:18:10 -04:00
Florian Bruhin
984dd1ba8c Fix remaining pylint/flake8 issues 2017-10-24 09:37:10 +02:00
Florian Bruhin
1d18e808b1 Merge remote-tracking branch 'origin/pr/3182' 2017-10-24 09:31:25 +02:00
Florian Bruhin
6b1519ed52 Regenerate docs 2017-10-24 08:57:45 +02:00
Florian Bruhin
43bca9793e Merge remote-tracking branch 'origin/pr/3136' 2017-10-24 08:57:28 +02:00
siddhugolu
c94327748e Merge branch 'master' of https://github.com/qutebrowser/qutebrowser into finer_pylint_pragmas 2017-10-24 12:20:13 +05:30
siddhugolu
570f1a849f modified as requested 2017-10-24 12:20:07 +05:30
Christopher Pezley
f67c445f3d Add test for opening non-ascii paths from command line. 2017-10-23 22:27:00 +02:00
Florian Bruhin
d2b315cac1 Update install instructions for Fedora/Gentoo
[ci skip]
2017-10-23 11:57:34 +02:00
Florian Bruhin
9fd53fd445 Add Anonymous to backers file
[ci skip]
2017-10-23 08:58:24 +02:00
Florian Bruhin
989d6d2b44 Add Kevin Kainan Li to backers
[ci skip]
2017-10-23 08:28:45 +02:00
siddhugolu
bc9d305354 modified as requested 2017-10-23 01:46:02 +05:30
siddhugolu
4862b2faf9 modified pylint pragmas 2017-10-22 23:52:35 +05:30
Luca Benci
1f521da134 Add missing full-stops 2017-10-22 20:03:46 +02:00
Luca Benci
96bbdb19e6 Add missing docstrings 2017-10-22 20:02:32 +02:00
Luca Benci
8b91a74aef Fix broken test after default config change 2017-10-22 20:02:06 +02:00
Christopher Pezley
f53d8135b0 Add test for opening non-ascii paths. 2017-10-22 19:39:46 +02:00
Christopher Pezley
96eff65690 Log when url contains characters not present in current locale. 2017-10-22 18:41:29 +02:00
Florian Bruhin
af98f9a77d Fix position in changelog
[ci skip]
2017-10-22 17:34:37 +02:00
Florian Bruhin
288fe3f808 Update changelog 2017-10-22 17:33:40 +02:00
Florian Bruhin
bd0289423e Merge remote-tracking branch 'origin/pr/3180' 2017-10-22 17:33:06 +02:00
Florian Bruhin
a704526582 Remove messages.unfocused 2017-10-22 17:30:47 +02:00
Ryan Farley
31f1025ff8 escape search engine URLs in importer 2017-10-21 18:12:25 -05:00
Michael Hoang
e5f2d27ed9 Ensure that a window with the given win_id exists 2017-10-22 08:22:45 +11:00
Luca Benci
56d29a1b5f Avoid scheduling spurious completion updates
Instead of setting `_ignore_change` to `True` before calling
`_change_completed_part` we just stop `_cmd` from emitting
`update_completion`.

This has the nice side-effect that when writing a complete command
`_ignore_change` was set to `True` regardless, and thus hitting space
would not update the completion view.

Now, hitting space will (as always) schedule a completion update that
now will not be incorrectly ignored
2017-10-21 23:20:37 +02:00
Jay Kamat
49daa7aab8 Add most recent tab bar to cache statistics 2017-10-21 16:18:23 -04:00
Christopher Pezley
bdfb9c60cc Fix issue where opening a file whose name contains characters not
present in locale would cause a crash.

Fixes qutebrowser/qutebrowser/1450
2017-10-21 21:01:07 +02:00
Florian Bruhin
34fc5335d9 Merge remote-tracking branch 'origin/pr/3176' 2017-10-21 19:04:01 +02:00
Florian Bruhin
13116b2679 Stabilize IPC test
We can get earlier log messages from objreg
2017-10-21 19:02:35 +02:00
Florian Bruhin
33df4eb865 Skip test_fake_haiku on Windows 2017-10-21 19:01:22 +02:00
Jay Kamat
5ba4e13cab Fix typo in :home on pinned tab test 2017-10-21 01:32:56 -04:00
Jay Kamat
b499474599 Prevent calling _tab_pinned on every tab twice 2017-10-21 00:32:05 -04:00
Jay Kamat
caae1c7008 Fix blowing cache for different icons 2017-10-20 22:13:54 -04:00
Jay Kamat
fde4495bc7 Clear cache on config changes 2017-10-20 16:35:11 -04:00
Luca Benci
dee0799e15 Avoid crash with LC_ALL=C and unicode filename 2017-10-20 22:06:59 +02:00
Jay Kamat
e705ea7e56 Rename _minimum_tab_size_hint_helper 2017-10-20 15:40:11 -04:00
Jay Kamat
f6cc9d53b8 Merge branch 'master' into jay/cache-tabsize 2017-10-20 15:24:22 -04:00
Florian Bruhin
4c2aeb01a8 Update docs 2017-10-20 12:47:48 +02:00
Florian Bruhin
589e9b7153 Fix string escaping in config.source test 2017-10-20 10:05:42 +02:00
Florian Bruhin
3dc06aad24 Update changelog 2017-10-20 09:15:22 +02:00
Florian Bruhin
128a16173e Merge remote-tracking branch 'origin/pr/3165' 2017-10-20 09:14:41 +02:00
Florian Bruhin
5fe6e60ffd Fix lint 2017-10-20 09:12:23 +02:00
Florian Bruhin
c3e9343a6d Update changelog for scrolling improvements
See #2233, #2822
2017-10-20 08:59:39 +02:00
Florian Bruhin
8504d41db3 Use Qt API for QtWebEngine scrolling
See #2233
Fixes #2822
2017-10-20 08:58:28 +02:00
Florian Bruhin
dd927ded6b Only update tab/window title on scroll if needed
This way, if {scroll_pos} is not in the window/tab title template,
we don't redraw anything unnecessarily.

See #2233
2017-10-20 08:25:43 +02:00
Florian Bruhin
280dddda6b Set backend in TestRectOnView.test_zoomed 2017-10-20 08:07:10 +02:00
Florian Bruhin
fd8e5e30c6 Re-add scroll filtering and disable it for mark/scroll tests
See #2233
2017-10-20 07:38:51 +02:00
Florian Bruhin
455b90ecad Log which dictionaries have been found
See #3166
2017-10-20 07:14:32 +02:00
Martin Fraga
2bfa853847 Add keyhint radius configuration option
The radius for the keyhint dialog box should be configurable vi via
c.keyhint.radius. The default was set to 6px, which is the previous
hardcoded value.
2017-10-19 02:03:59 -07:00
Luca Benci
9613deb89d Document new editor.command placeholders 2017-10-18 21:20:05 +02:00
Luca Benci
0436526203 Change default editor command 2017-10-18 21:08:22 +02:00
Luca Benci
9b177ae8e7 Remove single-function test class (move test out) 2017-10-18 20:33:14 +02:00
Luca Benci
937d0d0688 Add some more tests 2017-10-18 20:30:16 +02:00
Luca Benci
0d7a557396 Fix configtypes tests so that placeholder is True 2017-10-18 20:30:03 +02:00
Luca Benci
cf04219f79 Rename possible_placeholder to arg 2017-10-18 20:20:05 +02:00
Luca Benci
7907840ead Add full stops 2017-10-18 20:19:47 +02:00
Luca Benci
addccd7492 Move comment to docstring and fix typo 2017-10-18 20:19:09 +02:00
Florian Bruhin
378498bbd7 Add a test for multiple config.source() errors 2017-10-18 14:06:54 +02:00
Florian Bruhin
5a9042ab3e Add a config.source() method 2017-10-18 13:53:26 +02:00
Florian Bruhin
34787edf4e Add Xresources to config recipes
[ci skip]
2017-10-18 10:46:12 +02:00
Florian Bruhin
354c3c8c9b Handle unknown filetypes with qute://help 2017-10-18 09:02:39 +02:00
Luca Benci
6f1b9b7984 Add tests for line & column calculation 2017-10-17 23:19:10 +02:00
Luca Benci
06b990c0d1 Add ShellCommand tests for {file} 2017-10-17 23:03:42 +02:00
Luca Benci
f710536092 Move line and column calculation to own function 2017-10-17 22:48:43 +02:00
Luca Benci
233e72fef1 Adjust docstring 2017-10-17 22:38:11 +02:00
Florian Bruhin
9dc9bcaf39 Make standarddir work on HaikuOS
For some reason, it returns an empty DataLocation.
2017-10-17 22:37:14 +02:00
Luca Benci
e508224a46 Avoid the use of chained replaces 2017-10-17 22:35:01 +02:00
Luca Benci
b3445bc35a Add default value for caret_position 2017-10-17 22:08:54 +02:00
Ryan Farley
af8a5c58da use sys.exit 2017-10-17 14:48:56 -05:00
Ryan Farley
73c5666ff9 various importer fixes
* Line breaks reinserted
* None in place of ''
* Check for browser before selecting default input format (to fix
KeyError)
* Remove redundant -S option and clarify help to make it slightly more
obvious what output formats make sense
* Added long-form arguments and slightly more sensible names (not really a
fix, but I personally like having them)
2017-10-17 14:48:56 -05:00
Ryan Farley
a6ed079011 make browser argument optional 2017-10-17 14:48:56 -05:00
Ryan Farley
84b2b05254 help text mod
Browser choices are now formatted in the help text rather than listed
manually. Redundant line regarding output default removed from epilogue
2017-10-17 14:48:56 -05:00
Ryan Farley
d85a15f0a2 style, variable name typo 2017-10-17 14:48:56 -05:00
Ryan Farley
aa0613c6d8 support multiple input formats
This restructures things to better support future implementations of
other input formats. The default formats are specified in a global dict
of browsers, which prevents duplicating the list of choices for browser
in bother get_args() and main(), and a new option enables overriding of
the default.
2017-10-17 14:48:56 -05:00
Ryan Farley
799fe5deb3 default to new search format 2017-10-17 14:48:56 -05:00
Ryan Farley
898dde566d fix whitespace issues 2017-10-17 14:48:56 -05:00
Ryan Farley
c163f702c2 fix config.val in format 2017-10-17 14:48:56 -05:00
Ryan Farley
31bbc8c5b3 importer support for keywords and search engines
This allows importer.py to process Netscape HTML exports from Firefox
(and other Mozilla browsers) with three distinct types:
	* bookmarks (sans shortcuturl attribute)
	* keywords (bookmarks with a shortcuturl attribute)
	* searches (keywords with a URL containing a %s substitution)
The first two can be combined at will in either quickmark or bookmark
output formats, the only difference being that keywords will be used in
place of titles when exporting to quickmark format. Searches are
exported to qutebrowser.conf format, or the new config.py format.

Dictionaries are used in the import function for readability's sake, but
the command line arguments follow the same general formula of true-false
flags used to select input bookmark types and the output format.
2017-10-17 14:48:55 -05:00
Florian Bruhin
828ffd4979 Update changelog 2017-10-17 21:19:46 +02:00
Florian Bruhin
11f97f71f4 Merge remote-tracking branch 'origin/pr/3150' 2017-10-17 21:19:11 +02:00
Florian Bruhin
807b7701d5 Re-add blank line 2017-10-17 21:11:14 +02:00
Jay Kamat
62b6d62cd7 Clean up sub-module import and unneeded + 2017-10-17 14:22:18 -04:00
Jay Kamat
5d11a1fd75 Prevent :home from bypassing pinned tab warnings
Closes #3138
2017-10-17 11:37:37 -04:00
Jay Kamat
95761c5023 Fix crashes on qute_pylint module when not running in the root
Useful for editors that run from non-root directories for
integrations, but skips some tests. Shouldn't impact tests run normally.
2017-10-17 10:36:37 -04:00
Florian Bruhin
5c6a821b1e Update changelog 2017-10-17 15:35:58 +02:00
Florian Bruhin
96bec9f9d7 Fix error code for "database is locked"
See #2930
2017-10-17 15:35:23 +02:00
Florian Bruhin
12c9590524 Always use shortest match for completion.use_best_match 2017-10-17 15:01:37 +02:00
Florian Bruhin
4984c9d05c Update docs 2017-10-17 14:57:41 +02:00
Florian Bruhin
161b96be1e Fix long line 2017-10-17 13:10:00 +02:00
Florian Bruhin
bf1af698bd Merge pull request #3147 from fiete201/Fix_debian_install_instructions_for1.0.2
fix debian install instructions to fit debian9 and new apt
2017-10-17 13:10:40 +02:00
Fritz Reichwald
2fccc083af fix debian install instructions to fit debian9 and new apt 2017-10-17 12:03:27 +02:00
Florian Bruhin
4f263505ee Improve tests for partial matching 2017-10-17 11:49:46 +02:00
Florian Bruhin
2e64dda592 Clean up getting matching commands 2017-10-17 11:40:34 +02:00
Florian Bruhin
52423fa426 Remove unneeded variable 2017-10-17 11:37:19 +02:00
Florian Bruhin
c3441ae4a8 Update changelog 2017-10-17 11:34:46 +02:00
Florian Bruhin
c233099bca Merge remote-tracking branch 'origin/pr/3063' 2017-10-17 11:34:35 +02:00
Florian Bruhin
44e5dc1c5a Add a comment to @xfail_norun 2017-10-17 10:45:58 +02:00
Florian Bruhin
458a45c172 Remove old deprecated commands 2017-10-17 10:44:22 +02:00
Florian Bruhin
f1ddf58260 Add a deprecated :tab-detach 2017-10-17 10:30:47 +02:00
Florian Bruhin
f84af0a6fb Fix docstring 2017-10-17 09:33:20 +02:00
Florian Bruhin
ced4713fda Reverse if/else 2017-10-17 09:14:59 +02:00
Florian Bruhin
2c86788901 Update changelog 2017-10-17 09:14:02 +02:00
Florian Bruhin
cce4ff6d53 Merge remote-tracking branch 'origin/pr/3054' 2017-10-17 09:10:45 +02:00
Florian Bruhin
8d169597ae Fix lint for standardpaths_tester 2017-10-17 09:06:52 +02:00
Florian Bruhin
9470bff464 Merge pull request #3137 from qutebrowser/pyup-scheduled-update-10-16-2017
Scheduled weekly dependency update for week 42
2017-10-17 08:13:19 +02:00
Florian Bruhin
a8eae03ee9 Update release checklist 2017-10-17 07:52:43 +02:00
Florian Bruhin
373ad28d2e Release v1.0.2
(cherry picked from commit 55a88ceea6)
2017-10-17 07:46:02 +02:00
Florian Bruhin
14a63b8a82 Include appdata file in MANIFEST 2017-10-17 07:39:44 +02:00
Florian Bruhin
6bc35a1842 Remove blank lines 2017-10-17 07:39:09 +02:00
Florian Bruhin
dd683ea08c Merge remote-tracking branch 'origin/pr/3139' 2017-10-17 07:38:48 +02:00
Florian Bruhin
db874d8bba Show apps with/without QApplication in standardpaths_tester 2017-10-17 06:34:08 +02:00
Florian Bruhin
1a7612e559 Bump up yaml timeout a bit 2017-10-17 06:28:22 +02:00
Florian Bruhin
d8384ced0a Show better error message when trying to toggle with :set 2017-10-17 06:26:42 +02:00
Florian Bruhin
544c508fac Add standardpaths_tester.py 2017-10-17 06:22:40 +02:00
Florian Bruhin
8acd014d39 Ignore new Qt 5.10 debug build messages 2017-10-17 06:22:26 +02:00
suve
2ad7bafcdf Add "faq" and "help" links in appdata.xml file 2017-10-16 22:30:51 +02:00
suve
914d72a216 Remove the .desktop suffix from <id> in appdata.xml
This used to be required by the standard, but is no longer the case.
2017-10-16 22:26:46 +02:00
suve
30f7f7b03c Change <id> in appdata.xml to match the {tld}.{vendor}.{product} scheme 2017-10-16 22:05:07 +02:00
suve
18776456f3 Add <provides> to appdata.xml file 2017-10-16 21:58:58 +02:00
suve
3084e7be02 Add <categories> to appdata.xml file 2017-10-16 21:58:51 +02:00
suve
a76fdfe205 Add more URLs to appdata file 2017-10-16 21:55:24 +02:00
suve
1d5d6acdea Add <launchable> info to appdata.xml 2017-10-16 21:34:08 +02:00
suve
039edd8d85 Add a basic appdata.xml file 2017-10-16 21:32:53 +02:00
Aneesh Roy
50983f01b8 New tab opens as unrelated 2017-10-16 17:14:48 +01:00
pyup-bot
eec129807e Update hypothesis from 3.32.0 to 3.33.0 2017-10-16 16:53:15 +02:00
pyup-bot
dd70019d4c Update setuptools from 36.5.0 to 36.6.0 2017-10-16 16:53:13 +02:00
Aneesh Roy
4d780e23af Add tabs.close_mouse_button_on_bar ignore option 2017-10-16 15:49:19 +01:00
Aneesh Roy
674269724f Configurable behavior of close mouse button on bar 2017-10-16 15:44:52 +01:00
Florian Bruhin
e89fda189a Fix tab sizing when we get a QPainter and not a QStylePainter
I'm not sure yet how that happens, but I got a crash report for that.
See #3099
2017-10-16 13:44:51 +02:00
Florian Bruhin
e766fe14fc Fix HTML escaping in completion 2017-10-16 12:27:13 +02:00
Florian Bruhin
7adab9ec78 Fix long line 2017-10-16 09:58:44 +02:00
Florian Bruhin
5307b97ca5 Improve checkpyver error message 2017-10-16 09:24:31 +02:00
Florian Bruhin
caeab959a5 Update changelog 2017-10-16 08:32:11 +02:00
Florian Bruhin
8756997dc8 Merge remote-tracking branch 'origin/pr/3099' 2017-10-16 08:30:03 +02:00
Florian Bruhin
09868c1e7f Update docs 2017-10-16 08:17:45 +02:00
Florian Bruhin
3797b0cfed Merge remote-tracking branch 'origin/pr/3034' 2017-10-16 08:12:15 +02:00
Florian Bruhin
3d02feac2b Merge pull request #3118 from jgkamat/jay/git-version
Change qute:version git commit to display hash
2017-10-16 07:59:52 +02:00
Florian Bruhin
2a65cadb67 Fix setting monospace fonts with None values
Fixes #3130
2017-10-16 06:18:09 +02:00
Florian Bruhin
e003b11670 Fix overflow handling for QtWebKit scrolling
If we do "m * val / 100", the value gets bigger, so we need to check for an
overflow afterwards.
2017-10-15 22:30:17 +02:00
Florian Bruhin
fa4a66f7b3 Add SQLITE_READONLY to environmental errors 2017-10-15 21:10:11 +02:00
Adrien Folie
57e1135abe fix blurry favicons on hidpi displays 2017-10-15 19:24:15 +02:00
Florian Bruhin
e90a5f509e Improve install docs
[ci skip]
2017-10-15 12:25:57 +02:00
Florian Bruhin
392ea8825b Clarify completion keybinding changes
See #3125
[ci skip]
2017-10-15 12:21:14 +02:00
Florian Bruhin
af3c9a2b9e Update changelog 2017-10-15 00:29:45 +02:00
Florian Bruhin
16b2df56df Merge remote-tracking branch 'origin/pr/3115' 2017-10-15 00:27:14 +02:00
Florian Bruhin
2eba2cc8f5 Skip another history test on AppVeyor 2017-10-15 00:26:26 +02:00
Florian Bruhin
f4796b5ec6 Add missing period 2017-10-15 00:22:19 +02:00
Florian Bruhin
e3a305a814 Regenerate docs 2017-10-15 00:21:56 +02:00
Florian Bruhin
71f48a1e30 Move statusbar colors together in configdata.yml 2017-10-15 00:21:35 +02:00
Florian Bruhin
69d4bb6c6a Merge remote-tracking branch 'origin/pr/3119' 2017-10-15 00:20:47 +02:00
Jay Kamat
4ff44eff7b Clean up logic for finding git hash
Also add implementation for release scripts as well
2017-10-14 18:08:52 -04:00
Florian Bruhin
8f9bb67762 Merge pull request #3102 from rcorre/configuring_pylint
Note how to ignore pylint in configuring doc.
2017-10-15 00:05:11 +02:00
Jay Kamat
08b562ea0c Add caching for tab sizes 2017-10-14 17:59:50 -04:00
Florian Bruhin
01d2654c23 Improve history formatting in crashdialog 2017-10-14 22:27:30 +02:00
Florian Bruhin
bad349aacf Fix getting history in crash dialog 2017-10-14 22:23:03 +02:00
Kimat Boven
8ca0c87b1f FakeUrl had no url 2017-10-14 22:14:01 +02:00
Kimat Boven
ffab9e263f it was not possible to show the current_url in tab or window title
note that I couldn't use {url} as field for the FormatString
2017-10-14 22:14:01 +02:00
Florian Bruhin
5dacf1431f eslint: Disable multiline-comment-style 2017-10-14 21:41:56 +02:00
Florian Bruhin
27c46f20c0 Make sure the config default values are mutable
While the old values meant the same thing, they weren't mutable, so the config
couldn't modify them with a simple .append().

Fixes #3104
2017-10-14 16:40:44 +02:00
Florian Bruhin
97a14c14b3 Update changelog
[ci skip]
2017-10-14 12:50:34 +02:00
Florian Bruhin
0195f717c3 Move QOpenGL imports to the top
We don't support Qt < 5.4 anymore anyways.
2017-10-14 12:11:41 +02:00
Florian Bruhin
b3f395453b Run Nvidia shader workaround earlier
We need to do it before utils.opengl_vendor(), and it fits better there anyway.
This was a regression in v1.0.

See #2554, #3106
2017-10-14 12:10:21 +02:00
sMailund
f5cccfb097 re-add erroneously removed line 2017-10-14 10:43:34 +02:00
sMailund
14005e3684 trigger color change on passthrough mode 2017-10-14 10:30:44 +02:00
sMailund
57c4285dbc configure colorflags for passthrough mode 2017-10-14 10:29:34 +02:00
sMailund
4d2ca878ea add color configuration to passthrough mode 2017-10-14 10:26:55 +02:00
Jay Kamat
ee3d7463f6 Change qute:version git commit to display hash
Replaces output of git-describe

Closes #3095
2017-10-13 23:30:07 -04:00
Florian Bruhin
d411ec1eba Mark content.notifications as QtWebKit-only 2017-10-13 23:18:36 +02:00
Luca Benci
440740d30b Don't crash when opening editor under webkit 2017-10-13 20:40:08 +02:00
Ryan Roden-Corrent
dde50c23bc Fix up pylint notes in configuring.asciidoc.
- Use short form of pylint disable
- Update the following code block as well
- Add pylint ignore for missing-module-docstring
2017-10-13 07:44:26 -04:00
Florian Bruhin
db8fa5fdb6 Skip "History with invalid URL" test on Windows
For some reason, this hangs a lot on AppVeyor
2017-10-13 10:45:40 +02:00
Panagiotis K
630384e07f Fix tests. 2017-10-13 10:39:34 +03:00
Luca Benci
ad9ac2191b Also accept {file} placeholder 2017-10-12 23:48:49 +02:00
Luca Benci
6425061b3a Substitute new editor.command placeholders
Added placeholders are:

* `{file}` has the same function as `{}`
* `{line}` is the 1-based line number
* `{column}` is the 1-based column number
* `{line0}` like `{line}`, but 0-based
* `{column0}` like `{column}` but 0-based
2017-10-12 22:46:05 +02:00
Luca Benci
cdf4f69251 Pass caret_position to editor's edit() 2017-10-12 22:43:31 +02:00
Luca Benci
67e41af875 Add sanity check and accessor for caret_position 2017-10-12 22:43:06 +02:00
Luca Benci
f43a597370 Add cursor_position to serialize_elem output 2017-10-12 22:42:40 +02:00
Bryan Gilbert
0e527d2584 Consistently space + center favicons when using vertical tabs 2017-10-12 14:55:13 -04:00
Ryan Roden-Corrent
69ced4e033 Note how to ignore pylint in configuring doc.
The doc explains how to ignore flake8 errors, but the `c` and `config`
variables may also make pylint unhappy
2017-10-12 11:51:03 -04:00
Joakim Reinert
efef588c30 fix lints in completer 2017-10-12 14:43:22 +02:00
Panagiotis K
10388b0515 Remove an unused variable. 2017-10-12 15:16:35 +03:00
Panagiotis K
0a753915ff Prompt for non-existing download directories.
Closes #2120
2017-10-12 15:00:35 +03:00
Joakim Reinert
7c584e7b6c add optional interval argument to start function of Timer stubs
Fixes failing tests for completer
2017-10-12 13:02:37 +02:00
Michael Hoang
249e497d36 Add test for window completion 2017-10-11 17:18:13 +11:00
Michael Hoang
29f66dcd95 Merge :tab-detach with :tab-give 2017-10-11 17:18:12 +11:00
Michael Hoang
67437a0d5d Add :tab-give and :tab-take commands and tests 2017-10-11 16:27:35 +11:00
Michael Hoang
b7061dc7db Separate logic for resolving buffers from index 2017-10-11 16:27:35 +11:00
Luca Benci
c8d41a4f87 Make tests pass 2017-10-10 22:54:49 +02:00
Luca Benci
052c527e4c Avoid explicit config monkeypatching 2017-10-10 22:52:57 +02:00
Luca Benci
787e3db3d5 Move tests to test_runners.py 2017-10-10 22:51:40 +02:00
Luca Benci
5078080bb0 Add (not fully working) tests for use_best_match 2017-10-10 22:02:25 +02:00
Joakim Reinert
0226025308 add adjustable amount of chars required to update completions 2017-10-09 16:51:19 +02:00
Joakim Reinert
019d66a4c6 add adjustable delay for completion updates 2017-10-09 16:51:19 +02:00
Luca Benci
0578349e29 Default completion.use_best_match to false 2017-10-09 11:12:42 +02:00
Luca Benci
71048a1b55 Add (and use) completion.use_best_match config 2017-10-09 11:12:37 +02:00
Luca Benci
9d0dfd5726 Always run best-matching command 2017-10-09 11:12:28 +02:00
Josefson Fraga
92f9a8503e add required redirect (url,title,atime,redirect) 2017-10-03 01:55:31 -04:00
Josefson Fraga
665a76561e add insertions to ComandHistory table as well 2017-10-02 22:50:52 -04:00
Josefson Fraga
4dc232f259 pylint fixes 2017-10-02 13:54:24 -04:00
Josefson Fraga
c6d140a40a adding script to import history data from other browsers 2017-10-02 00:26:47 -04:00
Josefson Fraga
8cb6b832d1 script to import history data from other browsers 2017-10-02 00:24:59 -04:00
319 changed files with 8772 additions and 3904 deletions

View File

@@ -12,6 +12,7 @@ exclude_lines =
def __repr__
raise AssertionError
raise NotImplementedError
raise utils\.Unreachable
if __name__ == ["']__main__["']:
[xml]

30
.flake8
View File

@@ -1,5 +1,8 @@
[flake8]
exclude = .*,__pycache__,resources.py
# B001: bare except
# B008: Do not perform calls in argument defaults. (fine with some Qt stuff)
# B305: .next() (false-positives)
# E128: continuation line under-indented for visual indent
# E226: missing whitespace around arithmetic operator
# E265: Block comment should start with '#'
@@ -19,32 +22,33 @@ exclude = .*,__pycache__,resources.py
# 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)
# D106: Missing docstring in public nested class (will be handled by others)
# D107: Missing docstring in __init__ (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)
# D401: First line should be in imperative mood (okay sometimes)
# D402: First line should not be function's signature (false-positives)
# D403: First word of the first line should be properly capitalized
# (false-positives)
# D413: Missing blank line after last section (not in pep257?)
# A003: Builtin name for class attribute (needed for attrs)
ignore =
B001,B008,B305,
E128,E226,E265,E501,E402,E266,E722,E731,
F401,
N802,
P101,P102,P103,
D102,D103,D104,D105,D209,D211,D402,D403
D102,D103,D106,D107,D104,D105,D209,D211,D401,D402,D403,D413,
A003
min-version = 3.4.0
max-complexity = 12
putty-auto-ignore = True
putty-ignore =
/# pylint: disable=invalid-name/ : +N801,N806
/# pragma: no mccabe/ : +C901
tests/*/test_*.py : +D100,D101,D401
tests/conftest.py : +F403
tests/unit/browser/test_history.py : +N806
tests/helpers/fixtures.py : +N806
tests/unit/browser/webkit/http/test_content_disposition.py : +D400
scripts/dev/ci/appveyor_install.py : +FI53
# FIXME:conf
tests/unit/completion/test_models.py : +F821
per-file-ignores =
tests/*/test_*.py : D100,D101,D401
tests/unit/browser/test_history.py : N806
tests/helpers/fixtures.py : N806
tests/unit/browser/webkit/http/test_content_disposition.py : D400
scripts/dev/ci/appveyor_install.py : FI53
copyright-check = True
copyright-regexp = # Copyright [\d-]+ .*
copyright-min-file-size = 110

2
.github/CODEOWNERS vendored
View File

@@ -6,3 +6,5 @@ tests/end2end/features/test_completion_bdd.py @rcorre
tests/unit/browser/test_history.py @rcorre
tests/unit/completion/* @rcorre
tests/unit/misc/test_sql.py @rcorre
qutebrowser/config/configdata.yml @mschilli87

46
.github/CODE_OF_CONDUCT.md vendored Normal file
View File

@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mail@qutebrowser.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -4,6 +4,9 @@
- Either run the testsuite locally, or keep an eye on Travis CI / AppVeyor
after pushing changes.
See the full contribution docs for details:
- If you are stuck somewhere or have questions,
https://github.com/qutebrowser/qutebrowser#getting-help[please ask]!
See the full contribution documentation for details and other useful hints:
include::../doc/contributing.asciidoc[]

17
.gitignore vendored
View File

@@ -27,15 +27,16 @@ __pycache__
/.cache
/.testmondata
/.hypothesis
/.mypy_cache
/prof
/venv
TODO
/scripts/testbrowser_cpp/webkit/Makefile
/scripts/testbrowser_cpp/webkit/main.o
/scripts/testbrowser_cpp/webkit/testbrowser
/scripts/testbrowser_cpp/webkit/.qmake.stash
/scripts/testbrowser_cpp/webengine/Makefile
/scripts/testbrowser_cpp/webengine/main.o
/scripts/testbrowser_cpp/webengine/testbrowser
/scripts/testbrowser_cpp/webengine/.qmake.stash
/scripts/testbrowser/cpp/webkit/Makefile
/scripts/testbrowser/cpp/webkit/main.o
/scripts/testbrowser/cpp/webkit/testbrowser
/scripts/testbrowser/cpp/webkit/.qmake.stash
/scripts/testbrowser/cpp/webengine/Makefile
/scripts/testbrowser/cpp/webengine/main.o
/scripts/testbrowser/cpp/webengine/testbrowser
/scripts/testbrowser/cpp/webengine/.qmake.stash
/scripts/dev/pylint_checkers/qute_pylint.egg-info

View File

@@ -13,34 +13,33 @@ persistent=n
[MESSAGES CONTROL]
enable=all
disable=no-self-use,
fixme,
global-statement,
locally-disabled,
disable=locally-disabled,
locally-enabled,
too-many-ancestors,
too-few-public-methods,
too-many-public-methods,
suppressed-message,
fixme,
no-self-use,
cyclic-import,
bad-continuation,
too-many-instance-attributes,
blacklisted-name,
too-many-lines,
logging-format-interpolation,
logging-not-lazy,
broad-except,
bare-except,
eval-used,
exec-used,
ungrouped-imports,
suppressed-message,
too-many-return-statements,
duplicate-code,
global-statement,
wrong-import-position,
duplicate-code,
no-else-return,
# https://github.com/PyCQA/pylint/issues/1698
unsupported-membership-test,
unsupported-assignment-operation,
unsubscriptable-object
too-many-ancestors,
too-many-public-methods,
too-many-instance-attributes,
too-many-lines,
too-many-return-statements,
too-many-boolean-expressions,
too-many-locals,
too-many-branches,
too-many-statements,
too-few-public-methods
[BASIC]
function-rgx=[a-z_][a-z0-9_]{2,50}$
@@ -69,10 +68,10 @@ valid-metaclass-classmethod-first-arg=cls
[TYPECHECK]
ignored-modules=PyQt5,PyQt5.QtWebKit
ignored-classes=_CountingAttr
[IMPORTS]
# WORKAROUND
# For some reason, pylint doesn't know about some Python 3 modules on
# AppVeyor...
known-standard-library=faulthandler,http,enum,tokenize,posixpath,importlib,types
known-third-party=sip

View File

@@ -23,7 +23,7 @@ matrix:
env: TESTENV=py36-pyqt59-cov
- os: osx
env: TESTENV=py36 OSX=sierra
osx_image: xcode8.3
osx_image: xcode9.2
language: generic
# https://github.com/qutebrowser/qutebrowser/issues/2013
# - os: osx
@@ -51,7 +51,11 @@ matrix:
env: TESTENV=eslint
language: node_js
python: null
node_js: node
node_js: "lts/*"
- os: linux
language: generic
env: TESTENV=shellcheck
services: docker
fast_finish: true
cache:

View File

@@ -13,6 +13,8 @@ include qutebrowser/utils/testfile
include qutebrowser/git-commit-id
include LICENSE doc/* README.asciidoc
include misc/qutebrowser.desktop
include misc/qutebrowser.appdata.xml
include misc/Makefile
include requirements.txt
include tox.ini
include qutebrowser.py
@@ -21,7 +23,7 @@ include qutebrowser/config/configdata.yml
prune www
prune scripts/dev
prune scripts/testbrowser_cpp
prune scripts/testbrowser/cpp
prune .github
exclude scripts/asciidoc2html.py
exclude doc/notes

View File

@@ -15,7 +15,7 @@ image:https://travis-ci.org/qutebrowser/qutebrowser.svg?branch=master["Build Sta
image:https://ci.appveyor.com/api/projects/status/5pyauww2k68bbow2/branch/master?svg=true["AppVeyor build status", link="https://ci.appveyor.com/project/qutebrowser/qutebrowser"]
image:https://codecov.io/github/qutebrowser/qutebrowser/coverage.svg?branch=master["coverage badge",link="https://codecov.io/github/qutebrowser/qutebrowser?branch=master"]
link:https://www.qutebrowser.org[website] | link:https://blog.qutebrowser.org[blog] | link:https://github.com/qutebrowser/qutebrowser/releases[releases]
link:https://www.qutebrowser.org[website] | link:https://blog.qutebrowser.org[blog] | https://github.com/qutebrowser/qutebrowser/blob/master/doc/faq.asciidoc[FAQ] | https://www.qutebrowser.org/doc/contributing.html[contributing] | link:https://github.com/qutebrowser/qutebrowser/releases[releases] | https://github.com/qutebrowser/qutebrowser/blob/master/doc/install.asciidoc[installing]
// QUTE_WEB_HIDE_END
qutebrowser is a keyboard-focused browser with a minimal GUI. It's based
@@ -109,7 +109,7 @@ The following software and libraries are required to run qutebrowser:
link:https://github.com/annulen/webkit/wiki[updated fork] (5.212) is
supported
* http://www.riverbankcomputing.com/software/pyqt/intro[PyQt] 5.7.0 or newer
(5.9 recommended) for Python 3
(5.9.2 recommended) for Python 3
* https://pypi.python.org/pypi/setuptools/[pkg_resources/setuptools]
* http://fdik.org/pyPEG/[pyPEG2]
* http://jinja.pocoo.org/[jinja2]
@@ -182,7 +182,9 @@ Active
* Firefox addons (based on WebExtensions):
https://addons.mozilla.org/en-GB/firefox/addon/vimium-ff/[Vimium-FF] (experimental),
https://key.saka.io[Saka Key],
https://github.com/cmcaine/tridactyl[Tridactyl] (in early development, working
https://github.com/ueokande/vim-vixen[Vim Vixen],
https://github.com/shinglyu/QuantumVim[QuantumVim],
https://github.com/cmcaine/tridactyl[Tridactyl] (working
on a https://bugzilla.mozilla.org/show_bug.cgi?id=1215061[better API] for
keyboard integration in Firefox).
@@ -200,7 +202,6 @@ main inspiration for qutebrowser)
http://www.vimperator.org/[Vimperator],
http://5digits.org/pentadactyl/[Pentadactyl],
https://github.com/akhodakivskiy/VimFx[VimFx],
https://github.com/shinglyu/QuantumVim[QuantumVim]
* Chrome/Chromium addons:
https://chrome.google.com/webstore/detail/vichrome/gghkfhpblkcmlkmpcpgaajbbiikbhpdi?hl=en[ViChrome],
https://github.com/jinzhu/vrome[Vrome]

View File

@@ -118,7 +118,7 @@ TODO: people with t-shirts or higher pledge levels
- toml
- vimja
- wiz
- 43 Anonymous
- 44 Anonymous
2016
----
@@ -212,6 +212,7 @@ Other sponsors
- Julie Engel
- Jörg Behrmann
- Jørgen Skancke
- Kevin Kainan Li
- Kevin Velghe
- Konstantin Shmelkov
- Kyle Frazer

View File

@@ -15,10 +15,230 @@ breaking changes (such as renamed commands) can happen in minor releases.
// `Fixed` for any bug fixes.
// `Security` to invite users to upgrade in case of vulnerabilities.
v1.1.2
------
Changed
~~~~~~~
- Windows/macOS releases now bundle Qt 5.10.1 which includes security fixes from
Chromium up to version 64.0.3282.140.
Fixed
~~~~~
- QtWebEngine: Crash with Qt 5.10.1 when using :undo on some tabs.
- Compatibility with Python 3.7
v1.1.1
------
Fixed
~~~~~
- The Makefile now actually works.
- Fixed crashes with Qt 5.10 when closing a tab before it finished loading.
v1.1.0
------
Added
~~~~~
- Initial support for Greasemonkey scripts. There are still some rough edges,
but many scripts should already work.
- There's now a `misc/Makefile` file in releases, which should help
distributions which package qutebrowser, as they can run something like
`make -f misc/Makefile DESTDIR="$pkgdir" install` now.
- New fields for `window.title_format` and `tabs.title.format`:
* `{current_url}`
* `{protocol}`
- New settings:
* `colors.statusbar.passthrough.fg`/`.bg`
* `completion.delay` and `completion.min_chars` to update the completion less
often.
* `completion.use_best_match` to automatically use the best-matching
command in the completion.
* `keyhint.radius` to configure the edge rounding for the key hint widget.
* `qt.highdpi` to turn on Qt's High-DPI scaling.
* `tabs.pinned.shrink` (`true` by default) to make it possible
for pinned tabs and normal tabs to have the same size.
* `content.windowed_fullscreen` to show e.g. a fullscreened video in the
window without fullscreening that window.
* `tabs.persist_mode_on_change` to keep the current mode when
switching tabs.
* `session.lazy_restore` which allows to not load pages immediately
when restoring a session.
- New commands:
* `:tab-give` and `:tab-take`, to give tabs to another window, or take them
from another window.
* `:completion-item-yank` (bound to `<Ctrl-C>`) to yank the current
completion item text.
* `:edit-command` to edit the commandline in an editor.
* `search.incremental` for incremental text search.
- New flags for existing commands:
* `-o` flag for `:spawn` to show stdout/stderr in a new tab.
* `--rapid` flag for `:command-accept` (bound to `Ctrl-Enter` by default),
which allows executing a command in the completion without closing it.
* `--private` and `--related` flags for `:edit-url`, which have the
same effect they have with `:open`.
* `--history` for `:completion-item-focus` which causes it to go
through the command history when no text was entered. The default bindings for
cursor keys in the completion changed to use that, so that they can be used
again to navigate through completion items when a text was entered.
* `--file` for `:debug-pyeval` which makes it take a filename instead of a
line of code.
- New `config.source(...)` method for `config.py` to source another file.
- New `{line}` and `{column}` replacements for `editor.command` to position the
cursor correctly.
- New `qute-pass` userscript as alternative to `password_fill` which allows
selecting accounts via rofi or any other dmenu-compatile application.
- New `hist_importer.py` script to import history from Firefox/Chromium.
Changed
~~~~~~~
- Some settings got renamed:
* `tabs.width.bar` -> `tabs.width`
* `tabs.width.indicator` -> `tabs.indicator.width`
* `tabs.indicator_padding` -> `tabs.indicator.padding`
* `session_default_name` -> `session.default_name`
* `ignore_case` -> `search.ignore_case`
- Much improved user stylesheet handling for QtWebEngine which reduces
flickering and updates immediately after setting a stylesheet.
- High-DPI favicons are now used when available.
- The `asciidoc2html.py` script now uses Pygments (which is already a dependency
of qutebrowser) instead of `source-highlight` for syntax highlighting.
- The `:buffer` command now doesn't require quoting anymore, similar to `:open`.
- The `importer.py` script was largely rewritten and now also supports importing
from Firefox' `places.sqlite` file and Chrome/Chromium profiles.
- Various internal refactorings to use Python 3.5 and ECMAscript 6 features.
- If the `window.hide_wayland_decoration` setting is False, but
`QT_WAYLAND_DISABLE_WINDOWDECORATION` is set in the environment,
the decorations are still hidden.
- The `install_dict.py` script for QtWebEngine was renamed to `dictcli.py` and
can now also upgrade dictionaries correctly.
- `:undo` now can re-open multiple tabs after `:tab-only` was used.
- `:config-write-py` with a relative path now puts the file into the config
directory.
- The `qute://version` page now also shows the uptime of qutebrowser.
- qutebrowser now prompts to create a non-existing directory when starting a
download.
- `:jseval --file` now searches relative paths in a `js/` subdir in
qutebrowser's data dir, e.g. `~/.local/share/qutebrowser/js`.
- The current/default bindings are now shown in the ``:bind` completion.
- Empty categories are now hidden in the `:open` completion.
- Search terms for URLs and titles can now be mixed when filtering the
completion.
- The default font size for the UI got bumped up from 8pt to 10pt.
- Improved matching in the completion: The words entered are now matched in any
order, and mixed matches on URL/tite are possible.
- The system's default encoding (rather than UTF-8) is now used to decode
subprocess output.
- qutebrowser now ensures it's focused again after an external editor is closed.
- The `colors.completion.fg` setting can now be a list, allowing to specify
different colors for the three completion columns.
Fixed
~~~~~
- More consistent sizing for favicons with vertical tabs.
- Using `:home` on pinned tabs is now prevented.
- Fix crash with unknown file types loaded via `qute://help`.
- Scrolling performance improvements.
- Sites like `qute://help` now redirect to `qute://help/` to make sure links
work properly.
- Fixes for the size calculation of pinned tabs in the tab bar.
- Worked around a crash with PyQt 5.9.1 compiled against Qt < 5.9.1 when using
`:yank` or `qute://` URLs.
- Fixed crash when opening `qute://help/img`.
- Fixed `gU` (`:navigate up`) on `qute://help` and webservers not handling `..`
in a URL.
- Using e.g. `-s backend webkit` to set the backend now works correctly.
- Fixed crash when closing the tab an external editor was opened in.
- When using `:search-next` before a search is finished, no warning about no
results being found is shown anymore.
- Fix `:click-element` with an ID containing non-alphanumeric characters.
- Fix crash when a subprocess outputs data which is not decodable as UTF-8.
- Fix crash when closing a tab immediately after hinting.
- Worked around issues in Qt 5.10 with loading progress never being finished.
- Fixed a crash when writing a flag before a command (e.g. `:-w open `).
- Fixed a crash when clicking certain form elements with QtWebEngine.
Deprecated
~~~~~~~~~~
- `:tab-detach` has been deprecated, as `:tab-give` without argument can be used
instead.
Removed
~~~~~~~
- The long-deprecated `:prompt-yes`, `:prompt-no`, `:paste-primary` and `:paste`
commands have been removed.
- The invocation `:download <url> <dest>` which was deprecated in v0.5.0 was
removed, use `:download --dest <dest> <url>` instead.
- The `messages.unfocused` option which wasn't used anymore was removed.
- The `x[xtb]` default bindings got removed again as many users accidentally
triggered them.
v1.0.4
------
Fixed
~~~~~
- The `qute://gpl` page now works correctly again.
- Trying to bind an empty command now doesn't crash anymore.
- Fixed crash when `:config-write-py` fails to write to the given path.
- Fixed crash for some users when selecting a file with Qt 5.9.3
- Improved handling for various SQL errors
- Fix crash when setting content.cache.size to a big value (> 2 GB)
v1.0.3
------
Changed
~~~~~~~
- macOS and Windows builds are now built with PyQt 5.9.1 and Qt 5.9.2, including
various bugfixes, as well as security fixes from Chromium up to version
61.0.3163.79.
- Performance improvements for tab rendering.
- The :open-editor command is now not hidden anymore as it's also usable in
normal mode.
Fixed
~~~~~
- Handle accessing a locked sqlite database gracefully
- Abort pinned tab dialogs properly when a tab is closed e.g. by closing a
window
- Unbinding a default keybinding twice now doesn't bind it again
- Completions are now sorted correctly again when filtered
v1.0.2
------
Fixed
~~~~~
- Fix workaround for black screens or crashes with Nvidia cards
- Handle a filesystem going read-only gracefully
- Fix crash when setting `fonts.monospace`
- Fix list options not being modifyable via `.append()` in `config.py`
- Mark the content.notifications setting as QtWebKit only correctly
- Fix wrong rendering of keys like `<back>` in the completion
Changed
~~~~~~~
- Nicer error messages and other minor improvements
v1.0.1
------
Fixes
Fixed
~~~~~
- Fixed starting after customizing `fonts.tabs` or `fonts.debug_console`.
@@ -56,6 +276,9 @@ Major changes
the entire browsing history. The default for
`completion.web_history_max_items` got changed to `-1` (unlimited). If the
completion is too slow on your machine, try setting it to a few 1000 items.
- Up/Down now navigates through the command history instead of selecting
completion items. Either use Tab to cycle through the completion, or
https://github.com/qutebrowser/qutebrowser/blob/master/doc/help/configuring.asciidoc#migrating-older-configurations[restore the old behavior].
Added
~~~~~
@@ -895,7 +1118,7 @@ Added
- New `:fake-key` command to send a fake keypress to a website or to
qutebrowser.
- New `--mhtml` argument for `:download` to download a page including all
ressources as MHTML file.
resources as MHTML file.
- New option `tabs -> title-alignment` to change the alignment of tab titles.
Changed
@@ -1095,7 +1318,7 @@ Added
- New argument `--no-err-windows` to suppress all error windows.
- New arguments `--top-navigate` and `--bottom-navigate` (`-t`/`-b`) for `:scroll-page` to specify a navigation action (e.g. automatically go to the next page when arriving at the bottom).
- New flag `-d`/`--detach` for `:spawn` to detach the spawned process so it's not closed when qutebrowser is.
- New flag `-v`/`--verbose` for `:spawn` to print informations when the process started/exited successfully.
- New flag `-v`/`--verbose` for `:spawn` to print information when the process started/exited successfully.
- Many new color settings (foreground setting for every background setting).
- New setting `ui -> modal-js-dialog` to use the standard modal dialogs for javascript questions instead of using the statusbar.
- New setting `colors -> webpage.bg` to set the background color to use for websites which don't set one.

View File

@@ -100,16 +100,10 @@ Currently, the following tox environments are available:
- `py35`, `py36`: Run pytest for python 3.5/3.6 with the system-wide PyQt.
- `py36-pyqt57`, ..., `py36-pyqt59`: Run pytest with the given PyQt version (`py35-*` also works).
- `py36-pyqt59-cov`: Run with coverage support (other Python/PyQt versions work too).
* `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].
* `flake8`: Run various linting checks via https://pypi.python.org/pypi/flake8[flake8].
* `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.
@@ -470,7 +464,6 @@ The following arguments are supported for `@cmdutils.argument`:
- `flag`: Customize the short flag (`-x`) the argument will get.
- `win_id=True`: Mark the argument as special window ID argument.
- `count=True`: Mark the argument as special count argument.
- `hide=True`: Hide the argument from the documentation.
- `completion`: A completion function (see `qutebrowser.completions.models.*`)
to use when completing arguments for the given command.
- `choices`: The allowed string choices for the argument.
@@ -681,7 +674,6 @@ qutebrowser release
* Adjust `__version_info__` in `qutebrowser/__init__.py`.
* Update changelog (remove *(unreleased)*).
* Run tests again.
* Commit.
* Create annotated git tag (`git tag -s "v1.$x.$y" -m "Release v1.$x.$y"`).
@@ -691,9 +683,9 @@ qutebrowser release
* Mark the milestone at https://github.com/qutebrowser/qutebrowser/milestones
as closed.
* Linux: Run `python3 scripts/dev/build_release.py --upload v1.$x.$y`.
* Windows: Run `C:\Python36-32\python scripts\dev\build_release.py --asciidoc C:\Python27\python C:\asciidoc-8.6.9\asciidoc.py --upload v1.X.Y` (replace X/Y by hand).
* macOS: Run `python3 scripts/dev/build_release.py --upload v1.X.Y` (replace X/Y by hand).
* Linux: Run `git checkout v1.$x.$y && python3 scripts/dev/build_release.py --upload v1.$x.$y`.
* Windows: Run `git checkout v1.X.Y; C:\Python36-32\python scripts\dev\build_release.py --asciidoc C:\Python27\python C:\asciidoc-8.6.9\asciidoc.py --upload v1.X.Y` (replace X/Y by hand).
* macOS: Run `git checkout v1.X.Y && python3 scripts/dev/build_release.py --upload v1.X.Y` (replace X/Y by hand).
* On server: Run `python3 scripts/dev/download_release.py v1.X.Y` (replace X/Y by hand).
* Update `qutebrowser-git` PKGBUILD if dependencies/install changed.
* Announce to qutebrowser and qutebrowser-announce mailinglist.

View File

@@ -28,16 +28,20 @@ What's wrong with link:http://portix.bitbucket.org/dwb/[dwb]/link:http://sourcef
https://lists.webkit.org/pipermail/webkit-gtk/2014-March/001821.html[deprecated],
these bugs are never going to be fixed.
+
The newer http://webkitgtk.org/reference/webkit2gtk/stable/index.html[WebKit2
API] seems to lack basic features like proxy support, and almost no projects
seem to have started porting to WebKit2 (I only know of
http://www.uzbl.org/[uzbl]).
When qutebrowser was created, the newer
http://webkitgtk.org/reference/webkit2gtk/stable/index.html[WebKit2 API] lacked
basic features like proxy support, and almost no projects have started porting
to WebKit2. In the meantime, this situation has improved a bit, but there are
stil only a few project which have some kind of WebKit2 support (see the
https://github.com/qutebrowser/qutebrowser#similar-projects[list of
alternatives]).
+
qutebrowser uses http://qt.io/[Qt] and http://wiki.qt.io/QtWebKit[QtWebKit]
instead, which suffers from far less such crashes. It might switch to
http://wiki.qt.io/QtWebEngine[QtWebEngine] in the future, which is based on
Google's https://en.wikipedia.org/wiki/Blink_(layout_engine)[Blink] rendering
engine.
qutebrowser uses http://qt.io/[Qt] and
http://wiki.qt.io/QtWebEngine[QtWebEngine] by default (and supports
http://wiki.qt.io/QtWebKit[QtWebKit] optionally). QtWebEngine is based on
Google's https://www.chromium.org/Home[Chromium]. With an up-to-date Qt, it has
much more man-power behind it than WebKitGTK+ has, and thus supports more modern
web features - it's also arguably more secure.
What's wrong with https://www.mozilla.org/en-US/firefox/new/[Firefox] and link:http://5digits.org/pentadactyl/[Pentadactyl]/link:http://www.vimperator.org/vimperator[Vimperator]?::
Firefox likes to break compatibility with addons on each upgrade, gets
@@ -146,13 +150,13 @@ For QtWebKit:
For QtWebEngine:
. Make sure your versions of PyQt and Qt are 5.8 or higher.
. Use `install_dict.py` script to install dictionaries.
. Use `dictcli.py` script to install dictionaries.
Run the script with `-h` for the parameter description.
. Set `spellcheck.languages` to the desired list of languages, e.g.:
`:set spellcheck.languages "['en-US', 'pl-PL']"`
How do I use Tor with qutebrowser?::
Start tor on your machine, and do `:set network proxy socks://localhost:9050/`
Start tor on your machine, and do `:set content.proxy socks://localhost:9050/`
in qutebrowser. Note this won't give you the same amount of fingerprinting
protection that the Tor Browser does, but it's useful to be able to access
`.onion` sites.
@@ -162,7 +166,7 @@ Why does J move to the next (right) tab, and K to the previous (left) one?::
and qutebrowser's keybindings are designed to be compatible with dwb's.
The rationale behind it is that J is "down" in vim, and K is "up", which
corresponds nicely to "next"/"previous". It also makes much more sense with
vertical tabs (e.g. `:set tabs position left`).
vertical tabs (e.g. `:set tabs.position left`).
What's the difference between insert and passthrough mode?::
They are quite similar, but insert mode has some bindings (like `Ctrl-e` to
@@ -186,10 +190,6 @@ Why takes it longer to open an URL in qutebrowser than in chromium?::
== Troubleshooting
Configuration not saved after modifying config.::
When editing your config file manually, qutebrowser must be exited completely.
This can be done by issuing the command `:quit` or by pressing `Ctrl+q`.
Unable to view flash content.::
If you have flash installed for on your system, it's necessary to enable plugins
to use the flash plugin. Using the command `:set content.plugins true`
@@ -221,5 +221,5 @@ My issue is not listed.::
https://github.com/qutebrowser/qutebrowser/issues[the issue tracker] or
using the `:report` command.
If you are reporting a segfault, make sure you read the
link:doc/stacktrace.asciidoc[guide] on how to report them with all needed
link:stacktrace.asciidoc[guide] on how to report them with all needed
information.

View File

@@ -30,6 +30,9 @@ It is possible to run or bind multiple commands by separating them with `;;`.
|<<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.
|<<clear-keychain,clear-keychain>>|Clear the currently entered key chain.
|<<clear-messages,clear-messages>>|Clear all message notifications.
|<<click-element,click-element>>|Click the element matching the given filter.
|<<close,close>>|Close the current window.
|<<config-clear,config-clear>>|Set all settings back to their default.
|<<config-cycle,config-cycle>>|Cycle an option between multiple values.
@@ -44,10 +47,14 @@ It is possible to run or bind multiple commands by separating them with `;;`.
|<<download-open,download-open>>|Open the last/[count]th download.
|<<download-remove,download-remove>>|Remove the last/[count]th download from the list.
|<<download-retry,download-retry>>|Retry the first failed/[count]th download.
|<<edit-command,edit-command>>|Open an editor to modify the current command.
|<<edit-url,edit-url>>|Navigate to a url formed in an external editor.
|<<enter-mode,enter-mode>>|Enter a key mode.
|<<fake-key,fake-key>>|Send a fake keypress or key string to the website or qutebrowser.
|<<follow-selected,follow-selected>>|Follow the selected text.
|<<forward,forward>>|Go forward in the history of the current tab.
|<<fullscreen,fullscreen>>|Toggle fullscreen mode.
|<<greasemonkey-reload,greasemonkey-reload>>|Re-read Greasemonkey scripts from disk.
|<<help,help>>|Show help about a command or setting.
|<<hint,hint>>|Start hinting.
|<<history,history>>|Show browsing history.
@@ -56,10 +63,16 @@ It is possible to run or bind multiple commands by separating them with `;;`.
|<<insert-text,insert-text>>|Insert text at cursor position.
|<<inspector,inspector>>|Toggle the web inspector.
|<<jseval,jseval>>|Evaluate a JavaScript string.
|<<jump-mark,jump-mark>>|Jump to the mark named by `key`.
|<<later,later>>|Execute a command after some time.
|<<message-error,message-error>>|Show an error message in the statusbar.
|<<message-info,message-info>>|Show an info message in the statusbar.
|<<message-warning,message-warning>>|Show a warning message in the statusbar.
|<<messages,messages>>|Show a log of past messages.
|<<navigate,navigate>>|Open typical prev/next links or navigate using the URL path.
|<<nop,nop>>|Do nothing.
|<<open,open>>|Open a URL in the current/[count]th tab.
|<<open-editor,open-editor>>|Open an external editor with the currently selected form field.
|<<print,print>>|Print the current/[count]th tab.
|<<quickmark-add,quickmark-add>>|Add a new quickmark.
|<<quickmark-del,quickmark-del>>|Delete a quickmark.
@@ -69,29 +82,39 @@ It is possible to run or bind multiple commands by separating them with `;;`.
|<<record-macro,record-macro>>|Start or stop recording a macro.
|<<reload,reload>>|Reload the current/[count]th tab.
|<<repeat,repeat>>|Repeat a given command.
|<<repeat-command,repeat-command>>|Repeat the last executed command.
|<<report,report>>|Report a bug in qutebrowser.
|<<restart,restart>>|Restart qutebrowser while keeping existing tabs open.
|<<run-macro,run-macro>>|Run a recorded macro.
|<<run-with-count,run-with-count>>|Run a command with the given count.
|<<save,save>>|Save configs and state.
|<<scroll,scroll>>|Scroll the current tab in the given direction.
|<<scroll-page,scroll-page>>|Scroll the frame page-wise.
|<<scroll-px,scroll-px>>|Scroll the current tab by 'count * dx/dy' pixels.
|<<scroll-to-perc,scroll-to-perc>>|Scroll to a specific percentage of the page.
|<<search,search>>|Search for a text on the current page. With no text, clear results.
|<<search-next,search-next>>|Continue the search to the ([count]th) next term.
|<<search-prev,search-prev>>|Continue the search to the ([count]th) previous term.
|<<session-delete,session-delete>>|Delete a session.
|<<session-load,session-load>>|Load a session.
|<<session-save,session-save>>|Save a session.
|<<set,set>>|Set an option.
|<<set-cmd-text,set-cmd-text>>|Preset the statusbar to some text.
|<<set-mark,set-mark>>|Set a mark at the current scroll position in the current tab.
|<<spawn,spawn>>|Spawn a command in a shell.
|<<stop,stop>>|Stop loading in the current/[count]th tab.
|<<tab-clone,tab-clone>>|Duplicate the current tab.
|<<tab-close,tab-close>>|Close the current/[count]th tab.
|<<tab-detach,tab-detach>>|Detach the current tab to its own window.
|<<tab-focus,tab-focus>>|Select the tab given as argument/[count].
|<<tab-give,tab-give>>|Give the current tab to a new or existing window if win_id given.
|<<tab-move,tab-move>>|Move the current tab according to the argument and [count].
|<<tab-next,tab-next>>|Switch to the next tab, or switch [count] tabs forward.
|<<tab-only,tab-only>>|Close all tabs except for the current one.
|<<tab-pin,tab-pin>>|Pin/Unpin the current/[count]th tab.
|<<tab-prev,tab-prev>>|Switch to the previous tab, or switch [count] tabs back.
|<<tab-take,tab-take>>|Take a tab from another window.
|<<unbind,unbind>>|Unbind a keychain.
|<<undo,undo>>|Re-open a closed tab.
|<<undo,undo>>|Re-open the last closed tab or tabs.
|<<version,version>>|Show version information.
|<<view-source,view-source>>|Show the source of the current page in a new tab.
|<<window-only,window-only>>|Close all windows except for the current one.
@@ -204,6 +227,34 @@ Focuses window if necessary when index is given. If both index and count are giv
==== count
The tab index to focus, starting with 1.
==== note
* This command does not split arguments after the last argument and handles quotes literally.
[[clear-keychain]]
=== clear-keychain
Clear the currently entered key chain.
[[clear-messages]]
=== clear-messages
Clear all message notifications.
[[click-element]]
=== click-element
Syntax: +:click-element [*--target* 'target'] [*--force-event*] 'filter' 'value'+
Click the element matching the given filter.
The given filter needs to result in exactly one element, otherwise, an error is shown.
==== positional arguments
* +'filter'+: How to filter the elements. id: Get an element based on its ID.
* +'value'+: The value to filter for.
==== optional arguments
* +*-t*+, +*--target*+: How to open the clicked element (normal/tab/tab-bg/window).
* +*-f*+, +*--force-event*+: Force generating a fake click event.
[[close]]
=== close
Close the current window.
@@ -283,12 +334,10 @@ Write the current configuration to a config.py file.
[[download]]
=== download
Syntax: +:download [*--mhtml*] [*--dest* 'dest'] ['url'] ['dest-old']+
Syntax: +:download [*--mhtml*] [*--dest* 'dest'] ['url']+
Download a given URL, or current page if no URL given.
The form `:download [url] [dest]` is deprecated, use `:download --dest [dest] [url]` instead.
==== positional arguments
* +'url'+: The URL to download. If not given, download the current page.
@@ -358,9 +407,18 @@ Retry the first failed/[count]th download.
==== count
The index of the download to retry.
[[edit-command]]
=== edit-command
Syntax: +:edit-command [*--run*]+
Open an editor to modify the current command.
==== optional arguments
* +*-r*+, +*--run*+: Run the command if the editor exits successfully.
[[edit-url]]
=== edit-url
Syntax: +:edit-url [*--bg*] [*--tab*] [*--window*] ['url']+
Syntax: +:edit-url [*--bg*] [*--tab*] [*--window*] [*--private*] [*--related*] ['url']+
Navigate to a url formed in an external editor.
@@ -373,6 +431,18 @@ The editor which should be launched can be configured via the `editor.command` c
* +*-b*+, +*--bg*+: Open in a new background tab.
* +*-t*+, +*--tab*+: Open in a new tab.
* +*-w*+, +*--window*+: Open in a new window.
* +*-p*+, +*--private*+: Open a new window in private browsing mode.
* +*-r*+, +*--related*+: If opening a new tab, position the tab as related to the current one (like clicking on a link).
[[enter-mode]]
=== enter-mode
Syntax: +:enter-mode 'mode'+
Enter a key mode.
==== positional arguments
* +'mode'+: The mode to enter.
[[fake-key]]
=== fake-key
@@ -388,6 +458,15 @@ Send a fake keypress or key string to the website or qutebrowser.
==== optional arguments
* +*-g*+, +*--global*+: If given, the keys are sent to the qutebrowser UI.
[[follow-selected]]
=== follow-selected
Syntax: +:follow-selected [*--tab*]+
Follow the selected text.
==== optional arguments
* +*-t*+, +*--tab*+: Load the selected link in a new tab.
[[forward]]
=== forward
Syntax: +:forward [*--tab*] [*--bg*] [*--window*]+
@@ -411,6 +490,12 @@ Toggle fullscreen mode.
==== optional arguments
* +*-l*+, +*--leave*+: Only leave fullscreen if it was entered by the page.
[[greasemonkey-reload]]
=== greasemonkey-reload
Re-read Greasemonkey scripts from disk.
The scripts are read from a 'greasemonkey' subdirectory in qutebrowser's data directory (see `:version`).
[[help]]
=== help
Syntax: +:help [*--tab*] [*--bg*] [*--window*] ['topic']+
@@ -431,7 +516,7 @@ Show help about a command or setting.
[[hint]]
=== hint
Syntax: +:hint [*--rapid*] [*--mode* 'mode'] [*--add-history*]
Syntax: +:hint [*--mode* 'mode'] [*--add-history*] [*--rapid*]
['group'] ['target'] ['args' ['args' ...]]+
Start hinting.
@@ -485,9 +570,6 @@ Start hinting.
==== optional arguments
* +*-r*+, +*--rapid*+: Whether to do rapid hinting. This is only possible with targets `tab` (with `tabs.background_tabs=true`), `tab-bg`,
`window`, `run`, `hover`, `userscript` and `spawn`.
* +*-m*+, +*--mode*+: The hinting mode to use.
- `number`: Use numeric hints.
@@ -499,6 +581,11 @@ Start hinting.
* +*-a*+, +*--add-history*+: Whether to add the spawned or yanked link to the browsing history.
* +*-r*+, +*--rapid*+: Whether to do rapid hinting. With rapid hinting, the hint mode isn't left after a hint is followed, so you can easily
open multiple links. This is only possible with targets
`tab` (with `tabs.background_tabs=true`), `tab-bg`,
`window`, `run`, `hover`, `userscript` and `spawn`.
==== note
* This command does not split arguments after the last argument and handles quotes literally.
@@ -557,7 +644,10 @@ Evaluate a JavaScript string.
* +'js-code'+: The string/file to evaluate.
==== optional arguments
* +*-f*+, +*--file*+: Interpret js-code as a path to a file.
* +*-f*+, +*--file*+: Interpret js-code as a path to a file. If the path is relative, the file is searched in a js/ subdir
in qutebrowser's data dir, e.g.
`~/.local/share/qutebrowser/js`.
* +*-q*+, +*--quiet*+: Don't show resulting JS object.
* +*-w*+, +*--world*+: Ignored on QtWebKit. On QtWebEngine, a world ID or name to run the snippet in.
@@ -566,6 +656,15 @@ Evaluate a JavaScript string.
* 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.
[[jump-mark]]
=== jump-mark
Syntax: +:jump-mark 'key'+
Jump to the mark named by `key`.
==== positional arguments
* +'key'+: mark identifier; capital indicates a global mark
[[later]]
=== later
Syntax: +:later 'ms' 'command'+
@@ -581,6 +680,36 @@ Execute a command after some time.
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
* This command does not replace variables like +\{url\}+.
[[message-error]]
=== message-error
Syntax: +:message-error 'text'+
Show an error message in the statusbar.
==== positional arguments
* +'text'+: The text to show.
[[message-info]]
=== message-info
Syntax: +:message-info 'text'+
Show an info message in the statusbar.
==== positional arguments
* +'text'+: The text to show.
==== count
How many times to show the message
[[message-warning]]
=== message-warning
Syntax: +:message-warning 'text'+
Show a warning message in the statusbar.
==== positional arguments
* +'text'+: The text to show.
[[messages]]
=== messages
Syntax: +:messages [*--plain*] [*--tab*] [*--bg*] [*--window*] ['level']+
@@ -626,6 +755,10 @@ This tries to automatically click on typical _Previous Page_ or _Next Page_ link
For `increment` and `decrement`, the number to change the URL by. For `up`, the number of levels to go up in the URL.
[[nop]]
=== nop
Do nothing.
[[open]]
=== open
Syntax: +:open [*--related*] [*--bg*] [*--tab*] [*--window*] [*--secure*] [*--private*]
@@ -653,6 +786,12 @@ The tab index to open the URL in.
==== note
* This command does not split arguments after the last argument and handles quotes literally.
[[open-editor]]
=== open-editor
Open an external editor with the currently selected form field.
The editor which should be launched can be configured via the `editor.command` config option.
[[print]]
=== print
Syntax: +:print [*--preview*] [*--pdf* 'file']+
@@ -762,6 +901,13 @@ Repeat a given command.
* With this command, +;;+ is interpreted literally instead of splitting off a second command.
* This command does not replace variables like +\{url\}+.
[[repeat-command]]
=== repeat-command
Repeat the last executed command.
==== count
Which count to pass the command.
[[report]]
=== report
Report a bug in qutebrowser.
@@ -782,6 +928,26 @@ Run a recorded macro.
==== count
How many times to run the macro.
[[run-with-count]]
=== run-with-count
Syntax: +:run-with-count 'count-arg' 'command'+
Run a command with the given count.
If run_with_count itself is run with a count, it multiplies count_arg.
==== positional arguments
* +'count-arg'+: The count to pass to the command.
* +'command'+: The command to run, with optional args.
==== count
The count that run_with_count itself received.
==== 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.
* This command does not replace variables like +\{url\}+.
[[save]]
=== save
Syntax: +:save ['what' ['what' ...]]+
@@ -792,6 +958,70 @@ Save configs and state.
* +'what'+: What to save (`config`/`key-config`/`cookies`/...). If not given, everything is saved.
[[scroll]]
=== scroll
Syntax: +:scroll 'direction'+
Scroll the current tab in the given direction.
Note you can use `:run-with-count` to have a keybinding with a bigger scroll increment.
==== positional arguments
* +'direction'+: In which direction to scroll (up/down/left/right/top/bottom).
==== count
multiplier
[[scroll-page]]
=== scroll-page
Syntax: +:scroll-page [*--top-navigate* 'ACTION'] [*--bottom-navigate* 'ACTION'] 'x' 'y'+
Scroll the frame page-wise.
==== positional arguments
* +'x'+: How many pages to scroll to the right.
* +'y'+: How many pages to scroll down.
==== optional arguments
* +*-t*+, +*--top-navigate*+: :navigate action (prev, decrement) to run when scrolling up at the top of the page.
* +*-b*+, +*--bottom-navigate*+: :navigate action (next, increment) to run when scrolling down at the bottom of the page.
==== count
multiplier
[[scroll-px]]
=== scroll-px
Syntax: +:scroll-px 'dx' 'dy'+
Scroll the current tab by 'count * dx/dy' pixels.
==== positional arguments
* +'dx'+: How much to scroll in x-direction.
* +'dy'+: How much to scroll in y-direction.
==== count
multiplier
[[scroll-to-perc]]
=== scroll-to-perc
Syntax: +:scroll-to-perc [*--horizontal*] ['perc']+
Scroll to a specific percentage of the page.
The percentage can be given either as argument or as count. If no percentage is given, the page is scrolled to the end.
==== positional arguments
* +'perc'+: Percentage to scroll.
==== optional arguments
* +*-x*+, +*--horizontal*+: Scroll horizontally instead of vertically.
==== count
Percentage to scroll.
[[search]]
=== search
Syntax: +:search [*--reverse*] ['text']+
@@ -807,6 +1037,20 @@ Search for a text on the current page. With no text, clear results.
==== note
* This command does not split arguments after the last argument and handles quotes literally.
[[search-next]]
=== search-next
Continue the search to the ([count]th) next term.
==== count
How many elements to ignore.
[[search-prev]]
=== search-prev
Continue the search to the ([count]th) previous term.
==== count
How many elements to ignore.
[[session-delete]]
=== session-delete
Syntax: +:session-delete [*--force*] 'name'+
@@ -844,7 +1088,7 @@ Syntax: +:session-save [*--current*] [*--quiet*] [*--force*] [*--only-active-win
Save a session.
==== positional arguments
* +'name'+: The name of the session. If not given, the session configured in session_default_name is saved.
* +'name'+: The name of the session. If not given, the session configured in session.default_name is saved.
==== optional arguments
@@ -891,9 +1135,18 @@ The count if given.
==== note
* This command does not split arguments after the last argument and handles quotes literally.
[[set-mark]]
=== set-mark
Syntax: +:set-mark 'key'+
Set a mark at the current scroll position in the current tab.
==== positional arguments
* +'key'+: mark identifier; capital indicates a global mark
[[spawn]]
=== spawn
Syntax: +:spawn [*--userscript*] [*--verbose*] [*--detach*] 'cmdline'+
Syntax: +:spawn [*--userscript*] [*--verbose*] [*--output*] [*--detach*] 'cmdline'+
Spawn a command in a shell.
@@ -908,6 +1161,7 @@ Spawn a command in a shell.
- `/usr/share/qutebrowser/userscripts`
* +*-v*+, +*--verbose*+: Show notifications when the command started/exited.
* +*-o*+, +*--output*+: Whether the output should be shown in a new tab.
* +*-d*+, +*--detach*+: Whether the command should be detached from qutebrowser.
==== note
@@ -946,10 +1200,6 @@ Close the current/[count]th tab.
==== count
The tab index to close
[[tab-detach]]
=== tab-detach
Detach the current tab to its own window.
[[tab-focus]]
=== tab-focus
Syntax: +:tab-focus ['index']+
@@ -967,6 +1217,17 @@ If neither count nor index are given, it behaves like tab-next. If both are give
==== count
The tab index to focus, starting with 1.
[[tab-give]]
=== tab-give
Syntax: +:tab-give ['win-id']+
Give the current tab to a new or existing window if win_id given.
If no win_id is given, the tab will get detached into a new window.
==== positional arguments
* +'win-id'+: The window ID of the window to give the current tab to.
[[tab-move]]
=== tab-move
Syntax: +:tab-move ['index']+
@@ -1019,6 +1280,16 @@ Switch to the previous tab, or switch [count] tabs back.
==== count
How many tabs to switch back.
[[tab-take]]
=== tab-take
Syntax: +:tab-take 'index'+
Take a tab from another window.
==== positional arguments
* +'index'+: The [win_id/]index of the tab to take. Or a substring in which case the closest match will be taken.
[[unbind]]
=== unbind
Syntax: +:unbind [*--mode* 'mode'] 'key'+
@@ -1034,7 +1305,7 @@ Unbind a keychain.
[[undo]]
=== undo
Re-open a closed tab.
Re-open the last closed tab or tabs.
[[version]]
=== version
@@ -1099,28 +1370,20 @@ Decrease the zoom level for the current tab.
How many steps to zoom out.
== Hidden commands
== Commands not usable in normal mode
.Quick reference
[options="header",width="75%",cols="25%,75%"]
|==============
|Command|Description
|<<clear-keychain,clear-keychain>>|Clear the currently entered key chain.
|<<clear-messages,clear-messages>>|Clear all message notifications.
|<<click-element,click-element>>|Click the element matching the given filter.
|<<command-accept,command-accept>>|Execute the command currently in the commandline.
|<<command-history-next,command-history-next>>|Go forward in the commandline history.
|<<command-history-prev,command-history-prev>>|Go back in the commandline history.
|<<completion-item-del,completion-item-del>>|Delete the current completion item.
|<<completion-item-focus,completion-item-focus>>|Shift the focus of the completion menu to another item.
|<<completion-item-yank,completion-item-yank>>|Yank the current completion item into the clipboard.
|<<drop-selection,drop-selection>>|Drop selection and keep selection mode enabled.
|<<enter-mode,enter-mode>>|Enter a key mode.
|<<follow-hint,follow-hint>>|Follow a hint.
|<<follow-selected,follow-selected>>|Follow the selected text.
|<<jump-mark,jump-mark>>|Jump to the mark named by `key`.
|<<leave-mode,leave-mode>>|Leave the mode we're currently in.
|<<message-error,message-error>>|Show an error message in the statusbar.
|<<message-info,message-info>>|Show an info message in the statusbar.
|<<message-warning,message-warning>>|Show a warning message in the statusbar.
|<<move-to-end-of-document,move-to-end-of-document>>|Move the cursor or selection to the end of the document.
|<<move-to-end-of-line,move-to-end-of-line>>|Move the cursor or selection to the end of line.
|<<move-to-end-of-next-block,move-to-end-of-next-block>>|Move the cursor or selection to the end of next block.
@@ -1136,12 +1399,9 @@ How many steps to zoom out.
|<<move-to-start-of-line,move-to-start-of-line>>|Move the cursor or selection to the start of the line.
|<<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.
|<<nop,nop>>|Do nothing.
|<<open-editor,open-editor>>|Open an external editor with the currently selected form field.
|<<prompt-accept,prompt-accept>>|Accept the current prompt.
|<<prompt-item-focus,prompt-item-focus>>|Shift the focus of the prompt file completion menu to another item.
|<<prompt-open-download,prompt-open-download>>|Immediately open a download.
|<<repeat-command,repeat-command>>|Repeat the last executed command.
|<<rl-backward-char,rl-backward-char>>|Move back a character.
|<<rl-backward-delete-char,rl-backward-delete-char>>|Delete the character before the cursor.
|<<rl-backward-kill-word,rl-backward-kill-word>>|Remove chars from the cursor to the beginning of the word.
@@ -1157,45 +1417,17 @@ How many steps to zoom out.
|<<rl-unix-line-discard,rl-unix-line-discard>>|Remove chars backward from the cursor to the beginning of the line.
|<<rl-unix-word-rubout,rl-unix-word-rubout>>|Remove chars from the cursor to the beginning of the word.
|<<rl-yank,rl-yank>>|Paste the most recently deleted text.
|<<run-with-count,run-with-count>>|Run a command with the given count.
|<<scroll,scroll>>|Scroll the current tab in the given direction.
|<<scroll-page,scroll-page>>|Scroll the frame page-wise.
|<<scroll-px,scroll-px>>|Scroll the current tab by 'count * dx/dy' pixels.
|<<scroll-to-perc,scroll-to-perc>>|Scroll to a specific percentage of the page.
|<<search-next,search-next>>|Continue the search to the ([count]th) next term.
|<<search-prev,search-prev>>|Continue the search to the ([count]th) previous term.
|<<set-mark,set-mark>>|Set a mark at the current scroll position in the current tab.
|<<toggle-selection,toggle-selection>>|Toggle caret selection mode.
|==============
[[clear-keychain]]
=== clear-keychain
Clear the currently entered key chain.
[[clear-messages]]
=== clear-messages
Clear all message notifications.
[[click-element]]
=== click-element
Syntax: +:click-element [*--target* 'target'] [*--force-event*] 'filter' 'value'+
Click the element matching the given filter.
The given filter needs to result in exactly one element, otherwise, an error is shown.
==== positional arguments
* +'filter'+: How to filter the elements. id: Get an element based on its ID.
* +'value'+: The value to filter for.
==== optional arguments
* +*-t*+, +*--target*+: How to open the clicked element (normal/tab/tab-bg/window).
* +*-f*+, +*--force-event*+: Force generating a fake click event.
[[command-accept]]
=== command-accept
Syntax: +:command-accept [*--rapid*]+
Execute the command currently in the commandline.
==== optional arguments
* +*-r*+, +*--rapid*+: Run the command without closing or clearing the command bar.
[[command-history-next]]
=== command-history-next
Go forward in the commandline history.
@@ -1210,26 +1442,29 @@ Delete the current completion item.
[[completion-item-focus]]
=== completion-item-focus
Syntax: +:completion-item-focus 'which'+
Syntax: +:completion-item-focus [*--history*] 'which'+
Shift the focus of the completion menu to another item.
==== positional arguments
* +'which'+: 'next', 'prev', 'next-category', or 'prev-category'.
==== optional arguments
* +*-H*+, +*--history*+: Navigate through command history if no text was typed.
[[completion-item-yank]]
=== completion-item-yank
Syntax: +:completion-item-yank [*--sel*]+
Yank the current completion item into the clipboard.
==== optional arguments
* +*-s*+, +*--sel*+: Use the primary selection instead of the clipboard.
[[drop-selection]]
=== drop-selection
Drop selection and keep selection mode enabled.
[[enter-mode]]
=== enter-mode
Syntax: +:enter-mode 'mode'+
Enter a key mode.
==== positional arguments
* +'mode'+: The mode to enter.
[[follow-hint]]
=== follow-hint
Syntax: +:follow-hint ['keystring']+
@@ -1239,58 +1474,10 @@ Follow a hint.
==== positional arguments
* +'keystring'+: The hint to follow.
[[follow-selected]]
=== follow-selected
Syntax: +:follow-selected [*--tab*]+
Follow the selected text.
==== optional arguments
* +*-t*+, +*--tab*+: Load the selected link in a new tab.
[[jump-mark]]
=== jump-mark
Syntax: +:jump-mark 'key'+
Jump to the mark named by `key`.
==== positional arguments
* +'key'+: mark identifier; capital indicates a global mark
[[leave-mode]]
=== leave-mode
Leave the mode we're currently in.
[[message-error]]
=== message-error
Syntax: +:message-error 'text'+
Show an error message in the statusbar.
==== positional arguments
* +'text'+: The text to show.
[[message-info]]
=== message-info
Syntax: +:message-info 'text'+
Show an info message in the statusbar.
==== positional arguments
* +'text'+: The text to show.
==== count
How many times to show the message
[[message-warning]]
=== message-warning
Syntax: +:message-warning 'text'+
Show a warning message in the statusbar.
==== positional arguments
* +'text'+: The text to show.
[[move-to-end-of-document]]
=== move-to-end-of-document
Move the cursor or selection to the end of the document.
@@ -1384,16 +1571,6 @@ Move the cursor or selection to the start of previous block.
==== count
How many blocks to move.
[[nop]]
=== nop
Do nothing.
[[open-editor]]
=== open-editor
Open an external editor with the currently selected form field.
The editor which should be launched can be configured via the `editor.command` config option.
[[prompt-accept]]
=== prompt-accept
Syntax: +:prompt-accept ['value']+
@@ -1430,13 +1607,6 @@ If no specific command is given, this will use the system's default application
==== note
* This command does not split arguments after the last argument and handles quotes literally.
[[repeat-command]]
=== repeat-command
Repeat the last executed command.
==== count
Which count to pass the command.
[[rl-backward-char]]
=== rl-backward-char
Move back a character.
@@ -1527,113 +1697,6 @@ Paste the most recently deleted text.
This acts like readline's yank.
[[run-with-count]]
=== run-with-count
Syntax: +:run-with-count 'count-arg' 'command'+
Run a command with the given count.
If run_with_count itself is run with a count, it multiplies count_arg.
==== positional arguments
* +'count-arg'+: The count to pass to the command.
* +'command'+: The command to run, with optional args.
==== count
The count that run_with_count itself received.
==== 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.
* This command does not replace variables like +\{url\}+.
[[scroll]]
=== scroll
Syntax: +:scroll 'direction'+
Scroll the current tab in the given direction.
Note you can use `:run-with-count` to have a keybinding with a bigger scroll increment.
==== positional arguments
* +'direction'+: In which direction to scroll (up/down/left/right/top/bottom).
==== count
multiplier
[[scroll-page]]
=== scroll-page
Syntax: +:scroll-page [*--top-navigate* 'ACTION'] [*--bottom-navigate* 'ACTION'] 'x' 'y'+
Scroll the frame page-wise.
==== positional arguments
* +'x'+: How many pages to scroll to the right.
* +'y'+: How many pages to scroll down.
==== optional arguments
* +*-t*+, +*--top-navigate*+: :navigate action (prev, decrement) to run when scrolling up at the top of the page.
* +*-b*+, +*--bottom-navigate*+: :navigate action (next, increment) to run when scrolling down at the bottom of the page.
==== count
multiplier
[[scroll-px]]
=== scroll-px
Syntax: +:scroll-px 'dx' 'dy'+
Scroll the current tab by 'count * dx/dy' pixels.
==== positional arguments
* +'dx'+: How much to scroll in x-direction.
* +'dy'+: How much to scroll in y-direction.
==== count
multiplier
[[scroll-to-perc]]
=== scroll-to-perc
Syntax: +:scroll-to-perc [*--horizontal*] ['perc']+
Scroll to a specific percentage of the page.
The percentage can be given either as argument or as count. If no percentage is given, the page is scrolled to the end.
==== positional arguments
* +'perc'+: Percentage to scroll.
==== optional arguments
* +*-x*+, +*--horizontal*+: Scroll horizontally instead of vertically.
==== count
Percentage to scroll.
[[search-next]]
=== search-next
Continue the search to the ([count]th) next term.
==== count
How many elements to ignore.
[[search-prev]]
=== search-prev
Continue the search to the ([count]th) previous term.
==== count
How many elements to ignore.
[[set-mark]]
=== set-mark
Syntax: +:set-mark 'key'+
Set a mark at the current scroll position in the current tab.
==== positional arguments
* +'key'+: mark identifier; capital indicates a global mark
[[toggle-selection]]
=== toggle-selection
Toggle caret selection mode.
@@ -1737,7 +1800,7 @@ Change the log level for console logging.
[[debug-pyeval]]
=== debug-pyeval
Syntax: +:debug-pyeval [*--quiet*] 's'+
Syntax: +:debug-pyeval [*--file*] [*--quiet*] 's'+
Evaluate a python string and display the results as a web page.
@@ -1745,6 +1808,7 @@ Evaluate a python string and display the results as a web page.
* +'s'+: The string to evaluate.
==== optional arguments
* +*-f*+, +*--file*+: Interpret s as a path to file, also implies --quiet.
* +*-q*+, +*--quiet*+: Don't show the output in a new tab.
==== note

View File

@@ -11,19 +11,29 @@ Migrating older configurations
------------------------------
qutebrowser does no automatic migration for the new configuration. However,
there's a special link:qute://configdiff/old[configdiff] page in qutebrowser,
which will show you the changes you did in your old configuration, compared to
the old defaults.
there's a special link:qute://configdiff/old[configdiff] page
(`qute://configdiff/old`) in qutebrowser, which will show you the changes you
did in your old configuration, compared to the old defaults.
Other changes in default settings:
- `<Up>` and `<Down>` in the completion now navigate through command history
instead of selecting completion items. You can get back the old behavior by
doing:
- In v1.1.x and newer, `<Up>` and `<Down>` navigate through command history
if no text was entered yet.
With v1.0.x, they always navigate through command history instead of selecting
completion items. Use `<Tab>`/`<Shift-Tab>` to cycle through the completion
instead.
You can get back the old behavior by doing:
+
----
:bind -f -m command <Up> completion-item-focus prev
:bind -f -m command <Down> completion-item-focus next
:bind -m command <Up> completion-item-focus prev
:bind -m command <Down> completion-item-focus next
----
+
or always navigate through command history with
+
----
:bind -m command <Up> command-history-prev
:bind -m command <Down> command-history-next
----
- The default for `completion.web_history_max_items` is now set to `-1`, showing
@@ -237,6 +247,9 @@ that via `import utils` as well.
While it's in some cases possible to import code from the qutebrowser
installation, doing so is unsupported and discouraged.
To read config data from a different file with `c` and `config` available, you
can use `config.source('otherfile.py')` in your `config.py`.
Getting the config directory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -251,7 +264,7 @@ get a string:
.config.py:
[source,python]
----
print(str(config.configdir / 'config.py')
print(str(config.configdir / 'config.py'))
----
Handling errors
@@ -346,15 +359,38 @@ def bind_chained(key, *commands):
bind_chained('<Escape>', 'clear-keychain', 'search')
----
Avoiding flake8 errors
^^^^^^^^^^^^^^^^^^^^^^
Reading colors from Xresources
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you use an editor with flake8 integration which complains about `c` and `config` being undefined, you can use:
You can use something like this to read colors from an `~/.Xresources` file:
[source,python]
----
c = c # noqa: F821
config = config # noqa: F821
def read_xresources(prefix):
props = {}
x = subprocess.run(['xrdb', '-query'], stdout=subprocess.PIPE)
lines = x.stdout.decode().split('\n')
for line in filter(lambda l : l.startswith(prefix), lines):
prop, _, value = line.partition(':\t')
props[prop] = value
return props
xresources = read_xresources('*')
c.colors.statusbar.normal.bg = xresources['*background']
----
Avoiding flake8 errors
^^^^^^^^^^^^^^^^^^^^^^
If you use an editor with flake8 and pylint integration, it may have some
complaints about invalid names, undefined variables, or missing docstrings.
You can silence those with:
[source,python]
----
# pylint: disable=C0111
c = c # noqa: F821 pylint: disable=E0602,C0103
config = config # noqa: F821 pylint: disable=E0602,C0103
----
For type annotation support (note that those imports aren't guaranteed to be
@@ -362,8 +398,9 @@ stable across qutebrowser versions):
[source,python]
----
# pylint: disable=C0111
from qutebrowser.config.configfiles import ConfigAPI # noqa: F401
from qutebrowser.config.config import ConfigContainer # noqa: F401
config = config # type: ConfigAPI # noqa: F821
c = c # type: ConfigContainer # noqa: F821
config = config # type: ConfigAPI # noqa: F821 pylint: disable=E0602,C0103
c = c # type: ConfigContainer # noqa: F821 pylint: disable=E0602,C0103
----

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 989 KiB

After

Width:  |  Height:  |  Size: 1024 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -21,7 +21,7 @@ Those distributions only have Python 3.4 and a too old Qt version available,
while qutebrowser requires Python 3.5 and Qt 5.7.1 or newer.
It should be possible to install Python 3.5 e.g. from the
https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa[deadsnakes PPA] or via_ipca
https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa[deadsnakes PPA] or via
https://github.com/pyenv/pyenv[pyenv], but nobody tried that yet.
If you get qutebrowser running on those distributions, please
@@ -35,30 +35,37 @@ Ubuntu 16.04 doesn't come with an up-to-date engine (a new enough QtWebKit, or
QtWebEngine). However, it comes with Python 3.5, so you can
<<tox,install qutebrowser via tox>>.
Debian Stretch / Ubuntu 17.04 and newer
Debian Stretch / Ubuntu 17.04 and 17.10
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Those versions come with QtWebEngine in the repositories. This makes it possible
to install qutebrowser via the Debian package.
Install the dependencies via apt-get:
----
# apt install python-tox python3-{lxml,pyqt5,sip,jinja2,pygments,yaml,attr} python3-pyqt5.qt{webengine,quick,opengl,sql} libqt5sql5-sqlite
----
Get the qutebrowser package from the
https://github.com/qutebrowser/qutebrowser/releases[release page] and download
the https://qutebrowser.org/python3-pypeg2_2.15.2-1_all.deb[PyPEG2 package].
(If you are using debian testing you can just use the python3-pypeg2 package from the repos)
Install the packages:
----
# dpkg -i python3-pypeg2_*_all.deb
# dpkg -i qutebrowser_*_all.deb
# apt install ./python3-pypeg2_*_all.deb
# apt install ./qutebrowser_*_all.deb
----
Some additional hints:
Debian Testing / Ubuntu 18.04
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
On Debian Testing, qutebrowser is in the official repositories, and you can
install it with apt:
----
# apt install qutebrowser
----
Additional hints
~~~~~~~~~~~~~~~~
- Alternatively, you can <<tox,install qutebrowser via tox>> to get a newer
QtWebEngine version.
@@ -66,31 +73,44 @@ Some additional hints:
`:help` command:
+
----
# apt-get install --no-install-recommends asciidoc source-highlight
# apt install --no-install-recommends asciidoc source-highlight
$ python3 scripts/asciidoc2html.py
----
- If you prefer using QtWebKit, there's an up-to-date version available in
Debian experimental, or from http://repo.paretje.be/unstable/[this repository]
for Debian Stretch.
https://packages.debian.org/buster/libqt5webkit5[Debian Testing].
- If video or sound don't work with QtWebKit, try installing the gstreamer plugins:
+
----
# apt-get install gstreamer1.0-plugins-{bad,base,good,ugly}
# apt install gstreamer1.0-plugins-{bad,base,good,ugly}
----
On Fedora
---------
qutebrowser is available in the official repositories for Fedora 22 and newer.
NOTE: Fedora's packages used to be outdated for a long time, but are
now (November 2017) maintained and up-to-date again.
----
qutebrowser is available in the official repositories:
-----
# dnf install qutebrowser
----
-----
It's also recommended to install `python3-qt5-webengine` and start with `--backend
webengine` to use the new backend. v1.0.0 (which is not in the Fedora repos
currently) uses QtWebEngine by default.
However, note that Fedora 25/26 won't be updated to qutebrowser v1.0, so you
might want to <<tox,install qutebrowser via tox>> instead there.
Additional hints
~~~~~~~~~~~~~~~~
Fedora only ships free software in the repositories.
To be able to play videos with proprietary codecs with QtWebEngine, you will
need to install an additional package from the RPM Fusion Free repository.
For more information see https://rpmfusion.org/Configuration.
-----
# dnf install qt5-qtwebengine-freeworld
-----
On Archlinux
------------
@@ -125,14 +145,16 @@ If video or sound don't work with QtWebKit, try installing the gstreamer plugins
On Gentoo
---------
The Gentoo packages (even the live version) are lagging behind a lot and are
effectively unmaintained. If you want to create and maintain an official
qutebrowser overlay for Gentoo, please mailto:mail@qutebrowser.org[get in
touch.]
NOTE: Gentoo's packages used to be severely outdated for a long time, but are
now (October 2017) maintained and up-to-date again.
It's recommended to <<tox,install qutebrowser via tox>> instead.
qutebrowser is available in the main repository and can be installed with:
To get an up-to-date QtWebKit, you can use
----
# emerge -av qutebrowser
----
To use QtWebKit instead of QtWebEngine, you'll need a newer QtWebKit using
https://gist.github.com/annulen/309569fb61e5d64a703c055c1e726f71[this ebuild].
If video or sound don't work with QtWebKit, try installing the gstreamer
@@ -189,6 +211,10 @@ To use the QtWebEngine backend, install `libqt5-qtwebengine`.
On OpenBSD
----------
WARNING: OpenBSD only packages a legacy unmaintained version of QtWebKit (for
which support was dropped in qutebrowser v1.0). It's advised to not use
qutebrowser from OpenBSD ports for untrusted websites.
qutebrowser is in http://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/www/qutebrowser/[OpenBSD ports].
Install the package:
@@ -204,6 +230,21 @@ Or alternatively, use the ports system :
# make install
----
On FreeBSD
----------
qutebrowser is in https://www.freshports.org/www/qutebrowser/[FreeBSD ports].
It can be installed with:
----
# cd /usr/ports/www/qutebrowser
# make install clean
----
At present, precompiled packages are not available for this port,
and QtWebEngine backend is also not available.
On Windows
----------
@@ -221,6 +262,10 @@ https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser-announce[qutebrows
mailinglist] to get notified on new releases). You can install a newer version
without uninstalling the older one.
The binary release ships with a QtWebEngine built without proprietary codec
support. To get support for e.g. h264/h265 videos, you'll need to build
QtWebEngine from source yourself with support for that enabled.
https://chocolatey.org/packages/qutebrowser[Chocolatey package]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -261,6 +306,10 @@ Note that you'll need to upgrade to new versions manually (subscribe to the
https://lists.schokokeks.org/mailman/listinfo.cgi/qutebrowser-announce[qutebrowser-announce
mailinglist] to get notified on new releases).
The binary release ships with a QtWebEngine built without proprietary codec
support. To get support for e.g. h264/h265 videos, you'll need to build
QtWebEngine from source yourself with support for that enabled.
This binary is also available through the
https://caskroom.github.io/[Homebrew Cask] package manager:
@@ -352,20 +401,35 @@ local Qt install instead of installing PyQt in the virtualenv. However, unless
you have a new QtWebKit or QtWebEngine available, qutebrowser will not work. It
also typically means you'll be using an older release of QtWebEngine.
On Windows, run `tox -e 'mkvenv-win' instead, however make sure that ONLY
Python3 is in your PATH before running tox.
On Windows, run `set PYTHON=C:\path\to\python.exe` (CMD) or ``$Env:PYTHON =
"..."` (Powershell) first.
Creating a wrapper script
~~~~~~~~~~~~~~~~~~~~~~~~~
You can then create a simple wrapper script to start qutebrowser somewhere in
your `$PATH` (e.g. `/usr/local/bin/qutebrowser` or `~/bin/qutebrowser`):
Running `tox` does not install a system-wide `qutebrowser` script. You can
launch qutebrowser by doing `.venv/bin/python3 -m qutebrowser`.
You can create a simple wrapper script to start qutebrowser somewhere in your
`$PATH` (e.g. `/usr/local/bin/qutebrowser` or `~/bin/qutebrowser`):
----
#!/bin/bash
~/path/to/qutebrowser/.venv/bin/python3 -m qutebrowser "$@"
----
Building the docs
~~~~~~~~~~~~~~~~~
To build the documentation, install `asciidoc` (note that LaTeX which comes as
optional/recommended dependency with some distributions is not required).
Then, run:
----
$ python3 scripts/asciidoc2html.py
----
Updating
~~~~~~~~

View File

@@ -22,9 +22,9 @@ Basic keybindings to get you started
What to do now
--------------
* View the link:http://qutebrowser.org/img/cheatsheet-big.png[key binding cheatsheet]
* View the link:https://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"]
image:https://qutebrowser.org/img/cheatsheet-small.png["qutebrowser key binding cheatsheet",link="https://qutebrowser.org/img/cheatsheet-big.png"]
* There's also a https://www.shortcutfoo.com/app/dojos/qutebrowser[free training
course] on shortcutfoo for the keybindings - note that you need to be in
insert mode (i) for it to work.

View File

@@ -57,7 +57,7 @@ Then edit your `/etc/pacman.conf` to add the repository to the bottom:
----
[qt-debug]
Server = http://qutebrowser.org/qt-debug/$arch
Server = https://qutebrowser.org/qt-debug/$arch
----
Then install the packages:

View File

@@ -31,7 +31,7 @@ The following environment variables will be set when a userscript is launched:
- `QUTE_MODE`: Either `hints` (started via hints) or `command` (started via
command or key binding).
- `QUTE_USER_AGENT`: The currently set user agent.
- `QUTE_USER_AGENT`: The currently set user agent, if customized.
- `QUTE_FIFO`: The FIFO or file to write commands to.
- `QUTE_HTML`: Path of a file containing the HTML source of the current page.
- `QUTE_TEXT`: Path of a file containing the plaintext of the current page.

View File

@@ -1,207 +1,302 @@
/* XPM */
static char *qutebrowser[] = {
/* columns rows colors chars-per-pixel */
"32 32 169 2 ",
" c #0A396E",
". c #0B3C72",
"X c #0B4077",
"o c #0C437B",
"O c #134175",
"+ c #15467C",
"@ c #18477B",
"# c #1A497D",
"$ c #0D4B86",
"% c #0F4E8D",
"& c #124A80",
"* c #1F4F83",
"= c #0E518C",
"- c #1F5084",
"; c #11508C",
": c #0F5193",
"> c #115799",
", c #115B9C",
"< c #204F83",
"1 c #245287",
"2 c #2A598C",
"3 c #325E8F",
"4 c #11609F",
"5 c #346496",
"6 c #3B6898",
"7 c #115CA1",
"8 c #115EAC",
"9 c #1263A3",
"0 c #1260AD",
"q c #136BAC",
"w c #136BB2",
"e c #1366BA",
"r c #196BB2",
"t c #157ABB",
"y c #1577BB",
"u c #2E6DB0",
"i c #387FB1",
"p c #456E9A",
"a c #4873A1",
"s c #4375AA",
"d c #507AA6",
"f c #597EA4",
"g c #4D7EB3",
"h c #156FCB",
"j c #167AC5",
"k c #1675CA",
"l c #177BCE",
"z c #1777D8",
"x c #1476E4",
"c c #167BE6",
"v c #167DE8",
"b c #197EEF",
"n c #1A7FF0",
"m c #1A80BE",
"M c #5F87AF",
"N c #5D8BBA",
"B c #5A84B1",
"V c #6C8FB3",
"C c #6F96BE",
"Z c #1886CC",
"A c #1883D7",
"S c #198DD5",
"D c #1987D9",
"F c #198ADC",
"G c #1A96DC",
"H c #3090D9",
"J c #1682E9",
"K c #1983ED",
"L c #1689E9",
"P c #1A8DEE",
"I c #1B95ED",
"U c #1C9EEA",
"Y c #1B97E4",
"T c #1A84F2",
"R c #1A8BF2",
"E c #1C94F4",
"W c #1D9CF5",
"Q c #3388E6",
"! c #3D90E9",
"~ c #228EF3",
"^ c #229FF6",
"/ c #3294F4",
"( c #3D9FF6",
") c #339CF4",
"_ c #1CA2E5",
"` c #1DABEE",
"' c #1DA4F6",
"] c #1EA9F7",
"[ c #1EADF8",
"{ c #1FB4F9",
"} c #1FB9FA",
"| c #20ACF8",
" . c #27A4F6",
".. c #3DA9F6",
"X. c #20B9FA",
"o. c #2EB6F9",
"O. c #458DC9",
"+. c #5C8DC1",
"@. c #5795C6",
"#. c #709DCB",
"$. c #74A8DD",
"%. c #4A97EA",
"&. c #4896EA",
"*. c #559EEA",
"=. c #439AF5",
"-. c #46A3F6",
";. c #5FA9F6",
":. c #5EA6F3",
">. c #47BCF9",
",. c #51B5F8",
"<. c #58BDF8",
"1. c #68ABEF",
"2. c #7DB9E7",
"3. c #63AEF7",
"4. c #6FB1F7",
"5. c #66B9F8",
"6. c #61B2F6",
"7. c #71B4F7",
"8. c #78B7F4",
"9. c #72BFF9",
"0. c #3BC0FA",
"q. c #6FCEFB",
"w. c #6CC5FA",
"e. c #7BCAF9",
"r. c #89A7C3",
"t. c #83A2C1",
"y. c #98B6D3",
"u. c #9DB9D3",
"i. c #89B6E4",
"p. c #83B6E9",
"a. c #81BDF7",
"s. c #83BFF8",
"d. c #9EC4E9",
"f. c #8CC2F9",
"g. c #85CDFB",
"h. c #87C4F9",
"j. c #92C6F9",
"k. c #95CAFA",
"l. c #9CCBFA",
"z. c #89D7FC",
"x. c #91D9FC",
"c. c #9CDEFD",
"v. c #9ED2FB",
"b. c #A7CAEC",
"n. c #B5CEE3",
"m. c #A1CEFA",
"M. c #AED0F0",
"N. c #ACD6FA",
"B. c #A0DFFC",
"V. c #AFD8FC",
"C. c #B5D9FB",
"Z. c #BCDDFC",
"A. c #BFDCF5",
"S. c #ACE3FD",
"D. c #B5E5FE",
"F. c #BBE2FC",
"G. c #CFE5F5",
"H. c #C3E1FC",
"J. c #CAE6FD",
"K. c #CCEBFD",
"L. c #C4EBFE",
"P. c #D6EDFE",
"I. c #DAEEFD",
"U. c #DEF1FE",
"Y. c #D6F2FE",
"T. c #E4F4FE",
"R. c #E9F6FE",
"E. c #EBF8FF",
"W. c None",
/* pixels */
"W.W.W.W.W.W.W.W.W.W.W.c.S.L.Y.E.E.S.X.} W.W.W.W.W.W.W.W.W.W.W.W.",
"W.W.W.W.W.W.W.W.W.D.T.E.E.T.L.D.c.z.} } X.} } W.W.W.W.W.W.W.W.W.",
"W.W.W.W.W.W.W.B.T.T.R.T.R.U.0.X.z.S.} } } } { { X.W.W.W.W.W.W.W.",
"W.W.W.W.W.W.x.x.K.T.T.T.L.P.q.o.{ } } ` _ { { { { { W.W.W.W.W.W.",
"W.W.W.W.W.c.P.D.G.u.r.i 9 Z _ { { G 4 X t { { { { { { W.W.W.W.W.",
"W.W.W.W.K.U.n.f O { = t { { { { [ { { W.W.W.W.",
"W.W.W.F.I.t.. ' t { { [ [ [ [ [ >.W.W.W.",
"W.W.x.P.V ' X t ` [ [ [ [ [ [ o.e.W.W.",
"W.W.J.y. X t S Y Z $ ' . y [ [ [ ] [ [ | Z.J.W.W.",
"W.<.e.& , _ ] ] [ ] U . ' . y [ ' [ ] ] ] w.K.J.g.W.",
"W.' S o ' ' [ ' [ ' ] o ' . y Y 9 = = 9 @.J.J.J.F.W.",
"W.| , j ' ' ' ' ' ' ' o ' . $ p A.J.J.g.",
"' .. G ' ' ' ' ' ' ' o ' . M H.H.h.",
",.2. . W ' W ' ' ' ' W . ' . M.A.x.",
"N.M.. . W W W ' W W W W .w 9 I U 0 #.Z.m.",
" .9.O D W W W W ' W j $ % F W W W .5 d Z.C.",
"W W ; 9 9.h.5...Q % o j W W W W W W O. 3 C.N.",
"E W 7 B b.d.a . w E E W W W E W E A @ C.l.",
"I E l u W E W E W E E E E A . - k.6.",
"P E E 7 m.o E E E E E E E E l . = E P ",
"L E E E > . O s.o E E E E E E E E 7 , E L ",
"W.R E R ) #.5 1 6 N i.2 s.+ E E E E E E R L . k R W.",
"W.L R E -.m.m.m.m.m.m.2 m.@ N m.m.s.( R R % X E J W.",
"W.W.K R ~ a.m.l.l.l.l.2 s.+ < i.l.m.j.h % e K W.W.",
"W.W.J R R / l.l.l.l.k.2 s.+ * 5 + 8 R J W.W.",
"W.W.W.v T R 3.k.k.j.k.2 2 j.& . 8 R v W.W.W.",
"W.W.W.W.J T ~ 7.j.j.j.g +.p.j.s.+. . . : z T v W.W.W.W.",
"W.W.W.W.W.c T T =.f.j.j.s.j.j.j.j.$.g s u e h b T T v W.W.W.W.W.",
"W.W.W.W.W.W.c b n 4.f.f.s.m.s.s.s.j.s.j./ T n T b c W.W.W.W.W.W.",
"W.W.W.W.W.W.W.c x 1.s.s.s.s.s.s.s.s.4.=.n T n c c W.W.W.W.W.W.W.",
"W.W.W.W.W.W.W.W.W.&.*.1.a.s.s.s.s.3.n n v x x W.W.W.W.W.W.W.W.W.",
"W.W.W.W.W.W.W.W.W.W.W.%.%.%.%.*.*.Q x x x W.W.W.W.W.W.W.W.W.W.W."
};
static char * qutebrowser_xpm[] = {
"32 32 267 2",
" c None",
". c #9FD4FD",
"+ c #99CBFE",
"@ c #90C3FE",
"# c #89BFFE",
"$ c #81BCFF",
"% c #80BBFF",
"& c #9BCAFD",
"* c #A9DBFB",
"= c #88D3FB",
"- c #98CBFE",
"; c #81BBFF",
"> c #7EBAFF",
", c #84BDFF",
"' c #8DC2FF",
") c #96C7FE",
"! c #A0CCFE",
"~ c #A9D1FE",
"{ c #CEE5FD",
"] c #C7E3FC",
"^ c #8AD3FB",
"/ c #9DCFFD",
"( c #C3DFFD",
"_ c #CDE4FD",
": c #A3CEFE",
"< c #94C6FE",
"[ c #CAE5FC",
"} c #7DD0FB",
"| c #9ECDFD",
"1 c #A1CDFE",
"2 c #8BC1FF",
"3 c #87BFFF",
"4 c #ADD4FE",
"5 c #C6E1FD",
"6 c #CCE3FC",
"7 c #A7DAFB",
"8 c #9DCBFE",
"9 c #78AFF1",
"0 c #6096D4",
"a c #4B82C0",
"b c #5A84B3",
"c c #6589B1",
"d c #6F92B9",
"e c #90AED0",
"f c #C4DBF5",
"g c #6286AE",
"h c #7D9EC2",
"i c #BADFFC",
"j c #85BDFE",
"k c #78B4F8",
"l c #4C83C0",
"m c #1E4F87",
"n c #0A396E",
"o c #345D8D",
"p c #CDE4FC",
"q c #88A7CA",
"r c #1D497C",
"s c #799BBF",
"t c #8AC1FD",
"u c #5E97D7",
"v c #14457B",
"w c #4F76A0",
"x c #A9D5FC",
"y c #95C9FD",
"z c #4C82C1",
"A c #0A3A6F",
"B c #C9E3FD",
"C c #95CCFC",
"D c #629BDB",
"E c #0B3A6F",
"F c #0C3B6F",
"G c #4E749F",
"H c #8CACCE",
"I c #6185AD",
"J c #CBE4FD",
"K c #89C0FF",
"L c #98CDFA",
"M c #27558A",
"N c #144175",
"O c #9BB8D8",
"P c #335D8C",
"Q c #AFC9E6",
"R c #AFD4FE",
"S c #91C7FD",
"T c #A0C0DE",
"U c #194779",
"V c #80A1C5",
"W c #C8E1F9",
"X c #9CB9D8",
"Y c #7799BE",
"Z c #6489B0",
"` c #7092B9",
" . c #6E9DCF",
".. c #79B5F9",
"+. c #83BDFE",
"@. c #7395BA",
"#. c #315C8B",
"$. c #7C9EC2",
"%. c #C0D9F3",
"&. c #7294BA",
"*. c #5C94D4",
"=. c #91CCFC",
"-. c #88CBFA",
";. c #5179A3",
">. c #6E91B7",
",. c #6084AC",
"'. c #96B3D4",
"). c #275283",
"!. c #0C3C71",
"~. c #629CDC",
"{. c #94C6FD",
"]. c #A7D2FC",
"^. c #36659A",
"/. c #2C5788",
"(. c #9DBAD9",
"_. c #B4CEEA",
":. c #476E9A",
"<. c #7EB9FE",
"[. c #8DC3FD",
"}. c #8CC2FE",
"|. c #2F619B",
"1. c #87A6C9",
"2. c #7A9BC0",
"3. c #CBE2FB",
"4. c #C7DFF8",
"5. c #6C8FB5",
"6. c #113F73",
"7. c #0F3D71",
"8. c #547AA4",
"9. c #9CBAD9",
"0. c #B9D3EE",
"a. c #A3C0DE",
"b. c #31629A",
"c. c #659EE0",
"d. c #87BFFE",
"e. c #C3E0FD",
"f. c #4371A4",
"g. c #7496BB",
"h. c #90AFD1",
"i. c #245081",
"j. c #416A96",
"k. c #B0CBE7",
"l. c #CCE4FD",
"m. c #7DB8FD",
"n. c #1E5088",
"o. c #497EBC",
"p. c #C9E3FC",
"q. c #7193B9",
"r. c #C6E0FB",
"s. c #A2CDFE",
"t. c #97C8FE",
"u. c #A7D0FE",
"v. c #BDDCFD",
"w. c #9EC2E8",
"x. c #416996",
"y. c #366AA6",
"z. c #C0DEFC",
"A. c #A2BFDD",
"B. c #326299",
"C. c #649DDF",
"D. c #71ABED",
"E. c #3569A4",
"F. c #0D3C71",
"G. c #6998CD",
"H. c #30639D",
"I. c #A8D3F8",
"J. c #2B5686",
"K. c #3A679B",
"L. c #ADCAEA",
"M. c #85A6C9",
"N. c #33639B",
"O. c #9CCBFD",
"P. c #86C2F7",
"Q. c #0E3C71",
"R. c #1B4C83",
"S. c #5D95D5",
"T. c #557BA5",
"U. c #85C0F6",
"V. c #55A8EF",
"W. c #94B3D3",
"X. c #1C497C",
"Y. c #13437A",
"Z. c #487DBB",
"`. c #7BB7FB",
" + c #76B1F5",
".+ c #4E85C3",
"++ c #ACD3FE",
"@+ c #2F5989",
"#+ c #7597BC",
"$+ c #53A7EF",
"%+ c #C6E1FC",
"&+ c #B6D5F7",
"*+ c #5890D0",
"=+ c #4076B2",
"-+ c #619ADB",
";+ c #7CB7FC",
">+ c #7DB9FE",
",+ c #5087C6",
"'+ c #134479",
")+ c #23548D",
"!+ c #24558D",
"~+ c #8AAACC",
"{+ c #A2C1E1",
"]+ c #86C1F5",
"^+ c #B4D7FE",
"/+ c #6CA5E8",
"(+ c #22548C",
"_+ c #6D94BF",
":+ c #98B6D6",
"<+ c #134174",
"[+ c #84BDF5",
"}+ c #CAE4FC",
"|+ c #CBE3FD",
"1+ c #8FC3FF",
"2+ c #3F72AD",
"3+ c #49719C",
"4+ c #0C3B70",
"5+ c #9CBBDB",
"6+ c #79B7F3",
"7+ c #BFDCFD",
"8+ c #7FBBFF",
"9+ c #7E9FC3",
"0+ c #77B6F3",
"a+ c #A5CEF7",
"b+ c #9FCBFE",
"c+ c #3267A1",
"d+ c #A4CDF7",
"e+ c #B9D9FA",
"f+ c #C7E1FD",
"g+ c #90C3FF",
"h+ c #15457C",
"i+ c #558CCB",
"j+ c #2E5889",
"k+ c #7B9CC1",
"l+ c #C4DDF6",
"m+ c #BBDAFA",
"n+ c #CDE5FD",
"o+ c #B3D6FE",
"p+ c #80BAFF",
"q+ c #4E84C3",
"r+ c #3E73AF",
"s+ c #78B3F7",
"t+ c #5991D1",
"u+ c #477DBA",
"v+ c #4075B2",
"w+ c #5783B6",
"x+ c #BDD6F0",
"y+ c #A1CBF6",
"z+ c #90C4FF",
"A+ c #BCDBFD",
"B+ c #73B0F1",
"C+ c #C5E0FB",
"D+ c #91C5FF",
"E+ c #AED3FE",
"F+ c #C9E2FC",
"G+ c #76B2F2",
"H+ c #8BBFF9",
"I+ c #81BBFE",
"J+ c #9ECBFE",
"K+ c #84B8F3",
"L+ c #79B4F4",
"M+ c #88BEFA",
"N+ c #83BCFE",
"O+ c #A4CFFC",
"P+ c #A6CDF6",
"Q+ c #82B8F2",
"R+ c #529BEC",
" . + @ # $ % & * = ",
" - ; > > , ' ) ! ~ { { { ] ^ ",
" / ; > > > > ; ( _ : < { { { { { [ } ",
" | 1 2 > > > 2 3 4 5 { { { { { 6 { { { 7 ",
" 8 $ < 9 0 a b c d e { { { { f g h { { { { i ",
" j k l m n n n n n n o { { p q r n s { { { { { i ",
" t u v n n n n n n n n o { { w n n n s { { { { { { x ",
" y z A n n n n n n n n n o { { o n n n s { { { { { { B C ",
" D E n n n F G H I n n n o { { o n n n s { { { { { J K % ",
" L M n n n N O { { s n n n o { { o n n P Q { { { { { R > > S ",
" T n n n n H { { { s n n n o { { o U V 6 W X Y Z ` ...> > +. ",
" @.n n n #.{ { { { s n n n o { { $.%.W &.U n n n n n v *.> > =.",
"-.;.n n n >.{ { { { s n n n ,.{ { { '.).n n n n n n n n !.~.> {.",
"].^.n n n q { { { { s n /.(.{ { _.:.n n n n n n n n n n n m <.[.",
"}.|.n n n H { { { { 1.2.3.{ 4.5.6.n n n 7.8.9.0.a.b.n n n n c.d.",
"e.f.n n n g.{ { { { { { { h.i.n n n n j.k.{ { { l.m.n.n n n o.$ ",
"p.q.n n n /.r.s.t.u.v.w.x.n n n n i.h.{ { { { { { u.o.n n n y.$ ",
"z.A.n n n n B.C.D.u E.F.n n n 6.5.4.{ 3.2.1.{ { { { G.n n n H.d.",
"I.p J.n n n n n n n n n n n K.L.{ { (./.n s { { { { M.n n n N.O.",
"P.{ (.Q.n n n n n n n n R.S.> K _ ,.n n n s { { { { 5.n n n T.U.",
"V.{ { W.X.n n n n n Y.Z.`. +.+> ++o n n n s { { { { @+n n n #+$+",
" %+{ { &+*+Z.=+a -+;+>+,+'+)+> > !+n n n s { { { ~+n n n n {+ ",
" ]+{ { ^+> > > > > /+(+n n )+> > )+n n n _+{ { :+<+n n n o [+ ",
" }+{ |+1+> > > > l n n n )+> > )+n n n 2+~+3+E n n n 4+5+ ",
" 6+{ { 7+8+> > > l n n n )+> > )+n n n n n n n n n F 9+0+ ",
" a+{ { b+> > > l n n n c+> > )+n n n n n n n n r O d+ ",
" e+{ f+g+> > l n h+i+<.> > )+n n n n n E j+k+l+m+ ",
" e+{ n+o+p+q+r+s+> > > > t+u+v+w+2.W.x+{ { e+ ",
" y+{ { z+>+> > > > > > > > > A+{ { { { d+ ",
" B+C+) > > > > > > > > D+E+{ { { F+G+ ",
" H+I+> > > > > > J+{ { { C+K+ ",
" L+M+# N+; 8+O+P+Q+R+ "};

25
misc/Makefile Normal file
View File

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

View File

@@ -13,7 +13,7 @@
height="682.66669"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.92.1 r"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
version="1.0"
sodipodi:docname="cheatsheet.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
@@ -32,21 +32,21 @@
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.7582312"
inkscape:cx="513.85167"
inkscape:cy="273.37342"
inkscape:zoom="1.24"
inkscape:cx="305.29152"
inkscape:cy="465.48793"
inkscape:document-units="px"
inkscape:current-layer="layer1"
width="1024px"
height="640px"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1440"
inkscape:window-width="1024"
inkscape:window-height="723"
inkscape:window-x="0"
inkscape:window-y="0"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-maximized="0"
inkscape:window-maximized="1"
inkscape:snap-text-baseline="true">
<inkscape:grid
id="GridFromPre046Settings"
@@ -84,9 +84,9 @@
height="64"
width="74.666664"
id="rect3328"
style="font-size:18px;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1.06666672" />
style="font-size:18px;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.06666672" />
<rect
style="font-size:18px;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1.06666672"
style="font-size:18px;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.06666672"
id="rect3330"
width="64"
height="64"
@@ -715,7 +715,7 @@
height="64"
width="63.461262"
id="rect3720"
style="font-size:18px;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1.06666672" />
style="font-size:18px;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.06666672" />
<path
id="path3724"
d="m 854.35172,271.52738 c 21.26539,0 42.53077,0 63.79615,0"
@@ -985,7 +985,7 @@
<g
id="g7167"
transform="translate(74.666662,16.594076)"
style="fill:#babdb6;fill-opacity:1">
style="fill:#eeeeec;fill-opacity:1">
<rect
ry="4.7797003"
y="296.53333"
@@ -993,9 +993,9 @@
height="64"
width="63.461262"
id="rect7169"
style="font-size:18px;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1.06666672" />
style="font-size:18px;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.06666672" />
<rect
style="font-size:18px;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1.06666672"
style="font-size:18px;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.06666672"
id="rect7171"
width="63.461262"
height="32"
@@ -1005,7 +1005,7 @@
<path
id="path7173"
d="m 640.14582,329.06667 c 21.0911,0 42.18218,0 63.27327,0"
style="font-size:18px;fill:#babdb6;fill-opacity:1;stroke:#000000;stroke-width:1.16182172px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
style="font-size:18px;fill:#eeeeec;fill-opacity:1;stroke:#000000;stroke-width:1.16182172px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:connector-curvature="0" />
</g>
<text
@@ -1303,7 +1303,7 @@
height="64"
width="63.461262"
id="rect3980"
style="font-size:18px;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1.06666672" />
style="font-size:18px;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.06666672" />
<path
id="path3982"
d="m 11.247578,121.66071 c 21.091093,0 42.182176,0 63.273269,0"
@@ -2475,21 +2475,21 @@
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">prev</tspan></text>
<text
id="text9514-60-8"
y="357.28558"
y="355.28558"
x="588.79791"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:TlwgTypewriter;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
xml:space="preserve"><tspan
y="357.28558"
y="355.28558"
x="588.79791"
sodipodi:role="line"
id="tspan5524"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">save</tspan><tspan
y="364.96558"
y="362.96558"
x="588.79791"
sodipodi:role="line"
id="tspan5530"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">quick-</tspan><tspan
y="372.64557"
y="370.64557"
x="588.79791"
sodipodi:role="line"
id="tspan5532"
@@ -3039,6 +3039,8 @@
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara3792">;I - hint images in new tab</flowPara><flowPara
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara6096">;t - hint inputs</flowPara><flowPara
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara3794">;o - put hinted URL in cmd. line</flowPara><flowPara
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara3796">;O - like <flowSpan
@@ -3188,7 +3190,9 @@
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara4148">&lt;Ctrl-P&gt; - prev. history item</flowPara><flowPara
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara3935-9">&lt;Ctrl-N&gt; - next history item</flowPara></flowRoot> <rect
id="flowPara3935-9">&lt;Ctrl-N&gt; - next history item</flowPara><flowPara
style="font-size:10.66666698px;line-height:1.25;font-family:sans-serif;fill:#000000;stroke-width:1.06666672"
id="flowPara6189">&lt;Ctrl-D&gt; - delete current item</flowPara></flowRoot> <rect
style="font-size:18px;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1.06666672"
id="rect3764-9"
width="64"
@@ -3440,7 +3444,8 @@
<flowRoot
xml:space="preserve"
id="flowRoot5691-4-9-3-6-6"
style="font-style:normal;font-weight:normal;font-size:12.80000019px;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"><flowRegion
style="font-style:normal;font-weight:normal;font-size:12.80000019px;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
transform="translate(0,10)"><flowRegion
id="flowRegion5693-9-1-7-3-8"
style="font-family:sans-serif;stroke-width:1.06666672"><rect
id="rect5695-9-8-7-7-6"
@@ -3498,5 +3503,162 @@
sodipodi:role="line"
id="tspan4112"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">mode</tspan></text>
<text
id="text10564-5"
y="274.2934"
x="873.4303"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:TlwgTypewriter;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
xml:space="preserve"><tspan
y="274.2934"
x="873.4303"
sodipodi:role="line"
id="tspan10566-6"
style="font-size:9.60000038px;line-height:0.89999998;stroke-width:1.06666672"> </tspan><tspan
id="tspan10570-91"
y="282.1763"
x="873.4303"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">jump to</tspan><tspan
y="289.85632"
x="873.4303"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6066">scroll</tspan><tspan
y="297.53632"
x="873.4303"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6068">mark</tspan></text>
<text
id="text10564-2"
y="362.50635"
x="731.82947"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:TlwgTypewriter;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
xml:space="preserve"><tspan
id="tspan10568-0"
y="362.50635"
x="731.82947"
sodipodi:role="line"
style="font-size:9.60000038px;line-height:0.89999998;stroke-width:1.06666672">repeat</tspan><tspan
id="tspan10570-93"
y="370.38925"
x="731.82947"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">cmd</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:TlwgTypewriter;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
x="183.06667"
y="97.639633"
id="text7245-1-6"><tspan
sodipodi:role="line"
x="183.06667"
y="97.639633"
id="tspan7366-3-0"
style="font-size:9.60000038px;line-height:0.89999998;stroke-width:1.06666672"> </tspan><tspan
sodipodi:role="line"
x="183.06667"
y="105.52255"
id="tspan7249-4-6"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">run</tspan><tspan
sodipodi:role="line"
x="183.06667"
y="113.20255"
id="tspan5293-2"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">macro</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:TlwgTypewriter;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
x="117.44301"
y="203.05061"
id="text7245-1-61"><tspan
sodipodi:role="line"
x="117.44301"
y="203.05061"
id="tspan7366-3-8"
style="font-size:9.60000038px;line-height:0.89999998;stroke-width:1.06666672"> </tspan><tspan
sodipodi:role="line"
x="117.44301"
y="210.93353"
id="tspan5293-9"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">record</tspan><tspan
sodipodi:role="line"
x="117.44301"
y="218.61353"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6136">macro</tspan></text>
<text
id="text10564-5-2"
y="125.17836"
x="37.344757"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:TlwgTypewriter;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
xml:space="preserve"><tspan
y="125.17836"
x="37.344757"
sodipodi:role="line"
id="tspan10566-6-0"
style="font-size:9.60000038px;line-height:0.89999998;stroke-width:1.06666672"> </tspan><tspan
id="tspan10570-91-2"
y="133.06128"
x="37.344757"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">set</tspan><tspan
y="140.74127"
x="37.344757"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6066-3">scroll</tspan><tspan
y="148.42128"
x="37.344757"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6068-7">mark</tspan></text>
<text
id="text9514-60-8-5"
y="323.89648"
x="590.26257"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:TlwgTypewriter;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
xml:space="preserve"><tspan
y="323.89648"
x="590.26257"
sodipodi:role="line"
id="tspan5524-9"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">save</tspan><tspan
y="331.57648"
x="590.26257"
sodipodi:role="line"
id="tspan5530-2"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">book-</tspan><tspan
y="339.25647"
x="590.26257"
sodipodi:role="line"
id="tspan5532-2"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">mark</tspan></text>
<text
id="text10564-5-2-8"
y="200.40416"
x="21.280243"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:12.80000019px;line-height:0%;font-family:TlwgTypewriter;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
xml:space="preserve"><tspan
y="200.40416"
x="21.280243"
sodipodi:role="line"
id="tspan10566-6-0-9"
style="font-size:9.60000038px;line-height:0.89999998;stroke-width:1.06666672"> </tspan><tspan
id="tspan10570-91-2-7"
y="208.28708"
x="21.280243"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672">cycle</tspan><tspan
y="215.96707"
x="21.280243"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6068-7-6">completion</tspan><tspan
y="223.64708"
x="21.280243"
sodipodi:role="line"
style="font-size:8.53333378px;line-height:0.89999998;stroke-width:1.06666672"
id="tspan6220">items</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2017 suve <veg@svgames.pl> -->
<component type="desktop">
<id>org.qutebrowser.qutebrowser</id>
<metadata_license>CC-BY-SA-3.0</metadata_license>
<project_license>GPL-3.0</project_license>
<name>qutebrowser</name>
<summary>A keyboard-driven web browser</summary>
<description>
<p>
qutebrowser is a keyboard-focused browser with a minimal GUI.
It was inspired by other browsers/addons like dwb and Vimperator/Pentadactyl,
and is based on Python and PyQt5.
</p>
</description>
<categories>
<category>Network</category>
<category>WebBrowser</category>
</categories>
<provides>
<binary>qutebrowser</binary>
</provides>
<launchable type="desktop-id">qutebrowser.desktop</launchable>
<screenshots>
<screenshot type="default">
<image>https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/main.png</image>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/downloads.png</image>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/completion.png</image>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/qutebrowser/qutebrowser/master/doc/img/hints.png</image>
</screenshot>
</screenshots>
<url type="homepage">https://www.qutebrowser.org</url>
<url type="faq">https://qutebrowser.org/doc/faq.html</url>
<url type="help">https://qutebrowser.org/doc/help/</url>
<url type="bugtracker">https://github.com/qutebrowser/qutebrowser/issues/</url>
<url type="donation">https://github.com/qutebrowser/qutebrowser#donating</url>
</component>

View File

@@ -7,5 +7,5 @@ Categories=Network;WebBrowser;
Exec=qutebrowser %u
Terminal=false
StartupNotify=false
MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;
MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/qute;
Keywords=Browser

View File

@@ -1,5 +1,5 @@
This directory contains various `requirements` files which are used by `tox` to
have reproducable tests with pinned versions.
have reproducible tests with pinned versions.
The files are generated based on unpinned requirements in `*.txt-raw` files.

View File

@@ -1,3 +1,3 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
check-manifest==0.35
check-manifest==0.36

View File

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

View File

@@ -1,23 +1,25 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
flake8==2.6.2 # rq.filter: < 3.0.0
attrs==17.4.0
flake8==3.5.0
flake8-bugbear==17.12.0
flake8-builtins==1.0.post0
flake8-comprehensions==1.4.1
flake8-copyright==0.2.0
flake8-debugger==1.4.0 # rq.filter: != 2.0.0
flake8-deprecated==1.2.1
flake8-docstrings==1.0.3 # rq.filter: < 1.1.0
flake8-future-import==0.4.3
flake8-debugger==3.0.0
flake8-deprecated==1.3
flake8-docstrings==1.3.0
flake8-future-import==0.4.4
flake8-mock==0.3
flake8-pep3101==1.0 # rq.filter: < 1.1
flake8-polyfill==1.0.1
flake8-putty==0.4.0
flake8-per-file-ignores==0.4
flake8-polyfill==1.0.2
flake8-string-format==0.2.3
flake8-tidy-imports==1.1.0
flake8-tuple==0.2.13
mccabe==0.6.1
packaging==16.8
pep8-naming==0.4.1
pep8-naming==0.5.0
pycodestyle==2.3.1
pydocstyle==1.1.1 # rq.filter: < 2.0.0
pydocstyle==2.1.1
pyflakes==1.6.0
pyparsing==2.2.0
six==1.11.0
snowballstemmer==1.2.1

View File

@@ -1,29 +1,17 @@
flake8<3.0.0
flake8
flake8-bugbear
flake8-builtins
flake8-comprehensions
flake8-copyright
flake8-debugger!=2.0.0
flake8-debugger
flake8-deprecated
flake8-docstrings<1.1.0
flake8-docstrings
flake8-future-import
flake8-mock
flake8-pep3101<1.1
flake8-putty
flake8-per-file-ignores
flake8-string-format
flake8-tidy-imports
flake8-tuple
pep8-naming
pydocstyle<2.0.0
pydocstyle
pyflakes
# Pinned to 2.0.0 otherwise
pycodestyle==2.3.1
# Pinned to 0.5.3 otherwise
mccabe==0.6.1
# Waiting until flake8-putty updated
#@ filter: flake8 < 3.0.0
#@ filter: pydocstyle < 2.0.0
#@ filter: flake8-docstrings < 1.1.0
#@ filter: flake8-pep3101 < 1.1
# https://github.com/JBKahn/flake8-debugger/issues/5
#@ filter: flake8-debugger != 2.0.0

View File

@@ -3,6 +3,6 @@
appdirs==1.4.3
packaging==16.8
pyparsing==2.2.0
setuptools==36.5.0
setuptools==38.4.0
six==1.11.0
wheel==0.30.0

View File

@@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
altgraph==0.14
altgraph==0.15
future==0.16.0
macholib==1.8
pefile==2017.9.3
macholib==1.9
pefile==2017.11.5
-e git+https://github.com/pyinstaller/pyinstaller.git@develop#egg=PyInstaller

View File

@@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-e git+https://github.com/PyCQA/astroid.git#egg=astroid
certifi==2017.7.27.1
certifi==2017.11.5
chardet==3.0.4
github3.py==0.9.6
idna==2.6

View File

@@ -1,14 +1,14 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
astroid==1.5.3
certifi==2017.7.27.1
astroid==1.6.0
certifi==2017.11.5
chardet==3.0.4
github3.py==0.9.6
idna==2.6
isort==4.2.15
lazy-object-proxy==1.3.1
mccabe==0.6.1
pylint==1.7.4
pylint==1.8.1
./scripts/dev/pylint_checkers
requests==2.18.4
six==1.11.0

View File

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

View File

@@ -1,4 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
docutils==0.14
pyroma==2.2
pyroma==2.3

View File

@@ -12,12 +12,6 @@ git+https://github.com/jenisys/parse_type.git
hg+https://bitbucket.org/pytest-dev/py
git+https://github.com/pytest-dev/pytest.git@features
git+https://github.com/pytest-dev/pytest-bdd.git
# This is broken at the moment because logfail tries to access
# LogCaptureHandler
# git+https://github.com/eisensheng/pytest-catchlog.git
pytest-catchlog==1.2.2
git+https://github.com/pytest-dev/pytest-cov.git
git+https://github.com/pytest-dev/pytest-faulthandler.git
git+https://github.com/pytest-dev/pytest-instafail.git

View File

@@ -1,39 +1,39 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
attrs==17.2.0
attrs==17.4.0
beautifulsoup4==4.6.0
cheroot==5.8.3
cheroot==6.0.0
click==6.7
# colorama==0.3.9
coverage==4.4.1
coverage==4.4.2
EasyProcess==0.2.3
fields==5.0.0
Flask==0.12.2
glob2==0.6
hunter==2.0.1
hypothesis==3.32.0
hunter==2.0.2
hypothesis==3.44.16
itsdangerous==0.24
# Jinja2==2.9.6
# Jinja2==2.10
Mako==1.0.7
# MarkupSafe==1.0
parse==1.8.2
parse-type==0.4.2
py==1.4.34
pluggy==0.6.0
py==1.5.2
py-cpuinfo==3.3.0
pytest==3.2.3
pytest-bdd==2.18.2
pytest==3.3.1 # rq.filter: != 3.3.2
pytest-bdd==2.19.0
pytest-benchmark==3.1.1
pytest-catchlog==1.2.2
pytest-cov==2.5.1
pytest-faulthandler==1.3.1
pytest-instafail==0.3.0
pytest-mock==1.6.3
pytest-qt==2.2.1
pytest-qt==2.3.1
pytest-repeat==0.4.1
pytest-rerunfailures==3.1
pytest-travis-fold==1.2.0
pytest-rerunfailures==4.0
pytest-travis-fold==1.3.0
pytest-xvfb==1.0.0
PyVirtualDisplay==0.2.1
six==1.11.0
vulture==0.26
Werkzeug==0.12.2
Werkzeug==0.14.1

View File

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

View File

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

View File

@@ -133,18 +133,24 @@ echo "jseval -q $(printjs)" >> "$QUTE_FIFO"
tmpdir=$(mktemp -d)
file_to_cast=${tmpdir}/qutecast
program_=$(command -v castnow)
if [[ "${program_}" == "" ]]; then
msg error "castnow can't be found..."
exit 1
fi
# kill any running instance of castnow
pkill -f /usr/bin/castnow
pkill -f "${program_}"
# start youtube download in stream mode (-o -) into temporary file
youtube-dl -qo - "$1" > ${file_to_cast} &
youtube-dl -qo - "$1" > "${file_to_cast}" &
ytdl_pid=$!
msg info "Casting $1" >> "$QUTE_FIFO"
# start castnow in stream mode to cast on ChromeCast
tail -F "${file_to_cast}" | castnow -
tail -F "${file_to_cast}" | ${program_} -
# cleanup remaining background process and file on disk
kill ${ytdl_pid}
rm -rf ${tmpdir}
rm -rf "${tmpdir}"

View File

@@ -41,7 +41,7 @@
[ -z "$QUTE_URL" ] && QUTE_URL='http://google.com'
url=$(echo "$QUTE_URL" | cat - "$QUTE_CONFIG_DIR/quickmarks" "$QUTE_DATA_DIR/history" | dmenu -l 15 -p qutebrowser)
url=$(echo "$url" | sed -E 's/[^ ]+ +//g' | egrep "https?:" || echo "$url")
url=$(echo "$url" | sed -E 's/[^ ]+ +//g' | grep -E "https?:" || echo "$url")
[ -z "${url// }" ] && exit

View File

@@ -1,4 +1,5 @@
#!/bin/sh
set -euo pipefail
#
# Behavior:
# Userscript for qutebrowser which will take the raw JSON text of the current
@@ -19,29 +20,23 @@
#
# Bryan Gilbert, 2017
# do not run pygmentize on files larger than this amount of bytes
MAX_SIZE_PRETTIFY=10485760 # 10 MB
# default style to monokai if none is provided
STYLE=${1:-monokai}
# format json using jq
FORMATTED_JSON="$(cat "$QUTE_TEXT" | jq '.')"
# if jq command failed or formatted json is empty, assume failure and terminate
if [ $? -ne 0 ] || [ -z "$FORMATTED_JSON" ]; then
echo "Invalid json, aborting..."
exit 1
TEMP_FILE="$(mktemp)"
jq . "$QUTE_TEXT" >"$TEMP_FILE"
# try GNU stat first and then OSX stat if the former fails
FILE_SIZE=$(
stat --printf="%s" "$TEMP_FILE" 2>/dev/null ||
stat -f%z "$TEMP_FILE" 2>/dev/null
)
if [ "$FILE_SIZE" -lt "$MAX_SIZE_PRETTIFY" ]; then
pygmentize -l json -f html -O full,style="$STYLE" <"$TEMP_FILE" >"${TEMP_FILE}_"
mv -f "${TEMP_FILE}_" "$TEMP_FILE"
fi
# calculate the filesize of the json document
FILE_SIZE=$(ls -s --block-size=1048576 "$QUTE_TEXT" | cut -d' ' -f1)
# use pygments to pretty-up the json (syntax highlight) if file is less than 10MB
if [ "$FILE_SIZE" -lt "10" ]; then
FORMATTED_JSON="$(echo "$FORMATTED_JSON" | pygmentize -l json -f html -O full,style=$STYLE)"
fi
# create a temp file and write the formatted json to that file
TEMP_FILE="$(mktemp --suffix '.html')"
echo "$FORMATTED_JSON" > $TEMP_FILE
# send the command to qutebrowser to open the new file containing the formatted json
echo "open -t file://$TEMP_FILE" >> "$QUTE_FIFO"

View File

@@ -76,6 +76,7 @@ crop-first-column() {
ls-files() {
# add the slash at the end of the download dir enforces to follow the
# symlink, if the DOWNLOAD_DIR itself is a symlink
# shellcheck disable=SC2010
ls -Q --quoting-style escape -h -o -1 -A -t "${DOWNLOAD_DIR}/" \
| grep '^[-]' \
| cut -d' ' -f3- \
@@ -91,10 +92,10 @@ if [ "${#entries[@]}" -eq 0 ] ; then
die "Download directory »${DOWNLOAD_DIR}« empty"
fi
line=$(printf "%s\n" "${entries[@]}" \
line=$(printf '%s\n' "${entries[@]}" \
| crop-first-column 55 \
| column -s $'\t' -t \
| $ROFI_CMD "${rofi_default_args[@]}" $ROFI_ARGS) || true
| $ROFI_CMD "${rofi_default_args[@]}" "$ROFI_ARGS") || true
if [ -z "$line" ]; then
exit 0
fi

View File

@@ -64,7 +64,7 @@ die() {
javascript_escape() {
# print the first argument in an escaped way, such that it can safely
# be used within javascripts double quotes
sed "s,[\\\'\"],\\\&,g" <<< "$1"
sed "s,[\\\\'\"],\\\\&,g" <<< "$1"
}
# ======================================================= #
@@ -178,7 +178,7 @@ choose_entry_menu() {
if [ "$nr" -eq 1 ] && ! ((menu_if_one_entry)) ; then
file="${files[0]}"
else
file=$( printf "%s\n" "${files[@]}" | "${MENU_COMMAND[@]}" )
file=$( printf '%s\n' "${files[@]}" | "${MENU_COMMAND[@]}" )
fi
}
@@ -236,7 +236,7 @@ pass_backend() {
if ((match_line)) ; then
# add entries with matching URL-tag
while read -r -d "" passfile ; do
if $GPG "${GPG_OPTS}" -d "$passfile" \
if $GPG "${GPG_OPTS[@]}" -d "$passfile" \
| grep --max-count=1 -iE "${match_line_pattern}${url}" > /dev/null
then
passfile="${passfile#$PREFIX}"
@@ -269,7 +269,7 @@ pass_backend() {
break
fi
fi
done < <($GPG "${GPG_OPTS}" -d "$path" )
done < <($GPG "${GPG_OPTS[@]}" -d "$path" )
}
}
# =======================================================
@@ -283,8 +283,8 @@ secret_backend() {
query_entries() {
local domain="$1"
while read -r line ; do
if [[ "$line" =~ "attribute.username = " ]] ; then
files+=("$domain ${line#${BASH_REMATCH[0]}}")
if [[ "$line" == "attribute.username = "* ]] ; then
files+=("$domain ${line:21}")
fi
done < <( secret-tool search --unlock --all domain "$domain" 2>&1 )
}
@@ -303,6 +303,7 @@ pass_backend
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
# shellcheck source=/dev/null
source "$PWFILL_CONFIG"
fi
init
@@ -311,7 +312,7 @@ simplify_url "$QUTE_URL"
query_entries "${simple_url}"
no_entries_found
# remove duplicates
mapfile -t files < <(printf "%s\n" "${files[@]}" | sort | uniq )
mapfile -t files < <(printf '%s\n' "${files[@]}" | sort | uniq )
choose_entry
if [ -z "$file" ] ; then
# choose_entry didn't want any of these entries

176
misc/userscripts/qute-pass Executable file
View File

@@ -0,0 +1,176 @@
#!/usr/bin/env python3
# Copyright 2017 Chris Braun (cryzed) <cryzed@googlemail.com>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""
Insert login information using pass and a dmenu-compatible application (e.g. dmenu, rofi -dmenu, ...). A short
demonstration can be seen here: https://i.imgur.com/KN3XuZP.gif.
"""
USAGE = """The domain of the site has to appear as a segment in the pass path, for example: "github.com/cryzed" or
"websites/github.com". How the username and password are determined is freely configurable using the CLI arguments. The
login information is inserted by emulating key events using qutebrowser's fake-key command in this manner:
[USERNAME]<Tab>[PASSWORD], which is compatible with almost all login forms."""
EPILOG = """Dependencies: tldextract (Python 3 module), pass.
For issues and feedback please use: https://github.com/cryzed/qutebrowser-userscripts.
WARNING: The login details are viewable as plaintext in qutebrowser's debug log (qute://log) and might be shared if
you decide to submit a crash report!"""
import argparse
import enum
import fnmatch
import functools
import os
import re
import shlex
import subprocess
import sys
import tldextract
argument_parser = argparse.ArgumentParser(description=__doc__, usage=USAGE, epilog=EPILOG)
argument_parser.add_argument('url', nargs='?', default=os.getenv('QUTE_URL'))
argument_parser.add_argument('--password-store', '-p', default=os.path.expanduser('~/.password-store'),
help='Path to your pass password-store')
argument_parser.add_argument('--username-pattern', '-u', default=r'.*/(.+)',
help='Regular expression that matches the username')
argument_parser.add_argument('--username-target', '-U', choices=['path', 'secret'], default='path',
help='The target for the username regular expression')
argument_parser.add_argument('--password-pattern', '-P', default=r'(.*)',
help='Regular expression that matches the password')
argument_parser.add_argument('--dmenu-invocation', '-d', default='rofi -dmenu',
help='Invocation used to execute a dmenu-provider')
argument_parser.add_argument('--no-insert-mode', '-n', dest='insert_mode', action='store_false',
help="Don't automatically enter insert mode")
argument_parser.add_argument('--io-encoding', '-i', default='UTF-8',
help='Encoding used to communicate with subprocesses')
argument_parser.add_argument('--merge-candidates', '-m', action='store_true',
help='Merge pass candidates for fully-qualified and registered domain name')
group = argument_parser.add_mutually_exclusive_group()
group.add_argument('--username-only', '-e', action='store_true', help='Only insert username')
group.add_argument('--password-only', '-w', action='store_true', help='Only insert password')
stderr = functools.partial(print, file=sys.stderr)
class ExitCodes(enum.IntEnum):
SUCCESS = 0
FAILURE = 1
# 1 is automatically used if Python throws an exception
NO_PASS_CANDIDATES = 2
COULD_NOT_MATCH_USERNAME = 3
COULD_NOT_MATCH_PASSWORD = 4
def qute_command(command):
with open(os.environ['QUTE_FIFO'], 'w') as fifo:
fifo.write(command + '\n')
fifo.flush()
def find_pass_candidates(domain, password_store_path):
candidates = []
for path, directories, file_names in os.walk(password_store_path):
if directories or domain not in path.split(os.path.sep):
continue
# Strip password store path prefix to get the relative pass path
pass_path = path[len(password_store_path) + 1:]
secrets = fnmatch.filter(file_names, '*.gpg')
candidates.extend(os.path.join(pass_path, os.path.splitext(secret)[0]) for secret in secrets)
return candidates
def pass_(path, encoding):
process = subprocess.run(['pass', path], stdout=subprocess.PIPE)
return process.stdout.decode(encoding).strip()
def dmenu(items, invocation, encoding):
command = shlex.split(invocation)
process = subprocess.run(command, input='\n'.join(items).encode(encoding), stdout=subprocess.PIPE)
return process.stdout.decode(encoding).strip()
def main(arguments):
if not arguments.url:
argument_parser.print_help()
return ExitCodes.FAILURE
extract_result = tldextract.extract(arguments.url)
# Expand potential ~ in paths, since this script won't be called from a shell that does it for us
password_store_path = os.path.expanduser(arguments.password_store)
# Try to find candidates using targets in the following order: fully-qualified domain name (includes subdomains),
# the registered domain name and finally: the IPv4 address if that's what the URL represents
candidates = set()
for target in filter(None, [extract_result.fqdn, extract_result.registered_domain, extract_result.ipv4]):
target_candidates = find_pass_candidates(target, password_store_path)
if not target_candidates:
continue
candidates.update(target_candidates)
if not arguments.merge_candidates:
break
else:
if not candidates:
stderr('No pass candidates for URL {!r} found!'.format(arguments.url))
return ExitCodes.NO_PASS_CANDIDATES
selection = candidates.pop() if len(candidates) == 1 else dmenu(sorted(candidates), arguments.dmenu_invocation,
arguments.io_encoding)
# Nothing was selected, simply return
if not selection:
return ExitCodes.SUCCESS
secret = pass_(selection, arguments.io_encoding)
# Match username
target = selection if arguments.username_target == 'path' else secret
match = re.match(arguments.username_pattern, target)
if not match:
stderr('Failed to match username pattern on {}!'.format(arguments.username_target))
return ExitCodes.COULD_NOT_MATCH_USERNAME
username = match.group(1)
# Match password
match = re.match(arguments.password_pattern, secret)
if not match:
stderr('Failed to match password pattern on secret!')
return ExitCodes.COULD_NOT_MATCH_PASSWORD
password = match.group(1)
insert_mode = ';; enter-mode insert' if arguments.insert_mode else ''
if arguments.username_only:
qute_command('fake-key {}{}'.format(username, insert_mode))
elif arguments.password_only:
qute_command('fake-key {}{}'.format(password, insert_mode))
else:
# Enter username and password using fake-key and <Tab> (which seems to work almost universally), then switch
# back into insert-mode, so the form can be directly submitted by hitting enter afterwards
qute_command('fake-key {} ;; fake-key <Tab> ;; fake-key {}{}'.format(username, password, insert_mode))
return ExitCodes.SUCCESS
if __name__ == '__main__':
arguments = argument_parser.parse_args()
sys.exit(main(arguments))

View File

@@ -35,17 +35,12 @@ get_selection() {
# Main
# https://github.com/halfwit/dotfiles/blob/master/.config/dmenu/font
if [[ -s $confdir/dmenu/font ]]; then
read -r font < "$confdir"/dmenu/font
fi
[[ -s $confdir/dmenu/font ]] && read -r font < "$confdir"/dmenu/font
if [[ $font ]]; then
opts+=(-fn "$font")
fi
[[ $font ]] && opts+=(-fn "$font")
if [[ -s $optsfile ]]; then
source "$optsfile"
fi
# shellcheck source=/dev/null
[[ -s $optsfile ]] && source "$optsfile"
url=$(get_selection)
url=${url/*http/http}

View File

@@ -32,7 +32,7 @@ add_feed () {
if grep -Fq "$1" "feeds"; then
notice "$1 is saved already."
else
printf "%s\n" "$1" >> "feeds"
printf '%s\n' "$1" >> "feeds"
fi
}
@@ -57,7 +57,7 @@ notice () {
# Update a database of a feed and open new URLs
read_items () {
cd read_urls
cd read_urls || return 1
feed_file="$(echo "$1" | tr -d /)"
feed_temp_file="$(mktemp "$feed_file.tmp.XXXXXXXXXX")"
feed_new_items="$(mktemp "$feed_file.new.XXXXXXXXXX")"
@@ -75,7 +75,7 @@ read_items () {
cat "$feed_new_items" >> "$feed_file"
sort -o "$feed_file" "$feed_file"
rm "$feed_temp_file" "$feed_new_items"
fi | while read item; do
fi | while read -r item; do
echo "open -t $item" > "$QUTE_FIFO"
done
}
@@ -85,7 +85,7 @@ if [ ! -d "$config_dir/read_urls" ]; then
mkdir -p "$config_dir/read_urls"
fi
cd "$config_dir"
cd "$config_dir" || exit 1
if [ $# != 0 ]; then
for arg in "$@"; do
@@ -115,7 +115,7 @@ if < /dev/null grep --help 2>&1 | grep -q -- -a; then
text_only="-a"
fi
while read feed_url; do
while read -r feed_url; do
read_items "$feed_url" &
done < "$config_dir/feeds"

View File

@@ -25,12 +25,10 @@
[[ $QUTE_MODE == 'hints' ]] && title=$QUTE_SELECTED_TEXT || title=$QUTE_TITLE
# try to add the task and grab the output
msg="$(task add $title $@ 2>&1)"
if [[ $? == 0 ]]; then
if msg="$(task add "$title" "$*" 2>&1)"; then
# annotate the new task with the url, send the output back to the browser
task +LATEST annotate "$QUTE_URL"
echo "message-info '$msg'" >> $QUTE_FIFO
echo "message-info '$msg'" >> "$QUTE_FIFO"
else
echo "message-error '$msg'" >> $QUTE_FIFO
echo "message-error '$msg'" >> "$QUTE_FIFO"
fi

View File

@@ -50,7 +50,7 @@ msg() {
MPV_COMMAND=${MPV_COMMAND:-mpv}
# Warning: spaces in single flags are not supported
MPV_FLAGS=${MPV_FLAGS:- --force-window --no-terminal --keep-open=yes --ytdl --ytdl-raw-options=yes-playlist=}
video_command=( "$MPV_COMMAND" $MPV_FLAGS )
IFS=" " read -r -a video_command <<< "$MPV_COMMAND $MPV_FLAGS"
js() {
cat <<EOF

View File

@@ -26,6 +26,7 @@ markers =
no_invalid_lines: Don't fail on unparseable lines in end2end tests
issue2478: Tests which are broken on Windows with QtWebEngine, https://github.com/qutebrowser/qutebrowser/issues/2478
fake_os: Fake utils.is_* to a fake operating system
unicode_locale: Tests which need an unicode locale to work
qt_log_level_fail = WARNING
qt_log_ignore =
^SpellCheck: .*
@@ -50,9 +51,12 @@ qt_log_ignore =
^Error when parsing the netrc file
^Image of format '' blocked because it is not considered safe. If you are sure it is safe to do so, you can white-list the format by setting the environment variable QTWEBKIT_IMAGEFORMAT_WHITELIST=
^QPainter::end: Painter ended with \d+ saved states
^QSslSocket: cannot resolve *
^QSslSocket: cannot resolve .*
^QSslSocket: cannot call unresolved function .*
^Incompatible version of OpenSSL
^QQuickWidget::invalidateRenderControl could not make context current
^libpng warning: iCCP: known incorrect sRGB profile
^inotify_add_watch(".*") failed: "No space left on device"
^inotify_add_watch\(".*"\) failed: "No space left on device"
^QSettings::value: Empty key passed
^Icon theme ".*" not found
xfail_strict = true

View File

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

View File

@@ -51,7 +51,7 @@ import tokenize
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QDesktopServices, QPixmap, QIcon, QWindow
from PyQt5.QtCore import (pyqtSlot, qInstallMessageHandler, QTimer, QUrl,
QObject, QEvent, pyqtSignal)
QObject, QEvent, pyqtSignal, Qt)
try:
import hunter
except ImportError:
@@ -64,7 +64,7 @@ from qutebrowser.completion.models import miscmodels
from qutebrowser.commands import cmdutils, runners, cmdexc
from qutebrowser.config import config, websettings, configfiles, configinit
from qutebrowser.browser import (urlmarks, adblock, history, browsertab,
downloads)
downloads, greasemonkey)
from qutebrowser.browser.network import proxy
from qutebrowser.browser.webkit import cookies, cache
from qutebrowser.browser.webkit.network import networkmanager
@@ -417,7 +417,6 @@ def _init_modules(args, crash_handler):
args: The argparse namespace.
crash_handler: The CrashHandler instance.
"""
# pylint: disable=too-many-statements
log.init.debug("Initializing save manager...")
save_manager = savemanager.SaveManager(qApp)
objreg.register('save-manager', save_manager)
@@ -492,6 +491,9 @@ def _init_modules(args, crash_handler):
diskcache = cache.DiskCache(standarddir.cache(), parent=qApp)
objreg.register('cache', diskcache)
log.init.debug("Initializing Greasemonkey...")
greasemonkey.init()
log.init.debug("Misc initialization...")
macros.init()
# Init backend-specific stuff
@@ -562,8 +564,8 @@ class Quitter:
cwd = os.path.abspath(os.path.dirname(sys.executable))
else:
args = [sys.executable, '-m', 'qutebrowser']
cwd = os.path.join(os.path.abspath(os.path.dirname(
qutebrowser.__file__)), '..')
cwd = os.path.join(
os.path.abspath(os.path.dirname(qutebrowser.__file__)), '..')
if not os.path.isdir(cwd):
# Probably running from a python egg. Let's fallback to
# cwd=None and see if that works out.
@@ -821,6 +823,7 @@ class Application(QApplication):
self.launch_time = datetime.datetime.now()
self.focusObjectChanged.connect(self.on_focus_object_changed)
self.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
@pyqtSlot(QObject)
def on_focus_object_changed(self, obj):
@@ -869,10 +872,6 @@ class EventFilter(QObject):
super().__init__(parent)
self._activated = True
self._handlers = {
QEvent.MouseButtonDblClick: self._handle_mouse_event,
QEvent.MouseButtonPress: self._handle_mouse_event,
QEvent.MouseButtonRelease: self._handle_mouse_event,
QEvent.MouseMove: self._handle_mouse_event,
QEvent.KeyPress: self._handle_key_event,
QEvent.KeyRelease: self._handle_key_event,
}
@@ -897,19 +896,6 @@ class EventFilter(QObject):
# No window available yet, or not a MainWindow
return False
def _handle_mouse_event(self, _event):
"""Handle a mouse event.
Args:
_event: The QEvent which is about to be delivered.
Return:
True if the event should be filtered, False if it's passed through.
"""
# Mouse cursor shown (overrideCursor None) -> don't filter event
# Mouse cursor hidden (overrideCursor not None) -> filter event
return qApp.overrideCursor() is not None
def eventFilter(self, obj, event):
"""Handle an event.

View File

@@ -19,8 +19,10 @@
"""Base class for a wrapper over QWebView/QWebEngineView."""
import enum
import itertools
import sip
import attr
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt
from PyQt5.QtGui import QIcon
@@ -74,7 +76,7 @@ class UnsupportedOperationError(WebTabError):
"""Raised when an operation is not supported with the given backend."""
TerminationStatus = usertypes.enum('TerminationStatus', [
TerminationStatus = enum.Enum('TerminationStatus', [
'normal',
'abnormal', # non-zero exit status
'crashed', # e.g. segfault
@@ -485,6 +487,7 @@ class AbstractHistory:
raise NotImplementedError
def back(self, count=1):
"""Go back in the tab's history."""
idx = self.current_idx() - count
if idx >= 0:
self._go_to_item(self._item_at(idx))
@@ -493,6 +496,7 @@ class AbstractHistory:
raise WebTabError("At beginning of history.")
def forward(self, count=1):
"""Go forward in the tab's history."""
idx = self.current_idx() + count
if idx < len(self):
self._go_to_item(self._item_at(idx))
@@ -702,8 +706,8 @@ class AbstractTab(QWidget):
# This only gives us some mild protection against re-using events, but
# it's certainly better than a segfault.
if getattr(evt, 'posted', False):
raise AssertionError("Can't re-use an event which was already "
"posted!")
raise utils.Unreachable("Can't re-use an event which was already "
"posted!")
recipient = self.event_target()
evt.posted = True
QApplication.postEvent(recipient, evt)
@@ -745,6 +749,10 @@ class AbstractTab(QWidget):
@pyqtSlot(bool)
def _on_load_finished(self, ok):
if sip.isdeleted(self._widget):
# https://github.com/qutebrowser/qutebrowser/issues/3498
return
sess_manager = objreg.get('session-manager')
sess_manager.save_autosave()
@@ -863,3 +871,6 @@ class AbstractTab(QWidget):
except (AttributeError, RuntimeError) as exc:
url = '<{}>'.format(exc.__class__.__name__)
return utils.get_repr(self, tab_id=self.tab_id, url=url)
def is_deleted(self):
return sip.isdeleted(self._widget)

View File

@@ -39,7 +39,7 @@ from qutebrowser.browser import (urlmarks, browsertab, inspector, navigate,
webelem, downloads)
from qutebrowser.keyinput import modeman
from qutebrowser.utils import (message, usertypes, log, qtutils, urlutils,
objreg, utils, debug)
objreg, utils, debug, standarddir)
from qutebrowser.utils.usertypes import KeyMode
from qutebrowser.misc import editor, guiprocess
from qutebrowser.completion.models import urlmodel, miscmodels
@@ -353,6 +353,10 @@ class CommandDispatcher:
Return:
A list of URLs that can be opened.
"""
if isinstance(url, QUrl):
yield url
return
force_search = False
urllist = [u for u in url.split('\n') if u.strip()]
if (len(urllist) > 1 and not urlutils.is_url(urllist[0]) and
@@ -514,14 +518,58 @@ class CommandDispatcher:
return newtab
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('index', completion=miscmodels.other_buffer)
def tab_take(self, index):
"""Take a tab from another window.
Args:
index: The [win_id/]index of the tab to take. Or a substring
in which case the closest match will be taken.
"""
tabbed_browser, tab = self._resolve_buffer_index(index)
if tabbed_browser is self._tabbed_browser:
raise cmdexc.CommandError("Can't take a tab from the same window")
self._open(tab.url(), tab=True)
tabbed_browser.close_tab(tab, add_undo=False)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('win_id', completion=miscmodels.window)
def tab_give(self, win_id: int = None):
"""Give the current tab to a new or existing window if win_id given.
If no win_id is given, the tab will get detached into a new window.
Args:
win_id: The window ID of the window to give the current tab to.
"""
if win_id == self._win_id:
raise cmdexc.CommandError("Can't give a tab to the same window")
if win_id is None:
if self._count() < 2:
raise cmdexc.CommandError("Cannot detach from a window with "
"only one tab")
tabbed_browser = self._new_tabbed_browser(
private=self._tabbed_browser.private)
else:
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)
tabbed_browser.tabopen(self._current_url())
self._tabbed_browser.close_tab(self._current_widget(), add_undo=False)
@cmdutils.register(instance='command-dispatcher', scope='window',
deprecated='Use :tab-give instead!')
def tab_detach(self):
"""Detach the current tab to its own window."""
if self._count() < 2:
raise cmdexc.CommandError("Cannot detach one tab.")
url = self._current_url()
self._open(url, window=True)
cur_widget = self._current_widget()
self._tabbed_browser.close_tab(cur_widget, add_undo=False)
"""Deprecated way to detach a tab."""
self.tab_give()
def _back_forward(self, tab, bg, window, count, forward):
"""Helper function for :back/:forward."""
@@ -625,12 +673,11 @@ class CommandDispatcher:
self._open(new_url, tab, bg, window, related=True)
else: # pragma: no cover
raise ValueError("Got called with invalid value {} for "
"`where'.".format(where))
"`where'.".format(where))
except navigate.Error as e:
raise cmdexc.CommandError(e)
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def scroll_px(self, dx: int, dy: int, count=1):
"""Scroll the current tab by 'count * dx/dy' pixels.
@@ -646,8 +693,7 @@ class CommandDispatcher:
cmdutils.check_overflow(dy, 'int')
self._current_widget().scroller.delta(dx, dy)
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def scroll(self, direction: typing.Union[str, int], count=1):
"""Scroll the current tab in the given direction.
@@ -684,8 +730,7 @@ class CommandDispatcher:
else:
func(count=count)
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('horizontal', flag='x')
def scroll_to_perc(self, perc: float = None, horizontal=False, count=None):
@@ -716,8 +761,7 @@ class CommandDispatcher:
self._current_widget().scroller.to_perc(x, y)
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
@cmdutils.argument('top_navigate', metavar='ACTION',
choices=('prev', 'decrement'))
@@ -766,7 +810,7 @@ class CommandDispatcher:
flags |= QUrl.FullyEncoded
url = QUrl(self._current_url())
url_query = QUrlQuery()
url_query_str = url.query()
url_query_str = urlutils.query_string(url)
if '&' not in url_query_str and ';' in url_query_str:
url_query.setQueryDelimiters('=', ';')
url_query.setQuery(url_query_str)
@@ -920,13 +964,15 @@ class CommandDispatcher:
prev=prev, next_=next_, force=True))
return
first_tab = True
for i, tab in enumerate(self._tabbed_browser.widgets()):
if _to_close(i):
self._tabbed_browser.close_tab(tab)
self._tabbed_browser.close_tab(tab, new_undo=first_tab)
first_tab = False
@cmdutils.register(instance='command-dispatcher', scope='window')
def undo(self):
"""Re-open a closed tab."""
"""Re-open the last closed tab or tabs."""
try:
self._tabbed_browser.undo()
except IndexError:
@@ -972,77 +1018,27 @@ class CommandDispatcher:
else:
raise cmdexc.CommandError("Last tab")
@cmdutils.register(instance='command-dispatcher', scope='window',
deprecated="Use :open {clipboard}")
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.
def _resolve_buffer_index(self, index):
"""Resolve a buffer index to the tabbedbrowser and 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.
"""
force_search = False
if not utils.supports_selection():
sel = False
try:
text = utils.get_clipboard(selection=sel)
except utils.ClipboardError as e:
raise cmdexc.CommandError(e)
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):
force_search = True
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, force_search=force_search)
except urlutils.InvalidUrlError as e:
raise cmdexc.CommandError(e)
self._open(url, tab, bg, window)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('index', completion=miscmodels.buffer)
@cmdutils.argument('count', count=True)
def buffer(self, index=None, count=None):
"""Select tab by index or url/title best match.
Focuses window if necessary when index is given. If both index and
count are given, use count.
Args:
index: The [win_id/]index of the tab to focus. Or a substring
index: The [win_id/]index of the tab to be selected. Or a substring
in which case the closest match will be focused.
count: The tab index to focus, starting with 1.
"""
if count is not None:
index_parts = [count]
elif index is None:
raise cmdexc.CommandError("buffer: Either a count or the argument "
"index must be specified.")
else:
index_parts = index.split('/', 1)
index_parts = index.split('/', 1)
try:
for part in index_parts:
int(part)
except ValueError:
model = miscmodels.buffer()
model.set_pattern(index)
if model.count() > 0:
index = model.data(model.first_item())
index_parts = index.split('/', 1)
else:
raise cmdexc.CommandError(
"No matching tab for: {}".format(index))
try:
for part in index_parts:
int(part)
except ValueError:
model = miscmodels.buffer()
model.set_pattern(index)
if model.count() > 0:
index = model.data(model.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])
@@ -1066,10 +1062,36 @@ class CommandDispatcher:
raise cmdexc.CommandError(
"There's no tab with index {}!".format(idx))
window = objreg.window_registry[win_id]
return (tabbed_browser, tabbed_browser.widget(idx-1))
@cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0)
@cmdutils.argument('index', completion=miscmodels.buffer)
@cmdutils.argument('count', count=True)
def buffer(self, index=None, count=None):
"""Select tab by index or url/title best match.
Focuses window if necessary when index is given. If both index and
count are given, use count.
Args:
index: The [win_id/]index of the tab to focus. Or a substring
in which case the closest match will be focused.
count: The tab index to focus, starting with 1.
"""
if count is None and index is None:
raise cmdexc.CommandError("buffer: Either a count or the argument "
"index must be specified.")
if count is not None:
index = str(count)
tabbed_browser, tab = self._resolve_buffer_index(index)
window = tabbed_browser.window()
window.activateWindow()
window.raise_()
tabbed_browser.setCurrentIndex(idx-1)
tabbed_browser.setCurrentWidget(tab)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('index', choices=['last'])
@@ -1155,7 +1177,8 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0, no_replace_variables=True)
def spawn(self, cmdline, userscript=False, verbose=False, detach=False):
def spawn(self, cmdline, userscript=False, verbose=False,
output=False, detach=False):
"""Spawn a command in a shell.
Args:
@@ -1166,6 +1189,7 @@ class CommandDispatcher:
(or `$XDG_DATA_DIR`)
- `/usr/share/qutebrowser/userscripts`
verbose: Show notifications when the command started/exited.
output: Whether the output should be shown in a new tab.
detach: Whether the command should be detached from qutebrowser.
cmdline: The commandline to execute.
"""
@@ -1192,10 +1216,15 @@ class CommandDispatcher:
else:
proc.start(cmd, args)
if output:
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window='last-focused')
tabbed_browser.openurl(QUrl('qute://spawn-output'), newtab=True)
@cmdutils.register(instance='command-dispatcher', scope='window')
def home(self):
"""Open main startpage in current tab."""
self._current_widget().openurl(config.val.url.start_pages[0])
self.openurl(config.val.url.start_pages[0])
def _run_userscript(self, cmd, *args, verbose=False):
"""Run a userscript given as argument.
@@ -1362,8 +1391,7 @@ class CommandDispatcher:
except KeyError:
raise cmdexc.CommandError("Bookmark '{}' not found!".format(url))
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.register(instance='command-dispatcher', scope='window')
def follow_selected(self, *, tab=False):
"""Follow the selected text.
@@ -1397,27 +1425,14 @@ class CommandDispatcher:
raise cmdexc.CommandError(e)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('dest_old', hide=True)
def download(self, url=None, dest_old=None, *, mhtml_=False, dest=None):
def download(self, url=None, *, mhtml_=False, dest=None):
"""Download a given URL, or current page if no URL given.
The form `:download [url] [dest]` is deprecated, use `:download --dest
[dest] [url]` instead.
Args:
url: The URL to download. If not given, download the current page.
dest_old: (deprecated) Same as dest.
dest: The file path to write the download to, or None to ask.
mhtml_: Download the current page and all assets as mhtml file.
"""
if dest_old is not None:
message.warning(":download [url] [dest] is deprecated - use "
":download --dest [dest] [url]")
if dest is not None:
raise cmdexc.CommandError("Can't give two destinations for the"
" download.")
dest = dest_old
# FIXME:qtwebengine do this with the QtWebEngine download manager?
download_manager = objreg.get('qtnetwork-download-manager',
scope='window', window=self._win_id)
@@ -1467,8 +1482,6 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
def view_source(self):
"""Show the source of the current page in a new tab."""
# pylint: disable=no-member
# WORKAROUND for https://bitbucket.org/logilab/pylint/issue/491/
tab = self._current_widget()
if tab.data.viewing_source:
raise cmdexc.CommandError("Already viewing source!")
@@ -1481,10 +1494,13 @@ class CommandDispatcher:
def show_source_cb(source):
"""Show source as soon as it's ready."""
# WORKAROUND for https://github.com/PyCQA/pylint/issues/491
# pylint: disable=no-member
lexer = pygments.lexers.HtmlLexer()
formatter = pygments.formatters.HtmlFormatter(
full=True, linenos='table',
title='Source for {}'.format(current_url.toDisplayString()))
# pylint: enable=no-member
highlighted = pygments.highlight(source, lexer, formatter)
new_tab = self._tabbed_browser.tabopen()
@@ -1506,6 +1522,7 @@ class CommandDispatcher:
dest = os.path.expanduser(dest)
def callback(data):
"""Write the data to disk."""
try:
with open(dest, 'w', encoding='utf-8') as f:
f.write(data)
@@ -1594,13 +1611,14 @@ class CommandDispatcher:
return
assert isinstance(text, str), text
caret_position = elem.caret_position()
ed = editor.ExternalEditor(self._tabbed_browser)
ed.editing_finished.connect(functools.partial(
self.on_editing_finished, elem))
ed.edit(text)
ed.edit(text, caret_position)
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.register(instance='command-dispatcher', scope='window')
def open_editor(self):
"""Open an external editor with the currently selected form field.
@@ -1621,16 +1639,12 @@ class CommandDispatcher:
"""
try:
elem.set_value(text)
except webelem.OrphanedError as e:
message.error('Edited element vanished')
except webelem.Error as e:
raise cmdexc.CommandError(str(e))
@cmdutils.register(instance='command-dispatcher',
deprecated="Use :insert-text {primary}",
modes=[KeyMode.insert], hide=True, scope='window',
backend=usertypes.Backend.QtWebKit)
def paste_primary(self):
"""Paste the primary selection at cursor position."""
self.insert_text(utils.get_clipboard(selection=True, fallback=True))
mainwindow.raise_window(objreg.last_focused_window(), alert=False)
@cmdutils.register(instance='command-dispatcher', maxsplit=0,
scope='window')
@@ -1654,8 +1668,7 @@ class CommandDispatcher:
tab.elements.find_focused(_insert_text_cb)
@cmdutils.register(instance='command-dispatcher', scope='window',
hide=True)
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('filter_', choices=['id'])
def click_element(self, filter_: str, value, *,
target: usertypes.ClickTarget =
@@ -1726,7 +1739,8 @@ class CommandDispatcher:
elif going_up and tab.scroller.pos_px().y() > old_scroll_pos.y():
message.info("Search hit TOP, continuing at BOTTOM")
else:
message.warning("Text '{}' not found on page!".format(text))
message.warning("Text '{}' not found on page!".format(text),
replace=True)
@cmdutils.register(instance='command-dispatcher', scope='window',
maxsplit=0)
@@ -1746,7 +1760,7 @@ class CommandDispatcher:
return
options = {
'ignore_case': config.val.ignore_case,
'ignore_case': config.val.search.ignore_case,
'reverse': reverse,
}
@@ -1760,8 +1774,7 @@ class CommandDispatcher:
tab.search.search(text, **options)
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def search_next(self, count=1):
"""Continue the search to the ([count]th) next term.
@@ -1795,8 +1808,7 @@ class CommandDispatcher:
tab.search.next_result()
tab.search.next_result(result_cb=cb)
@cmdutils.register(instance='command-dispatcher', hide=True,
scope='window')
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def search_prev(self, count=1):
"""Continue the search to the ([count]th) previous term.
@@ -1830,8 +1842,8 @@ class CommandDispatcher:
tab.search.prev_result()
tab.search.prev_result(result_cb=cb)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_next_line(self, count=1):
"""Move the cursor or selection to the next line.
@@ -1841,8 +1853,8 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_next_line(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_prev_line(self, count=1):
"""Move the cursor or selection to the prev line.
@@ -1852,8 +1864,8 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_prev_line(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_next_char(self, count=1):
"""Move the cursor or selection to the next char.
@@ -1863,8 +1875,8 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_next_char(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_prev_char(self, count=1):
"""Move the cursor or selection to the previous char.
@@ -1874,8 +1886,8 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_prev_char(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_end_of_word(self, count=1):
"""Move the cursor or selection to the end of the word.
@@ -1885,8 +1897,8 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_end_of_word(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_next_word(self, count=1):
"""Move the cursor or selection to the next word.
@@ -1896,8 +1908,8 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_next_word(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_prev_word(self, count=1):
"""Move the cursor or selection to the previous word.
@@ -1907,20 +1919,20 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_prev_word(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
def move_to_start_of_line(self):
"""Move the cursor or selection to the start of the line."""
self._current_widget().caret.move_to_start_of_line()
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
def move_to_end_of_line(self):
"""Move the cursor or selection to the end of line."""
self._current_widget().caret.move_to_end_of_line()
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_start_of_next_block(self, count=1):
"""Move the cursor or selection to the start of next block.
@@ -1930,8 +1942,8 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_start_of_next_block(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_start_of_prev_block(self, count=1):
"""Move the cursor or selection to the start of previous block.
@@ -1941,8 +1953,8 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_start_of_prev_block(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_end_of_next_block(self, count=1):
"""Move the cursor or selection to the end of next block.
@@ -1952,8 +1964,8 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_end_of_next_block(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
@cmdutils.argument('count', count=True)
def move_to_end_of_prev_block(self, count=1):
"""Move the cursor or selection to the end of previous block.
@@ -1963,26 +1975,26 @@ class CommandDispatcher:
"""
self._current_widget().caret.move_to_end_of_prev_block(count)
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
def move_to_start_of_document(self):
"""Move the cursor or selection to the start of the document."""
self._current_widget().caret.move_to_start_of_document()
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
def move_to_end_of_document(self):
"""Move the cursor or selection to the end of the document."""
self._current_widget().caret.move_to_end_of_document()
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
def toggle_selection(self):
"""Toggle caret selection mode."""
self._current_widget().caret.toggle_selection()
@cmdutils.register(instance='command-dispatcher', hide=True,
modes=[KeyMode.caret], scope='window')
@cmdutils.register(instance='command-dispatcher', modes=[KeyMode.caret],
scope='window')
def drop_selection(self):
"""Drop selection and keep selection mode enabled."""
self._current_widget().caret.drop_selection()
@@ -2017,6 +2029,9 @@ class CommandDispatcher:
Args:
js_code: The string/file to evaluate.
file: Interpret js-code as a path to a file.
If the path is relative, the file is searched in a js/ subdir
in qutebrowser's data dir, e.g.
`~/.local/share/qutebrowser/js`.
quiet: Don't show resulting JS object.
world: Ignored on QtWebKit. On QtWebEngine, a world ID or name to
run the snippet in.
@@ -2028,6 +2043,7 @@ class CommandDispatcher:
jseval_cb = None
else:
def jseval_cb(out):
"""Show the data returned from JS."""
if out is None:
# Getting the actual error (if any) seems to be difficult.
# The error does end up in
@@ -2046,6 +2062,9 @@ class CommandDispatcher:
if file:
path = os.path.expanduser(js_code)
if not os.path.isabs(path):
path = os.path.join(standarddir.data(), 'js', path)
try:
with open(path, 'r', encoding='utf-8') as f:
js_code = f.read()
@@ -2096,7 +2115,8 @@ class CommandDispatcher:
self._current_widget().clear_ssl_errors()
@cmdutils.register(instance='command-dispatcher', scope='window')
def edit_url(self, url=None, bg=False, tab=False, window=False):
def edit_url(self, url=None, bg=False, tab=False, window=False,
private=False, related=False):
"""Navigate to a url formed in an external editor.
The editor which should be launched can be configured via the
@@ -2107,6 +2127,9 @@ class CommandDispatcher:
bg: Open in a new background tab.
tab: Open in a new tab.
window: Open in a new window.
private: Open a new window in private browsing mode.
related: If opening a new tab, position the tab as related to the
current one (like clicking on a link).
"""
cmdutils.check_exclusive((tab, bg, window), 'tbw')
@@ -2117,12 +2140,11 @@ class CommandDispatcher:
# Passthrough for openurl args (e.g. -t, -b, -w)
ed.editing_finished.connect(functools.partial(
self._open_if_changed, old_url=old_url, bg=bg, tab=tab,
window=window))
window=window, private=private, related=related))
ed.edit(url or old_url)
@cmdutils.register(instance='command-dispatcher', scope='window',
hide=True)
@cmdutils.register(instance='command-dispatcher', scope='window')
def set_mark(self, key):
"""Set a mark at the current scroll position in the current tab.
@@ -2131,8 +2153,7 @@ class CommandDispatcher:
"""
self._tabbed_browser.set_mark(key)
@cmdutils.register(instance='command-dispatcher', scope='window',
hide=True)
@cmdutils.register(instance='command-dispatcher', scope='window')
def jump_mark(self, key):
"""Jump to the mark named by `key`.
@@ -2142,7 +2163,7 @@ class CommandDispatcher:
self._tabbed_browser.jump_mark(key)
def _open_if_changed(self, url=None, old_url=None, bg=False, tab=False,
window=False):
window=False, private=False, related=False):
"""Open a URL unless it's already open in the tab.
Args:
@@ -2151,9 +2172,13 @@ class CommandDispatcher:
bg: Open in a new background tab.
tab: Open in a new tab.
window: Open in a new window.
private: Open a new window in private browsing mode.
related: If opening a new tab, position the tab as related to the
current one (like clicking on a link).
"""
if bg or tab or window or url != old_url:
self.openurl(url=url, bg=bg, tab=tab, window=window)
if bg or tab or window or private or related or url != old_url:
self.openurl(url=url, bg=bg, tab=tab, window=window,
private=private, related=related)
@cmdutils.register(instance='command-dispatcher', scope='window')
def fullscreen(self, leave=False):

View File

@@ -27,6 +27,7 @@ import collections
import functools
import pathlib
import tempfile
import enum
import sip
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex,
@@ -38,8 +39,7 @@ from qutebrowser.utils import (usertypes, standarddir, utils, message, log,
qtutils)
ModelRole = usertypes.enum('ModelRole', ['item'], start=Qt.UserRole,
is_int=True)
ModelRole = enum.IntEnum('ModelRole', ['item'], start=Qt.UserRole)
# Remember the last used directory
@@ -103,6 +103,8 @@ def immediate_download_path(prompt_download_directory=None):
if not prompt_download_directory:
return download_dir()
return None
def _path_suggestion(filename):
"""Get the suggested file path.
@@ -137,7 +139,8 @@ def create_full_filename(basename, filename):
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):
if os.path.isabs(filename) and (os.path.isdir(filename) or
filename.endswith(os.sep)):
# We got an absolute directory from the user, so we save it under
# the default filename in that directory.
return os.path.join(filename, basename)
@@ -179,7 +182,7 @@ def transform_path(path):
path = utils.expand_windows_drive(path)
# Drive dependent working directories are not supported, e.g.
# E:filename is invalid
if re.match(r'[A-Z]:[^\\]', path, re.IGNORECASE):
if re.search(r'^[A-Z]:[^\\]', path, re.IGNORECASE):
return None
# Paths like COM1, ...
# See https://github.com/qutebrowser/qutebrowser/issues/82
@@ -604,6 +607,11 @@ class AbstractDownloadItem(QObject):
"""Ask a confirmation question for the download."""
raise NotImplementedError
def _ask_create_parent_question(self, title, msg,
force_overwrite, remember_directory):
"""Ask a confirmation question for the parent directory."""
raise NotImplementedError
def _set_fileobj(self, fileobj, *, autoclose=True):
"""Set a file object to save the download to.
@@ -630,7 +638,6 @@ class AbstractDownloadItem(QObject):
remember_directory: If True, remember the directory for future
downloads.
"""
global last_used_directory
filename = os.path.expanduser(filename)
self._ensure_can_set_filename(filename)
@@ -657,11 +664,41 @@ class AbstractDownloadItem(QObject):
self._filename = create_full_filename(self.basename,
os.path.expanduser('~'))
dirname = os.path.dirname(self._filename)
if not os.path.exists(dirname):
txt = ("<b>{}</b> does not exist. Create it?".
format(html.escape(
os.path.join(dirname, ""))))
self._ask_create_parent_question("Create directory?", txt,
force_overwrite,
remember_directory)
else:
self._after_create_parent_question(force_overwrite,
remember_directory)
def _after_create_parent_question(self,
force_overwrite, remember_directory):
"""After asking about parent directory.
Args:
force_overwrite: Force overwriting existing files.
remember_directory: If True, remember the directory for future
downloads.
"""
global last_used_directory
try:
os.makedirs(os.path.dirname(self._filename))
except FileExistsError:
pass
except OSError as e:
self._die(e.strerror)
self.basename = os.path.basename(self._filename)
if remember_directory:
last_used_directory = os.path.dirname(self._filename)
log.downloads.debug("Setting filename to {}".format(filename))
log.downloads.debug("Setting filename to {}".format(self._filename))
if force_overwrite:
self._after_set_filename()
elif os.path.isfile(self._filename):
@@ -955,7 +992,7 @@ class DownloadModel(QAbstractListModel):
if not count:
count = len(self)
raise cmdexc.CommandError("Download {} is already done!"
.format(count))
.format(count))
download.cancel()
@cmdutils.register(instance='download-model', scope='window')

View File

@@ -0,0 +1,224 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2017 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Load, parse and make available Greasemonkey scripts."""
import re
import os
import json
import fnmatch
import functools
import glob
import attr
from PyQt5.QtCore import pyqtSignal, QObject, QUrl
from qutebrowser.utils import log, standarddir, jinja, objreg
from qutebrowser.commands import cmdutils
def _scripts_dir():
"""Get the directory of the scripts."""
return os.path.join(standarddir.data(), 'greasemonkey')
class GreasemonkeyScript:
"""Container class for userscripts, parses metadata blocks."""
def __init__(self, properties, code):
self._code = code
self.includes = []
self.excludes = []
self.description = None
self.name = None
self.namespace = None
self.run_at = None
self.script_meta = None
self.runs_on_sub_frames = True
for name, value in properties:
if name == 'name':
self.name = value
elif name == 'namespace':
self.namespace = value
elif name == 'description':
self.description = value
elif name in ['include', 'match']:
self.includes.append(value)
elif name in ['exclude', 'exclude_match']:
self.excludes.append(value)
elif name == 'run-at':
self.run_at = value
elif name == 'noframes':
self.runs_on_sub_frames = False
HEADER_REGEX = r'// ==UserScript==|\n+// ==/UserScript==\n'
PROPS_REGEX = r'// @(?P<prop>[^\s]+)\s*(?P<val>.*)'
@classmethod
def parse(cls, source):
"""GreasemonkeyScript factory.
Takes a userscript source and returns a GreasemonkeyScript.
Parses the Greasemonkey metadata block, if present, to fill out
attributes.
"""
matches = re.split(cls.HEADER_REGEX, source, maxsplit=2)
try:
_head, props, _code = matches
except ValueError:
props = ""
script = cls(re.findall(cls.PROPS_REGEX, props), source)
script.script_meta = props
if not props:
script.includes = ['*']
return script
def code(self):
"""Return the processed JavaScript code of this script.
Adorns the source code with GM_* methods for Greasemonkey
compatibility and wraps it in an IFFE to hide it within a
lexical scope. Note that this means line numbers in your
browser's debugger/inspector will not match up to the line
numbers in the source script directly.
"""
return jinja.js_environment.get_template(
'greasemonkey_wrapper.js').render(
scriptName="/".join([self.namespace or '', self.name]),
scriptInfo=self._meta_json(),
scriptMeta=self.script_meta,
scriptSource=self._code)
def _meta_json(self):
return json.dumps({
'name': self.name,
'description': self.description,
'matches': self.includes,
'includes': self.includes,
'excludes': self.excludes,
'run-at': self.run_at,
})
@attr.s
class MatchingScripts(object):
"""All userscripts registered to run on a particular url."""
url = attr.ib()
start = attr.ib(default=attr.Factory(list))
end = attr.ib(default=attr.Factory(list))
idle = attr.ib(default=attr.Factory(list))
class GreasemonkeyManager(QObject):
"""Manager of userscripts and a Greasemonkey compatible environment.
Signals:
scripts_reloaded: Emitted when scripts are reloaded from disk.
Any cached or already-injected scripts should be
considered obselete.
"""
scripts_reloaded = pyqtSignal()
# https://wiki.greasespot.net/Include_and_exclude_rules#Greaseable_schemes
# Limit the schemes scripts can run on due to unreasonable levels of
# exploitability
greaseable_schemes = ['http', 'https', 'ftp', 'file']
def __init__(self, parent=None):
super().__init__(parent)
self.load_scripts()
@cmdutils.register(name='greasemonkey-reload',
instance='greasemonkey')
def load_scripts(self):
"""Re-read Greasemonkey scripts from disk.
The scripts are read from a 'greasemonkey' subdirectory in
qutebrowser's data directory (see `:version`).
"""
self._run_start = []
self._run_end = []
self._run_idle = []
scripts_dir = os.path.abspath(_scripts_dir())
log.greasemonkey.debug("Reading scripts from: {}".format(scripts_dir))
for script_filename in glob.glob(os.path.join(scripts_dir, '*.js')):
if not os.path.isfile(script_filename):
continue
script_path = os.path.join(scripts_dir, script_filename)
with open(script_path, encoding='utf-8') as script_file:
script = GreasemonkeyScript.parse(script_file.read())
if not script.name:
script.name = script_filename
if script.run_at == 'document-start':
self._run_start.append(script)
elif script.run_at == 'document-end':
self._run_end.append(script)
elif script.run_at == 'document-idle':
self._run_idle.append(script)
else:
log.greasemonkey.warning("Script {} has invalid run-at "
"defined, defaulting to "
"document-end"
.format(script_path))
# Default as per
# https://wiki.greasespot.net/Metadata_Block#.40run-at
self._run_end.append(script)
log.greasemonkey.debug("Loaded script: {}".format(script.name))
self.scripts_reloaded.emit()
def scripts_for(self, url):
"""Fetch scripts that are registered to run for url.
returns a tuple of lists of scripts meant to run at (document-start,
document-end, document-idle)
"""
if url.scheme() not in self.greaseable_schemes:
return MatchingScripts(url, [], [], [])
match = functools.partial(fnmatch.fnmatch,
url.toString(QUrl.FullyEncoded))
tester = (lambda script:
any(match(pat) for pat in script.includes) and
not any(match(pat) for pat in script.excludes))
return MatchingScripts(
url,
[script for script in self._run_start if tester(script)],
[script for script in self._run_end if tester(script)],
[script for script in self._run_idle if tester(script)]
)
def all_scripts(self):
"""Return all scripts found in the configured script directory."""
return self._run_start + self._run_end + self._run_idle
def init():
"""Initialize Greasemonkey support."""
gm_manager = GreasemonkeyManager()
objreg.register('greasemonkey', gm_manager)
try:
os.mkdir(_scripts_dir())
except FileExistsError:
pass

View File

@@ -24,6 +24,7 @@ import functools
import math
import re
import html
import enum
from string import ascii_lowercase
import attr
@@ -37,10 +38,9 @@ from qutebrowser.commands import userscripts, cmdexc, cmdutils, runners
from qutebrowser.utils import usertypes, log, qtutils, message, objreg, utils
Target = usertypes.enum('Target', ['normal', 'current', 'tab', 'tab_fg',
'tab_bg', 'window', 'yank', 'yank_primary',
'run', 'fill', 'hover', 'download',
'userscript', 'spawn'])
Target = enum.Enum('Target', ['normal', 'current', 'tab', 'tab_fg', 'tab_bg',
'window', 'yank', 'yank_primary', 'run', 'fill',
'hover', 'download', 'userscript', 'spawn'])
class HintingError(Exception):
@@ -390,7 +390,6 @@ class HintManager(QObject):
def _cleanup(self):
"""Clean up after hinting."""
# pylint: disable=not-an-iterable
for label in self._context.all_labels:
label.cleanup()
@@ -445,8 +444,17 @@ class HintManager(QObject):
# Short hints are the number of hints we can possibly show which are
# (needed - 1) digits in length.
if needed > min_chars:
short_count = math.floor((len(chars) ** needed - len(elems)) /
total_space = len(chars) ** needed
# Calculate short_count naively, by finding the avaiable space and
# dividing by the number of spots we would loose by adding a
# short element
short_count = math.floor((total_space - len(elems)) /
len(chars))
# Check if we double counted above to warrant another short_count
# https://github.com/qutebrowser/qutebrowser/issues/3242
if total_space - (short_count * len(chars) +
(len(elems) - short_count)) >= len(chars) - 1:
short_count += 1
else:
short_count = 0
@@ -611,13 +619,16 @@ class HintManager(QObject):
@cmdutils.register(instance='hintmanager', scope='tab', name='hint',
star_args_optional=True, maxsplit=2)
@cmdutils.argument('win_id', win_id=True)
def start(self, rapid=False, group=webelem.Group.all, target=Target.normal,
*args, win_id, mode=None, add_history=False):
def start(self, # pylint: disable=keyword-arg-before-vararg
group=webelem.Group.all, target=Target.normal,
*args, win_id, mode=None, add_history=False, rapid=False):
"""Start hinting.
Args:
rapid: Whether to do rapid hinting. This is only possible with
targets `tab` (with `tabs.background_tabs=true`), `tab-bg`,
rapid: Whether to do rapid hinting. With rapid hinting, the hint
mode isn't left after a hint is followed, so you can easily
open multiple links. This is only possible with targets
`tab` (with `tabs.background_tabs=true`), `tab-bg`,
`window`, `run`, `hover`, `userscript` and `spawn`.
add_history: Whether to add the spawned or yanked link to the
browsing history.
@@ -797,7 +808,6 @@ class HintManager(QObject):
log.hints.debug("Filtering hints on {!r}".format(filterstr))
visible = []
# pylint: disable=not-an-iterable
for label in self._context.all_labels:
try:
if self._filter_matches(filterstr, str(label.elem)):
@@ -898,7 +908,7 @@ class HintManager(QObject):
except HintingError as e:
message.error(str(e))
@cmdutils.register(instance='hintmanager', scope='tab', hide=True,
@cmdutils.register(instance='hintmanager', scope='tab',
modes=[usertypes.KeyMode.hint])
def follow_hint(self, keystring=None):
"""Follow a hint.

View File

@@ -21,6 +21,7 @@
import os
import time
import contextlib
from PyQt5.QtCore import pyqtSlot, QUrl, QTimer
@@ -31,7 +32,7 @@ from qutebrowser.misc import objects, sql
# increment to indicate that HistoryCompletion must be regenerated
_USER_VERSION = 1
_USER_VERSION = 2
class CompletionHistory(sql.SqlTable):
@@ -87,11 +88,22 @@ class WebHistory(sql.SqlTable):
def __contains__(self, url):
return self._contains_query.run(val=url).value()
@contextlib.contextmanager
def _handle_sql_errors(self):
try:
yield
except sql.SqlError as e:
if e.environmental:
message.error("Failed to write history: {}".format(e.text()))
else:
raise
def _rebuild_completion(self):
data = {'url': [], 'title': [], 'last_atime': []}
# select the latest entry for each url
q = sql.Query('SELECT url, title, max(atime) AS atime FROM History '
'WHERE NOT redirect GROUP BY url ORDER BY atime asc')
'WHERE NOT redirect and url NOT LIKE "qute://back%" '
'GROUP BY url ORDER BY atime asc')
for entry in q.run():
data['url'].append(self._format_completion_url(QUrl(entry.url)))
data['title'].append(entry.title)
@@ -138,12 +150,13 @@ class WebHistory(sql.SqlTable):
if force:
self._do_clear()
else:
message.confirm_async(self._do_clear, title="Clear all browsing "
"history?")
message.confirm_async(yes_action=self._do_clear,
title="Clear all browsing history?")
def _do_clear(self):
self.delete_all()
self.completion.delete_all()
with self._handle_sql_errors():
self.delete_all()
self.completion.delete_all()
def delete_url(self, url):
"""Remove all history entries with the given url.
@@ -159,7 +172,9 @@ class WebHistory(sql.SqlTable):
@pyqtSlot(QUrl, QUrl, str)
def add_from_tab(self, url, requested_url, title):
"""Add a new history entry as slot, called from a BrowserTab."""
if url.scheme() == 'data' or requested_url.scheme() == 'data':
if any(url.scheme() == 'data' or
(url.scheme(), url.host()) == ('qute', 'back')
for url in (url, requested_url)):
return
if url.isEmpty():
# things set via setHtml
@@ -191,7 +206,7 @@ class WebHistory(sql.SqlTable):
atime = int(atime) if (atime is not None) else int(time.time())
try:
with self._handle_sql_errors():
self.insert({'url': self._format_url(url),
'title': title,
'atime': atime,
@@ -202,11 +217,6 @@ class WebHistory(sql.SqlTable):
'title': title,
'last_atime': atime
}, replace=True)
except sql.SqlError as e:
if e.environmental:
message.error("Failed to write history: {}".format(e.text()))
else:
raise
def _parse_entry(self, line):
"""Parse a history line like '12345 http://example.com title'."""
@@ -261,6 +271,7 @@ class WebHistory(sql.SqlTable):
return
def action():
"""Actually run the import."""
with debug.log_time(log.init, 'Import old history file to sqlite'):
try:
self._read(path)
@@ -333,7 +344,7 @@ class WebHistory(sql.SqlTable):
f.write('\n'.join(lines))
message.info("Dumped history to {}".format(dest))
except OSError as e:
raise cmdexc.CommandError('Could not write history: {}', e)
raise cmdexc.CommandError('Could not write history: {}'.format(e))
def init(parent=None):

View File

@@ -94,6 +94,7 @@ class AbstractWebInspector(QWidget):
raise NotImplementedError
def toggle(self, page):
"""Show/hide the inspector."""
if self._widget.isVisible():
self.hide()
else:

View File

@@ -19,15 +19,13 @@
"""Mouse handling for a browser tab."""
from PyQt5.QtCore import QObject, QEvent, Qt, QTimer
from qutebrowser.config import config
from qutebrowser.utils import message, log, usertypes
from qutebrowser.keyinput import modeman
from PyQt5.QtCore import QObject, QEvent, Qt, QTimer
class ChildEventFilter(QObject):
"""An event filter re-adding MouseEventFilter on ChildEvent.

View File

@@ -64,6 +64,7 @@ def path_up(url, count):
raise Error("Can't go up!")
for _i in range(0, min(count, path.count('/'))):
path = posixpath.join(path, posixpath.pardir)
path = posixpath.normpath(path)
url.setPath(path)
return url

View File

@@ -59,6 +59,7 @@ def _js_slot(*args):
def _decorator(method):
@functools.wraps(method)
def new_method(self, *args, **kwargs):
"""Call the underlying function."""
try:
return method(self, *args, **kwargs)
except:

View File

@@ -82,7 +82,7 @@ def fix_urls(asset):
('viewer.css', 'qute://pdfjs/web/viewer.css'),
('compatibility.js', 'qute://pdfjs/web/compatibility.js'),
('locale/locale.properties',
'qute://pdfjs/web/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'),

View File

@@ -203,8 +203,19 @@ class DownloadItem(downloads.AbstractDownloadItem):
no_action=no_action, cancel_action=no_action,
abort_on=[self.cancelled, self.error])
def _ask_create_parent_question(self, title, msg,
force_overwrite, remember_directory):
no_action = functools.partial(self.cancel, remove_data=False)
message.confirm_async(title=title, text=msg,
yes_action=(lambda:
self._after_create_parent_question(
force_overwrite,
remember_directory)),
no_action=no_action, cancel_action=no_action,
abort_on=[self.cancelled, self.error])
def _set_fileobj(self, fileobj, *, autoclose=True):
""""Set the file object to write the download to.
"""Set the file object to write the download to.
Args:
fileobj: A file-like object.
@@ -292,8 +303,7 @@ class DownloadItem(downloads.AbstractDownloadItem):
"""Handle QNetworkReply errors."""
if code == QNetworkReply.OperationCanceledError:
return
else:
self._die(self._reply.errorString())
self._die(self._reply.errorString())
@pyqtSlot()
def _on_read_timer_timeout(self):
@@ -388,7 +398,7 @@ class DownloadManager(downloads.AbstractDownloadManager):
"""
if not url.isValid():
urlutils.invalid_url_error(url, "start download")
return
return None
req = QNetworkRequest(url)
if user_agent is not None:
req.setHeader(QNetworkRequest.UserAgentHeader, user_agent)

View File

@@ -27,20 +27,22 @@ Module attributes:
import json
import os
import time
import urllib.parse
import textwrap
import pkg_resources
import mimetypes
import urllib
import pkg_resources
from PyQt5.QtCore import QUrlQuery, QUrl
import qutebrowser
from qutebrowser.config import config, configdata, configexc, configdiff
from qutebrowser.utils import (version, utils, jinja, log, message, docutils,
objreg)
objreg, urlutils)
from qutebrowser.misc import objects
pyeval_output = ":pyeval was never called"
spawn_output = ":spawn was never called"
_HANDLERS = {}
@@ -91,7 +93,7 @@ class Redirect(Exception):
self.url = url
class add_handler: # pylint: disable=invalid-name
class add_handler: # noqa: N801,N806 pylint: disable=invalid-name
"""Decorator to register a qute://* URL handler.
@@ -111,6 +113,7 @@ class add_handler: # pylint: disable=invalid-name
return function
def wrapper(self, *args, **kwargs):
"""Call the underlying function."""
if self._backend is not None and objects.backend != self._backend:
return self.wrong_backend_handler(*args, **kwargs)
else:
@@ -135,16 +138,30 @@ def data_for_url(url):
Return:
A (mimetype, data) tuple.
"""
norm_url = url.adjusted(QUrl.NormalizePathSegments |
QUrl.StripTrailingSlash)
if norm_url != url:
raise Redirect(norm_url)
path = url.path()
host = url.host()
query = urlutils.query_string(url)
# A url like "qute:foo" is split as "scheme:path", not "scheme:host".
log.misc.debug("url: {}, path: {}, host {}".format(
url.toDisplayString(), path, host))
if path and not host:
if not path or not host:
new_url = QUrl()
new_url.setScheme('qute')
new_url.setHost(path)
# When path is absent, e.g. qute://help (with no trailing slash)
if host:
new_url.setHost(host)
# When host is absent, e.g. qute:help
else:
new_url.setHost(path)
new_url.setPath('/')
if query:
new_url.setQuery(query)
if new_url.host(): # path was a valid host
raise Redirect(new_url)
@@ -253,6 +270,13 @@ def qute_pyeval(_url):
return 'text/html', html
@add_handler('spawn-output')
def qute_spawn_output(_url):
"""Handler for qute://spawn-output."""
html = jinja.render('pre.html', title='spawn output', content=spawn_output)
return 'text/html', html
@add_handler('version')
@add_handler('verizon')
def qute_version(_url):
@@ -274,9 +298,8 @@ def qute_plainlog(url):
if log.ram_handler is None:
text = "Log output was disabled."
else:
try:
level = urllib.parse.parse_qs(url.query())['level'][0]
except KeyError:
level = QUrlQuery(url).queryItemValue('level')
if not level:
level = 'vdebug'
text = log.ram_handler.dump_log(html=False, level=level)
html = jinja.render('pre.html', title='log', content=text)
@@ -294,9 +317,8 @@ def qute_log(url):
if log.ram_handler is None:
html_log = None
else:
try:
level = urllib.parse.parse_qs(url.query())['level'][0]
except KeyError:
level = QUrlQuery(url).queryItemValue('level')
if not level:
level = 'vdebug'
html_log = log.ram_handler.dump_log(html=True, level=level)
@@ -307,7 +329,7 @@ def qute_log(url):
@add_handler('gpl')
def qute_gpl(_url):
"""Handler for qute://gpl. Return HTML content as string."""
return 'text/html', utils.read_file('html/LICENSE.html')
return 'text/html', utils.read_file('html/license.html')
@add_handler('help')
@@ -323,8 +345,14 @@ def qute_help(url):
"scripts/asciidoc2html.py.")
path = 'html/doc/{}'.format(urlpath)
if urlpath.endswith('.png'):
return 'image/png', utils.read_file(path, binary=True)
if not urlpath.endswith('.html'):
try:
bdata = utils.read_file(path, binary=True)
except OSError as e:
raise QuteSchemeOSError(e)
mimetype, _encoding = mimetypes.guess_type(urlpath)
assert mimetype is not None, url
return mimetype, bdata
try:
data = utils.read_file(path)
@@ -407,6 +435,18 @@ def qute_settings(url):
return 'text/html', html
@add_handler('back')
def qute_back(url):
"""Handler for qute://back.
Simple page to free ram / lazy load a site, goes back on focusing the tab.
"""
html = jinja.render(
'back.html',
title='Suspended: ' + urllib.parse.unquote(url.fragment()))
return 'text/html', html
@add_handler('configdiff')
def qute_configdiff(url):
"""Handler for qute://configdiff."""
@@ -415,7 +455,7 @@ def qute_configdiff(url):
return 'text/html', configdiff.get_diff()
except OSError as e:
error = (b'Failed to read old config: ' +
str(e.strerror).encode('utf-8'))
str(e.strerror).encode('utf-8'))
return 'text/plain', error
else:
data = config.instance.dump_userconfig().encode('utf-8')

View File

@@ -22,7 +22,7 @@
import html
from qutebrowser.config import config
from qutebrowser.utils import usertypes, message, log, objreg, jinja
from qutebrowser.utils import usertypes, message, log, objreg, jinja, utils
from qutebrowser.mainwindow import mainwindow
@@ -182,7 +182,7 @@ def ignore_certificate_errors(url, errors, abort_on):
return False
else:
raise ValueError("Invalid ssl_strict value {!r}".format(ssl_strict))
raise AssertionError("Not reached")
raise utils.Unreachable
def feature_permission(url, option, msg, yes_action, no_action, abort_on):

View File

@@ -26,8 +26,8 @@ to a file on shutdown, so it makes sense to keep them as strings here.
"""
import os
import html
import os.path
import html
import functools
import collections

View File

@@ -24,6 +24,7 @@ Module attributes:
SELECTORS: CSS selectors for different groups of elements.
"""
import enum
import collections.abc
from PyQt5.QtCore import QUrl, Qt, QEvent, QTimer
@@ -35,7 +36,7 @@ from qutebrowser.mainwindow import mainwindow
from qutebrowser.utils import log, usertypes, utils, qtutils, objreg
Group = usertypes.enum('Group', ['all', 'links', 'images', 'url', 'inputs'])
Group = enum.Enum('Group', ['all', 'links', 'images', 'url', 'inputs'])
SELECTORS = {
@@ -59,6 +60,13 @@ class Error(Exception):
pass
class OrphanedError(Error):
"""Raised when a webelement's parent has vanished."""
pass
class AbstractWebElement(collections.abc.MutableMapping):
"""A wrapper around QtWebKit/QtWebEngine web element.
@@ -220,7 +228,7 @@ class AbstractWebElement(collections.abc.MutableMapping):
}
relevant_classes = classes[self.tag_name()]
for klass in self.classes():
if any([klass.strip().startswith(e) for e in relevant_classes]):
if any(klass.strip().startswith(e) for e in relevant_classes):
return True
return False

View File

@@ -21,8 +21,20 @@
import glob
import os
import re
from PyQt5.QtCore import QLibraryInfo
from qutebrowser.utils import log
def version(filename):
"""Extract the version number from the dictionary file name."""
version_re = re.compile(r".+-(?P<version>[0-9]+-[0-9]+?)\.bdic")
match = version_re.fullmatch(filename)
if match is None:
raise ValueError('the given dictionary file name is malformed: {}'
.format(filename))
return tuple(int(n) for n in match.group('version').split('-'))
def dictionary_dir():
@@ -31,16 +43,23 @@ def dictionary_dir():
return os.path.join(datapath, 'qtwebengine_dictionaries')
def installed_file(code):
"""Return the installed dictionary for the given code.
Return the filename of the installed dictionary or None
if the dictionary is not installed.
"""
def local_files(code):
"""Return all installed dictionaries for the given code."""
pathname = os.path.join(dictionary_dir(), '{}*.bdic'.format(code))
matching_dicts = glob.glob(pathname)
if matching_dicts:
with_extension = os.path.basename(matching_dicts[0])
return os.path.splitext(with_extension)[0]
else:
return None
files = []
for matching_dict in sorted(matching_dicts, key=version, reverse=True):
filename = os.path.basename(matching_dict)
log.config.debug('Found file for dict {}: {}'.format(code, filename))
files.append(filename)
return files
def local_filename(code):
"""Return the newest installed dictionary for the given code.
Return the filename of the installed dictionary with the highest version
number or None if the dictionary is not installed.
"""
all_installed = local_files(code)
return os.path.splitext(all_installed[0])[0] if all_installed else None

View File

@@ -133,6 +133,22 @@ class DownloadItem(downloads.AbstractDownloadItem):
self.error.connect(question.abort)
message.global_bridge.ask(question, blocking=True)
def _ask_create_parent_question(self, title, msg,
force_overwrite, remember_directory):
no_action = functools.partial(self.cancel, remove_data=False)
question = usertypes.Question()
question.title = title
question.text = msg
question.mode = usertypes.PromptMode.yesno
question.answered_yes.connect(lambda:
self._after_create_parent_question(
force_overwrite, remember_directory))
question.answered_no.connect(no_action)
question.cancelled.connect(no_action)
self.cancelled.connect(question.abort)
self.error.connect(question.abort)
message.global_bridge.ask(question, blocking=True)
def _after_set_filename(self):
self._qt_item.setPath(self._filename)
self._qt_item.accept()

View File

@@ -47,6 +47,7 @@ class WebEngineElement(webelem.AbstractWebElement):
'class_name': str,
'rects': list,
'attributes': dict,
'caret_position': (int, type(None)),
}
assert set(js_dict.keys()).issubset(js_dict_types.keys())
for name, typ in js_dict_types.items():
@@ -99,6 +100,8 @@ class WebEngineElement(webelem.AbstractWebElement):
def _js_call(self, name, *args, callback=None):
"""Wrapper to run stuff from webelem.js."""
if self._tab.is_deleted():
raise webelem.OrphanedError("Tab containing element vanished")
js_code = javascript.assemble('webelem', name, self._id, *args)
self._tab.run_js_async(js_code, callback=callback)
@@ -132,6 +135,13 @@ class WebEngineElement(webelem.AbstractWebElement):
def set_value(self, value):
self._js_call('set_value', value)
def caret_position(self):
"""Get the text caret position for the current element.
If the element is not a text element, None is returned.
"""
return self._js_dict.get('caret_position', None)
def insert_text(self, text):
if not self.is_editable(strict=True):
raise webelem.Error("Element is not editable!")
@@ -201,11 +211,11 @@ class WebEngineElement(webelem.AbstractWebElement):
def _click_js(self, _click_target):
# FIXME:qtwebengine Have a proper API for this
# pylint: disable=protected-access
settings = self._tab._widget.settings()
view = self._tab._widget
# pylint: enable=protected-access
attribute = QWebEngineSettings.JavascriptCanOpenWindows
could_open_windows = settings.testAttribute(attribute)
settings.setAttribute(attribute, True)
could_open_windows = view.settings().testAttribute(attribute)
view.settings().setAttribute(attribute, True)
# Get QtWebEngine do apply the settings
# (it does so with a 0ms QTimer...)
@@ -216,6 +226,12 @@ class WebEngineElement(webelem.AbstractWebElement):
QEventLoop.ExcludeUserInputEvents)
def reset_setting(_arg):
settings.setAttribute(attribute, could_open_windows)
"""Set the JavascriptCanOpenWindows setting to its old value."""
try:
view.settings().setAttribute(attribute, could_open_windows)
except RuntimeError:
# Happens if this callback gets called during QWebEnginePage
# destruction, i.e. if the tab was closed in the meantime.
pass
self._js_call('click', callback=reset_setting)

View File

@@ -28,9 +28,8 @@ Module attributes:
"""
import os
import ctypes
import ctypes.util
import sip
from PyQt5.QtGui import QFont
from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
QWebEngineScript)
@@ -38,7 +37,8 @@ from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
from qutebrowser.browser import shared
from qutebrowser.browser.webengine import spell
from qutebrowser.config import config, websettings
from qutebrowser.utils import utils, standarddir, javascript, qtutils, message
from qutebrowser.utils import (utils, standarddir, javascript, qtutils,
message, log, objreg)
# The default QWebEngineProfile
default_profile = None
@@ -94,9 +94,10 @@ class DefaultProfileSetter(websettings.Base):
"""A setting set on the QWebEngineProfile."""
def __init__(self, setter, default=websettings.UNSET):
def __init__(self, setter, converter=None, default=websettings.UNSET):
super().__init__(default)
self._setter = setter
self._converter = converter
def __repr__(self):
return utils.get_repr(self, setter=self._setter, constructor=True)
@@ -105,7 +106,11 @@ class DefaultProfileSetter(websettings.Base):
if settings is not None:
raise ValueError("'settings' may not be set with "
"DefaultProfileSetters!")
setter = getattr(default_profile, self._setter)
if self._converter is not None:
value = self._converter(value)
setter(value)
@@ -135,51 +140,63 @@ class DictionaryLanguageSetter(DefaultProfileSetter):
super().__init__('setSpellCheckLanguages', default=[])
def _find_installed(self, code):
installed_file = spell.installed_file(code)
if not installed_file:
local_filename = spell.local_filename(code)
if not local_filename:
message.warning(
"Language {} is not installed - see scripts/install_dict.py "
"Language {} is not installed - see scripts/dictcli.py "
"in qutebrowser's sources".format(code))
return installed_file
return local_filename
def _set(self, value, settings=None):
if settings is not None:
raise ValueError("'settings' may not be set with "
"DictionaryLanguageSetter!")
filenames = [self._find_installed(code) for code in value]
log.config.debug("Found dicts: {}".format(filenames))
super()._set([f for f in filenames if f], settings)
def _init_stylesheet(profile):
"""Initialize custom stylesheets.
Mostly inspired by QupZilla:
Partially inspired by QupZilla:
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/tools/scripts.cpp#L119-L132
"""
old_script = profile.scripts().findScript('_qute_stylesheet')
if not old_script.isNull():
profile.scripts().remove(old_script)
css = shared.get_user_stylesheet()
source = """
(function() {{
var css = document.createElement('style');
css.setAttribute('type', 'text/css');
css.appendChild(document.createTextNode('{}'));
document.getElementsByTagName('head')[0].appendChild(css);
}})()
""".format(javascript.string_escape(css))
source = '\n'.join([
'"use strict";',
'window._qutebrowser = window._qutebrowser || {};',
utils.read_file('javascript/stylesheet.js'),
javascript.assemble('stylesheet', 'set_css', css),
])
script = QWebEngineScript()
script.setName('_qute_stylesheet')
script.setInjectionPoint(QWebEngineScript.DocumentReady)
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
script.setWorldId(QWebEngineScript.ApplicationWorld)
script.setRunsOnSubFrames(True)
script.setSourceCode(source)
profile.scripts().insert(script)
def _update_stylesheet():
"""Update the custom stylesheet in existing tabs."""
css = shared.get_user_stylesheet()
code = javascript.assemble('stylesheet', 'set_css', css)
for win_id, window in objreg.window_registry.items():
# We could be in the middle of destroying a window here
if sip.isdeleted(window):
continue
tab_registry = objreg.get('tab-registry', scope='window',
window=win_id)
for tab in tab_registry.values():
tab.run_js_async(code)
def _set_http_headers(profile):
"""Set the user agent and accept-language for the given profile.
@@ -199,6 +216,7 @@ def _update_settings(option):
if option in ['scrolling.bar', 'content.user_stylesheets']:
_init_stylesheet(default_profile)
_init_stylesheet(private_profile)
_update_stylesheet()
elif option in ['content.headers.user_agent',
'content.headers.accept_language']:
_set_http_headers(default_profile)
@@ -226,16 +244,48 @@ def _init_profiles():
private_profile.setSpellCheckEnabled(True)
def inject_userscripts():
"""Register user JavaScript files with the global profiles."""
# The Greasemonkey metadata block support in QtWebEngine only starts at
# Qt 5.8. With 5.7.1, we need to inject the scripts ourselves in response
# to urlChanged.
if not qtutils.version_check('5.8'):
return
# Since we are inserting scripts into profile.scripts they won't
# just get replaced by new gm scripts like if we were injecting them
# ourselves so we need to remove all gm scripts, while not removing
# any other stuff that might have been added. Like the one for
# stylesheets.
greasemonkey = objreg.get('greasemonkey')
for profile in [default_profile, private_profile]:
scripts = profile.scripts()
for script in scripts.toList():
if script.name().startswith("GM-"):
log.greasemonkey.debug('Removing script: {}'
.format(script.name()))
removed = scripts.remove(script)
assert removed, script.name()
# Then add the new scripts.
for script in greasemonkey.all_scripts():
# @run-at (and @include/@exclude/@match) is parsed by
# QWebEngineScript.
new_script = QWebEngineScript()
new_script.setWorldId(QWebEngineScript.MainWorld)
new_script.setSourceCode(script.code())
new_script.setName("GM-{}".format(script.name))
new_script.setRunsOnSubFrames(script.runs_on_sub_frames)
log.greasemonkey.debug('adding script: {}'
.format(new_script.name()))
scripts.insert(new_script)
def init(args):
"""Initialize the global QWebSettings."""
if args.enable_webengine_inspector:
os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = str(utils.random_port())
# WORKAROUND for
# https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
if utils.is_linux:
ctypes.CDLL(ctypes.util.find_library("GL"), mode=ctypes.RTLD_GLOBAL)
_init_profiles()
# We need to do this here as a WORKAROUND for
@@ -288,7 +338,9 @@ MAPPINGS = {
Attribute(QWebEngineSettings.LocalStorageEnabled),
'content.cache.size':
# 0: automatically managed by QtWebEngine
DefaultProfileSetter('setHttpCacheMaximumSize', default=0),
DefaultProfileSetter('setHttpCacheMaximumSize', default=0,
converter=lambda val:
qtutils.check_overflow(val, 'int', fatal=False)),
'content.xss_auditing':
Attribute(QWebEngineSettings.XSSAuditingEnabled),
'content.default_encoding':

View File

@@ -24,7 +24,8 @@ import functools
import html as html_utils
import sip
from PyQt5.QtCore import pyqtSlot, Qt, QEvent, QPoint, QUrl, QTimer
from PyQt5.QtCore import (pyqtSignal, pyqtSlot, Qt, QEvent, QPoint, QPointF,
QUrl, QTimer)
from PyQt5.QtGui import QKeyEvent
from PyQt5.QtNetwork import QAuthenticator
from PyQt5.QtWidgets import QApplication
@@ -69,6 +70,10 @@ def init():
download_manager.install(webenginesettings.private_profile)
objreg.register('webengine-download-manager', download_manager)
greasemonkey = objreg.get('greasemonkey')
greasemonkey.scripts_reloaded.connect(webenginesettings.inject_userscripts)
webenginesettings.inject_userscripts()
# Mapping worlds from usertypes.JsWorld to QWebEngineScript world IDs.
_JS_WORLD_MAP = {
@@ -121,18 +126,35 @@ class WebEnginePrinting(browsertab.AbstractPrinting):
class WebEngineSearch(browsertab.AbstractSearch):
"""QtWebEngine implementations related to searching on the page."""
"""QtWebEngine implementations related to searching on the page.
Attributes:
_flags: The QWebEnginePage.FindFlags of the last search.
_pending_searches: How many searches have been started but not called
back yet.
"""
def __init__(self, parent=None):
super().__init__(parent)
self._flags = QWebEnginePage.FindFlags(0)
self._pending_searches = 0
def _find(self, text, flags, callback, caller):
"""Call findText on the widget."""
self.search_displayed = True
self._pending_searches += 1
def wrapped_callback(found):
"""Wrap the callback to do debug logging."""
self._pending_searches -= 1
if self._pending_searches > 0:
# See https://github.com/qutebrowser/qutebrowser/issues/2442
# and https://github.com/qt/qtwebengine/blob/5.10/src/core/web_contents_adapter.cpp#L924-L934
log.webview.debug("Ignoring cancelled search callback with "
"{} pending searches".format(
self._pending_searches))
return
found_text = 'found' if found else "didn't find"
if flags:
flag_text = 'with flags {}'.format(debug.qflags_key(
@@ -293,6 +315,7 @@ class WebEngineScroller(browsertab.AbstractScroller):
def __init__(self, tab, parent=None):
super().__init__(tab, parent)
self._args = objreg.get('args')
self._pos_perc = (0, 0)
self._pos_px = QPoint()
self._at_bottom = False
@@ -307,39 +330,42 @@ class WebEngineScroller(browsertab.AbstractScroller):
for _ in range(min(count, 5000)):
self._tab.key_press(key, modifier)
@pyqtSlot()
def _update_pos(self):
@pyqtSlot(QPointF)
def _update_pos(self, pos):
"""Update the scroll position attributes when it changed."""
def update_pos_cb(jsret):
"""Callback after getting scroll position via JS."""
if jsret is None:
# This can happen when the callback would get called after
# shutting down a tab
return
log.webview.vdebug(jsret)
assert isinstance(jsret, dict), jsret
self._pos_px = QPoint(jsret['px']['x'], jsret['px']['y'])
self._pos_px = pos.toPoint()
contents_size = self._widget.page().contentsSize()
dx = jsret['scroll']['width'] - jsret['inner']['width']
if dx == 0:
perc_x = 0
else:
perc_x = min(100, round(100 / dx * jsret['px']['x']))
scrollable_x = contents_size.width() - self._widget.width()
if scrollable_x == 0:
perc_x = 0
else:
try:
perc_x = min(100, round(100 / scrollable_x * pos.x()))
except ValueError:
# https://github.com/qutebrowser/qutebrowser/issues/3219
log.misc.debug("Got ValueError!")
log.misc.debug("contents_size.width(): {}".format(
contents_size.width()))
log.misc.debug("self._widget.width(): {}".format(
self._widget.width()))
log.misc.debug("scrollable_x: {}".format(scrollable_x))
log.misc.debug("pos.x(): {}".format(pos.x()))
raise
dy = jsret['scroll']['height'] - jsret['inner']['height']
if dy == 0:
perc_y = 0
else:
perc_y = min(100, round(100 / dy * jsret['px']['y']))
scrollable_y = contents_size.height() - self._widget.height()
if scrollable_y == 0:
perc_y = 0
else:
perc_y = min(100, round(100 / scrollable_y * pos.y()))
self._at_bottom = math.ceil(jsret['px']['y']) >= dy
self._at_bottom = math.ceil(pos.y()) >= scrollable_y
if (self._pos_perc != (perc_x, perc_y) or
'no-scroll-filtering' in self._args.debug_flags):
self._pos_perc = perc_x, perc_y
self.perc_changed.emit(*self._pos_perc)
js_code = javascript.assemble('scroll', 'pos')
self._tab.run_js_async(js_code, update_pos_cb)
def pos_px(self):
return self._pos_px
@@ -514,7 +540,15 @@ class WebEngineElements(browsertab.AbstractElements):
class WebEngineTab(browsertab.AbstractTab):
"""A QtWebEngine tab in the browser."""
"""A QtWebEngine tab in the browser.
Signals:
_load_finished_fake:
Used in place of unreliable loadFinished
"""
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-65223
_load_finished_fake = pyqtSignal(bool)
def __init__(self, *, win_id, mode_manager, private, parent=None):
super().__init__(win_id=win_id, mode_manager=mode_manager,
@@ -540,7 +574,7 @@ class WebEngineTab(browsertab.AbstractTab):
def _init_js(self):
js_code = '\n'.join([
'"use strict";',
'window._qutebrowser = {};',
'window._qutebrowser = window._qutebrowser || {};',
utils.read_file('javascript/scroll.js'),
utils.read_file('javascript/webelem.js'),
])
@@ -563,6 +597,9 @@ class WebEngineTab(browsertab.AbstractTab):
@pyqtSlot()
def _restore_zoom(self):
if sip.isdeleted(self._widget):
# https://github.com/qutebrowser/qutebrowser/issues/3498
return
if self._saved_zoom is None:
return
self.zoom.set_factor(self._saved_zoom)
@@ -693,6 +730,7 @@ class WebEngineTab(browsertab.AbstractTab):
try:
# pylint: disable=no-member, useless-suppression
sip.assign(authenticator, QAuthenticator())
# pylint: enable=no-member, useless-suppression
except AttributeError:
url_string = url.toDisplayString()
error_page = jinja.render(
@@ -712,6 +750,7 @@ class WebEngineTab(browsertab.AbstractTab):
try:
# pylint: disable=no-member, useless-suppression
sip.assign(authenticator, QAuthenticator())
# pylint: enable=no-member, useless-suppression
except AttributeError:
# WORKAROUND for
# https://www.riverbankcomputing.com/pipermail/pyqt/2016-December/038400.html
@@ -766,6 +805,24 @@ class WebEngineTab(browsertab.AbstractTab):
}
self.renderer_process_terminated.emit(status_map[status], exitcode)
@pyqtSlot(int)
def _on_load_progress_workaround(self, perc):
"""Use loadProgress(100) to emit loadFinished(True).
See https://bugreports.qt.io/browse/QTBUG-65223
"""
if perc == 100 and self.load_status() != usertypes.LoadStatus.error:
self._load_finished_fake.emit(True)
@pyqtSlot(bool)
def _on_load_finished_workaround(self, ok):
"""Use only loadFinished(False).
See https://bugreports.qt.io/browse/QTBUG-65223
"""
if not ok:
self._load_finished_fake.emit(False)
def _connect_signals(self):
view = self._widget
page = view.page()
@@ -774,9 +831,6 @@ class WebEngineTab(browsertab.AbstractTab):
page.linkHovered.connect(self.link_hovered)
page.loadProgress.connect(self._on_load_progress)
page.loadStarted.connect(self._on_load_started)
page.loadFinished.connect(self._on_history_trigger)
page.loadFinished.connect(self._restore_zoom)
page.loadFinished.connect(self._on_load_finished)
page.certificate_error.connect(self._on_ssl_errors)
page.authenticationRequired.connect(self._on_authentication_required)
page.proxyAuthenticationRequired.connect(
@@ -789,6 +843,19 @@ class WebEngineTab(browsertab.AbstractTab):
view.renderProcessTerminated.connect(
self._on_render_process_terminated)
view.iconChanged.connect(self.icon_changed)
# WORKAROUND for https://bugreports.qt.io/browse/QTBUG-65223
if qtutils.version_check('5.10', compiled=False):
page.loadProgress.connect(self._on_load_progress_workaround)
self._load_finished_fake.connect(self._on_history_trigger)
self._load_finished_fake.connect(self._restore_zoom)
self._load_finished_fake.connect(self._on_load_finished)
page.loadFinished.connect(self._on_load_finished_workaround)
else:
# for older Qt versions which break with the above
page.loadProgress.connect(self._on_load_progress)
page.loadFinished.connect(self._on_history_trigger)
page.loadFinished.connect(self._restore_zoom)
page.loadFinished.connect(self._on_load_finished)
def event_target(self):
return self._widget.focusProxy()

View File

@@ -23,12 +23,14 @@ import functools
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QUrl, PYQT_VERSION
from PyQt5.QtGui import QPalette
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtWebEngineWidgets import (QWebEngineView, QWebEnginePage,
QWebEngineScript)
from qutebrowser.browser import shared
from qutebrowser.browser.webengine import certificateerror, webenginesettings
from qutebrowser.config import config
from qutebrowser.utils import log, debug, usertypes, jinja, urlutils, message
from qutebrowser.utils import (log, debug, usertypes, jinja, urlutils, message,
objreg, qtutils)
class WebEngineView(QWebEngineView):
@@ -135,6 +137,7 @@ class WebEnginePage(QWebEnginePage):
self._theme_color = theme_color
self._set_bg_color()
config.instance.changed.connect(self._set_bg_color)
self.urlChanged.connect(self._inject_userjs)
@config.change_filter('colors.webpage.bg')
def _set_bg_color(self):
@@ -300,3 +303,43 @@ class WebEnginePage(QWebEnginePage):
message.error(msg)
return False
return True
@pyqtSlot('QUrl')
def _inject_userjs(self, url):
"""Inject userscripts registered for `url` into the current page."""
if qtutils.version_check('5.8'):
# Handled in webenginetab with the builtin Greasemonkey
# support.
return
# Using QWebEnginePage.scripts() to hold the user scripts means
# we don't have to worry ourselves about where to inject the
# page but also means scripts hang around for the tab lifecycle.
# So clear them here.
scripts = self.scripts()
for script in scripts.toList():
if script.name().startswith("GM-"):
log.greasemonkey.debug("Removing script: {}"
.format(script.name()))
removed = scripts.remove(script)
assert removed, script.name()
def _add_script(script, injection_point):
new_script = QWebEngineScript()
new_script.setInjectionPoint(injection_point)
new_script.setWorldId(QWebEngineScript.MainWorld)
new_script.setSourceCode(script.code())
new_script.setName("GM-{}".format(script.name))
new_script.setRunsOnSubFrames(script.runs_on_sub_frames)
log.greasemonkey.debug("Adding script: {}"
.format(new_script.name()))
scripts.insert(new_script)
greasemonkey = objreg.get('greasemonkey')
matching_scripts = greasemonkey.scripts_for(url)
for script in matching_scripts.start:
_add_script(script, QWebEngineScript.DocumentCreation)
for script in matching_scripts.end:
_add_script(script, QWebEngineScript.DocumentReady)
for script in matching_scripts.idle:
_add_script(script, QWebEngineScript.Deferred)

View File

@@ -22,11 +22,11 @@
import os.path
from PyQt5.QtNetwork import QNetworkRequest
from qutebrowser.utils import log
from qutebrowser.browser.webkit import rfc6266
from PyQt5.QtNetwork import QNetworkRequest
def parse_content_disposition(reply):
"""Parse a content_disposition header.
@@ -57,9 +57,7 @@ def parse_content_disposition(reply):
is_inline = content_disposition.is_inline()
# Then try to get filename from url
if not filename:
path = reply.url().path()
if path is not None:
filename = path.rstrip('/')
filename = reply.url().path().rstrip('/')
# If that fails as well, use a fallback
if not filename:
filename = 'qutebrowser-download'

View File

@@ -502,8 +502,8 @@ class _Downloader:
This is needed if a download finishes before attaching its
finished signal.
"""
items = set((url, item) for url, item in self.pending_downloads
if item.done)
items = {(url, item) for url, item in self.pending_downloads
if item.done}
log.downloads.debug("Zombie downloads: {}".format(items))
for url, item in items:
self._finished(url, item)

View File

@@ -127,7 +127,11 @@ class FileSchemeHandler(schemehandler.SchemeHandler):
A QNetworkReply for directories, None for files.
"""
path = request.url().toLocalFile()
if os.path.isdir(path):
data = dirbrowser_html(path)
return networkreply.FixedDataNetworkReply(
request, data, 'text/html', self.parent())
try:
if os.path.isdir(path):
data = dirbrowser_html(path)
return networkreply.FixedDataNetworkReply(
request, data, 'text/html', self.parent())
return None
except UnicodeEncodeError:
return None

View File

@@ -206,7 +206,7 @@ class NetworkManager(QNetworkAccessManager):
# No @pyqtSlot here, see
# https://github.com/qutebrowser/qutebrowser/issues/2213
def on_ssl_errors(self, reply, errors): # pragma: no mccabe
def on_ssl_errors(self, reply, errors): # noqa: C901 pragma: no mccabe
"""Decide if SSL errors should be ignored or not.
This slot is called on SSL/TLS errors by the self.sslErrors signal.

View File

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

View File

@@ -270,6 +270,7 @@ class _ContentDisposition:
elif 'filename' in self.assocs:
# XXX Reject non-ascii (parsed via qdtext) here?
return self.assocs['filename']
return None
def is_inline(self):
"""Return if the file should be handled inline.

View File

@@ -118,6 +118,8 @@ class WebKitElement(webelem.AbstractWebElement):
def set_value(self, value):
self._check_vanished()
if self._tab.is_deleted():
raise webelem.OrphanedError("Tab containing element vanished")
if self.is_content_editable():
log.webelem.debug("Filling {!r} via set_text.".format(self))
self._elem.setPlainText(value)
@@ -126,6 +128,14 @@ class WebKitElement(webelem.AbstractWebElement):
value = javascript.string_escape(value)
self._elem.evaluateJavaScript("this.value='{}'".format(value))
def caret_position(self):
"""Get the text caret position for the current element."""
self._check_vanished()
pos = self._elem.evaluateJavaScript('this.selectionStart')
if pos is None:
return 0
return int(pos)
def insert_text(self, text):
self._check_vanished()
if not self.is_editable(strict=True):

View File

@@ -19,6 +19,7 @@
"""Wrapper over our (QtWebKit) WebView."""
import re
import functools
import xml.etree.ElementTree
@@ -422,12 +423,13 @@ class WebKitScroller(browsertab.AbstractScroller):
else:
for val, orientation in [(x, Qt.Horizontal), (y, Qt.Vertical)]:
if val is not None:
val = qtutils.check_overflow(val, 'int', fatal=False)
frame = self._widget.page().mainFrame()
m = frame.scrollBarMaximum(orientation)
if m == 0:
maximum = frame.scrollBarMaximum(orientation)
if maximum == 0:
continue
frame.setScrollBarValue(orientation, int(m * val / 100))
pos = int(maximum * val / 100)
pos = qtutils.check_overflow(pos, 'int', fatal=False)
frame.setScrollBarValue(orientation, pos)
def _key_press(self, key, count=1, getter_name=None, direction=None):
frame = self._widget.page().mainFrame()
@@ -540,10 +542,15 @@ class WebKitElements(browsertab.AbstractElements):
def find_id(self, elem_id, callback):
def find_id_cb(elems):
"""Call the real callback with the found elements."""
if not elems:
callback(None)
else:
callback(elems[0])
# Escape non-alphanumeric characters in the selector
# https://www.w3.org/TR/CSS2/syndata.html#value-def-identifier
elem_id = re.sub(r'[^a-zA-Z0-9_-]', r'\\\g<0>', elem_id)
self.find_css('#' + elem_id, find_id_cb)
def find_focused(self, callback):

View File

@@ -86,6 +86,21 @@ class BrowserPage(QWebPage):
self.on_save_frame_state_requested)
self.restoreFrameStateRequested.connect(
self.on_restore_frame_state_requested)
self.loadFinished.connect(
functools.partial(self._inject_userjs, self.mainFrame()))
self.frameCreated.connect(self._connect_userjs_signals)
@pyqtSlot('QWebFrame*')
def _connect_userjs_signals(self, frame):
"""Connect userjs related signals to `frame`.
Connect the signals used as triggers for injecting user
JavaScripts into the passed QWebFrame.
"""
log.greasemonkey.debug("Connecting to frame {} ({})"
.format(frame, frame.url().toDisplayString()))
frame.loadFinished.connect(
functools.partial(self._inject_userjs, frame))
def javaScriptPrompt(self, frame, js_msg, default):
"""Override javaScriptPrompt to use qutebrowser prompts."""
@@ -283,6 +298,38 @@ class BrowserPage(QWebPage):
else:
self.error_occurred = False
def _inject_userjs(self, frame):
"""Inject user JavaScripts into the page.
Args:
frame: The QWebFrame to inject the user scripts into.
"""
url = frame.url()
if url.isEmpty():
url = frame.requestedUrl()
log.greasemonkey.debug("_inject_userjs called for {} ({})"
.format(frame, url.toDisplayString()))
greasemonkey = objreg.get('greasemonkey')
scripts = greasemonkey.scripts_for(url)
# QtWebKit has trouble providing us with signals representing
# page load progress at reasonable times, so we just load all
# scripts on the same event.
toload = scripts.start + scripts.end + scripts.idle
if url.isEmpty():
# This happens during normal usage like with view source but may
# also indicate a bug.
log.greasemonkey.debug("Not running scripts for frame with no "
"url: {}".format(frame))
assert not toload, toload
for script in toload:
if frame is self.mainFrame() or script.runs_on_sub_frames:
log.webview.debug('Running GM script: {}'.format(script.name))
frame.evaluateJavaScript(script.code())
@pyqtSlot('QWebFrame*', 'QWebPage::Feature')
def _on_feature_permission_requested(self, frame, feature):
"""Ask the user for approval for geolocation/notifications."""

View File

@@ -61,7 +61,7 @@ def check_exclusive(flags, names):
argstr))
class register: # pylint: disable=invalid-name
class register: # noqa: N801,N806 pylint: disable=invalid-name
"""Decorator to register a new command handler.
@@ -114,7 +114,7 @@ class register: # pylint: disable=invalid-name
return func
class argument: # pylint: disable=invalid-name
class argument: # noqa: N801,N806 pylint: disable=invalid-name
"""Decorator to customize an argument for @cmdutils.register.

View File

@@ -58,7 +58,6 @@ class Command:
name: The main name of the command.
maxsplit: The maximum amount of splits to do for the commandline, or
None.
hide: Whether to hide the arguments or not.
deprecated: False, or a string to describe why a command is deprecated.
desc: The description of the command.
handler: The handler function to call.
@@ -69,41 +68,37 @@ class Command:
backend: Which backend the command works with (or None if it works with
both)
no_replace_variables: Don't replace variables like {url}
modes: The modes the command can be executed in.
_qute_args: The saved data from @cmdutils.argument
_modes: The modes the command can be executed in.
_count: The count set for the command.
_instance: The object to bind 'self' to.
_scope: The scope to get _instance for in the object registry.
"""
def __init__(self, *, handler, name, instance=None, maxsplit=None,
hide=False, modes=None, not_modes=None, debug=False,
deprecated=False, no_cmd_split=False,
star_args_optional=False, scope='global', backend=None,
no_replace_variables=False):
# I really don't know how to solve this in a better way, I tried.
# pylint: disable=too-many-locals
modes=None, not_modes=None, debug=False, deprecated=False,
no_cmd_split=False, star_args_optional=False, scope='global',
backend=None, no_replace_variables=False):
if modes is not None and not_modes is not None:
raise ValueError("Only modes or not_modes can be given!")
if modes is not None:
for m in modes:
if not isinstance(m, usertypes.KeyMode):
raise TypeError("Mode {} is no KeyMode member!".format(m))
self._modes = set(modes)
self.modes = set(modes)
elif not_modes is not None:
for m in not_modes:
if not isinstance(m, usertypes.KeyMode):
raise TypeError("Mode {} is no KeyMode member!".format(m))
self._modes = set(usertypes.KeyMode).difference(not_modes)
self.modes = set(usertypes.KeyMode).difference(not_modes)
else:
self._modes = set(usertypes.KeyMode)
self.modes = set(usertypes.KeyMode)
if scope != 'global' and instance is None:
raise ValueError("Setting scope without setting instance makes "
"no sense!")
self.name = name
self.maxsplit = maxsplit
self.hide = hide
self.deprecated = deprecated
self._instance = instance
self._scope = scope
@@ -195,6 +190,7 @@ class Command:
return True
elif arg_info.win_id:
return True
return False
def _inspect_func(self):
"""Inspect the function to get useful informations from it.
@@ -398,10 +394,8 @@ class Command:
if isinstance(typ, tuple):
raise TypeError("{}: Legacy tuple type annotation!".format(
self.name))
elif type(typ) is type(typing.Union): # flake8: disable=E721
elif getattr(typ, '__origin__', None) is typing.Union:
# this is... slightly evil, I know
# We also can't use isinstance here because typing.Union doesn't
# support that.
# pylint: disable=no-member,useless-suppression
try:
types = list(typ.__args__)
@@ -510,8 +504,8 @@ class Command:
Args:
mode: The usertypes.KeyMode to check.
"""
if mode not in self._modes:
mode_names = '/'.join(sorted(m.name for m in self._modes))
if mode not in self.modes:
mode_names = '/'.join(sorted(m.name for m in self.modes))
raise cmdexc.PrerequisitesError(
"{}: This command is only allowed in {} mode, not {}.".format(
self.name, mode_names, mode.name))

View File

@@ -95,7 +95,6 @@ class CommandParser:
"""Parse qutebrowser commandline commands.
Attributes:
_partial_match: Whether to allow partial command matches.
"""
@@ -127,7 +126,7 @@ class CommandParser:
new_cmd += ' '
return new_cmd
def _parse_all_gen(self, text, aliases=True, *args, **kwargs):
def _parse_all_gen(self, text, *args, aliases=True, **kwargs):
"""Split a command on ;; and parse all parts.
If the first command in the commandline is a non-split one, it only
@@ -214,12 +213,12 @@ class CommandParser:
Return:
cmdstr modified to the matching completion or unmodified
"""
matches = []
for valid_command in cmdutils.cmd_dict:
if valid_command.find(cmdstr) == 0:
matches.append(valid_command)
matches = [cmd for cmd in sorted(cmdutils.cmd_dict, key=len)
if cmdstr in cmd]
if len(matches) == 1:
cmdstr = matches[0]
elif len(matches) > 1 and config.val.completion.use_best_match:
cmdstr = matches[0]
return cmdstr
def _split_args(self, cmd, argstr, keep):

View File

@@ -56,6 +56,7 @@ class _QtFIFOReader(QObject):
# can add O_NONBLOCK.
# pylint: disable=no-member,useless-suppression
fd = os.open(filepath, os.O_RDWR | os.O_NONBLOCK)
# pylint: enable=no-member,useless-suppression
self._fifo = os.fdopen(fd, 'r')
self._notifier = QSocketNotifier(fd, QSocketNotifier.Read, self)
self._notifier.activated.connect(self.read_line)
@@ -247,6 +248,7 @@ class _POSIXUserscriptRunner(_BaseUserscriptRunner):
dir=standarddir.runtime())
# pylint: disable=no-member,useless-suppression
os.mkfifo(self._filepath)
# pylint: enable=no-member,useless-suppression
except OSError as e:
message.error("Error while creating FIFO: {}".format(e))
return

View File

@@ -35,6 +35,7 @@ class CompletionInfo:
config = attr.ib()
keyconf = attr.ib()
win_id = attr.ib()
class Completer(QObject):
@@ -43,7 +44,7 @@ class Completer(QObject):
Attributes:
_cmd: The statusbar Command object this completer belongs to.
_ignore_change: Whether to ignore the next completion update.
_win_id: The id of the window that owns this object.
_timer: The timer used to trigger the completion update.
_last_cursor_pos: The old cursor position so we avoid double completion
updates.
@@ -51,10 +52,10 @@ class Completer(QObject):
_last_completion_func: The completion function used for the last text.
"""
def __init__(self, cmd, parent=None):
def __init__(self, *, cmd, win_id, parent=None):
super().__init__(parent)
self._cmd = cmd
self._ignore_change = False
self._win_id = win_id
self._timer = QTimer()
self._timer.setSingleShot(True)
self._timer.setInterval(0)
@@ -86,8 +87,6 @@ class Completer(QObject):
# cursor on a flag or after an explicit split (--)
return None
log.completion.debug("Before removing flags: {}".format(before_cursor))
before_cursor = [x for x in before_cursor if not x.startswith('-')]
log.completion.debug("After removing flags: {}".format(before_cursor))
if not before_cursor:
# '|' or 'set|'
log.completion.debug('Starting command completion')
@@ -98,6 +97,9 @@ class Completer(QObject):
log.completion.debug("No completion for unknown command: {}"
.format(before_cursor[0]))
return None
before_cursor = [x for x in before_cursor if not x.startswith('-')]
log.completion.debug("After removing flags: {}".format(before_cursor))
argpos = len(before_cursor) - 1
try:
func = cmd.get_pos_arg_info(argpos).completion
@@ -133,9 +135,7 @@ class Completer(QObject):
return [], '', []
parser = runners.CommandParser()
result = parser.parse(text, fallback=True, keep=True)
# pylint: disable=not-an-iterable
parts = [x for x in result.cmdline if x]
# pylint: enable=not-an-iterable
pos = self._cmd.cursorPosition() - len(self._cmd.prefix())
pos = min(pos, len(text)) # Qt treats 2-byte UTF-16 chars as 2 chars
log.completion.debug('partitioning {} around position {}'.format(parts,
@@ -154,8 +154,7 @@ class Completer(QObject):
"partitioned: {} '{}' {}".format(prefix, center, postfix))
return prefix, center, postfix
# We should always return above
assert False, parts
raise utils.Unreachable("Not all parts consumed: {}".format(parts))
@pyqtSlot(str)
def on_selection_changed(self, text):
@@ -178,16 +177,16 @@ class Completer(QObject):
text = self._quote(text)
model = self._model()
if model.count() == 1 and config.val.completion.quick:
# If we only have one item, we want to apply it immediately
# and go on to the next part.
self._change_completed_part(text, before, after, immediate=True)
# If we only have one item, we want to apply it immediately and go
# on to the next part, unless we are quick-completing the part
# after maxsplit, so that we don't keep offering completions
# (see issue #1519)
if maxsplit is not None and maxsplit < len(before):
# If we are quick-completing the part after maxsplit, don't
# keep offering completions (see issue #1519)
self._ignore_change = True
self._change_completed_part(text, before, after)
else:
self._change_completed_part(text, before, after,
immediate=True)
else:
log.completion.debug("Will ignore next completion update.")
self._ignore_change = True
self._change_completed_part(text, before, after)
@pyqtSlot()
@@ -196,26 +195,31 @@ class Completer(QObject):
For performance reasons we don't want to block here, instead we do this
in the background.
We delay the update only if we've already input some text and ignore
updates if the text is shorter than completion.min_chars (unless we're
hitting backspace in which case updates won't be ignored).
"""
if (self._cmd.cursorPosition() == self._last_cursor_pos and
self._cmd.text() == self._last_text):
_cmd, _sep, rest = self._cmd.text().partition(' ')
input_length = len(rest)
if (0 < input_length < config.val.completion.min_chars and
self._cmd.cursorPosition() > self._last_cursor_pos):
log.completion.debug("Ignoring update because the length of "
"the text is less than completion.min_chars.")
elif (self._cmd.cursorPosition() == self._last_cursor_pos and
self._cmd.text() == self._last_text):
log.completion.debug("Ignoring update because there were no "
"changes.")
else:
log.completion.debug("Scheduling completion update.")
self._timer.start()
start_delay = config.val.completion.delay if self._last_text else 0
self._timer.start(start_delay)
self._last_cursor_pos = self._cmd.cursorPosition()
self._last_text = self._cmd.text()
@pyqtSlot()
def _update_completion(self):
"""Check if completions are available and activate them."""
if self._ignore_change:
log.completion.debug("Ignoring completion update because "
"ignore_change is True.")
self._ignore_change = False
return
completion = self.parent()
if self._cmd.prefix() != ':':
@@ -244,10 +248,11 @@ class Completer(QObject):
if func != self._last_completion_func:
self._last_completion_func = func
args = (x for x in before_cursor[1:] if not x.startswith('-'))
with debug.log_time(log.completion,
'Starting {} completion'.format(func.__name__)):
with debug.log_time(log.completion, 'Starting {} completion'
.format(func.__name__)):
info = CompletionInfo(config=config.instance,
keyconf=config.key_instance)
keyconf=config.key_instance,
win_id=self._win_id)
model = func(*args, info=info)
with debug.log_time(log.completion, 'Set completion model'):
completion.set_model(model)
@@ -273,7 +278,20 @@ class Completer(QObject):
# pad with a space if quick-completing the last entry
text += ' '
log.completion.debug("setting text = '{}', pos = {}".format(text, pos))
# generally, we don't want to let self._cmd emit cursorPositionChanged,
# because that'll schedule a completion update. That happens when
# tabbing through the completions, and we want to change the command
# text but we also want to keep the original completion list for the
# command the user manually entered. The exception is when we're
# immediately completing, in which case we *do* want to update the
# completion view so that we can start completing the next part
if not immediate:
self._cmd.blockSignals(True)
self._cmd.setText(text)
self._cmd.setCursorPosition(pos)
self._cmd.setFocus()
self._cmd.blockSignals(False)
self._cmd.show_cmd.emit()

View File

@@ -138,10 +138,10 @@ class CompletionItemDelegate(QStyledItemDelegate):
self._painter.translate(text_rect.left(), text_rect.top())
self._get_textdoc(index)
self._draw_textdoc(text_rect)
self._draw_textdoc(text_rect, index.column())
self._painter.restore()
def _draw_textdoc(self, rect):
def _draw_textdoc(self, rect, col):
"""Draw the QTextDocument of an item.
Args:
@@ -156,7 +156,9 @@ class CompletionItemDelegate(QStyledItemDelegate):
elif not self._opt.state & QStyle.State_Enabled:
color = config.val.colors.completion.category.fg
else:
color = config.val.colors.completion.fg
colors = config.val.colors.completion.fg
# if multiple colors are set, use different colors per column
color = colors[col % len(colors)]
self._painter.setPen(color)
ctx = QAbstractTextDocumentLayout.PaintContext()
@@ -202,7 +204,8 @@ class CompletionItemDelegate(QStyledItemDelegate):
if index.column() in columns_to_filter and pattern:
repl = r'<span class="highlight">\g<0></span>'
text = re.sub(re.escape(pattern).replace(r'\ ', r'|'),
repl, self._opt.text, flags=re.IGNORECASE)
repl, html.escape(self._opt.text),
flags=re.IGNORECASE)
self._doc.setHtml(text)
else:
self._doc.setPlainText(self._opt.text)

View File

@@ -23,12 +23,12 @@ Defines a CompletionView which uses CompletionFiterModel and CompletionModel
subclasses to provide completions.
"""
from PyQt5.QtWidgets import QStyle, QTreeView, QSizePolicy, QStyleFactory
from PyQt5.QtWidgets import QTreeView, QSizePolicy, QStyleFactory
from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QItemSelectionModel, QSize
from qutebrowser.config import config
from qutebrowser.completion import completiondelegate
from qutebrowser.utils import utils, usertypes, debug, log
from qutebrowser.utils import utils, usertypes, debug, log, objreg
from qutebrowser.commands import cmdexc, cmdutils
@@ -152,12 +152,12 @@ class CompletionView(QTreeView):
column_widths = self.model().column_widths
pixel_widths = [(width * perc // 100) for perc in column_widths]
if self.verticalScrollBar().isVisible():
delta = self.style().pixelMetric(QStyle.PM_ScrollBarExtent) + 5
if pixel_widths[-1] > delta:
pixel_widths[-1] -= delta
else:
pixel_widths[-2] -= delta
delta = self.verticalScrollBar().sizeHint().width()
if pixel_widths[-1] > delta:
pixel_widths[-1] -= delta
else:
pixel_widths[-2] -= delta
for i, w in enumerate(pixel_widths):
assert w >= 0, i
self.setColumnWidth(i, w)
@@ -180,6 +180,7 @@ class CompletionView(QTreeView):
return self.model().last_item()
else:
return self.model().first_item()
while True:
idx = self.indexAbove(idx) if upwards else self.indexBelow(idx)
# wrap around if we arrived at beginning/end
@@ -193,6 +194,8 @@ class CompletionView(QTreeView):
# Item is a real item, not a category header -> success
return idx
raise utils.Unreachable
def _next_category_idx(self, upwards):
"""Get the index of the previous/next category.
@@ -222,30 +225,46 @@ class CompletionView(QTreeView):
self.scrollTo(idx)
return idx.child(0, 0)
@cmdutils.register(instance='completion', hide=True,
raise utils.Unreachable
@cmdutils.register(instance='completion',
modes=[usertypes.KeyMode.command], scope='window')
@cmdutils.argument('which', choices=['next', 'prev', 'next-category',
'prev-category'])
def completion_item_focus(self, which):
@cmdutils.argument('history', flag='H')
def completion_item_focus(self, which, history=False):
"""Shift the focus of the completion menu to another item.
Args:
which: 'next', 'prev', 'next-category', or 'prev-category'.
history: Navigate through command history if no text was typed.
"""
if history:
status = objreg.get('status-command', scope='window',
window=self._win_id)
if (status.text() == ':' or status.history.is_browsing() or
not self._active):
if which == 'next':
status.command_history_next()
return
elif which == 'prev':
status.command_history_prev()
return
else:
raise cmdexc.CommandError("Can't combine --history with "
"{}!".format(which))
if not self._active:
return
selmodel = self.selectionModel()
if which == 'next':
idx = self._next_idx(upwards=False)
elif which == 'prev':
idx = self._next_idx(upwards=True)
elif which == 'next-category':
idx = self._next_category_idx(upwards=False)
elif which == 'prev-category':
idx = self._next_category_idx(upwards=True)
else: # pragma: no cover
raise ValueError("Invalid 'which' value {!r}".format(which))
selmodel = self.selectionModel()
indices = {
'next': self._next_idx(upwards=False),
'prev': self._next_idx(upwards=True),
'next-category': self._next_category_idx(upwards=False),
'prev-category': self._next_category_idx(upwards=True),
}
idx = indices[which]
if not idx.isValid():
return
@@ -369,7 +388,7 @@ class CompletionView(QTreeView):
scrollbar.setValue(scrollbar.minimum())
super().showEvent(e)
@cmdutils.register(instance='completion', hide=True,
@cmdutils.register(instance='completion',
modes=[usertypes.KeyMode.command], scope='window')
def completion_item_del(self):
"""Delete the current completion item."""
@@ -377,3 +396,21 @@ class CompletionView(QTreeView):
if not index.isValid():
raise cmdexc.CommandError("No item selected!")
self.model().delete_cur_item(index)
@cmdutils.register(instance='completion',
modes=[usertypes.KeyMode.command], scope='window')
def completion_item_yank(self, sel=False):
"""Yank the current completion item into the clipboard.
Args:
sel: Use the primary selection instead of the clipboard.
"""
status = objreg.get('status-command', scope='window',
window=self._win_id)
text = status.selectedText()
if not text:
index = self.currentIndex()
if not index.isValid():
raise cmdexc.CommandError("No item selected!")
text = self.model().data(index)
utils.set_clipboard(text, selection=sel)

View File

@@ -60,8 +60,6 @@ class CompletionModel(QAbstractItemModel):
def add_category(self, cat):
"""Add a completion category to the model."""
self._categories.append(cat)
cat.layoutAboutToBeChanged.connect(self.layoutAboutToBeChanged)
cat.layoutChanged.connect(self.layoutChanged)
def data(self, index, role=Qt.DisplayRole):
"""Return the item data for index.
@@ -179,8 +177,13 @@ class CompletionModel(QAbstractItemModel):
pattern: The filter pattern to set.
"""
log.completion.debug("Setting completion pattern '{}'".format(pattern))
# WORKAROUND:
# layoutChanged is broken in PyQt 5.7.1, so we must use metaObject
# https://www.riverbankcomputing.com/pipermail/pyqt/2017-January/038483.html
self.metaObject().invokeMethod(self, "layoutAboutToBeChanged")
for cat in self._categories:
cat.set_pattern(pattern)
self.metaObject().invokeMethod(self, "layoutChanged")
def first_item(self):
"""Return the index of the first child (non-category) in the model."""

View File

@@ -29,7 +29,7 @@ def option(*, info):
model = completionmodel.CompletionModel(column_widths=(20, 70, 10))
options = ((opt.name, opt.description, info.config.get_str(opt.name))
for opt in configdata.DATA.values())
model.add_category(listcategory.ListCategory("Options", sorted(options)))
model.add_category(listcategory.ListCategory("Options", options))
return model
@@ -39,7 +39,7 @@ def customized_option(*, info):
options = ((opt.name, opt.description, info.config.get_str(opt.name))
for opt, _value in info.config)
model.add_category(listcategory.ListCategory("Customized options",
sorted(options)))
options))
return model
@@ -60,14 +60,14 @@ def value(optname, *_values, info):
opt = info.config.get_opt(optname)
default = opt.typ.to_str(opt.default)
cur_cat = listcategory.ListCategory("Current/Default",
cur_cat = listcategory.ListCategory(
"Current/Default",
[(current, "Current value"), (default, "Default value")])
model.add_category(cur_cat)
vals = opt.typ.complete()
if vals is not None:
model.add_category(listcategory.ListCategory("Completions",
sorted(vals)))
model.add_category(listcategory.ListCategory("Completions", vals))
return model
@@ -78,17 +78,26 @@ def bind(key, *, info):
key: the key being bound.
"""
model = completionmodel.CompletionModel(column_widths=(20, 60, 20))
cmd_text = info.keyconf.get_command(key, 'normal')
data = []
cmd_text = info.keyconf.get_command(key, 'normal')
if cmd_text:
parser = runners.CommandParser()
try:
cmd = parser.parse(cmd_text).cmd
except cmdexc.NoSuchCommandError:
data = [(cmd_text, 'Invalid command!', key)]
data.append((cmd_text, '(Current) Invalid command!', key))
else:
data = [(cmd_text, cmd.desc, key)]
model.add_category(listcategory.ListCategory("Current", data))
data.append((cmd_text, '(Current) {}'.format(cmd.desc), key))
cmd_text = info.keyconf.get_command(key, 'normal', default=True)
if cmd_text:
parser = runners.CommandParser()
cmd = parser.parse(cmd_text).cmd
data.append((cmd_text, '(Default) {}'.format(cmd.desc), key))
if data:
model.add_category(listcategory.ListCategory("Current/Default", data))
cmdlist = util.get_cmd_completions(info, include_hidden=True,
include_aliases=True)

View File

@@ -19,8 +19,6 @@
"""A completion category that queries the SQL History store."""
import re
from PyQt5.QtSql import QSqlQueryModel
from qutebrowser.misc import sql
@@ -36,21 +34,7 @@ class HistoryCategory(QSqlQueryModel):
"""Create a new History completion category."""
super().__init__(parent=parent)
self.name = "History"
# replace ' in timestamp-format to avoid breaking the query
timestamp_format = config.val.completion.timestamp_format
timefmt = ("strftime('{}', last_atime, 'unixepoch', 'localtime')"
.format(timestamp_format.replace("'", "`")))
self._query = sql.Query(' '.join([
"SELECT url, title, {}".format(timefmt),
"FROM CompletionHistory",
# the incoming pattern will have literal % and _ escaped with '\'
# we need to tell sql to treat '\' as an escape character
"WHERE (url LIKE :pat escape '\\' or title LIKE :pat escape '\\')",
self._atime_expr(),
"ORDER BY last_atime DESC",
]), forward_only=False)
self._query = None
# advertise that this model filters by URL and title
self.columns_to_filter = [0, 1]
@@ -86,11 +70,36 @@ class HistoryCategory(QSqlQueryModel):
# escape to treat a user input % or _ as a literal, not a wildcard
pattern = pattern.replace('%', '\\%')
pattern = pattern.replace('_', '\\_')
# treat spaces as wildcards to match any of the typed words
pattern = re.sub(r' +', '%', pattern)
pattern = '%{}%'.format(pattern)
words = ['%{}%'.format(w) for w in pattern.split(' ')]
# build a where clause to match all of the words in any order
# given the search term "a b", the WHERE clause would be:
# ((url || title) LIKE '%a%') AND ((url || title) LIKE '%b%')
where_clause = ' AND '.join(
"(url || title) LIKE :{} escape '\\'".format(i)
for i in range(len(words)))
# replace ' in timestamp-format to avoid breaking the query
timestamp_format = config.val.completion.timestamp_format
timefmt = ("strftime('{}', last_atime, 'unixepoch', 'localtime')"
.format(timestamp_format.replace("'", "`")))
if not self._query or len(words) != len(self._query.boundValues()):
# if the number of words changed, we need to generate a new query
# otherwise, we can reuse the prepared query for performance
self._query = sql.Query(' '.join([
"SELECT url, title, {}".format(timefmt),
"FROM CompletionHistory",
# the incoming pattern will have literal % and _ escaped
# we need to tell sql to treat '\' as an escape character
'WHERE ({})'.format(where_clause),
self._atime_expr(),
"ORDER BY last_atime DESC",
]), forward_only=False)
with debug.log_time('sql', 'Running completion query'):
self._query.run(pat=pattern)
self._query.run(**{
str(i): w for i, w in enumerate(words)})
self.setQuery(self._query)
def removeRows(self, row, _count, _parent=None):

View File

@@ -31,7 +31,7 @@ class ListCategory(QSortFilterProxyModel):
"""Expose a list of items as a category for the CompletionModel."""
def __init__(self, name, items, delete_func=None, parent=None):
def __init__(self, name, items, sort=True, delete_func=None, parent=None):
super().__init__(parent)
self.name = name
self.srcmodel = QStandardItemModel(parent=self)
@@ -43,6 +43,7 @@ class ListCategory(QSortFilterProxyModel):
self.srcmodel.appendRow([QStandardItem(x) for x in item])
self.setSourceModel(self.srcmodel)
self.delete_func = delete_func
self._sort = sort
def set_pattern(self, val):
"""Setter for pattern.
@@ -60,19 +61,33 @@ class ListCategory(QSortFilterProxyModel):
sortcol = 0
self.sort(sortcol)
def lessThan(self, _lindex, rindex):
def lessThan(self, lindex, rindex):
"""Custom sorting implementation.
Prefers all items which start with self._pattern. Other than that, keep
items in their original order.
Prefers all items which start with self._pattern. Other than that, uses
normal Python string sorting.
Args:
_lindex: The QModelIndex of the left item (*left* < right)
lindex: The QModelIndex of the left item (*left* < right)
rindex: The QModelIndex of the right item (left < *right*)
Return:
True if left < right, else False
"""
qtutils.ensure_valid(lindex)
qtutils.ensure_valid(rindex)
left = self.srcmodel.data(lindex)
right = self.srcmodel.data(rindex)
return not right.startswith(self._pattern)
leftstart = left.startswith(self._pattern)
rightstart = right.startswith(self._pattern)
if leftstart and not rightstart:
return True
elif rightstart and not leftstart:
return False
elif self._sort:
return left < right
else:
return False

View File

@@ -43,7 +43,7 @@ def helptopic(*, info):
for opt in configdata.DATA.values())
model.add_category(listcategory.ListCategory("Commands", cmdlist))
model.add_category(listcategory.ListCategory("Settings", sorted(settings)))
model.add_category(listcategory.ListCategory("Settings", settings))
return model
@@ -59,7 +59,8 @@ def quickmark(*, info=None): # pylint: disable=unused-argument
model = completionmodel.CompletionModel(column_widths=(30, 70, 0))
marks = objreg.get('quickmark-manager').marks.items()
model.add_category(listcategory.ListCategory('Quickmarks', marks,
delete_func=delete))
delete_func=delete,
sort=False))
return model
@@ -75,7 +76,8 @@ def bookmark(*, info=None): # pylint: disable=unused-argument
model = completionmodel.CompletionModel(column_widths=(30, 70, 0))
marks = objreg.get('bookmark-manager').marks.items()
model.add_category(listcategory.ListCategory('Bookmarks', marks,
delete_func=delete))
delete_func=delete,
sort=False))
return model
@@ -92,10 +94,11 @@ def session(*, info=None): # pylint: disable=unused-argument
return model
def buffer(*, info=None): # pylint: disable=unused-argument
"""A model to complete on open tabs across all windows.
def _buffer(skip_win_id=None):
"""Helper to get the completion model for buffer/other_buffer.
Used for switching the buffer command.
Args:
skip_win_id: The id of the window to skip, or None to include all.
"""
def delete_buffer(data):
"""Close the selected tab."""
@@ -107,6 +110,8 @@ def buffer(*, info=None): # pylint: disable=unused-argument
model = completionmodel.CompletionModel(column_widths=(6, 40, 54))
for win_id in objreg.window_registry:
if skip_win_id and win_id == skip_win_id:
continue
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
if tabbed_browser.shutting_down:
@@ -118,7 +123,44 @@ def buffer(*, info=None): # pylint: disable=unused-argument
tab.url().toDisplayString(),
tabbed_browser.page_title(idx)))
cat = listcategory.ListCategory("{}".format(win_id), tabs,
delete_func=delete_buffer)
delete_func=delete_buffer)
model.add_category(cat)
return model
def buffer(*, info=None): # pylint: disable=unused-argument
"""A model to complete on open tabs across all windows.
Used for switching the buffer command.
"""
return _buffer()
def other_buffer(*, info):
"""A model to complete on open tabs across all windows except the current.
Used for the tab-take command.
"""
return _buffer(skip_win_id=info.win_id)
def window(*, info):
"""A model to complete on all open windows."""
model = completionmodel.CompletionModel(column_widths=(6, 30, 64))
windows = []
for win_id in objreg.window_registry:
if win_id == info.win_id:
continue
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
tab_titles = (tab.title() for tab in tabbed_browser.widgets())
windows.append(("{}".format(win_id),
objreg.window_registry[win_id].windowTitle(),
", ".join(tab_titles)))
model.add_category(listcategory.ListCategory("Windows", windows))
return model

View File

@@ -56,14 +56,17 @@ def url(*, info):
"""
model = completionmodel.CompletionModel(column_widths=(40, 50, 10))
quickmarks = ((url, name) for (name, url)
in objreg.get('quickmark-manager').marks.items())
quickmarks = [(url, name) for (name, url)
in objreg.get('quickmark-manager').marks.items()]
bookmarks = objreg.get('bookmark-manager').marks.items()
model.add_category(listcategory.ListCategory(
'Quickmarks', quickmarks, delete_func=_delete_quickmark))
model.add_category(listcategory.ListCategory(
'Bookmarks', bookmarks, delete_func=_delete_bookmark))
if quickmarks:
model.add_category(listcategory.ListCategory(
'Quickmarks', quickmarks, delete_func=_delete_quickmark,
sort=False))
if bookmarks:
model.add_category(listcategory.ListCategory(
'Bookmarks', bookmarks, delete_func=_delete_bookmark, sort=False))
if info.config.get('completion.web_history_max_items') != 0:
hist_cat = histcategory.HistoryCategory(delete_func=_delete_history)

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